kfc-code-cli 0.0.1-alpha.3 → 0.0.1-alpha.4
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/main.mjs +1182 -670
- package/package.json +2 -2
package/dist/main.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { createRequire } from "node:module";
|
|
|
5
5
|
import { Command, Option } from "commander";
|
|
6
6
|
import * as nodeFs from "node:fs";
|
|
7
7
|
import Vt, { chmodSync, closeSync, constants, createReadStream, createWriteStream, existsSync, fsyncSync, mkdirSync, openSync, promises, readFileSync, readdirSync, realpathSync, renameSync, statSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
|
|
8
|
-
import
|
|
8
|
+
import fs, { access, appendFile, chmod, lstat, mkdir, mkdtemp, open, readFile, readdir, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
9
9
|
import * as path$2 from "node:path";
|
|
10
10
|
import path, { basename, dirname, extname, isAbsolute, join, normalize, posix, resolve, sep, win32 } from "node:path";
|
|
11
11
|
import { finished, pipeline } from "node:stream/promises";
|
|
@@ -28,12 +28,12 @@ import * as ks from "zlib";
|
|
|
28
28
|
import qr from "zlib";
|
|
29
29
|
import so from "node:assert";
|
|
30
30
|
import { parse as parse$1, stringify } from "smol-toml";
|
|
31
|
-
import * as fs$
|
|
31
|
+
import * as fs$2 from "fs/promises";
|
|
32
32
|
import { writeFile as writeFile$1 } from "fs/promises";
|
|
33
33
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
34
34
|
import "yazl";
|
|
35
35
|
import pino from "pino";
|
|
36
|
-
import { CombinedAutocompleteProvider, Container, Editor, Image, Key, Markdown, ProcessTerminal, Spacer, TUI, Text, decodeKittyPrintable, fuzzyFilter, fuzzyMatch, getCapabilities, matchesKey, truncateToWidth, visibleWidth } from "@mariozechner/pi-tui";
|
|
36
|
+
import { CombinedAutocompleteProvider, Container, Editor, Image, Input, Key, Markdown, ProcessTerminal, Spacer, TUI, Text, decodeKittyPrintable, fuzzyFilter, fuzzyMatch, getCapabilities, matchesKey, truncateToWidth, visibleWidth } from "@mariozechner/pi-tui";
|
|
37
37
|
import chalk from "chalk";
|
|
38
38
|
import { highlight } from "cli-highlight";
|
|
39
39
|
import { gt, valid } from "semver";
|
|
@@ -1026,26 +1026,12 @@ var BaseContextState = class {
|
|
|
1026
1026
|
this._systemPrompt = event.new_prompt;
|
|
1027
1027
|
return;
|
|
1028
1028
|
case "model_changed":
|
|
1029
|
-
await this.journalWriter.append({
|
|
1030
|
-
type: "model_changed",
|
|
1031
|
-
old_model: event.old_model,
|
|
1032
|
-
new_model: event.new_model
|
|
1033
|
-
});
|
|
1034
1029
|
this._model = event.new_model;
|
|
1035
1030
|
return;
|
|
1036
1031
|
case "thinking_changed":
|
|
1037
|
-
await this.journalWriter.append({
|
|
1038
|
-
type: "thinking_changed",
|
|
1039
|
-
level: event.level
|
|
1040
|
-
});
|
|
1041
1032
|
this._thinkingLevel = event.level;
|
|
1042
1033
|
return;
|
|
1043
|
-
case "plan_mode_changed":
|
|
1044
|
-
await this.journalWriter.append({
|
|
1045
|
-
type: "plan_mode_changed",
|
|
1046
|
-
enabled: event.enabled
|
|
1047
|
-
});
|
|
1048
|
-
return;
|
|
1034
|
+
case "plan_mode_changed": return;
|
|
1049
1035
|
case "tools_changed":
|
|
1050
1036
|
await this.journalWriter.append({
|
|
1051
1037
|
type: "tools_changed",
|
|
@@ -1146,9 +1132,6 @@ var WiredSessionJournalImpl = class {
|
|
|
1146
1132
|
async appendTeamMail(data) {
|
|
1147
1133
|
await this.journalWriter.append(data);
|
|
1148
1134
|
}
|
|
1149
|
-
async appendPermissionModeChanged(data) {
|
|
1150
|
-
await this.journalWriter.append(data);
|
|
1151
|
-
}
|
|
1152
1135
|
async appendToolDenied(data) {
|
|
1153
1136
|
await this.journalWriter.append(data);
|
|
1154
1137
|
}
|
|
@@ -1164,9 +1147,6 @@ var WiredSessionJournalImpl = class {
|
|
|
1164
1147
|
async appendOwnershipChanged(data) {
|
|
1165
1148
|
await this.journalWriter.append(data);
|
|
1166
1149
|
}
|
|
1167
|
-
async appendSessionMetaChanged(data) {
|
|
1168
|
-
await this.journalWriter.append(data);
|
|
1169
|
-
}
|
|
1170
1150
|
};
|
|
1171
1151
|
//#endregion
|
|
1172
1152
|
//#region ../../packages/kimi-core/src/storage/schema/records.ts
|
|
@@ -1284,25 +1264,6 @@ const _rawSystemPromptChangedRecordSchema = z.object({
|
|
|
1284
1264
|
time: z.number(),
|
|
1285
1265
|
new_prompt: z.string()
|
|
1286
1266
|
});
|
|
1287
|
-
const _rawModelChangedRecordSchema = z.object({
|
|
1288
|
-
type: z.literal("model_changed"),
|
|
1289
|
-
seq: z.number(),
|
|
1290
|
-
time: z.number(),
|
|
1291
|
-
old_model: z.string(),
|
|
1292
|
-
new_model: z.string()
|
|
1293
|
-
});
|
|
1294
|
-
const _rawThinkingChangedRecordSchema = z.object({
|
|
1295
|
-
type: z.literal("thinking_changed"),
|
|
1296
|
-
seq: z.number(),
|
|
1297
|
-
time: z.number(),
|
|
1298
|
-
level: z.string()
|
|
1299
|
-
});
|
|
1300
|
-
const _rawPlanModeChangedRecordSchema = z.object({
|
|
1301
|
-
type: z.literal("plan_mode_changed"),
|
|
1302
|
-
seq: z.number(),
|
|
1303
|
-
time: z.number(),
|
|
1304
|
-
enabled: z.boolean()
|
|
1305
|
-
});
|
|
1306
1267
|
const _rawToolsChangedRecordSchema = z.object({
|
|
1307
1268
|
type: z.literal("tools_changed"),
|
|
1308
1269
|
seq: z.number(),
|
|
@@ -1359,17 +1320,6 @@ const _rawNotificationRecordSchema = z.object({
|
|
|
1359
1320
|
envelope_id: z.string().optional()
|
|
1360
1321
|
})
|
|
1361
1322
|
});
|
|
1362
|
-
const _rawPermissionModeChangedRecordSchema = z.object({
|
|
1363
|
-
type: z.literal("permission_mode_changed"),
|
|
1364
|
-
seq: z.number(),
|
|
1365
|
-
time: z.number(),
|
|
1366
|
-
turn_id: z.string().optional(),
|
|
1367
|
-
data: z.object({
|
|
1368
|
-
from: z.string(),
|
|
1369
|
-
to: z.string(),
|
|
1370
|
-
reason: z.string()
|
|
1371
|
-
})
|
|
1372
|
-
});
|
|
1373
1323
|
const _rawToolDeniedRecordSchema = z.object({
|
|
1374
1324
|
type: z.literal("tool_denied"),
|
|
1375
1325
|
seq: z.number(),
|
|
@@ -1611,25 +1561,6 @@ const _rawOwnershipChangedRecordSchema = z.object({
|
|
|
1611
1561
|
old_owner: z.string().nullable(),
|
|
1612
1562
|
new_owner: z.string()
|
|
1613
1563
|
});
|
|
1614
|
-
const _rawSessionMetaChangedRecordSchema = z.object({
|
|
1615
|
-
type: z.literal("session_meta_changed"),
|
|
1616
|
-
seq: z.number(),
|
|
1617
|
-
time: z.number(),
|
|
1618
|
-
patch: z.object({
|
|
1619
|
-
title: z.string().optional(),
|
|
1620
|
-
tags: z.array(z.string()).optional(),
|
|
1621
|
-
description: z.string().optional(),
|
|
1622
|
-
archived: z.boolean().optional(),
|
|
1623
|
-
color: z.string().optional(),
|
|
1624
|
-
plan_slug: z.string().optional()
|
|
1625
|
-
}),
|
|
1626
|
-
source: z.enum([
|
|
1627
|
-
"user",
|
|
1628
|
-
"auto",
|
|
1629
|
-
"system"
|
|
1630
|
-
]),
|
|
1631
|
-
reason: z.string().optional()
|
|
1632
|
-
});
|
|
1633
1564
|
const _rawContextEditRecordSchema = z.object({
|
|
1634
1565
|
type: z.literal("context_edit"),
|
|
1635
1566
|
seq: z.number(),
|
|
@@ -1662,15 +1593,15 @@ const _sessionInitializedCommonShape = {
|
|
|
1662
1593
|
seq: z.number(),
|
|
1663
1594
|
time: z.number(),
|
|
1664
1595
|
system_prompt: z.string(),
|
|
1665
|
-
model: z.string(),
|
|
1666
1596
|
active_tools: z.array(z.string()),
|
|
1597
|
+
model: z.string().optional(),
|
|
1667
1598
|
permission_mode: z.enum([
|
|
1668
1599
|
"default",
|
|
1669
1600
|
"acceptEdits",
|
|
1670
1601
|
"bypassPermissions"
|
|
1671
|
-
]),
|
|
1672
|
-
plan_mode: z.boolean(),
|
|
1673
|
-
workspace_dir: z.string(),
|
|
1602
|
+
]).optional(),
|
|
1603
|
+
plan_mode: z.boolean().optional(),
|
|
1604
|
+
workspace_dir: z.string().optional(),
|
|
1674
1605
|
thinking_level: z.string().optional()
|
|
1675
1606
|
};
|
|
1676
1607
|
const _rawSessionInitializedMainSchema = z.object({
|
|
@@ -1707,13 +1638,9 @@ const WireRecordSchema = z.discriminatedUnion("type", [
|
|
|
1707
1638
|
_rawToolResultRecordSchema,
|
|
1708
1639
|
_rawCompactionRecordSchema,
|
|
1709
1640
|
_rawSystemPromptChangedRecordSchema,
|
|
1710
|
-
_rawModelChangedRecordSchema,
|
|
1711
|
-
_rawThinkingChangedRecordSchema,
|
|
1712
|
-
_rawPlanModeChangedRecordSchema,
|
|
1713
1641
|
_rawToolsChangedRecordSchema,
|
|
1714
1642
|
_rawSystemReminderRecordSchema,
|
|
1715
1643
|
_rawNotificationRecordSchema,
|
|
1716
|
-
_rawPermissionModeChangedRecordSchema,
|
|
1717
1644
|
_rawToolDeniedRecordSchema,
|
|
1718
1645
|
_rawStepBeginRecordSchema,
|
|
1719
1646
|
_rawStepEndRecordSchema,
|
|
@@ -1730,7 +1657,6 @@ const WireRecordSchema = z.discriminatedUnion("type", [
|
|
|
1730
1657
|
_rawOwnershipChangedRecordSchema,
|
|
1731
1658
|
_rawContextEditRecordSchema,
|
|
1732
1659
|
_rawContextClearedRecordSchema,
|
|
1733
|
-
_rawSessionMetaChangedRecordSchema,
|
|
1734
1660
|
_rawSessionInitializedRecordSchema
|
|
1735
1661
|
]);
|
|
1736
1662
|
//#endregion
|
|
@@ -1849,13 +1775,9 @@ const KNOWN_RECORD_TYPES = new Set([
|
|
|
1849
1775
|
"tool_result",
|
|
1850
1776
|
"compaction",
|
|
1851
1777
|
"system_prompt_changed",
|
|
1852
|
-
"model_changed",
|
|
1853
|
-
"thinking_changed",
|
|
1854
|
-
"plan_mode_changed",
|
|
1855
1778
|
"tools_changed",
|
|
1856
1779
|
"system_reminder",
|
|
1857
1780
|
"notification",
|
|
1858
|
-
"permission_mode_changed",
|
|
1859
1781
|
"tool_denied",
|
|
1860
1782
|
"step_begin",
|
|
1861
1783
|
"step_end",
|
|
@@ -1871,8 +1793,7 @@ const KNOWN_RECORD_TYPES = new Set([
|
|
|
1871
1793
|
"subagent_failed",
|
|
1872
1794
|
"ownership_changed",
|
|
1873
1795
|
"context_edit",
|
|
1874
|
-
"context_cleared"
|
|
1875
|
-
"session_meta_changed"
|
|
1796
|
+
"context_cleared"
|
|
1876
1797
|
]);
|
|
1877
1798
|
//#endregion
|
|
1878
1799
|
//#region ../../packages/kimi-core/src/storage/journal/rotation.ts
|
|
@@ -2286,6 +2207,15 @@ async function runSoulTurn(config, context, runtime, sink, signal, overrides) {
|
|
|
2286
2207
|
if (steps >= maxSteps) throw new MaxStepsExceededError(maxSteps);
|
|
2287
2208
|
steps += 1;
|
|
2288
2209
|
const currentStep = steps;
|
|
2210
|
+
const turnId = context.currentTurnId?.() ?? UNKNOWN_TURN_ID;
|
|
2211
|
+
if (config.beforeStep !== void 0) {
|
|
2212
|
+
const beforeStep = await config.beforeStep({
|
|
2213
|
+
turnId,
|
|
2214
|
+
stepNumber: currentStep,
|
|
2215
|
+
context
|
|
2216
|
+
}, signal);
|
|
2217
|
+
if (beforeStep?.block === true) throw new Error(beforeStep.reason ?? `Step ${String(currentStep)} was blocked`);
|
|
2218
|
+
}
|
|
2289
2219
|
safeEmit(sink, {
|
|
2290
2220
|
type: "step.begin",
|
|
2291
2221
|
step: currentStep
|
|
@@ -2298,7 +2228,6 @@ async function runSoulTurn(config, context, runtime, sink, signal, overrides) {
|
|
|
2298
2228
|
const visibleTools = buildLLMVisibleTools(config.tools, overrides?.activeTools);
|
|
2299
2229
|
const messages = context.buildMessages();
|
|
2300
2230
|
const stepUuid = randomUUID();
|
|
2301
|
-
const turnId = context.currentTurnId?.() ?? UNKNOWN_TURN_ID;
|
|
2302
2231
|
const toolCallByProviderId = /* @__PURE__ */ new Map();
|
|
2303
2232
|
const prefetchedResults = /* @__PURE__ */ new Map();
|
|
2304
2233
|
await context.appendStepBegin({
|
|
@@ -2420,6 +2349,14 @@ async function runSoulTurn(config, context, runtime, sink, signal, overrides) {
|
|
|
2420
2349
|
step: currentStep
|
|
2421
2350
|
});
|
|
2422
2351
|
const sr = response.stopReason ?? "end_turn";
|
|
2352
|
+
if (config.afterStep !== void 0) try {
|
|
2353
|
+
await config.afterStep({
|
|
2354
|
+
turnId,
|
|
2355
|
+
stepNumber: currentStep,
|
|
2356
|
+
context,
|
|
2357
|
+
stopReason: sr
|
|
2358
|
+
}, signal);
|
|
2359
|
+
} catch {}
|
|
2423
2360
|
if (sr === "tool_use") continue;
|
|
2424
2361
|
stopReason = sr;
|
|
2425
2362
|
break;
|
|
@@ -2929,21 +2866,26 @@ function hookDedupeKey(hook) {
|
|
|
2929
2866
|
/**
|
|
2930
2867
|
* Extracts the string fed to a hook's matcher regex. Event-dependent:
|
|
2931
2868
|
*
|
|
2869
|
+
* - `PreTurn` / `UserPromptSubmit` — the prompt text itself.
|
|
2870
|
+
* - `PostTurn` / `Stop` — the turn reason (`done` / `cancelled` /
|
|
2871
|
+
* `error`), so hooks can filter e.g. `/^error$/`.
|
|
2872
|
+
* - `PreStep` / `PostStep` — the step number as a string.
|
|
2932
2873
|
* - `PreToolUse` / `PostToolUse` / `OnToolFailure` — tool name
|
|
2933
2874
|
* (mirrors Python's `matcher_value=toolCall.name` contract).
|
|
2934
|
-
* - `UserPromptSubmit` — the prompt text itself (Python parity).
|
|
2935
|
-
* - `Stop` — the turn reason (`done` / `cancelled` / `error`), so
|
|
2936
|
-
* hooks can filter e.g. `/^error$/`.
|
|
2937
2875
|
* - `Notification` — the notification type string, so a single hook
|
|
2938
2876
|
* can subscribe to an entire notification class via regex.
|
|
2939
2877
|
*/
|
|
2940
2878
|
function extractMatcherValue(input) {
|
|
2941
2879
|
switch (input.event) {
|
|
2880
|
+
case "PreTurn":
|
|
2881
|
+
case "UserPromptSubmit": return input.prompt;
|
|
2882
|
+
case "PostTurn":
|
|
2883
|
+
case "Stop": return input.reason;
|
|
2884
|
+
case "PreStep":
|
|
2885
|
+
case "PostStep": return String(input.stepNumber);
|
|
2942
2886
|
case "PreToolUse":
|
|
2943
2887
|
case "PostToolUse":
|
|
2944
2888
|
case "OnToolFailure": return input.toolCall.name;
|
|
2945
|
-
case "UserPromptSubmit": return input.prompt;
|
|
2946
|
-
case "Stop": return input.reason;
|
|
2947
2889
|
case "Notification": return input.notificationType;
|
|
2948
2890
|
case "StopFailure": return input.error;
|
|
2949
2891
|
case "SubagentStart":
|
|
@@ -2953,6 +2895,7 @@ function extractMatcherValue(input) {
|
|
|
2953
2895
|
case "PreCompact":
|
|
2954
2896
|
case "PostCompact": return "";
|
|
2955
2897
|
}
|
|
2898
|
+
return input;
|
|
2956
2899
|
}
|
|
2957
2900
|
const AgentToolInputSchema = z.preprocess((input) => {
|
|
2958
2901
|
if (typeof input !== "object" || input === null || Array.isArray(input)) return input;
|
|
@@ -3252,7 +3195,7 @@ var EnterPlanModeTool = class {
|
|
|
3252
3195
|
isError: true,
|
|
3253
3196
|
content: "Plan mode is already active. Use ExitPlanMode when the plan is ready."
|
|
3254
3197
|
};
|
|
3255
|
-
if (this.deps.isYoloMode()) {
|
|
3198
|
+
if (this.deps.isYoloMode() || this.deps.shouldAutoApprove?.() === true) {
|
|
3256
3199
|
try {
|
|
3257
3200
|
await this.deps.setPlanMode(true);
|
|
3258
3201
|
} catch (error) {
|
|
@@ -3588,15 +3531,10 @@ var CompactionOrchestrator = class {
|
|
|
3588
3531
|
const summary = await (this.deps.runtimeSlot?.current().compactionProvider ?? this.deps.compactionProvider).run(messages, signal, customInstruction !== void 0 ? { userInstructions: customInstruction } : void 0);
|
|
3589
3532
|
signal.throwIfAborted();
|
|
3590
3533
|
const baselineInit = await this.deps.journalCapability.readSessionInitialized();
|
|
3591
|
-
const runtime = this.deps.runtimeStateProvider();
|
|
3592
3534
|
const cs = this.deps.contextState;
|
|
3593
3535
|
const sessionInitialized = applyRuntimeOverlay(baselineInit, {
|
|
3594
3536
|
system_prompt: cs.systemPrompt,
|
|
3595
|
-
|
|
3596
|
-
active_tools: [...cs.activeTools],
|
|
3597
|
-
permission_mode: runtime.permissionMode,
|
|
3598
|
-
plan_mode: runtime.planMode,
|
|
3599
|
-
thinking_level: runtime.thinkingLevel
|
|
3537
|
+
active_tools: [...cs.activeTools]
|
|
3600
3538
|
});
|
|
3601
3539
|
await this.deps.journalWriter.flush();
|
|
3602
3540
|
const rotateResult = await this.deps.journalCapability.rotate({
|
|
@@ -3663,16 +3601,15 @@ var CompactionOrchestrator = class {
|
|
|
3663
3601
|
};
|
|
3664
3602
|
/**
|
|
3665
3603
|
* Phase 23 fix — overlay the runtime-mutable subset of a baseline
|
|
3666
|
-
* `session_initialized` with the live ContextState
|
|
3604
|
+
* `session_initialized` with the live wire-owned ContextState baseline.
|
|
3667
3605
|
*
|
|
3668
3606
|
* Identity-class fields (`type`, `seq`, `time`, `agent_type`, `session_id`,
|
|
3669
|
-
* `agent_id`, parent lineage
|
|
3607
|
+
* `agent_id`, parent lineage) are preserved verbatim
|
|
3670
3608
|
* because they cannot legally mutate at runtime — see the discriminated-union
|
|
3671
|
-
* shape in `wire-record.ts`. The mutable fields
|
|
3672
|
-
* `
|
|
3673
|
-
*
|
|
3674
|
-
*
|
|
3675
|
-
* mutable: `session.setThinking` (Phase 24 24b) changes it at runtime.
|
|
3609
|
+
* shape in `wire-record.ts`. The mutable wire-owned fields
|
|
3610
|
+
* (`system_prompt`, `active_tools`) are overwritten so the post-rotate
|
|
3611
|
+
* baseline reflects the compaction-time snapshot rather than the original
|
|
3612
|
+
* startup config. Runtime/session fields live in state.json.
|
|
3676
3613
|
*
|
|
3677
3614
|
* The generic preserves the discriminated-union narrowing so each branch
|
|
3678
3615
|
* (main / sub / independent) returns its own concrete type.
|
|
@@ -3681,11 +3618,7 @@ function applyRuntimeOverlay(baseline, overlay) {
|
|
|
3681
3618
|
return {
|
|
3682
3619
|
...baseline,
|
|
3683
3620
|
system_prompt: overlay.system_prompt,
|
|
3684
|
-
|
|
3685
|
-
active_tools: [...overlay.active_tools],
|
|
3686
|
-
permission_mode: overlay.permission_mode,
|
|
3687
|
-
plan_mode: overlay.plan_mode,
|
|
3688
|
-
...overlay.thinking_level !== void 0 ? { thinking_level: overlay.thinking_level } : {}
|
|
3621
|
+
active_tools: [...overlay.active_tools]
|
|
3689
3622
|
};
|
|
3690
3623
|
}
|
|
3691
3624
|
/**
|
|
@@ -4449,11 +4382,13 @@ var DefaultSessionControl = class {
|
|
|
4449
4382
|
contextState;
|
|
4450
4383
|
sessionJournal;
|
|
4451
4384
|
setPlanModeOverride;
|
|
4385
|
+
setYoloOverride;
|
|
4452
4386
|
constructor(deps) {
|
|
4453
4387
|
this.turnManager = deps.turnManager;
|
|
4454
4388
|
this.contextState = deps.contextState;
|
|
4455
4389
|
this.sessionJournal = deps.sessionJournal;
|
|
4456
4390
|
this.setPlanModeOverride = deps.setPlanModeOverride;
|
|
4391
|
+
this.setYoloOverride = deps.setYoloOverride;
|
|
4457
4392
|
}
|
|
4458
4393
|
async compact(customInstruction) {
|
|
4459
4394
|
await this.turnManager.triggerCompaction(customInstruction);
|
|
@@ -4478,18 +4413,15 @@ var DefaultSessionControl = class {
|
|
|
4478
4413
|
this.turnManager.setPlanMode(enabled);
|
|
4479
4414
|
}
|
|
4480
4415
|
async setYolo(enabled) {
|
|
4416
|
+
if (this.setYoloOverride !== void 0) {
|
|
4417
|
+
await this.setYoloOverride(enabled);
|
|
4418
|
+
return;
|
|
4419
|
+
}
|
|
4481
4420
|
const previousMode = this.turnManager.getPermissionMode();
|
|
4482
4421
|
const newMode = enabled ? "bypassPermissions" : "default";
|
|
4483
4422
|
if (previousMode === newMode) return;
|
|
4484
4423
|
this.turnManager.setPermissionMode(newMode);
|
|
4485
|
-
|
|
4486
|
-
type: "permission_mode_changed",
|
|
4487
|
-
data: {
|
|
4488
|
-
from: previousMode,
|
|
4489
|
-
to: newMode,
|
|
4490
|
-
reason: enabled ? "/yolo on" : "/yolo off"
|
|
4491
|
-
}
|
|
4492
|
-
});
|
|
4424
|
+
this.sessionJournal;
|
|
4493
4425
|
}
|
|
4494
4426
|
};
|
|
4495
4427
|
//#endregion
|
|
@@ -4591,19 +4523,16 @@ var SessionMetaService = class {
|
|
|
4591
4523
|
}
|
|
4592
4524
|
}
|
|
4593
4525
|
async applyPatch(patch, source, reason) {
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
|
|
4599
|
-
|
|
4600
|
-
if (patch.
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
if (patch.color !== void 0) this.meta.color = patch.color;
|
|
4605
|
-
if (patch.plan_slug !== void 0) this.meta.plan_slug = patch.plan_slug;
|
|
4606
|
-
this.meta.last_updated = Date.now();
|
|
4526
|
+
const next = cloneMeta(this.meta);
|
|
4527
|
+
if (patch.title !== void 0) next.title = patch.title;
|
|
4528
|
+
if (patch.tags !== void 0) next.tags = [...patch.tags];
|
|
4529
|
+
if (patch.description !== void 0) next.description = patch.description;
|
|
4530
|
+
if (patch.archived !== void 0) next.archived = patch.archived;
|
|
4531
|
+
if (patch.color !== void 0) next.color = patch.color;
|
|
4532
|
+
if (patch.plan_slug !== void 0) next.plan_slug = patch.plan_slug;
|
|
4533
|
+
next.last_updated = Date.now();
|
|
4534
|
+
await this.flushStateJson(next);
|
|
4535
|
+
this.meta = next;
|
|
4607
4536
|
this.deps.eventBus.emit({
|
|
4608
4537
|
type: "session_meta.changed",
|
|
4609
4538
|
data: {
|
|
@@ -4636,7 +4565,7 @@ var SessionMetaService = class {
|
|
|
4636
4565
|
if (this.flushTimer !== null) return;
|
|
4637
4566
|
this.flushTimer = setTimeout(() => {
|
|
4638
4567
|
this.flushTimer = null;
|
|
4639
|
-
this.flushStateJson().catch(() => {});
|
|
4568
|
+
this.flushStateJson(this.meta).catch(() => {});
|
|
4640
4569
|
}, this.flushDebounceMs);
|
|
4641
4570
|
this.flushTimer.unref?.();
|
|
4642
4571
|
}
|
|
@@ -4651,25 +4580,27 @@ var SessionMetaService = class {
|
|
|
4651
4580
|
* because createSession / closeSession / plan_mode / yolo all need
|
|
4652
4581
|
* to migrate off direct state.json writes first.
|
|
4653
4582
|
*/
|
|
4654
|
-
async flushStateJson() {
|
|
4655
|
-
|
|
4656
|
-
...
|
|
4657
|
-
session_id:
|
|
4658
|
-
created_at:
|
|
4659
|
-
updated_at:
|
|
4583
|
+
async flushStateJson(meta = this.meta) {
|
|
4584
|
+
await this.deps.stateCache.update((existing) => ({
|
|
4585
|
+
...existing ?? {
|
|
4586
|
+
session_id: meta.session_id,
|
|
4587
|
+
created_at: meta.created_at,
|
|
4588
|
+
updated_at: meta.last_updated
|
|
4660
4589
|
},
|
|
4661
|
-
session_id:
|
|
4662
|
-
created_at:
|
|
4663
|
-
updated_at:
|
|
4664
|
-
...
|
|
4665
|
-
...
|
|
4666
|
-
...
|
|
4667
|
-
...
|
|
4668
|
-
...
|
|
4669
|
-
...
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4590
|
+
session_id: meta.session_id,
|
|
4591
|
+
created_at: meta.created_at,
|
|
4592
|
+
updated_at: meta.last_updated,
|
|
4593
|
+
...meta.title !== void 0 ? { custom_title: meta.title } : {},
|
|
4594
|
+
...meta.tags !== void 0 ? { tags: [...meta.tags] } : {},
|
|
4595
|
+
...meta.description !== void 0 ? { description: meta.description } : {},
|
|
4596
|
+
...meta.archived !== void 0 ? { archived: meta.archived } : {},
|
|
4597
|
+
...meta.color !== void 0 ? { color: meta.color } : {},
|
|
4598
|
+
...meta.last_model !== void 0 ? { model: meta.last_model } : {},
|
|
4599
|
+
turn_count: meta.turn_count,
|
|
4600
|
+
...meta.plan_slug !== void 0 ? { plan_slug: meta.plan_slug } : {},
|
|
4601
|
+
...meta.producer !== void 0 ? { producer: { ...meta.producer } } : {},
|
|
4602
|
+
last_exit_code: "dirty"
|
|
4603
|
+
}));
|
|
4673
4604
|
}
|
|
4674
4605
|
};
|
|
4675
4606
|
function cloneMeta(meta) {
|
|
@@ -5258,11 +5189,7 @@ async function runSubagentTurn(deps, agentId, request, signal) {
|
|
|
5258
5189
|
parent_tool_call_id: request.parentToolCallId,
|
|
5259
5190
|
run_in_background: request.runInBackground ?? false,
|
|
5260
5191
|
system_prompt: childSystemPrompt ?? "",
|
|
5261
|
-
|
|
5262
|
-
active_tools: childActiveTools,
|
|
5263
|
-
permission_mode: "default",
|
|
5264
|
-
plan_mode: false,
|
|
5265
|
-
workspace_dir: deps.workDir ?? process.cwd()
|
|
5192
|
+
active_tools: childActiveTools
|
|
5266
5193
|
};
|
|
5267
5194
|
await childJournalWriter.append(subInitInput);
|
|
5268
5195
|
childContext = new WiredContextState({
|
|
@@ -19848,6 +19775,49 @@ OpenAI.Containers = Containers;
|
|
|
19848
19775
|
OpenAI.Skills = Skills$1;
|
|
19849
19776
|
OpenAI.Videos = Videos;
|
|
19850
19777
|
//#endregion
|
|
19778
|
+
//#region ../../packages/kimi-core/src/hooks/execution-pipeline.ts
|
|
19779
|
+
const ALLOW = Object.freeze({
|
|
19780
|
+
blockAction: false,
|
|
19781
|
+
additionalContext: []
|
|
19782
|
+
});
|
|
19783
|
+
var ExecutionHookBlockedError = class extends Error {
|
|
19784
|
+
event;
|
|
19785
|
+
reason;
|
|
19786
|
+
constructor(event, reason) {
|
|
19787
|
+
super(reason !== void 0 ? `${event} hook blocked: ${reason}` : `${event} hook blocked`);
|
|
19788
|
+
this.name = "ExecutionHookBlockedError";
|
|
19789
|
+
this.event = event;
|
|
19790
|
+
this.reason = reason;
|
|
19791
|
+
}
|
|
19792
|
+
};
|
|
19793
|
+
/**
|
|
19794
|
+
* Awaited execution-hook adapter.
|
|
19795
|
+
*
|
|
19796
|
+
* This sits on the execution side of the architecture, separate from the
|
|
19797
|
+
* wire-event publication pipeline. Pre hooks can block real work before it
|
|
19798
|
+
* happens; post hooks can still run in order without being able to rewrite
|
|
19799
|
+
* already-durable facts unless their caller explicitly interprets a result.
|
|
19800
|
+
*/
|
|
19801
|
+
var ExecutionHookPipeline = class {
|
|
19802
|
+
hookEngine;
|
|
19803
|
+
constructor(options) {
|
|
19804
|
+
this.hookEngine = options.hookEngine;
|
|
19805
|
+
}
|
|
19806
|
+
async run(input, signal) {
|
|
19807
|
+
if (this.hookEngine === void 0) return ALLOW;
|
|
19808
|
+
return this.hookEngine.executeHooks(input.event, input, signal);
|
|
19809
|
+
}
|
|
19810
|
+
async runBlocking(input, signal) {
|
|
19811
|
+
const result = await this.run(input, signal);
|
|
19812
|
+
if (result.blockAction) throw new ExecutionHookBlockedError(input.event, result.reason);
|
|
19813
|
+
return result;
|
|
19814
|
+
}
|
|
19815
|
+
dispatch(input) {
|
|
19816
|
+
const controller = new AbortController();
|
|
19817
|
+
this.run(input, controller.signal).catch(() => {});
|
|
19818
|
+
}
|
|
19819
|
+
};
|
|
19820
|
+
//#endregion
|
|
19851
19821
|
//#region ../../packages/kimi-core/src/soul-plus/capability-check.ts
|
|
19852
19822
|
function checkLLMCapabilities(opts) {
|
|
19853
19823
|
if (opts.model === "") return;
|
|
@@ -19944,7 +19914,10 @@ var TurnManager = class {
|
|
|
19944
19914
|
runtimeSlot;
|
|
19945
19915
|
compactionConfig;
|
|
19946
19916
|
sessionId;
|
|
19917
|
+
executionHooks;
|
|
19947
19918
|
activeToolExecutionScope;
|
|
19919
|
+
pendingLaunchController;
|
|
19920
|
+
pendingLaunchDrain;
|
|
19948
19921
|
/**
|
|
19949
19922
|
* Phase 18 A.13 — terminal reason per turn id for callers that
|
|
19950
19923
|
* observe the turn lifecycle out-of-band (after the `end` event
|
|
@@ -19972,6 +19945,7 @@ var TurnManager = class {
|
|
|
19972
19945
|
this.runtimeSlot = deps.runtimeSlot;
|
|
19973
19946
|
this.compactionConfig = deps.compactionConfig;
|
|
19974
19947
|
this.sessionId = deps.sessionId ?? "unknown";
|
|
19948
|
+
this.executionHooks = new ExecutionHookPipeline({ hookEngine: deps.hookEngine });
|
|
19975
19949
|
}
|
|
19976
19950
|
setPermissionMode(mode) {
|
|
19977
19951
|
this.permissionMode = mode;
|
|
@@ -20154,6 +20128,13 @@ var TurnManager = class {
|
|
|
20154
20128
|
};
|
|
20155
20129
|
const scope = this.activeToolExecutionScope;
|
|
20156
20130
|
this.deps.approvalRuntime?.cancelBySource(source);
|
|
20131
|
+
if (this.pendingLaunchTurnId === turnId && this.pendingLaunchController !== void 0) {
|
|
20132
|
+
this.pendingLaunchController.abort();
|
|
20133
|
+
try {
|
|
20134
|
+
await this.pendingLaunchDrain;
|
|
20135
|
+
} catch {}
|
|
20136
|
+
return;
|
|
20137
|
+
}
|
|
20157
20138
|
scope?.discardStreaming?.("aborted");
|
|
20158
20139
|
await this.deps.lifecycle.cancelTurn(turnId);
|
|
20159
20140
|
scope?.drainPrefetched?.();
|
|
@@ -20178,8 +20159,16 @@ var TurnManager = class {
|
|
|
20178
20159
|
if (mismatch !== void 0) throw mismatch;
|
|
20179
20160
|
}
|
|
20180
20161
|
const turnId = this.deps.lifecycle.allocateTurnId();
|
|
20162
|
+
const pendingLaunchController = new AbortController();
|
|
20181
20163
|
this.pendingLaunchTurnId = turnId;
|
|
20164
|
+
this.pendingLaunchController = pendingLaunchController;
|
|
20165
|
+
let releasePendingLaunch;
|
|
20166
|
+
this.pendingLaunchDrain = new Promise((resolve) => {
|
|
20167
|
+
releasePendingLaunch = resolve;
|
|
20168
|
+
});
|
|
20182
20169
|
try {
|
|
20170
|
+
await this.executePreTurnHook(turnId, input, pendingLaunchController.signal);
|
|
20171
|
+
pendingLaunchController.signal.throwIfAborted();
|
|
20183
20172
|
await this.deps.sessionJournal.appendTurnBegin({
|
|
20184
20173
|
type: "turn_begin",
|
|
20185
20174
|
turn_id: turnId,
|
|
@@ -20210,17 +20199,23 @@ var TurnManager = class {
|
|
|
20210
20199
|
};
|
|
20211
20200
|
this.launchTurn(turnId, trigger);
|
|
20212
20201
|
this.pendingLaunchTurnId = void 0;
|
|
20202
|
+
this.pendingLaunchController = void 0;
|
|
20203
|
+
this.pendingLaunchDrain = void 0;
|
|
20204
|
+
releasePendingLaunch();
|
|
20213
20205
|
return {
|
|
20214
20206
|
turn_id: turnId,
|
|
20215
20207
|
status: "started"
|
|
20216
20208
|
};
|
|
20217
20209
|
} catch (error) {
|
|
20218
20210
|
this.pendingLaunchTurnId = void 0;
|
|
20211
|
+
this.pendingLaunchController = void 0;
|
|
20212
|
+
this.pendingLaunchDrain = void 0;
|
|
20213
|
+
releasePendingLaunch();
|
|
20219
20214
|
throw error;
|
|
20220
20215
|
}
|
|
20221
20216
|
}
|
|
20222
20217
|
async handleCancel(req) {
|
|
20223
|
-
const requestedId = req.data.turn_id ?? this.
|
|
20218
|
+
const requestedId = req.data.turn_id ?? this.getCurrentTurnId();
|
|
20224
20219
|
if (requestedId === void 0) return { ok: true };
|
|
20225
20220
|
await this.abortTurn(requestedId, "dispatch-cancel");
|
|
20226
20221
|
return { ok: true };
|
|
@@ -20258,16 +20253,27 @@ var TurnManager = class {
|
|
|
20258
20253
|
const parsed = Number.parseInt(match[1] ?? "1", 10);
|
|
20259
20254
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : 1;
|
|
20260
20255
|
}
|
|
20256
|
+
async executePreTurnHook(turnId, input, signal) {
|
|
20257
|
+
try {
|
|
20258
|
+
await this.executionHooks.runBlocking({
|
|
20259
|
+
event: "PreTurn",
|
|
20260
|
+
sessionId: this.sessionId,
|
|
20261
|
+
turnId,
|
|
20262
|
+
agentId: this.agentId,
|
|
20263
|
+
prompt: input.text,
|
|
20264
|
+
inputKind: "user"
|
|
20265
|
+
}, signal);
|
|
20266
|
+
} catch (error) {
|
|
20267
|
+
if (error instanceof ExecutionHookBlockedError) throw error;
|
|
20268
|
+
}
|
|
20269
|
+
}
|
|
20261
20270
|
/**
|
|
20262
|
-
* Fire-and-forget dispatch
|
|
20271
|
+
* Fire-and-forget dispatch for legacy lifecycle hook events. Tool-scoped
|
|
20263
20272
|
* events go through the actor-local `ToolExecutionScope`; this helper
|
|
20264
|
-
* only covers
|
|
20273
|
+
* only covers compatibility events TurnManager owns.
|
|
20265
20274
|
*/
|
|
20266
20275
|
dispatchLifecycleHook(input) {
|
|
20267
|
-
|
|
20268
|
-
if (engine === void 0) return;
|
|
20269
|
-
const controller = new AbortController();
|
|
20270
|
-
engine.executeHooks(input.event, input, controller.signal).catch(() => {});
|
|
20276
|
+
this.executionHooks.dispatch(input);
|
|
20271
20277
|
}
|
|
20272
20278
|
launchTurn(turnId, trigger) {
|
|
20273
20279
|
const controller = this.deps.soulRegistry.getOrCreate("main").abortController;
|
|
@@ -20312,6 +20318,32 @@ var TurnManager = class {
|
|
|
20312
20318
|
compactionConfig,
|
|
20313
20319
|
contextWindow: compactionConfig.maxContextSize
|
|
20314
20320
|
};
|
|
20321
|
+
if (this.deps.hookEngine !== void 0) soulConfig = {
|
|
20322
|
+
...soulConfig,
|
|
20323
|
+
beforeStep: async (ctx, signal) => {
|
|
20324
|
+
const result = await this.executionHooks.run({
|
|
20325
|
+
event: "PreStep",
|
|
20326
|
+
sessionId: this.sessionId,
|
|
20327
|
+
turnId: ctx.turnId,
|
|
20328
|
+
stepNumber: ctx.stepNumber,
|
|
20329
|
+
agentId: this.agentId
|
|
20330
|
+
}, signal);
|
|
20331
|
+
if (result.blockAction) return {
|
|
20332
|
+
block: true,
|
|
20333
|
+
...result.reason !== void 0 ? { reason: result.reason } : {}
|
|
20334
|
+
};
|
|
20335
|
+
},
|
|
20336
|
+
afterStep: async (ctx, signal) => {
|
|
20337
|
+
await this.executionHooks.run({
|
|
20338
|
+
event: "PostStep",
|
|
20339
|
+
sessionId: this.sessionId,
|
|
20340
|
+
turnId: ctx.turnId,
|
|
20341
|
+
stepNumber: ctx.stepNumber,
|
|
20342
|
+
agentId: this.agentId,
|
|
20343
|
+
stopReason: ctx.stopReason
|
|
20344
|
+
}, signal);
|
|
20345
|
+
}
|
|
20346
|
+
};
|
|
20315
20347
|
const input = trigger.input;
|
|
20316
20348
|
const runPromise = this.runTurn(turnId, input, soulConfig, runtimeForTurn, controller.signal);
|
|
20317
20349
|
runPromise.catch(() => {});
|
|
@@ -20418,6 +20450,16 @@ var TurnManager = class {
|
|
|
20418
20450
|
...result.usage.cache_write !== void 0 ? { cache_write_tokens: result.usage.cache_write } : {}
|
|
20419
20451
|
};
|
|
20420
20452
|
await this.deps.sessionJournal.appendTurnEnd(turnEnd);
|
|
20453
|
+
try {
|
|
20454
|
+
await this.executionHooks.run({
|
|
20455
|
+
event: "PostTurn",
|
|
20456
|
+
sessionId: this.sessionId,
|
|
20457
|
+
turnId,
|
|
20458
|
+
agentId: this.agentId,
|
|
20459
|
+
reason,
|
|
20460
|
+
success: reason === "done"
|
|
20461
|
+
}, new AbortController().signal);
|
|
20462
|
+
} catch {}
|
|
20421
20463
|
this.dispatchLifecycleHook({
|
|
20422
20464
|
event: "Stop",
|
|
20423
20465
|
sessionId: this.sessionId,
|
|
@@ -20670,6 +20712,7 @@ var SoulPlus = class {
|
|
|
20670
20712
|
hostToolNames;
|
|
20671
20713
|
planController;
|
|
20672
20714
|
setPlanModeImpl;
|
|
20715
|
+
stateCache;
|
|
20673
20716
|
/**
|
|
20674
20717
|
* Phase 18 A.3–A.6 — lazy `SessionControlHandler` owned by the
|
|
20675
20718
|
* facade. External hosts (SessionManager) still construct their own
|
|
@@ -20681,6 +20724,7 @@ var SoulPlus = class {
|
|
|
20681
20724
|
sessionControlInstance;
|
|
20682
20725
|
constructor(deps) {
|
|
20683
20726
|
this.sessionId = deps.sessionId;
|
|
20727
|
+
this.stateCache = deps.stateCache;
|
|
20684
20728
|
const eventBus = deps.eventBus;
|
|
20685
20729
|
const toolRegistry = [...deps.tools];
|
|
20686
20730
|
const enabledToolNames = deps.enabledToolNames !== void 0 ? new Set(deps.enabledToolNames) : void 0;
|
|
@@ -20703,7 +20747,6 @@ var SoulPlus = class {
|
|
|
20703
20747
|
const approvalRuntime = deps.approvalRuntime;
|
|
20704
20748
|
const sessionMeta = deps.stateCache !== void 0 && deps.initialMeta !== void 0 ? new SessionMetaService({
|
|
20705
20749
|
sessionId: deps.sessionId,
|
|
20706
|
-
sessionJournal,
|
|
20707
20750
|
eventBus,
|
|
20708
20751
|
stateCache: deps.stateCache,
|
|
20709
20752
|
initialMeta: deps.initialMeta
|
|
@@ -20838,6 +20881,19 @@ var SoulPlus = class {
|
|
|
20838
20881
|
const setPlanMode = async (enabled) => {
|
|
20839
20882
|
if (enabled) {
|
|
20840
20883
|
await planController.ensurePlanFilePath();
|
|
20884
|
+
await deps.stateCache?.update((current) => {
|
|
20885
|
+
const now = Date.now();
|
|
20886
|
+
return {
|
|
20887
|
+
...current ?? {
|
|
20888
|
+
session_id: deps.sessionId,
|
|
20889
|
+
created_at: now,
|
|
20890
|
+
updated_at: now
|
|
20891
|
+
},
|
|
20892
|
+
plan_mode: true,
|
|
20893
|
+
updated_at: now,
|
|
20894
|
+
last_exit_code: "dirty"
|
|
20895
|
+
};
|
|
20896
|
+
});
|
|
20841
20897
|
await contextState.applyConfigChange({
|
|
20842
20898
|
type: "plan_mode_changed",
|
|
20843
20899
|
enabled
|
|
@@ -20845,6 +20901,19 @@ var SoulPlus = class {
|
|
|
20845
20901
|
turnManager.setPlanMode(enabled);
|
|
20846
20902
|
return;
|
|
20847
20903
|
}
|
|
20904
|
+
await deps.stateCache?.update((current) => {
|
|
20905
|
+
const now = Date.now();
|
|
20906
|
+
return {
|
|
20907
|
+
...current ?? {
|
|
20908
|
+
session_id: deps.sessionId,
|
|
20909
|
+
created_at: now,
|
|
20910
|
+
updated_at: now
|
|
20911
|
+
},
|
|
20912
|
+
plan_mode: false,
|
|
20913
|
+
updated_at: now,
|
|
20914
|
+
last_exit_code: "dirty"
|
|
20915
|
+
};
|
|
20916
|
+
});
|
|
20848
20917
|
await contextState.applyConfigChange({
|
|
20849
20918
|
type: "plan_mode_changed",
|
|
20850
20919
|
enabled
|
|
@@ -20862,6 +20931,7 @@ var SoulPlus = class {
|
|
|
20862
20931
|
isPlanModeActive: () => turnManager.getPlanMode(),
|
|
20863
20932
|
setPlanMode,
|
|
20864
20933
|
isYoloMode: () => turnManager.getPermissionMode() === "bypassPermissions",
|
|
20934
|
+
shouldAutoApprove: () => true,
|
|
20865
20935
|
requestApproval: enterPlanRequestApproval,
|
|
20866
20936
|
getPlanFilePath: () => planController.getPlanFilePath()
|
|
20867
20937
|
}));
|
|
@@ -21098,19 +21168,49 @@ var SoulPlus = class {
|
|
|
21098
21168
|
turnManager: this.components.turnManager,
|
|
21099
21169
|
contextState: this.journal.contextState,
|
|
21100
21170
|
sessionJournal: this.journal.sessionJournal,
|
|
21101
|
-
setPlanModeOverride: (enabled) => this.setPlanMode(enabled)
|
|
21171
|
+
setPlanModeOverride: (enabled) => this.setPlanMode(enabled),
|
|
21172
|
+
setYoloOverride: async (enabled) => {
|
|
21173
|
+
const permissionMode = enabled ? "bypassPermissions" : "default";
|
|
21174
|
+
await this.stateCache?.update((current) => {
|
|
21175
|
+
const now = Date.now();
|
|
21176
|
+
return {
|
|
21177
|
+
...current ?? {
|
|
21178
|
+
session_id: this.sessionId,
|
|
21179
|
+
created_at: now,
|
|
21180
|
+
updated_at: now
|
|
21181
|
+
},
|
|
21182
|
+
permission_mode: permissionMode,
|
|
21183
|
+
updated_at: now,
|
|
21184
|
+
last_exit_code: "dirty"
|
|
21185
|
+
};
|
|
21186
|
+
});
|
|
21187
|
+
this.components.turnManager.setPermissionMode(permissionMode);
|
|
21188
|
+
}
|
|
21102
21189
|
});
|
|
21103
21190
|
return this.sessionControlInstance;
|
|
21104
21191
|
}
|
|
21105
21192
|
/**
|
|
21106
21193
|
* Phase 18 A.3 — programmatic model change. Applies the config
|
|
21107
|
-
* change event to ContextState
|
|
21194
|
+
* change event to ContextState, persists state.json, and emits a
|
|
21108
21195
|
* fresh `status.update` so downstream observers pick up the new
|
|
21109
21196
|
* model without waiting for the next turn boundary.
|
|
21110
21197
|
*/
|
|
21111
21198
|
async setModel(model) {
|
|
21112
21199
|
const oldModel = this.journal.contextState.model;
|
|
21113
21200
|
if (oldModel === model) return;
|
|
21201
|
+
await this.stateCache?.update((current) => {
|
|
21202
|
+
const now = Date.now();
|
|
21203
|
+
return {
|
|
21204
|
+
...current ?? {
|
|
21205
|
+
session_id: this.sessionId,
|
|
21206
|
+
created_at: now,
|
|
21207
|
+
updated_at: now
|
|
21208
|
+
},
|
|
21209
|
+
model,
|
|
21210
|
+
updated_at: now,
|
|
21211
|
+
last_exit_code: "dirty"
|
|
21212
|
+
};
|
|
21213
|
+
});
|
|
21114
21214
|
await this.journal.contextState.applyConfigChange({
|
|
21115
21215
|
type: "model_changed",
|
|
21116
21216
|
old_model: oldModel,
|
|
@@ -21127,8 +21227,7 @@ var SoulPlus = class {
|
|
|
21127
21227
|
}
|
|
21128
21228
|
/**
|
|
21129
21229
|
* Phase 18 A.6 / Phase 21 §A — programmatic thinking-level change.
|
|
21130
|
-
*
|
|
21131
|
-
* ContextState.applyConfigChange) and emits two SoulEvents:
|
|
21230
|
+
* Persists state.json, updates ContextState, and emits two SoulEvents:
|
|
21132
21231
|
* 1. `thinking.changed` — distinct event the wire bridge maps to a
|
|
21133
21232
|
* `thinking.changed` wire event with the bridge's per-session
|
|
21134
21233
|
* `seq` counter (replaces the old `seq: 0` direct send from
|
|
@@ -21137,6 +21236,19 @@ var SoulPlus = class {
|
|
|
21137
21236
|
* can repaint without subscribing to the dedicated event.
|
|
21138
21237
|
*/
|
|
21139
21238
|
async setThinking(level) {
|
|
21239
|
+
await this.stateCache?.update((current) => {
|
|
21240
|
+
const now = Date.now();
|
|
21241
|
+
return {
|
|
21242
|
+
...current ?? {
|
|
21243
|
+
session_id: this.sessionId,
|
|
21244
|
+
created_at: now,
|
|
21245
|
+
updated_at: now
|
|
21246
|
+
},
|
|
21247
|
+
thinking_level: level,
|
|
21248
|
+
updated_at: now,
|
|
21249
|
+
last_exit_code: "dirty"
|
|
21250
|
+
};
|
|
21251
|
+
});
|
|
21140
21252
|
await this.journal.contextState.applyConfigChange({
|
|
21141
21253
|
type: "thinking_changed",
|
|
21142
21254
|
level
|
|
@@ -21288,17 +21400,35 @@ var KosongAdapter = class {
|
|
|
21288
21400
|
}));
|
|
21289
21401
|
const onDelta = params.onDelta;
|
|
21290
21402
|
const onThinkDelta = params.onThinkDelta;
|
|
21403
|
+
const onToolCallPart = params.onToolCallPart;
|
|
21291
21404
|
const onAtomicPart = params.onAtomicPart;
|
|
21292
|
-
const needMessagePart = onDelta !== void 0 || onThinkDelta !== void 0;
|
|
21405
|
+
const needMessagePart = onDelta !== void 0 || onThinkDelta !== void 0 || onToolCallPart !== void 0;
|
|
21406
|
+
const toolCallsByStreamIndex = /* @__PURE__ */ new Map();
|
|
21407
|
+
let lastToolCall;
|
|
21293
21408
|
let result;
|
|
21294
21409
|
try {
|
|
21295
21410
|
result = await generate$1(activeProvider, params.systemPrompt, kosongTools, params.messages, needMessagePart ? { onMessagePart: async (part) => {
|
|
21296
21411
|
if (part.type === "text" && onDelta !== void 0) onDelta(part.text);
|
|
21297
21412
|
else if (part.type === "think" && onThinkDelta !== void 0) onThinkDelta(part.think);
|
|
21413
|
+
else if (part.type === "function") {
|
|
21414
|
+
lastToolCall = {
|
|
21415
|
+
id: part.id,
|
|
21416
|
+
name: part.function.name
|
|
21417
|
+
};
|
|
21418
|
+
if (part._streamIndex !== void 0) toolCallsByStreamIndex.set(part._streamIndex, lastToolCall);
|
|
21419
|
+
} else if (isToolCallPart(part) && onToolCallPart !== void 0) {
|
|
21420
|
+
const target = part.index !== void 0 ? toolCallsByStreamIndex.get(part.index) : lastToolCall;
|
|
21421
|
+
if (target !== void 0) onToolCallPart({
|
|
21422
|
+
type: "tool_call_part",
|
|
21423
|
+
tool_call_id: target.id,
|
|
21424
|
+
name: target.name,
|
|
21425
|
+
...part.argumentsPart !== null ? { arguments_chunk: part.argumentsPart } : {}
|
|
21426
|
+
});
|
|
21427
|
+
}
|
|
21298
21428
|
} } : void 0, { signal: params.signal });
|
|
21299
|
-
} catch (
|
|
21300
|
-
if (isContextOverflowProviderError(
|
|
21301
|
-
throw
|
|
21429
|
+
} catch (error) {
|
|
21430
|
+
if (isContextOverflowProviderError(error)) throw new ContextOverflowError(extractMessage(error));
|
|
21431
|
+
throw error;
|
|
21302
21432
|
}
|
|
21303
21433
|
if (onAtomicPart !== void 0) {
|
|
21304
21434
|
for (const part of result.message.content) if (part.type === "text" || part.type === "think") await onAtomicPart({
|
|
@@ -26470,7 +26600,7 @@ K(Un, Hn, Wn, Gn, (s, t) => {
|
|
|
26470
26600
|
if (!t?.length) throw new TypeError("no paths specified to add to archive");
|
|
26471
26601
|
});
|
|
26472
26602
|
var fr = (process.env.__FAKE_PLATFORM__ || process.platform) === "win32", { O_CREAT: dr, O_NOFOLLOW: ar, O_TRUNC: ur, O_WRONLY: mr } = I.constants, pr = Number(process.env.__FAKE_FS_O_FILENAME__) || I.constants.UV_FS_O_FILEMAP || 0, Kn = fr && !!pr, Vn = 512 * 1024, $n = pr | ur | dr | mr, lr = !fr && typeof ar == "number" ? ar | ur | dr | mr : null, cs = lr !== null ? () => lr : Kn ? (s) => s < Vn ? $n : "w" : () => "w";
|
|
26473
|
-
var fs$
|
|
26603
|
+
var fs$13 = (s, t, e) => {
|
|
26474
26604
|
try {
|
|
26475
26605
|
return Vt.lchownSync(s, t, e);
|
|
26476
26606
|
} catch (i) {
|
|
@@ -26502,7 +26632,7 @@ var fs$12 = (s, t, e) => {
|
|
|
26502
26632
|
for (let l of n) Xn(s, l, t, e, a);
|
|
26503
26633
|
});
|
|
26504
26634
|
}, qn = (s, t, e, i) => {
|
|
26505
|
-
t.isDirectory() && us(path.resolve(s, t.name), e, i), fs$
|
|
26635
|
+
t.isDirectory() && us(path.resolve(s, t.name), e, i), fs$13(path.resolve(s, t.name), e, i);
|
|
26506
26636
|
}, us = (s, t, e) => {
|
|
26507
26637
|
let i;
|
|
26508
26638
|
try {
|
|
@@ -26510,11 +26640,11 @@ var fs$12 = (s, t, e) => {
|
|
|
26510
26640
|
} catch (r) {
|
|
26511
26641
|
let n = r;
|
|
26512
26642
|
if (n?.code === "ENOENT") return;
|
|
26513
|
-
if (n?.code === "ENOTDIR" || n?.code === "ENOTSUP") return fs$
|
|
26643
|
+
if (n?.code === "ENOTDIR" || n?.code === "ENOTSUP") return fs$13(s, t, e);
|
|
26514
26644
|
throw n;
|
|
26515
26645
|
}
|
|
26516
26646
|
for (let r of i) qn(s, r, t, e);
|
|
26517
|
-
return fs$
|
|
26647
|
+
return fs$13(s, t, e);
|
|
26518
26648
|
};
|
|
26519
26649
|
var we = class extends Error {
|
|
26520
26650
|
path;
|
|
@@ -26549,7 +26679,7 @@ var Qn = (s, t) => {
|
|
|
26549
26679
|
E ? e(E) : x && a ? ds(x, o, h, (xe) => S(xe)) : n ? Vt.chmod(s, r, e) : e();
|
|
26550
26680
|
};
|
|
26551
26681
|
if (s === d) return Qn(s, S);
|
|
26552
|
-
if (l) return
|
|
26682
|
+
if (l) return fs.mkdir(s, {
|
|
26553
26683
|
mode: r,
|
|
26554
26684
|
recursive: !0
|
|
26555
26685
|
}).then((E) => S(null, E ?? void 0), S);
|
|
@@ -27308,7 +27438,7 @@ var require_pend = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
27308
27438
|
//#endregion
|
|
27309
27439
|
//#region ../../node_modules/.pnpm/yauzl@3.3.0/node_modules/yauzl/fd-slicer.js
|
|
27310
27440
|
var require_fd_slicer = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
27311
|
-
var fs$
|
|
27441
|
+
var fs$12 = __require("fs");
|
|
27312
27442
|
var util$7 = __require("util");
|
|
27313
27443
|
var stream$4 = __require("stream");
|
|
27314
27444
|
var Readable = stream$4.Readable;
|
|
@@ -27333,7 +27463,7 @@ var require_fd_slicer = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
27333
27463
|
FdSlicer.prototype.read = function(buffer, offset, length, position, callback) {
|
|
27334
27464
|
var self = this;
|
|
27335
27465
|
self.pend.go(function(cb) {
|
|
27336
|
-
fs$
|
|
27466
|
+
fs$12.read(self.fd, buffer, offset, length, position, function(err, bytesRead, buffer) {
|
|
27337
27467
|
cb();
|
|
27338
27468
|
callback(err, bytesRead, buffer);
|
|
27339
27469
|
});
|
|
@@ -27342,7 +27472,7 @@ var require_fd_slicer = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
27342
27472
|
FdSlicer.prototype.write = function(buffer, offset, length, position, callback) {
|
|
27343
27473
|
var self = this;
|
|
27344
27474
|
self.pend.go(function(cb) {
|
|
27345
|
-
fs$
|
|
27475
|
+
fs$12.write(self.fd, buffer, offset, length, position, function(err, written, buffer) {
|
|
27346
27476
|
cb();
|
|
27347
27477
|
callback(err, written, buffer);
|
|
27348
27478
|
});
|
|
@@ -27362,7 +27492,7 @@ var require_fd_slicer = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
27362
27492
|
self.refCount -= 1;
|
|
27363
27493
|
if (self.refCount > 0) return;
|
|
27364
27494
|
if (self.refCount < 0) throw new Error("invalid unref");
|
|
27365
|
-
if (self.autoClose) fs$
|
|
27495
|
+
if (self.autoClose) fs$12.close(self.fd, onCloseDone);
|
|
27366
27496
|
function onCloseDone(err) {
|
|
27367
27497
|
if (err) self.emit("error", err);
|
|
27368
27498
|
else self.emit("close");
|
|
@@ -27393,7 +27523,7 @@ var require_fd_slicer = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
27393
27523
|
self.context.pend.go(function(cb) {
|
|
27394
27524
|
if (self.destroyed) return cb();
|
|
27395
27525
|
var buffer = Buffer.allocUnsafe(toRead);
|
|
27396
|
-
fs$
|
|
27526
|
+
fs$12.read(self.context.fd, buffer, 0, toRead, self.pos, function(err, bytesRead) {
|
|
27397
27527
|
if (err) self.destroy(err);
|
|
27398
27528
|
else if (bytesRead === 0) {
|
|
27399
27529
|
self.destroyed = true;
|
|
@@ -27439,7 +27569,7 @@ var require_fd_slicer = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
27439
27569
|
}
|
|
27440
27570
|
self.context.pend.go(function(cb) {
|
|
27441
27571
|
if (self.destroyed) return cb();
|
|
27442
|
-
fs$
|
|
27572
|
+
fs$12.write(self.context.fd, buffer, 0, buffer.length, self.pos, function(err, bytes) {
|
|
27443
27573
|
if (err) {
|
|
27444
27574
|
self.destroy();
|
|
27445
27575
|
cb();
|
|
@@ -29313,6 +29443,28 @@ var SetTodoListTool = class {
|
|
|
29313
29443
|
}));
|
|
29314
29444
|
}
|
|
29315
29445
|
};
|
|
29446
|
+
//#endregion
|
|
29447
|
+
//#region ../../packages/kimi-core/src/hooks/supported-events.ts
|
|
29448
|
+
const SUPPORTED_HOOK_EVENTS = [
|
|
29449
|
+
"PreTurn",
|
|
29450
|
+
"PostTurn",
|
|
29451
|
+
"PreStep",
|
|
29452
|
+
"PostStep",
|
|
29453
|
+
"PreToolUse",
|
|
29454
|
+
"PostToolUse",
|
|
29455
|
+
"OnToolFailure",
|
|
29456
|
+
"UserPromptSubmit",
|
|
29457
|
+
"Stop",
|
|
29458
|
+
"StopFailure",
|
|
29459
|
+
"Notification",
|
|
29460
|
+
"SubagentStart",
|
|
29461
|
+
"SubagentStop",
|
|
29462
|
+
"SessionStart",
|
|
29463
|
+
"SessionEnd",
|
|
29464
|
+
"PreCompact",
|
|
29465
|
+
"PostCompact"
|
|
29466
|
+
];
|
|
29467
|
+
new Set(SUPPORTED_HOOK_EVENTS);
|
|
29316
29468
|
const _rawWireErrorSchema = z.object({
|
|
29317
29469
|
code: z.number(),
|
|
29318
29470
|
message: z.string(),
|
|
@@ -29505,188 +29657,332 @@ function createWireEvent(options) {
|
|
|
29505
29657
|
};
|
|
29506
29658
|
}
|
|
29507
29659
|
//#endregion
|
|
29660
|
+
//#region ../../packages/kimi-core/src/wire-protocol/event-pipeline.ts
|
|
29661
|
+
/**
|
|
29662
|
+
* WireEventPipeline is the ordered, awaited publication path from a translated
|
|
29663
|
+
* `WireEventDraft` to one or more event consumers.
|
|
29664
|
+
*
|
|
29665
|
+
* `enqueue()` intentionally returns void: upstream Soul/SoulPlus emitters must
|
|
29666
|
+
* not be back-pressured by transport, telemetry, or debug consumers. The
|
|
29667
|
+
* pipeline drains in the background and awaits each middleware/consumer
|
|
29668
|
+
* internally to preserve per-session event ordering.
|
|
29669
|
+
*/
|
|
29670
|
+
var WireEventPipeline = class {
|
|
29671
|
+
sessionId;
|
|
29672
|
+
getEventFilter;
|
|
29673
|
+
middlewares;
|
|
29674
|
+
consumers;
|
|
29675
|
+
queue = [];
|
|
29676
|
+
idleWaiters = [];
|
|
29677
|
+
draining = false;
|
|
29678
|
+
seq = 0;
|
|
29679
|
+
constructor(options) {
|
|
29680
|
+
this.sessionId = options.sessionId;
|
|
29681
|
+
this.getEventFilter = options.getEventFilter;
|
|
29682
|
+
this.consumers = options.consumers ?? [createTransportWireEventConsumer({
|
|
29683
|
+
transport: options.transport,
|
|
29684
|
+
codec: options.codec
|
|
29685
|
+
})];
|
|
29686
|
+
this.middlewares = [
|
|
29687
|
+
createWireEventFilterMiddleware(this.getEventFilter),
|
|
29688
|
+
...options.middlewares ?? [],
|
|
29689
|
+
this.createFrameMiddleware(),
|
|
29690
|
+
createWireEventConsumerMiddleware(this.consumers)
|
|
29691
|
+
];
|
|
29692
|
+
}
|
|
29693
|
+
enqueue(draft) {
|
|
29694
|
+
this.queue.push(draft);
|
|
29695
|
+
if (!this.draining) this.drain();
|
|
29696
|
+
}
|
|
29697
|
+
/**
|
|
29698
|
+
* Test / controlled-host helper: resolves once the queue that is currently
|
|
29699
|
+
* known to the pipeline has drained. Normal production callers should use
|
|
29700
|
+
* fire-and-forget `enqueue()`.
|
|
29701
|
+
*/
|
|
29702
|
+
async flush() {
|
|
29703
|
+
if (!this.draining && this.queue.length === 0) return;
|
|
29704
|
+
await new Promise((resolve) => {
|
|
29705
|
+
this.idleWaiters.push(resolve);
|
|
29706
|
+
});
|
|
29707
|
+
}
|
|
29708
|
+
async drain() {
|
|
29709
|
+
this.draining = true;
|
|
29710
|
+
let restart = false;
|
|
29711
|
+
try {
|
|
29712
|
+
while (this.queue.length > 0) {
|
|
29713
|
+
const draft = this.queue.shift();
|
|
29714
|
+
if (draft === void 0) continue;
|
|
29715
|
+
await this.processOne(draft);
|
|
29716
|
+
}
|
|
29717
|
+
} finally {
|
|
29718
|
+
this.draining = false;
|
|
29719
|
+
if (this.queue.length > 0) restart = true;
|
|
29720
|
+
else {
|
|
29721
|
+
const waiters = this.idleWaiters.splice(0);
|
|
29722
|
+
for (const resolve of waiters) resolve();
|
|
29723
|
+
}
|
|
29724
|
+
}
|
|
29725
|
+
if (restart) this.drain();
|
|
29726
|
+
}
|
|
29727
|
+
async processOne(draft) {
|
|
29728
|
+
const ctx = {
|
|
29729
|
+
sessionId: this.sessionId,
|
|
29730
|
+
draft
|
|
29731
|
+
};
|
|
29732
|
+
try {
|
|
29733
|
+
await composeWireEventMiddlewares(this.middlewares)(ctx);
|
|
29734
|
+
} catch {}
|
|
29735
|
+
}
|
|
29736
|
+
createFrameMiddleware() {
|
|
29737
|
+
return async (ctx, next) => {
|
|
29738
|
+
ctx.event = createWireEvent({
|
|
29739
|
+
method: ctx.draft.method,
|
|
29740
|
+
sessionId: ctx.sessionId,
|
|
29741
|
+
seq: this.seq++,
|
|
29742
|
+
...ctx.draft.requestId !== void 0 ? { requestId: ctx.draft.requestId } : {},
|
|
29743
|
+
...ctx.draft.turnId !== void 0 ? { turnId: ctx.draft.turnId } : {},
|
|
29744
|
+
agentType: ctx.draft.agentType ?? "main",
|
|
29745
|
+
...ctx.draft.source !== void 0 ? { source: ctx.draft.source } : {},
|
|
29746
|
+
data: ctx.draft.data
|
|
29747
|
+
});
|
|
29748
|
+
await next();
|
|
29749
|
+
};
|
|
29750
|
+
}
|
|
29751
|
+
};
|
|
29752
|
+
function createWireEventFilterMiddleware(getEventFilter) {
|
|
29753
|
+
return async (ctx, next) => {
|
|
29754
|
+
if (getEventFilter !== void 0) {
|
|
29755
|
+
const filter = getEventFilter();
|
|
29756
|
+
if (filter !== void 0 && !filter.has(ctx.draft.method)) return;
|
|
29757
|
+
}
|
|
29758
|
+
await next();
|
|
29759
|
+
};
|
|
29760
|
+
}
|
|
29761
|
+
function createTransportWireEventConsumer(options) {
|
|
29762
|
+
const codec = options.codec ?? new WireCodec();
|
|
29763
|
+
return {
|
|
29764
|
+
name: "transport",
|
|
29765
|
+
async consume(event) {
|
|
29766
|
+
try {
|
|
29767
|
+
await options.transport.send(codec.encode(event));
|
|
29768
|
+
} catch {}
|
|
29769
|
+
}
|
|
29770
|
+
};
|
|
29771
|
+
}
|
|
29772
|
+
function createWireEventConsumerMiddleware(consumers) {
|
|
29773
|
+
return async (ctx) => {
|
|
29774
|
+
if (ctx.event === void 0) return;
|
|
29775
|
+
const snapshot = [...consumers];
|
|
29776
|
+
for (const consumer of snapshot) try {
|
|
29777
|
+
await consumer.consume(ctx.event, {
|
|
29778
|
+
sessionId: ctx.sessionId,
|
|
29779
|
+
draft: ctx.draft
|
|
29780
|
+
});
|
|
29781
|
+
} catch {}
|
|
29782
|
+
};
|
|
29783
|
+
}
|
|
29784
|
+
function composeWireEventMiddlewares(middlewares) {
|
|
29785
|
+
return async (ctx) => {
|
|
29786
|
+
let index = -1;
|
|
29787
|
+
const dispatch = async (i) => {
|
|
29788
|
+
if (i <= index) throw new Error("wire event middleware called next() multiple times");
|
|
29789
|
+
index = i;
|
|
29790
|
+
const middleware = middlewares[i];
|
|
29791
|
+
if (middleware === void 0) return;
|
|
29792
|
+
await middleware(ctx, () => dispatch(i + 1));
|
|
29793
|
+
};
|
|
29794
|
+
await dispatch(0);
|
|
29795
|
+
};
|
|
29796
|
+
}
|
|
29797
|
+
//#endregion
|
|
29798
|
+
//#region ../../packages/kimi-core/src/wire-protocol/event-translators.ts
|
|
29799
|
+
function draft(event, ctx, method, data) {
|
|
29800
|
+
return {
|
|
29801
|
+
method,
|
|
29802
|
+
data,
|
|
29803
|
+
...ctx.currentTurnId !== void 0 ? { turnId: ctx.currentTurnId } : {},
|
|
29804
|
+
...event.source !== void 0 ? { source: event.source } : {}
|
|
29805
|
+
};
|
|
29806
|
+
}
|
|
29807
|
+
const BUS_EVENT_TRANSLATORS = {
|
|
29808
|
+
"step.begin": (event, ctx) => {
|
|
29809
|
+
return draft(event, ctx, "step.begin", { step: event.step });
|
|
29810
|
+
},
|
|
29811
|
+
"step.end": (event, ctx) => {
|
|
29812
|
+
return draft(event, ctx, "step.end", { step: event.step });
|
|
29813
|
+
},
|
|
29814
|
+
"step.interrupted": (event, ctx) => {
|
|
29815
|
+
return draft(event, ctx, "step.interrupted", {
|
|
29816
|
+
step: event.step,
|
|
29817
|
+
reason: event.reason
|
|
29818
|
+
});
|
|
29819
|
+
},
|
|
29820
|
+
"content.delta": (event, ctx) => {
|
|
29821
|
+
return draft(event, ctx, "content.delta", {
|
|
29822
|
+
type: "text",
|
|
29823
|
+
text: event.delta
|
|
29824
|
+
});
|
|
29825
|
+
},
|
|
29826
|
+
"thinking.delta": (event, ctx) => {
|
|
29827
|
+
return draft(event, ctx, "content.delta", {
|
|
29828
|
+
type: "thinking",
|
|
29829
|
+
thinking: event.delta
|
|
29830
|
+
});
|
|
29831
|
+
},
|
|
29832
|
+
tool_call_part: (event, ctx) => {
|
|
29833
|
+
return draft(event, ctx, "tool.call.delta", {
|
|
29834
|
+
tool_call_id: event.tool_call_id,
|
|
29835
|
+
...event.name !== void 0 ? { name: event.name } : {},
|
|
29836
|
+
arguments_part: event.arguments_chunk ?? null
|
|
29837
|
+
});
|
|
29838
|
+
},
|
|
29839
|
+
"tool.call": (event, ctx) => {
|
|
29840
|
+
return draft(event, ctx, "tool.call", {
|
|
29841
|
+
id: event.toolCallId,
|
|
29842
|
+
name: event.name,
|
|
29843
|
+
args: event.args
|
|
29844
|
+
});
|
|
29845
|
+
},
|
|
29846
|
+
"tool.progress": (event, ctx) => draft(event, ctx, "tool.progress", {
|
|
29847
|
+
id: event.toolCallId,
|
|
29848
|
+
update: event.update
|
|
29849
|
+
}),
|
|
29850
|
+
"tool.result": (event, ctx) => {
|
|
29851
|
+
return draft(event, ctx, "tool.result", {
|
|
29852
|
+
tool_call_id: event.toolCallId,
|
|
29853
|
+
output: event.output,
|
|
29854
|
+
...event.isError !== void 0 ? { is_error: event.isError } : {}
|
|
29855
|
+
});
|
|
29856
|
+
},
|
|
29857
|
+
"compaction.begin": (event, ctx) => {
|
|
29858
|
+
return draft(event, ctx, "compaction.begin", {});
|
|
29859
|
+
},
|
|
29860
|
+
"compaction.end": (event, ctx) => {
|
|
29861
|
+
return draft(event, ctx, "compaction.end", {
|
|
29862
|
+
...event.tokensBefore !== void 0 ? { tokens_before: event.tokensBefore } : {},
|
|
29863
|
+
...event.tokensAfter !== void 0 ? { tokens_after: event.tokensAfter } : {}
|
|
29864
|
+
});
|
|
29865
|
+
},
|
|
29866
|
+
"session.error": (event, ctx) => {
|
|
29867
|
+
return draft(event, ctx, "session.error", {
|
|
29868
|
+
error: event.error,
|
|
29869
|
+
...event.error_type !== void 0 ? { error_type: event.error_type } : {},
|
|
29870
|
+
...event.retry_after_ms !== void 0 ? { retry_after_ms: event.retry_after_ms } : {},
|
|
29871
|
+
...event.details !== void 0 ? { details: event.details } : {}
|
|
29872
|
+
});
|
|
29873
|
+
},
|
|
29874
|
+
"hook.triggered": (event, ctx) => draft(event, ctx, "hook.triggered", {
|
|
29875
|
+
event: event.event,
|
|
29876
|
+
matchers: event.matchers,
|
|
29877
|
+
matched_count: event.matched_count
|
|
29878
|
+
}),
|
|
29879
|
+
"hook.resolved": (event, ctx) => draft(event, ctx, "hook.resolved", {
|
|
29880
|
+
hook_id: event.hook_id,
|
|
29881
|
+
outcome: event.outcome
|
|
29882
|
+
}),
|
|
29883
|
+
"status.update": (event, ctx) => draft(event, ctx, "status.update", event.data),
|
|
29884
|
+
"session_meta.changed": (event, ctx) => draft(event, ctx, "session_meta.changed", event.data),
|
|
29885
|
+
"thinking.changed": (event, ctx) => draft(event, ctx, "thinking.changed", { level: event.level }),
|
|
29886
|
+
"skill.invoked": (event, ctx) => draft(event, ctx, "skill.invoked", event.data),
|
|
29887
|
+
"skill.completed": (event, ctx) => draft(event, ctx, "skill.completed", event.data),
|
|
29888
|
+
"mcp.loading": (event, ctx) => draft(event, ctx, "mcp.loading", event.data),
|
|
29889
|
+
"mcp.connected": (event, ctx) => draft(event, ctx, "mcp.connected", event.data),
|
|
29890
|
+
"mcp.disconnected": (event, ctx) => draft(event, ctx, "mcp.disconnected", event.data),
|
|
29891
|
+
"mcp.error": (event, ctx) => draft(event, ctx, "mcp.error", event.data),
|
|
29892
|
+
"mcp.tools_changed": (event, ctx) => draft(event, ctx, "mcp.tools_changed", event.data),
|
|
29893
|
+
"mcp.resources_changed": (event, ctx) => draft(event, ctx, "mcp.resources_changed", event.data),
|
|
29894
|
+
"mcp.auth_required": (event, ctx) => draft(event, ctx, "mcp.auth_required", event.data),
|
|
29895
|
+
"status.update.mcp_status": (event, ctx) => draft(event, ctx, "status.update.mcp_status", event.data),
|
|
29896
|
+
"subagent.spawned": (event, ctx) => draft(event, ctx, "subagent.spawned", event.data),
|
|
29897
|
+
"subagent.completed": (event, ctx) => draft(event, ctx, "subagent.completed", event.data),
|
|
29898
|
+
"subagent.failed": (event, ctx) => draft(event, ctx, "subagent.failed", event.data),
|
|
29899
|
+
"model.changed": () => {},
|
|
29900
|
+
"turn.end": () => {}
|
|
29901
|
+
};
|
|
29902
|
+
function translateBusEvent(event, currentTurnId) {
|
|
29903
|
+
const translator = BUS_EVENT_TRANSLATORS[event.type];
|
|
29904
|
+
return translator(event, currentTurnId !== void 0 ? { currentTurnId } : {});
|
|
29905
|
+
}
|
|
29906
|
+
function translateNotificationEvent(notif) {
|
|
29907
|
+
return {
|
|
29908
|
+
method: "notification",
|
|
29909
|
+
data: notif
|
|
29910
|
+
};
|
|
29911
|
+
}
|
|
29912
|
+
function translateTurnLifecycleEvent(event, currentTurnId) {
|
|
29913
|
+
if (event.kind === "begin") return {
|
|
29914
|
+
draft: {
|
|
29915
|
+
method: "turn.begin",
|
|
29916
|
+
data: {
|
|
29917
|
+
turn_id: event.turnId,
|
|
29918
|
+
user_input: event.userInputParts ?? event.userInput,
|
|
29919
|
+
input_kind: event.inputKind
|
|
29920
|
+
},
|
|
29921
|
+
turnId: event.turnId
|
|
29922
|
+
},
|
|
29923
|
+
nextTurnId: event.turnId
|
|
29924
|
+
};
|
|
29925
|
+
return {
|
|
29926
|
+
draft: {
|
|
29927
|
+
method: "turn.end",
|
|
29928
|
+
data: {
|
|
29929
|
+
turn_id: event.turnId,
|
|
29930
|
+
reason: event.reason,
|
|
29931
|
+
success: event.success,
|
|
29932
|
+
...event.usage !== void 0 ? { usage: {
|
|
29933
|
+
input_tokens: event.usage.input,
|
|
29934
|
+
output_tokens: event.usage.output,
|
|
29935
|
+
...event.usage.cache_read !== void 0 ? { cache_read_tokens: event.usage.cache_read } : {},
|
|
29936
|
+
...event.usage.cache_write !== void 0 ? { cache_write_tokens: event.usage.cache_write } : {}
|
|
29937
|
+
} } : {}
|
|
29938
|
+
},
|
|
29939
|
+
turnId: event.turnId
|
|
29940
|
+
},
|
|
29941
|
+
...currentTurnId === event.turnId && currentTurnId !== void 0 ? {} : currentTurnId !== void 0 ? { nextTurnId: currentTurnId } : {}
|
|
29942
|
+
};
|
|
29943
|
+
}
|
|
29944
|
+
//#endregion
|
|
29508
29945
|
//#region ../../packages/kimi-core/src/wire-protocol/event-bridge.ts
|
|
29509
29946
|
/**
|
|
29510
|
-
* WireEventBridge — SoulEvent + TurnLifecycleEvent →
|
|
29947
|
+
* WireEventBridge — SoulEvent + TurnLifecycleEvent → WireEventDraft adapter
|
|
29511
29948
|
* (Phase 17 §A.1).
|
|
29512
29949
|
*
|
|
29513
|
-
* Subscribes to
|
|
29514
|
-
* and forwards translated
|
|
29515
|
-
* Each bridge instance owns its own
|
|
29516
|
-
* pointer
|
|
29517
|
-
* Phase 10 test helper).
|
|
29950
|
+
* Subscribes to three input channels (SessionEventBus + notification channel
|
|
29951
|
+
* + TurnLifecycleTracker) and forwards translated drafts through a
|
|
29952
|
+
* per-session WireEventPipeline. Each bridge instance owns its own
|
|
29953
|
+
* `currentTurnId` pointer; the pipeline owns the per-session wire `seq`.
|
|
29518
29954
|
*
|
|
29519
29955
|
* Invariants (§5.0):
|
|
29520
|
-
* - L4: listeners return `void`; the bridge never awaits
|
|
29956
|
+
* - L4: listeners return `void`; the bridge never awaits pipeline drain
|
|
29521
29957
|
* - L5: listener does not touch wire.jsonl — translation is write-only
|
|
29522
29958
|
* toward the transport
|
|
29523
29959
|
*/
|
|
29524
|
-
const codec = new WireCodec();
|
|
29525
29960
|
function installWireEventBridge(opts) {
|
|
29526
29961
|
const { server, eventBus, addTurnLifecycleListener, sessionId, getEventFilter } = opts;
|
|
29527
|
-
let seq = 0;
|
|
29528
29962
|
let currentTurnId;
|
|
29529
|
-
const
|
|
29530
|
-
|
|
29531
|
-
|
|
29532
|
-
|
|
29533
|
-
|
|
29534
|
-
const frame = codec.encode(createWireEvent({
|
|
29535
|
-
method,
|
|
29536
|
-
sessionId,
|
|
29537
|
-
seq: seq++,
|
|
29538
|
-
...turnId !== void 0 ? { turnId } : {},
|
|
29539
|
-
agentType: "main",
|
|
29540
|
-
...source !== void 0 ? { source } : {},
|
|
29541
|
-
data
|
|
29542
|
-
}));
|
|
29543
|
-
server.send(frame).catch(() => {});
|
|
29544
|
-
};
|
|
29963
|
+
const pipeline = new WireEventPipeline({
|
|
29964
|
+
sessionId,
|
|
29965
|
+
transport: server,
|
|
29966
|
+
...getEventFilter !== void 0 ? { getEventFilter } : {}
|
|
29967
|
+
});
|
|
29545
29968
|
const soulListener = (event) => {
|
|
29546
|
-
|
|
29547
|
-
|
|
29548
|
-
|
|
29549
|
-
|
|
29550
|
-
|
|
29551
|
-
sendWire("step.end", { step: event.step }, currentTurnId, event.source);
|
|
29552
|
-
return;
|
|
29553
|
-
case "step.interrupted":
|
|
29554
|
-
sendWire("step.interrupted", {
|
|
29555
|
-
step: event.step,
|
|
29556
|
-
reason: event.reason
|
|
29557
|
-
}, currentTurnId, event.source);
|
|
29558
|
-
return;
|
|
29559
|
-
case "content.delta":
|
|
29560
|
-
sendWire("content.delta", {
|
|
29561
|
-
type: "text",
|
|
29562
|
-
text: event.delta
|
|
29563
|
-
}, currentTurnId, event.source);
|
|
29564
|
-
return;
|
|
29565
|
-
case "thinking.delta":
|
|
29566
|
-
sendWire("content.delta", {
|
|
29567
|
-
type: "thinking",
|
|
29568
|
-
thinking: event.delta
|
|
29569
|
-
}, currentTurnId, event.source);
|
|
29570
|
-
return;
|
|
29571
|
-
case "tool_call_part":
|
|
29572
|
-
sendWire("content.delta", {
|
|
29573
|
-
type: "tool_call_part",
|
|
29574
|
-
tool_call_id: event.tool_call_id,
|
|
29575
|
-
...event.name !== void 0 ? { name: event.name } : {},
|
|
29576
|
-
...event.arguments_chunk !== void 0 ? { arguments_chunk: event.arguments_chunk } : {}
|
|
29577
|
-
}, currentTurnId, event.source);
|
|
29578
|
-
return;
|
|
29579
|
-
case "tool.call":
|
|
29580
|
-
sendWire("tool.call", {
|
|
29581
|
-
id: event.toolCallId,
|
|
29582
|
-
name: event.name,
|
|
29583
|
-
args: event.args
|
|
29584
|
-
}, currentTurnId, event.source);
|
|
29585
|
-
return;
|
|
29586
|
-
case "tool.progress":
|
|
29587
|
-
sendWire("tool.progress", {
|
|
29588
|
-
id: event.toolCallId,
|
|
29589
|
-
update: event.update
|
|
29590
|
-
}, currentTurnId, event.source);
|
|
29591
|
-
return;
|
|
29592
|
-
case "tool.result":
|
|
29593
|
-
sendWire("tool.result", {
|
|
29594
|
-
tool_call_id: event.toolCallId,
|
|
29595
|
-
output: event.output,
|
|
29596
|
-
...event.isError !== void 0 ? { is_error: event.isError } : {}
|
|
29597
|
-
}, currentTurnId, event.source);
|
|
29598
|
-
return;
|
|
29599
|
-
case "compaction.begin":
|
|
29600
|
-
sendWire("compaction.begin", {}, currentTurnId, event.source);
|
|
29601
|
-
return;
|
|
29602
|
-
case "compaction.end":
|
|
29603
|
-
sendWire("compaction.end", {
|
|
29604
|
-
...event.tokensBefore !== void 0 ? { tokens_before: event.tokensBefore } : {},
|
|
29605
|
-
...event.tokensAfter !== void 0 ? { tokens_after: event.tokensAfter } : {}
|
|
29606
|
-
}, currentTurnId, event.source);
|
|
29607
|
-
return;
|
|
29608
|
-
case "session.error":
|
|
29609
|
-
sendWire("session.error", {
|
|
29610
|
-
error: event.error,
|
|
29611
|
-
...event.error_type !== void 0 ? { error_type: event.error_type } : {},
|
|
29612
|
-
...event.retry_after_ms !== void 0 ? { retry_after_ms: event.retry_after_ms } : {},
|
|
29613
|
-
...event.details !== void 0 ? { details: event.details } : {}
|
|
29614
|
-
}, currentTurnId, event.source);
|
|
29615
|
-
return;
|
|
29616
|
-
case "hook.triggered":
|
|
29617
|
-
sendWire("hook.triggered", {
|
|
29618
|
-
event: event.event,
|
|
29619
|
-
matchers: event.matchers,
|
|
29620
|
-
matched_count: event.matched_count
|
|
29621
|
-
}, currentTurnId, event.source);
|
|
29622
|
-
return;
|
|
29623
|
-
case "hook.resolved":
|
|
29624
|
-
sendWire("hook.resolved", {
|
|
29625
|
-
hook_id: event.hook_id,
|
|
29626
|
-
outcome: event.outcome
|
|
29627
|
-
}, currentTurnId, event.source);
|
|
29628
|
-
return;
|
|
29629
|
-
case "status.update":
|
|
29630
|
-
sendWire("status.update", event.data, currentTurnId, event.source);
|
|
29631
|
-
return;
|
|
29632
|
-
case "session_meta.changed":
|
|
29633
|
-
sendWire("session_meta.changed", event.data, currentTurnId, event.source);
|
|
29634
|
-
return;
|
|
29635
|
-
case "thinking.changed":
|
|
29636
|
-
sendWire("thinking.changed", { level: event.level }, currentTurnId, event.source);
|
|
29637
|
-
return;
|
|
29638
|
-
case "skill.invoked":
|
|
29639
|
-
sendWire("skill.invoked", event.data, currentTurnId, event.source);
|
|
29640
|
-
return;
|
|
29641
|
-
case "skill.completed":
|
|
29642
|
-
sendWire("skill.completed", event.data, currentTurnId, event.source);
|
|
29643
|
-
return;
|
|
29644
|
-
case "mcp.loading":
|
|
29645
|
-
case "mcp.connected":
|
|
29646
|
-
case "mcp.disconnected":
|
|
29647
|
-
case "mcp.error":
|
|
29648
|
-
case "mcp.tools_changed":
|
|
29649
|
-
case "mcp.resources_changed":
|
|
29650
|
-
case "mcp.auth_required":
|
|
29651
|
-
case "status.update.mcp_status":
|
|
29652
|
-
sendWire(event.type, event.data, currentTurnId, event.source);
|
|
29653
|
-
return;
|
|
29654
|
-
case "subagent.spawned":
|
|
29655
|
-
case "subagent.completed":
|
|
29656
|
-
case "subagent.failed":
|
|
29657
|
-
sendWire(event.type, event.data, currentTurnId, event.source);
|
|
29658
|
-
return;
|
|
29659
|
-
default:
|
|
29660
|
-
}
|
|
29969
|
+
const draft = translateBusEvent(event, currentTurnId);
|
|
29970
|
+
if (draft !== void 0) pipeline.enqueue(draft);
|
|
29971
|
+
};
|
|
29972
|
+
const notificationListener = (notif) => {
|
|
29973
|
+
pipeline.enqueue(translateNotificationEvent(notif));
|
|
29661
29974
|
};
|
|
29662
29975
|
const turnListener = (event) => {
|
|
29663
|
-
|
|
29664
|
-
|
|
29665
|
-
|
|
29666
|
-
turn_id: event.turnId,
|
|
29667
|
-
user_input: event.userInputParts ?? event.userInput,
|
|
29668
|
-
input_kind: event.inputKind
|
|
29669
|
-
}, event.turnId);
|
|
29670
|
-
return;
|
|
29671
|
-
}
|
|
29672
|
-
const turnId = event.turnId;
|
|
29673
|
-
sendWire("turn.end", {
|
|
29674
|
-
turn_id: turnId,
|
|
29675
|
-
reason: event.reason,
|
|
29676
|
-
success: event.success,
|
|
29677
|
-
...event.usage !== void 0 ? { usage: {
|
|
29678
|
-
input_tokens: event.usage.input,
|
|
29679
|
-
output_tokens: event.usage.output,
|
|
29680
|
-
...event.usage.cache_read !== void 0 ? { cache_read_tokens: event.usage.cache_read } : {},
|
|
29681
|
-
...event.usage.cache_write !== void 0 ? { cache_write_tokens: event.usage.cache_write } : {}
|
|
29682
|
-
} } : {}
|
|
29683
|
-
}, turnId);
|
|
29684
|
-
if (currentTurnId === turnId) currentTurnId = void 0;
|
|
29976
|
+
const translated = translateTurnLifecycleEvent(event, currentTurnId);
|
|
29977
|
+
currentTurnId = translated.nextTurnId;
|
|
29978
|
+
pipeline.enqueue(translated.draft);
|
|
29685
29979
|
};
|
|
29686
29980
|
const unsubTurn = addTurnLifecycleListener(turnListener);
|
|
29687
29981
|
eventBus.on(soulListener);
|
|
29982
|
+
eventBus.subscribeNotifications(notificationListener);
|
|
29688
29983
|
return { dispose() {
|
|
29689
29984
|
eventBus.off(soulListener);
|
|
29985
|
+
eventBus.unsubscribeNotifications(notificationListener);
|
|
29690
29986
|
unsubTurn();
|
|
29691
29987
|
} };
|
|
29692
29988
|
}
|
|
@@ -30116,6 +30412,48 @@ function errorMessage(error) {
|
|
|
30116
30412
|
return error instanceof Error ? error.message : String(error);
|
|
30117
30413
|
}
|
|
30118
30414
|
//#endregion
|
|
30415
|
+
//#region ../../packages/kimi-core/src/session/state-cache.ts
|
|
30416
|
+
/**
|
|
30417
|
+
* StateCache — state.json derived cache (§9续).
|
|
30418
|
+
*
|
|
30419
|
+
* Reads / writes `state.json` in a session directory. Used by
|
|
30420
|
+
* SessionManager to persist session metadata and runtime state (model,
|
|
30421
|
+
* permission mode, plan mode, last turn index) outside the transcript.
|
|
30422
|
+
*
|
|
30423
|
+
* Writes go through `atomicWrite` (write-tmp-fsync-rename, Decision #104)
|
|
30424
|
+
* so a crash mid-write never leaves a half-truncated state.json that
|
|
30425
|
+
* subsequent reads would treat as "missing". Read-modify-write callers
|
|
30426
|
+
* still need their own concurrency guard for "merge then write" races
|
|
30427
|
+
* across processes — see SessionManager.renameSession.
|
|
30428
|
+
*/
|
|
30429
|
+
var StateCache = class {
|
|
30430
|
+
writeQueue = Promise.resolve();
|
|
30431
|
+
constructor(statePath) {
|
|
30432
|
+
this.statePath = statePath;
|
|
30433
|
+
}
|
|
30434
|
+
async read() {
|
|
30435
|
+
try {
|
|
30436
|
+
const raw = await readFile(this.statePath, "utf-8");
|
|
30437
|
+
if (raw.length === 0) return null;
|
|
30438
|
+
return JSON.parse(raw);
|
|
30439
|
+
} catch {
|
|
30440
|
+
return null;
|
|
30441
|
+
}
|
|
30442
|
+
}
|
|
30443
|
+
async write(state) {
|
|
30444
|
+
await atomicWrite(this.statePath, JSON.stringify(state, null, 2));
|
|
30445
|
+
}
|
|
30446
|
+
async update(mutator) {
|
|
30447
|
+
const nextWrite = this.writeQueue.then(async () => {
|
|
30448
|
+
const next = mutator(await this.read());
|
|
30449
|
+
await this.write(next);
|
|
30450
|
+
return next;
|
|
30451
|
+
});
|
|
30452
|
+
this.writeQueue = nextWrite.then(() => {}, () => {});
|
|
30453
|
+
return nextWrite;
|
|
30454
|
+
}
|
|
30455
|
+
};
|
|
30456
|
+
//#endregion
|
|
30119
30457
|
//#region ../../packages/kimi-core/src/session/session-application-service.ts
|
|
30120
30458
|
function withCompactionConfigFallback(bundle, fallback) {
|
|
30121
30459
|
if (bundle.compactionConfig !== void 0 || fallback === void 0) return bundle;
|
|
@@ -30192,7 +30530,7 @@ var DefaultSessionApplicationService = class {
|
|
|
30192
30530
|
eventBus,
|
|
30193
30531
|
...hookEngine !== void 0 ? { hookEngine } : {}
|
|
30194
30532
|
});
|
|
30195
|
-
const initialModel = this.deps.defaultModelProvider();
|
|
30533
|
+
const initialModel = (await new StateCache(this.deps.pathConfig.statePath(sessionId)).read())?.model ?? this.deps.defaultModelProvider();
|
|
30196
30534
|
const runtimeBundle = await this.deps.runtimeBundleProvider?.({
|
|
30197
30535
|
sessionId,
|
|
30198
30536
|
model: initialModel
|
|
@@ -30268,22 +30606,13 @@ var DefaultSessionApplicationService = class {
|
|
|
30268
30606
|
}
|
|
30269
30607
|
async resumeSnapshot(sessionId) {
|
|
30270
30608
|
const managed = this.getManaged(sessionId);
|
|
30271
|
-
|
|
30272
|
-
|
|
30273
|
-
|
|
30274
|
-
const bodyLines = (await readFile(this.deps.pathConfig.wirePath(sessionId), "utf8")).split("\n").filter((line) => line.length > 0).slice(1);
|
|
30275
|
-
for (const line of bodyLines) try {
|
|
30276
|
-
const rec = JSON.parse(line);
|
|
30277
|
-
if (rec.type === "turn_begin") {
|
|
30278
|
-
turnCount += 1;
|
|
30279
|
-
if (rec.turn_id !== void 0) lastTurnId = rec.turn_id;
|
|
30280
|
-
}
|
|
30281
|
-
} catch {}
|
|
30282
|
-
} catch {}
|
|
30609
|
+
const state = await managed.stateCache.read();
|
|
30610
|
+
const turnCount = state?.turn_count ?? 0;
|
|
30611
|
+
const lastTurnId = state?.last_turn_id;
|
|
30283
30612
|
managed.eventBus.emit({
|
|
30284
30613
|
type: "status.update",
|
|
30285
30614
|
data: {
|
|
30286
|
-
model:
|
|
30615
|
+
model: managed.contextState.model,
|
|
30287
30616
|
plan_mode: managed.soulPlus.getTurnManager().getPlanMode(),
|
|
30288
30617
|
yolo: managed.soulPlus.getTurnManager().getPermissionMode() === "bypassPermissions"
|
|
30289
30618
|
}
|
|
@@ -30349,7 +30678,21 @@ var DefaultSessionApplicationService = class {
|
|
|
30349
30678
|
}
|
|
30350
30679
|
async setYolo(sessionId, enabled) {
|
|
30351
30680
|
const managed = this.getManaged(sessionId);
|
|
30352
|
-
|
|
30681
|
+
const permissionMode = enabled ? "bypassPermissions" : "default";
|
|
30682
|
+
await managed.stateCache.update((current) => {
|
|
30683
|
+
const now = Date.now();
|
|
30684
|
+
return {
|
|
30685
|
+
...current ?? {
|
|
30686
|
+
session_id: sessionId,
|
|
30687
|
+
created_at: now,
|
|
30688
|
+
updated_at: now
|
|
30689
|
+
},
|
|
30690
|
+
permission_mode: permissionMode,
|
|
30691
|
+
updated_at: now,
|
|
30692
|
+
last_exit_code: "dirty"
|
|
30693
|
+
};
|
|
30694
|
+
});
|
|
30695
|
+
managed.soulPlus.getTurnManager().setPermissionMode(permissionMode);
|
|
30353
30696
|
if (this.deps.approvalStateStore !== void 0) await this.deps.approvalStateStore.setYolo(enabled);
|
|
30354
30697
|
managed.soulPlus.getTurnManager().emitStatusUpdate({
|
|
30355
30698
|
input: 0,
|
|
@@ -30384,6 +30727,19 @@ var DefaultSessionApplicationService = class {
|
|
|
30384
30727
|
compactionConfig
|
|
30385
30728
|
});
|
|
30386
30729
|
}
|
|
30730
|
+
await managed.stateCache.update((current) => {
|
|
30731
|
+
const now = Date.now();
|
|
30732
|
+
return {
|
|
30733
|
+
...current ?? {
|
|
30734
|
+
session_id: sessionId,
|
|
30735
|
+
created_at: now,
|
|
30736
|
+
updated_at: now
|
|
30737
|
+
},
|
|
30738
|
+
model,
|
|
30739
|
+
updated_at: now,
|
|
30740
|
+
last_exit_code: "dirty"
|
|
30741
|
+
};
|
|
30742
|
+
});
|
|
30387
30743
|
await managed.soulPlus.setModel(model);
|
|
30388
30744
|
}
|
|
30389
30745
|
async setSystemPrompt(sessionId, prompt) {
|
|
@@ -30393,7 +30749,21 @@ var DefaultSessionApplicationService = class {
|
|
|
30393
30749
|
});
|
|
30394
30750
|
}
|
|
30395
30751
|
async setThinking(sessionId, level) {
|
|
30396
|
-
|
|
30752
|
+
const managed = this.getManaged(sessionId);
|
|
30753
|
+
await managed.stateCache.update((current) => {
|
|
30754
|
+
const now = Date.now();
|
|
30755
|
+
return {
|
|
30756
|
+
...current ?? {
|
|
30757
|
+
session_id: sessionId,
|
|
30758
|
+
created_at: now,
|
|
30759
|
+
updated_at: now
|
|
30760
|
+
},
|
|
30761
|
+
thinking_level: level,
|
|
30762
|
+
updated_at: now,
|
|
30763
|
+
last_exit_code: "dirty"
|
|
30764
|
+
};
|
|
30765
|
+
});
|
|
30766
|
+
await managed.soulPlus.setThinking(level);
|
|
30397
30767
|
}
|
|
30398
30768
|
async addSystemReminder(sessionId, content) {
|
|
30399
30769
|
await this.getManaged(sessionId).soulPlus.addSystemReminder(content);
|
|
@@ -30448,7 +30818,7 @@ var ChangeListenerRegistry = class {
|
|
|
30448
30818
|
}
|
|
30449
30819
|
};
|
|
30450
30820
|
/**
|
|
30451
|
-
* Production adapter that reads / writes `auto_approve_actions` + `
|
|
30821
|
+
* Production adapter that reads / writes `auto_approve_actions` + `permission_mode`
|
|
30452
30822
|
* on the session's `state.json` file via the existing `StateCache`
|
|
30453
30823
|
* service. The rest of the state.json fields are preserved on write —
|
|
30454
30824
|
* we only rewrite the approval-state fields.
|
|
@@ -30476,7 +30846,7 @@ var SessionStateApprovalStateStore = class {
|
|
|
30476
30846
|
const raw = state?.auto_approve_actions;
|
|
30477
30847
|
const actions = raw === void 0 ? /* @__PURE__ */ new Set() : new Set(raw);
|
|
30478
30848
|
this.cachedActions = new Set(actions);
|
|
30479
|
-
this.cachedYolo = state
|
|
30849
|
+
this.cachedYolo = permissionModeFromState(state) === "bypassPermissions";
|
|
30480
30850
|
return actions;
|
|
30481
30851
|
}
|
|
30482
30852
|
async save(actions) {
|
|
@@ -30487,7 +30857,7 @@ var SessionStateApprovalStateStore = class {
|
|
|
30487
30857
|
async getYolo() {
|
|
30488
30858
|
if (this.cachedYolo !== void 0) return this.cachedYolo;
|
|
30489
30859
|
const state = await this.stateCache.read();
|
|
30490
|
-
this.cachedYolo = state
|
|
30860
|
+
this.cachedYolo = permissionModeFromState(state) === "bypassPermissions";
|
|
30491
30861
|
this.cachedActions = new Set(state?.auto_approve_actions ?? []);
|
|
30492
30862
|
return this.cachedYolo;
|
|
30493
30863
|
}
|
|
@@ -30505,7 +30875,7 @@ var SessionStateApprovalStateStore = class {
|
|
|
30505
30875
|
const current = await this.stateCache.read();
|
|
30506
30876
|
const now = this.now();
|
|
30507
30877
|
const nextActions = patch.actions !== void 0 ? [...patch.actions] : current?.auto_approve_actions !== void 0 ? [...current.auto_approve_actions] : void 0;
|
|
30508
|
-
const
|
|
30878
|
+
const nextMode = patch.yolo !== void 0 ? patch.yolo ? "bypassPermissions" : "default" : permissionModeFromState(current);
|
|
30509
30879
|
const next = {
|
|
30510
30880
|
...current ? {
|
|
30511
30881
|
...current,
|
|
@@ -30516,7 +30886,7 @@ var SessionStateApprovalStateStore = class {
|
|
|
30516
30886
|
updated_at: now
|
|
30517
30887
|
},
|
|
30518
30888
|
...nextActions !== void 0 ? { auto_approve_actions: nextActions } : {},
|
|
30519
|
-
|
|
30889
|
+
permission_mode: nextMode
|
|
30520
30890
|
};
|
|
30521
30891
|
await this.stateCache.write(next);
|
|
30522
30892
|
}
|
|
@@ -30527,6 +30897,11 @@ var SessionStateApprovalStateStore = class {
|
|
|
30527
30897
|
});
|
|
30528
30898
|
}
|
|
30529
30899
|
};
|
|
30900
|
+
function permissionModeFromState(state) {
|
|
30901
|
+
const mode = state?.permission_mode;
|
|
30902
|
+
if (mode === "acceptEdits" || mode === "bypassPermissions") return mode;
|
|
30903
|
+
return "default";
|
|
30904
|
+
}
|
|
30530
30905
|
//#endregion
|
|
30531
30906
|
//#region ../../packages/kimi-core/src/wire-protocol/reverse-rpc.ts
|
|
30532
30907
|
/**
|
|
@@ -30686,6 +31061,10 @@ function buildHookRequestData(subscriptionId, input) {
|
|
|
30686
31061
|
base["tool_call_id"] = input.toolCall.id;
|
|
30687
31062
|
base["args"] = input.toolCall.args;
|
|
30688
31063
|
}
|
|
31064
|
+
if (input.event === "PreTurn" || input.event === "UserPromptSubmit") base["prompt"] = input.prompt;
|
|
31065
|
+
if (input.event === "PostTurn" || input.event === "Stop") base["reason"] = input.reason;
|
|
31066
|
+
if (input.event === "PreStep" || input.event === "PostStep") base["step_number"] = input.stepNumber;
|
|
31067
|
+
if (input.event === "PostStep") base["stop_reason"] = input.stopReason;
|
|
30689
31068
|
return base;
|
|
30690
31069
|
}
|
|
30691
31070
|
//#endregion
|
|
@@ -30728,21 +31107,6 @@ function buildHookRequestData(subscriptionId, input) {
|
|
|
30728
31107
|
* - `registerDefaultWireHandlers` returns a handle so the host can
|
|
30729
31108
|
* plug per-session state (event filter for now) into the bridge.
|
|
30730
31109
|
*/
|
|
30731
|
-
const HOOK_SUPPORTED_EVENTS = [
|
|
30732
|
-
"PreToolUse",
|
|
30733
|
-
"PostToolUse",
|
|
30734
|
-
"OnToolFailure",
|
|
30735
|
-
"UserPromptSubmit",
|
|
30736
|
-
"Stop",
|
|
30737
|
-
"StopFailure",
|
|
30738
|
-
"Notification",
|
|
30739
|
-
"SubagentStart",
|
|
30740
|
-
"SubagentStop",
|
|
30741
|
-
"SessionStart",
|
|
30742
|
-
"SessionEnd",
|
|
30743
|
-
"PreCompact",
|
|
30744
|
-
"PostCompact"
|
|
30745
|
-
];
|
|
30746
31110
|
const SUPPORTED_WIRE_EVENTS = [
|
|
30747
31111
|
"turn.begin",
|
|
30748
31112
|
"turn.end",
|
|
@@ -30981,7 +31345,7 @@ function registerDefaultWireHandlers(deps) {
|
|
|
30981
31345
|
events: [...SUPPORTED_WIRE_EVENTS],
|
|
30982
31346
|
methods: [...SUPPORTED_WIRE_METHODS],
|
|
30983
31347
|
hooks: {
|
|
30984
|
-
supported_events:
|
|
31348
|
+
supported_events: SUPPORTED_HOOK_EVENTS,
|
|
30985
31349
|
configured: initialHooks.map((h) => ({
|
|
30986
31350
|
event: h.event,
|
|
30987
31351
|
...typeof h.matcher === "string" && h.matcher.length > 0 ? { matcher: h.matcher } : {}
|
|
@@ -32063,12 +32427,6 @@ async function repairJournal(options) {
|
|
|
32063
32427
|
}
|
|
32064
32428
|
//#endregion
|
|
32065
32429
|
//#region ../../packages/kimi-core/src/session/replay-projector.ts
|
|
32066
|
-
/** Whitelist of valid PermissionMode values for safe runtime validation. */
|
|
32067
|
-
const VALID_PERMISSION_MODES = new Set([
|
|
32068
|
-
"default",
|
|
32069
|
-
"acceptEdits",
|
|
32070
|
-
"bypassPermissions"
|
|
32071
|
-
]);
|
|
32072
32430
|
function isContentPart(value) {
|
|
32073
32431
|
if (typeof value !== "object" || value === null) return false;
|
|
32074
32432
|
const part = value;
|
|
@@ -32084,26 +32442,26 @@ function cloneContentPart(part) {
|
|
|
32084
32442
|
* Project replayed WireRecords into the initial state needed to hydrate a
|
|
32085
32443
|
* resumed `WiredContextState`.
|
|
32086
32444
|
*
|
|
32087
|
-
*
|
|
32088
|
-
*
|
|
32089
|
-
* plan_mode
|
|
32090
|
-
*
|
|
32445
|
+
* `sessionInitialized` is the truth source for wire-owned startup context
|
|
32446
|
+
* (system_prompt / active_tools). Runtime/session config (model,
|
|
32447
|
+
* permission_mode, plan_mode, workspace_dir, thinking_level) comes from
|
|
32448
|
+
* `runtimeBaseline`, which is built from state.json by SessionManager.
|
|
32091
32449
|
*
|
|
32092
32450
|
* @param records — ordered records from `replayWire().records`
|
|
32093
32451
|
* @param sessionInitialized — the line-2 baseline from `replayWire().sessionInitialized`
|
|
32094
32452
|
* @returns Projected state suitable for `WiredContextState` constructor.
|
|
32095
32453
|
*/
|
|
32096
|
-
function projectReplayState(records, sessionInitialized) {
|
|
32454
|
+
function projectReplayState(records, sessionInitialized, runtimeBaseline) {
|
|
32097
32455
|
let messages = [];
|
|
32098
|
-
let model = sessionInitialized.model;
|
|
32456
|
+
let model = runtimeBaseline?.model ?? sessionInitialized.model ?? "";
|
|
32099
32457
|
let systemPrompt = sessionInitialized.system_prompt;
|
|
32100
32458
|
const activeTools = new Set(sessionInitialized.active_tools);
|
|
32101
32459
|
let lastSeq = 0;
|
|
32102
|
-
let permissionMode = sessionInitialized.permission_mode;
|
|
32460
|
+
let permissionMode = runtimeBaseline?.permissionMode ?? sessionInitialized.permission_mode ?? "default";
|
|
32103
32461
|
let tokenCount = 0;
|
|
32104
|
-
let planMode = sessionInitialized.plan_mode;
|
|
32105
|
-
let thinkingLevel = sessionInitialized.thinking_level;
|
|
32106
|
-
const workspaceDir = sessionInitialized.workspace_dir;
|
|
32462
|
+
let planMode = runtimeBaseline?.planMode ?? sessionInitialized.plan_mode ?? false;
|
|
32463
|
+
let thinkingLevel = runtimeBaseline?.thinkingLevel ?? sessionInitialized.thinking_level;
|
|
32464
|
+
const workspaceDir = runtimeBaseline?.workspaceDir ?? sessionInitialized.workspace_dir ?? process.cwd();
|
|
32107
32465
|
const sessionMetaPatch = { turn_count: 0 };
|
|
32108
32466
|
let todos = [];
|
|
32109
32467
|
const pendingTodoWrites = /* @__PURE__ */ new Map();
|
|
@@ -32184,21 +32542,9 @@ function projectReplayState(records, sessionInitialized) {
|
|
|
32184
32542
|
}];
|
|
32185
32543
|
tokenCount = r.post_compact_tokens;
|
|
32186
32544
|
break;
|
|
32187
|
-
case "model_changed":
|
|
32188
|
-
model = r.new_model;
|
|
32189
|
-
sessionMetaPatch.last_model = r.new_model;
|
|
32190
|
-
break;
|
|
32191
32545
|
case "turn_begin":
|
|
32192
32546
|
sessionMetaPatch.turn_count += 1;
|
|
32193
32547
|
break;
|
|
32194
|
-
case "session_meta_changed":
|
|
32195
|
-
if (r.patch.title !== void 0) sessionMetaPatch.title = r.patch.title;
|
|
32196
|
-
if (r.patch.tags !== void 0) sessionMetaPatch.tags = [...r.patch.tags];
|
|
32197
|
-
if (r.patch.description !== void 0) sessionMetaPatch.description = r.patch.description;
|
|
32198
|
-
if (r.patch.archived !== void 0) sessionMetaPatch.archived = r.patch.archived;
|
|
32199
|
-
if (r.patch.color !== void 0) sessionMetaPatch.color = r.patch.color;
|
|
32200
|
-
if (r.patch.plan_slug !== void 0) sessionMetaPatch.plan_slug = r.patch.plan_slug;
|
|
32201
|
-
break;
|
|
32202
32548
|
case "system_prompt_changed":
|
|
32203
32549
|
systemPrompt = r.new_prompt;
|
|
32204
32550
|
break;
|
|
@@ -32209,15 +32555,6 @@ function projectReplayState(records, sessionInitialized) {
|
|
|
32209
32555
|
} else if (r.operation === "register") for (const t of r.tools) activeTools.add(t);
|
|
32210
32556
|
else if (r.operation === "remove") for (const t of r.tools) activeTools.delete(t);
|
|
32211
32557
|
break;
|
|
32212
|
-
case "permission_mode_changed":
|
|
32213
|
-
if (VALID_PERMISSION_MODES.has(r.data.to)) permissionMode = r.data.to;
|
|
32214
|
-
break;
|
|
32215
|
-
case "plan_mode_changed":
|
|
32216
|
-
planMode = r.enabled;
|
|
32217
|
-
break;
|
|
32218
|
-
case "thinking_changed":
|
|
32219
|
-
thinkingLevel = r.level;
|
|
32220
|
-
break;
|
|
32221
32558
|
case "context_cleared":
|
|
32222
32559
|
flushOpenStep();
|
|
32223
32560
|
messages = [];
|
|
@@ -32362,38 +32699,6 @@ var SessionTodoStore = class {
|
|
|
32362
32699
|
}
|
|
32363
32700
|
};
|
|
32364
32701
|
//#endregion
|
|
32365
|
-
//#region ../../packages/kimi-core/src/session/state-cache.ts
|
|
32366
|
-
/**
|
|
32367
|
-
* StateCache — state.json derived cache (§9续).
|
|
32368
|
-
*
|
|
32369
|
-
* Reads / writes `state.json` in a session directory. Used by
|
|
32370
|
-
* SessionManager to persist quick-access session metadata (model,
|
|
32371
|
-
* status, last turn timestamp) without replaying the full wire.jsonl.
|
|
32372
|
-
*
|
|
32373
|
-
* Writes go through `atomicWrite` (write-tmp-fsync-rename, Decision #104)
|
|
32374
|
-
* so a crash mid-write never leaves a half-truncated state.json that
|
|
32375
|
-
* subsequent reads would treat as "missing". Read-modify-write callers
|
|
32376
|
-
* still need their own concurrency guard for "merge then write" races
|
|
32377
|
-
* across processes — see SessionManager.renameSession.
|
|
32378
|
-
*/
|
|
32379
|
-
var StateCache = class {
|
|
32380
|
-
constructor(statePath) {
|
|
32381
|
-
this.statePath = statePath;
|
|
32382
|
-
}
|
|
32383
|
-
async read() {
|
|
32384
|
-
try {
|
|
32385
|
-
const raw = await readFile(this.statePath, "utf-8");
|
|
32386
|
-
if (raw.length === 0) return null;
|
|
32387
|
-
return JSON.parse(raw);
|
|
32388
|
-
} catch {
|
|
32389
|
-
return null;
|
|
32390
|
-
}
|
|
32391
|
-
}
|
|
32392
|
-
async write(state) {
|
|
32393
|
-
await atomicWrite(this.statePath, JSON.stringify(state, null, 2));
|
|
32394
|
-
}
|
|
32395
|
-
};
|
|
32396
|
-
//#endregion
|
|
32397
32702
|
//#region ../../packages/kimi-core/src/session/usage-aggregator.ts
|
|
32398
32703
|
/**
|
|
32399
32704
|
* Token usage aggregator — replays a wire.jsonl and sums usage from
|
|
@@ -32553,6 +32858,17 @@ function normalizeRuntimeSlot(slot, fallback) {
|
|
|
32553
32858
|
});
|
|
32554
32859
|
return runtimeSlot;
|
|
32555
32860
|
}
|
|
32861
|
+
function normalizePermissionMode(value) {
|
|
32862
|
+
if (value === "acceptEdits" || value === "bypassPermissions") return value;
|
|
32863
|
+
return "default";
|
|
32864
|
+
}
|
|
32865
|
+
function createFallbackState(sessionId, now) {
|
|
32866
|
+
return {
|
|
32867
|
+
session_id: sessionId,
|
|
32868
|
+
created_at: now,
|
|
32869
|
+
updated_at: now
|
|
32870
|
+
};
|
|
32871
|
+
}
|
|
32556
32872
|
var SessionManager = class {
|
|
32557
32873
|
paths;
|
|
32558
32874
|
producer;
|
|
@@ -32590,6 +32906,29 @@ var SessionManager = class {
|
|
|
32590
32906
|
this.stateWriteMutex.set(sessionId, next.then(() => {}, () => {}));
|
|
32591
32907
|
return next;
|
|
32592
32908
|
}
|
|
32909
|
+
attachStateTracker(sessionId, stateCache, turnManager) {
|
|
32910
|
+
return turnManager.addTurnLifecycleListener((event) => {
|
|
32911
|
+
const now = Date.now();
|
|
32912
|
+
stateCache.update((current) => {
|
|
32913
|
+
const base = current ?? createFallbackState(sessionId, now);
|
|
32914
|
+
if (event.kind === "begin") return {
|
|
32915
|
+
...base,
|
|
32916
|
+
last_turn_id: event.turnId,
|
|
32917
|
+
last_turn_time: now,
|
|
32918
|
+
updated_at: now,
|
|
32919
|
+
last_exit_code: "dirty"
|
|
32920
|
+
};
|
|
32921
|
+
return {
|
|
32922
|
+
...base,
|
|
32923
|
+
turn_count: (base.turn_count ?? 0) + 1,
|
|
32924
|
+
last_turn_id: event.turnId,
|
|
32925
|
+
last_turn_time: now,
|
|
32926
|
+
updated_at: now,
|
|
32927
|
+
last_exit_code: "dirty"
|
|
32928
|
+
};
|
|
32929
|
+
}).catch(() => {});
|
|
32930
|
+
});
|
|
32931
|
+
}
|
|
32593
32932
|
async createSession(options) {
|
|
32594
32933
|
const sessionId = options.sessionId ?? `ses_${randomUUID().replaceAll("-", "").slice(0, 12)}`;
|
|
32595
32934
|
if (this.sessions.has(sessionId)) throw new Error(`Session already exists: ${sessionId}`);
|
|
@@ -32623,11 +32962,7 @@ var SessionManager = class {
|
|
|
32623
32962
|
agent_type: "main",
|
|
32624
32963
|
session_id: sessionId,
|
|
32625
32964
|
system_prompt: options.systemPrompt ?? "",
|
|
32626
|
-
|
|
32627
|
-
active_tools: sessionTools.map((t) => t.name),
|
|
32628
|
-
permission_mode: options.permissionMode ?? "default",
|
|
32629
|
-
plan_mode: false,
|
|
32630
|
-
workspace_dir: options.workspaceDir
|
|
32965
|
+
active_tools: sessionTools.map((t) => t.name)
|
|
32631
32966
|
};
|
|
32632
32967
|
await journalWriter.append(mainInitInput);
|
|
32633
32968
|
const sessionJournal = new WiredSessionJournalImpl(journalWriter);
|
|
@@ -32643,10 +32978,12 @@ var SessionManager = class {
|
|
|
32643
32978
|
await stateCache.write({
|
|
32644
32979
|
session_id: sessionId,
|
|
32645
32980
|
model: options.model,
|
|
32646
|
-
status: "active",
|
|
32647
32981
|
created_at: now,
|
|
32648
32982
|
updated_at: now,
|
|
32649
32983
|
workspace_dir: options.workspaceDir,
|
|
32984
|
+
permission_mode: options.permissionMode ?? "default",
|
|
32985
|
+
plan_mode: false,
|
|
32986
|
+
turn_count: 0,
|
|
32650
32987
|
last_exit_code: "dirty",
|
|
32651
32988
|
producer: this.producer,
|
|
32652
32989
|
todos: []
|
|
@@ -32703,6 +33040,7 @@ var SessionManager = class {
|
|
|
32703
33040
|
...options.logger !== void 0 ? { logger: options.logger } : {}
|
|
32704
33041
|
});
|
|
32705
33042
|
turnManagerRef = soulPlus.getTurnManager();
|
|
33043
|
+
const disposeStateTracking = this.attachStateTracker(sessionId, stateCache, turnManagerRef);
|
|
32706
33044
|
await soulPlus.init();
|
|
32707
33045
|
if (options.permissionMode !== void 0) turnManagerRef.setPermissionMode(options.permissionMode);
|
|
32708
33046
|
const managed = {
|
|
@@ -32712,7 +33050,20 @@ var SessionManager = class {
|
|
|
32712
33050
|
turnManager: turnManagerRef,
|
|
32713
33051
|
contextState,
|
|
32714
33052
|
sessionJournal,
|
|
32715
|
-
setPlanModeOverride: (enabled) => soulPlus.setPlanMode(enabled)
|
|
33053
|
+
setPlanModeOverride: (enabled) => soulPlus.setPlanMode(enabled),
|
|
33054
|
+
setYoloOverride: async (enabled) => {
|
|
33055
|
+
const permissionMode = enabled ? "bypassPermissions" : "default";
|
|
33056
|
+
await stateCache.update((current) => {
|
|
33057
|
+
const now = Date.now();
|
|
33058
|
+
return {
|
|
33059
|
+
...current ?? createFallbackState(sessionId, now),
|
|
33060
|
+
permission_mode: permissionMode,
|
|
33061
|
+
updated_at: now,
|
|
33062
|
+
last_exit_code: "dirty"
|
|
33063
|
+
};
|
|
33064
|
+
});
|
|
33065
|
+
turnManagerRef.setPermissionMode(permissionMode);
|
|
33066
|
+
}
|
|
32716
33067
|
}),
|
|
32717
33068
|
contextState,
|
|
32718
33069
|
eventBus,
|
|
@@ -32721,6 +33072,7 @@ var SessionManager = class {
|
|
|
32721
33072
|
journalWriter,
|
|
32722
33073
|
runtimeSlot,
|
|
32723
33074
|
lifecycleStateMachine,
|
|
33075
|
+
disposeStateTracking,
|
|
32724
33076
|
todoStore
|
|
32725
33077
|
};
|
|
32726
33078
|
this.sessions.set(sessionId, managed);
|
|
@@ -32743,7 +33095,18 @@ var SessionManager = class {
|
|
|
32743
33095
|
throw new Error(`Failed to replay session ${sessionId}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
32744
33096
|
}
|
|
32745
33097
|
if (replayResult.sessionInitialized.agent_type !== "main") throw new MalformedWireError("agent-type-mismatch", `resumeSession expected agent_type='main' on wire line 2 for "${sessionId}", got agent_type='${replayResult.sessionInitialized.agent_type}'`);
|
|
32746
|
-
const
|
|
33098
|
+
const stateCache = new StateCache(this.paths.statePath(sessionId));
|
|
33099
|
+
const stateData = await stateCache.read();
|
|
33100
|
+
if (stateData === null) throw new Error(`resumeSession: state.json missing or unreadable for session "${sessionId}"`);
|
|
33101
|
+
if (stateData.model === void 0 || stateData.model.length === 0) throw new Error(`resumeSession: state.json missing model for session "${sessionId}"`);
|
|
33102
|
+
const statePermissionMode = normalizePermissionMode(stateData.permission_mode);
|
|
33103
|
+
const projected = projectReplayState(replayResult.records, replayResult.sessionInitialized, {
|
|
33104
|
+
model: stateData.model,
|
|
33105
|
+
permissionMode: statePermissionMode,
|
|
33106
|
+
planMode: stateData.plan_mode ?? false,
|
|
33107
|
+
workspaceDir: stateData.workspace_dir ?? process.cwd(),
|
|
33108
|
+
...stateData.thinking_level !== void 0 ? { thinkingLevel: stateData.thinking_level } : {}
|
|
33109
|
+
});
|
|
32747
33110
|
const lifecycleStateMachine = new SessionLifecycleStateMachine();
|
|
32748
33111
|
const lifecycleGate = new SoulLifecycleGate(lifecycleStateMachine);
|
|
32749
33112
|
let contextStateRef;
|
|
@@ -32778,10 +33141,7 @@ var SessionManager = class {
|
|
|
32778
33141
|
sessionJournal,
|
|
32779
33142
|
currentTurnId: () => turnManagerRef?.getCurrentTurnId() ?? "recovery"
|
|
32780
33143
|
});
|
|
32781
|
-
const
|
|
32782
|
-
const stateData = await stateCache.read();
|
|
32783
|
-
const isClean = stateData?.last_exit_code === "clean";
|
|
32784
|
-
const initialTodos = isClean ? cloneTodos(stateData?.todos ?? projected.todos) : cloneTodos(projected.todos);
|
|
33144
|
+
const initialTodos = stateData.last_exit_code === "clean" ? cloneTodos(stateData.todos ?? projected.todos) : cloneTodos(projected.todos);
|
|
32785
33145
|
const todoStore = new SessionTodoStore(stateCache, initialTodos);
|
|
32786
33146
|
const sessionTools = bindTodoStore(options.tools, todoStore);
|
|
32787
33147
|
const runtimeSlot = normalizeRuntimeSlot(options.runtimeSlot, {
|
|
@@ -32791,32 +33151,25 @@ var SessionManager = class {
|
|
|
32791
33151
|
...options.compactionConfig !== void 0 ? { compactionConfig: options.compactionConfig } : {}
|
|
32792
33152
|
});
|
|
32793
33153
|
const runtimeBundle = runtimeSlot.current();
|
|
32794
|
-
|
|
33154
|
+
await stateCache.write({
|
|
32795
33155
|
...stateData,
|
|
32796
|
-
status: "active",
|
|
32797
33156
|
updated_at: Date.now(),
|
|
32798
33157
|
todos: initialTodos,
|
|
32799
33158
|
last_exit_code: "dirty"
|
|
32800
33159
|
});
|
|
32801
|
-
const replayedMeta = projected.sessionMetaPatch;
|
|
32802
33160
|
const now = Date.now();
|
|
32803
|
-
const pickTitle = isClean ? stateData?.custom_title ?? replayedMeta.title : replayedMeta.title ?? stateData?.custom_title;
|
|
32804
|
-
const pickTags = isClean ? stateData?.tags ?? replayedMeta.tags : replayedMeta.tags ?? stateData?.tags;
|
|
32805
|
-
const pickDescription = isClean ? stateData?.description ?? replayedMeta.description : replayedMeta.description ?? stateData?.description;
|
|
32806
|
-
const pickArchived = isClean ? stateData?.archived ?? replayedMeta.archived : replayedMeta.archived ?? stateData?.archived;
|
|
32807
|
-
const pickLastModel = isClean ? stateData?.model ?? replayedMeta.last_model : replayedMeta.last_model ?? stateData?.model;
|
|
32808
|
-
const pickPlanSlug = isClean ? stateData?.plan_slug ?? replayedMeta.plan_slug : replayedMeta.plan_slug ?? stateData?.plan_slug;
|
|
32809
33161
|
const initialMeta = {
|
|
32810
33162
|
session_id: sessionId,
|
|
32811
|
-
created_at: stateData
|
|
32812
|
-
turn_count:
|
|
32813
|
-
last_updated: stateData
|
|
32814
|
-
...
|
|
32815
|
-
...
|
|
32816
|
-
...
|
|
32817
|
-
...
|
|
32818
|
-
...
|
|
32819
|
-
|
|
33163
|
+
created_at: stateData.created_at ?? now,
|
|
33164
|
+
turn_count: stateData.turn_count ?? 0,
|
|
33165
|
+
last_updated: stateData.updated_at ?? now,
|
|
33166
|
+
...stateData.custom_title !== void 0 ? { title: stateData.custom_title } : {},
|
|
33167
|
+
...stateData.tags !== void 0 ? { tags: [...stateData.tags] } : {},
|
|
33168
|
+
...stateData.description !== void 0 ? { description: stateData.description } : {},
|
|
33169
|
+
...stateData.archived !== void 0 ? { archived: stateData.archived } : {},
|
|
33170
|
+
...stateData.color !== void 0 ? { color: stateData.color } : {},
|
|
33171
|
+
last_model: stateData.model,
|
|
33172
|
+
...stateData.plan_slug !== void 0 ? { plan_slug: stateData.plan_slug } : {},
|
|
32820
33173
|
producer: replayResult.producer,
|
|
32821
33174
|
last_exit_code: "dirty"
|
|
32822
33175
|
};
|
|
@@ -32865,11 +33218,12 @@ var SessionManager = class {
|
|
|
32865
33218
|
subagentStore,
|
|
32866
33219
|
agentTypeRegistry: options.agentTypeRegistry,
|
|
32867
33220
|
sessionDir,
|
|
32868
|
-
workDir: stateData
|
|
33221
|
+
workDir: stateData.workspace_dir ?? process.cwd()
|
|
32869
33222
|
} : {},
|
|
32870
33223
|
...options.logger !== void 0 ? { logger: options.logger } : {}
|
|
32871
33224
|
});
|
|
32872
33225
|
turnManagerRef = soulPlus.getTurnManager();
|
|
33226
|
+
const disposeStateTracking = this.attachStateTracker(sessionId, stateCache, turnManagerRef);
|
|
32873
33227
|
await soulPlus.init();
|
|
32874
33228
|
turnManagerRef.setPermissionMode(effectivePermissionMode);
|
|
32875
33229
|
if (projected.thinkingLevel !== void 0) turnManagerRef.setThinkingLevel(projected.thinkingLevel);
|
|
@@ -32896,7 +33250,20 @@ var SessionManager = class {
|
|
|
32896
33250
|
turnManager: turnManagerRef,
|
|
32897
33251
|
contextState,
|
|
32898
33252
|
sessionJournal,
|
|
32899
|
-
setPlanModeOverride: (enabled) => soulPlus.setPlanMode(enabled)
|
|
33253
|
+
setPlanModeOverride: (enabled) => soulPlus.setPlanMode(enabled),
|
|
33254
|
+
setYoloOverride: async (enabled) => {
|
|
33255
|
+
const permissionMode = enabled ? "bypassPermissions" : "default";
|
|
33256
|
+
await stateCache.update((current) => {
|
|
33257
|
+
const now = Date.now();
|
|
33258
|
+
return {
|
|
33259
|
+
...current ?? createFallbackState(sessionId, now),
|
|
33260
|
+
permission_mode: permissionMode,
|
|
33261
|
+
updated_at: now,
|
|
33262
|
+
last_exit_code: "dirty"
|
|
33263
|
+
};
|
|
33264
|
+
});
|
|
33265
|
+
turnManagerRef.setPermissionMode(permissionMode);
|
|
33266
|
+
}
|
|
32900
33267
|
}),
|
|
32901
33268
|
contextState,
|
|
32902
33269
|
eventBus,
|
|
@@ -32905,6 +33272,7 @@ var SessionManager = class {
|
|
|
32905
33272
|
journalWriter,
|
|
32906
33273
|
runtimeSlot,
|
|
32907
33274
|
lifecycleStateMachine,
|
|
33275
|
+
disposeStateTracking,
|
|
32908
33276
|
todoStore
|
|
32909
33277
|
};
|
|
32910
33278
|
this.sessions.set(sessionId, managed);
|
|
@@ -32926,7 +33294,6 @@ var SessionManager = class {
|
|
|
32926
33294
|
session_id: state.session_id,
|
|
32927
33295
|
created_at: state.created_at,
|
|
32928
33296
|
...state.model !== void 0 ? { model: state.model } : {},
|
|
32929
|
-
...state.status !== void 0 ? { status: state.status } : {},
|
|
32930
33297
|
...state.workspace_dir !== void 0 ? { workspace_dir: state.workspace_dir } : {},
|
|
32931
33298
|
...state.custom_title !== void 0 ? { title: state.custom_title } : {},
|
|
32932
33299
|
...lastActivity !== void 0 ? { last_activity: lastActivity } : {},
|
|
@@ -32970,7 +33337,8 @@ var SessionManager = class {
|
|
|
32970
33337
|
await cache.write({
|
|
32971
33338
|
...existing,
|
|
32972
33339
|
custom_title: trimmed,
|
|
32973
|
-
updated_at: Date.now()
|
|
33340
|
+
updated_at: Date.now(),
|
|
33341
|
+
last_exit_code: "dirty"
|
|
32974
33342
|
});
|
|
32975
33343
|
this.usageAggregator.invalidate(this.paths.wirePath(sessionId));
|
|
32976
33344
|
});
|
|
@@ -32995,7 +33363,8 @@ var SessionManager = class {
|
|
|
32995
33363
|
await cache.write({
|
|
32996
33364
|
...existing,
|
|
32997
33365
|
tags: next,
|
|
32998
|
-
updated_at: Date.now()
|
|
33366
|
+
updated_at: Date.now(),
|
|
33367
|
+
last_exit_code: "dirty"
|
|
32999
33368
|
});
|
|
33000
33369
|
this.usageAggregator.invalidate(this.paths.wirePath(sessionId));
|
|
33001
33370
|
});
|
|
@@ -33079,7 +33448,29 @@ var SessionManager = class {
|
|
|
33079
33448
|
keepUpToLine = turnBeginIndices[totalTurns - nTurnsBack];
|
|
33080
33449
|
newTurnCount = totalTurns - nTurnsBack;
|
|
33081
33450
|
}
|
|
33082
|
-
|
|
33451
|
+
const kept = lines.slice(0, keepUpToLine);
|
|
33452
|
+
await atomicWrite(wirePath, `${kept.join("\n")}\n`);
|
|
33453
|
+
let lastTurnId;
|
|
33454
|
+
let lastTurnTime;
|
|
33455
|
+
for (let i = kept.length - 1; i >= 0; i--) try {
|
|
33456
|
+
const rec = JSON.parse(kept[i] ?? "");
|
|
33457
|
+
if (rec.type === "turn_begin" && rec.turn_id !== void 0) {
|
|
33458
|
+
lastTurnId = rec.turn_id;
|
|
33459
|
+
if (typeof rec.time === "number") lastTurnTime = rec.time;
|
|
33460
|
+
break;
|
|
33461
|
+
}
|
|
33462
|
+
} catch {}
|
|
33463
|
+
await new StateCache(this.paths.statePath(sessionId)).update((current) => {
|
|
33464
|
+
const now = Date.now();
|
|
33465
|
+
return {
|
|
33466
|
+
...current ?? createFallbackState(sessionId, now),
|
|
33467
|
+
turn_count: newTurnCount,
|
|
33468
|
+
last_turn_id: lastTurnId,
|
|
33469
|
+
last_turn_time: lastTurnTime,
|
|
33470
|
+
updated_at: now,
|
|
33471
|
+
last_exit_code: "dirty"
|
|
33472
|
+
};
|
|
33473
|
+
});
|
|
33083
33474
|
this.usageAggregator.invalidate(wirePath);
|
|
33084
33475
|
return { new_turn_count: newTurnCount };
|
|
33085
33476
|
}
|
|
@@ -33091,18 +33482,8 @@ var SessionManager = class {
|
|
|
33091
33482
|
async getSessionStatus(sessionId) {
|
|
33092
33483
|
const live = this.sessions.get(sessionId);
|
|
33093
33484
|
if (live !== void 0) return live.lifecycleStateMachine.state;
|
|
33094
|
-
|
|
33095
|
-
|
|
33096
|
-
const validStatuses = new Set([
|
|
33097
|
-
"idle",
|
|
33098
|
-
"active",
|
|
33099
|
-
"completing",
|
|
33100
|
-
"compacting",
|
|
33101
|
-
"destroying",
|
|
33102
|
-
"closed"
|
|
33103
|
-
]);
|
|
33104
|
-
if (state.status !== void 0 && validStatuses.has(state.status)) return state.status;
|
|
33105
|
-
return "idle";
|
|
33485
|
+
if (await new StateCache(this.paths.statePath(sessionId)).read() === null) throw new Error(`getSessionStatus: session "${sessionId}" not found`);
|
|
33486
|
+
return "closed";
|
|
33106
33487
|
}
|
|
33107
33488
|
/**
|
|
33108
33489
|
* Return aggregated token usage for a session.
|
|
@@ -33141,33 +33522,43 @@ var SessionManager = class {
|
|
|
33141
33522
|
await managed.todoStore?.flushPending();
|
|
33142
33523
|
const existing = await managed.stateCache.read();
|
|
33143
33524
|
const now = Date.now();
|
|
33144
|
-
const
|
|
33525
|
+
const turnManager = managed.soulPlus.getTurnManager();
|
|
33526
|
+
const currentPlanMode = turnManager.getPlanMode();
|
|
33527
|
+
const currentPermissionMode = turnManager.getPermissionMode();
|
|
33528
|
+
const currentThinkingLevel = turnManager.getThinkingLevel();
|
|
33145
33529
|
const currentTodos = managed.todoStore?.getTodos() ?? [];
|
|
33146
33530
|
const meta = sessionMetaService?.get();
|
|
33147
33531
|
const stateToFlush = existing ? {
|
|
33148
33532
|
...existing,
|
|
33149
|
-
status: "closed",
|
|
33150
33533
|
updated_at: now,
|
|
33534
|
+
model: managed.contextState.model,
|
|
33535
|
+
permission_mode: currentPermissionMode,
|
|
33151
33536
|
...meta?.title !== void 0 ? { custom_title: meta.title } : {},
|
|
33152
33537
|
...meta?.tags !== void 0 ? { tags: [...meta.tags] } : {},
|
|
33153
33538
|
...meta?.description !== void 0 ? { description: meta.description } : {},
|
|
33154
33539
|
...meta?.archived !== void 0 ? { archived: meta.archived } : {},
|
|
33155
|
-
...meta?.
|
|
33540
|
+
...meta?.color !== void 0 ? { color: meta.color } : {},
|
|
33541
|
+
turn_count: meta?.turn_count ?? existing.turn_count ?? 0,
|
|
33156
33542
|
...meta?.plan_slug !== void 0 ? { plan_slug: meta.plan_slug } : {},
|
|
33543
|
+
...currentThinkingLevel !== void 0 ? { thinking_level: currentThinkingLevel } : {},
|
|
33157
33544
|
...currentPlanMode ? { plan_mode: true } : { plan_mode: false },
|
|
33158
33545
|
todos: cloneTodos(currentTodos),
|
|
33159
33546
|
last_exit_code: "clean"
|
|
33160
33547
|
} : {
|
|
33161
33548
|
session_id: sessionId,
|
|
33162
|
-
status: "closed",
|
|
33163
33549
|
created_at: now,
|
|
33164
33550
|
updated_at: now,
|
|
33551
|
+
model: managed.contextState.model,
|
|
33552
|
+
permission_mode: currentPermissionMode,
|
|
33165
33553
|
plan_mode: currentPlanMode,
|
|
33554
|
+
turn_count: meta?.turn_count ?? 0,
|
|
33555
|
+
...currentThinkingLevel !== void 0 ? { thinking_level: currentThinkingLevel } : {},
|
|
33166
33556
|
todos: cloneTodos(currentTodos),
|
|
33167
33557
|
last_exit_code: "clean"
|
|
33168
33558
|
};
|
|
33169
33559
|
await managed.stateCache.write(stateToFlush);
|
|
33170
33560
|
sessionMetaService?.dispose();
|
|
33561
|
+
managed.disposeStateTracking?.();
|
|
33171
33562
|
await managed.journalWriter.close();
|
|
33172
33563
|
this.sessions.delete(sessionId);
|
|
33173
33564
|
});
|
|
@@ -38852,7 +39243,7 @@ var require_node_loaders = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
38852
39243
|
};
|
|
38853
39244
|
return _setPrototypeOf(o, p);
|
|
38854
39245
|
}
|
|
38855
|
-
var fs$
|
|
39246
|
+
var fs$10 = __require("fs");
|
|
38856
39247
|
var path$10 = __require("path");
|
|
38857
39248
|
var Loader = require_loader();
|
|
38858
39249
|
var PrecompiledLoader = require_precompiled_loader().PrecompiledLoader;
|
|
@@ -38876,7 +39267,7 @@ var require_node_loaders = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
38876
39267
|
} catch (e) {
|
|
38877
39268
|
throw new Error("watch requires chokidar to be installed");
|
|
38878
39269
|
}
|
|
38879
|
-
var paths = _this.searchPaths.filter(fs$
|
|
39270
|
+
var paths = _this.searchPaths.filter(fs$10.existsSync);
|
|
38880
39271
|
var watcher = chokidar.watch(paths);
|
|
38881
39272
|
watcher.on("all", function(event, fullname) {
|
|
38882
39273
|
fullname = path$10.resolve(fullname);
|
|
@@ -38895,7 +39286,7 @@ var require_node_loaders = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
38895
39286
|
for (var i = 0; i < paths.length; i++) {
|
|
38896
39287
|
var basePath = path$10.resolve(paths[i]);
|
|
38897
39288
|
var p = path$10.resolve(paths[i], name);
|
|
38898
|
-
if (p.indexOf(basePath) === 0 && fs$
|
|
39289
|
+
if (p.indexOf(basePath) === 0 && fs$10.existsSync(p)) {
|
|
38899
39290
|
fullpath = p;
|
|
38900
39291
|
break;
|
|
38901
39292
|
}
|
|
@@ -38903,7 +39294,7 @@ var require_node_loaders = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
38903
39294
|
if (!fullpath) return null;
|
|
38904
39295
|
this.pathsToNames[fullpath] = name;
|
|
38905
39296
|
var source = {
|
|
38906
|
-
src: fs$
|
|
39297
|
+
src: fs$10.readFileSync(fullpath, "utf-8"),
|
|
38907
39298
|
path: fullpath,
|
|
38908
39299
|
noCache: this.noCache
|
|
38909
39300
|
};
|
|
@@ -38951,7 +39342,7 @@ var require_node_loaders = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
38951
39342
|
}
|
|
38952
39343
|
this.pathsToNames[fullpath] = name;
|
|
38953
39344
|
var source = {
|
|
38954
|
-
src: fs$
|
|
39345
|
+
src: fs$10.readFileSync(fullpath, "utf-8"),
|
|
38955
39346
|
path: fullpath,
|
|
38956
39347
|
noCache: this.noCache
|
|
38957
39348
|
};
|
|
@@ -39695,7 +40086,7 @@ var require_precompile_global = /* @__PURE__ */ __commonJSMin(((exports, module)
|
|
|
39695
40086
|
//#endregion
|
|
39696
40087
|
//#region ../../node_modules/.pnpm/nunjucks@3.2.4/node_modules/nunjucks/src/precompile.js
|
|
39697
40088
|
var require_precompile = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
39698
|
-
var fs$
|
|
40089
|
+
var fs$9 = __require("fs");
|
|
39699
40090
|
var path$8 = __require("path");
|
|
39700
40091
|
var _prettifyError = require_lib$1()._prettifyError;
|
|
39701
40092
|
var compiler = require_compiler();
|
|
@@ -39720,27 +40111,27 @@ var require_precompile = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
39720
40111
|
var env = opts.env || new Environment([]);
|
|
39721
40112
|
var wrapper = opts.wrapper || precompileGlobal;
|
|
39722
40113
|
if (opts.isString) return precompileString(input, opts);
|
|
39723
|
-
var pathStats = fs$
|
|
40114
|
+
var pathStats = fs$9.existsSync(input) && fs$9.statSync(input);
|
|
39724
40115
|
var precompiled = [];
|
|
39725
40116
|
var templates = [];
|
|
39726
40117
|
function addTemplates(dir) {
|
|
39727
|
-
fs$
|
|
40118
|
+
fs$9.readdirSync(dir).forEach(function(file) {
|
|
39728
40119
|
var filepath = path$8.join(dir, file);
|
|
39729
40120
|
var subpath = filepath.substr(path$8.join(input, "/").length);
|
|
39730
|
-
var stat = fs$
|
|
40121
|
+
var stat = fs$9.statSync(filepath);
|
|
39731
40122
|
if (stat && stat.isDirectory()) {
|
|
39732
40123
|
subpath += "/";
|
|
39733
40124
|
if (!match(subpath, opts.exclude)) addTemplates(filepath);
|
|
39734
40125
|
} else if (match(subpath, opts.include)) templates.push(filepath);
|
|
39735
40126
|
});
|
|
39736
40127
|
}
|
|
39737
|
-
if (pathStats.isFile()) precompiled.push(_precompile(fs$
|
|
40128
|
+
if (pathStats.isFile()) precompiled.push(_precompile(fs$9.readFileSync(input, "utf-8"), opts.name || input, env));
|
|
39738
40129
|
else if (pathStats.isDirectory()) {
|
|
39739
40130
|
addTemplates(input);
|
|
39740
40131
|
for (var i = 0; i < templates.length; i++) {
|
|
39741
40132
|
var name = templates[i].replace(path$8.join(input, "/"), "");
|
|
39742
40133
|
try {
|
|
39743
|
-
precompiled.push(_precompile(fs$
|
|
40134
|
+
precompiled.push(_precompile(fs$9.readFileSync(templates[i], "utf-8"), name, env));
|
|
39744
40135
|
} catch (e) {
|
|
39745
40136
|
if (opts.force) console.error(e);
|
|
39746
40137
|
else throw e;
|
|
@@ -51014,7 +51405,7 @@ var require_util = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
51014
51405
|
exports.removeUndefinedValuesInObject = removeUndefinedValuesInObject;
|
|
51015
51406
|
exports.isValidFile = isValidFile;
|
|
51016
51407
|
exports.getWellKnownCertificateConfigFileLocation = getWellKnownCertificateConfigFileLocation;
|
|
51017
|
-
const fs$
|
|
51408
|
+
const fs$8 = __require("fs");
|
|
51018
51409
|
const os$1 = __require("os");
|
|
51019
51410
|
const path$6 = __require("path");
|
|
51020
51411
|
const WELL_KNOWN_CERTIFICATE_CONFIG_FILE = "certificate_config.json";
|
|
@@ -51134,7 +51525,7 @@ var require_util = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
51134
51525
|
*/
|
|
51135
51526
|
async function isValidFile(filePath) {
|
|
51136
51527
|
try {
|
|
51137
|
-
return (await fs$
|
|
51528
|
+
return (await fs$8.promises.lstat(filePath)).isFile();
|
|
51138
51529
|
} catch (e) {
|
|
51139
51530
|
return false;
|
|
51140
51531
|
}
|
|
@@ -52847,10 +53238,10 @@ var require_getCredentials = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
52847
53238
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
52848
53239
|
exports.getCredentials = getCredentials;
|
|
52849
53240
|
const path$5 = __require("path");
|
|
52850
|
-
const fs$
|
|
53241
|
+
const fs$7 = __require("fs");
|
|
52851
53242
|
const util_1$1 = __require("util");
|
|
52852
53243
|
const errorWithCode_1 = require_errorWithCode();
|
|
52853
|
-
const readFile = fs$
|
|
53244
|
+
const readFile = fs$7.readFile ? (0, util_1$1.promisify)(fs$7.readFile) : async () => {
|
|
52854
53245
|
throw new errorWithCode_1.ErrorWithCode("use key rather than keyFile.", "MISSING_CREDENTIALS");
|
|
52855
53246
|
};
|
|
52856
53247
|
var ExtensionFiles;
|
|
@@ -54397,10 +54788,10 @@ var require_filesubjecttokensupplier = /* @__PURE__ */ __commonJSMin(((exports)
|
|
|
54397
54788
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
54398
54789
|
exports.FileSubjectTokenSupplier = void 0;
|
|
54399
54790
|
const util_1 = __require("util");
|
|
54400
|
-
const fs$
|
|
54401
|
-
const readFile = (0, util_1.promisify)(fs$
|
|
54402
|
-
const realpath = (0, util_1.promisify)(fs$
|
|
54403
|
-
const lstat = (0, util_1.promisify)(fs$
|
|
54791
|
+
const fs$6 = __require("fs");
|
|
54792
|
+
const readFile = (0, util_1.promisify)(fs$6.readFile ?? (() => {}));
|
|
54793
|
+
const realpath = (0, util_1.promisify)(fs$6.realpath ?? (() => {}));
|
|
54794
|
+
const lstat = (0, util_1.promisify)(fs$6.lstat ?? (() => {}));
|
|
54404
54795
|
/**
|
|
54405
54796
|
* Internal subject token supplier implementation used when a file location
|
|
54406
54797
|
* is configured in the credential configuration used to build an {@link IdentityPoolClient}
|
|
@@ -54502,7 +54893,7 @@ var require_certificatesubjecttokensupplier = /* @__PURE__ */ __commonJSMin(((ex
|
|
|
54502
54893
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
54503
54894
|
exports.CertificateSubjectTokenSupplier = exports.InvalidConfigurationError = exports.CertificateSourceUnavailableError = exports.CERTIFICATE_CONFIGURATION_ENV_VARIABLE = void 0;
|
|
54504
54895
|
const util_1 = require_util();
|
|
54505
|
-
const fs$
|
|
54896
|
+
const fs$5 = __require("fs");
|
|
54506
54897
|
const crypto_1 = __require("crypto");
|
|
54507
54898
|
const https$1 = __require("https");
|
|
54508
54899
|
exports.CERTIFICATE_CONFIGURATION_ENV_VARIABLE = "GOOGLE_API_CERTIFICATE_CONFIG";
|
|
@@ -54597,7 +54988,7 @@ var require_certificatesubjecttokensupplier = /* @__PURE__ */ __commonJSMin(((ex
|
|
|
54597
54988
|
const configPath = this.certificateConfigPath;
|
|
54598
54989
|
let fileContents;
|
|
54599
54990
|
try {
|
|
54600
|
-
fileContents = await fs$
|
|
54991
|
+
fileContents = await fs$5.promises.readFile(configPath, "utf8");
|
|
54601
54992
|
} catch (err) {
|
|
54602
54993
|
throw new CertificateSourceUnavailableError(`Failed to read certificate config file at: ${configPath}`);
|
|
54603
54994
|
}
|
|
@@ -54622,13 +55013,13 @@ var require_certificatesubjecttokensupplier = /* @__PURE__ */ __commonJSMin(((ex
|
|
|
54622
55013
|
async #getKeyAndCert(certPath, keyPath) {
|
|
54623
55014
|
let cert, key;
|
|
54624
55015
|
try {
|
|
54625
|
-
cert = await fs$
|
|
55016
|
+
cert = await fs$5.promises.readFile(certPath);
|
|
54626
55017
|
new crypto_1.X509Certificate(cert);
|
|
54627
55018
|
} catch (err) {
|
|
54628
55019
|
throw new CertificateSourceUnavailableError(`Failed to read certificate file at ${certPath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
54629
55020
|
}
|
|
54630
55021
|
try {
|
|
54631
|
-
key = await fs$
|
|
55022
|
+
key = await fs$5.promises.readFile(keyPath);
|
|
54632
55023
|
(0, crypto_1.createPrivateKey)(key);
|
|
54633
55024
|
} catch (err) {
|
|
54634
55025
|
throw new CertificateSourceUnavailableError(`Failed to read private key file at ${keyPath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -54647,7 +55038,7 @@ var require_certificatesubjecttokensupplier = /* @__PURE__ */ __commonJSMin(((ex
|
|
|
54647
55038
|
const leafCert = new crypto_1.X509Certificate(leafCertBuffer);
|
|
54648
55039
|
if (!this.trustChainPath) return JSON.stringify([leafCert.raw.toString("base64")]);
|
|
54649
55040
|
try {
|
|
54650
|
-
const chainCerts = ((await fs$
|
|
55041
|
+
const chainCerts = ((await fs$5.promises.readFile(this.trustChainPath, "utf8")).match(/-----BEGIN CERTIFICATE-----[^-]+-----END CERTIFICATE-----/g) ?? []).map((pem, index) => {
|
|
54651
55042
|
try {
|
|
54652
55043
|
return new crypto_1.X509Certificate(pem);
|
|
54653
55044
|
} catch (err) {
|
|
@@ -55307,7 +55698,7 @@ var require_pluggable_auth_handler = /* @__PURE__ */ __commonJSMin(((exports) =>
|
|
|
55307
55698
|
exports.PluggableAuthHandler = exports.ExecutableError = void 0;
|
|
55308
55699
|
const executable_response_1 = require_executable_response();
|
|
55309
55700
|
const childProcess = __require("child_process");
|
|
55310
|
-
const fs$
|
|
55701
|
+
const fs$4 = __require("fs");
|
|
55311
55702
|
/**
|
|
55312
55703
|
* Error thrown from the executable run by PluggableAuthClient.
|
|
55313
55704
|
*/
|
|
@@ -55384,12 +55775,12 @@ var require_pluggable_auth_handler = /* @__PURE__ */ __commonJSMin(((exports) =>
|
|
|
55384
55775
|
if (!this.outputFile || this.outputFile.length === 0) return;
|
|
55385
55776
|
let filePath;
|
|
55386
55777
|
try {
|
|
55387
|
-
filePath = await fs$
|
|
55778
|
+
filePath = await fs$4.promises.realpath(this.outputFile);
|
|
55388
55779
|
} catch {
|
|
55389
55780
|
return;
|
|
55390
55781
|
}
|
|
55391
|
-
if (!(await fs$
|
|
55392
|
-
const responseString = await fs$
|
|
55782
|
+
if (!(await fs$4.promises.lstat(filePath)).isFile()) return;
|
|
55783
|
+
const responseString = await fs$4.promises.readFile(filePath, { encoding: "utf8" });
|
|
55393
55784
|
if (responseString === "") return;
|
|
55394
55785
|
try {
|
|
55395
55786
|
const responseJson = JSON.parse(responseString);
|
|
@@ -55811,7 +56202,7 @@ var require_googleauth = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
55811
56202
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
55812
56203
|
exports.GoogleAuth = exports.GoogleAuthExceptionMessages = void 0;
|
|
55813
56204
|
const child_process_1 = __require("child_process");
|
|
55814
|
-
const fs$
|
|
56205
|
+
const fs$3 = __require("fs");
|
|
55815
56206
|
const gaxios_1 = require_src$3();
|
|
55816
56207
|
const gcpMetadata = require_src$1();
|
|
55817
56208
|
const os = __require("os");
|
|
@@ -56059,7 +56450,7 @@ var require_googleauth = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
56059
56450
|
}
|
|
56060
56451
|
if (location) {
|
|
56061
56452
|
location = path$4.join(location, "gcloud", "application_default_credentials.json");
|
|
56062
|
-
if (!fs$
|
|
56453
|
+
if (!fs$3.existsSync(location)) location = null;
|
|
56063
56454
|
}
|
|
56064
56455
|
if (!location) return null;
|
|
56065
56456
|
return await this._getApplicationCredentialsFromFilePath(location, options);
|
|
@@ -56073,13 +56464,13 @@ var require_googleauth = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
56073
56464
|
async _getApplicationCredentialsFromFilePath(filePath, options = {}) {
|
|
56074
56465
|
if (!filePath || filePath.length === 0) throw new Error("The file path is invalid.");
|
|
56075
56466
|
try {
|
|
56076
|
-
filePath = fs$
|
|
56077
|
-
if (!fs$
|
|
56467
|
+
filePath = fs$3.realpathSync(filePath);
|
|
56468
|
+
if (!fs$3.lstatSync(filePath).isFile()) throw new Error();
|
|
56078
56469
|
} catch (err) {
|
|
56079
56470
|
if (err instanceof Error) err.message = `The file at ${filePath} does not exist, or it is not a file. ${err.message}`;
|
|
56080
56471
|
throw err;
|
|
56081
56472
|
}
|
|
56082
|
-
const readStream = fs$
|
|
56473
|
+
const readStream = fs$3.createReadStream(filePath);
|
|
56083
56474
|
return this.fromStream(readStream, options);
|
|
56084
56475
|
}
|
|
56085
56476
|
/**
|
|
@@ -56346,7 +56737,7 @@ var require_googleauth = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
56346
56737
|
if (this.jsonContent) return this._cacheClientFromJSON(this.jsonContent, this.clientOptions);
|
|
56347
56738
|
else if (this.keyFilename) {
|
|
56348
56739
|
const filePath = path$4.resolve(this.keyFilename);
|
|
56349
|
-
const stream = fs$
|
|
56740
|
+
const stream = fs$3.createReadStream(filePath);
|
|
56350
56741
|
return await this.fromStreamAsync(stream, this.clientOptions);
|
|
56351
56742
|
} else if (this.apiKey) {
|
|
56352
56743
|
const client = await this.fromAPIKey(this.apiKey, this.clientOptions);
|
|
@@ -74856,7 +75247,7 @@ var NodeUploader = class {
|
|
|
74856
75247
|
type: void 0
|
|
74857
75248
|
};
|
|
74858
75249
|
if (typeof file === "string") {
|
|
74859
|
-
fileStat.size = (await fs$
|
|
75250
|
+
fileStat.size = (await fs$2.stat(file)).size;
|
|
74860
75251
|
fileStat.type = this.inferMimeType(file);
|
|
74861
75252
|
return fileStat;
|
|
74862
75253
|
} else return await getBlobStat(file);
|
|
@@ -74989,7 +75380,7 @@ var NodeUploader = class {
|
|
|
74989
75380
|
let fileHandle;
|
|
74990
75381
|
const fileName = path$1$1.basename(file);
|
|
74991
75382
|
try {
|
|
74992
|
-
fileHandle = await fs$
|
|
75383
|
+
fileHandle = await fs$2.open(file, "r");
|
|
74993
75384
|
if (!fileHandle) throw new Error(`Failed to open file`);
|
|
74994
75385
|
fileSize = (await fileHandle.stat()).size;
|
|
74995
75386
|
while (offset < fileSize) {
|
|
@@ -91423,7 +91814,7 @@ var require_clone = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
91423
91814
|
//#endregion
|
|
91424
91815
|
//#region ../../node_modules/.pnpm/graceful-fs@4.2.11/node_modules/graceful-fs/graceful-fs.js
|
|
91425
91816
|
var require_graceful_fs = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
91426
|
-
var fs = __require("fs");
|
|
91817
|
+
var fs$1 = __require("fs");
|
|
91427
91818
|
var polyfills = require_polyfills();
|
|
91428
91819
|
var legacy = require_legacy_streams();
|
|
91429
91820
|
var clone = require_clone();
|
|
@@ -91452,36 +91843,36 @@ var require_graceful_fs = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
91452
91843
|
m = "GFS4: " + m.split(/\n/).join("\nGFS4: ");
|
|
91453
91844
|
console.error(m);
|
|
91454
91845
|
};
|
|
91455
|
-
if (!fs[gracefulQueue]) {
|
|
91456
|
-
publishQueue(fs, global[gracefulQueue] || []);
|
|
91457
|
-
fs.close = (function(fs$close) {
|
|
91846
|
+
if (!fs$1[gracefulQueue]) {
|
|
91847
|
+
publishQueue(fs$1, global[gracefulQueue] || []);
|
|
91848
|
+
fs$1.close = (function(fs$close) {
|
|
91458
91849
|
function close(fd, cb) {
|
|
91459
|
-
return fs$close.call(fs, fd, function(err) {
|
|
91850
|
+
return fs$close.call(fs$1, fd, function(err) {
|
|
91460
91851
|
if (!err) resetQueue();
|
|
91461
91852
|
if (typeof cb === "function") cb.apply(this, arguments);
|
|
91462
91853
|
});
|
|
91463
91854
|
}
|
|
91464
91855
|
Object.defineProperty(close, previousSymbol, { value: fs$close });
|
|
91465
91856
|
return close;
|
|
91466
|
-
})(fs.close);
|
|
91467
|
-
fs.closeSync = (function(fs$closeSync) {
|
|
91857
|
+
})(fs$1.close);
|
|
91858
|
+
fs$1.closeSync = (function(fs$closeSync) {
|
|
91468
91859
|
function closeSync(fd) {
|
|
91469
|
-
fs$closeSync.apply(fs, arguments);
|
|
91860
|
+
fs$closeSync.apply(fs$1, arguments);
|
|
91470
91861
|
resetQueue();
|
|
91471
91862
|
}
|
|
91472
91863
|
Object.defineProperty(closeSync, previousSymbol, { value: fs$closeSync });
|
|
91473
91864
|
return closeSync;
|
|
91474
|
-
})(fs.closeSync);
|
|
91865
|
+
})(fs$1.closeSync);
|
|
91475
91866
|
if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || "")) process.on("exit", function() {
|
|
91476
|
-
debug(fs[gracefulQueue]);
|
|
91477
|
-
__require("assert").equal(fs[gracefulQueue].length, 0);
|
|
91867
|
+
debug(fs$1[gracefulQueue]);
|
|
91868
|
+
__require("assert").equal(fs$1[gracefulQueue].length, 0);
|
|
91478
91869
|
});
|
|
91479
91870
|
}
|
|
91480
|
-
if (!global[gracefulQueue]) publishQueue(global, fs[gracefulQueue]);
|
|
91481
|
-
module.exports = patch(clone(fs));
|
|
91482
|
-
if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs.__patched) {
|
|
91483
|
-
module.exports = patch(fs);
|
|
91484
|
-
fs.__patched = true;
|
|
91871
|
+
if (!global[gracefulQueue]) publishQueue(global, fs$1[gracefulQueue]);
|
|
91872
|
+
module.exports = patch(clone(fs$1));
|
|
91873
|
+
if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs$1.__patched) {
|
|
91874
|
+
module.exports = patch(fs$1);
|
|
91875
|
+
fs$1.__patched = true;
|
|
91485
91876
|
}
|
|
91486
91877
|
function patch(fs) {
|
|
91487
91878
|
polyfills(fs);
|
|
@@ -91736,23 +92127,23 @@ var require_graceful_fs = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
91736
92127
|
}
|
|
91737
92128
|
function enqueue(elem) {
|
|
91738
92129
|
debug("ENQUEUE", elem[0].name, elem[1]);
|
|
91739
|
-
fs[gracefulQueue].push(elem);
|
|
92130
|
+
fs$1[gracefulQueue].push(elem);
|
|
91740
92131
|
retry();
|
|
91741
92132
|
}
|
|
91742
92133
|
var retryTimer;
|
|
91743
92134
|
function resetQueue() {
|
|
91744
92135
|
var now = Date.now();
|
|
91745
|
-
for (var i = 0; i < fs[gracefulQueue].length; ++i) if (fs[gracefulQueue][i].length > 2) {
|
|
91746
|
-
fs[gracefulQueue][i][3] = now;
|
|
91747
|
-
fs[gracefulQueue][i][4] = now;
|
|
92136
|
+
for (var i = 0; i < fs$1[gracefulQueue].length; ++i) if (fs$1[gracefulQueue][i].length > 2) {
|
|
92137
|
+
fs$1[gracefulQueue][i][3] = now;
|
|
92138
|
+
fs$1[gracefulQueue][i][4] = now;
|
|
91748
92139
|
}
|
|
91749
92140
|
retry();
|
|
91750
92141
|
}
|
|
91751
92142
|
function retry() {
|
|
91752
92143
|
clearTimeout(retryTimer);
|
|
91753
92144
|
retryTimer = void 0;
|
|
91754
|
-
if (fs[gracefulQueue].length === 0) return;
|
|
91755
|
-
var elem = fs[gracefulQueue].shift();
|
|
92145
|
+
if (fs$1[gracefulQueue].length === 0) return;
|
|
92146
|
+
var elem = fs$1[gracefulQueue].shift();
|
|
91756
92147
|
var fn = elem[0];
|
|
91757
92148
|
var args = elem[1];
|
|
91758
92149
|
var err = elem[2];
|
|
@@ -91771,7 +92162,7 @@ var require_graceful_fs = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
91771
92162
|
if (sinceAttempt >= Math.min(sinceStart * 1.2, 100)) {
|
|
91772
92163
|
debug("RETRY", fn.name, args);
|
|
91773
92164
|
fn.apply(null, args.concat([startTime]));
|
|
91774
|
-
} else fs[gracefulQueue].push(elem);
|
|
92165
|
+
} else fs$1[gracefulQueue].push(elem);
|
|
91775
92166
|
}
|
|
91776
92167
|
if (retryTimer === void 0) retryTimer = setTimeout(retry, 0);
|
|
91777
92168
|
}
|
|
@@ -94290,7 +94681,7 @@ function shellQuote(path) {
|
|
|
94290
94681
|
}
|
|
94291
94682
|
//#endregion
|
|
94292
94683
|
//#region src/tui/components/messages/assistant-message.ts
|
|
94293
|
-
const BULLET$1 = "
|
|
94684
|
+
const BULLET$1 = "⏺ ";
|
|
94294
94685
|
const INDENT$2 = " ";
|
|
94295
94686
|
var AssistantMessageComponent = class {
|
|
94296
94687
|
contentContainer;
|
|
@@ -94363,7 +94754,7 @@ var ImageThumbnail = class extends Container {
|
|
|
94363
94754
|
};
|
|
94364
94755
|
//#endregion
|
|
94365
94756
|
//#region src/tui/components/messages/thinking.ts
|
|
94366
|
-
const BULLET = "
|
|
94757
|
+
const BULLET = "⏺ ";
|
|
94367
94758
|
const INDENT$1 = " ";
|
|
94368
94759
|
const PREVIEW_LINES$1 = 3;
|
|
94369
94760
|
var ThinkingComponent = class {
|
|
@@ -94563,6 +94954,19 @@ function extractApprovedPlan(output) {
|
|
|
94563
94954
|
if (markerIndex < 0) return "";
|
|
94564
94955
|
return output.slice(markerIndex + 17).trim();
|
|
94565
94956
|
}
|
|
94957
|
+
function compactPreview(value) {
|
|
94958
|
+
const oneLine = value.replaceAll(/\s+/g, " ").trim();
|
|
94959
|
+
if (oneLine.length <= 160) return oneLine;
|
|
94960
|
+
return oneLine.slice(0, 157) + "...";
|
|
94961
|
+
}
|
|
94962
|
+
function parseArgsPreview(value) {
|
|
94963
|
+
if (value.trim().length === 0) return {};
|
|
94964
|
+
try {
|
|
94965
|
+
const parsed = JSON.parse(value);
|
|
94966
|
+
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) return parsed;
|
|
94967
|
+
} catch {}
|
|
94968
|
+
return { arguments: value };
|
|
94969
|
+
}
|
|
94566
94970
|
function extractKeyArgument(toolName, args) {
|
|
94567
94971
|
const candidates = {
|
|
94568
94972
|
Shell: ["command"],
|
|
@@ -94650,6 +95054,12 @@ var ToolCallComponent = class extends Container {
|
|
|
94650
95054
|
this.headerText.setText(this.buildHeader());
|
|
94651
95055
|
this.rebuildContent();
|
|
94652
95056
|
}
|
|
95057
|
+
updateToolCall(toolCall) {
|
|
95058
|
+
this.toolCall = toolCall;
|
|
95059
|
+
this.headerText.setText(this.buildHeader());
|
|
95060
|
+
this.rebuildBody();
|
|
95061
|
+
this.ui?.requestRender();
|
|
95062
|
+
}
|
|
94653
95063
|
applySubagentReplay(subagent) {
|
|
94654
95064
|
if (subagent === void 0) return;
|
|
94655
95065
|
this.subagentAgentId = subagent.id;
|
|
@@ -94688,9 +95098,23 @@ var ToolCallComponent = class extends Container {
|
|
|
94688
95098
|
this.ui?.requestRender();
|
|
94689
95099
|
}
|
|
94690
95100
|
appendSubToolCall(call) {
|
|
95101
|
+
const existing = this.ongoingSubCalls.get(call.id);
|
|
94691
95102
|
this.ongoingSubCalls.set(call.id, {
|
|
94692
95103
|
name: call.name,
|
|
94693
|
-
args: call.args
|
|
95104
|
+
args: call.args,
|
|
95105
|
+
...existing?.streamingArguments !== void 0 ? { streamingArguments: existing.streamingArguments } : {}
|
|
95106
|
+
});
|
|
95107
|
+
this.rebuildContent();
|
|
95108
|
+
this.ui?.requestRender();
|
|
95109
|
+
}
|
|
95110
|
+
appendSubToolCallDelta(delta) {
|
|
95111
|
+
const existing = this.ongoingSubCalls.get(delta.id);
|
|
95112
|
+
const nextArgsText = `${existing?.streamingArguments ?? ""}${delta.argumentsPart ?? ""}`;
|
|
95113
|
+
const parsed = parseArgsPreview(nextArgsText);
|
|
95114
|
+
this.ongoingSubCalls.set(delta.id, {
|
|
95115
|
+
name: delta.name ?? existing?.name ?? "Tool",
|
|
95116
|
+
args: parsed,
|
|
95117
|
+
streamingArguments: nextArgsText
|
|
94694
95118
|
});
|
|
94695
95119
|
this.rebuildContent();
|
|
94696
95120
|
this.ui?.requestRender();
|
|
@@ -94717,8 +95141,8 @@ var ToolCallComponent = class extends Container {
|
|
|
94717
95141
|
const isFinished = result !== void 0;
|
|
94718
95142
|
const isError = result?.is_error ?? false;
|
|
94719
95143
|
let bullet;
|
|
94720
|
-
if (isFinished) bullet = isError ? chalk.hex(colors.error)("✗ ") : chalk.hex(colors.success)("
|
|
94721
|
-
else bullet = this.blinkOn ? chalk.white("
|
|
95144
|
+
if (isFinished) bullet = isError ? chalk.hex(colors.error)("✗ ") : chalk.hex(colors.success)("⏺ ");
|
|
95145
|
+
else bullet = this.blinkOn ? chalk.white("⏺ ") : " ";
|
|
94722
95146
|
if (toolCall.name === "ExitPlanMode") return chalk.hex(colors.primary).bold("Current plan");
|
|
94723
95147
|
if (toolCall.name === "AskUserQuestion") {
|
|
94724
95148
|
const label = isFinished ? isError ? "Could not collect your input" : "Collected your answers" : "Waiting for your input";
|
|
@@ -94736,6 +95160,13 @@ var ToolCallComponent = class extends Container {
|
|
|
94736
95160
|
this.buildContent();
|
|
94737
95161
|
this.buildSubagentBlock();
|
|
94738
95162
|
}
|
|
95163
|
+
rebuildBody() {
|
|
95164
|
+
while (this.children.length > 2) this.children.pop();
|
|
95165
|
+
this.buildCallPreview();
|
|
95166
|
+
this.callPreviewEndIndex = this.children.length;
|
|
95167
|
+
this.buildContent();
|
|
95168
|
+
this.buildSubagentBlock();
|
|
95169
|
+
}
|
|
94739
95170
|
buildSubagentBlock() {
|
|
94740
95171
|
if (this.subagentAgentId === void 0 && this.ongoingSubCalls.size === 0 && this.finishedSubCalls.length === 0 && this.subagentText.length === 0) return;
|
|
94741
95172
|
const dim = chalk.dim;
|
|
@@ -94757,6 +95188,7 @@ var ToolCallComponent = class extends Container {
|
|
|
94757
95188
|
const nameCol = chalk.hex(this.colors.primary)(call.name);
|
|
94758
95189
|
const argCol = keyArg ? dim(` (${keyArg})`) : "";
|
|
94759
95190
|
this.addChild(new Text(` ${dim("…")} Using ${nameCol}${argCol}`, 0, 0));
|
|
95191
|
+
if (call.streamingArguments !== void 0 && call.streamingArguments.length > 0) this.addChild(new Text(` ${dim(compactPreview(call.streamingArguments))}`, 0, 0));
|
|
94760
95192
|
}
|
|
94761
95193
|
if (this.subagentText.length > 0) {
|
|
94762
95194
|
const tailLines = this.subagentText.split("\n").slice(-3);
|
|
@@ -94773,15 +95205,19 @@ var ToolCallComponent = class extends Container {
|
|
|
94773
95205
|
this.buildPlanPreview();
|
|
94774
95206
|
return;
|
|
94775
95207
|
}
|
|
95208
|
+
if (this.toolCall.streamingArguments !== void 0) {
|
|
95209
|
+
this.addChild(new Text(chalk.dim(compactPreview(this.toolCall.streamingArguments)), 2, 0));
|
|
95210
|
+
return;
|
|
95211
|
+
}
|
|
94776
95212
|
if (name === "Write" || name === "WriteFile") {
|
|
94777
95213
|
const content = str(this.toolCall.args["content"]);
|
|
94778
95214
|
if (content.length === 0) return;
|
|
94779
95215
|
const allLines = highlightLines(content, langFromPath(str(this.toolCall.args["file_path"] ?? this.toolCall.args["path"])));
|
|
94780
95216
|
const shown = allLines.slice(0, CALL_PREVIEW_LINES);
|
|
94781
95217
|
const remaining = allLines.length - shown.length;
|
|
94782
|
-
for (
|
|
95218
|
+
for (const [i, line] of shown.entries()) {
|
|
94783
95219
|
const lineNum = chalk.dim(String(i + 1).padStart(4) + " ");
|
|
94784
|
-
this.addChild(new Text(lineNum +
|
|
95220
|
+
this.addChild(new Text(lineNum + line, 2, 0));
|
|
94785
95221
|
}
|
|
94786
95222
|
if (remaining > 0) this.addChild(new Text(chalk.dim(`... (${String(remaining)} more lines, ${String(allLines.length)} total)`), 2, 0));
|
|
94787
95223
|
} else if (name === "Edit" || name === "EditFile") {
|
|
@@ -94815,15 +95251,14 @@ var ToolCallComponent = class extends Container {
|
|
|
94815
95251
|
return;
|
|
94816
95252
|
}
|
|
94817
95253
|
if (this.toolCall.name === "SetTodoList" && !result.is_error) return;
|
|
94818
|
-
if (this.toolCall.name === "AskUserQuestion" && !result.is_error)
|
|
94819
|
-
|
|
94820
|
-
}
|
|
95254
|
+
if (this.toolCall.name === "AskUserQuestion" && !result.is_error && this.renderAskUserQuestionResult(result.output)) return;
|
|
95255
|
+
const tint = result.is_error ? chalk.hex(this.colors.error) : chalk.dim;
|
|
94821
95256
|
const lines = result.output.split("\n");
|
|
94822
|
-
if (this.expanded) this.addChild(new Text(
|
|
95257
|
+
if (this.expanded) this.addChild(new Text(tint(result.output), 2, 0));
|
|
94823
95258
|
else {
|
|
94824
95259
|
const shown = lines.slice(0, PREVIEW_LINES);
|
|
94825
95260
|
const remaining = lines.length - shown.length;
|
|
94826
|
-
this.addChild(new Text(
|
|
95261
|
+
this.addChild(new Text(tint(shown.join("\n")), 2, 0));
|
|
94827
95262
|
if (remaining > 0) this.addChild(new Text(chalk.dim(`... (${String(remaining)} more lines, ctrl+o to expand)`), 2, 0));
|
|
94828
95263
|
}
|
|
94829
95264
|
}
|
|
@@ -95200,6 +95635,15 @@ function handleSubagentSourceEvent(ectx, payload) {
|
|
|
95200
95635
|
});
|
|
95201
95636
|
return;
|
|
95202
95637
|
}
|
|
95638
|
+
if (payload.method === "tool.call.delta") {
|
|
95639
|
+
const d = payload.data;
|
|
95640
|
+
if (typeof d.tool_call_id === "string") tc.appendSubToolCallDelta({
|
|
95641
|
+
id: `${payload.source_id}:${d.tool_call_id}`,
|
|
95642
|
+
...typeof d.name === "string" ? { name: d.name } : {},
|
|
95643
|
+
argumentsPart: typeof d.arguments_part === "string" ? d.arguments_part : null
|
|
95644
|
+
});
|
|
95645
|
+
return;
|
|
95646
|
+
}
|
|
95203
95647
|
if (payload.method === "tool.result") {
|
|
95204
95648
|
const d = payload.data;
|
|
95205
95649
|
if (typeof d.tool_call_id === "string") tc.finishSubToolCall({
|
|
@@ -96540,6 +96984,7 @@ function createTUIState(options) {
|
|
|
96540
96984
|
assistantStreamActive: false,
|
|
96541
96985
|
thinkingDraft: "",
|
|
96542
96986
|
activeToolCalls: /* @__PURE__ */ new Map(),
|
|
96987
|
+
streamingToolCallArguments: /* @__PURE__ */ new Map(),
|
|
96543
96988
|
toastTimers: /* @__PURE__ */ new Map(),
|
|
96544
96989
|
pendingExit: null,
|
|
96545
96990
|
queuedMessages: [],
|
|
@@ -96701,6 +97146,7 @@ function sendMessageInternal(state, addEntry, input, options) {
|
|
|
96701
97146
|
state.assistantStreamActive = false;
|
|
96702
97147
|
state.thinkingDraft = "";
|
|
96703
97148
|
state.activeToolCalls.clear();
|
|
97149
|
+
state.streamingToolCallArguments.clear();
|
|
96704
97150
|
state.livePane = {
|
|
96705
97151
|
...state.livePane,
|
|
96706
97152
|
mode: "waiting",
|
|
@@ -97319,6 +97765,7 @@ function releaseSessionSideEffects(state) {
|
|
|
97319
97765
|
state.queuedMessages = [];
|
|
97320
97766
|
state.queueIdCounter = 0;
|
|
97321
97767
|
state.activeToolCalls.clear();
|
|
97768
|
+
state.streamingToolCallArguments?.clear();
|
|
97322
97769
|
state.currentTurnId = void 0;
|
|
97323
97770
|
state.assistantDraft = "";
|
|
97324
97771
|
state.assistantStreamActive = false;
|
|
@@ -97370,8 +97817,8 @@ var CompactionComponent = class extends Container {
|
|
|
97370
97817
|
this.stopBlink();
|
|
97371
97818
|
}
|
|
97372
97819
|
buildHeader() {
|
|
97373
|
-
if (this.done) return `${chalk.hex(this.colors.success)("
|
|
97374
|
-
return `${this.blinkOn ? chalk.white("
|
|
97820
|
+
if (this.done) return `${chalk.hex(this.colors.success)("⏺ ")}${chalk.hex(this.colors.success).bold("Compaction complete")}${this.tokensBefore !== void 0 && this.tokensAfter !== void 0 ? chalk.dim(` (${String(this.tokensBefore)} → ${String(this.tokensAfter)} tokens)`) : ""}`;
|
|
97821
|
+
return `${this.blinkOn ? chalk.white("⏺ ") : " "}${chalk.hex(this.colors.primary).bold("Compacting context...")}`;
|
|
97375
97822
|
}
|
|
97376
97823
|
startBlink() {
|
|
97377
97824
|
this.blinkTimer = setInterval(() => {
|
|
@@ -97577,6 +98024,7 @@ async function dispatchSlashCommand(input, state, buildCtx, addEntry) {
|
|
|
97577
98024
|
//#endregion
|
|
97578
98025
|
//#region src/tui/handlers/turn-lifecycle.ts
|
|
97579
98026
|
function handleTurnBegin(ectx, _data) {
|
|
98027
|
+
ectx.state.streamingToolCallArguments.clear();
|
|
97580
98028
|
ectx.patchLivePane({
|
|
97581
98029
|
mode: "waiting",
|
|
97582
98030
|
thinkingText: "",
|
|
@@ -97594,6 +98042,7 @@ function handleTurnBegin(ectx, _data) {
|
|
|
97594
98042
|
function handleTurnEnd(ectx, _data, sendQueued) {
|
|
97595
98043
|
const todos = ectx.state.todoPanel.getTodos();
|
|
97596
98044
|
if (todos.length > 0 && todos.every((t) => t.status === "done")) ectx.setTodoList([]);
|
|
98045
|
+
ectx.state.streamingToolCallArguments.clear();
|
|
97597
98046
|
finalizeTurn(ectx, sendQueued);
|
|
97598
98047
|
}
|
|
97599
98048
|
function handleStepBegin(ectx) {
|
|
@@ -97645,24 +98094,18 @@ function handleContentDelta(ectx, data) {
|
|
|
97645
98094
|
streamingPhase: "composing",
|
|
97646
98095
|
streamingStartTime: Date.now()
|
|
97647
98096
|
});
|
|
97648
|
-
return;
|
|
97649
|
-
}
|
|
97650
|
-
if (data.type === "tool_call_part") {
|
|
97651
|
-
if (ectx.state.thinkingDraft.length > 0) flushThinkingToTranscript(ectx, "idle");
|
|
97652
|
-
ectx.patchLivePane({
|
|
97653
|
-
mode: "idle",
|
|
97654
|
-
pendingToolCall: null,
|
|
97655
|
-
pendingApproval: null,
|
|
97656
|
-
pendingQuestion: null
|
|
97657
|
-
});
|
|
97658
|
-
ectx.setAppState({
|
|
97659
|
-
streamingPhase: "composing",
|
|
97660
|
-
streamingStartTime: Date.now()
|
|
97661
|
-
});
|
|
97662
98097
|
}
|
|
97663
98098
|
}
|
|
97664
98099
|
//#endregion
|
|
97665
98100
|
//#region src/tui/handlers/tool.ts
|
|
98101
|
+
function parseStreamingArgs(argumentsText) {
|
|
98102
|
+
if (argumentsText.trim().length === 0) return {};
|
|
98103
|
+
try {
|
|
98104
|
+
const parsed = JSON.parse(argumentsText);
|
|
98105
|
+
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) return parsed;
|
|
98106
|
+
} catch {}
|
|
98107
|
+
return { arguments: argumentsText };
|
|
98108
|
+
}
|
|
97666
98109
|
function isTodoItemShape(value) {
|
|
97667
98110
|
if (typeof value !== "object" || value === null) return false;
|
|
97668
98111
|
const rec = value;
|
|
@@ -97676,15 +98119,53 @@ function handleToolCall(ectx, data) {
|
|
|
97676
98119
|
args: data.args,
|
|
97677
98120
|
description: data.description
|
|
97678
98121
|
};
|
|
98122
|
+
const existing = ectx.state.activeToolCalls.get(data.id);
|
|
97679
98123
|
ectx.state.activeToolCalls.set(data.id, toolCall);
|
|
97680
|
-
|
|
97681
|
-
ectx.
|
|
98124
|
+
ectx.state.streamingToolCallArguments.delete(data.id);
|
|
98125
|
+
const existingComponent = ectx.state.pendingToolComponents.get(data.id);
|
|
98126
|
+
if (existingComponent !== void 0) existingComponent.updateToolCall(toolCall);
|
|
98127
|
+
else if (existing === void 0) {
|
|
98128
|
+
flushTurnBuffers(ectx, "tool");
|
|
98129
|
+
ectx.onToolCallStart(toolCall);
|
|
98130
|
+
}
|
|
98131
|
+
ectx.patchLivePane({
|
|
98132
|
+
mode: "tool",
|
|
98133
|
+
pendingToolCall: toolCall,
|
|
98134
|
+
pendingApproval: null,
|
|
98135
|
+
pendingQuestion: null
|
|
98136
|
+
});
|
|
98137
|
+
}
|
|
98138
|
+
function handleToolCallDelta(ectx, data) {
|
|
98139
|
+
if (typeof data.tool_call_id !== "string" || data.tool_call_id.length === 0) return;
|
|
98140
|
+
const id = data.tool_call_id;
|
|
98141
|
+
const existing = ectx.state.streamingToolCallArguments.get(id);
|
|
98142
|
+
const argumentsText = `${existing?.argumentsText ?? ""}${data.arguments_part ?? ""}`;
|
|
98143
|
+
const name = data.name ?? existing?.name ?? ectx.state.activeToolCalls.get(id)?.name ?? "Tool";
|
|
98144
|
+
ectx.state.streamingToolCallArguments.set(id, {
|
|
98145
|
+
name,
|
|
98146
|
+
argumentsText
|
|
98147
|
+
});
|
|
98148
|
+
const toolCall = {
|
|
98149
|
+
id,
|
|
98150
|
+
name,
|
|
98151
|
+
args: parseStreamingArgs(argumentsText),
|
|
98152
|
+
streamingArguments: argumentsText
|
|
98153
|
+
};
|
|
98154
|
+
ectx.state.activeToolCalls.set(id, toolCall);
|
|
98155
|
+
if (ectx.state.thinkingDraft.length > 0) flushTurnBuffers(ectx, "tool");
|
|
98156
|
+
const existingComponent = ectx.state.pendingToolComponents.get(id);
|
|
98157
|
+
if (existingComponent !== void 0) existingComponent.updateToolCall(toolCall);
|
|
98158
|
+
else ectx.onToolCallStart(toolCall);
|
|
97682
98159
|
ectx.patchLivePane({
|
|
97683
98160
|
mode: "tool",
|
|
97684
98161
|
pendingToolCall: toolCall,
|
|
97685
98162
|
pendingApproval: null,
|
|
97686
98163
|
pendingQuestion: null
|
|
97687
98164
|
});
|
|
98165
|
+
ectx.setAppState({
|
|
98166
|
+
streamingPhase: "composing",
|
|
98167
|
+
streamingStartTime: Date.now()
|
|
98168
|
+
});
|
|
97688
98169
|
}
|
|
97689
98170
|
function handleToolResult(ectx, data) {
|
|
97690
98171
|
const matchedCall = ectx.state.activeToolCalls.get(data.tool_call_id);
|
|
@@ -97698,7 +98179,7 @@ function handleToolResult(ectx, data) {
|
|
|
97698
98179
|
if (matchedCall.name === "SetTodoList" && !data.is_error) {
|
|
97699
98180
|
const rawTodos = matchedCall.args.todos;
|
|
97700
98181
|
if (Array.isArray(rawTodos)) {
|
|
97701
|
-
const sanitized = rawTodos.filter(isTodoItemShape).map((t) => ({
|
|
98182
|
+
const sanitized = rawTodos.filter((todo) => isTodoItemShape(todo)).map((t) => ({
|
|
97702
98183
|
title: t.title,
|
|
97703
98184
|
status: t.status
|
|
97704
98185
|
}));
|
|
@@ -97707,6 +98188,7 @@ function handleToolResult(ectx, data) {
|
|
|
97707
98188
|
}
|
|
97708
98189
|
}
|
|
97709
98190
|
ectx.state.activeToolCalls.delete(data.tool_call_id);
|
|
98191
|
+
ectx.state.streamingToolCallArguments.delete(data.tool_call_id);
|
|
97710
98192
|
ectx.patchLivePane({
|
|
97711
98193
|
mode: "waiting",
|
|
97712
98194
|
pendingToolCall: null
|
|
@@ -97823,6 +98305,9 @@ function dispatchEvent(event, ectx, sendQueued) {
|
|
|
97823
98305
|
case "tool.call":
|
|
97824
98306
|
handleToolCall(ectx, event.data);
|
|
97825
98307
|
break;
|
|
98308
|
+
case "tool.call.delta":
|
|
98309
|
+
handleToolCallDelta(ectx, event.data);
|
|
98310
|
+
break;
|
|
97826
98311
|
case "tool.result":
|
|
97827
98312
|
handleToolResult(ectx, event.data);
|
|
97828
98313
|
break;
|
|
@@ -99092,7 +99577,7 @@ var ApprovalPanelComponent = class extends Container {
|
|
|
99092
99577
|
focused = false;
|
|
99093
99578
|
selectedIndex = 0;
|
|
99094
99579
|
feedbackMode = false;
|
|
99095
|
-
|
|
99580
|
+
feedbackInput = new Input();
|
|
99096
99581
|
expanded = false;
|
|
99097
99582
|
onResponse;
|
|
99098
99583
|
request;
|
|
@@ -99100,6 +99585,13 @@ var ApprovalPanelComponent = class extends Container {
|
|
|
99100
99585
|
super();
|
|
99101
99586
|
this.request = request;
|
|
99102
99587
|
this.onResponse = onResponse;
|
|
99588
|
+
this.feedbackInput.onSubmit = (value) => {
|
|
99589
|
+
this.submit(this.selectedIndex, value);
|
|
99590
|
+
};
|
|
99591
|
+
this.feedbackInput.onEscape = () => {
|
|
99592
|
+
this.feedbackMode = false;
|
|
99593
|
+
this.feedbackInput.setValue("");
|
|
99594
|
+
};
|
|
99103
99595
|
}
|
|
99104
99596
|
submit(index, feedback = "") {
|
|
99105
99597
|
const option = this.choiceAt(index);
|
|
@@ -99120,21 +99612,16 @@ var ApprovalPanelComponent = class extends Container {
|
|
|
99120
99612
|
}
|
|
99121
99613
|
onToggleToolExpand;
|
|
99122
99614
|
handleInput(data) {
|
|
99615
|
+
if (matchesKey(data, Key.ctrl("c")) || matchesKey(data, Key.ctrl("d"))) {
|
|
99616
|
+
this.onResponse({ response: "rejected" });
|
|
99617
|
+
return;
|
|
99618
|
+
}
|
|
99123
99619
|
if (matchesKey(data, Key.ctrl("o"))) {
|
|
99124
99620
|
this.expanded = !this.expanded;
|
|
99125
99621
|
this.onToggleToolExpand?.();
|
|
99126
99622
|
return;
|
|
99127
99623
|
}
|
|
99128
99624
|
if (this.feedbackMode) {
|
|
99129
|
-
if (matchesKey(data, Key.enter)) {
|
|
99130
|
-
this.submit(this.selectedIndex, this.feedbackText);
|
|
99131
|
-
return;
|
|
99132
|
-
}
|
|
99133
|
-
if (matchesKey(data, Key.escape)) {
|
|
99134
|
-
this.feedbackMode = false;
|
|
99135
|
-
this.feedbackText = "";
|
|
99136
|
-
return;
|
|
99137
|
-
}
|
|
99138
99625
|
if (matchesKey(data, Key.up)) {
|
|
99139
99626
|
this.feedbackMode = false;
|
|
99140
99627
|
this.selectedIndex = (this.selectedIndex - 1 + this.choiceCount()) % this.choiceCount();
|
|
@@ -99145,16 +99632,7 @@ var ApprovalPanelComponent = class extends Container {
|
|
|
99145
99632
|
this.selectedIndex = (this.selectedIndex + 1) % this.choiceCount();
|
|
99146
99633
|
return;
|
|
99147
99634
|
}
|
|
99148
|
-
|
|
99149
|
-
this.feedbackText = this.feedbackText.slice(0, -1);
|
|
99150
|
-
return;
|
|
99151
|
-
}
|
|
99152
|
-
const printable = decodeKittyPrintable(data);
|
|
99153
|
-
if (printable !== void 0) {
|
|
99154
|
-
this.feedbackText += printable;
|
|
99155
|
-
return;
|
|
99156
|
-
}
|
|
99157
|
-
if (data.length > 0 && !data.startsWith("\x1B")) this.feedbackText += data;
|
|
99635
|
+
this.feedbackInput.handleInput(data);
|
|
99158
99636
|
return;
|
|
99159
99637
|
}
|
|
99160
99638
|
if (this.choiceCount() === 0) return;
|
|
@@ -99177,6 +99655,7 @@ var ApprovalPanelComponent = class extends Container {
|
|
|
99177
99655
|
render(width) {
|
|
99178
99656
|
this.clear();
|
|
99179
99657
|
this.ensureValidSelection();
|
|
99658
|
+
this.feedbackInput.focused = this.focused && this.feedbackMode;
|
|
99180
99659
|
const { data } = this.request;
|
|
99181
99660
|
const horizontalBar = borderColor("─".repeat(width));
|
|
99182
99661
|
const indent = (s) => ` ${s}`;
|
|
@@ -99201,12 +99680,12 @@ var ApprovalPanelComponent = class extends Container {
|
|
|
99201
99680
|
const isSelected = idx === this.selectedIndex;
|
|
99202
99681
|
const num = idx + 1;
|
|
99203
99682
|
const labelWithNum = `${String(num)}. ${option.label}`;
|
|
99204
|
-
if (this.feedbackMode && option.requires_feedback === true && isSelected) lines.push(indent(
|
|
99683
|
+
if (this.feedbackMode && option.requires_feedback === true && isSelected) lines.push(indent(this.renderInlineFeedbackLine(width - 2, labelWithNum)));
|
|
99205
99684
|
else if (isSelected) lines.push(indent(`${selectColor.bold("▶")} ${selectColor.bold(labelWithNum)}`));
|
|
99206
99685
|
else lines.push(indent(chalk.gray(` ${labelWithNum}`)));
|
|
99207
99686
|
}
|
|
99208
99687
|
lines.push("");
|
|
99209
|
-
if (this.feedbackMode) lines.push(indent(chalk.dim("Type feedback
|
|
99688
|
+
if (this.feedbackMode) lines.push(indent(chalk.dim("Type feedback · ↵ submit.")));
|
|
99210
99689
|
else {
|
|
99211
99690
|
const expandHint = hasDiff ? ` · ctrl+o ${this.expanded ? "collapse" : "expand"}` : "";
|
|
99212
99691
|
lines.push(indent(chalk.dim(`↑/↓ select · ${buildNumericHint(data.choices.length)} choose · ↵ confirm${expandHint}`)));
|
|
@@ -99228,6 +99707,16 @@ var ApprovalPanelComponent = class extends Container {
|
|
|
99228
99707
|
}
|
|
99229
99708
|
if (this.selectedIndex < 0 || this.selectedIndex >= count) this.selectedIndex = Math.max(0, Math.min(this.selectedIndex, count - 1));
|
|
99230
99709
|
}
|
|
99710
|
+
renderInlineFeedbackLine(width, labelWithNum) {
|
|
99711
|
+
const prefix = `${selectColor.bold("▶")} ${selectColor.bold(labelWithNum)} `;
|
|
99712
|
+
const inputWidth = Math.max(4, width - visibleWidth(prefix) + 2);
|
|
99713
|
+
const inputLine = this.feedbackInput.render(inputWidth)[0] ?? "> ";
|
|
99714
|
+
return prefix + (inputLine.startsWith("> ") ? inputLine.slice(2) : inputLine);
|
|
99715
|
+
}
|
|
99716
|
+
invalidate() {
|
|
99717
|
+
super.invalidate();
|
|
99718
|
+
this.feedbackInput.invalidate();
|
|
99719
|
+
}
|
|
99231
99720
|
};
|
|
99232
99721
|
function buildNumericHint(count) {
|
|
99233
99722
|
if (count <= 0) return "↵";
|
|
@@ -99314,6 +99803,7 @@ var QuestionDialogComponent = class extends Container {
|
|
|
99314
99803
|
colors;
|
|
99315
99804
|
onAnswer;
|
|
99316
99805
|
maxVisibleOptions;
|
|
99806
|
+
otherInput = new Input();
|
|
99317
99807
|
currentTab = 0;
|
|
99318
99808
|
submitActionIdx = 0;
|
|
99319
99809
|
editingOther = false;
|
|
@@ -99336,6 +99826,9 @@ var QuestionDialogComponent = class extends Container {
|
|
|
99336
99826
|
this.onAnswer = onAnswer;
|
|
99337
99827
|
this.colors = colors;
|
|
99338
99828
|
this.maxVisibleOptions = maxVisibleOptions;
|
|
99829
|
+
this.otherInput.onSubmit = (value) => {
|
|
99830
|
+
this.commitOtherInput(value);
|
|
99831
|
+
};
|
|
99339
99832
|
const total = request.data.questions.length;
|
|
99340
99833
|
this.cursors = Array.from({ length: total }, () => 0);
|
|
99341
99834
|
this.singleSelections = Array.from({ length: total }, () => void 0);
|
|
@@ -99349,6 +99842,10 @@ var QuestionDialogComponent = class extends Container {
|
|
|
99349
99842
|
this.onAnswer([]);
|
|
99350
99843
|
return;
|
|
99351
99844
|
}
|
|
99845
|
+
if (matchesKey(data, Key.ctrl("c")) || matchesKey(data, Key.ctrl("d"))) {
|
|
99846
|
+
this.onAnswer([]);
|
|
99847
|
+
return;
|
|
99848
|
+
}
|
|
99352
99849
|
if (this.isEditingOther()) {
|
|
99353
99850
|
this.handleOtherInput(data);
|
|
99354
99851
|
return;
|
|
@@ -99390,58 +99887,32 @@ var QuestionDialogComponent = class extends Container {
|
|
|
99390
99887
|
this.activateQuestionOption(numIdx);
|
|
99391
99888
|
return;
|
|
99392
99889
|
}
|
|
99393
|
-
if (printable === " " || matchesKey(data, Key.space))
|
|
99394
|
-
if (question.multi_select) this.activateQuestionOption(this.currentCursor());
|
|
99395
|
-
return;
|
|
99396
|
-
}
|
|
99890
|
+
if ((printable === " " || matchesKey(data, Key.space)) && question.multi_select) this.activateQuestionOption(this.currentCursor());
|
|
99397
99891
|
}
|
|
99398
99892
|
handleOtherInput(data) {
|
|
99399
99893
|
const questionIdx = this.currentQuestionIndex();
|
|
99400
99894
|
if (questionIdx === void 0) return;
|
|
99401
|
-
if (matchesKey(data, Key.
|
|
99402
|
-
this.
|
|
99403
|
-
this.gotoTab(this.currentTab - 1);
|
|
99404
|
-
return;
|
|
99405
|
-
}
|
|
99406
|
-
if (matchesKey(data, Key.right) || matchesKey(data, Key.tab)) {
|
|
99895
|
+
if (matchesKey(data, Key.tab)) {
|
|
99896
|
+
this.syncOtherDraft(questionIdx);
|
|
99407
99897
|
this.editingOther = false;
|
|
99408
99898
|
this.gotoTab(this.currentTab + 1);
|
|
99409
99899
|
return;
|
|
99410
99900
|
}
|
|
99411
99901
|
if (matchesKey(data, Key.up)) {
|
|
99902
|
+
this.syncOtherDraft(questionIdx);
|
|
99412
99903
|
this.editingOther = false;
|
|
99413
99904
|
this.moveQuestionCursor(-1);
|
|
99414
99905
|
return;
|
|
99415
99906
|
}
|
|
99416
99907
|
if (matchesKey(data, Key.down)) {
|
|
99908
|
+
this.syncOtherDraft(questionIdx);
|
|
99417
99909
|
this.editingOther = false;
|
|
99418
99910
|
this.moveQuestionCursor(1);
|
|
99419
99911
|
return;
|
|
99420
99912
|
}
|
|
99421
|
-
|
|
99422
|
-
|
|
99423
|
-
|
|
99424
|
-
}
|
|
99425
|
-
if (matchesKey(data, Key.backspace)) {
|
|
99426
|
-
this.otherDrafts[questionIdx] = this.otherDrafts[questionIdx]?.slice(0, -1) ?? "";
|
|
99427
|
-
this.reviewMessage = void 0;
|
|
99428
|
-
return;
|
|
99429
|
-
}
|
|
99430
|
-
const printable = decodeKittyPrintable(data);
|
|
99431
|
-
if (printable !== void 0) {
|
|
99432
|
-
this.otherDrafts[questionIdx] = (this.otherDrafts[questionIdx] ?? "") + printable;
|
|
99433
|
-
this.reviewMessage = void 0;
|
|
99434
|
-
return;
|
|
99435
|
-
}
|
|
99436
|
-
if (data === " " || matchesKey(data, Key.space)) {
|
|
99437
|
-
this.otherDrafts[questionIdx] = (this.otherDrafts[questionIdx] ?? "") + " ";
|
|
99438
|
-
this.reviewMessage = void 0;
|
|
99439
|
-
return;
|
|
99440
|
-
}
|
|
99441
|
-
if (data.length > 0 && !data.startsWith("\x1B")) {
|
|
99442
|
-
this.otherDrafts[questionIdx] = (this.otherDrafts[questionIdx] ?? "") + data;
|
|
99443
|
-
this.reviewMessage = void 0;
|
|
99444
|
-
}
|
|
99913
|
+
this.otherInput.handleInput(data);
|
|
99914
|
+
this.syncOtherDraft(questionIdx);
|
|
99915
|
+
this.reviewMessage = void 0;
|
|
99445
99916
|
}
|
|
99446
99917
|
handleSubmitInput(data) {
|
|
99447
99918
|
if (matchesKey(data, Key.up)) {
|
|
@@ -99475,7 +99946,6 @@ var QuestionDialogComponent = class extends Container {
|
|
|
99475
99946
|
if (printable === "2") {
|
|
99476
99947
|
this.submitActionIdx = 1;
|
|
99477
99948
|
this.executeSubmitAction(1);
|
|
99478
|
-
return;
|
|
99479
99949
|
}
|
|
99480
99950
|
}
|
|
99481
99951
|
gotoTab(target) {
|
|
@@ -99524,15 +99994,17 @@ var QuestionDialogComponent = class extends Container {
|
|
|
99524
99994
|
enterOtherInput(questionIdx) {
|
|
99525
99995
|
this.cursors[questionIdx] = this.otherOptionIndex(questionIdx);
|
|
99526
99996
|
this.editingOther = true;
|
|
99997
|
+
this.otherInput.setValue(this.otherDraftValue(questionIdx));
|
|
99527
99998
|
this.reviewMessage = void 0;
|
|
99528
99999
|
}
|
|
99529
|
-
commitOtherInput() {
|
|
100000
|
+
commitOtherInput(rawValue) {
|
|
99530
100001
|
const questionIdx = this.currentQuestionIndex();
|
|
99531
100002
|
if (questionIdx === void 0) return;
|
|
99532
100003
|
const question = this.request.data.questions[questionIdx];
|
|
99533
100004
|
if (question === void 0) return;
|
|
99534
|
-
const value = this.
|
|
100005
|
+
const value = (rawValue ?? this.otherInput.getValue()).trim();
|
|
99535
100006
|
if (value.length === 0) return;
|
|
100007
|
+
this.otherInput.setValue(value);
|
|
99536
100008
|
this.otherDrafts[questionIdx] = value;
|
|
99537
100009
|
this.committedOtherValues[questionIdx] = value;
|
|
99538
100010
|
if (question.multi_select) this.multiSelections[questionIdx]?.add(this.otherOptionIndex(questionIdx));
|
|
@@ -99599,6 +100071,7 @@ var QuestionDialogComponent = class extends Container {
|
|
|
99599
100071
|
this.onAnswer(out);
|
|
99600
100072
|
}
|
|
99601
100073
|
render(width) {
|
|
100074
|
+
this.otherInput.focused = this.focused && this.isEditingOther();
|
|
99602
100075
|
return this.isSubmitTab() ? this.renderSubmitTab(width) : this.renderQuestionTab(width);
|
|
99603
100076
|
}
|
|
99604
100077
|
renderQuestionTab(width) {
|
|
@@ -99611,10 +100084,11 @@ var QuestionDialogComponent = class extends Container {
|
|
|
99611
100084
|
const dim = chalk.hex(colors.textDim);
|
|
99612
100085
|
const success = chalk.hex(colors.success);
|
|
99613
100086
|
const renderWidth = Math.max(1, width);
|
|
99614
|
-
const lines = [
|
|
99615
|
-
|
|
99616
|
-
|
|
99617
|
-
|
|
100087
|
+
const lines = [
|
|
100088
|
+
accent("─".repeat(renderWidth)),
|
|
100089
|
+
accent.bold(" question"),
|
|
100090
|
+
""
|
|
100091
|
+
];
|
|
99618
100092
|
this.pushTabs(lines);
|
|
99619
100093
|
lines.push("");
|
|
99620
100094
|
lines.push(accent(` ? ${question.question}`));
|
|
@@ -99635,10 +100109,15 @@ var QuestionDialogComponent = class extends Container {
|
|
|
99635
100109
|
const singleSelection = this.singleSelections[questionIdx];
|
|
99636
100110
|
for (let i = visibleStart; i < visibleEnd; i++) {
|
|
99637
100111
|
const option = options[i];
|
|
100112
|
+
if (option === void 0) continue;
|
|
99638
100113
|
const num = i + 1;
|
|
99639
100114
|
const isCursor = i === cursor;
|
|
99640
100115
|
const isOther = option.kind === "other";
|
|
99641
100116
|
const isSelected = question.multi_select ? multiSet.has(i) : singleSelection === i;
|
|
100117
|
+
if (this.isEditingOther() && isCursor && isOther) {
|
|
100118
|
+
lines.push(this.renderEditingOtherLine(renderWidth, questionIdx, option, num, isSelected));
|
|
100119
|
+
continue;
|
|
100120
|
+
}
|
|
99642
100121
|
const label = this.renderOptionLabel(questionIdx, option, isCursor);
|
|
99643
100122
|
let line;
|
|
99644
100123
|
if (question.multi_select) {
|
|
@@ -99666,10 +100145,11 @@ var QuestionDialogComponent = class extends Container {
|
|
|
99666
100145
|
const text = chalk.hex(colors.text);
|
|
99667
100146
|
const warning = chalk.hex(colors.warning);
|
|
99668
100147
|
const renderWidth = Math.max(1, width);
|
|
99669
|
-
const lines = [
|
|
99670
|
-
|
|
99671
|
-
|
|
99672
|
-
|
|
100148
|
+
const lines = [
|
|
100149
|
+
accent("─".repeat(renderWidth)),
|
|
100150
|
+
accent.bold(" question"),
|
|
100151
|
+
""
|
|
100152
|
+
];
|
|
99673
100153
|
this.pushTabs(lines);
|
|
99674
100154
|
lines.push("");
|
|
99675
100155
|
lines.push(text.bold(` ${REVIEW_TITLE}`));
|
|
@@ -99678,6 +100158,7 @@ var QuestionDialogComponent = class extends Container {
|
|
|
99678
100158
|
lines.push("");
|
|
99679
100159
|
for (let i = 0; i < this.request.data.questions.length; i++) {
|
|
99680
100160
|
const question = this.request.data.questions[i];
|
|
100161
|
+
if (question === void 0) continue;
|
|
99681
100162
|
const answer = this.answers[i];
|
|
99682
100163
|
lines.push(` ${dim("Q")} ${question.question}`);
|
|
99683
100164
|
if (answer !== void 0 && answer.length > 0) lines.push(` ${accent("→")} ${text(answer)}`);
|
|
@@ -99688,6 +100169,7 @@ var QuestionDialogComponent = class extends Container {
|
|
|
99688
100169
|
lines.push("");
|
|
99689
100170
|
for (let i = 0; i < SUBMIT_ACTIONS.length; i++) {
|
|
99690
100171
|
const label = SUBMIT_ACTIONS[i];
|
|
100172
|
+
if (label === void 0) continue;
|
|
99691
100173
|
const num = i + 1;
|
|
99692
100174
|
if (i === this.submitActionIdx) lines.push(accent(` → [${String(num)}] ${label}`));
|
|
99693
100175
|
else lines.push(dim(` [${String(num)}] ${label}`));
|
|
@@ -99703,6 +100185,7 @@ var QuestionDialogComponent = class extends Container {
|
|
|
99703
100185
|
const tabs = [];
|
|
99704
100186
|
for (let i = 0; i < this.request.data.questions.length; i++) {
|
|
99705
100187
|
const question = this.request.data.questions[i];
|
|
100188
|
+
if (question === void 0) continue;
|
|
99706
100189
|
const label = question.header !== void 0 && question.header.length > 0 ? question.header : `Q${String(i + 1)}`;
|
|
99707
100190
|
if (i === this.currentTab) tabs.push(active(` ${label} `));
|
|
99708
100191
|
else if (this.isAnswered(i)) tabs.push(chalk.green(`(✓) ${label}`));
|
|
@@ -99714,14 +100197,17 @@ var QuestionDialogComponent = class extends Container {
|
|
|
99714
100197
|
lines.push(` ${tabs.join(" ")}`);
|
|
99715
100198
|
}
|
|
99716
100199
|
buildQuestionHint(dim, questionIdx) {
|
|
99717
|
-
if (this.isEditingOther()) {
|
|
99718
|
-
|
|
99719
|
-
|
|
99720
|
-
|
|
99721
|
-
|
|
99722
|
-
}
|
|
100200
|
+
if (this.isEditingOther()) return dim(` ${[
|
|
100201
|
+
"type answer",
|
|
100202
|
+
"↵ save",
|
|
100203
|
+
...this.totalTabs() > 1 ? ["tab switch"] : [],
|
|
100204
|
+
"esc dismiss"
|
|
100205
|
+
].join(" ")}`);
|
|
99723
100206
|
const optionCount = Math.min(this.displayOptions(questionIdx).length, NUMBER_KEYS.length);
|
|
99724
|
-
const
|
|
100207
|
+
const numberHint = optionCount <= 1 ? "1" : `1-${String(optionCount)}`;
|
|
100208
|
+
const question = this.request.data.questions[questionIdx];
|
|
100209
|
+
if (question === void 0) return dim(" esc dismiss");
|
|
100210
|
+
const parts = ["▲/▼ select", `${numberHint} / ↵ ${question.multi_select ? "toggle" : "choose"}`];
|
|
99725
100211
|
if (this.totalTabs() > 1) parts.push("←/→/tab switch");
|
|
99726
100212
|
parts.push("esc dismiss");
|
|
99727
100213
|
return dim(` ${parts.join(" ")}`);
|
|
@@ -99783,11 +100269,33 @@ var QuestionDialogComponent = class extends Container {
|
|
|
99783
100269
|
}
|
|
99784
100270
|
renderOptionLabel(questionIdx, option, isCursor) {
|
|
99785
100271
|
if (option.kind !== "other") return option.label;
|
|
99786
|
-
const value = this.
|
|
100272
|
+
const value = this.otherDraftValue(questionIdx);
|
|
99787
100273
|
if (this.isEditingOther() && isCursor) return `${option.label}: ${value ?? ""}█`;
|
|
99788
100274
|
if (value !== void 0 && value.length > 0) return `${option.label}: ${value}`;
|
|
99789
100275
|
return option.label;
|
|
99790
100276
|
}
|
|
100277
|
+
renderEditingOtherLine(width, questionIdx, option, num, isSelected) {
|
|
100278
|
+
const question = this.request.data.questions[questionIdx];
|
|
100279
|
+
if (question === void 0) return option.label;
|
|
100280
|
+
let prefix;
|
|
100281
|
+
if (question.multi_select) {
|
|
100282
|
+
const body = ` [${isSelected ? "✓" : " "}] ${option.label}: `;
|
|
100283
|
+
prefix = isSelected ? chalk.hex(this.colors.success).bold(body) : chalk.hex(this.colors.primary)(body);
|
|
100284
|
+
} else {
|
|
100285
|
+
const body = ` → [${String(num)}] ${option.label}: `;
|
|
100286
|
+
prefix = isSelected && this.isAnswered(questionIdx) ? chalk.hex(this.colors.success).bold(body) : chalk.hex(this.colors.primary)(body);
|
|
100287
|
+
}
|
|
100288
|
+
const inputWidth = Math.max(4, width - visibleWidth(prefix) + 2);
|
|
100289
|
+
const inputLine = this.otherInput.render(inputWidth)[0] ?? "> ";
|
|
100290
|
+
const inlineInput = inputLine.startsWith("> ") ? inputLine.slice(2) : inputLine;
|
|
100291
|
+
return prefix + inlineInput;
|
|
100292
|
+
}
|
|
100293
|
+
otherDraftValue(questionIdx) {
|
|
100294
|
+
return this.otherDrafts[questionIdx] || this.committedOtherValues[questionIdx] || "";
|
|
100295
|
+
}
|
|
100296
|
+
syncOtherDraft(questionIdx) {
|
|
100297
|
+
this.otherDrafts[questionIdx] = this.otherInput.getValue();
|
|
100298
|
+
}
|
|
99791
100299
|
isAnswered(questionIdx) {
|
|
99792
100300
|
const answer = this.answers[questionIdx];
|
|
99793
100301
|
return answer !== void 0 && answer.length > 0;
|
|
@@ -99796,6 +100304,10 @@ var QuestionDialogComponent = class extends Container {
|
|
|
99796
100304
|
for (let i = 0; i < this.request.data.questions.length; i++) if (!this.isAnswered(i)) return true;
|
|
99797
100305
|
return false;
|
|
99798
100306
|
}
|
|
100307
|
+
invalidate() {
|
|
100308
|
+
super.invalidate();
|
|
100309
|
+
this.otherInput.invalidate();
|
|
100310
|
+
}
|
|
99799
100311
|
};
|
|
99800
100312
|
//#endregion
|
|
99801
100313
|
//#region src/tui/reverse-rpc/question/ui.ts
|