scream-code 0.5.12 → 0.5.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{app-DCQ0Id5H.mjs → app-DQEAmJsy.mjs} +447 -1544
- package/dist/main.mjs +1 -1
- package/package.json +2 -3
|
@@ -20,13 +20,13 @@ import { finished, pipeline as pipeline$1 } from "node:stream/promises";
|
|
|
20
20
|
import * as vs from "zlib";
|
|
21
21
|
import Qr from "zlib";
|
|
22
22
|
import * as fs$10 from "node:fs";
|
|
23
|
-
import Vt, { appendFileSync, chmodSync, closeSync, constants, createReadStream, createWriteStream as createWriteStream$1, existsSync, fsyncSync, mkdirSync, openSync, promises, readFileSync, readSync,
|
|
23
|
+
import Vt, { appendFileSync, chmodSync, closeSync, constants, createReadStream, createWriteStream as createWriteStream$1, existsSync, fsyncSync, mkdirSync, openSync, promises, readFileSync, readSync, renameSync, statSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
|
|
24
24
|
import * as path$9 from "node:path";
|
|
25
25
|
import path$1, { basename, dirname as dirname$1, extname, isAbsolute, join, posix, relative, resolve, sep, win32 } from "node:path";
|
|
26
26
|
import { z } from "zod";
|
|
27
27
|
import { DatabaseSync } from "node:sqlite";
|
|
28
28
|
import * as nodeOs from "node:os";
|
|
29
|
-
import { arch, homedir, hostname,
|
|
29
|
+
import { arch, homedir, hostname, release, tmpdir, type } from "node:os";
|
|
30
30
|
import { EventEmitter as EventEmitter$1 } from "node:events";
|
|
31
31
|
import { StringDecoder } from "node:string_decoder";
|
|
32
32
|
import Pi from "assert";
|
|
@@ -216,8 +216,8 @@ const parse$7 = function(p) {
|
|
|
216
216
|
* Error codes for Scream Core's public error protocol.
|
|
217
217
|
*
|
|
218
218
|
* `ErrorCodes` is the source of truth for every code Scream Core may emit.
|
|
219
|
-
* Downstream consumers (SDK, RPC clients,
|
|
220
|
-
*
|
|
219
|
+
* Downstream consumers (SDK, RPC clients, agent-facing docs) should depend on
|
|
220
|
+
* these string values rather than on class identity.
|
|
221
221
|
*
|
|
222
222
|
* Codes follow `domain.reason`. Adding a code is a minor change; renaming
|
|
223
223
|
* or removing one is a major change.
|
|
@@ -939,7 +939,7 @@ let uuid4$2 = function() {
|
|
|
939
939
|
};
|
|
940
940
|
//#endregion
|
|
941
941
|
//#region ../../node_modules/.pnpm/@anthropic-ai+sdk@0.95.2_zod@4.4.3/node_modules/@anthropic-ai/sdk/internal/errors.mjs
|
|
942
|
-
function isAbortError$
|
|
942
|
+
function isAbortError$4(err) {
|
|
943
943
|
return typeof err === "object" && err !== null && ("name" in err && err.name === "AbortError" || "message" in err && String(err.message).includes("FetchRequestCanceledException"));
|
|
944
944
|
}
|
|
945
945
|
const castToError$2 = (err) => {
|
|
@@ -2438,7 +2438,7 @@ var Stream$5 = class Stream$5 {
|
|
|
2438
2438
|
}
|
|
2439
2439
|
done = true;
|
|
2440
2440
|
} catch (e) {
|
|
2441
|
-
if (isAbortError$
|
|
2441
|
+
if (isAbortError$4(e)) return;
|
|
2442
2442
|
throw e;
|
|
2443
2443
|
} finally {
|
|
2444
2444
|
if (!done) controller.abort();
|
|
@@ -2469,7 +2469,7 @@ var Stream$5 = class Stream$5 {
|
|
|
2469
2469
|
}
|
|
2470
2470
|
done = true;
|
|
2471
2471
|
} catch (e) {
|
|
2472
|
-
if (isAbortError$
|
|
2472
|
+
if (isAbortError$4(e)) return;
|
|
2473
2473
|
throw e;
|
|
2474
2474
|
} finally {
|
|
2475
2475
|
if (!done) controller.abort();
|
|
@@ -5076,7 +5076,7 @@ var BetaMessageStream = class BetaMessageStream {
|
|
|
5076
5076
|
_BetaMessageStream_logger.set(this, void 0);
|
|
5077
5077
|
_BetaMessageStream_handleError.set(this, (error) => {
|
|
5078
5078
|
__classPrivateFieldSet$1(this, _BetaMessageStream_errored, true, "f");
|
|
5079
|
-
if (isAbortError$
|
|
5079
|
+
if (isAbortError$4(error)) error = new APIUserAbortError$2();
|
|
5080
5080
|
if (error instanceof APIUserAbortError$2) {
|
|
5081
5081
|
__classPrivateFieldSet$1(this, _BetaMessageStream_aborted, true, "f");
|
|
5082
5082
|
return this._emit("abort", error);
|
|
@@ -7003,7 +7003,7 @@ var MessageStream = class MessageStream {
|
|
|
7003
7003
|
_MessageStream_logger.set(this, void 0);
|
|
7004
7004
|
_MessageStream_handleError.set(this, (error) => {
|
|
7005
7005
|
__classPrivateFieldSet$1(this, _MessageStream_errored, true, "f");
|
|
7006
|
-
if (isAbortError$
|
|
7006
|
+
if (isAbortError$4(error)) error = new APIUserAbortError$2();
|
|
7007
7007
|
if (error instanceof APIUserAbortError$2) {
|
|
7008
7008
|
__classPrivateFieldSet$1(this, _MessageStream_aborted, true, "f");
|
|
7009
7009
|
return this._emit("abort", error);
|
|
@@ -8095,7 +8095,7 @@ var BaseAnthropic = class {
|
|
|
8095
8095
|
if (response instanceof globalThis.Error) {
|
|
8096
8096
|
const retryMessage = `retrying, ${retriesRemaining} attempts remaining`;
|
|
8097
8097
|
if (options.signal?.aborted) throw new APIUserAbortError$2();
|
|
8098
|
-
const isTimeout = isAbortError$
|
|
8098
|
+
const isTimeout = isAbortError$4(response) || /timed? ?out/i.test(String(response) + ("cause" in response ? String(response.cause) : ""));
|
|
8099
8099
|
if (retriesRemaining) {
|
|
8100
8100
|
loggerFor$2(this).info(`[${requestLogID}] connection ${isTimeout ? "timed out" : "failed"} - ${retryMessage}`);
|
|
8101
8101
|
loggerFor$2(this).debug(`[${requestLogID}] connection ${isTimeout ? "timed out" : "failed"} (${retryMessage})`, formatRequestDetails$2({
|
|
@@ -8790,16 +8790,24 @@ const CACHEABLE_TYPES = new Set([
|
|
|
8790
8790
|
"server_tool_use",
|
|
8791
8791
|
"web_search_tool_result"
|
|
8792
8792
|
]);
|
|
8793
|
-
function injectCacheControlOnLastBlock(messages) {
|
|
8794
|
-
const
|
|
8795
|
-
if (
|
|
8796
|
-
const content =
|
|
8793
|
+
function injectCacheControlOnLastBlock(messages, messageIndex) {
|
|
8794
|
+
const message = messages[messageIndex ?? messages.length - 1];
|
|
8795
|
+
if (message === void 0) return;
|
|
8796
|
+
const content = message.content;
|
|
8797
8797
|
if (!Array.isArray(content) || content.length === 0) return;
|
|
8798
8798
|
const lastBlock = content.at(-1);
|
|
8799
8799
|
if (lastBlock === void 0) return;
|
|
8800
8800
|
if (CACHEABLE_TYPES.has(lastBlock.type)) lastBlock.cache_control = CACHE_CONTROL;
|
|
8801
8801
|
}
|
|
8802
8802
|
/**
|
|
8803
|
+
* Inject cache_control on the last block of the second-to-last message,
|
|
8804
|
+
* when there is enough budget for an extra breakpoint.
|
|
8805
|
+
*/
|
|
8806
|
+
function injectCacheControlOnPenultimateMessage(messages) {
|
|
8807
|
+
if (messages.length < 2) return;
|
|
8808
|
+
injectCacheControlOnLastBlock(messages, messages.length - 2);
|
|
8809
|
+
}
|
|
8810
|
+
/**
|
|
8803
8811
|
* Check whether a MessageParam is a user message whose content consists
|
|
8804
8812
|
* entirely of `tool_result` blocks.
|
|
8805
8813
|
*
|
|
@@ -9185,6 +9193,7 @@ var AnthropicChatProvider = class {
|
|
|
9185
9193
|
if (last !== void 0 && isToolResultOnly(last) && isToolResultOnly(converted)) last.content = [...last.content, ...converted.content];
|
|
9186
9194
|
else messages.push(converted);
|
|
9187
9195
|
}
|
|
9196
|
+
injectCacheControlOnPenultimateMessage(messages);
|
|
9188
9197
|
injectCacheControlOnLastBlock(messages);
|
|
9189
9198
|
const kwargs = {};
|
|
9190
9199
|
if (this._generationKwargs.max_tokens !== void 0) kwargs["max_tokens"] = this._generationKwargs.max_tokens;
|
|
@@ -34834,7 +34843,7 @@ const uuid4$1 = () => uuid4Internal();
|
|
|
34834
34843
|
* Copyright 2025 Google LLC
|
|
34835
34844
|
* SPDX-License-Identifier: Apache-2.0
|
|
34836
34845
|
*/
|
|
34837
|
-
function isAbortError$
|
|
34846
|
+
function isAbortError$3(err) {
|
|
34838
34847
|
return typeof err === "object" && err !== null && ("name" in err && err.name === "AbortError" || "message" in err && String(err.message).includes("FetchRequestCanceledException"));
|
|
34839
34848
|
}
|
|
34840
34849
|
const castToError$1 = (err) => {
|
|
@@ -35571,7 +35580,7 @@ var Stream$1 = class Stream$1 {
|
|
|
35571
35580
|
}
|
|
35572
35581
|
done = true;
|
|
35573
35582
|
} catch (e) {
|
|
35574
|
-
if (isAbortError$
|
|
35583
|
+
if (isAbortError$3(e)) return yield __await(void 0);
|
|
35575
35584
|
throw e;
|
|
35576
35585
|
} finally {
|
|
35577
35586
|
if (!done) controller.abort();
|
|
@@ -35636,7 +35645,7 @@ var Stream$1 = class Stream$1 {
|
|
|
35636
35645
|
}
|
|
35637
35646
|
done = true;
|
|
35638
35647
|
} catch (e) {
|
|
35639
|
-
if (isAbortError$
|
|
35648
|
+
if (isAbortError$3(e)) return yield __await(void 0);
|
|
35640
35649
|
throw e;
|
|
35641
35650
|
} finally {
|
|
35642
35651
|
if (!done) controller.abort();
|
|
@@ -36162,7 +36171,7 @@ var BaseGeminiNextGenAPIClient = class BaseGeminiNextGenAPIClient {
|
|
|
36162
36171
|
if (response instanceof globalThis.Error) {
|
|
36163
36172
|
const retryMessage = `retrying, ${retriesRemaining} attempts remaining`;
|
|
36164
36173
|
if ((_d = options.signal) === null || _d === void 0 ? void 0 : _d.aborted) throw new APIUserAbortError$1();
|
|
36165
|
-
const isTimeout = isAbortError$
|
|
36174
|
+
const isTimeout = isAbortError$3(response) || /timed? ?out/i.test(String(response) + ("cause" in response ? String(response.cause) : ""));
|
|
36166
36175
|
if (retriesRemaining) {
|
|
36167
36176
|
loggerFor$1(this).info(`[${requestLogID}] connection ${isTimeout ? "timed out" : "failed"} - ${retryMessage}`);
|
|
36168
36177
|
loggerFor$1(this).debug(`[${requestLogID}] connection ${isTimeout ? "timed out" : "failed"} (${retryMessage})`, formatRequestDetails$1({
|
|
@@ -38685,7 +38694,7 @@ let uuid4 = function() {
|
|
|
38685
38694
|
};
|
|
38686
38695
|
//#endregion
|
|
38687
38696
|
//#region ../../node_modules/.pnpm/openai@6.39.1_ws@8.21.0_zod@4.4.3/node_modules/openai/internal/errors.mjs
|
|
38688
|
-
function isAbortError$
|
|
38697
|
+
function isAbortError$2(err) {
|
|
38689
38698
|
return typeof err === "object" && err !== null && ("name" in err && err.name === "AbortError" || "message" in err && String(err.message).includes("FetchRequestCanceledException"));
|
|
38690
38699
|
}
|
|
38691
38700
|
const castToError = (err) => {
|
|
@@ -39514,7 +39523,7 @@ var Stream = class Stream {
|
|
|
39514
39523
|
}
|
|
39515
39524
|
done = true;
|
|
39516
39525
|
} catch (e) {
|
|
39517
|
-
if (isAbortError$
|
|
39526
|
+
if (isAbortError$2(e)) return;
|
|
39518
39527
|
throw e;
|
|
39519
39528
|
} finally {
|
|
39520
39529
|
if (!done) controller.abort();
|
|
@@ -39545,7 +39554,7 @@ var Stream = class Stream {
|
|
|
39545
39554
|
}
|
|
39546
39555
|
done = true;
|
|
39547
39556
|
} catch (e) {
|
|
39548
|
-
if (isAbortError$
|
|
39557
|
+
if (isAbortError$2(e)) return;
|
|
39549
39558
|
throw e;
|
|
39550
39559
|
} finally {
|
|
39551
39560
|
if (!done) controller.abort();
|
|
@@ -47724,7 +47733,7 @@ var OpenAI = class {
|
|
|
47724
47733
|
if (response instanceof globalThis.Error) {
|
|
47725
47734
|
const retryMessage = `retrying, ${retriesRemaining} attempts remaining`;
|
|
47726
47735
|
if (options.signal?.aborted) throw new APIUserAbortError();
|
|
47727
|
-
const isTimeout = isAbortError$
|
|
47736
|
+
const isTimeout = isAbortError$2(response) || /timed? ?out/i.test(String(response) + ("cause" in response ? String(response.cause) : ""));
|
|
47728
47737
|
if (retriesRemaining) {
|
|
47729
47738
|
loggerFor(this).info(`[${requestLogID}] connection ${isTimeout ? "timed out" : "failed"} - ${retryMessage}`);
|
|
47730
47739
|
loggerFor(this).debug(`[${requestLogID}] connection ${isTimeout ? "timed out" : "failed"} (${retryMessage})`, formatRequestDetails({
|
|
@@ -50695,16 +50704,6 @@ function resolveGlobalLogPath(homeDir) {
|
|
|
50695
50704
|
return join$1(homeDir, "logs", "scream-code.log");
|
|
50696
50705
|
}
|
|
50697
50706
|
//#endregion
|
|
50698
|
-
//#region ../../packages/agent-core/src/telemetry.ts
|
|
50699
|
-
const noopTelemetryClient = {
|
|
50700
|
-
track: () => {},
|
|
50701
|
-
withContext: () => noopTelemetryClient,
|
|
50702
|
-
setContext: () => {}
|
|
50703
|
-
};
|
|
50704
|
-
function withTelemetryContext$1(telemetry, patch) {
|
|
50705
|
-
return telemetry.withContext?.(patch) ?? telemetry;
|
|
50706
|
-
}
|
|
50707
|
-
//#endregion
|
|
50708
50707
|
//#region ../../packages/agent-core/src/utils/tokens.ts
|
|
50709
50708
|
/**
|
|
50710
50709
|
* Estimate token count from text using a character-based heuristic.
|
|
@@ -50760,7 +50759,7 @@ function createMaxStepsExceededError(maxSteps, message) {
|
|
|
50760
50759
|
function isMaxStepsExceededError(error) {
|
|
50761
50760
|
return isScreamError(error) && error.code === ErrorCodes.LOOP_MAX_STEPS_EXCEEDED;
|
|
50762
50761
|
}
|
|
50763
|
-
function isAbortError$
|
|
50762
|
+
function isAbortError$1(err) {
|
|
50764
50763
|
if (err instanceof Error) return err.name === "AbortError";
|
|
50765
50764
|
return false;
|
|
50766
50765
|
}
|
|
@@ -51556,7 +51555,7 @@ var BackgroundProcessManager = class {
|
|
|
51556
51555
|
this.appendOutput(entry, r.result);
|
|
51557
51556
|
await this.finalizeTerminal(entry, "completed", 0);
|
|
51558
51557
|
}).catch(async (error) => {
|
|
51559
|
-
if (entry.stopRequested && isAbortError$
|
|
51558
|
+
if (entry.stopRequested && isAbortError$1(error)) {
|
|
51560
51559
|
await this.finalizeTerminal(entry, "killed", null);
|
|
51561
51560
|
return;
|
|
51562
51561
|
}
|
|
@@ -54727,7 +54726,6 @@ var CronCreateTool = class {
|
|
|
54727
54726
|
const ideal = computeNextCronRun(parsed, nowMs);
|
|
54728
54727
|
const nextFireAt = ideal === null ? null : recurring ? jitteredNextCronRunMs(task, parsed, ideal) : oneShotJitteredNextCronRunMs(task, ideal);
|
|
54729
54728
|
const humanSchedule = cronToHuman(parsed);
|
|
54730
|
-
this.manager.emitScheduled(task);
|
|
54731
54729
|
return {
|
|
54732
54730
|
output: formatOutput({
|
|
54733
54731
|
id: task.id,
|
|
@@ -54777,13 +54775,12 @@ var cron_delete_default = "Cancel a scheduled cron job by id.\n\nUse this tool t
|
|
|
54777
54775
|
* thought it deleted. Surfacing `isError: true` lets the model
|
|
54778
54776
|
* correct itself (typically by calling `CronList` again).
|
|
54779
54777
|
*
|
|
54780
|
-
* Why the manager is not consulted
|
|
54781
|
-
* branch:
|
|
54778
|
+
* Why the manager is not consulted on the not-found branch:
|
|
54782
54779
|
*
|
|
54783
|
-
* - `cron_deleted` records an actual state change.
|
|
54784
|
-
* miss would
|
|
54785
|
-
*
|
|
54786
|
-
*
|
|
54780
|
+
* - `cron_deleted` records an actual state change. Reporting success on a
|
|
54781
|
+
* miss would silently teach the model that CronDelete is idempotent
|
|
54782
|
+
* against missing ids, which it is not. The branch is fully observable
|
|
54783
|
+
* through the tool result already.
|
|
54787
54784
|
*
|
|
54788
54785
|
* Refresh-cron pattern this tool participates in:
|
|
54789
54786
|
*
|
|
@@ -54824,7 +54821,6 @@ var CronDeleteTool = class {
|
|
|
54824
54821
|
isError: true,
|
|
54825
54822
|
output: `No cron job with id ${args.id}.`
|
|
54826
54823
|
};
|
|
54827
|
-
this.manager.emitDeleted(args.id);
|
|
54828
54824
|
return {
|
|
54829
54825
|
output: `Deleted cron job ${args.id}.`,
|
|
54830
54826
|
isError: false
|
|
@@ -55018,7 +55014,7 @@ function normalizePath(path) {
|
|
|
55018
55014
|
}
|
|
55019
55015
|
//#endregion
|
|
55020
55016
|
//#region ../../packages/agent-core/src/utils/abort.ts
|
|
55021
|
-
function abortError
|
|
55017
|
+
function abortError() {
|
|
55022
55018
|
const error = /* @__PURE__ */ new Error("Aborted");
|
|
55023
55019
|
error.name = "AbortError";
|
|
55024
55020
|
return error;
|
|
@@ -55051,7 +55047,7 @@ function abortable(promise, signal) {
|
|
|
55051
55047
|
signal.throwIfAborted();
|
|
55052
55048
|
return new Promise((resolve, reject) => {
|
|
55053
55049
|
const onAbort = () => {
|
|
55054
|
-
reject(abortError
|
|
55050
|
+
reject(abortError());
|
|
55055
55051
|
};
|
|
55056
55052
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
55057
55053
|
promise.then(resolve, reject).finally(() => {
|
|
@@ -55078,7 +55074,7 @@ function createDeadlineAbortSignal(source, timeoutMs) {
|
|
|
55078
55074
|
let didTimeout = false;
|
|
55079
55075
|
let timeout = setTimeout(() => {
|
|
55080
55076
|
didTimeout = true;
|
|
55081
|
-
controller.abort(abortError
|
|
55077
|
+
controller.abort(abortError());
|
|
55082
55078
|
}, timeoutMs);
|
|
55083
55079
|
return {
|
|
55084
55080
|
signal: controller.signal,
|
|
@@ -55300,7 +55296,7 @@ var AgentTool = class {
|
|
|
55300
55296
|
let message;
|
|
55301
55297
|
if (foregroundDeadline?.timedOut() === true && args.timeout !== void 0) message = `Agent timed out after ${args.timeout}s.`;
|
|
55302
55298
|
else if (isUserCancellation(signal.reason)) message = "The user manually interrupted this subagent (and any sibling agents launched alongside it). This was a deliberate user action, not a system error, a timeout, or a capacity/concurrency limit. Do not retry automatically or speculate about why it failed — wait for the user's next instruction.";
|
|
55303
|
-
else if (isAbortError$
|
|
55299
|
+
else if (isAbortError$1(error)) message = "The subagent was stopped before it finished.";
|
|
55304
55300
|
else message = error instanceof Error ? error.message : String(error);
|
|
55305
55301
|
return {
|
|
55306
55302
|
output: [
|
|
@@ -55317,7 +55313,7 @@ var AgentTool = class {
|
|
|
55317
55313
|
let message;
|
|
55318
55314
|
if (foregroundDeadline?.timedOut() === true && args.timeout !== void 0) message = `Agent timed out after ${args.timeout}s.`;
|
|
55319
55315
|
else if (isUserCancellation(signal.reason)) message = "The user manually interrupted this subagent (and any sibling agents launched alongside it). This was a deliberate user action, not a system error, a timeout, or a capacity/concurrency limit. Do not retry automatically or speculate about why it failed — wait for the user's next instruction.";
|
|
55320
|
-
else if (isAbortError$
|
|
55316
|
+
else if (isAbortError$1(error)) message = "The subagent was stopped before it finished.";
|
|
55321
55317
|
else message = error instanceof Error ? error.message : String(error);
|
|
55322
55318
|
return {
|
|
55323
55319
|
output: `subagent error: ${message}`,
|
|
@@ -55397,19 +55393,13 @@ var AskUserQuestionTool = class {
|
|
|
55397
55393
|
multiSelect: q.multi_select
|
|
55398
55394
|
}))
|
|
55399
55395
|
}, { signal }));
|
|
55400
|
-
if (normalized === null || Object.keys(normalized.answers).length === 0)
|
|
55401
|
-
this.agent.telemetry.track("question_dismissed");
|
|
55402
|
-
return dismissedQuestionResult();
|
|
55403
|
-
}
|
|
55404
|
-
const properties = { answered: Object.keys(normalized.answers).length };
|
|
55405
|
-
if (normalized.method !== void 0) properties["method"] = normalized.method;
|
|
55406
|
-
this.agent.telemetry.track("question_answered", properties);
|
|
55396
|
+
if (normalized === null || Object.keys(normalized.answers).length === 0) return dismissedQuestionResult();
|
|
55407
55397
|
return {
|
|
55408
55398
|
isError: false,
|
|
55409
55399
|
output: JSON.stringify({ answers: normalized.answers })
|
|
55410
55400
|
};
|
|
55411
55401
|
} catch (error) {
|
|
55412
|
-
if (isAbortError$
|
|
55402
|
+
if (isAbortError$1(error) || signal.aborted) throw error;
|
|
55413
55403
|
if (error instanceof ScreamError && error.code === ErrorCodes.NOT_IMPLEMENTED) return {
|
|
55414
55404
|
isError: true,
|
|
55415
55405
|
output: QUESTION_UNSUPPORTED_FAILURE_MESSAGE
|
|
@@ -56683,6 +56673,8 @@ var MemoryMemoStore = class MemoryMemoStore {
|
|
|
56683
56673
|
tags TEXT NOT NULL DEFAULT '[]'
|
|
56684
56674
|
);
|
|
56685
56675
|
|
|
56676
|
+
CREATE INDEX IF NOT EXISTS idx_memos_project_dir ON memos(project_dir);
|
|
56677
|
+
|
|
56686
56678
|
CREATE VIRTUAL TABLE IF NOT EXISTS memos_fts USING fts5(
|
|
56687
56679
|
user_need,
|
|
56688
56680
|
approach,
|
|
@@ -56698,6 +56690,8 @@ var MemoryMemoStore = class MemoryMemoStore {
|
|
|
56698
56690
|
model TEXT NOT NULL DEFAULT 'bge-small-zh-v1.5',
|
|
56699
56691
|
created_at INTEGER NOT NULL
|
|
56700
56692
|
);
|
|
56693
|
+
|
|
56694
|
+
CREATE INDEX IF NOT EXISTS idx_memory_embeddings_created_at ON memory_embeddings(created_at DESC);
|
|
56701
56695
|
`);
|
|
56702
56696
|
this.migrateSchema();
|
|
56703
56697
|
}
|
|
@@ -56706,6 +56700,10 @@ var MemoryMemoStore = class MemoryMemoStore {
|
|
|
56706
56700
|
const info = this.db.prepare("PRAGMA table_info(memos)").all();
|
|
56707
56701
|
if (!info.some((col) => col.name === "project_dir")) this.db.exec("ALTER TABLE memos ADD COLUMN project_dir TEXT NOT NULL DEFAULT ''");
|
|
56708
56702
|
if (!info.some((col) => col.name === "tags")) this.db.exec("ALTER TABLE memos ADD COLUMN tags TEXT NOT NULL DEFAULT '[]'");
|
|
56703
|
+
this.db.exec(`
|
|
56704
|
+
CREATE INDEX IF NOT EXISTS idx_memos_project_dir ON memos(project_dir);
|
|
56705
|
+
CREATE INDEX IF NOT EXISTS idx_memory_embeddings_created_at ON memory_embeddings(created_at DESC);
|
|
56706
|
+
`);
|
|
56709
56707
|
}
|
|
56710
56708
|
async migrateFromJsonl() {
|
|
56711
56709
|
const markerPath = join$1(this.projectDir, "memory", SQLITE_MIGRATION_MARKER);
|
|
@@ -56871,14 +56869,44 @@ var MemoryMemoStore = class MemoryMemoStore {
|
|
|
56871
56869
|
/**
|
|
56872
56870
|
* Search memos by vector similarity. Returns memos sorted by cosine
|
|
56873
56871
|
* similarity (highest first). Falls back to empty if no embeddings exist.
|
|
56872
|
+
*
|
|
56873
|
+
* Performance notes:
|
|
56874
|
+
* - candidateLimit bounds the SQL query so we never load every embedding.
|
|
56875
|
+
* - recencyCutoffDays lets callers ignore very old memos.
|
|
56876
|
+
* - projectDir is pushed into the SQL JOIN so unrelated projects are not
|
|
56877
|
+
* considered at all.
|
|
56874
56878
|
*/
|
|
56875
56879
|
async searchByVector(queryEmbedding, options) {
|
|
56876
56880
|
await this.init();
|
|
56877
56881
|
if (this.db === void 0) return [];
|
|
56878
|
-
const rows = this.db.prepare("SELECT memory_id, embedding_json FROM memory_embeddings ORDER BY created_at DESC").all();
|
|
56879
|
-
if (rows.length === 0) return [];
|
|
56880
56882
|
const limit = options?.candidateLimit ?? 200;
|
|
56881
56883
|
const projectDir = options?.projectDir;
|
|
56884
|
+
const recencyCutoffDays = options?.recencyCutoffDays;
|
|
56885
|
+
const cutoffMs = recencyCutoffDays !== void 0 && recencyCutoffDays > 0 ? Date.now() - recencyCutoffDays * 24 * 60 * 60 * 1e3 : void 0;
|
|
56886
|
+
let rows;
|
|
56887
|
+
if (projectDir !== void 0) {
|
|
56888
|
+
const stmt = cutoffMs === void 0 ? this.db.prepare(`
|
|
56889
|
+
SELECT e.memory_id, e.embedding_json
|
|
56890
|
+
FROM memory_embeddings e
|
|
56891
|
+
JOIN memos m ON m.id = e.memory_id
|
|
56892
|
+
WHERE (m.project_dir = ? OR m.project_dir = '')
|
|
56893
|
+
ORDER BY e.created_at DESC
|
|
56894
|
+
LIMIT ?
|
|
56895
|
+
`) : this.db.prepare(`
|
|
56896
|
+
SELECT e.memory_id, e.embedding_json
|
|
56897
|
+
FROM memory_embeddings e
|
|
56898
|
+
JOIN memos m ON m.id = e.memory_id
|
|
56899
|
+
WHERE (m.project_dir = ? OR m.project_dir = '')
|
|
56900
|
+
AND e.created_at > ?
|
|
56901
|
+
ORDER BY e.created_at DESC
|
|
56902
|
+
LIMIT ?
|
|
56903
|
+
`);
|
|
56904
|
+
rows = cutoffMs === void 0 ? stmt.all(projectDir, limit) : stmt.all(projectDir, cutoffMs, limit);
|
|
56905
|
+
} else {
|
|
56906
|
+
const stmt = cutoffMs === void 0 ? this.db.prepare("SELECT memory_id, embedding_json FROM memory_embeddings ORDER BY created_at DESC LIMIT ?") : this.db.prepare("SELECT memory_id, embedding_json FROM memory_embeddings WHERE created_at > ? ORDER BY created_at DESC LIMIT ?");
|
|
56907
|
+
rows = cutoffMs === void 0 ? stmt.all(limit) : stmt.all(cutoffMs, limit);
|
|
56908
|
+
}
|
|
56909
|
+
if (rows.length === 0) return [];
|
|
56882
56910
|
const scored = [];
|
|
56883
56911
|
for (const row of rows) try {
|
|
56884
56912
|
const vec = new Float32Array(JSON.parse(row.embedding_json));
|
|
@@ -56893,13 +56921,10 @@ var MemoryMemoStore = class MemoryMemoStore {
|
|
|
56893
56921
|
const results = [];
|
|
56894
56922
|
for (const { id, score } of topScored) {
|
|
56895
56923
|
const row = this.db.prepare("SELECT * FROM memos WHERE id = ?").get(id);
|
|
56896
|
-
if (row !== void 0) {
|
|
56897
|
-
|
|
56898
|
-
|
|
56899
|
-
|
|
56900
|
-
score
|
|
56901
|
-
});
|
|
56902
|
-
}
|
|
56924
|
+
if (row !== void 0) results.push({
|
|
56925
|
+
memo: rowToMemo(row),
|
|
56926
|
+
score
|
|
56927
|
+
});
|
|
56903
56928
|
}
|
|
56904
56929
|
return results;
|
|
56905
56930
|
}
|
|
@@ -57622,6 +57647,28 @@ var MemoryEditTool = class {
|
|
|
57622
57647
|
//#region ../../packages/agent-core/src/tools/builtin/memory/memory-lookup.ts
|
|
57623
57648
|
const DEFAULT_LIMIT = 5;
|
|
57624
57649
|
const MAX_LIMIT = 20;
|
|
57650
|
+
const QUERY_EMBEDDING_CACHE_MAX_SIZE = 50;
|
|
57651
|
+
const QUERY_EMBEDDING_CACHE_TTL_MS = 6e4;
|
|
57652
|
+
const queryEmbeddingCache = /* @__PURE__ */ new Map();
|
|
57653
|
+
function getCachedQueryEmbedding(key) {
|
|
57654
|
+
const entry = queryEmbeddingCache.get(key);
|
|
57655
|
+
if (entry === void 0) return void 0;
|
|
57656
|
+
if (Date.now() > entry.expiresAt) {
|
|
57657
|
+
queryEmbeddingCache.delete(key);
|
|
57658
|
+
return;
|
|
57659
|
+
}
|
|
57660
|
+
return entry.vec;
|
|
57661
|
+
}
|
|
57662
|
+
function setCachedQueryEmbedding(key, vec) {
|
|
57663
|
+
if (queryEmbeddingCache.size >= QUERY_EMBEDDING_CACHE_MAX_SIZE) {
|
|
57664
|
+
const oldest = queryEmbeddingCache.keys().next().value;
|
|
57665
|
+
if (oldest !== void 0) queryEmbeddingCache.delete(oldest);
|
|
57666
|
+
}
|
|
57667
|
+
queryEmbeddingCache.set(key, {
|
|
57668
|
+
vec,
|
|
57669
|
+
expiresAt: Date.now() + QUERY_EMBEDDING_CACHE_TTL_MS
|
|
57670
|
+
});
|
|
57671
|
+
}
|
|
57625
57672
|
const DEFAULT_MIN_SCORE = .2;
|
|
57626
57673
|
const MemoryLookupInputSchema = z.object({
|
|
57627
57674
|
query: z.string().min(1).describe("Search query describing the current task, error, approach, or keywords to look up in the memory memo store."),
|
|
@@ -57671,11 +57718,19 @@ var MemoryLookupTool = class {
|
|
|
57671
57718
|
let vectorScores;
|
|
57672
57719
|
const engine = store.getEmbeddingEngine();
|
|
57673
57720
|
if (engine?.available && store.hasEmbeddings()) try {
|
|
57674
|
-
|
|
57675
|
-
if (
|
|
57676
|
-
const
|
|
57721
|
+
let queryVec = getCachedQueryEmbedding(query);
|
|
57722
|
+
if (queryVec === void 0) {
|
|
57723
|
+
const queryVecs = await engine.embedBatch([query]);
|
|
57724
|
+
if (queryVecs !== null && queryVecs.length > 0) {
|
|
57725
|
+
queryVec = queryVecs[0];
|
|
57726
|
+
setCachedQueryEmbedding(query, queryVec);
|
|
57727
|
+
}
|
|
57728
|
+
}
|
|
57729
|
+
if (queryVec !== void 0) {
|
|
57730
|
+
const vectorResults = await store.searchByVector(queryVec, {
|
|
57677
57731
|
candidateLimit,
|
|
57678
|
-
projectDir
|
|
57732
|
+
projectDir,
|
|
57733
|
+
recencyCutoffDays: 90
|
|
57679
57734
|
});
|
|
57680
57735
|
if (vectorResults.length > 0) vectorScores = new Map(vectorResults.map((r) => [r.memo.id, r.score]));
|
|
57681
57736
|
}
|
|
@@ -57780,7 +57835,7 @@ const SEVERITY_LABELS = [
|
|
|
57780
57835
|
"Information",
|
|
57781
57836
|
"Hint"
|
|
57782
57837
|
];
|
|
57783
|
-
const DEFAULT_REQUEST_TIMEOUT_MS
|
|
57838
|
+
const DEFAULT_REQUEST_TIMEOUT_MS = 12e4;
|
|
57784
57839
|
var LspClient = class {
|
|
57785
57840
|
command;
|
|
57786
57841
|
workspaceRoot;
|
|
@@ -57884,8 +57939,8 @@ var LspClient = class {
|
|
|
57884
57939
|
return new Promise((resolve, reject) => {
|
|
57885
57940
|
const timer = setTimeout(() => {
|
|
57886
57941
|
this.pending.delete(id);
|
|
57887
|
-
reject(/* @__PURE__ */ new Error(`LSP request '${method}' timed out after ${DEFAULT_REQUEST_TIMEOUT_MS
|
|
57888
|
-
}, DEFAULT_REQUEST_TIMEOUT_MS
|
|
57942
|
+
reject(/* @__PURE__ */ new Error(`LSP request '${method}' timed out after ${DEFAULT_REQUEST_TIMEOUT_MS}ms`));
|
|
57943
|
+
}, DEFAULT_REQUEST_TIMEOUT_MS);
|
|
57889
57944
|
this.pending.set(id, {
|
|
57890
57945
|
resolve,
|
|
57891
57946
|
reject,
|
|
@@ -67278,7 +67333,7 @@ var WolfPackTool = class {
|
|
|
67278
67333
|
};
|
|
67279
67334
|
} catch (error) {
|
|
67280
67335
|
let message;
|
|
67281
|
-
if (isAbortError$
|
|
67336
|
+
if (isAbortError$1(error)) message = "The subagent was stopped before it finished.";
|
|
67282
67337
|
else message = error instanceof Error ? error.message : String(error);
|
|
67283
67338
|
return {
|
|
67284
67339
|
item,
|
|
@@ -72254,7 +72309,7 @@ var GrepTool = class {
|
|
|
72254
72309
|
try {
|
|
72255
72310
|
rgPath = (await ensureRgPath({ signal })).path;
|
|
72256
72311
|
} catch (error) {
|
|
72257
|
-
if (isAbortError$
|
|
72312
|
+
if (isAbortError$1(error)) return {
|
|
72258
72313
|
isError: true,
|
|
72259
72314
|
output: "Grep aborted"
|
|
72260
72315
|
};
|
|
@@ -73833,7 +73888,6 @@ var EnterPlanModeTool = class {
|
|
|
73833
73888
|
output: `Failed to enter plan mode: ${error instanceof Error ? error.message : "Failed to enter plan mode."}`
|
|
73834
73889
|
};
|
|
73835
73890
|
}
|
|
73836
|
-
this.agent.telemetry.track("plan_enter_resolved", { outcome: "auto_approved" });
|
|
73837
73891
|
return { output: enteredPlanModeMessage(this.agent.planMode.planFilePath) };
|
|
73838
73892
|
}
|
|
73839
73893
|
};
|
|
@@ -73913,17 +73967,15 @@ var ExitPlanModeTool = class {
|
|
|
73913
73967
|
if (args.options !== void 0 && args.options.length >= 2) display.options = args.options;
|
|
73914
73968
|
return display;
|
|
73915
73969
|
}
|
|
73916
|
-
async execution(
|
|
73970
|
+
async execution(_args) {
|
|
73917
73971
|
if (!this.agent.planMode.isActive) return {
|
|
73918
73972
|
isError: true,
|
|
73919
73973
|
output: "ExitPlanMode can only be called while plan mode is active. Use EnterPlanMode (or /plan) first."
|
|
73920
73974
|
};
|
|
73921
73975
|
const resolvedPlan = await this.resolvePlan();
|
|
73922
73976
|
if (!resolvedPlan.ok) return resolvedPlan.error;
|
|
73923
|
-
this.agent.telemetry.track("plan_submitted", { has_options: args.options !== void 0 && args.options.length >= 2 });
|
|
73924
73977
|
const failed = this.exitPlanMode();
|
|
73925
73978
|
if (failed !== void 0) return failed;
|
|
73926
|
-
this.agent.telemetry.track("plan_resolved", { outcome: "auto_approved" });
|
|
73927
73979
|
return {
|
|
73928
73980
|
isError: false,
|
|
73929
73981
|
output: `Exited plan mode. ${formatPlanForOutput(resolvedPlan.plan, resolvedPlan.path)}`
|
|
@@ -74647,7 +74699,6 @@ var BackgroundManager = class extends BackgroundProcessManager {
|
|
|
74647
74699
|
type: "background.task.started",
|
|
74648
74700
|
info
|
|
74649
74701
|
});
|
|
74650
|
-
this.agent.telemetry.track("background_task_created", { kind: info.taskId.startsWith("agent-") ? "agent" : "bash" });
|
|
74651
74702
|
return;
|
|
74652
74703
|
case "updated":
|
|
74653
74704
|
this.agent.emitEvent({
|
|
@@ -74655,22 +74706,12 @@ var BackgroundManager = class extends BackgroundProcessManager {
|
|
|
74655
74706
|
info
|
|
74656
74707
|
});
|
|
74657
74708
|
return;
|
|
74658
|
-
case "terminated":
|
|
74709
|
+
case "terminated":
|
|
74659
74710
|
this.agent.emitEvent({
|
|
74660
74711
|
type: "background.task.terminated",
|
|
74661
74712
|
info
|
|
74662
74713
|
});
|
|
74663
|
-
const success = info.status === "completed";
|
|
74664
|
-
const duration_s = info.endedAt !== null ? (info.endedAt - info.startedAt) / 1e3 : null;
|
|
74665
|
-
const properties = {
|
|
74666
|
-
kind: info.taskId.startsWith("agent-") ? "agent" : "bash",
|
|
74667
|
-
success,
|
|
74668
|
-
duration_s
|
|
74669
|
-
};
|
|
74670
|
-
if (!success) properties["reason"] = info.timedOut === true ? "timeout" : info.status === "killed" ? "killed" : "error";
|
|
74671
|
-
this.agent.telemetry.track("background_task_completed", properties);
|
|
74672
74714
|
return;
|
|
74673
|
-
}
|
|
74674
74715
|
}
|
|
74675
74716
|
});
|
|
74676
74717
|
}
|
|
@@ -74873,7 +74914,7 @@ async function chatWithRetry(input) {
|
|
|
74873
74914
|
}
|
|
74874
74915
|
}
|
|
74875
74916
|
function logRequestFailure(input, error, attempt, maxAttempts) {
|
|
74876
|
-
if (isAbortError$
|
|
74917
|
+
if (isAbortError$1(error) || input.params.signal.aborted) return;
|
|
74877
74918
|
input.log?.warn("llm request failed", {
|
|
74878
74919
|
turnStep: `${input.turnId}.${String(input.currentStep)}`,
|
|
74879
74920
|
attempt: `${String(attempt)}/${String(maxAttempts)}`,
|
|
@@ -75199,8 +75240,6 @@ var FullCompaction = class {
|
|
|
75199
75240
|
});
|
|
75200
75241
|
const active = {
|
|
75201
75242
|
abortController,
|
|
75202
|
-
startedAt: Date.now(),
|
|
75203
|
-
telemetryTrigger: compactionTelemetryTrigger(data.source, data.instruction),
|
|
75204
75243
|
promise: Promise.resolve(),
|
|
75205
75244
|
blockedByTurn: false
|
|
75206
75245
|
};
|
|
@@ -75299,13 +75338,11 @@ var FullCompaction = class {
|
|
|
75299
75338
|
signal.removeEventListener("abort", onAbort);
|
|
75300
75339
|
}
|
|
75301
75340
|
}
|
|
75302
|
-
async compactionWorker(signal, data,
|
|
75303
|
-
const startedAt = Date.now();
|
|
75341
|
+
async compactionWorker(signal, data, compactedCount) {
|
|
75304
75342
|
const originalHistory = [...this.agent.context.history];
|
|
75305
75343
|
const tokensBefore = estimateTokensForMessages(originalHistory);
|
|
75306
75344
|
let retryCount = 0;
|
|
75307
75345
|
try {
|
|
75308
|
-
let compactedCount = initialCompactedCount;
|
|
75309
75346
|
await this.triggerPreCompactHook(data, tokensBefore, signal);
|
|
75310
75347
|
const model = this.agent.config.model;
|
|
75311
75348
|
const delays = retryBackoffDelays(5);
|
|
@@ -75351,16 +75388,6 @@ var FullCompaction = class {
|
|
|
75351
75388
|
tokensBefore,
|
|
75352
75389
|
tokensAfter
|
|
75353
75390
|
};
|
|
75354
|
-
const active = this.compacting;
|
|
75355
|
-
this.agent.telemetry.track("compaction_finished", {
|
|
75356
|
-
trigger_type: active.telemetryTrigger,
|
|
75357
|
-
before_tokens: result.tokensBefore,
|
|
75358
|
-
after_tokens: result.tokensAfter,
|
|
75359
|
-
duration_ms: Date.now() - active.startedAt,
|
|
75360
|
-
compacted_count: result.compactedCount,
|
|
75361
|
-
retry_count: retryCount,
|
|
75362
|
-
...usage
|
|
75363
|
-
});
|
|
75364
75391
|
this.markCompleted();
|
|
75365
75392
|
this.agent.emitEvent({
|
|
75366
75393
|
type: "compaction.completed",
|
|
@@ -75371,7 +75398,7 @@ var FullCompaction = class {
|
|
|
75371
75398
|
this.triggerPostCompactHook(data, result);
|
|
75372
75399
|
this.consecutiveCompactionFailures = 0;
|
|
75373
75400
|
} catch (error) {
|
|
75374
|
-
if (!isAbortError$
|
|
75401
|
+
if (!isAbortError$1(error)) {
|
|
75375
75402
|
const blockedByTurn = this.compacting?.blockedByTurn === true;
|
|
75376
75403
|
this.consecutiveCompactionFailures += 1;
|
|
75377
75404
|
if (this.consecutiveCompactionFailures >= MAX_CONSECUTIVE_FAILURES) this.agent.emitEvent({
|
|
@@ -75391,13 +75418,6 @@ var FullCompaction = class {
|
|
|
75391
75418
|
...payload
|
|
75392
75419
|
});
|
|
75393
75420
|
}
|
|
75394
|
-
this.agent.telemetry.track("compaction_failed", {
|
|
75395
|
-
trigger_type: compactionTelemetryTrigger(data.source, data.instruction),
|
|
75396
|
-
before_tokens: tokensBefore,
|
|
75397
|
-
duration_ms: Date.now() - startedAt,
|
|
75398
|
-
retry_count: retryCount,
|
|
75399
|
-
error_type: error instanceof Error ? error.name : "Unknown"
|
|
75400
|
-
});
|
|
75401
75421
|
if (blockedByTurn) {
|
|
75402
75422
|
if (isScreamError(error) && error.code === ErrorCodes.AUTH_LOGIN_REQUIRED) throw error;
|
|
75403
75423
|
throw new ScreamError(ErrorCodes.COMPACTION_FAILED, String(error), { cause: error });
|
|
@@ -75479,11 +75499,6 @@ function extractCompactionSummary(response) {
|
|
|
75479
75499
|
return summary;
|
|
75480
75500
|
}
|
|
75481
75501
|
const COMPACTION_INSTRUCTION = (customInstruction = "") => renderPrompt(compaction_instruction_default, { customInstruction });
|
|
75482
|
-
function compactionTelemetryTrigger(trigger, instruction) {
|
|
75483
|
-
if (trigger === void 0) return "unknown";
|
|
75484
|
-
if (trigger === "manual" && instruction !== void 0 && instruction.length > 0) return "manual-with-prompt";
|
|
75485
|
-
return trigger;
|
|
75486
|
-
}
|
|
75487
75502
|
//#endregion
|
|
75488
75503
|
//#region ../../packages/agent-core/src/agent/compaction/micro.ts
|
|
75489
75504
|
const DEFAULT_CONFIG = {
|
|
@@ -75560,20 +75575,8 @@ var MicroCompaction = class {
|
|
|
75560
75575
|
const maxContextTokens = this.agent.config.modelCapabilities.max_context_tokens;
|
|
75561
75576
|
const contextTokens = this.agent.context.tokenCountWithPending;
|
|
75562
75577
|
if ((maxContextTokens !== void 0 && maxContextTokens > 0 ? contextTokens / maxContextTokens : 1) < config.minContextUsageRatio) return;
|
|
75563
|
-
const previousCutoff = this.cutoff;
|
|
75564
75578
|
const nextCutoff = Math.max(0, history.length - config.keepRecentMessages);
|
|
75565
75579
|
this.apply(nextCutoff);
|
|
75566
|
-
if (previousCutoff !== nextCutoff) {
|
|
75567
|
-
const effect = this.measureEffect(history, nextCutoff);
|
|
75568
|
-
this.agent.telemetry.track("micro_compaction_applied", {
|
|
75569
|
-
previous_cutoff: previousCutoff,
|
|
75570
|
-
cutoff: nextCutoff,
|
|
75571
|
-
message_count: history.length,
|
|
75572
|
-
truncated_count: effect.truncatedToolResultCount,
|
|
75573
|
-
before_tokens: effect.beforeTokens,
|
|
75574
|
-
after_tokens: effect.afterTokens
|
|
75575
|
-
});
|
|
75576
|
-
}
|
|
75577
75580
|
}
|
|
75578
75581
|
/**
|
|
75579
75582
|
* Apply micro-compaction to a message list: replace old tool results
|
|
@@ -76127,13 +76130,6 @@ function createCronScheduler(opts) {
|
|
|
76127
76130
|
};
|
|
76128
76131
|
}
|
|
76129
76132
|
//#endregion
|
|
76130
|
-
//#region ../../packages/agent-core/src/tools/cron/telemetry-events.ts
|
|
76131
|
-
/** Telemetry event names emitted by the cron subsystem. Centralised so a typo can't drift a metric. */
|
|
76132
|
-
const CRON_SCHEDULED = "cron_scheduled";
|
|
76133
|
-
const CRON_FIRED = "cron_fired";
|
|
76134
|
-
const CRON_MISSED = "cron_missed";
|
|
76135
|
-
const CRON_DELETED = "cron_deleted";
|
|
76136
|
-
//#endregion
|
|
76137
76133
|
//#region ../../packages/agent-core/src/agent/cron/manager.ts
|
|
76138
76134
|
/**
|
|
76139
76135
|
* Threshold past which a recurring task is flagged `stale: true` on its
|
|
@@ -76234,7 +76230,7 @@ var CronManager = class {
|
|
|
76234
76230
|
* subset of ids that were actually present, matching
|
|
76235
76231
|
* `SessionCronStore.remove`'s contract — callers (CronDelete /
|
|
76236
76232
|
* scheduler one-shot cleanup / stale auto-expire) read this to
|
|
76237
|
-
* decide whether to emit
|
|
76233
|
+
* decide whether to emit a `cron.fired` event.
|
|
76238
76234
|
*
|
|
76239
76235
|
* Persistence failures are logged and swallowed; cross-resume the
|
|
76240
76236
|
* worst case is a ghost entry that gets dropped on the next
|
|
@@ -76381,14 +76377,13 @@ var CronManager = class {
|
|
|
76381
76377
|
return Number.isFinite(age) && age >= STALE_THRESHOLD_MS;
|
|
76382
76378
|
}
|
|
76383
76379
|
/**
|
|
76384
|
-
* Translate a scheduler fire into a steer
|
|
76380
|
+
* Translate a scheduler fire into a steer carrying a `cron_job` origin.
|
|
76385
76381
|
*
|
|
76386
76382
|
* `agent.turn.steer` returns the new turnId, or `null` when the input
|
|
76387
76383
|
* was buffered because a turn is in flight (see turn/index.ts:84).
|
|
76388
|
-
* We propagate that as `buffered` on the
|
|
76384
|
+
* We propagate that as `buffered` on the origin so the rendered envelope
|
|
76389
76385
|
* can distinguish "fired into a fresh turn" from "fired into a steer
|
|
76390
76386
|
* buffer that may not run until the user's turn ends".
|
|
76391
|
-
*
|
|
76392
76387
|
* Honours the documented 7-day auto-expire contract for recurring
|
|
76393
76388
|
* tasks: a stale recurring task gets exactly one final delivery
|
|
76394
76389
|
* (already issued above) and is then removed from the store. The
|
|
@@ -76411,22 +76406,13 @@ var CronManager = class {
|
|
|
76411
76406
|
type: "text",
|
|
76412
76407
|
text: renderCronFireXml(origin, task.prompt)
|
|
76413
76408
|
}];
|
|
76414
|
-
|
|
76409
|
+
this.agent.turn.steer(content, origin);
|
|
76415
76410
|
this.agent.emitEvent?.({
|
|
76416
76411
|
type: "cron.fired",
|
|
76417
76412
|
origin,
|
|
76418
76413
|
prompt: task.prompt
|
|
76419
76414
|
});
|
|
76420
|
-
this.
|
|
76421
|
-
recurring: task.recurring !== false,
|
|
76422
|
-
coalesced_count: ctx.coalescedCount,
|
|
76423
|
-
stale,
|
|
76424
|
-
buffered: turnId === null
|
|
76425
|
-
});
|
|
76426
|
-
if (stale && task.recurring !== false) {
|
|
76427
|
-
this.removeTasks([task.id]);
|
|
76428
|
-
this.emitDeleted(task.id);
|
|
76429
|
-
}
|
|
76415
|
+
if (stale && task.recurring !== false) this.removeTasks([task.id]);
|
|
76430
76416
|
}
|
|
76431
76417
|
/**
|
|
76432
76418
|
* Reserved hook for an explicit "you missed N fires while offline"
|
|
@@ -76455,26 +76441,6 @@ var CronManager = class {
|
|
|
76455
76441
|
count: tasks.length
|
|
76456
76442
|
};
|
|
76457
76443
|
this.agent.turn.steer(content, origin);
|
|
76458
|
-
this.agent.telemetry.track(CRON_MISSED, { count: tasks.length });
|
|
76459
|
-
}
|
|
76460
|
-
/**
|
|
76461
|
-
* Emit `cron_scheduled` for a freshly-added task. Called by
|
|
76462
|
-
* `CronCreate` after a successful `store.add(...)`. Kept as an
|
|
76463
|
-
* explicit method so the tool layer never reaches into
|
|
76464
|
-
* `manager.agent.telemetry` — preserves the "tools see the manager,
|
|
76465
|
-
* the manager sees the agent" layering and matches the symmetric
|
|
76466
|
-
* `emitDeleted` used by `CronDelete` (P1.6).
|
|
76467
|
-
*/
|
|
76468
|
-
emitScheduled(task) {
|
|
76469
|
-
this.agent.telemetry.track(CRON_SCHEDULED, { recurring: task.recurring !== false });
|
|
76470
|
-
}
|
|
76471
|
-
/**
|
|
76472
|
-
* Emit `cron_deleted` for a removed task. Wired up here so P1.6 can
|
|
76473
|
-
* land without touching this file again. `task_id` matches the field
|
|
76474
|
-
* naming used elsewhere in the telemetry surface (snake_case).
|
|
76475
|
-
*/
|
|
76476
|
-
emitDeleted(taskId) {
|
|
76477
|
-
this.agent.telemetry.track(CRON_DELETED, { task_id: taskId });
|
|
76478
76444
|
}
|
|
76479
76445
|
/**
|
|
76480
76446
|
* Wire `SIGUSR1` to a manual `tick()` so bench scripts can advance the
|
|
@@ -76502,7 +76468,7 @@ var CronManager = class {
|
|
|
76502
76468
|
*
|
|
76503
76469
|
* The handler swallows any throw from `tick()` because a signal-driven
|
|
76504
76470
|
* bench tool must never crash the host process; the tick failure mode
|
|
76505
|
-
* is already surfaced via
|
|
76471
|
+
* is already surfaced via logs inside the scheduler.
|
|
76506
76472
|
* Set `SCREAM_CRON_DEBUG=1` to surface the swallowed error to stderr —
|
|
76507
76473
|
* mirrors `scheduler.ts`'s debugLog pattern so bench debugging can
|
|
76508
76474
|
* see a bad tick.
|
|
@@ -77938,7 +77904,6 @@ var ExitPlanModeReviewAskPermissionPolicy = class {
|
|
|
77938
77904
|
const display = context.execution.display;
|
|
77939
77905
|
if (display?.kind !== "plan_review") return;
|
|
77940
77906
|
if (display.plan.trim().length === 0) return;
|
|
77941
|
-
this.agent.telemetry.track("plan_submitted", { has_options: display.options !== void 0 && display.options.length >= 2 });
|
|
77942
77907
|
return {
|
|
77943
77908
|
kind: "ask",
|
|
77944
77909
|
reason: { has_options: display.options !== void 0 },
|
|
@@ -77957,11 +77922,6 @@ var ExitPlanModeReviewAskPermissionPolicy = class {
|
|
|
77957
77922
|
kind: "result",
|
|
77958
77923
|
syntheticResult: failed
|
|
77959
77924
|
};
|
|
77960
|
-
if (result.selectedLabel !== void 0 && result.selectedLabel.length > 0) this.agent.telemetry.track("plan_resolved", {
|
|
77961
|
-
outcome: "approved",
|
|
77962
|
-
chosen_option: result.selectedLabel
|
|
77963
|
-
});
|
|
77964
|
-
else this.agent.telemetry.track("plan_resolved", { outcome: "approved" });
|
|
77965
77925
|
return {
|
|
77966
77926
|
kind: "result",
|
|
77967
77927
|
syntheticResult: {
|
|
@@ -77971,7 +77931,6 @@ var ExitPlanModeReviewAskPermissionPolicy = class {
|
|
|
77971
77931
|
};
|
|
77972
77932
|
}
|
|
77973
77933
|
rejectedExitPlanModeApprovalResult(result) {
|
|
77974
|
-
this.trackRejectedPlanResolution(result);
|
|
77975
77934
|
if (result.decision === "cancelled") return {
|
|
77976
77935
|
kind: "result",
|
|
77977
77936
|
syntheticResult: {
|
|
@@ -78014,25 +77973,6 @@ var ExitPlanModeReviewAskPermissionPolicy = class {
|
|
|
78014
77973
|
};
|
|
78015
77974
|
}
|
|
78016
77975
|
}
|
|
78017
|
-
trackRejectedPlanResolution(result) {
|
|
78018
|
-
if (result.decision === "cancelled") {
|
|
78019
|
-
this.agent.telemetry.track("plan_resolved", { outcome: "dismissed" });
|
|
78020
|
-
return;
|
|
78021
|
-
}
|
|
78022
|
-
if (result.selectedLabel === "Reject and Exit") {
|
|
78023
|
-
this.agent.telemetry.track("plan_resolved", { outcome: "rejected_and_exited" });
|
|
78024
|
-
return;
|
|
78025
|
-
}
|
|
78026
|
-
const feedback = result.feedback ?? "";
|
|
78027
|
-
if (result.selectedLabel === "Revise" || feedback.length > 0) {
|
|
78028
|
-
this.agent.telemetry.track("plan_resolved", {
|
|
78029
|
-
outcome: "revise",
|
|
78030
|
-
has_feedback: feedback.length > 0
|
|
78031
|
-
});
|
|
78032
|
-
return;
|
|
78033
|
-
}
|
|
78034
|
-
this.agent.telemetry.track("plan_resolved", { outcome: "rejected" });
|
|
78035
|
-
}
|
|
78036
77976
|
};
|
|
78037
77977
|
function selectedExitPlanModeOption(options, label) {
|
|
78038
77978
|
if (options === void 0 || label === void 0) return;
|
|
@@ -78289,10 +78229,10 @@ function writesOnlyPlanFile(context, planFilePath) {
|
|
|
78289
78229
|
//#endregion
|
|
78290
78230
|
//#region ../../packages/agent-core/src/agent/turn/canonical-args.ts
|
|
78291
78231
|
/**
|
|
78292
|
-
* JSON canonicalization used by tool-call
|
|
78232
|
+
* JSON canonicalization used by tool-call deduplication.
|
|
78293
78233
|
* Recursively sorts object keys so semantically-equal args produce identical keys.
|
|
78294
78234
|
*/
|
|
78295
|
-
function
|
|
78235
|
+
function canonicalDedupArgs(args) {
|
|
78296
78236
|
return JSON.stringify(sortJsonValue(args)) ?? String(args);
|
|
78297
78237
|
}
|
|
78298
78238
|
function sortJsonValue(value) {
|
|
@@ -78628,13 +78568,6 @@ var PermissionManager = class {
|
|
|
78628
78568
|
async beforeToolCall(context) {
|
|
78629
78569
|
const evaluation = await this.evaluatePolicies(context);
|
|
78630
78570
|
if (evaluation === void 0) return void 0;
|
|
78631
|
-
this.agent.telemetry.track("permission_policy_decision", {
|
|
78632
|
-
policy_name: evaluation.policyName,
|
|
78633
|
-
tool_name: context.toolCall.name,
|
|
78634
|
-
permission_mode: this.mode,
|
|
78635
|
-
decision: evaluation.result.kind,
|
|
78636
|
-
...evaluation.result.reason
|
|
78637
|
-
});
|
|
78638
78571
|
return this.permissionPolicyResolutionToPrepare(evaluation.result, context, evaluation.policyName);
|
|
78639
78572
|
}
|
|
78640
78573
|
async requestToolApproval(context, result, policyName) {
|
|
@@ -78680,16 +78613,6 @@ var PermissionManager = class {
|
|
|
78680
78613
|
response = await Promise.race([customPromise, timeoutPromise]);
|
|
78681
78614
|
} catch (error) {
|
|
78682
78615
|
this.pendingApprovals.delete(approvalId);
|
|
78683
|
-
this.agent.telemetry.track("permission_approval_result", {
|
|
78684
|
-
policy_name: policyName ?? null,
|
|
78685
|
-
tool_name: name,
|
|
78686
|
-
permission_mode: this.mode,
|
|
78687
|
-
result: "error",
|
|
78688
|
-
approval_surface: display.kind,
|
|
78689
|
-
duration_ms: Date.now() - startedAt,
|
|
78690
|
-
session_cache_written: false,
|
|
78691
|
-
has_feedback: false
|
|
78692
|
-
});
|
|
78693
78616
|
const resolved = result.resolveError?.(error);
|
|
78694
78617
|
return await (resolved === void 0 ? Promise.reject(error) : this.permissionPolicyResolutionToPrepare(resolved, context, policyName));
|
|
78695
78618
|
} finally {
|
|
@@ -78705,16 +78628,6 @@ var PermissionManager = class {
|
|
|
78705
78628
|
sessionApprovalRule,
|
|
78706
78629
|
result: response
|
|
78707
78630
|
});
|
|
78708
|
-
this.agent.telemetry.track("permission_approval_result", {
|
|
78709
|
-
policy_name: policyName ?? null,
|
|
78710
|
-
tool_name: name,
|
|
78711
|
-
permission_mode: this.mode,
|
|
78712
|
-
result: response.decision === "approved" && response.scope === "session" ? "approved_for_session" : response.decision,
|
|
78713
|
-
approval_surface: display.kind,
|
|
78714
|
-
duration_ms: Date.now() - startedAt,
|
|
78715
|
-
session_cache_written: sessionApprovalRule !== void 0,
|
|
78716
|
-
has_feedback: response.feedback !== void 0 && response.feedback.length > 0
|
|
78717
|
-
});
|
|
78718
78631
|
const resolved = result.resolveApproval?.(response);
|
|
78719
78632
|
if (resolved !== void 0) return this.permissionPolicyResolutionToPrepare(resolved, context, policyName);
|
|
78720
78633
|
if (response.decision === "approved") return;
|
|
@@ -79894,11 +79807,6 @@ var SkillManager = class {
|
|
|
79894
79807
|
skillPath: origin.skillPath,
|
|
79895
79808
|
skillSource: origin.skillSource
|
|
79896
79809
|
});
|
|
79897
|
-
this.agent.telemetry.track("skill_invoked", {
|
|
79898
|
-
skill_name: origin.skillName,
|
|
79899
|
-
trigger: origin.trigger
|
|
79900
|
-
});
|
|
79901
|
-
if (origin.skillType === "flow") this.agent.telemetry.track("flow_invoked", { flow_name: origin.skillName });
|
|
79902
79810
|
if (input !== void 0) this.agent.turn.prompt(input, origin);
|
|
79903
79811
|
}
|
|
79904
79812
|
};
|
|
@@ -87679,7 +87587,7 @@ async function runPrepareToolExecutionHook(step, call) {
|
|
|
87679
87587
|
llm
|
|
87680
87588
|
});
|
|
87681
87589
|
} catch (error) {
|
|
87682
|
-
if (isAbortError$
|
|
87590
|
+
if (isAbortError$1(error) || signal.aborted) return {
|
|
87683
87591
|
kind: "hookFailed",
|
|
87684
87592
|
args,
|
|
87685
87593
|
output: `Tool "${call.toolName}" was aborted during prepareToolExecution hook`
|
|
@@ -87722,7 +87630,7 @@ async function runAuthorizeToolExecutionHook(step, call, args, execution) {
|
|
|
87722
87630
|
llm
|
|
87723
87631
|
});
|
|
87724
87632
|
} catch (error) {
|
|
87725
|
-
if (isAbortError$
|
|
87633
|
+
if (isAbortError$1(error) || signal.aborted) return {
|
|
87726
87634
|
block: true,
|
|
87727
87635
|
reason: `Tool "${call.toolName}" was aborted during authorizeToolExecution hook`
|
|
87728
87636
|
};
|
|
@@ -87749,7 +87657,7 @@ async function runRunnableToolCall(step, call, effectiveArgs, metadata, executio
|
|
|
87749
87657
|
try {
|
|
87750
87658
|
toolResult = coerceToolResult(await executeTool(step, execution, toolCall, toolName, metadata), toolName);
|
|
87751
87659
|
} catch (error) {
|
|
87752
|
-
const aborted = isAbortError$
|
|
87660
|
+
const aborted = isAbortError$1(error) || signal.aborted;
|
|
87753
87661
|
if (!aborted) step.log?.warn("tool execution failed", {
|
|
87754
87662
|
toolName,
|
|
87755
87663
|
toolCallId: toolCall.id,
|
|
@@ -87781,7 +87689,7 @@ async function finalizePendingToolResult(step, pendingResult) {
|
|
|
87781
87689
|
result: normalizeToolResult(effectiveResult)
|
|
87782
87690
|
};
|
|
87783
87691
|
} catch (error) {
|
|
87784
|
-
const aborted = isAbortError$
|
|
87692
|
+
const aborted = isAbortError$1(error) || signal.aborted;
|
|
87785
87693
|
if (!aborted) step.log?.warn("finalizeToolResult hook failed", {
|
|
87786
87694
|
toolName: pendingResult.toolName,
|
|
87787
87695
|
toolCallId: pendingResult.toolCall.id,
|
|
@@ -88135,7 +88043,7 @@ async function runTurn(input) {
|
|
|
88135
88043
|
}))?.continue) break;
|
|
88136
88044
|
}
|
|
88137
88045
|
} catch (error) {
|
|
88138
|
-
if (isAbortError$
|
|
88046
|
+
if (isAbortError$1(error) || signal.aborted) {
|
|
88139
88047
|
dispatchEvent(makeInterruptedEvent("aborted", steps, activeStep));
|
|
88140
88048
|
return {
|
|
88141
88049
|
stopReason: "aborted",
|
|
@@ -92970,7 +92878,7 @@ var ToolManager = class {
|
|
|
92970
92878
|
//#region ../../packages/agent-core/src/agent/turn/tool-dedup.ts
|
|
92971
92879
|
const REMINDER_TEXT_1 = "\n\n<system-reminder>\nYou are repeating the exact same tool call with identical parameters. Please carefully analyze the previous result. If the task is not yet complete, try a different method or parameters instead of repeating the same call.\n</system-reminder>";
|
|
92972
92880
|
function makeReminderText2(toolName, repeatCount, args) {
|
|
92973
|
-
const argsStr =
|
|
92881
|
+
const argsStr = canonicalDedupArgs(args);
|
|
92974
92882
|
return `
|
|
92975
92883
|
|
|
92976
92884
|
<system-reminder>
|
|
@@ -92990,7 +92898,7 @@ function makeDeferred() {
|
|
|
92990
92898
|
};
|
|
92991
92899
|
}
|
|
92992
92900
|
function makeKey(toolName, args) {
|
|
92993
|
-
return `${toolName} ${
|
|
92901
|
+
return `${toolName} ${canonicalDedupArgs(args)}`;
|
|
92994
92902
|
}
|
|
92995
92903
|
function appendReminder(result, reminderText) {
|
|
92996
92904
|
const output = result.output;
|
|
@@ -93187,13 +93095,7 @@ var TurnFlow = class {
|
|
|
93187
93095
|
steerBuffer = [];
|
|
93188
93096
|
turnId = -1;
|
|
93189
93097
|
activeTurn = null;
|
|
93190
|
-
toolCallStartedAt = /* @__PURE__ */ new Map();
|
|
93191
|
-
toolCallDupType = /* @__PURE__ */ new Map();
|
|
93192
|
-
stepToolCallKeys = /* @__PURE__ */ new Map();
|
|
93193
|
-
telemetryModeByTurn = /* @__PURE__ */ new Map();
|
|
93194
93098
|
currentStepByTurn = /* @__PURE__ */ new Map();
|
|
93195
|
-
interruptedTelemetryTurnIds = /* @__PURE__ */ new Set();
|
|
93196
|
-
stepFailureByTurn = /* @__PURE__ */ new Map();
|
|
93197
93099
|
currentStep = 0;
|
|
93198
93100
|
constructor(agent) {
|
|
93199
93101
|
this.agent = agent;
|
|
@@ -93385,13 +93287,8 @@ var TurnFlow = class {
|
|
|
93385
93287
|
*/
|
|
93386
93288
|
async runOneTurn(turnId, input, origin, signal, standalone) {
|
|
93387
93289
|
this.currentStep = 0;
|
|
93388
|
-
this.stepToolCallKeys.clear();
|
|
93389
|
-
this.toolCallDupType.clear();
|
|
93390
93290
|
this.agent.workingSet.decay(turnId);
|
|
93391
|
-
const telemetryMode = this.telemetryMode();
|
|
93392
|
-
this.telemetryModeByTurn.set(turnId, telemetryMode);
|
|
93393
93291
|
this.currentStepByTurn.set(turnId, 0);
|
|
93394
|
-
this.agent.telemetry.track("turn_started", { mode: telemetryMode });
|
|
93395
93292
|
this.agent.fullCompaction.resetForTurn();
|
|
93396
93293
|
this.agent.injection.resetForTurn();
|
|
93397
93294
|
this.agent.usage.beginTurn();
|
|
@@ -93401,7 +93298,6 @@ var TurnFlow = class {
|
|
|
93401
93298
|
origin
|
|
93402
93299
|
});
|
|
93403
93300
|
this.agent.context.appendUserMessage(input, origin);
|
|
93404
|
-
const startedAt = Date.now();
|
|
93405
93301
|
let ended;
|
|
93406
93302
|
let completedStopReason;
|
|
93407
93303
|
let errorEvent;
|
|
@@ -93418,7 +93314,7 @@ var TurnFlow = class {
|
|
|
93418
93314
|
};
|
|
93419
93315
|
}
|
|
93420
93316
|
} catch (error) {
|
|
93421
|
-
if (isAbortError$
|
|
93317
|
+
if (isAbortError$1(error)) ended = {
|
|
93422
93318
|
type: "turn.ended",
|
|
93423
93319
|
turnId,
|
|
93424
93320
|
reason: "cancelled"
|
|
@@ -93443,30 +93339,13 @@ var TurnFlow = class {
|
|
|
93443
93339
|
type: "error",
|
|
93444
93340
|
...summary
|
|
93445
93341
|
};
|
|
93446
|
-
if (this.shouldTrackApiError(turnId)) {
|
|
93447
|
-
const classification = classifyApiError(error, summary);
|
|
93448
|
-
const properties = {
|
|
93449
|
-
error_type: classification.errorType,
|
|
93450
|
-
model: this.agent.config.model,
|
|
93451
|
-
retryable: summary.retryable,
|
|
93452
|
-
duration_ms: Date.now() - startedAt
|
|
93453
|
-
};
|
|
93454
|
-
if (classification.statusCode !== void 0) properties["status_code"] = classification.statusCode;
|
|
93455
|
-
const inputTokens = currentTurnInputTokens(this.agent.usage.data().currentTurn);
|
|
93456
|
-
if (inputTokens !== void 0) properties["input_tokens"] = inputTokens;
|
|
93457
|
-
this.agent.telemetry.track("api_error", properties);
|
|
93458
|
-
}
|
|
93459
93342
|
}
|
|
93460
93343
|
}
|
|
93461
93344
|
if (this.currentId === turnId) this.agent.usage.endTurn();
|
|
93462
93345
|
this.agent.emitEvent(ended);
|
|
93463
93346
|
if (standalone && this.currentId === turnId) this.activeTurn = null;
|
|
93464
93347
|
if (errorEvent !== void 0) this.agent.emitEvent(errorEvent);
|
|
93465
|
-
if (ended.reason !== "completed") this.trackTurnInterrupted(turnId, this.currentStepByTurn.get(turnId) ?? this.currentStep);
|
|
93466
|
-
this.telemetryModeByTurn.delete(turnId);
|
|
93467
93348
|
this.currentStepByTurn.delete(turnId);
|
|
93468
|
-
this.interruptedTelemetryTurnIds.delete(turnId);
|
|
93469
|
-
this.stepFailureByTurn.delete(turnId);
|
|
93470
93349
|
return {
|
|
93471
93350
|
event: ended,
|
|
93472
93351
|
stopReason: completedStopReason
|
|
@@ -93650,94 +93529,21 @@ var TurnFlow = class {
|
|
|
93650
93529
|
this.agent.context.appendLoopEvent(event);
|
|
93651
93530
|
},
|
|
93652
93531
|
emitLiveEvent: (event) => {
|
|
93653
|
-
this.
|
|
93532
|
+
this.updateCurrentStepFromLoopEvent(event, turnId);
|
|
93654
93533
|
const mapped = mapLoopEvent(event, turnId);
|
|
93655
93534
|
if (mapped !== void 0) this.agent.emitEvent(mapped);
|
|
93656
93535
|
}
|
|
93657
93536
|
});
|
|
93658
93537
|
}
|
|
93659
|
-
|
|
93538
|
+
updateCurrentStepFromLoopEvent(event, turnId) {
|
|
93660
93539
|
if (event.type === "step.begin") {
|
|
93661
93540
|
this.beginTrackedStep(turnId, event.step);
|
|
93662
93541
|
return;
|
|
93663
93542
|
}
|
|
93664
|
-
if (event.type === "turn.interrupted") {
|
|
93665
|
-
if (event.reason === "error" && event.activeStep !== void 0) this.stepFailureByTurn.set(turnId, event);
|
|
93666
|
-
this.trackTurnInterrupted(turnId, interruptedStep(event));
|
|
93667
|
-
return;
|
|
93668
|
-
}
|
|
93669
|
-
this.trackToolLifecycle(event, turnId);
|
|
93670
93543
|
}
|
|
93671
93544
|
beginTrackedStep(turnId, step) {
|
|
93672
93545
|
this.currentStepByTurn.set(turnId, step);
|
|
93673
93546
|
this.currentStep = step;
|
|
93674
|
-
if (!this.stepToolCallKeys.has(step)) this.stepToolCallKeys.set(step, /* @__PURE__ */ new Set());
|
|
93675
|
-
}
|
|
93676
|
-
trackToolLifecycle(event, turnId) {
|
|
93677
|
-
if (event.type === "tool.call") {
|
|
93678
|
-
const dupType = this.trackDuplicateToolCall(turnId, event.step, event.name, event.args);
|
|
93679
|
-
this.toolCallDupType.set(event.toolCallId, dupType === "cross_step" ? "cross_step" : "normal");
|
|
93680
|
-
this.toolCallStartedAt.set(event.toolCallId, {
|
|
93681
|
-
name: event.name,
|
|
93682
|
-
startedAt: Date.now()
|
|
93683
|
-
});
|
|
93684
|
-
return;
|
|
93685
|
-
}
|
|
93686
|
-
if (event.type === "tool.result") {
|
|
93687
|
-
const started = this.toolCallStartedAt.get(event.toolCallId);
|
|
93688
|
-
if (started === void 0) return;
|
|
93689
|
-
this.toolCallStartedAt.delete(event.toolCallId);
|
|
93690
|
-
const dupType = this.toolCallDupType.get(event.toolCallId) ?? "normal";
|
|
93691
|
-
this.toolCallDupType.delete(event.toolCallId);
|
|
93692
|
-
const outcome = telemetryToolOutcome(event.result);
|
|
93693
|
-
const properties = {
|
|
93694
|
-
tool_name: started.name,
|
|
93695
|
-
outcome,
|
|
93696
|
-
duration_ms: Date.now() - started.startedAt,
|
|
93697
|
-
dup_type: dupType
|
|
93698
|
-
};
|
|
93699
|
-
const errorType = outcome === "error" ? telemetryToolErrorType(event.result) : void 0;
|
|
93700
|
-
if (errorType !== void 0) properties["error_type"] = errorType;
|
|
93701
|
-
this.agent.telemetry.track("tool_call", properties);
|
|
93702
|
-
}
|
|
93703
|
-
}
|
|
93704
|
-
trackDuplicateToolCall(turnId, step, toolName, args) {
|
|
93705
|
-
const argsText = canonicalTelemetryArgs(args);
|
|
93706
|
-
const key = `${toolName}\u0000${argsText}`;
|
|
93707
|
-
const stepKeys = this.stepToolCallKeys.get(step) ?? /* @__PURE__ */ new Set();
|
|
93708
|
-
this.stepToolCallKeys.set(step, stepKeys);
|
|
93709
|
-
let dupType;
|
|
93710
|
-
if (stepKeys.has(key)) dupType = "same_step";
|
|
93711
|
-
else if (this.hasPriorStepToolCallKey(step, key)) dupType = "cross_step";
|
|
93712
|
-
stepKeys.add(key);
|
|
93713
|
-
if (dupType === void 0) return "normal";
|
|
93714
|
-
this.agent.telemetry.track("tool_call_dedup_detected", {
|
|
93715
|
-
turn_id: turnId,
|
|
93716
|
-
step_no: step,
|
|
93717
|
-
tool_name: toolName,
|
|
93718
|
-
dup_type: dupType,
|
|
93719
|
-
args_hash: createHash("sha256").update(argsText).digest("hex").slice(0, 8)
|
|
93720
|
-
});
|
|
93721
|
-
return dupType;
|
|
93722
|
-
}
|
|
93723
|
-
hasPriorStepToolCallKey(step, key) {
|
|
93724
|
-
for (const [seenStep, keys] of this.stepToolCallKeys) if (seenStep !== step && keys.has(key)) return true;
|
|
93725
|
-
return false;
|
|
93726
|
-
}
|
|
93727
|
-
trackTurnInterrupted(turnId, atStep) {
|
|
93728
|
-
if (this.interruptedTelemetryTurnIds.has(turnId)) return;
|
|
93729
|
-
this.interruptedTelemetryTurnIds.add(turnId);
|
|
93730
|
-
this.agent.telemetry.track("turn_interrupted", {
|
|
93731
|
-
mode: this.telemetryModeByTurn.get(turnId) ?? this.telemetryMode(),
|
|
93732
|
-
at_step: atStep
|
|
93733
|
-
});
|
|
93734
|
-
}
|
|
93735
|
-
telemetryMode() {
|
|
93736
|
-
return this.agent.planMode.isActive ? "plan" : "agent";
|
|
93737
|
-
}
|
|
93738
|
-
shouldTrackApiError(turnId) {
|
|
93739
|
-
const failure = this.stepFailureByTurn.get(turnId);
|
|
93740
|
-
return failure?.reason === "error" && failure.activeStep !== void 0;
|
|
93741
93547
|
}
|
|
93742
93548
|
};
|
|
93743
93549
|
function mapLoopEvent(event, turnId) {
|
|
@@ -93842,7 +93648,7 @@ function summarizeTurnError(error, turnId) {
|
|
|
93842
93648
|
};
|
|
93843
93649
|
}
|
|
93844
93650
|
function toolInputRecord(args) {
|
|
93845
|
-
return
|
|
93651
|
+
return typeof args === "object" && args !== null && !Array.isArray(args) ? args : {};
|
|
93846
93652
|
}
|
|
93847
93653
|
function toolOutputText(output) {
|
|
93848
93654
|
if (typeof output === "string") return output;
|
|
@@ -93850,90 +93656,6 @@ function toolOutputText(output) {
|
|
|
93850
93656
|
return typeof part === "object" && part !== null && part.type === "text";
|
|
93851
93657
|
}).map((part) => part.text).join("");
|
|
93852
93658
|
}
|
|
93853
|
-
function interruptedStep(event) {
|
|
93854
|
-
return event.activeStep ?? event.attemptedSteps;
|
|
93855
|
-
}
|
|
93856
|
-
function classifyApiError(error, summary) {
|
|
93857
|
-
const statusCode = apiStatusCode(error) ?? summaryStatusCode(summary);
|
|
93858
|
-
if (statusCode !== void 0) {
|
|
93859
|
-
if (statusCode === 429) return {
|
|
93860
|
-
errorType: "rate_limit",
|
|
93861
|
-
statusCode
|
|
93862
|
-
};
|
|
93863
|
-
if (statusCode === 401 || statusCode === 403) return {
|
|
93864
|
-
errorType: "auth",
|
|
93865
|
-
statusCode
|
|
93866
|
-
};
|
|
93867
|
-
if (statusCode >= 500) return {
|
|
93868
|
-
errorType: "5xx_server",
|
|
93869
|
-
statusCode
|
|
93870
|
-
};
|
|
93871
|
-
if (isContextOverflowStatusError(statusCode, summary.message)) return {
|
|
93872
|
-
errorType: "context_overflow",
|
|
93873
|
-
statusCode
|
|
93874
|
-
};
|
|
93875
|
-
if (statusCode >= 400) return {
|
|
93876
|
-
errorType: "4xx_client",
|
|
93877
|
-
statusCode
|
|
93878
|
-
};
|
|
93879
|
-
return {
|
|
93880
|
-
errorType: "api",
|
|
93881
|
-
statusCode
|
|
93882
|
-
};
|
|
93883
|
-
}
|
|
93884
|
-
if (summary.code === ErrorCodes.PROVIDER_RATE_LIMIT) return { errorType: "rate_limit" };
|
|
93885
|
-
if (summary.code === ErrorCodes.PROVIDER_AUTH_ERROR) return { errorType: "auth" };
|
|
93886
|
-
if (summary.code === ErrorCodes.CONTEXT_OVERFLOW) return { errorType: "context_overflow" };
|
|
93887
|
-
if (isApiConnectionError(error, summary)) return { errorType: "network" };
|
|
93888
|
-
if (isApiTimeoutError(error, summary)) return { errorType: "timeout" };
|
|
93889
|
-
if (isApiEmptyResponseError(error, summary)) return { errorType: "empty_response" };
|
|
93890
|
-
return { errorType: "other" };
|
|
93891
|
-
}
|
|
93892
|
-
function apiStatusCode(error) {
|
|
93893
|
-
if (error instanceof APIStatusError) {
|
|
93894
|
-
const statusCode = error.statusCode;
|
|
93895
|
-
return typeof statusCode === "number" ? statusCode : void 0;
|
|
93896
|
-
}
|
|
93897
|
-
if (typeof error !== "object" || error === null) return void 0;
|
|
93898
|
-
const statusCode = error.statusCode;
|
|
93899
|
-
if (typeof statusCode === "number") return statusCode;
|
|
93900
|
-
const status = error.status;
|
|
93901
|
-
return typeof status === "number" ? status : void 0;
|
|
93902
|
-
}
|
|
93903
|
-
function summaryStatusCode(summary) {
|
|
93904
|
-
const statusCode = summary.details?.["statusCode"];
|
|
93905
|
-
return typeof statusCode === "number" ? statusCode : void 0;
|
|
93906
|
-
}
|
|
93907
|
-
function isApiConnectionError(error, summary) {
|
|
93908
|
-
return error instanceof APIConnectionError$3 || summary.name === "APIConnectionError";
|
|
93909
|
-
}
|
|
93910
|
-
function isApiTimeoutError(error, summary) {
|
|
93911
|
-
return error instanceof APITimeoutError || summary.name === "APITimeoutError" || summary.name === "TimeoutError";
|
|
93912
|
-
}
|
|
93913
|
-
function isApiEmptyResponseError(error, summary) {
|
|
93914
|
-
return error instanceof APIEmptyResponseError || summary.name === "APIEmptyResponseError";
|
|
93915
|
-
}
|
|
93916
|
-
function currentTurnInputTokens(usage) {
|
|
93917
|
-
if (usage === void 0) return void 0;
|
|
93918
|
-
return inputTotal(usage);
|
|
93919
|
-
}
|
|
93920
|
-
function telemetryToolOutcome(result) {
|
|
93921
|
-
if (result.isError !== true) return "success";
|
|
93922
|
-
const text = toolResultText(result).toLowerCase();
|
|
93923
|
-
return text.includes("aborted") || text.includes("cancelled") || text.includes("manually interrupted") ? "cancelled" : "error";
|
|
93924
|
-
}
|
|
93925
|
-
function telemetryToolErrorType(result) {
|
|
93926
|
-
const text = toolResultText(result);
|
|
93927
|
-
if (text.startsWith("Tool \"") && text.includes("\" not found")) return "ToolNotFound";
|
|
93928
|
-
if (text.startsWith("Invalid args for tool \"")) return "ToolInputError";
|
|
93929
|
-
if (text.includes("prepareToolExecution hook failed")) return "HookError";
|
|
93930
|
-
if (text.includes("finalizeToolResult hook failed")) return "HookError";
|
|
93931
|
-
if (text.includes("blocked")) return "ToolBlocked";
|
|
93932
|
-
return "ToolError";
|
|
93933
|
-
}
|
|
93934
|
-
function toolResultText(result) {
|
|
93935
|
-
return toolOutputText(result.output);
|
|
93936
|
-
}
|
|
93937
93659
|
/** Extract a short human-readable summary from tool arguments. */
|
|
93938
93660
|
function summarizeToolArgs(args) {
|
|
93939
93661
|
if (typeof args !== "object" || args === null) return "";
|
|
@@ -94233,7 +93955,6 @@ var Agent = class {
|
|
|
94233
93955
|
mcp;
|
|
94234
93956
|
hooks;
|
|
94235
93957
|
log;
|
|
94236
|
-
telemetry;
|
|
94237
93958
|
blobStore;
|
|
94238
93959
|
records;
|
|
94239
93960
|
fullCompaction;
|
|
@@ -94271,7 +93992,6 @@ var Agent = class {
|
|
|
94271
93992
|
this.mcp = options.mcp;
|
|
94272
93993
|
this.hooks = options.hookEngine;
|
|
94273
93994
|
this.log = options.log ?? log;
|
|
94274
|
-
this.telemetry = options.telemetry ?? noopTelemetryClient;
|
|
94275
93995
|
this.blobStore = options.homedir ? new BlobStore({ blobsDir: join$1(options.homedir, "blobs") }) : void 0;
|
|
94276
93996
|
this.records = new AgentRecords(this, options.persistence ?? (options.homedir ? new FileSystemAgentRecordPersistence(join$1(options.homedir, "wire.jsonl"), {
|
|
94277
93997
|
onError: (error) => {
|
|
@@ -94394,34 +94114,20 @@ var Agent = class {
|
|
|
94394
94114
|
this.turn.prompt(payload.input);
|
|
94395
94115
|
},
|
|
94396
94116
|
steer: (payload) => {
|
|
94397
|
-
this.telemetry.track("input_steer", { parts: payload.input.length });
|
|
94398
94117
|
this.turn.steer(payload.input);
|
|
94399
94118
|
},
|
|
94400
94119
|
cancel: (payload) => {
|
|
94401
|
-
if (this.turn.hasActiveTurn) this.telemetry.track("cancel", { from: "streaming" });
|
|
94402
94120
|
this.turn.cancel(payload.turnId);
|
|
94403
94121
|
},
|
|
94404
94122
|
setThinking: (payload) => {
|
|
94405
|
-
const wasEnabled = this.config.thinkingLevel !== "off";
|
|
94406
94123
|
this.config.update({ thinkingLevel: payload.level });
|
|
94407
|
-
const enabled = this.config.thinkingLevel !== "off";
|
|
94408
|
-
if (enabled !== wasEnabled) this.telemetry.track("thinking_toggle", { enabled });
|
|
94409
94124
|
},
|
|
94410
94125
|
setPermission: (payload) => {
|
|
94411
|
-
const wasYolo = this.permission.mode === "yolo";
|
|
94412
|
-
const wasAuto = this.permission.mode === "auto";
|
|
94413
94126
|
this.permission.setMode(payload.mode);
|
|
94414
|
-
const enabled = this.permission.mode === "yolo";
|
|
94415
|
-
if (enabled !== wasYolo) this.telemetry.track("yolo_toggle", { enabled });
|
|
94416
|
-
const afkEnabled = this.permission.mode === "auto";
|
|
94417
|
-
if (afkEnabled !== wasAuto) this.telemetry.track("afk_toggle", { enabled: afkEnabled });
|
|
94418
94127
|
},
|
|
94419
94128
|
setModel: (payload) => {
|
|
94420
94129
|
const resolved = this.modelProvider?.resolveProviderConfig(payload.model);
|
|
94421
|
-
if (this.config.modelAlias !== payload.model) {
|
|
94422
|
-
this.config.update({ modelAlias: payload.model });
|
|
94423
|
-
this.telemetry.track("model_switch", { model: payload.model });
|
|
94424
|
-
}
|
|
94130
|
+
if (this.config.modelAlias !== payload.model) this.config.update({ modelAlias: payload.model });
|
|
94425
94131
|
return {
|
|
94426
94132
|
model: payload.model,
|
|
94427
94133
|
providerName: resolved?.providerName
|
|
@@ -94450,7 +94156,6 @@ var Agent = class {
|
|
|
94450
94156
|
});
|
|
94451
94157
|
},
|
|
94452
94158
|
cancelCompaction: () => {
|
|
94453
|
-
if (this.fullCompaction.isCompacting) this.telemetry.track("cancel", { from: "compacting" });
|
|
94454
94159
|
this.fullCompaction.cancel();
|
|
94455
94160
|
},
|
|
94456
94161
|
registerTool: (payload) => {
|
|
@@ -94841,7 +94546,6 @@ const ScreamConfigSchema = z.object({
|
|
|
94841
94546
|
extraSkillDirs: z.array(z.string()).optional(),
|
|
94842
94547
|
loopControl: LoopControlSchema.optional(),
|
|
94843
94548
|
background: BackgroundConfigSchema.optional(),
|
|
94844
|
-
telemetry: z.boolean().optional(),
|
|
94845
94549
|
raw: z.record(z.string(), z.unknown()).optional()
|
|
94846
94550
|
});
|
|
94847
94551
|
const ProviderConfigPatchSchema = ProviderConfigSchema.partial();
|
|
@@ -94874,8 +94578,7 @@ const ScreamConfigPatchSchema = z.object({
|
|
|
94874
94578
|
mergeAllAvailableSkills: z.boolean().optional(),
|
|
94875
94579
|
extraSkillDirs: z.array(z.string()).optional(),
|
|
94876
94580
|
loopControl: LoopControlPatchSchema.optional(),
|
|
94877
|
-
background: BackgroundConfigPatchSchema.optional()
|
|
94878
|
-
telemetry: z.boolean().optional()
|
|
94581
|
+
background: BackgroundConfigPatchSchema.optional()
|
|
94879
94582
|
}).strict();
|
|
94880
94583
|
function getDefaultConfig() {
|
|
94881
94584
|
return { providers: {} };
|
|
@@ -95299,8 +95002,7 @@ function configToTomlData(config) {
|
|
|
95299
95002
|
"defaultPermissionMode",
|
|
95300
95003
|
"defaultPlanMode",
|
|
95301
95004
|
"mergeAllAvailableSkills",
|
|
95302
|
-
"extraSkillDirs"
|
|
95303
|
-
"telemetry"
|
|
95005
|
+
"extraSkillDirs"
|
|
95304
95006
|
]) setDefined(out, camelToSnake$1(key), config[key]);
|
|
95305
95007
|
setRecordSection(out, "providers", config.providers, providerToToml);
|
|
95306
95008
|
setRecordSection(out, "models", config.models, modelToToml);
|
|
@@ -99279,10 +98981,6 @@ var SessionSubagentHost = class {
|
|
|
99279
98981
|
description: options.description,
|
|
99280
98982
|
runInBackground: options.runInBackground
|
|
99281
98983
|
});
|
|
99282
|
-
parent.telemetry.track("subagent_created", {
|
|
99283
|
-
subagent_name: profileName,
|
|
99284
|
-
run_in_background: options.runInBackground
|
|
99285
|
-
});
|
|
99286
98984
|
try {
|
|
99287
98985
|
await prepareChild();
|
|
99288
98986
|
options.signal.throwIfAborted();
|
|
@@ -99391,7 +99089,6 @@ const BACKGROUND_KEEP_ALIVE_ON_EXIT_ENV = "SCREAM_CODE_BACKGROUND_KEEP_ALIVE_ON_
|
|
|
99391
99089
|
var Session$1 = class {
|
|
99392
99090
|
options;
|
|
99393
99091
|
rpc;
|
|
99394
|
-
telemetry;
|
|
99395
99092
|
skills;
|
|
99396
99093
|
agents = /* @__PURE__ */ new Map();
|
|
99397
99094
|
mcp;
|
|
@@ -99421,7 +99118,6 @@ var Session$1 = class {
|
|
|
99421
99118
|
cwd: options.jian.getcwd(),
|
|
99422
99119
|
sessionId: options.id
|
|
99423
99120
|
});
|
|
99424
|
-
this.telemetry = options.telemetry ?? noopTelemetryClient;
|
|
99425
99121
|
this.skills = new SkillRegistry({ sessionId: options.id });
|
|
99426
99122
|
this.mcp = new McpConnectionManager({
|
|
99427
99123
|
oauthService: new McpOAuthService({ screamHomeDir: options.screamHomeDir }),
|
|
@@ -99610,14 +99306,14 @@ var Session$1 = class {
|
|
|
99610
99306
|
const totalCount = entries.length;
|
|
99611
99307
|
if (totalCount === 0) return;
|
|
99612
99308
|
const connectedCount = entries.filter((entry) => entry.status === "connected").length;
|
|
99613
|
-
if (connectedCount > 0) this.
|
|
99614
|
-
|
|
99615
|
-
|
|
99309
|
+
if (connectedCount > 0) this.log.info("mcp servers connected", {
|
|
99310
|
+
connectedCount,
|
|
99311
|
+
totalCount
|
|
99616
99312
|
});
|
|
99617
99313
|
const failedCount = entries.filter((entry) => entry.status === "failed").length;
|
|
99618
|
-
if (failedCount > 0) this.
|
|
99619
|
-
|
|
99620
|
-
|
|
99314
|
+
if (failedCount > 0) this.log.warn("mcp servers failed", {
|
|
99315
|
+
failedCount,
|
|
99316
|
+
totalCount
|
|
99621
99317
|
});
|
|
99622
99318
|
}
|
|
99623
99319
|
emitInitialMcpLoadError(error) {
|
|
@@ -99669,7 +99365,6 @@ var Session$1 = class {
|
|
|
99669
99365
|
subagentHost: config.subagentHost ?? new SessionSubagentHost(this, id, this.backgroundTaskTimeoutMs()),
|
|
99670
99366
|
mcp: this.mcp,
|
|
99671
99367
|
permission: this.permissionOptions(parentAgentId, config.permission),
|
|
99672
|
-
telemetry: this.telemetry,
|
|
99673
99368
|
log: this.log.createChild({ agentId: id }),
|
|
99674
99369
|
pluginSessionStarts: type === "main" ? this.options.pluginSessionStarts : void 0
|
|
99675
99370
|
});
|
|
@@ -100954,6 +100649,50 @@ function isScreamNativeBinary() {
|
|
|
100954
100649
|
return !path$1.basename(process.execPath).toLowerCase().startsWith("node");
|
|
100955
100650
|
}
|
|
100956
100651
|
//#endregion
|
|
100652
|
+
//#region ../../packages/agent-core/src/tools/providers/fetch-cache.ts
|
|
100653
|
+
/**
|
|
100654
|
+
* Simple in-memory LRU cache for URL fetch results.
|
|
100655
|
+
*
|
|
100656
|
+
* The cache keeps up to `maxSize` entries. Entries older than `hardTtlMs`
|
|
100657
|
+
* are treated as a miss and evicted. Entries younger than `softTtlMs` are
|
|
100658
|
+
* returned directly; entries between soft and hard TTL are also returned
|
|
100659
|
+
* (no background refresh) because web content freshness is unpredictable
|
|
100660
|
+
* and a stale result is worse than a slightly older cached result for
|
|
100661
|
+
* agent tooling.
|
|
100662
|
+
*/
|
|
100663
|
+
var FetchCache = class {
|
|
100664
|
+
cache = /* @__PURE__ */ new Map();
|
|
100665
|
+
maxSize;
|
|
100666
|
+
hardTtlMs;
|
|
100667
|
+
constructor(options) {
|
|
100668
|
+
this.maxSize = options?.maxSize ?? 100;
|
|
100669
|
+
this.hardTtlMs = options?.hardTtlMs ?? 3600 * 1e3;
|
|
100670
|
+
}
|
|
100671
|
+
get(key) {
|
|
100672
|
+
const entry = this.cache.get(key);
|
|
100673
|
+
if (entry === void 0) return;
|
|
100674
|
+
if (Date.now() - entry.fetchedAt > this.hardTtlMs) {
|
|
100675
|
+
this.cache.delete(key);
|
|
100676
|
+
return;
|
|
100677
|
+
}
|
|
100678
|
+
this.cache.delete(key);
|
|
100679
|
+
this.cache.set(key, entry);
|
|
100680
|
+
return entry.result;
|
|
100681
|
+
}
|
|
100682
|
+
set(key, result) {
|
|
100683
|
+
while (this.cache.size >= this.maxSize && this.cache.size > 0) this.evictLRU();
|
|
100684
|
+
this.cache.set(key, {
|
|
100685
|
+
result,
|
|
100686
|
+
fetchedAt: Date.now()
|
|
100687
|
+
});
|
|
100688
|
+
}
|
|
100689
|
+
evictLRU() {
|
|
100690
|
+
const lru = this.cache.keys().next().value;
|
|
100691
|
+
if (lru === void 0) return;
|
|
100692
|
+
this.cache.delete(lru);
|
|
100693
|
+
}
|
|
100694
|
+
};
|
|
100695
|
+
//#endregion
|
|
100957
100696
|
//#region ../../node_modules/.pnpm/@mozilla+readability@0.6.0/node_modules/@mozilla/readability/Readability.js
|
|
100958
100697
|
var require_Readability = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
100959
100698
|
/**
|
|
@@ -113623,9 +113362,9 @@ setPrototypeOf(Document, Document$1).prototype = Document$1.prototype;
|
|
|
113623
113362
|
* common content containers (`<article>` / `<main>` / `<body>`)
|
|
113624
113363
|
* before throwing a "meaningful content" error.
|
|
113625
113364
|
*/
|
|
113626
|
-
const parseHTML = parseHTML$1;
|
|
113627
113365
|
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";
|
|
113628
113366
|
const DEFAULT_MAX_BYTES = 10 * 1024 * 1024;
|
|
113367
|
+
const parseHTML = parseHTML$1;
|
|
113629
113368
|
/**
|
|
113630
113369
|
* SSRF guard — reject non-http(s) schemes and (by default) any hostname
|
|
113631
113370
|
* that is, or parses as, a private / loopback / link-local / ULA IP
|
|
@@ -113661,19 +113400,32 @@ function assertSafeFetchTarget(url, allowPrivate) {
|
|
|
113661
113400
|
if (a === 127 || a === 10 || a === 192 && b === 168 || a === 172 && b >= 16 && b <= 31 || a === 169 && b === 254 || a === 0 || a === 100 && b >= 64 && b <= 127) throw new Error(`Refusing to fetch private address: "${host}"`);
|
|
113662
113401
|
}
|
|
113663
113402
|
}
|
|
113403
|
+
function cacheKey$1(url, allowPrivate, maxBytes, userAgent) {
|
|
113404
|
+
return `local:${url}:${String(allowPrivate)}:${String(maxBytes)}:${userAgent}`;
|
|
113405
|
+
}
|
|
113664
113406
|
var LocalFetchURLProvider = class {
|
|
113665
113407
|
userAgent;
|
|
113666
113408
|
fetchImpl;
|
|
113667
113409
|
maxBytes;
|
|
113668
113410
|
allowPrivateAddresses;
|
|
113411
|
+
cache;
|
|
113669
113412
|
constructor(options = {}) {
|
|
113670
113413
|
this.userAgent = options.userAgent ?? DEFAULT_USER_AGENT;
|
|
113671
113414
|
this.fetchImpl = options.fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
113672
113415
|
this.maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;
|
|
113673
113416
|
this.allowPrivateAddresses = options.allowPrivateAddresses ?? false;
|
|
113417
|
+
this.cache = options.cache ?? new FetchCache();
|
|
113674
113418
|
}
|
|
113675
113419
|
async fetch(url, _options) {
|
|
113676
113420
|
assertSafeFetchTarget(url, this.allowPrivateAddresses);
|
|
113421
|
+
const key = cacheKey$1(url, this.allowPrivateAddresses, this.maxBytes, this.userAgent);
|
|
113422
|
+
const cached = this.cache.get(key);
|
|
113423
|
+
if (cached !== void 0) return cached;
|
|
113424
|
+
const result = await this.fetchFresh(url);
|
|
113425
|
+
this.cache.set(key, result);
|
|
113426
|
+
return result;
|
|
113427
|
+
}
|
|
113428
|
+
async fetchFresh(url) {
|
|
113677
113429
|
const response = await this.fetchImpl(url, {
|
|
113678
113430
|
method: "GET",
|
|
113679
113431
|
headers: { "User-Agent": this.userAgent }
|
|
@@ -113735,6 +113487,9 @@ var LocalFetchURLProvider = class {
|
|
|
113735
113487
|
* is down.
|
|
113736
113488
|
* 4. If localFallback also throws → propagate that error.
|
|
113737
113489
|
*/
|
|
113490
|
+
function cacheKey(baseUrl, url) {
|
|
113491
|
+
return `cli:${baseUrl}:${url}`;
|
|
113492
|
+
}
|
|
113738
113493
|
var ScreamCliFetchURLProvider = class {
|
|
113739
113494
|
tokenProvider;
|
|
113740
113495
|
apiKey;
|
|
@@ -113743,6 +113498,7 @@ var ScreamCliFetchURLProvider = class {
|
|
|
113743
113498
|
customHeaders;
|
|
113744
113499
|
localFallback;
|
|
113745
113500
|
fetchImpl;
|
|
113501
|
+
cache;
|
|
113746
113502
|
constructor(options) {
|
|
113747
113503
|
this.tokenProvider = options.tokenProvider;
|
|
113748
113504
|
this.apiKey = options.apiKey;
|
|
@@ -113751,15 +113507,24 @@ var ScreamCliFetchURLProvider = class {
|
|
|
113751
113507
|
this.customHeaders = options.customHeaders ?? {};
|
|
113752
113508
|
this.localFallback = options.localFallback;
|
|
113753
113509
|
this.fetchImpl = options.fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
113510
|
+
this.cache = options.cache ?? new FetchCache();
|
|
113754
113511
|
}
|
|
113755
113512
|
async fetch(url, options) {
|
|
113513
|
+
const key = cacheKey(this.baseUrl, url);
|
|
113514
|
+
const cached = this.cache.get(key);
|
|
113515
|
+
if (cached !== void 0) return cached;
|
|
113516
|
+
const result = await this.fetchFresh(url, options?.toolCallId);
|
|
113517
|
+
this.cache.set(key, result);
|
|
113518
|
+
return result;
|
|
113519
|
+
}
|
|
113520
|
+
async fetchFresh(url, toolCallId) {
|
|
113756
113521
|
try {
|
|
113757
113522
|
return {
|
|
113758
|
-
content: await this.fetchViaScreamCli(url,
|
|
113523
|
+
content: await this.fetchViaScreamCli(url, toolCallId),
|
|
113759
113524
|
kind: "extracted"
|
|
113760
113525
|
};
|
|
113761
113526
|
} catch {
|
|
113762
|
-
return this.localFallback.fetch(url,
|
|
113527
|
+
return this.localFallback.fetch(url, { toolCallId });
|
|
113763
113528
|
}
|
|
113764
113529
|
}
|
|
113765
113530
|
async fetchViaScreamCli(url, toolCallId) {
|
|
@@ -116876,7 +116641,6 @@ var ScreamCore = class {
|
|
|
116876
116641
|
homeDir;
|
|
116877
116642
|
configPath;
|
|
116878
116643
|
sessions = /* @__PURE__ */ new Map();
|
|
116879
|
-
telemetry;
|
|
116880
116644
|
jian;
|
|
116881
116645
|
runtime;
|
|
116882
116646
|
config;
|
|
@@ -116904,7 +116668,6 @@ var ScreamCore = class {
|
|
|
116904
116668
|
this.screamRequestHeaders = options.screamRequestHeaders;
|
|
116905
116669
|
this.resolveOAuthTokenProvider = options.resolveOAuthTokenProvider;
|
|
116906
116670
|
this.skillDirs = options.skillDirs ?? [];
|
|
116907
|
-
this.telemetry = options.telemetry ?? noopTelemetryClient;
|
|
116908
116671
|
ensureScreamHome(this.homeDir);
|
|
116909
116672
|
this.config = loadRuntimeConfig(this.configPath);
|
|
116910
116673
|
this.sessionStore = new SessionStore(this.homeDir);
|
|
@@ -116955,7 +116718,6 @@ var ScreamCore = class {
|
|
|
116955
116718
|
permissionRules: config.permission?.rules,
|
|
116956
116719
|
skills: this.resolveSessionSkillConfig(config),
|
|
116957
116720
|
mcpConfig,
|
|
116958
|
-
telemetry: withTelemetryContext$1(this.telemetry, { sessionId: summary.id }),
|
|
116959
116721
|
pluginSessionStarts
|
|
116960
116722
|
});
|
|
116961
116723
|
try {
|
|
@@ -117033,7 +116795,6 @@ var ScreamCore = class {
|
|
|
117033
116795
|
permissionRules: config.permission?.rules,
|
|
117034
116796
|
skills: this.resolveSessionSkillConfig(config),
|
|
117035
116797
|
mcpConfig,
|
|
117036
|
-
telemetry: withTelemetryContext$1(this.telemetry, { sessionId: summary.id }),
|
|
117037
116798
|
initializeMainAgent: false,
|
|
117038
116799
|
pluginSessionStarts
|
|
117039
116800
|
});
|
|
@@ -117043,7 +116804,6 @@ var ScreamCore = class {
|
|
|
117043
116804
|
await this.refreshSessionRuntimeConfig(session, config);
|
|
117044
116805
|
} catch (error) {
|
|
117045
116806
|
await session.close().catch(() => {});
|
|
117046
|
-
withTelemetryContext$1(this.telemetry, { sessionId: summary.id }).track("session_load_failed", { reason: telemetryErrorReason(error) });
|
|
117047
116807
|
throw error;
|
|
117048
116808
|
}
|
|
117049
116809
|
this.sessions.set(summary.id, session);
|
|
@@ -117373,13 +117133,15 @@ var ScreamCore = class {
|
|
|
117373
117133
|
}
|
|
117374
117134
|
};
|
|
117375
117135
|
async function createRuntimeConfig(input) {
|
|
117376
|
-
const
|
|
117136
|
+
const fetchCache = new FetchCache();
|
|
117137
|
+
const localFetcher = new LocalFetchURLProvider({ cache: fetchCache });
|
|
117377
117138
|
const fetchService = input.config.services?.screamCliFetch;
|
|
117378
117139
|
return {
|
|
117379
117140
|
urlFetcher: fetchService?.baseUrl === void 0 ? localFetcher : new ScreamCliFetchURLProvider({
|
|
117380
117141
|
baseUrl: fetchService.baseUrl,
|
|
117381
117142
|
localFallback: localFetcher,
|
|
117382
117143
|
defaultHeaders: input.screamRequestHeaders,
|
|
117144
|
+
cache: fetchCache,
|
|
117383
117145
|
...serviceCredentials(fetchService, input.resolveOAuthTokenProvider)
|
|
117384
117146
|
}),
|
|
117385
117147
|
webSearcher: buildWebSearcher(input)
|
|
@@ -117415,11 +117177,6 @@ function requiredWorkDir(operation, value) {
|
|
|
117415
117177
|
function createSessionId() {
|
|
117416
117178
|
return `session_${randomUUID()}`;
|
|
117417
117179
|
}
|
|
117418
|
-
function telemetryErrorReason(error) {
|
|
117419
|
-
if (error instanceof ScreamError) return error.code;
|
|
117420
|
-
if (error instanceof Error && error.name.length > 0) return error.name;
|
|
117421
|
-
return typeof error;
|
|
117422
|
-
}
|
|
117423
117180
|
async function resumeSessionResult(summary, session, warning) {
|
|
117424
117181
|
const api = new SessionAPIImpl(session);
|
|
117425
117182
|
const agents = {};
|
|
@@ -117504,7 +117261,7 @@ function parsePositiveInt(value) {
|
|
|
117504
117261
|
* production state.
|
|
117505
117262
|
*/
|
|
117506
117263
|
const SCREAM_CODE_PLATFORM = "scream_code_cli";
|
|
117507
|
-
function createScreamDeviceId(homeDir,
|
|
117264
|
+
function createScreamDeviceId(homeDir, _options = {}) {
|
|
117508
117265
|
const deviceIdPath = join(homeDir, "device_id");
|
|
117509
117266
|
if (existsSync(deviceIdPath)) try {
|
|
117510
117267
|
const text = readFileSync(deviceIdPath, "utf-8").trim();
|
|
@@ -117521,9 +117278,6 @@ function createScreamDeviceId(homeDir, options = {}) {
|
|
|
117521
117278
|
mode: 384
|
|
117522
117279
|
});
|
|
117523
117280
|
} catch {}
|
|
117524
|
-
if (options.onFirstLaunch !== void 0) try {
|
|
117525
|
-
options.onFirstLaunch(id);
|
|
117526
|
-
} catch {}
|
|
117527
117281
|
return id;
|
|
117528
117282
|
}
|
|
117529
117283
|
function createScreamDeviceHeaders(options) {
|
|
@@ -117624,8 +117378,7 @@ var SDKRpcClient = class {
|
|
|
117624
117378
|
configPath: options.configPath,
|
|
117625
117379
|
screamRequestHeaders,
|
|
117626
117380
|
resolveOAuthTokenProvider: options.resolveOAuthTokenProvider,
|
|
117627
|
-
skillDirs: options.skillDirs
|
|
117628
|
-
telemetry: options.telemetry
|
|
117381
|
+
skillDirs: options.skillDirs
|
|
117629
117382
|
});
|
|
117630
117383
|
this.ready = sdkRpc(new ClientAPI(this)).then((rpc) => {
|
|
117631
117384
|
this.rpc = rpc;
|
|
@@ -118513,7 +118266,6 @@ var ScreamHarness = class {
|
|
|
118513
118266
|
auth;
|
|
118514
118267
|
identity;
|
|
118515
118268
|
uiMode;
|
|
118516
|
-
telemetry;
|
|
118517
118269
|
activeSessions = /* @__PURE__ */ new Map();
|
|
118518
118270
|
rpc;
|
|
118519
118271
|
constructor(options) {
|
|
@@ -118525,7 +118277,6 @@ var ScreamHarness = class {
|
|
|
118525
118277
|
configPath: options.configPath
|
|
118526
118278
|
});
|
|
118527
118279
|
this.configureLogging();
|
|
118528
|
-
this.telemetry = options.telemetry ?? noopTelemetryClient;
|
|
118529
118280
|
this.auth = new ScreamAuthFacade({
|
|
118530
118281
|
homeDir: this.homeDir,
|
|
118531
118282
|
configPath: this.configPath
|
|
@@ -118535,8 +118286,7 @@ var ScreamHarness = class {
|
|
|
118535
118286
|
configPath: this.configPath,
|
|
118536
118287
|
identity: this.identity,
|
|
118537
118288
|
resolveOAuthTokenProvider: this.auth.resolveOAuthTokenProvider,
|
|
118538
|
-
skillDirs: options.skillDirs
|
|
118539
|
-
telemetry: this.telemetry
|
|
118289
|
+
skillDirs: options.skillDirs
|
|
118540
118290
|
});
|
|
118541
118291
|
}
|
|
118542
118292
|
configureLogging() {
|
|
@@ -118551,12 +118301,6 @@ var ScreamHarness = class {
|
|
|
118551
118301
|
set interactiveAgentId(agentId) {
|
|
118552
118302
|
this.rpc.interactiveAgentId = agentId;
|
|
118553
118303
|
}
|
|
118554
|
-
track(event, properties) {
|
|
118555
|
-
this.telemetry.track(event, properties);
|
|
118556
|
-
}
|
|
118557
|
-
setTelemetryContext(patch) {
|
|
118558
|
-
this.telemetry.setContext?.(patch);
|
|
118559
|
-
}
|
|
118560
118304
|
async createSession(options) {
|
|
118561
118305
|
const { planMode, ...coreOptions } = options;
|
|
118562
118306
|
const summary = await this.rpc.createSession(coreOptions);
|
|
@@ -118571,8 +118315,6 @@ var ScreamHarness = class {
|
|
|
118571
118315
|
});
|
|
118572
118316
|
this.activeSessions.set(session.id, session);
|
|
118573
118317
|
if (planMode === true) await session.setPlanMode(true);
|
|
118574
|
-
this.trackSessionStarted(summary.id, false);
|
|
118575
|
-
this.trackSessionEvent(session.id, "session_new");
|
|
118576
118318
|
return session;
|
|
118577
118319
|
}
|
|
118578
118320
|
async resumeSession(input) {
|
|
@@ -118590,8 +118332,6 @@ var ScreamHarness = class {
|
|
|
118590
118332
|
}
|
|
118591
118333
|
});
|
|
118592
118334
|
this.activeSessions.set(session.id, session);
|
|
118593
|
-
this.trackSessionStarted(summary.id, true);
|
|
118594
|
-
this.trackSessionEvent(session.id, "session_resume");
|
|
118595
118335
|
return session;
|
|
118596
118336
|
}
|
|
118597
118337
|
async forkSession(input) {
|
|
@@ -118611,8 +118351,6 @@ var ScreamHarness = class {
|
|
|
118611
118351
|
}
|
|
118612
118352
|
});
|
|
118613
118353
|
this.activeSessions.set(session.id, session);
|
|
118614
|
-
this.trackSessionStarted(summary.id, true);
|
|
118615
|
-
this.trackSessionEvent(session.id, "session_fork");
|
|
118616
118354
|
return session;
|
|
118617
118355
|
}
|
|
118618
118356
|
getSession(id) {
|
|
@@ -118630,12 +118368,10 @@ var ScreamHarness = class {
|
|
|
118630
118368
|
this.activeSessions.get(input.id)?.emitMetaUpdated({ title: input.title });
|
|
118631
118369
|
}
|
|
118632
118370
|
async exportSession(input) {
|
|
118633
|
-
|
|
118371
|
+
return await this.rpc.exportSession({
|
|
118634
118372
|
...input,
|
|
118635
118373
|
version: input.version ?? this.identity?.version
|
|
118636
118374
|
});
|
|
118637
|
-
this.trackSessionEvent(input.id, "export");
|
|
118638
|
-
return result;
|
|
118639
118375
|
}
|
|
118640
118376
|
async listSessions(options = {}) {
|
|
118641
118377
|
return this.rpc.listSessions(options);
|
|
@@ -118666,17 +118402,6 @@ var ScreamHarness = class {
|
|
|
118666
118402
|
await getRootLogger().flush();
|
|
118667
118403
|
} catch {}
|
|
118668
118404
|
}
|
|
118669
|
-
trackSessionEvent(eventSessionId, event) {
|
|
118670
|
-
withTelemetryContext$1(this.telemetry, { sessionId: eventSessionId }).track(event);
|
|
118671
|
-
}
|
|
118672
|
-
trackSessionStarted(eventSessionId, resumed) {
|
|
118673
|
-
withTelemetryContext$1(this.telemetry, { sessionId: eventSessionId }).track("session_started", {
|
|
118674
|
-
client_name: this.identity?.userAgentProduct ?? null,
|
|
118675
|
-
client_version: this.identity?.version ?? null,
|
|
118676
|
-
ui_mode: this.uiMode,
|
|
118677
|
-
resumed
|
|
118678
|
-
});
|
|
118679
|
-
}
|
|
118680
118405
|
};
|
|
118681
118406
|
const DEFAULT_SESSION_STARTED_UI_MODE = "shell";
|
|
118682
118407
|
function normalizeSessionId(value) {
|
|
@@ -118796,641 +118521,11 @@ function applyCatalogProvider(config, options) {
|
|
|
118796
118521
|
return { defaultModel };
|
|
118797
118522
|
}
|
|
118798
118523
|
//#endregion
|
|
118799
|
-
//#region ../../packages/telemetry/src/types.ts
|
|
118800
|
-
function isTelemetryPrimitive(value) {
|
|
118801
|
-
return value === null || value === void 0 || typeof value === "boolean" || typeof value === "string" || typeof value === "number" && Number.isFinite(value);
|
|
118802
|
-
}
|
|
118803
|
-
//#endregion
|
|
118804
|
-
//#region ../../packages/telemetry/src/client.ts
|
|
118805
|
-
const MAX_QUEUE_SIZE = 1e3;
|
|
118806
|
-
var TelemetryClient = class {
|
|
118807
|
-
queue = [];
|
|
118808
|
-
sink = null;
|
|
118809
|
-
deviceId = null;
|
|
118810
|
-
sessionId = null;
|
|
118811
|
-
disabled = false;
|
|
118812
|
-
setContext(input) {
|
|
118813
|
-
if (input.deviceId !== void 0) this.deviceId = input.deviceId;
|
|
118814
|
-
if (input.sessionId !== void 0) this.sessionId = input.sessionId;
|
|
118815
|
-
}
|
|
118816
|
-
withContext(input) {
|
|
118817
|
-
return new ScopedTelemetryClient(this, input);
|
|
118818
|
-
}
|
|
118819
|
-
attachSink(sink) {
|
|
118820
|
-
if (this.sink !== null && this.sink !== sink) {
|
|
118821
|
-
this.sink.stopPeriodicFlush();
|
|
118822
|
-
this.sink.flushSync();
|
|
118823
|
-
}
|
|
118824
|
-
this.sink = sink;
|
|
118825
|
-
for (const event of this.queue) {
|
|
118826
|
-
const record = toTelemetryEvent(event);
|
|
118827
|
-
if (record.device_id === null && event.contextOverrides?.deviceId !== true) record.device_id = this.deviceId;
|
|
118828
|
-
if (record.session_id === null && event.contextOverrides?.sessionId !== true) record.session_id = this.sessionId;
|
|
118829
|
-
sink.accept(record);
|
|
118830
|
-
}
|
|
118831
|
-
this.queue = [];
|
|
118832
|
-
}
|
|
118833
|
-
disable() {
|
|
118834
|
-
this.disabled = true;
|
|
118835
|
-
this.queue = [];
|
|
118836
|
-
if (this.sink !== null) {
|
|
118837
|
-
this.sink.stopPeriodicFlush();
|
|
118838
|
-
this.sink.clearBuffer();
|
|
118839
|
-
this.sink = null;
|
|
118840
|
-
}
|
|
118841
|
-
}
|
|
118842
|
-
enable() {
|
|
118843
|
-
this.disabled = false;
|
|
118844
|
-
}
|
|
118845
|
-
track(event, properties = {}) {
|
|
118846
|
-
this.trackWithContext(event, properties, {});
|
|
118847
|
-
}
|
|
118848
|
-
trackWithContext(event, properties = {}, context) {
|
|
118849
|
-
if (this.disabled) return;
|
|
118850
|
-
const record = {
|
|
118851
|
-
event_id: randomUUID().replaceAll("-", ""),
|
|
118852
|
-
device_id: context.deviceId === void 0 ? this.deviceId : context.deviceId,
|
|
118853
|
-
session_id: context.sessionId === void 0 ? this.sessionId : context.sessionId,
|
|
118854
|
-
event,
|
|
118855
|
-
timestamp: Date.now() / 1e3,
|
|
118856
|
-
properties: sanitizeProperties(properties),
|
|
118857
|
-
contextOverrides: {
|
|
118858
|
-
deviceId: context.deviceId !== void 0,
|
|
118859
|
-
sessionId: context.sessionId !== void 0
|
|
118860
|
-
}
|
|
118861
|
-
};
|
|
118862
|
-
if (this.sink !== null) {
|
|
118863
|
-
this.sink.accept(toTelemetryEvent(record));
|
|
118864
|
-
return;
|
|
118865
|
-
}
|
|
118866
|
-
this.queue.push(record);
|
|
118867
|
-
if (this.queue.length > MAX_QUEUE_SIZE) this.queue = this.queue.slice(this.queue.length - MAX_QUEUE_SIZE);
|
|
118868
|
-
}
|
|
118869
|
-
getSink() {
|
|
118870
|
-
return this.sink;
|
|
118871
|
-
}
|
|
118872
|
-
async flush(signal) {
|
|
118873
|
-
await this.sink?.flush(signal);
|
|
118874
|
-
}
|
|
118875
|
-
flushSync() {
|
|
118876
|
-
this.sink?.flushSync();
|
|
118877
|
-
}
|
|
118878
|
-
async shutdown(options = {}) {
|
|
118879
|
-
const sink = this.sink;
|
|
118880
|
-
if (sink === null) return;
|
|
118881
|
-
sink.stopPeriodicFlush();
|
|
118882
|
-
if (options.timeoutMs === void 0) {
|
|
118883
|
-
await sink.flush();
|
|
118884
|
-
return;
|
|
118885
|
-
}
|
|
118886
|
-
const controller = new AbortController();
|
|
118887
|
-
const timer = setTimeout(() => {
|
|
118888
|
-
controller.abort();
|
|
118889
|
-
}, options.timeoutMs);
|
|
118890
|
-
timer.unref?.();
|
|
118891
|
-
try {
|
|
118892
|
-
await sink.flush(controller.signal);
|
|
118893
|
-
} catch {
|
|
118894
|
-
sink.flushSync();
|
|
118895
|
-
} finally {
|
|
118896
|
-
clearTimeout(timer);
|
|
118897
|
-
}
|
|
118898
|
-
}
|
|
118899
|
-
resetForTests() {
|
|
118900
|
-
this.sink?.stopPeriodicFlush();
|
|
118901
|
-
this.queue = [];
|
|
118902
|
-
this.sink = null;
|
|
118903
|
-
this.deviceId = null;
|
|
118904
|
-
this.sessionId = null;
|
|
118905
|
-
this.disabled = false;
|
|
118906
|
-
}
|
|
118907
|
-
};
|
|
118908
|
-
var ScopedTelemetryClient = class ScopedTelemetryClient extends TelemetryClient {
|
|
118909
|
-
parent;
|
|
118910
|
-
context;
|
|
118911
|
-
constructor(parent, context) {
|
|
118912
|
-
super();
|
|
118913
|
-
this.parent = parent;
|
|
118914
|
-
this.context = context;
|
|
118915
|
-
}
|
|
118916
|
-
setContext(input) {
|
|
118917
|
-
this.parent.setContext(input);
|
|
118918
|
-
}
|
|
118919
|
-
withContext(input) {
|
|
118920
|
-
return new ScopedTelemetryClient(this.parent, mergeContext(this.context, input));
|
|
118921
|
-
}
|
|
118922
|
-
attachSink(sink) {
|
|
118923
|
-
this.parent.attachSink(sink);
|
|
118924
|
-
}
|
|
118925
|
-
disable() {
|
|
118926
|
-
this.parent.disable();
|
|
118927
|
-
}
|
|
118928
|
-
enable() {
|
|
118929
|
-
this.parent.enable();
|
|
118930
|
-
}
|
|
118931
|
-
track(event, properties = {}) {
|
|
118932
|
-
this.parent.trackWithContext(event, properties, this.context);
|
|
118933
|
-
}
|
|
118934
|
-
getSink() {
|
|
118935
|
-
return this.parent.getSink();
|
|
118936
|
-
}
|
|
118937
|
-
async flush(signal) {
|
|
118938
|
-
await this.parent.flush(signal);
|
|
118939
|
-
}
|
|
118940
|
-
flushSync() {
|
|
118941
|
-
this.parent.flushSync();
|
|
118942
|
-
}
|
|
118943
|
-
async shutdown(options = {}) {
|
|
118944
|
-
await this.parent.shutdown(options);
|
|
118945
|
-
}
|
|
118946
|
-
resetForTests() {
|
|
118947
|
-
this.parent.resetForTests();
|
|
118948
|
-
}
|
|
118949
|
-
};
|
|
118950
|
-
const defaultClient = new TelemetryClient();
|
|
118951
|
-
function setContext(input) {
|
|
118952
|
-
defaultClient.setContext(input);
|
|
118953
|
-
}
|
|
118954
|
-
function track$1(event, properties = {}) {
|
|
118955
|
-
defaultClient.track(event, properties);
|
|
118956
|
-
}
|
|
118957
|
-
function withContext(input) {
|
|
118958
|
-
return defaultClient.withContext(input);
|
|
118959
|
-
}
|
|
118960
|
-
async function shutdown(options = {}) {
|
|
118961
|
-
await defaultClient.shutdown(options);
|
|
118962
|
-
}
|
|
118963
|
-
function getDefaultTelemetryClient() {
|
|
118964
|
-
return defaultClient;
|
|
118965
|
-
}
|
|
118966
|
-
function mergeContext(base, patch) {
|
|
118967
|
-
return {
|
|
118968
|
-
deviceId: patch.deviceId === void 0 ? base.deviceId : patch.deviceId,
|
|
118969
|
-
sessionId: patch.sessionId === void 0 ? base.sessionId : patch.sessionId
|
|
118970
|
-
};
|
|
118971
|
-
}
|
|
118972
|
-
function toTelemetryEvent(event) {
|
|
118973
|
-
return {
|
|
118974
|
-
event_id: event.event_id,
|
|
118975
|
-
device_id: event.device_id,
|
|
118976
|
-
session_id: event.session_id,
|
|
118977
|
-
event: event.event,
|
|
118978
|
-
timestamp: event.timestamp,
|
|
118979
|
-
properties: event.properties
|
|
118980
|
-
};
|
|
118981
|
-
}
|
|
118982
|
-
function sanitizeProperties(input) {
|
|
118983
|
-
const out = {};
|
|
118984
|
-
for (const [key, value] of Object.entries(input)) if (isTelemetryPrimitive(value)) out[key] = value;
|
|
118985
|
-
return out;
|
|
118986
|
-
}
|
|
118987
|
-
//#endregion
|
|
118988
|
-
//#region ../../packages/telemetry/src/sink.ts
|
|
118989
|
-
const DEFAULT_FLUSH_INTERVAL_MS = 3e4;
|
|
118990
|
-
const DEFAULT_FLUSH_THRESHOLD = 50;
|
|
118991
|
-
var EventSink = class {
|
|
118992
|
-
transport;
|
|
118993
|
-
context;
|
|
118994
|
-
flushIntervalMs;
|
|
118995
|
-
flushThreshold;
|
|
118996
|
-
buffer = [];
|
|
118997
|
-
flushTimer = null;
|
|
118998
|
-
constructor(options) {
|
|
118999
|
-
this.transport = options.transport;
|
|
119000
|
-
this.context = buildContext(options.context);
|
|
119001
|
-
this.flushIntervalMs = options.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS;
|
|
119002
|
-
this.flushThreshold = options.flushThreshold ?? DEFAULT_FLUSH_THRESHOLD;
|
|
119003
|
-
}
|
|
119004
|
-
accept(event) {
|
|
119005
|
-
const enriched = {
|
|
119006
|
-
...event,
|
|
119007
|
-
context: { ...this.context }
|
|
119008
|
-
};
|
|
119009
|
-
this.buffer.push(enriched);
|
|
119010
|
-
if (this.buffer.length >= this.flushThreshold) this.flush().catch(() => {});
|
|
119011
|
-
}
|
|
119012
|
-
startPeriodicFlush() {
|
|
119013
|
-
if (this.flushTimer !== null) return;
|
|
119014
|
-
this.flushTimer = setInterval(() => {
|
|
119015
|
-
this.flush().catch(() => {});
|
|
119016
|
-
}, this.flushIntervalMs);
|
|
119017
|
-
this.flushTimer.unref?.();
|
|
119018
|
-
}
|
|
119019
|
-
stopPeriodicFlush() {
|
|
119020
|
-
if (this.flushTimer === null) return;
|
|
119021
|
-
clearInterval(this.flushTimer);
|
|
119022
|
-
this.flushTimer = null;
|
|
119023
|
-
}
|
|
119024
|
-
async retryDiskEvents() {
|
|
119025
|
-
await this.transport.retryDiskEvents();
|
|
119026
|
-
}
|
|
119027
|
-
clearBuffer() {
|
|
119028
|
-
this.buffer = [];
|
|
119029
|
-
}
|
|
119030
|
-
async flush(signal) {
|
|
119031
|
-
if (this.buffer.length === 0) return;
|
|
119032
|
-
const events = this.buffer;
|
|
119033
|
-
this.buffer = [];
|
|
119034
|
-
await this.transport.send(events, signal);
|
|
119035
|
-
}
|
|
119036
|
-
flushSync() {
|
|
119037
|
-
if (this.buffer.length === 0) return;
|
|
119038
|
-
const events = this.buffer;
|
|
119039
|
-
this.buffer = [];
|
|
119040
|
-
try {
|
|
119041
|
-
this.transport.saveToDisk(events);
|
|
119042
|
-
} catch {}
|
|
119043
|
-
}
|
|
119044
|
-
};
|
|
119045
|
-
function buildContext(options) {
|
|
119046
|
-
const env = options.env ?? process.env;
|
|
119047
|
-
const context = {
|
|
119048
|
-
app_name: options.appName,
|
|
119049
|
-
version: options.version,
|
|
119050
|
-
runtime: "node",
|
|
119051
|
-
platform: platform(),
|
|
119052
|
-
arch: arch(),
|
|
119053
|
-
node_version: process.versions.node,
|
|
119054
|
-
os_version: release(),
|
|
119055
|
-
ci: env["CI"] !== void 0,
|
|
119056
|
-
locale: options.locale ?? env["LANG"] ?? "",
|
|
119057
|
-
terminal: options.terminal ?? env["TERM_PROGRAM"] ?? "",
|
|
119058
|
-
ui_mode: options.uiMode ?? "shell"
|
|
119059
|
-
};
|
|
119060
|
-
setPrimitive(context, "model", options.model);
|
|
119061
|
-
setPrimitive(context, "build_sha", options.buildSha);
|
|
119062
|
-
return context;
|
|
119063
|
-
}
|
|
119064
|
-
function setPrimitive(target, key, value) {
|
|
119065
|
-
if (value === void 0) return;
|
|
119066
|
-
if (typeof value === "string" && value.length === 0) return;
|
|
119067
|
-
target[key] = value;
|
|
119068
|
-
}
|
|
119069
|
-
const SERVER_EVENT_PREFIX = "kfc_";
|
|
119070
|
-
const USER_ID_PREFIX = "kfc_device_id_";
|
|
119071
|
-
const RETRY_BACKOFFS_MS = [
|
|
119072
|
-
1e3,
|
|
119073
|
-
4e3,
|
|
119074
|
-
16e3
|
|
119075
|
-
];
|
|
119076
|
-
const DEFAULT_REQUEST_TIMEOUT_MS = 1e4;
|
|
119077
|
-
var AsyncTransport = class {
|
|
119078
|
-
homeDir;
|
|
119079
|
-
deviceId;
|
|
119080
|
-
endpoint;
|
|
119081
|
-
getAccessToken;
|
|
119082
|
-
fetchImpl;
|
|
119083
|
-
retryBackoffsMs;
|
|
119084
|
-
requestTimeoutMs;
|
|
119085
|
-
sleepImpl;
|
|
119086
|
-
now;
|
|
119087
|
-
constructor(options) {
|
|
119088
|
-
this.homeDir = options.homeDir;
|
|
119089
|
-
this.deviceId = options.deviceId;
|
|
119090
|
-
this.endpoint = options.endpoint ?? "https://telemetry-logs.scream.com/v1/event";
|
|
119091
|
-
this.getAccessToken = options.getAccessToken ?? null;
|
|
119092
|
-
this.fetchImpl = options.fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
119093
|
-
this.retryBackoffsMs = options.retryBackoffsMs ?? RETRY_BACKOFFS_MS;
|
|
119094
|
-
this.requestTimeoutMs = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
119095
|
-
this.sleepImpl = options.sleep ?? abortableSleep;
|
|
119096
|
-
this.now = options.now ?? Date.now;
|
|
119097
|
-
}
|
|
119098
|
-
async send(events, signal) {
|
|
119099
|
-
if (events.length === 0) return;
|
|
119100
|
-
let savedToDisk = false;
|
|
119101
|
-
const saveEventsToDisk = () => {
|
|
119102
|
-
if (savedToDisk) return;
|
|
119103
|
-
this.saveToDisk(events);
|
|
119104
|
-
savedToDisk = true;
|
|
119105
|
-
};
|
|
119106
|
-
if (signal?.aborted === true) {
|
|
119107
|
-
saveEventsToDisk();
|
|
119108
|
-
throw abortError();
|
|
119109
|
-
}
|
|
119110
|
-
let payload;
|
|
119111
|
-
try {
|
|
119112
|
-
payload = buildPayload(events, this.deviceId);
|
|
119113
|
-
} catch {
|
|
119114
|
-
return;
|
|
119115
|
-
}
|
|
119116
|
-
try {
|
|
119117
|
-
for (let attempt = 0; attempt <= this.retryBackoffsMs.length; attempt++) try {
|
|
119118
|
-
await this.sendHttp(payload, signal);
|
|
119119
|
-
return;
|
|
119120
|
-
} catch (error) {
|
|
119121
|
-
if (isSignalAborted(signal) || isAbortError$2(error)) {
|
|
119122
|
-
saveEventsToDisk();
|
|
119123
|
-
throw error;
|
|
119124
|
-
}
|
|
119125
|
-
if (!(error instanceof TransientTelemetryError)) break;
|
|
119126
|
-
const backoff = this.retryBackoffsMs[attempt];
|
|
119127
|
-
if (backoff === void 0) break;
|
|
119128
|
-
await this.sleepImpl(backoff, signal);
|
|
119129
|
-
}
|
|
119130
|
-
} catch (error) {
|
|
119131
|
-
if (isSignalAborted(signal) || isAbortError$2(error)) {
|
|
119132
|
-
saveEventsToDisk();
|
|
119133
|
-
throw error;
|
|
119134
|
-
}
|
|
119135
|
-
}
|
|
119136
|
-
saveEventsToDisk();
|
|
119137
|
-
}
|
|
119138
|
-
saveToDisk(events) {
|
|
119139
|
-
if (events.length === 0) return;
|
|
119140
|
-
const path = join(this.telemetryDir(), `failed_${randomBytes(6).toString("hex")}.jsonl`);
|
|
119141
|
-
writeFileSync(path, events.map((event) => JSON.stringify(event)).join("\n") + "\n", {
|
|
119142
|
-
encoding: "utf-8",
|
|
119143
|
-
mode: 384,
|
|
119144
|
-
flag: "wx"
|
|
119145
|
-
});
|
|
119146
|
-
try {
|
|
119147
|
-
chmodSync(path, 384);
|
|
119148
|
-
} catch {}
|
|
119149
|
-
}
|
|
119150
|
-
async retryDiskEvents() {
|
|
119151
|
-
let entries;
|
|
119152
|
-
try {
|
|
119153
|
-
entries = readdirSync(this.telemetryDir());
|
|
119154
|
-
} catch {
|
|
119155
|
-
return;
|
|
119156
|
-
}
|
|
119157
|
-
const now = this.now();
|
|
119158
|
-
for (const entry of entries) {
|
|
119159
|
-
if (!entry.startsWith("failed_") || !entry.endsWith(".jsonl")) continue;
|
|
119160
|
-
const path = join(this.telemetryDir(), entry);
|
|
119161
|
-
try {
|
|
119162
|
-
if (now - statSync(path).mtimeMs > 6048e5) {
|
|
119163
|
-
unlinkSync(path);
|
|
119164
|
-
continue;
|
|
119165
|
-
}
|
|
119166
|
-
} catch {
|
|
119167
|
-
continue;
|
|
119168
|
-
}
|
|
119169
|
-
let events;
|
|
119170
|
-
let payload;
|
|
119171
|
-
try {
|
|
119172
|
-
events = readJsonl(path);
|
|
119173
|
-
payload = buildPayload(events, this.deviceId);
|
|
119174
|
-
} catch (error) {
|
|
119175
|
-
if (error instanceof SyntaxError || error instanceof TypeError) try {
|
|
119176
|
-
unlinkSync(path);
|
|
119177
|
-
} catch {}
|
|
119178
|
-
continue;
|
|
119179
|
-
}
|
|
119180
|
-
try {
|
|
119181
|
-
await this.sendHttp(payload);
|
|
119182
|
-
unlinkSync(path);
|
|
119183
|
-
} catch (error) {
|
|
119184
|
-
if (error instanceof TransientTelemetryError) continue;
|
|
119185
|
-
}
|
|
119186
|
-
}
|
|
119187
|
-
}
|
|
119188
|
-
async sendHttp(payload, signal) {
|
|
119189
|
-
const token = this.getAccessToken === null ? null : await this.getAccessToken();
|
|
119190
|
-
const headers = { "Content-Type": "application/json" };
|
|
119191
|
-
if (token !== null && token.length > 0) headers["Authorization"] = `Bearer ${token}`;
|
|
119192
|
-
const response = await this.post(payload, headers, signal);
|
|
119193
|
-
if (response.status === 401 && headers["Authorization"] !== void 0) {
|
|
119194
|
-
delete headers["Authorization"];
|
|
119195
|
-
handleStatus((await this.post(payload, headers, signal)).status);
|
|
119196
|
-
return;
|
|
119197
|
-
}
|
|
119198
|
-
handleStatus(response.status);
|
|
119199
|
-
}
|
|
119200
|
-
async post(payload, headers, signal) {
|
|
119201
|
-
try {
|
|
119202
|
-
return await fetchWithTimeout(this.fetchImpl, this.endpoint, {
|
|
119203
|
-
method: "POST",
|
|
119204
|
-
headers: { ...headers },
|
|
119205
|
-
body: JSON.stringify(payload)
|
|
119206
|
-
}, this.requestTimeoutMs, signal);
|
|
119207
|
-
} catch (error) {
|
|
119208
|
-
if (signal?.aborted === true || isAbortError$2(error)) throw error;
|
|
119209
|
-
throw new TransientTelemetryError(String(error));
|
|
119210
|
-
}
|
|
119211
|
-
}
|
|
119212
|
-
telemetryDir() {
|
|
119213
|
-
const path = join(this.homeDir, "telemetry");
|
|
119214
|
-
mkdirSync(path, {
|
|
119215
|
-
recursive: true,
|
|
119216
|
-
mode: 448
|
|
119217
|
-
});
|
|
119218
|
-
try {
|
|
119219
|
-
chmodSync(path, 448);
|
|
119220
|
-
} catch {}
|
|
119221
|
-
return path;
|
|
119222
|
-
}
|
|
119223
|
-
};
|
|
119224
|
-
var TransientTelemetryError = class extends Error {
|
|
119225
|
-
name = "TransientTelemetryError";
|
|
119226
|
-
};
|
|
119227
|
-
function buildUserId(deviceId) {
|
|
119228
|
-
return USER_ID_PREFIX + deviceId;
|
|
119229
|
-
}
|
|
119230
|
-
function buildPayload(events, deviceId) {
|
|
119231
|
-
return {
|
|
119232
|
-
user_id: buildUserId(deviceId),
|
|
119233
|
-
events: events.map((event) => flattenEvent(applyServerPrefix(event)))
|
|
119234
|
-
};
|
|
119235
|
-
}
|
|
119236
|
-
function applyServerPrefix(event) {
|
|
119237
|
-
const name = event.event;
|
|
119238
|
-
if (typeof name !== "string" || name.length === 0 || name.startsWith("kfc_")) return event;
|
|
119239
|
-
return {
|
|
119240
|
-
...event,
|
|
119241
|
-
event: SERVER_EVENT_PREFIX + name
|
|
119242
|
-
};
|
|
119243
|
-
}
|
|
119244
|
-
function flattenEvent(event) {
|
|
119245
|
-
const out = {};
|
|
119246
|
-
for (const [key, value] of Object.entries(event)) if (key === "properties") flattenNested(out, "property", value);
|
|
119247
|
-
else if (key === "context") flattenNested(out, "context", value);
|
|
119248
|
-
else {
|
|
119249
|
-
assertPrimitive(key, value);
|
|
119250
|
-
out[key] = value;
|
|
119251
|
-
}
|
|
119252
|
-
return out;
|
|
119253
|
-
}
|
|
119254
|
-
function flattenNested(target, prefix, value) {
|
|
119255
|
-
if (value === null || typeof value !== "object" || Array.isArray(value)) return;
|
|
119256
|
-
for (const [key, nestedValue] of Object.entries(value)) {
|
|
119257
|
-
assertPrimitive(`${prefix}.${key}`, nestedValue);
|
|
119258
|
-
target[`${prefix}_${key}`] = nestedValue;
|
|
119259
|
-
}
|
|
119260
|
-
}
|
|
119261
|
-
function assertPrimitive(key, value) {
|
|
119262
|
-
if (isTelemetryPrimitive(value)) return;
|
|
119263
|
-
throw new TypeError(`telemetry ${key} must be primitive`);
|
|
119264
|
-
}
|
|
119265
|
-
function handleStatus(status) {
|
|
119266
|
-
if (status >= 500 || status === 429) throw new TransientTelemetryError(`HTTP ${String(status)}`);
|
|
119267
|
-
if (status >= 400) return;
|
|
119268
|
-
}
|
|
119269
|
-
function readJsonl(path) {
|
|
119270
|
-
const text = readFileSync(path, "utf-8");
|
|
119271
|
-
const events = [];
|
|
119272
|
-
for (const line of text.split("\n")) {
|
|
119273
|
-
const trimmed = line.trim();
|
|
119274
|
-
if (trimmed.length === 0) continue;
|
|
119275
|
-
events.push(JSON.parse(trimmed));
|
|
119276
|
-
}
|
|
119277
|
-
return events;
|
|
119278
|
-
}
|
|
119279
|
-
async function fetchWithTimeout(fetchImpl, url, init, timeoutMs, externalSignal) {
|
|
119280
|
-
const controller = new AbortController();
|
|
119281
|
-
const abortFromExternal = () => {
|
|
119282
|
-
controller.abort(externalSignal?.reason);
|
|
119283
|
-
};
|
|
119284
|
-
const timeout = setTimeout(() => {
|
|
119285
|
-
controller.abort(/* @__PURE__ */ new Error("telemetry request timed out"));
|
|
119286
|
-
}, timeoutMs);
|
|
119287
|
-
timeout.unref?.();
|
|
119288
|
-
if (externalSignal?.aborted === true) abortFromExternal();
|
|
119289
|
-
externalSignal?.addEventListener("abort", abortFromExternal, { once: true });
|
|
119290
|
-
try {
|
|
119291
|
-
return await fetchImpl(url, {
|
|
119292
|
-
...init,
|
|
119293
|
-
signal: controller.signal
|
|
119294
|
-
});
|
|
119295
|
-
} finally {
|
|
119296
|
-
clearTimeout(timeout);
|
|
119297
|
-
externalSignal?.removeEventListener("abort", abortFromExternal);
|
|
119298
|
-
}
|
|
119299
|
-
}
|
|
119300
|
-
function abortableSleep(ms, signal) {
|
|
119301
|
-
if (signal?.aborted === true) return Promise.reject(abortError());
|
|
119302
|
-
return new Promise((resolve, reject) => {
|
|
119303
|
-
const timer = setTimeout(resolve, ms);
|
|
119304
|
-
timer.unref?.();
|
|
119305
|
-
const onAbort = () => {
|
|
119306
|
-
clearTimeout(timer);
|
|
119307
|
-
reject(abortError());
|
|
119308
|
-
};
|
|
119309
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
119310
|
-
});
|
|
119311
|
-
}
|
|
119312
|
-
function isAbortError$2(error) {
|
|
119313
|
-
return error instanceof Error && error.name === "AbortError";
|
|
119314
|
-
}
|
|
119315
|
-
function isSignalAborted(signal) {
|
|
119316
|
-
return signal?.aborted === true;
|
|
119317
|
-
}
|
|
119318
|
-
function abortError() {
|
|
119319
|
-
return new DOMException("The operation was aborted.", "AbortError");
|
|
119320
|
-
}
|
|
119321
|
-
//#endregion
|
|
119322
|
-
//#region ../../packages/telemetry/src/bootstrap.ts
|
|
119323
|
-
const TELEMETRY_DISABLE_ENV = "SCREAM_DISABLE_TELEMETRY";
|
|
119324
|
-
const TRUE_ENV_VALUES = new Set([
|
|
119325
|
-
"1",
|
|
119326
|
-
"true",
|
|
119327
|
-
"t",
|
|
119328
|
-
"yes",
|
|
119329
|
-
"y"
|
|
119330
|
-
]);
|
|
119331
|
-
function isTelemetryDisabledByEnv(env = process.env) {
|
|
119332
|
-
const value = env[TELEMETRY_DISABLE_ENV];
|
|
119333
|
-
return value !== void 0 && TRUE_ENV_VALUES.has(value.trim().toLowerCase());
|
|
119334
|
-
}
|
|
119335
|
-
function shouldEnableTelemetry(input = {}) {
|
|
119336
|
-
return input.enabled !== false && !isTelemetryDisabledByEnv(input.env ?? process.env);
|
|
119337
|
-
}
|
|
119338
|
-
function initializeTelemetry(options) {
|
|
119339
|
-
const client = getDefaultTelemetryClient();
|
|
119340
|
-
if (!shouldEnableTelemetry({ enabled: options.enabled })) {
|
|
119341
|
-
client.disable();
|
|
119342
|
-
return;
|
|
119343
|
-
}
|
|
119344
|
-
client.enable();
|
|
119345
|
-
client.setContext({
|
|
119346
|
-
deviceId: options.deviceId,
|
|
119347
|
-
sessionId: options.sessionId
|
|
119348
|
-
});
|
|
119349
|
-
const sink = new EventSink({
|
|
119350
|
-
transport: new AsyncTransport({
|
|
119351
|
-
homeDir: options.homeDir,
|
|
119352
|
-
deviceId: options.deviceId,
|
|
119353
|
-
getAccessToken: options.getAccessToken
|
|
119354
|
-
}),
|
|
119355
|
-
context: {
|
|
119356
|
-
appName: options.appName,
|
|
119357
|
-
version: options.version,
|
|
119358
|
-
uiMode: options.uiMode,
|
|
119359
|
-
model: options.model,
|
|
119360
|
-
buildSha: options.buildSha,
|
|
119361
|
-
terminal: options.terminal,
|
|
119362
|
-
locale: options.locale
|
|
119363
|
-
}
|
|
119364
|
-
});
|
|
119365
|
-
client.attachSink(sink);
|
|
119366
|
-
sink.startPeriodicFlush();
|
|
119367
|
-
sink.retryDiskEvents().catch(() => {});
|
|
119368
|
-
}
|
|
119369
|
-
//#endregion
|
|
119370
|
-
//#region ../../packages/telemetry/src/crash.ts
|
|
119371
|
-
let phase = "startup";
|
|
119372
|
-
let installed = false;
|
|
119373
|
-
let installedUncaughtHandler = null;
|
|
119374
|
-
function setCrashPhase(nextPhase) {
|
|
119375
|
-
phase = nextPhase;
|
|
119376
|
-
}
|
|
119377
|
-
function installCrashHandlers() {
|
|
119378
|
-
return installCrashHandlersForClient(getDefaultTelemetryClient());
|
|
119379
|
-
}
|
|
119380
|
-
function installCrashHandlersForClient(client) {
|
|
119381
|
-
if (installed && installedUncaughtHandler !== null) return () => {
|
|
119382
|
-
uninstallCrashHandlers();
|
|
119383
|
-
};
|
|
119384
|
-
const trackCrash = (errorType, source) => {
|
|
119385
|
-
try {
|
|
119386
|
-
client.track("crash", {
|
|
119387
|
-
error_type: errorType,
|
|
119388
|
-
where: phase,
|
|
119389
|
-
source
|
|
119390
|
-
});
|
|
119391
|
-
client.flushSync();
|
|
119392
|
-
} catch {}
|
|
119393
|
-
};
|
|
119394
|
-
installedUncaughtHandler = (error, origin) => {
|
|
119395
|
-
if (isAbortError$1(error)) return;
|
|
119396
|
-
trackCrash(error.name || error.constructor.name, origin);
|
|
119397
|
-
};
|
|
119398
|
-
process.on("uncaughtExceptionMonitor", installedUncaughtHandler);
|
|
119399
|
-
installed = true;
|
|
119400
|
-
return () => {
|
|
119401
|
-
uninstallCrashHandlers();
|
|
119402
|
-
};
|
|
119403
|
-
}
|
|
119404
|
-
function uninstallCrashHandlers() {
|
|
119405
|
-
if (!installed) return;
|
|
119406
|
-
if (installedUncaughtHandler !== null) process.off("uncaughtExceptionMonitor", installedUncaughtHandler);
|
|
119407
|
-
installedUncaughtHandler = null;
|
|
119408
|
-
installed = false;
|
|
119409
|
-
}
|
|
119410
|
-
function isAbortError$1(reason) {
|
|
119411
|
-
return typeof reason === "object" && reason !== null && "name" in reason && reason.name === "AbortError";
|
|
119412
|
-
}
|
|
119413
|
-
//#endregion
|
|
119414
|
-
//#region ../../packages/telemetry/src/index.ts
|
|
119415
|
-
function track(event, properties = {}) {
|
|
119416
|
-
track$1(event, properties);
|
|
119417
|
-
}
|
|
119418
|
-
function setTelemetryContext(patch) {
|
|
119419
|
-
setContext(patch);
|
|
119420
|
-
}
|
|
119421
|
-
function withTelemetryContext(patch) {
|
|
119422
|
-
return withContext(patch);
|
|
119423
|
-
}
|
|
119424
|
-
async function shutdownTelemetry(options = {}) {
|
|
119425
|
-
await shutdown(options);
|
|
119426
|
-
}
|
|
119427
|
-
//#endregion
|
|
119428
118524
|
//#region src/constant/app.ts
|
|
119429
118525
|
const PRODUCT_NAME = "Scream Code";
|
|
119430
118526
|
const CLI_COMMAND_NAME = "scream";
|
|
119431
118527
|
const CLI_USER_AGENT_PRODUCT = "scream-code-cli";
|
|
119432
118528
|
const CLI_UI_MODE = "shell";
|
|
119433
|
-
const CLI_SHUTDOWN_TIMEOUT_MS = 3e3;
|
|
119434
118529
|
const SCREAM_CODE_HOME_ENV = "SCREAM_CODE_HOME";
|
|
119435
118530
|
const SCREAM_CODE_DATA_DIR_NAME = ".scream-code";
|
|
119436
118531
|
const SCREAM_CODE_UPDATE_DIR_NAME = "updates";
|
|
@@ -119500,32 +118595,6 @@ function camelToSnake(s) {
|
|
|
119500
118595
|
}
|
|
119501
118596
|
new Set(Object.keys(ScreamConfigSchema.shape).filter((k) => k !== "raw" && k !== "providers" && k !== "models" && k !== "hooks").map(camelToSnake));
|
|
119502
118597
|
//#endregion
|
|
119503
|
-
//#region src/cli/telemetry.ts
|
|
119504
|
-
function createCliTelemetryBootstrap() {
|
|
119505
|
-
let firstLaunch = false;
|
|
119506
|
-
const homeDir = resolveScreamHome();
|
|
119507
|
-
return {
|
|
119508
|
-
homeDir,
|
|
119509
|
-
deviceId: createScreamDeviceId(homeDir, { onFirstLaunch: () => {
|
|
119510
|
-
firstLaunch = true;
|
|
119511
|
-
} }),
|
|
119512
|
-
firstLaunch
|
|
119513
|
-
};
|
|
119514
|
-
}
|
|
119515
|
-
function initializeCliTelemetry(options) {
|
|
119516
|
-
initializeTelemetry({
|
|
119517
|
-
homeDir: options.harness.homeDir,
|
|
119518
|
-
deviceId: options.bootstrap.deviceId,
|
|
119519
|
-
enabled: options.config.telemetry !== false,
|
|
119520
|
-
appName: CLI_USER_AGENT_PRODUCT,
|
|
119521
|
-
version: options.version,
|
|
119522
|
-
uiMode: options.uiMode,
|
|
119523
|
-
model: options.model ?? options.config.defaultModel,
|
|
119524
|
-
getAccessToken: async () => null
|
|
119525
|
-
});
|
|
119526
|
-
if (options.bootstrap.firstLaunch) options.harness.track("first_launch");
|
|
119527
|
-
}
|
|
119528
|
-
//#endregion
|
|
119529
118598
|
//#region src/cli/update/types.ts
|
|
119530
118599
|
function emptyUpdateCache() {
|
|
119531
118600
|
return {
|
|
@@ -119695,57 +118764,17 @@ function registerExportCommand(parent, deps) {
|
|
|
119695
118764
|
}
|
|
119696
118765
|
function createDefaultExportDeps(overrides = {}) {
|
|
119697
118766
|
let harness;
|
|
119698
|
-
let telemetryBootstrap;
|
|
119699
|
-
let telemetryInitialized = false;
|
|
119700
|
-
let telemetryShutdown = false;
|
|
119701
118767
|
const identity = createScreamCodeHostIdentity();
|
|
119702
|
-
const telemetryClient = {
|
|
119703
|
-
track,
|
|
119704
|
-
withContext: withTelemetryContext,
|
|
119705
|
-
setContext: setTelemetryContext
|
|
119706
|
-
};
|
|
119707
|
-
const getTelemetryBootstrap = () => {
|
|
119708
|
-
telemetryBootstrap ??= createCliTelemetryBootstrap();
|
|
119709
|
-
return telemetryBootstrap;
|
|
119710
|
-
};
|
|
119711
118768
|
const getHarness = () => {
|
|
119712
|
-
const currentTelemetryBootstrap = getTelemetryBootstrap();
|
|
119713
118769
|
harness ??= new ScreamHarness({
|
|
119714
|
-
homeDir:
|
|
119715
|
-
identity
|
|
119716
|
-
telemetry: telemetryClient
|
|
118770
|
+
homeDir: resolveScreamHome(),
|
|
118771
|
+
identity
|
|
119717
118772
|
});
|
|
119718
118773
|
return harness;
|
|
119719
118774
|
};
|
|
119720
|
-
const initializeDefaultTelemetry = async () => {
|
|
119721
|
-
if (telemetryInitialized) return;
|
|
119722
|
-
const currentTelemetryBootstrap = getTelemetryBootstrap();
|
|
119723
|
-
const currentHarness = getHarness();
|
|
119724
|
-
await currentHarness.ensureConfigFile();
|
|
119725
|
-
initializeCliTelemetry({
|
|
119726
|
-
harness: currentHarness,
|
|
119727
|
-
bootstrap: currentTelemetryBootstrap,
|
|
119728
|
-
config: await currentHarness.getConfig(),
|
|
119729
|
-
version: identity.version,
|
|
119730
|
-
uiMode: CLI_UI_MODE
|
|
119731
|
-
});
|
|
119732
|
-
telemetryInitialized = true;
|
|
119733
|
-
};
|
|
119734
|
-
const shutdownDefaultTelemetry = async () => {
|
|
119735
|
-
if (!telemetryInitialized || telemetryShutdown) return;
|
|
119736
|
-
telemetryShutdown = true;
|
|
119737
|
-
await shutdownTelemetry({ timeoutMs: CLI_SHUTDOWN_TIMEOUT_MS });
|
|
119738
|
-
};
|
|
119739
118775
|
return {
|
|
119740
118776
|
listSessions: overrides.listSessions ?? ((workDir) => getHarness().listSessions({ workDir })),
|
|
119741
|
-
exportSession: overrides.exportSession ?? (async (input) =>
|
|
119742
|
-
await initializeDefaultTelemetry();
|
|
119743
|
-
try {
|
|
119744
|
-
return await getHarness().exportSession(input);
|
|
119745
|
-
} finally {
|
|
119746
|
-
await shutdownDefaultTelemetry();
|
|
119747
|
-
}
|
|
119748
|
-
}),
|
|
118777
|
+
exportSession: overrides.exportSession ?? (async (input) => getHarness().exportSession(input)),
|
|
119749
118778
|
version: overrides.version ?? identity.version,
|
|
119750
118779
|
getInstallSource: overrides.getInstallSource ?? (() => Promise.resolve(detectInstallSource())),
|
|
119751
118780
|
getShellEnv: overrides.getShellEnv ?? detectShellEnvironment,
|
|
@@ -119864,23 +118893,15 @@ const PROMPT_MAIN_AGENT_ID = "main";
|
|
|
119864
118893
|
const PROMPT_BLOCK_BULLET = "• ";
|
|
119865
118894
|
const PROMPT_BLOCK_INDENT = " ";
|
|
119866
118895
|
async function runPrompt(opts, version, io = {}) {
|
|
119867
|
-
const startedAt = Date.now();
|
|
119868
118896
|
const stdout = io.stdout ?? process.stdout;
|
|
119869
118897
|
const stderr = io.stderr ?? process.stderr;
|
|
119870
118898
|
const promptProcess = io.process ?? process;
|
|
119871
118899
|
const workDir = process.cwd();
|
|
119872
|
-
const telemetryBootstrap = createCliTelemetryBootstrap();
|
|
119873
|
-
const telemetryClient = {
|
|
119874
|
-
track,
|
|
119875
|
-
withContext: withTelemetryContext,
|
|
119876
|
-
setContext: setTelemetryContext
|
|
119877
|
-
};
|
|
119878
118900
|
const harness = new ScreamHarness({
|
|
119879
|
-
homeDir:
|
|
118901
|
+
homeDir: resolveScreamHome(),
|
|
119880
118902
|
identity: createScreamCodeHostIdentity(version),
|
|
119881
118903
|
uiMode: PROMPT_UI_MODE,
|
|
119882
|
-
skillDirs: opts.skillsDirs
|
|
119883
|
-
telemetry: telemetryClient
|
|
118904
|
+
skillDirs: opts.skillsDirs
|
|
119884
118905
|
});
|
|
119885
118906
|
log.info("scream-code starting", {
|
|
119886
118907
|
version,
|
|
@@ -119895,11 +118916,9 @@ async function runPrompt(opts, version, io = {}) {
|
|
|
119895
118916
|
const cleanupPromptRun = async () => {
|
|
119896
118917
|
cleanupPromise ??= (async () => {
|
|
119897
118918
|
removeTerminationCleanup?.();
|
|
119898
|
-
setCrashPhase("shutdown");
|
|
119899
118919
|
try {
|
|
119900
118920
|
await restorePromptSessionPermission();
|
|
119901
118921
|
} finally {
|
|
119902
|
-
await shutdownTelemetry({ timeoutMs: CLI_SHUTDOWN_TIMEOUT_MS });
|
|
119903
118922
|
await harness.close();
|
|
119904
118923
|
}
|
|
119905
118924
|
})();
|
|
@@ -119908,30 +118927,13 @@ async function runPrompt(opts, version, io = {}) {
|
|
|
119908
118927
|
removeTerminationCleanup = installPromptTerminationCleanup(promptProcess, cleanupPromptRun);
|
|
119909
118928
|
try {
|
|
119910
118929
|
await harness.ensureConfigFile();
|
|
119911
|
-
const
|
|
119912
|
-
const { session, resumed, restorePermission, telemetryModel } = await resolvePromptSession(harness, opts, workDir, config.defaultModel, stderr, (restorePermission) => {
|
|
118930
|
+
const { session, restorePermission } = await resolvePromptSession(harness, opts, workDir, (await harness.getConfig()).defaultModel, stderr, (restorePermission) => {
|
|
119913
118931
|
restorePromptSessionPermission = restorePermission;
|
|
119914
118932
|
});
|
|
119915
118933
|
restorePromptSessionPermission = restorePermission;
|
|
119916
|
-
initializeCliTelemetry({
|
|
119917
|
-
harness,
|
|
119918
|
-
bootstrap: telemetryBootstrap,
|
|
119919
|
-
config,
|
|
119920
|
-
version,
|
|
119921
|
-
uiMode: PROMPT_UI_MODE,
|
|
119922
|
-
model: telemetryModel
|
|
119923
|
-
});
|
|
119924
|
-
setCrashPhase("runtime");
|
|
119925
|
-
withTelemetryContext({ sessionId: session.id }).track("started", {
|
|
119926
|
-
resumed,
|
|
119927
|
-
yolo: false,
|
|
119928
|
-
plan: false,
|
|
119929
|
-
afk: true
|
|
119930
|
-
});
|
|
119931
118934
|
const outputFormat = opts.outputFormat ?? "text";
|
|
119932
118935
|
await runPromptTurn(session, opts.prompt, outputFormat, stdout, stderr);
|
|
119933
118936
|
writeResumeHint(session.id, outputFormat, stdout, stderr);
|
|
119934
|
-
withTelemetryContext({ sessionId: session.id }).track("exit", { duration_s: (Date.now() - startedAt) / 1e3 });
|
|
119935
118937
|
} finally {
|
|
119936
118938
|
await cleanupPromptRun();
|
|
119937
118939
|
}
|
|
@@ -119948,30 +118950,26 @@ async function resolvePromptSession(harness, opts, workDir, defaultModel, stderr
|
|
|
119948
118950
|
throw new Error(`会话 "${opts.session}" 是在其他目录下创建的。`);
|
|
119949
118951
|
}
|
|
119950
118952
|
const session = await harness.resumeSession({ id: opts.session });
|
|
119951
|
-
const
|
|
119952
|
-
const restorePermission = await forcePromptPermission(session, status.permission, setRestorePermission);
|
|
118953
|
+
const restorePermission = await forcePromptPermission(session, (await session.getStatus()).permission, setRestorePermission);
|
|
119953
118954
|
if (opts.model !== void 0) await session.setModel(opts.model);
|
|
119954
118955
|
installHeadlessHandlers(session);
|
|
119955
118956
|
return {
|
|
119956
118957
|
session,
|
|
119957
118958
|
resumed: true,
|
|
119958
|
-
restorePermission
|
|
119959
|
-
telemetryModel: configuredModel(opts.model, status.model, defaultModel)
|
|
118959
|
+
restorePermission
|
|
119960
118960
|
};
|
|
119961
118961
|
}
|
|
119962
118962
|
if (opts.continue) {
|
|
119963
118963
|
const previous = (await harness.listSessions({ workDir }))[0];
|
|
119964
118964
|
if (previous !== void 0) {
|
|
119965
118965
|
const session = await harness.resumeSession({ id: previous.id });
|
|
119966
|
-
const
|
|
119967
|
-
const restorePermission = await forcePromptPermission(session, status.permission, setRestorePermission);
|
|
118966
|
+
const restorePermission = await forcePromptPermission(session, (await session.getStatus()).permission, setRestorePermission);
|
|
119968
118967
|
if (opts.model !== void 0) await session.setModel(opts.model);
|
|
119969
118968
|
installHeadlessHandlers(session);
|
|
119970
118969
|
return {
|
|
119971
118970
|
session,
|
|
119972
118971
|
resumed: true,
|
|
119973
|
-
restorePermission
|
|
119974
|
-
telemetryModel: configuredModel(opts.model, status.model, defaultModel)
|
|
118972
|
+
restorePermission
|
|
119975
118973
|
};
|
|
119976
118974
|
}
|
|
119977
118975
|
stderr.write(`"${workDir}" 下没有可继续的会话;正在启动新会话。\n`);
|
|
@@ -119986,8 +118984,7 @@ async function resolvePromptSession(harness, opts, workDir, defaultModel, stderr
|
|
|
119986
118984
|
return {
|
|
119987
118985
|
session,
|
|
119988
118986
|
resumed: false,
|
|
119989
|
-
restorePermission: async () => {}
|
|
119990
|
-
telemetryModel: model
|
|
118987
|
+
restorePermission: async () => {}
|
|
119991
118988
|
};
|
|
119992
118989
|
}
|
|
119993
118990
|
async function forcePromptPermission(session, previousPermission, setRestorePermission) {
|
|
@@ -120044,90 +119041,95 @@ function runPromptTurn(session, prompt, outputFormat, stdout, stderr) {
|
|
|
120044
119041
|
const outputWriter = outputFormat === "stream-json" ? new PromptJsonWriter(stdout) : new PromptTranscriptWriter(stdout, stderr);
|
|
120045
119042
|
let settled = false;
|
|
120046
119043
|
let unsubscribe;
|
|
120047
|
-
|
|
120048
|
-
|
|
120049
|
-
|
|
120050
|
-
|
|
120051
|
-
|
|
120052
|
-
|
|
120053
|
-
|
|
120054
|
-
|
|
119044
|
+
let resolve;
|
|
119045
|
+
let reject;
|
|
119046
|
+
const promise = new Promise((res, rej) => {
|
|
119047
|
+
resolve = res;
|
|
119048
|
+
reject = rej;
|
|
119049
|
+
});
|
|
119050
|
+
const finish = (error) => {
|
|
119051
|
+
if (settled) return;
|
|
119052
|
+
settled = true;
|
|
119053
|
+
unsubscribe?.();
|
|
119054
|
+
outputWriter.finish();
|
|
119055
|
+
if (error !== void 0) {
|
|
119056
|
+
reject(error);
|
|
119057
|
+
return;
|
|
119058
|
+
}
|
|
119059
|
+
resolve();
|
|
119060
|
+
};
|
|
119061
|
+
unsubscribe = session.onEvent((event) => {
|
|
119062
|
+
if (event.type === "error") {
|
|
119063
|
+
if (event.agentId !== PROMPT_MAIN_AGENT_ID) return;
|
|
119064
|
+
finish(/* @__PURE__ */ new Error(`${event.code}: ${event.message}`));
|
|
119065
|
+
return;
|
|
119066
|
+
}
|
|
119067
|
+
if (event.type === "turn.started" && activeTurnId === void 0) {
|
|
119068
|
+
if (event.agentId !== PROMPT_MAIN_AGENT_ID) return;
|
|
119069
|
+
activeTurnId = event.turnId;
|
|
119070
|
+
activeAgentId = event.agentId;
|
|
119071
|
+
return;
|
|
119072
|
+
}
|
|
119073
|
+
if (activeTurnId === void 0 || activeAgentId === void 0 || !hasTurnId(event) || event.turnId !== activeTurnId || event.agentId !== activeAgentId) return;
|
|
119074
|
+
switch (event.type) {
|
|
119075
|
+
case "turn.step.started":
|
|
119076
|
+
case "turn.step.interrupted":
|
|
119077
|
+
outputWriter.flushAssistant();
|
|
120055
119078
|
return;
|
|
120056
|
-
|
|
120057
|
-
|
|
120058
|
-
};
|
|
120059
|
-
unsubscribe = session.onEvent((event) => {
|
|
120060
|
-
if (event.type === "error") {
|
|
120061
|
-
if (event.agentId !== PROMPT_MAIN_AGENT_ID) return;
|
|
120062
|
-
finish(/* @__PURE__ */ new Error(`${event.code}: ${event.message}`));
|
|
119079
|
+
case "turn.step.retrying":
|
|
119080
|
+
outputWriter.discardAssistant();
|
|
120063
119081
|
return;
|
|
120064
|
-
|
|
120065
|
-
|
|
120066
|
-
if (event.agentId !== PROMPT_MAIN_AGENT_ID) return;
|
|
120067
|
-
activeTurnId = event.turnId;
|
|
120068
|
-
activeAgentId = event.agentId;
|
|
119082
|
+
case "assistant.delta":
|
|
119083
|
+
outputWriter.writeAssistantDelta(event.delta);
|
|
120069
119084
|
return;
|
|
120070
|
-
|
|
120071
|
-
|
|
120072
|
-
|
|
120073
|
-
|
|
120074
|
-
|
|
120075
|
-
|
|
120076
|
-
|
|
120077
|
-
|
|
120078
|
-
|
|
120079
|
-
|
|
120080
|
-
|
|
120081
|
-
|
|
120082
|
-
|
|
120083
|
-
|
|
120084
|
-
|
|
120085
|
-
|
|
120086
|
-
|
|
120087
|
-
|
|
120088
|
-
|
|
120089
|
-
|
|
120090
|
-
|
|
120091
|
-
return;
|
|
120092
|
-
case "tool.call.delta":
|
|
120093
|
-
outputWriter.writeToolCallDelta(event.toolCallId, event.name, event.argumentsPart);
|
|
120094
|
-
return;
|
|
120095
|
-
case "tool.result":
|
|
120096
|
-
outputWriter.writeToolResult(event.toolCallId, event.output);
|
|
120097
|
-
return;
|
|
120098
|
-
case "tool.progress":
|
|
120099
|
-
if (event.update.text !== void 0 && event.update.text.length > 0) stderr.write(event.update.text.endsWith("\n") ? event.update.text : `${event.update.text}\n`);
|
|
120100
|
-
return;
|
|
120101
|
-
case "turn.ended":
|
|
120102
|
-
if (event.reason === "completed") {
|
|
120103
|
-
finish();
|
|
120104
|
-
return;
|
|
120105
|
-
}
|
|
120106
|
-
finish(new Error(formatTurnEndedFailure(event)));
|
|
119085
|
+
case "hook.result":
|
|
119086
|
+
outputWriter.writeHookResult(event);
|
|
119087
|
+
return;
|
|
119088
|
+
case "thinking.delta":
|
|
119089
|
+
outputWriter.writeThinkingDelta(event.delta);
|
|
119090
|
+
return;
|
|
119091
|
+
case "tool.call.started":
|
|
119092
|
+
outputWriter.writeToolCall(event.toolCallId, event.name, event.args);
|
|
119093
|
+
return;
|
|
119094
|
+
case "tool.call.delta":
|
|
119095
|
+
outputWriter.writeToolCallDelta(event.toolCallId, event.name, event.argumentsPart);
|
|
119096
|
+
return;
|
|
119097
|
+
case "tool.result":
|
|
119098
|
+
outputWriter.writeToolResult(event.toolCallId, event.output);
|
|
119099
|
+
return;
|
|
119100
|
+
case "tool.progress":
|
|
119101
|
+
if (event.update.text !== void 0 && event.update.text.length > 0) stderr.write(event.update.text.endsWith("\n") ? event.update.text : `${event.update.text}\n`);
|
|
119102
|
+
return;
|
|
119103
|
+
case "turn.ended":
|
|
119104
|
+
if (event.reason === "completed") {
|
|
119105
|
+
finish();
|
|
120107
119106
|
return;
|
|
120108
|
-
|
|
120109
|
-
|
|
120110
|
-
|
|
120111
|
-
|
|
120112
|
-
|
|
120113
|
-
|
|
120114
|
-
|
|
120115
|
-
|
|
120116
|
-
|
|
120117
|
-
|
|
120118
|
-
|
|
120119
|
-
|
|
120120
|
-
|
|
120121
|
-
|
|
120122
|
-
|
|
120123
|
-
|
|
120124
|
-
|
|
120125
|
-
|
|
120126
|
-
|
|
120127
|
-
|
|
120128
|
-
|
|
120129
|
-
|
|
119107
|
+
}
|
|
119108
|
+
finish(new Error(formatTurnEndedFailure(event)));
|
|
119109
|
+
return;
|
|
119110
|
+
case "agent.status.updated":
|
|
119111
|
+
case "background.task.started":
|
|
119112
|
+
case "background.task.terminated":
|
|
119113
|
+
case "background.task.updated":
|
|
119114
|
+
case "compaction.blocked":
|
|
119115
|
+
case "compaction.cancelled":
|
|
119116
|
+
case "compaction.completed":
|
|
119117
|
+
case "compaction.started":
|
|
119118
|
+
case "mcp.server.status":
|
|
119119
|
+
case "session.meta.updated":
|
|
119120
|
+
case "skill.activated":
|
|
119121
|
+
case "subagent.completed":
|
|
119122
|
+
case "subagent.failed":
|
|
119123
|
+
case "subagent.spawned":
|
|
119124
|
+
case "tool.list.updated":
|
|
119125
|
+
case "turn.started":
|
|
119126
|
+
case "turn.step.completed": return;
|
|
119127
|
+
}
|
|
119128
|
+
});
|
|
119129
|
+
session.prompt(prompt).catch((error) => {
|
|
119130
|
+
finish(error instanceof Error ? error : new Error(String(error)));
|
|
120130
119131
|
});
|
|
119132
|
+
return promise;
|
|
120131
119133
|
}
|
|
120132
119134
|
var PromptTranscriptWriter = class {
|
|
120133
119135
|
assistantWriter;
|
|
@@ -121757,10 +120759,6 @@ async function handleConnectCommand(host, args) {
|
|
|
121757
120759
|
defaultThinking: config.defaultThinking
|
|
121758
120760
|
});
|
|
121759
120761
|
await host.authFlow.refreshConfigAfterLogin();
|
|
121760
|
-
host.track("config", {
|
|
121761
|
-
provider: providerId,
|
|
121762
|
-
model: selection.model.id
|
|
121763
|
-
});
|
|
121764
120762
|
host.showStatus(`Connected: ${entry.name ?? providerId} · ${selection.model.id}`);
|
|
121765
120763
|
}
|
|
121766
120764
|
async function handleLogoutCommand(host) {
|
|
@@ -121794,7 +120792,6 @@ async function handleLogoutCommand(host) {
|
|
|
121794
120792
|
availableProviders: updated.providers ?? {}
|
|
121795
120793
|
});
|
|
121796
120794
|
}
|
|
121797
|
-
host.track("logout", { provider: target });
|
|
121798
120795
|
host.showStatus(`已删除模型商: ${target}.`);
|
|
121799
120796
|
}
|
|
121800
120797
|
async function handleDiyConfig(host) {
|
|
@@ -121848,11 +120845,6 @@ async function handleDiyConfig(host) {
|
|
|
121848
120845
|
defaultThinking: config.defaultThinking
|
|
121849
120846
|
});
|
|
121850
120847
|
await host.authFlow.refreshConfigAfterLogin();
|
|
121851
|
-
host.track("config_diy", {
|
|
121852
|
-
providerId,
|
|
121853
|
-
model: modelId,
|
|
121854
|
-
wire
|
|
121855
|
-
});
|
|
121856
120848
|
host.showStatus(`已连接: ${providerId} · ${modelId} (${wire})`);
|
|
121857
120849
|
}
|
|
121858
120850
|
//#endregion
|
|
@@ -122188,6 +121180,10 @@ const darkColors = {
|
|
|
122188
121180
|
textStrong: dark.gray50,
|
|
122189
121181
|
textDim: dark.gray500,
|
|
122190
121182
|
textMuted: dark.gray600,
|
|
121183
|
+
mdLink: "#56B6C2",
|
|
121184
|
+
mdCodeBlock: "#9CDCFE",
|
|
121185
|
+
mdCodeBlockBorder: "#5C6370",
|
|
121186
|
+
mdQuote: "#7F848E",
|
|
122191
121187
|
border: dark.gray700,
|
|
122192
121188
|
borderFocus: dark.gold400,
|
|
122193
121189
|
success: dark.green400,
|
|
@@ -122213,6 +121209,10 @@ const lightColors = {
|
|
|
122213
121209
|
textStrong: light.gray900,
|
|
122214
121210
|
textDim: light.gray700,
|
|
122215
121211
|
textMuted: light.gray600,
|
|
121212
|
+
mdLink: "#007A8A",
|
|
121213
|
+
mdCodeBlock: "#1565C0",
|
|
121214
|
+
mdCodeBlockBorder: "#9E9E9E",
|
|
121215
|
+
mdQuote: "#616161",
|
|
122216
121216
|
border: light.gray500,
|
|
122217
121217
|
borderFocus: light.gold700,
|
|
122218
121218
|
success: light.green700,
|
|
@@ -122269,17 +121269,16 @@ const HEADING_HASH_PREFIX = /^((?:\u001B\[[0-9;]*m)*)#{1,6}[ \t]+/;
|
|
|
122269
121269
|
function createMarkdownTheme(colors) {
|
|
122270
121270
|
const stripHash = (text) => text.replace(HEADING_HASH_PREFIX, "$1");
|
|
122271
121271
|
const muted = chalk.hex(colors.textMuted);
|
|
122272
|
-
const dim = chalk.hex(colors.textDim);
|
|
122273
121272
|
const border = chalk.hex(colors.border);
|
|
122274
121273
|
return {
|
|
122275
121274
|
heading: (text) => chalk.bold.hex(colors.text)(stripHash(text)),
|
|
122276
|
-
link: (text) => chalk.hex(colors.
|
|
121275
|
+
link: (text) => chalk.hex(colors.mdLink)(text),
|
|
122277
121276
|
linkUrl: (text) => muted(text),
|
|
122278
121277
|
code: (text) => chalk.hex(colors.primary)(text),
|
|
122279
|
-
codeBlock: (text) => text,
|
|
122280
|
-
codeBlockBorder: (text) =>
|
|
122281
|
-
quote: (text) =>
|
|
122282
|
-
quoteBorder: (text) =>
|
|
121278
|
+
codeBlock: (text) => chalk.hex(colors.mdCodeBlock)(text),
|
|
121279
|
+
codeBlockBorder: (text) => chalk.hex(colors.mdCodeBlockBorder)(text),
|
|
121280
|
+
quote: (text) => chalk.hex(colors.mdQuote)(text),
|
|
121281
|
+
quoteBorder: (text) => chalk.hex(colors.mdQuote)(text),
|
|
122283
121282
|
hr: (text) => border(text),
|
|
122284
121283
|
listBullet: (text) => chalk.hex(colors.roleAssistant)(text.replace(/^-/, "•")),
|
|
122285
121284
|
bold: (text) => chalk.bold(text),
|
|
@@ -122918,10 +121917,6 @@ async function performModelSwitch(host, alias, thinking) {
|
|
|
122918
121917
|
model: alias,
|
|
122919
121918
|
thinking
|
|
122920
121919
|
});
|
|
122921
|
-
if (session === void 0 && runtimeChanged) {
|
|
122922
|
-
if (alias !== prevModel) host.track("model_switch", { model: alias });
|
|
122923
|
-
if (thinking !== prevThinking) host.track("thinking_toggle", { enabled: thinking });
|
|
122924
|
-
}
|
|
122925
121920
|
let persisted = false;
|
|
122926
121921
|
try {
|
|
122927
121922
|
persisted = await persistModelSelection(host, alias, thinking);
|
|
@@ -122974,7 +121969,6 @@ async function applyThemeChoice(host, theme) {
|
|
|
122974
121969
|
const resolved = theme === "auto" ? host.state.theme.resolvedTheme : theme;
|
|
122975
121970
|
host.applyTheme(theme, resolved);
|
|
122976
121971
|
host.refreshTerminalThemeTracking();
|
|
122977
|
-
host.track("theme_switch", { theme });
|
|
122978
121972
|
const detail = theme === "auto" ? ` (tracking terminal; current: ${resolved})` : "";
|
|
122979
121973
|
host.showStatus(`Theme set to "${theme}"${detail}.`);
|
|
122980
121974
|
}
|
|
@@ -123358,7 +122352,6 @@ async function handleInitCommand(host) {
|
|
|
123358
122352
|
host.beginSessionRequest();
|
|
123359
122353
|
try {
|
|
123360
122354
|
await session.init();
|
|
123361
|
-
host.track("init_complete");
|
|
123362
122355
|
host.streamingUI.finalizeTurn((item) => {
|
|
123363
122356
|
host.sendQueuedMessage(session, item);
|
|
123364
122357
|
});
|
|
@@ -124113,22 +123106,15 @@ var AssistantMessageComponent = class {
|
|
|
124113
123106
|
}
|
|
124114
123107
|
updateContent(text) {
|
|
124115
123108
|
const trimmedText = text.trim();
|
|
124116
|
-
|
|
124117
|
-
if (trimmedText === previousTrimmed) {
|
|
123109
|
+
if (trimmedText === this.lastText.trim()) {
|
|
124118
123110
|
this.lastText = text;
|
|
124119
123111
|
return;
|
|
124120
123112
|
}
|
|
124121
123113
|
this.lastText = text;
|
|
124122
123114
|
this.cachedWidth = void 0;
|
|
124123
123115
|
this.cachedLines = void 0;
|
|
124124
|
-
|
|
124125
|
-
if (
|
|
124126
|
-
markdownChild.setText(trimmedText);
|
|
124127
|
-
return;
|
|
124128
|
-
}
|
|
124129
|
-
this.contentContainer.clear();
|
|
124130
|
-
this.markdownChild = void 0;
|
|
124131
|
-
if (trimmedText.length > 0) {
|
|
123116
|
+
if (this.markdownChild !== void 0) this.markdownChild.setText(trimmedText);
|
|
123117
|
+
else if (trimmedText.length > 0) {
|
|
124132
123118
|
this.markdownChild = new Markdown(trimmedText, 0, 0, this.markdownTheme);
|
|
124133
123119
|
this.contentContainer.addChild(this.markdownChild);
|
|
124134
123120
|
}
|
|
@@ -128348,10 +127334,6 @@ async function executeSlashCommand(host, input) {
|
|
|
128348
127334
|
switch (intent.kind) {
|
|
128349
127335
|
case "not-command": return;
|
|
128350
127336
|
case "blocked":
|
|
128351
|
-
host.track("input_command_invalid", {
|
|
128352
|
-
reason: "blocked",
|
|
128353
|
-
command: intent.commandName
|
|
128354
|
-
});
|
|
128355
127337
|
host.showError(slashBusyMessage(intent.commandName, intent.reason));
|
|
128356
127338
|
return;
|
|
128357
127339
|
case "skill": {
|
|
@@ -128360,10 +127342,6 @@ async function executeSlashCommand(host, input) {
|
|
|
128360
127342
|
host.showError(LLM_NOT_SET_MESSAGE);
|
|
128361
127343
|
return;
|
|
128362
127344
|
}
|
|
128363
|
-
host.track("input_command", {
|
|
128364
|
-
command: intent.commandName,
|
|
128365
|
-
skill_name: intent.skillName
|
|
128366
|
-
});
|
|
128367
127345
|
host.sendSkillActivation(session, intent.skillName, intent.args);
|
|
128368
127346
|
return;
|
|
128369
127347
|
}
|
|
@@ -128371,8 +127349,6 @@ async function executeSlashCommand(host, input) {
|
|
|
128371
127349
|
host.sendNormalUserInput(intent.input);
|
|
128372
127350
|
return;
|
|
128373
127351
|
case "builtin":
|
|
128374
|
-
host.track("input_command", { command: intent.name });
|
|
128375
|
-
if (intent.name === "new" && parsedCommand?.name === "clear") host.track("clear");
|
|
128376
127352
|
try {
|
|
128377
127353
|
const args = intent.name === "goal" && parsedCommand?.name === "goaloff" ? "off" : intent.args;
|
|
128378
127354
|
await handleBuiltInSlashCommand(host, intent.name, args);
|
|
@@ -129304,16 +128280,12 @@ var EditorKeyboardController = class {
|
|
|
129304
128280
|
return;
|
|
129305
128281
|
}
|
|
129306
128282
|
const next = !host.state.appState.planMode;
|
|
129307
|
-
host.track("shortcut_plan_toggle", { enabled: next });
|
|
129308
|
-
host.track("shortcut_mode_switch", { to_mode: next ? "plan" : "agent" });
|
|
129309
128283
|
host.handlePlanToggle(next);
|
|
129310
128284
|
};
|
|
129311
128285
|
editor.onOpenExternalEditor = () => {
|
|
129312
|
-
host.track("shortcut_editor");
|
|
129313
128286
|
this.openExternalEditor();
|
|
129314
128287
|
};
|
|
129315
128288
|
editor.onToggleToolExpand = () => {
|
|
129316
|
-
host.track("shortcut_expand");
|
|
129317
128289
|
host.toggleToolOutputExpansion();
|
|
129318
128290
|
};
|
|
129319
128291
|
editor.onTogglePlanExpand = () => host.togglePlanExpansion();
|
|
@@ -129337,15 +128309,6 @@ var EditorKeyboardController = class {
|
|
|
129337
128309
|
host.updateQueueDisplay();
|
|
129338
128310
|
host.state.ui.requestRender();
|
|
129339
128311
|
};
|
|
129340
|
-
editor.onUndo = () => {
|
|
129341
|
-
host.track("undo");
|
|
129342
|
-
};
|
|
129343
|
-
editor.onInsertNewline = () => {
|
|
129344
|
-
host.track("shortcut_newline");
|
|
129345
|
-
};
|
|
129346
|
-
editor.onTextPaste = () => {
|
|
129347
|
-
host.track("shortcut_paste", { kind: "text" });
|
|
129348
|
-
};
|
|
129349
128312
|
editor.onUpArrowEmpty = () => {
|
|
129350
128313
|
if (host.state.appState.streamingPhase === "idle" && !host.state.appState.isCompacting) return false;
|
|
129351
128314
|
const recalled = host.recallLastQueued();
|
|
@@ -129407,7 +128370,6 @@ var EditorKeyboardController = class {
|
|
|
129407
128370
|
const attachment = this.imageStore.addVideo(media.mimeType, media.sourcePath, media.filename);
|
|
129408
128371
|
this.host.state.editor.insertTextAtCursor?.(`${attachment.placeholder} `);
|
|
129409
128372
|
this.host.state.ui.requestRender();
|
|
129410
|
-
this.host.track("shortcut_paste", { kind: "video" });
|
|
129411
128373
|
return true;
|
|
129412
128374
|
}
|
|
129413
128375
|
const meta = parseImageMeta(media.bytes);
|
|
@@ -129415,7 +128377,6 @@ var EditorKeyboardController = class {
|
|
|
129415
128377
|
const attachment = this.imageStore.addImage(media.bytes, meta.mime, meta.width, meta.height);
|
|
129416
128378
|
this.host.state.editor.insertTextAtCursor?.(`${attachment.placeholder} `);
|
|
129417
128379
|
this.host.state.ui.requestRender();
|
|
129418
|
-
this.host.track("shortcut_paste", { kind: "image" });
|
|
129419
128380
|
return true;
|
|
129420
128381
|
}
|
|
129421
128382
|
async openExternalEditor() {
|
|
@@ -133149,7 +132110,7 @@ var TranscriptController = class TranscriptController {
|
|
|
133149
132110
|
committedComponent;
|
|
133150
132111
|
liveComponentToEntry = /* @__PURE__ */ new Map();
|
|
133151
132112
|
pendingComponents = /* @__PURE__ */ new Set();
|
|
133152
|
-
static LIVE_LIMIT =
|
|
132113
|
+
static LIVE_LIMIT = 150;
|
|
133153
132114
|
constructor(host) {
|
|
133154
132115
|
this.host = host;
|
|
133155
132116
|
}
|
|
@@ -133176,6 +132137,7 @@ var TranscriptController = class TranscriptController {
|
|
|
133176
132137
|
}
|
|
133177
132138
|
commit() {
|
|
133178
132139
|
const { state } = this.host;
|
|
132140
|
+
if (state.appState.streamingPhase !== "idle") return;
|
|
133179
132141
|
const container = state.transcriptContainer;
|
|
133180
132142
|
const children = container.children;
|
|
133181
132143
|
if (children.length <= TranscriptController.LIVE_LIMIT) return;
|
|
@@ -133354,6 +132316,7 @@ var TranscriptController = class TranscriptController {
|
|
|
133354
132316
|
}
|
|
133355
132317
|
toggleToolOutputExpansion() {
|
|
133356
132318
|
const { state } = this.host;
|
|
132319
|
+
state.ui.setClearOnShrink(false);
|
|
133357
132320
|
state.toolOutputExpanded = !state.toolOutputExpanded;
|
|
133358
132321
|
const walk = (children) => {
|
|
133359
132322
|
for (const child of children) {
|
|
@@ -133366,6 +132329,7 @@ var TranscriptController = class TranscriptController {
|
|
|
133366
132329
|
}
|
|
133367
132330
|
togglePlanExpansion() {
|
|
133368
132331
|
const { state } = this.host;
|
|
132332
|
+
state.ui.setClearOnShrink(false);
|
|
133369
132333
|
const next = !state.planExpanded;
|
|
133370
132334
|
let toggled = false;
|
|
133371
132335
|
for (const child of state.transcriptContainer.children) if (isPlanExpandable(child) && child.setPlanExpanded(next)) toggled = true;
|
|
@@ -134558,7 +133522,6 @@ var InputController = class {
|
|
|
134558
133522
|
parts: options?.parts,
|
|
134559
133523
|
imageAttachmentIds: options?.imageAttachmentIds !== void 0 && options.imageAttachmentIds.length > 0 ? options.imageAttachmentIds : void 0
|
|
134560
133524
|
});
|
|
134561
|
-
this.host.track("input_queue");
|
|
134562
133525
|
}
|
|
134563
133526
|
sendMessageInternal(session, input, options) {
|
|
134564
133527
|
const imageAttachmentIds = options?.imageAttachmentIds !== void 0 && options.imageAttachmentIds.length > 0 ? options.imageAttachmentIds : void 0;
|
|
@@ -135681,9 +134644,6 @@ var CustomEditor = class extends Editor {
|
|
|
135681
134644
|
onTogglePlanExpand;
|
|
135682
134645
|
onOpenExternalEditor;
|
|
135683
134646
|
onCtrlS;
|
|
135684
|
-
onUndo;
|
|
135685
|
-
onInsertNewline;
|
|
135686
|
-
onTextPaste;
|
|
135687
134647
|
/**
|
|
135688
134648
|
* Called when ↑ is pressed in an empty editor. Return `true` to consume
|
|
135689
134649
|
* the key (e.g. recalled a queued message); return `false` to fall
|
|
@@ -135794,10 +134754,7 @@ var CustomEditor = class extends Editor {
|
|
|
135794
134754
|
if (this.onPasteImage !== void 0) {
|
|
135795
134755
|
const handler = this.onPasteImage;
|
|
135796
134756
|
handler().then((handled) => {
|
|
135797
|
-
if (!handled)
|
|
135798
|
-
this.onTextPaste?.();
|
|
135799
|
-
super.handleInput.call(this, normalized);
|
|
135800
|
-
}
|
|
134757
|
+
if (!handled) super.handleInput.call(this, normalized);
|
|
135801
134758
|
});
|
|
135802
134759
|
return;
|
|
135803
134760
|
}
|
|
@@ -135831,10 +134788,8 @@ var CustomEditor = class extends Editor {
|
|
|
135831
134788
|
this.onShiftTab?.();
|
|
135832
134789
|
return;
|
|
135833
134790
|
}
|
|
135834
|
-
if (matchesKey(normalized, Key.ctrl("-"))) this.onUndo?.();
|
|
135835
134791
|
const newlineInput = getNewlineInput(normalized);
|
|
135836
134792
|
if (newlineInput !== void 0) {
|
|
135837
|
-
this.onInsertNewline?.();
|
|
135838
134793
|
super.handleInput(newlineInput);
|
|
135839
134794
|
return;
|
|
135840
134795
|
}
|
|
@@ -136106,6 +135061,7 @@ function createTUIState(options) {
|
|
|
136106
135061
|
const theme = createScreamTUIThemeBundle(initialAppState.theme, options.resolvedTheme);
|
|
136107
135062
|
const terminal = new ProcessTerminal();
|
|
136108
135063
|
const ui = new TUI(terminal);
|
|
135064
|
+
ui.setClearOnShrink(false);
|
|
136109
135065
|
const uiAny = ui;
|
|
136110
135066
|
const originalDoRender = uiAny["doRender"].bind(ui);
|
|
136111
135067
|
uiAny["doRender"] = () => {
|
|
@@ -136643,7 +135599,6 @@ var SessionManager = class {
|
|
|
136643
135599
|
async setSession(session) {
|
|
136644
135600
|
await this.unloadCurrentSession("switching session")?.close({ extractMemories: false });
|
|
136645
135601
|
this.host.session = session;
|
|
136646
|
-
this.host.harness.setTelemetryContext({ sessionId: session.id });
|
|
136647
135602
|
this.registerSessionHandlers(session);
|
|
136648
135603
|
}
|
|
136649
135604
|
async syncRuntimeState(session = this.requireSession()) {
|
|
@@ -136682,7 +135637,6 @@ var SessionManager = class {
|
|
|
136682
135637
|
this.host.approvalController.cancelAll(reason);
|
|
136683
135638
|
this.host.questionController.cancelAll(reason);
|
|
136684
135639
|
this.host.session = void 0;
|
|
136685
|
-
this.host.harness.setTelemetryContext({ sessionId: null });
|
|
136686
135640
|
return previous;
|
|
136687
135641
|
}
|
|
136688
135642
|
clearReverseRpcPanels() {
|
|
@@ -138780,9 +137734,6 @@ var ScreamTUI = class {
|
|
|
138780
137734
|
lifecycleController;
|
|
138781
137735
|
inputController;
|
|
138782
137736
|
onExit;
|
|
138783
|
-
track(event, properties) {
|
|
138784
|
-
this.harness.track(event, properties);
|
|
138785
|
-
}
|
|
138786
137737
|
constructor(harness, startupInput) {
|
|
138787
137738
|
this.harness = harness;
|
|
138788
137739
|
const tuiOptions = {
|
|
@@ -139503,8 +138454,6 @@ function runLoadingAnimation(theme = "dark") {
|
|
|
139503
138454
|
//#endregion
|
|
139504
138455
|
//#region src/cli/run-shell.ts
|
|
139505
138456
|
async function runShell(opts, version) {
|
|
139506
|
-
const startedAt = Date.now();
|
|
139507
|
-
const configStartedAt = startedAt;
|
|
139508
138457
|
let tuiConfig;
|
|
139509
138458
|
let configWarning;
|
|
139510
138459
|
try {
|
|
@@ -139516,16 +138465,9 @@ async function runShell(opts, version) {
|
|
|
139516
138465
|
}
|
|
139517
138466
|
const resolvedTheme = tuiConfig.theme === "auto" ? await detectTerminalTheme() : tuiConfig.theme;
|
|
139518
138467
|
const workDir = process.cwd();
|
|
139519
|
-
const telemetryBootstrap = createCliTelemetryBootstrap();
|
|
139520
|
-
const telemetryClient = {
|
|
139521
|
-
track,
|
|
139522
|
-
withContext: withTelemetryContext,
|
|
139523
|
-
setContext: setTelemetryContext
|
|
139524
|
-
};
|
|
139525
138468
|
const harness = new ScreamHarness({
|
|
139526
|
-
homeDir:
|
|
139527
|
-
identity: createScreamCodeHostIdentity(version)
|
|
139528
|
-
telemetry: telemetryClient
|
|
138469
|
+
homeDir: resolveScreamHome(),
|
|
138470
|
+
identity: createScreamCodeHostIdentity(version)
|
|
139529
138471
|
});
|
|
139530
138472
|
log.info("scream-code starting", {
|
|
139531
138473
|
version,
|
|
@@ -139535,8 +138477,6 @@ async function runShell(opts, version) {
|
|
|
139535
138477
|
workDir
|
|
139536
138478
|
});
|
|
139537
138479
|
await harness.ensureConfigFile();
|
|
139538
|
-
const config = await harness.getConfig();
|
|
139539
|
-
const configMs = Date.now() - configStartedAt;
|
|
139540
138480
|
await harness.preflight();
|
|
139541
138481
|
await runLoadingAnimation(resolvedTheme);
|
|
139542
138482
|
const tui = new ScreamTUI(harness, {
|
|
@@ -139547,31 +138487,9 @@ async function runShell(opts, version) {
|
|
|
139547
138487
|
startupNotice: configWarning,
|
|
139548
138488
|
resolvedTheme
|
|
139549
138489
|
});
|
|
139550
|
-
initializeCliTelemetry({
|
|
139551
|
-
harness,
|
|
139552
|
-
bootstrap: telemetryBootstrap,
|
|
139553
|
-
config,
|
|
139554
|
-
version,
|
|
139555
|
-
uiMode: CLI_UI_MODE
|
|
139556
|
-
});
|
|
139557
|
-
setCrashPhase("runtime");
|
|
139558
|
-
const resumed = opts.continue || opts.session !== void 0;
|
|
139559
|
-
const trackLifecycleForSession = (sessionId, event, properties) => {
|
|
139560
|
-
if (sessionId.length === 0) {
|
|
139561
|
-
harness.track(event, properties);
|
|
139562
|
-
return;
|
|
139563
|
-
}
|
|
139564
|
-
withTelemetryContext({ sessionId }).track(event, properties);
|
|
139565
|
-
};
|
|
139566
|
-
const trackLifecycle = (event, properties) => {
|
|
139567
|
-
trackLifecycleForSession(tui.getCurrentSessionId(), event, properties);
|
|
139568
|
-
};
|
|
139569
138490
|
tui.onExit = async (exitCode = 0) => {
|
|
139570
138491
|
const sessionId = tui.getCurrentSessionId();
|
|
139571
138492
|
const hasContent = tui.hasSessionContent();
|
|
139572
|
-
setCrashPhase("shutdown");
|
|
139573
|
-
trackLifecycle("exit", { duration_s: (Date.now() - startedAt) / 1e3 });
|
|
139574
|
-
await shutdownTelemetry({ timeoutMs: CLI_SHUTDOWN_TIMEOUT_MS });
|
|
139575
138493
|
const gutter = " ".repeat(1);
|
|
139576
138494
|
process.stdout.write(`${gutter}再见!\n`);
|
|
139577
138495
|
if (sessionId !== "" && hasContent) process.stderr.write(`\n${gutter}恢复此会话:scream -r ${sessionId}\n`);
|
|
@@ -139581,28 +138499,8 @@ async function runShell(opts, version) {
|
|
|
139581
138499
|
execSync("stty -ixon", { stdio: "ignore" });
|
|
139582
138500
|
} catch {}
|
|
139583
138501
|
try {
|
|
139584
|
-
const initStartedAt = Date.now();
|
|
139585
138502
|
await tui.start();
|
|
139586
|
-
const initMs = Date.now() - initStartedAt;
|
|
139587
|
-
trackLifecycle("started", {
|
|
139588
|
-
resumed,
|
|
139589
|
-
yolo: opts.yolo,
|
|
139590
|
-
auto: opts.auto,
|
|
139591
|
-
plan: opts.plan,
|
|
139592
|
-
afk: false
|
|
139593
|
-
});
|
|
139594
|
-
const startupSessionId = tui.getCurrentSessionId();
|
|
139595
|
-
const mcpMs = await tui.getStartupMcpMs();
|
|
139596
|
-
trackLifecycleForSession(startupSessionId, "startup_perf", {
|
|
139597
|
-
duration_ms: Date.now() - startedAt,
|
|
139598
|
-
config_ms: configMs,
|
|
139599
|
-
init_ms: initMs,
|
|
139600
|
-
mcp_ms: mcpMs
|
|
139601
|
-
});
|
|
139602
138503
|
} catch (error) {
|
|
139603
|
-
setCrashPhase("shutdown");
|
|
139604
|
-
trackLifecycle("exit", { duration_s: (Date.now() - startedAt) / 1e3 });
|
|
139605
|
-
await shutdownTelemetry({ timeoutMs: CLI_SHUTDOWN_TIMEOUT_MS });
|
|
139606
138504
|
await harness.close();
|
|
139607
138505
|
throw error;
|
|
139608
138506
|
}
|
|
@@ -140109,15 +139007,13 @@ function mapCcConnectMode(mode) {
|
|
|
140109
139007
|
}
|
|
140110
139008
|
}
|
|
140111
139009
|
async function runStreamJson(opts) {
|
|
139010
|
+
const homeDir = resolveScreamHome();
|
|
140112
139011
|
const workDir = opts.workDir ?? process.cwd();
|
|
140113
|
-
const telemetryBootstrap = createCliTelemetryBootstrap();
|
|
140114
|
-
const telemetryClient = { track };
|
|
140115
139012
|
const harness = new ScreamHarness({
|
|
140116
|
-
homeDir
|
|
139013
|
+
homeDir,
|
|
140117
139014
|
identity: createScreamCodeHostIdentity("dev"),
|
|
140118
139015
|
uiMode: "print",
|
|
140119
|
-
skillDirs: opts.skillsDirs
|
|
140120
|
-
telemetry: telemetryClient
|
|
139016
|
+
skillDirs: opts.skillsDirs
|
|
140121
139017
|
});
|
|
140122
139018
|
const writer = new ClaudeStreamJsonWriter((line) => {
|
|
140123
139019
|
process.stdout.write(`${line}\n`);
|
|
@@ -140213,11 +139109,14 @@ async function runStreamJson(opts) {
|
|
|
140213
139109
|
writer.setModel(opts.model ?? config.defaultModel ?? "");
|
|
140214
139110
|
writer.emitSystem(sessionKey);
|
|
140215
139111
|
function sendControlRequest(request) {
|
|
140216
|
-
|
|
140217
|
-
|
|
140218
|
-
|
|
140219
|
-
writer.emitControlRequest(reqId, request.toolCallId, request.toolName, request.display);
|
|
139112
|
+
let resolve;
|
|
139113
|
+
const promise = new Promise((res) => {
|
|
139114
|
+
resolve = res;
|
|
140220
139115
|
});
|
|
139116
|
+
const reqId = `req_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
139117
|
+
pendingApprovals.set(reqId, { resolve });
|
|
139118
|
+
writer.emitControlRequest(reqId, request.toolCallId, request.toolName, request.display);
|
|
139119
|
+
return promise;
|
|
140221
139120
|
}
|
|
140222
139121
|
switch (opts.permissionMode) {
|
|
140223
139122
|
case "yolo":
|
|
@@ -140242,84 +139141,89 @@ async function runStreamJson(opts) {
|
|
|
140242
139141
|
}
|
|
140243
139142
|
session.setQuestionHandler(() => null);
|
|
140244
139143
|
}
|
|
139144
|
+
let resolve;
|
|
139145
|
+
let reject;
|
|
139146
|
+
const turnPromise = new Promise((res, rej) => {
|
|
139147
|
+
resolve = res;
|
|
139148
|
+
reject = rej;
|
|
139149
|
+
});
|
|
140245
139150
|
let activeTurnId;
|
|
140246
139151
|
let activeAgentId;
|
|
140247
139152
|
let settled = false;
|
|
140248
139153
|
let unsubscribe;
|
|
140249
|
-
|
|
140250
|
-
|
|
140251
|
-
|
|
140252
|
-
|
|
140253
|
-
|
|
140254
|
-
|
|
140255
|
-
|
|
140256
|
-
|
|
140257
|
-
|
|
140258
|
-
|
|
140259
|
-
|
|
140260
|
-
|
|
140261
|
-
|
|
140262
|
-
|
|
140263
|
-
if (event.
|
|
140264
|
-
|
|
140265
|
-
|
|
140266
|
-
|
|
140267
|
-
|
|
140268
|
-
|
|
140269
|
-
|
|
140270
|
-
|
|
140271
|
-
|
|
140272
|
-
|
|
140273
|
-
|
|
140274
|
-
|
|
140275
|
-
|
|
140276
|
-
|
|
140277
|
-
|
|
140278
|
-
|
|
140279
|
-
|
|
140280
|
-
|
|
140281
|
-
|
|
140282
|
-
|
|
140283
|
-
|
|
140284
|
-
|
|
140285
|
-
if (event.
|
|
140286
|
-
|
|
140287
|
-
|
|
140288
|
-
|
|
140289
|
-
|
|
140290
|
-
|
|
140291
|
-
|
|
140292
|
-
|
|
140293
|
-
|
|
140294
|
-
|
|
140295
|
-
|
|
140296
|
-
|
|
140297
|
-
|
|
140298
|
-
|
|
140299
|
-
writer.updateUsage(inputTotal, event.usage.output ?? 0);
|
|
140300
|
-
}
|
|
140301
|
-
} else if (type === "turn.ended") if (event.reason === "completed") finish();
|
|
140302
|
-
else {
|
|
140303
|
-
const errMsg = event.error !== void 0 ? `${event.error.code}: ${event.error.message}` : `Turn ended: ${event.reason}`;
|
|
140304
|
-
finish(new Error(errMsg));
|
|
140305
|
-
}
|
|
140306
|
-
});
|
|
140307
|
-
session.prompt(userText).catch((error) => {
|
|
140308
|
-
const msg = error instanceof Error ? error.message : String(error);
|
|
140309
|
-
if (msg.includes("insufficient tool messages") || msg.includes("tool_calls")) {
|
|
140310
|
-
log.warn("stream-json: resetting session after tool call mismatch", {
|
|
140311
|
-
sessionId: session?.id,
|
|
140312
|
-
error: msg
|
|
140313
|
-
});
|
|
140314
|
-
session?.close().catch(() => {});
|
|
140315
|
-
harness.deleteSession(sessionKey).catch(() => {});
|
|
140316
|
-
session = void 0;
|
|
140317
|
-
finish(/* @__PURE__ */ new Error("会话已自动重置,请重新发送你的消息。"));
|
|
140318
|
-
return;
|
|
139154
|
+
const finish = (error) => {
|
|
139155
|
+
if (settled) return;
|
|
139156
|
+
settled = true;
|
|
139157
|
+
unsubscribe?.();
|
|
139158
|
+
if (error) {
|
|
139159
|
+
writer.emitResult("error", error.message);
|
|
139160
|
+
reject(error);
|
|
139161
|
+
} else {
|
|
139162
|
+
writer.emitResult("success", "");
|
|
139163
|
+
resolve();
|
|
139164
|
+
}
|
|
139165
|
+
};
|
|
139166
|
+
unsubscribe = session.onEvent((event) => {
|
|
139167
|
+
if (event.type === "error") {
|
|
139168
|
+
if (event.agentId !== "main") return;
|
|
139169
|
+
finish(/* @__PURE__ */ new Error(`${event.code}: ${event.message}`));
|
|
139170
|
+
return;
|
|
139171
|
+
}
|
|
139172
|
+
if (event.type === "subagent.spawned") {
|
|
139173
|
+
subagentNames.set(event.subagentId, event.subagentName);
|
|
139174
|
+
writer.writeAssistantDelta(`\n[子任务: ${event.subagentName}]\n`);
|
|
139175
|
+
return;
|
|
139176
|
+
}
|
|
139177
|
+
if (event.type === "subagent.completed") {
|
|
139178
|
+
const name = subagentNames.get(event.subagentId) ?? event.subagentId;
|
|
139179
|
+
writer.writeAssistantDelta(`\n[子任务完成: ${name}]\n`);
|
|
139180
|
+
subagentNames.delete(event.subagentId);
|
|
139181
|
+
return;
|
|
139182
|
+
}
|
|
139183
|
+
if (event.type === "subagent.failed") {
|
|
139184
|
+
const name = subagentNames.get(event.subagentId) ?? event.subagentId;
|
|
139185
|
+
writer.writeAssistantDelta(`\n[子任务失败: ${name} - ${event.error}]\n`);
|
|
139186
|
+
subagentNames.delete(event.subagentId);
|
|
139187
|
+
return;
|
|
139188
|
+
}
|
|
139189
|
+
if (event.type === "turn.started" && activeTurnId === void 0) {
|
|
139190
|
+
if (event.agentId !== "main") return;
|
|
139191
|
+
activeTurnId = event.turnId;
|
|
139192
|
+
activeAgentId = event.agentId;
|
|
139193
|
+
return;
|
|
139194
|
+
}
|
|
139195
|
+
if (activeTurnId === void 0 || activeAgentId === void 0 || !("turnId" in event) || event.turnId !== activeTurnId || event.agentId !== activeAgentId) return;
|
|
139196
|
+
const type = event.type;
|
|
139197
|
+
if (type === "turn.step.started" || type === "turn.step.interrupted") writer.flushAssistant();
|
|
139198
|
+
else if (type === "turn.step.retrying") writer.discardAssistant();
|
|
139199
|
+
else if (type === "assistant.delta") writer.writeAssistantDelta(event.delta);
|
|
139200
|
+
else if (type === "turn.step.completed") {
|
|
139201
|
+
if (event.usage) {
|
|
139202
|
+
const inputTotal = (event.usage.inputOther ?? 0) + (event.usage.inputCacheRead ?? 0) + (event.usage.inputCacheCreation ?? 0);
|
|
139203
|
+
writer.updateUsage(inputTotal, event.usage.output ?? 0);
|
|
140319
139204
|
}
|
|
140320
|
-
|
|
140321
|
-
|
|
139205
|
+
} else if (type === "turn.ended") if (event.reason === "completed") finish();
|
|
139206
|
+
else {
|
|
139207
|
+
const errMsg = event.error !== void 0 ? `${event.error.code}: ${event.error.message}` : `Turn ended: ${event.reason}`;
|
|
139208
|
+
finish(new Error(errMsg));
|
|
139209
|
+
}
|
|
139210
|
+
});
|
|
139211
|
+
session.prompt(userText).catch((error) => {
|
|
139212
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
139213
|
+
if (msg.includes("insufficient tool messages") || msg.includes("tool_calls")) {
|
|
139214
|
+
log.warn("stream-json: resetting session after tool call mismatch", {
|
|
139215
|
+
sessionId: session?.id,
|
|
139216
|
+
error: msg
|
|
139217
|
+
});
|
|
139218
|
+
session?.close().catch(() => {});
|
|
139219
|
+
harness.deleteSession(sessionKey).catch(() => {});
|
|
139220
|
+
session = void 0;
|
|
139221
|
+
finish(/* @__PURE__ */ new Error("会话已自动重置,请重新发送你的消息。"));
|
|
139222
|
+
return;
|
|
139223
|
+
}
|
|
139224
|
+
finish(error instanceof Error ? error : new Error(msg));
|
|
140322
139225
|
});
|
|
139226
|
+
await turnPromise;
|
|
140323
139227
|
}
|
|
140324
139228
|
} catch (error) {
|
|
140325
139229
|
log.error("stream-json: fatal", { error });
|
|
@@ -140425,7 +139329,6 @@ async function handleMigrateCommand() {
|
|
|
140425
139329
|
}
|
|
140426
139330
|
function main() {
|
|
140427
139331
|
initProcessName();
|
|
140428
|
-
installCrashHandlers();
|
|
140429
139332
|
const version = getVersion();
|
|
140430
139333
|
createProgram(version, (opts) => {
|
|
140431
139334
|
handleMainCommand(opts, version).catch(async (error) => {
|