@jun133/kitty 0.0.13 → 0.0.14

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.
@@ -3558,14 +3558,21 @@ async function launchCommand(command, cwd, timeoutMs, abortSignal) {
3558
3558
  function encodePowerShellCommand(command) {
3559
3559
  const wrapped = [
3560
3560
  "$ProgressPreference = 'SilentlyContinue'",
3561
+ "$ErrorActionPreference = 'Stop'",
3561
3562
  "[Console]::InputEncoding = [System.Text.Encoding]::UTF8",
3562
3563
  "[Console]::OutputEncoding = [System.Text.Encoding]::UTF8",
3563
3564
  "$OutputEncoding = [System.Text.Encoding]::UTF8",
3564
3565
  "try { chcp 65001 > $null } catch { }",
3566
+ "$code = 0",
3567
+ "try {",
3565
3568
  `& { ${command} }`,
3566
3569
  "$code = if ($null -ne $LASTEXITCODE) { [int]$LASTEXITCODE } elseif ($?) { 0 } else { 1 }",
3570
+ "} catch {",
3571
+ "[Console]::Error.WriteLine($_.Exception.Message)",
3572
+ "$code = 1",
3573
+ "}",
3567
3574
  "exit $code"
3568
- ].join("; ");
3575
+ ].join("\n");
3569
3576
  return Buffer.from(wrapped, "utf16le").toString("base64");
3570
3577
  }
3571
3578
  function buildCommandEnvironment() {
@@ -3577,422 +3584,33 @@ function buildCommandEnvironment() {
3577
3584
  };
3578
3585
  }
3579
3586
 
3580
- // src/utils/commandRunner/platformArgs.ts
3581
- function splitByAndAnd(command) {
3582
- const segments = [];
3583
- let current = "";
3584
- let inSingle = false;
3585
- let inDouble = false;
3586
- for (let index = 0; index < command.length; index += 1) {
3587
- const char = command.charAt(index);
3588
- if (char === "'" && !inDouble) {
3589
- inSingle = !inSingle;
3590
- current += char;
3591
- continue;
3592
- }
3593
- if (char === '"' && !inSingle) {
3594
- inDouble = !inDouble;
3595
- current += char;
3596
- continue;
3597
- }
3598
- if (!inSingle && !inDouble && char === "&" && command.charAt(index + 1) === "&") {
3599
- if (current.trim()) {
3600
- segments.push(current.trim());
3601
- }
3602
- current = "";
3603
- index += 1;
3604
- continue;
3605
- }
3606
- current += char;
3607
- }
3608
- if (current.trim()) {
3609
- segments.push(current.trim());
3610
- }
3611
- return segments.length > 0 ? segments : [command];
3612
- }
3613
- function joinWithAndSemantics(segments) {
3614
- if (segments.length <= 1) {
3615
- return segments[0] ?? "";
3616
- }
3617
- let script = segments[0] ?? "";
3618
- for (let index = 1; index < segments.length; index += 1) {
3619
- const segment = segments[index];
3620
- script += `; if ($?) { ${segment} }`;
3621
- }
3622
- return script;
3623
- }
3624
- function splitArgs(command) {
3625
- const args = [];
3626
- let current = "";
3627
- let inSingle = false;
3628
- let inDouble = false;
3629
- for (let index = 0; index < command.length; index += 1) {
3630
- const char = command.charAt(index);
3631
- if (char === "'" && !inDouble) {
3632
- inSingle = !inSingle;
3633
- continue;
3634
- }
3635
- if (char === '"' && !inSingle) {
3636
- inDouble = !inDouble;
3637
- continue;
3638
- }
3639
- if (!inSingle && !inDouble && /\s/.test(char)) {
3640
- if (current) {
3641
- args.push(current);
3642
- current = "";
3643
- }
3644
- continue;
3645
- }
3646
- current += char;
3647
- }
3648
- if (current) {
3649
- args.push(current);
3650
- }
3651
- return args;
3652
- }
3653
- function expandPaths(paths) {
3654
- return paths.flatMap((targetPath) => expandBraces(targetPath));
3655
- }
3656
- function normalizeWindowsPath(value) {
3657
- if (value.includes("://")) {
3658
- return value;
3659
- }
3660
- return value.replace(/\//g, "\\");
3661
- }
3662
- function quotePowerShell(value) {
3663
- const escaped = value.replace(/'/g, "''");
3664
- return `'${escaped}'`;
3665
- }
3666
- function expandBraces(input) {
3667
- const start = findBraceStart(input);
3668
- if (start === -1) {
3669
- return [input];
3670
- }
3671
- const end = findMatchingBrace(input, start);
3672
- if (end === -1) {
3673
- return [input];
3674
- }
3675
- const prefix = input.slice(0, start);
3676
- const suffix = input.slice(end + 1);
3677
- const body = input.slice(start + 1, end);
3678
- const parts = splitBraceParts(body);
3679
- const expandedSuffix = expandBraces(suffix);
3680
- const results = [];
3681
- for (const part of parts) {
3682
- for (const expandedPart of expandBraces(part)) {
3683
- for (const tail of expandedSuffix) {
3684
- results.push(`${prefix}${expandedPart}${tail}`);
3685
- }
3686
- }
3687
- }
3688
- return results;
3689
- }
3690
- function findBraceStart(input) {
3691
- let inSingle = false;
3692
- let inDouble = false;
3693
- for (let index = 0; index < input.length; index += 1) {
3694
- const char = input.charAt(index);
3695
- if (char === "'" && !inDouble) {
3696
- inSingle = !inSingle;
3697
- continue;
3698
- }
3699
- if (char === '"' && !inSingle) {
3700
- inDouble = !inDouble;
3701
- continue;
3702
- }
3703
- if (!inSingle && !inDouble && char === "{") {
3704
- return index;
3705
- }
3706
- }
3707
- return -1;
3708
- }
3709
- function findMatchingBrace(input, start) {
3710
- let depth = 0;
3711
- let inSingle = false;
3712
- let inDouble = false;
3713
- for (let index = start; index < input.length; index += 1) {
3714
- const char = input.charAt(index);
3715
- if (char === "'" && !inDouble) {
3716
- inSingle = !inSingle;
3717
- continue;
3718
- }
3719
- if (char === '"' && !inSingle) {
3720
- inDouble = !inDouble;
3721
- continue;
3722
- }
3723
- if (inSingle || inDouble) {
3724
- continue;
3725
- }
3726
- if (char === "{") {
3727
- depth += 1;
3728
- } else if (char === "}") {
3729
- depth -= 1;
3730
- if (depth === 0) {
3731
- return index;
3732
- }
3733
- }
3734
- }
3735
- return -1;
3736
- }
3737
- function splitBraceParts(input) {
3738
- const parts = [];
3739
- let current = "";
3740
- let depth = 0;
3741
- for (let index = 0; index < input.length; index += 1) {
3742
- const char = input.charAt(index);
3743
- if (char === "{") {
3744
- depth += 1;
3745
- current += char;
3746
- continue;
3747
- }
3748
- if (char === "}") {
3749
- depth -= 1;
3750
- current += char;
3751
- continue;
3752
- }
3753
- if (char === "," && depth === 0) {
3754
- parts.push(current);
3755
- current = "";
3756
- continue;
3757
- }
3758
- current += char;
3759
- }
3760
- if (current) {
3761
- parts.push(current);
3762
- }
3763
- return parts.length > 0 ? parts : [input];
3764
- }
3765
-
3766
- // src/utils/commandRunner/platformTransforms.ts
3767
- function startsWithExplicitShell(command) {
3768
- return /^\s*(cmd(?:\.exe)?\s+\/c|powershell(?:\.exe)?\b|pwsh\b|bash\b)/i.test(command);
3769
- }
3770
- function normalizeWindowsSegment(segment) {
3771
- const trimmed = segment.trim();
3772
- if (!trimmed) {
3773
- return segment;
3774
- }
3775
- const lowered = trimmed.toLowerCase();
3776
- if (lowered.startsWith("get-childitem") || lowered.startsWith("new-item")) {
3777
- return segment;
3778
- }
3779
- if (lowered.startsWith("ls")) {
3780
- return normalizeLsSegment(trimmed);
3781
- }
3782
- if (lowered.startsWith("mkdir") || lowered.startsWith("md ")) {
3783
- return normalizeMkdirSegment(trimmed);
3784
- }
3785
- if (lowered.startsWith("rm ")) {
3786
- return normalizeRemoveSegment(trimmed);
3787
- }
3788
- if (lowered.startsWith("cp ")) {
3789
- return normalizeCopySegment(trimmed);
3790
- }
3791
- if (lowered.startsWith("mv ")) {
3792
- return normalizeMoveSegment(trimmed);
3793
- }
3794
- if (lowered.startsWith("touch ")) {
3795
- return normalizeTouchSegment(trimmed);
3587
+ // src/utils/commandRunner/output.ts
3588
+ function normalizeCommandOutput(output) {
3589
+ if (!output.includes("#< CLIXML")) {
3590
+ return output;
3796
3591
  }
3797
- if (lowered.startsWith("cat ")) {
3798
- return normalizeCatSegment(trimmed);
3592
+ const errors = [...output.matchAll(/<S\s+S="Error">([\s\S]*?)<\/S>/g)].map((match) => decodePowerShellText(match[1] ?? "")).map((line) => line.trimEnd()).filter(Boolean);
3593
+ if (errors.length === 0) {
3594
+ return output;
3799
3595
  }
3800
- return segment;
3596
+ return errors.join("\n").replace(/\n{3,}/g, "\n\n").trim();
3801
3597
  }
3802
- function normalizeLsSegment(segment) {
3803
- const args = splitArgs(segment).slice(1);
3804
- const flags = args.filter((arg) => arg.startsWith("-"));
3805
- const paths = args.filter((arg) => !arg.startsWith("-"));
3806
- const force = flags.some((flag) => flag.includes("a"));
3807
- const targetPath = paths[0];
3808
- let command = "Get-ChildItem";
3809
- if (force) {
3810
- command += " -Force";
3811
- }
3812
- if (targetPath) {
3813
- command += ` -LiteralPath ${quotePowerShell(normalizeWindowsPath(targetPath))}`;
3814
- }
3815
- return command;
3816
- }
3817
- function normalizeMkdirSegment(segment) {
3818
- const args = splitArgs(segment);
3819
- if (args.length <= 1) {
3820
- return segment;
3821
- }
3822
- const rest = args.slice(1);
3823
- let hasParents = false;
3824
- const paths = rest.filter((arg) => {
3825
- const lowered = arg.toLowerCase();
3826
- if (lowered === "-p" || lowered === "--parents") {
3827
- hasParents = true;
3828
- return false;
3829
- }
3830
- return true;
3831
- });
3832
- const needsNormalization = hasParents || paths.some((targetPath) => targetPath.includes("{"));
3833
- if (!needsNormalization) {
3834
- return segment;
3835
- }
3836
- const expanded = expandPaths(paths);
3837
- if (expanded.length === 0) {
3838
- return segment;
3839
- }
3840
- const normalizedPaths = expanded.map((targetPath) => quotePowerShell(normalizeWindowsPath(targetPath)));
3841
- return `New-Item -ItemType Directory -Force -Path ${normalizedPaths.join(", ")}`;
3842
- }
3843
- function normalizeRemoveSegment(segment) {
3844
- const args = splitArgs(segment);
3845
- if (args.length <= 1) {
3846
- return segment;
3847
- }
3848
- const flags = args.slice(1).filter((arg) => arg.startsWith("-"));
3849
- const paths = args.slice(1).filter((arg) => !arg.startsWith("-"));
3850
- if (paths.length === 0) {
3851
- return segment;
3852
- }
3853
- const recurse = flags.some((flag) => /r/i.test(flag));
3854
- const force = flags.some((flag) => /f/i.test(flag));
3855
- let command = "Remove-Item";
3856
- if (recurse) {
3857
- command += " -Recurse";
3858
- }
3859
- if (force) {
3860
- command += " -Force";
3861
- }
3862
- command += ` -LiteralPath ${paths.map((targetPath) => quotePowerShell(normalizeWindowsPath(targetPath))).join(", ")}`;
3863
- return command;
3864
- }
3865
- function normalizeCopySegment(segment) {
3866
- const args = splitArgs(segment);
3867
- if (args.length < 3) {
3868
- return segment;
3869
- }
3870
- const flags = args.slice(1).filter((arg) => arg.startsWith("-"));
3871
- const paths = args.slice(1).filter((arg) => !arg.startsWith("-"));
3872
- if (paths.length < 2) {
3873
- return segment;
3874
- }
3875
- const recurse = flags.some((flag) => /r/i.test(flag));
3876
- const force = flags.some((flag) => /f/i.test(flag));
3877
- const destination = paths[paths.length - 1];
3878
- if (!destination) {
3879
- return segment;
3880
- }
3881
- const sources = paths.slice(0, -1);
3882
- let command = "Copy-Item";
3883
- if (recurse) {
3884
- command += " -Recurse";
3885
- }
3886
- if (force) {
3887
- command += " -Force";
3888
- }
3889
- command += ` -Path ${sources.map((targetPath) => quotePowerShell(normalizeWindowsPath(targetPath))).join(", ")}`;
3890
- command += ` -Destination ${quotePowerShell(normalizeWindowsPath(destination))}`;
3891
- return command;
3892
- }
3893
- function normalizeMoveSegment(segment) {
3894
- const args = splitArgs(segment);
3895
- if (args.length < 3) {
3896
- return segment;
3897
- }
3898
- const flags = args.slice(1).filter((arg) => arg.startsWith("-"));
3899
- const paths = args.slice(1).filter((arg) => !arg.startsWith("-"));
3900
- if (paths.length < 2) {
3901
- return segment;
3902
- }
3903
- const force = flags.some((flag) => /f/i.test(flag));
3904
- const destination = paths[paths.length - 1];
3905
- if (!destination) {
3906
- return segment;
3907
- }
3908
- const sources = paths.slice(0, -1);
3909
- let command = "Move-Item";
3910
- if (force) {
3911
- command += " -Force";
3912
- }
3913
- command += ` -Path ${sources.map((targetPath) => quotePowerShell(normalizeWindowsPath(targetPath))).join(", ")}`;
3914
- command += ` -Destination ${quotePowerShell(normalizeWindowsPath(destination))}`;
3915
- return command;
3916
- }
3917
- function normalizeTouchSegment(segment) {
3918
- const args = splitArgs(segment).slice(1);
3919
- if (args.length === 0) {
3920
- return segment;
3921
- }
3922
- const expanded = expandPaths(args);
3923
- if (expanded.length === 0) {
3924
- return segment;
3925
- }
3926
- const paths = expanded.map((targetPath) => quotePowerShell(normalizeWindowsPath(targetPath)));
3927
- return `New-Item -ItemType File -Force -Path ${paths.join(", ")}`;
3928
- }
3929
- function normalizeCatSegment(segment) {
3930
- const args = splitArgs(segment).slice(1);
3931
- if (args.length === 0) {
3932
- return segment;
3933
- }
3934
- const targetPath = args[0];
3935
- if (!targetPath) {
3936
- return segment;
3937
- }
3938
- return `Get-Content -LiteralPath ${quotePowerShell(normalizeWindowsPath(targetPath))}`;
3939
- }
3940
-
3941
- // src/utils/commandRunner/platform.ts
3942
- function normalizeCommandForPlatform(command) {
3943
- if (process.platform !== "win32") {
3944
- return command;
3945
- }
3946
- const trimmed = command.trim();
3947
- if (!trimmed) {
3948
- return command;
3949
- }
3950
- const normalized = normalizeWindowsCommand(trimmed);
3951
- return normalizeNpmCommandNames(normalized);
3952
- }
3953
- function normalizeWindowsCommand(command) {
3954
- if (startsWithExplicitShell(command)) {
3955
- return command;
3956
- }
3957
- const segments = splitByAndAnd(command);
3958
- const normalizedSegments = segments.map((segment) => normalizeWindowsSegment(segment));
3959
- return joinWithAndSemantics(normalizedSegments);
3960
- }
3961
- function normalizeNpmCommandNames(command) {
3962
- const commandNames = {
3963
- npm: "npm.cmd",
3964
- npx: "npx.cmd",
3965
- pnpm: "pnpm.cmd",
3966
- yarn: "yarn.cmd"
3967
- };
3968
- const pattern = /(^|[;&|]|\&\&)\s*(npm|npx|pnpm|yarn)(?=\s|$)/gi;
3969
- return command.replace(pattern, (match, prefix, tool) => {
3970
- const replacement = commandNames[String(tool).toLowerCase()];
3971
- if (!replacement) {
3972
- return match;
3973
- }
3974
- if (!prefix) {
3975
- return replacement;
3976
- }
3977
- return `${prefix} ${replacement}`;
3978
- });
3598
+ function decodePowerShellText(value) {
3599
+ return value.replace(/_x000D__x000A_/g, "\n").replace(/_x000D_/g, "\r").replace(/_x000A_/g, "\n").replace(/_x0009_/g, " ").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&apos;/g, "'").replace(/&amp;/g, "&");
3979
3600
  }
3980
3601
 
3981
3602
  // src/utils/commandRunner/run.ts
3982
3603
  var STALL_KILL_TIMEOUT_MS = 5e3;
3983
3604
  async function runCommandWithPolicy(options) {
3984
- const normalizedCommand = normalizeCommandForPlatform(options.command);
3985
- return runCommandOnce({
3986
- ...options,
3987
- command: normalizedCommand
3988
- });
3605
+ return runCommandOnce(options);
3989
3606
  }
3990
3607
  async function runCommandOnce(options) {
3991
3608
  const start = Date.now();
3992
3609
  let stalled = false;
3993
3610
  let stallTimer = null;
3994
3611
  let forceKillTimer = null;
3995
- const { subprocess } = await launchCommand(options.command, options.cwd, options.timeoutMs, options.abortSignal);
3612
+ const launched = await launchCommand(options.command, options.cwd, options.timeoutMs, options.abortSignal);
3613
+ const { subprocess } = launched;
3996
3614
  const outputCapture = await createBashOutputCapture(options.outputCapture ?? {});
3997
3615
  const clearTimers = () => {
3998
3616
  if (stallTimer) {
@@ -4045,9 +3663,11 @@ async function runCommandOnce(options) {
4045
3663
  const result = await subprocess;
4046
3664
  clearTimers();
4047
3665
  const shellOutput = await outputCapture.finalize();
3666
+ const output = normalizeCommandOutput(shellOutput.outputPreview);
4048
3667
  return {
3668
+ command: options.command,
4049
3669
  exitCode: typeof result.exitCode === "number" ? result.exitCode : null,
4050
- output: shellOutput.outputPreview,
3670
+ output,
4051
3671
  outputPath: shellOutput.outputPath,
4052
3672
  truncated: shellOutput.truncated,
4053
3673
  outputChars: shellOutput.outputChars,
@@ -4062,9 +3682,12 @@ async function runCommandOnce(options) {
4062
3682
  const timedOut = isTimedOutError(error);
4063
3683
  clearTimers();
4064
3684
  const shellOutput = await outputCapture.finalize();
3685
+ const fallbackOutput = shellOutput.outputChars > 0 ? shellOutput.outputPreview : readProcessOutput(error);
3686
+ const output = normalizeCommandOutput(fallbackOutput);
4065
3687
  return {
3688
+ command: options.command,
4066
3689
  exitCode: readExitCode(error),
4067
- output: shellOutput.outputChars > 0 ? shellOutput.outputPreview : readProcessOutput(error),
3690
+ output,
4068
3691
  outputPath: shellOutput.outputPath,
4069
3692
  truncated: shellOutput.truncated,
4070
3693
  outputChars: shellOutput.outputChars,
@@ -4625,7 +4248,7 @@ var bashToolDefinition = {
4625
4248
  const status = result.aborted ? "aborted" : result.stalled ? "stalled" : result.timedOut ? "timed_out" : result.exitCode === 0 ? "completed" : "failed";
4626
4249
  const outputGovernance = governToolOutput({
4627
4250
  toolName: "bash",
4628
- command,
4251
+ command: result.command,
4629
4252
  status,
4630
4253
  exitCode: result.exitCode,
4631
4254
  durationMs: result.durationMs,
@@ -4653,7 +4276,7 @@ var bashToolDefinition = {
4653
4276
  return okResult(
4654
4277
  JSON.stringify(
4655
4278
  {
4656
- command,
4279
+ command: result.command,
4657
4280
  cwd: resolvedCwd,
4658
4281
  exitCode: result.exitCode,
4659
4282
  status,
@@ -6100,6 +5723,53 @@ async function executeToolBatch(params) {
6100
5723
  };
6101
5724
  }
6102
5725
 
5726
+ // src/session/events.ts
5727
+ import fs15 from "fs/promises";
5728
+ import path15 from "path";
5729
+ var SessionEventStore = class {
5730
+ constructor(eventsDir) {
5731
+ this.eventsDir = eventsDir;
5732
+ }
5733
+ async append(event) {
5734
+ const record = {
5735
+ id: createEventId(),
5736
+ createdAt: event.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
5737
+ type: event.type,
5738
+ sessionId: event.sessionId,
5739
+ cwd: event.cwd,
5740
+ host: event.host,
5741
+ message: event.message,
5742
+ details: event.details
5743
+ };
5744
+ await fs15.mkdir(this.eventsDir, { recursive: true });
5745
+ await fs15.appendFile(this.getSessionEventPath(event.sessionId), `${JSON.stringify(record)}
5746
+ `, "utf8");
5747
+ return record;
5748
+ }
5749
+ async list(sessionId, limit = 100) {
5750
+ const filePath = this.getSessionEventPath(sessionId);
5751
+ let raw = "";
5752
+ try {
5753
+ raw = await fs15.readFile(filePath, "utf8");
5754
+ } catch (error) {
5755
+ if (error.code === "ENOENT") {
5756
+ return [];
5757
+ }
5758
+ throw error;
5759
+ }
5760
+ return raw.split(/\r?\n/).filter(Boolean).map((line) => JSON.parse(line)).slice(-limit);
5761
+ }
5762
+ getSessionEventPath(sessionId) {
5763
+ return path15.join(this.eventsDir, `${sanitizeSessionId(sessionId)}.jsonl`);
5764
+ }
5765
+ };
5766
+ function createEventId() {
5767
+ return `${(/* @__PURE__ */ new Date()).toISOString().replace(/[-:.TZ]/g, "").slice(0, 14)}-${Math.random().toString(16).slice(2, 10)}`;
5768
+ }
5769
+ function sanitizeSessionId(sessionId) {
5770
+ return sessionId.replace(/[^a-zA-Z0-9_.-]/g, "_");
5771
+ }
5772
+
6103
5773
  // src/agent/turn/toolFailure.ts
6104
5774
  function readToolFailureError(output) {
6105
5775
  try {
@@ -6135,9 +5805,16 @@ async function processToolCallBatch(input) {
6135
5805
  const batchToolMessages = [];
6136
5806
  const batchModelOutputs = [];
6137
5807
  const batchChangedPaths = /* @__PURE__ */ new Set();
5808
+ const sessionEvents = new SessionEventStore(options.config.paths.eventsDir);
6138
5809
  const leadWaitExecutionsBefore = identity.kind === "lead" ? listLeadWaitExecutions(projectContext.stateRootDir) : [];
6139
5810
  for (const toolCall of response.toolCalls) {
6140
5811
  throwIfAborted(options.abortSignal, "Turn aborted by user.");
5812
+ await sessionEvents.append({
5813
+ type: "tool.started",
5814
+ sessionId: session.id,
5815
+ cwd: options.cwd,
5816
+ details: buildToolStartedEventDetails(toolCall, identity)
5817
+ });
6141
5818
  options.callbacks?.onToolCall?.(toolCall.function.name, toolCall.function.arguments);
6142
5819
  await recordObservabilityEvent(projectContext.stateRootDir, {
6143
5820
  event: "tool.execution",
@@ -6171,6 +5848,7 @@ async function processToolCallBatch(input) {
6171
5848
  } else if (metadata?.sessionDiff) {
6172
5849
  session = await options.sessionStore.save(noteSessionDiff(session, metadata.sessionDiff));
6173
5850
  }
5851
+ const failureError = result.ok ? void 0 : readToolFailureError(result.output);
6174
5852
  await recordObservabilityEvent(projectContext.stateRootDir, {
6175
5853
  event: "tool.execution",
6176
5854
  status: result.ok ? "completed" : "failed",
@@ -6179,11 +5857,23 @@ async function processToolCallBatch(input) {
6179
5857
  identityName: identity.name,
6180
5858
  toolName: toolCall.function.name,
6181
5859
  durationMs,
6182
- error: result.ok ? void 0 : readToolFailureError(result.output),
5860
+ error: failureError,
6183
5861
  details: {
6184
5862
  changedPathCount: metadata?.changedPaths?.length ?? 0
6185
5863
  }
6186
5864
  });
5865
+ await sessionEvents.append({
5866
+ type: result.ok ? "tool.completed" : "tool.failed",
5867
+ sessionId: session.id,
5868
+ cwd: options.cwd,
5869
+ details: buildToolFinishedEventDetails({
5870
+ toolCall,
5871
+ identity,
5872
+ durationMs,
5873
+ changedPathCount: metadata?.changedPaths?.length ?? 0,
5874
+ error: failureError ? formatToolFailureError(failureError) : void 0
5875
+ })
5876
+ });
6187
5877
  if (metadata?.outputGovernance) {
6188
5878
  await recordObservabilityEvent(projectContext.stateRootDir, {
6189
5879
  event: "tool.output",
@@ -6277,6 +5967,33 @@ async function processToolCallBatch(input) {
6277
5967
  }
6278
5968
  };
6279
5969
  }
5970
+ function buildToolStartedEventDetails(toolCall, identity) {
5971
+ return {
5972
+ toolName: toolCall.function.name,
5973
+ toolCallId: toolCall.id,
5974
+ identityKind: identity.kind,
5975
+ identityName: identity.name,
5976
+ argumentsPreview: previewToolArguments(toolCall.function.arguments)
5977
+ };
5978
+ }
5979
+ function buildToolFinishedEventDetails(input) {
5980
+ return {
5981
+ toolName: input.toolCall.function.name,
5982
+ toolCallId: input.toolCall.id,
5983
+ identityKind: input.identity.kind,
5984
+ identityName: input.identity.name,
5985
+ durationMs: input.durationMs,
5986
+ changedPathCount: input.changedPathCount,
5987
+ error: input.error
5988
+ };
5989
+ }
5990
+ function previewToolArguments(rawArgs) {
5991
+ const normalized = rawArgs.replace(/\s+/g, " ").trim();
5992
+ return normalized.length > 240 ? `${normalized.slice(0, 237)}...` : normalized;
5993
+ }
5994
+ function formatToolFailureError(error) {
5995
+ return error.code ? `${error.code}: ${error.message}` : error.message;
5996
+ }
6280
5997
 
6281
5998
  // src/agent/turn/toolless.ts
6282
5999
  async function resolveToollessTurn(params) {
@@ -6363,8 +6080,8 @@ function normalizeToolArguments(raw) {
6363
6080
 
6364
6081
  // src/agent/changes/store.ts
6365
6082
  import crypto2 from "crypto";
6366
- import fs15 from "fs/promises";
6367
- import path15 from "path";
6083
+ import fs16 from "fs/promises";
6084
+ import path16 from "path";
6368
6085
  var ChangeStore = class {
6369
6086
  constructor(changesDir) {
6370
6087
  this.changesDir = changesDir;
@@ -6372,8 +6089,8 @@ var ChangeStore = class {
6372
6089
  async record(input) {
6373
6090
  const id = createChangeId();
6374
6091
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
6375
- const blobDir = path15.join(this.changesDir, id);
6376
- await fs15.mkdir(blobDir, { recursive: true });
6092
+ const blobDir = path16.join(this.changesDir, id);
6093
+ await fs16.mkdir(blobDir, { recursive: true });
6377
6094
  const operations = await Promise.all(
6378
6095
  input.operations.map(async (operation, index) => {
6379
6096
  const beforeSnapshotPath = await this.writeSnapshot(
@@ -6413,21 +6130,21 @@ var ChangeStore = class {
6413
6130
  preview: input.preview,
6414
6131
  operations
6415
6132
  };
6416
- await fs15.mkdir(this.changesDir, { recursive: true });
6417
- await fs15.writeFile(this.getMetadataPath(id), `${JSON.stringify(record, null, 2)}
6133
+ await fs16.mkdir(this.changesDir, { recursive: true });
6134
+ await fs16.writeFile(this.getMetadataPath(id), `${JSON.stringify(record, null, 2)}
6418
6135
  `, "utf8");
6419
6136
  return record;
6420
6137
  }
6421
6138
  async list(limit = 20) {
6422
- await fs15.mkdir(this.changesDir, { recursive: true });
6423
- const entries = await fs15.readdir(this.changesDir, { withFileTypes: true });
6139
+ await fs16.mkdir(this.changesDir, { recursive: true });
6140
+ const entries = await fs16.readdir(this.changesDir, { withFileTypes: true });
6424
6141
  const changes = await Promise.all(
6425
- entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map(async (entry) => this.load(path15.basename(entry.name, ".json")))
6142
+ entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map(async (entry) => this.load(path16.basename(entry.name, ".json")))
6426
6143
  );
6427
6144
  return changes.sort((left, right) => right.createdAt.localeCompare(left.createdAt)).slice(0, limit);
6428
6145
  }
6429
6146
  async load(id) {
6430
- const raw = await fs15.readFile(this.getMetadataPath(id), "utf8");
6147
+ const raw = await fs16.readFile(this.getMetadataPath(id), "utf8");
6431
6148
  return JSON.parse(raw);
6432
6149
  }
6433
6150
  async loadLatestUndoable() {
@@ -6451,17 +6168,17 @@ var ChangeStore = class {
6451
6168
  restoredPaths.push(operation.path);
6452
6169
  if (operation.beforeSnapshotPath) {
6453
6170
  const buffer = await this.readSnapshot(operation.beforeSnapshotPath);
6454
- await fs15.mkdir(path15.dirname(operation.path), { recursive: true });
6455
- await fs15.writeFile(operation.path, buffer);
6171
+ await fs16.mkdir(path16.dirname(operation.path), { recursive: true });
6172
+ await fs16.writeFile(operation.path, buffer);
6456
6173
  continue;
6457
6174
  }
6458
- await fs15.rm(operation.path, { force: true });
6175
+ await fs16.rm(operation.path, { force: true });
6459
6176
  }
6460
6177
  const updated = {
6461
6178
  ...record,
6462
6179
  undoneAt: (/* @__PURE__ */ new Date()).toISOString()
6463
6180
  };
6464
- await fs15.writeFile(this.getMetadataPath(updated.id), `${JSON.stringify(updated, null, 2)}
6181
+ await fs16.writeFile(this.getMetadataPath(updated.id), `${JSON.stringify(updated, null, 2)}
6465
6182
  `, "utf8");
6466
6183
  return {
6467
6184
  record: updated,
@@ -6469,19 +6186,19 @@ var ChangeStore = class {
6469
6186
  };
6470
6187
  }
6471
6188
  getMetadataPath(id) {
6472
- return path15.join(this.changesDir, `${id}.json`);
6189
+ return path16.join(this.changesDir, `${id}.json`);
6473
6190
  }
6474
6191
  async writeSnapshot(blobDir, label, buffer) {
6475
6192
  if (!buffer) {
6476
6193
  return void 0;
6477
6194
  }
6478
6195
  const fileName = `${label}.bin`;
6479
- const absolutePath = path15.join(blobDir, fileName);
6480
- await fs15.writeFile(absolutePath, buffer);
6481
- return path15.relative(this.changesDir, absolutePath);
6196
+ const absolutePath = path16.join(blobDir, fileName);
6197
+ await fs16.writeFile(absolutePath, buffer);
6198
+ return path16.relative(this.changesDir, absolutePath);
6482
6199
  }
6483
6200
  async readSnapshot(relativePath) {
6484
- return fs15.readFile(path15.join(this.changesDir, relativePath));
6201
+ return fs16.readFile(path16.join(this.changesDir, relativePath));
6485
6202
  }
6486
6203
  };
6487
6204
  function createChangeId() {
@@ -6867,9 +6584,10 @@ var backgroundRunTool = {
6867
6584
  registerBackgroundProcess(job.id, subprocess);
6868
6585
  store.markRunning(job.id, { pid: subprocess.pid ?? 0 });
6869
6586
  const outputTracker = createBackgroundOutputTracker((output) => {
6587
+ const normalizedOutput = normalizeCommandOutput(output);
6870
6588
  store.updateRunningOutput(job.id, {
6871
- output,
6872
- summary: summarizeBackgroundOutput(output),
6589
+ output: normalizedOutput,
6590
+ summary: summarizeBackgroundOutput(normalizedOutput),
6873
6591
  lastOutputAt: (/* @__PURE__ */ new Date()).toISOString()
6874
6592
  });
6875
6593
  });
@@ -6879,7 +6597,7 @@ var backgroundRunTool = {
6879
6597
  void subprocess.then(async (result) => {
6880
6598
  outputTracker.flush();
6881
6599
  const running2 = store.load(job.id);
6882
- const resultOutput = typeof result.all === "string" ? result.all : "";
6600
+ const resultOutput = normalizeCommandOutput(typeof result.all === "string" ? result.all : "");
6883
6601
  const output = resultOutput || running2?.output || "";
6884
6602
  store.close(job.id, {
6885
6603
  status: result.exitCode === 0 ? "completed" : "failed",
@@ -6891,7 +6609,7 @@ var backgroundRunTool = {
6891
6609
  }, async (error) => {
6892
6610
  outputTracker.flush();
6893
6611
  const running2 = store.load(job.id);
6894
- const errorOutput = typeof error.all === "string" ? error.all : "";
6612
+ const errorOutput = normalizeCommandOutput(typeof error.all === "string" ? error.all : "");
6895
6613
  const output = errorOutput || running2?.output || String(error.message);
6896
6614
  store.close(job.id, {
6897
6615
  status: "failed",
@@ -7059,20 +6777,20 @@ function createBackgroundTools() {
7059
6777
  }
7060
6778
 
7061
6779
  // src/extensions/tools/network/tools/downloadUrl.ts
7062
- import fs17 from "fs/promises";
6780
+ import fs18 from "fs/promises";
7063
6781
 
7064
6782
  // src/extensions/shared.ts
7065
- import fs16 from "fs/promises";
7066
- import path16 from "path";
6783
+ import fs17 from "fs/promises";
6784
+ import path17 from "path";
7067
6785
  async function ensureExtensionDir(rootDir, extensionId) {
7068
6786
  const paths = await ensureProjectStateDirectories(rootDir);
7069
- const dir = path16.join(paths.extensionsDir, extensionId);
7070
- await fs16.mkdir(dir, { recursive: true });
6787
+ const dir = path17.join(paths.extensionsDir, extensionId);
6788
+ await fs17.mkdir(dir, { recursive: true });
7071
6789
  return dir;
7072
6790
  }
7073
6791
  async function readJsonFile(filePath, fallback) {
7074
6792
  try {
7075
- return JSON.parse(await fs16.readFile(filePath, "utf8"));
6793
+ return JSON.parse(await fs17.readFile(filePath, "utf8"));
7076
6794
  } catch (error) {
7077
6795
  if (error.code === "ENOENT") {
7078
6796
  return fallback;
@@ -7081,8 +6799,8 @@ async function readJsonFile(filePath, fallback) {
7081
6799
  }
7082
6800
  }
7083
6801
  async function writeJsonFile(filePath, value) {
7084
- await fs16.mkdir(path16.dirname(filePath), { recursive: true });
7085
- await fs16.writeFile(filePath, `${JSON.stringify(value, null, 2)}
6802
+ await fs17.mkdir(path17.dirname(filePath), { recursive: true });
6803
+ await fs17.writeFile(filePath, `${JSON.stringify(value, null, 2)}
7086
6804
  `, "utf8");
7087
6805
  }
7088
6806
  function jsonResult(value) {
@@ -7098,7 +6816,7 @@ function sanitizeStateSegment(value) {
7098
6816
  }
7099
6817
 
7100
6818
  // src/extensions/tools/network/session.ts
7101
- import path17 from "path";
6819
+ import path18 from "path";
7102
6820
  async function listHttpSessions(rootDir) {
7103
6821
  const state = await readJsonFile(await sessionFile(rootDir), { sessions: [] });
7104
6822
  return Array.isArray(state.sessions) ? state.sessions.map(normalizeSession) : [];
@@ -7123,7 +6841,7 @@ async function getHttpSessionStateFile(rootDir) {
7123
6841
  return sessionFile(rootDir);
7124
6842
  }
7125
6843
  async function sessionFile(rootDir) {
7126
- return path17.join(await ensureExtensionDir(rootDir, "network"), "http-sessions.json");
6844
+ return path18.join(await ensureExtensionDir(rootDir, "network"), "http-sessions.json");
7127
6845
  }
7128
6846
  function normalizeSession(value) {
7129
6847
  return {
@@ -7352,7 +7070,7 @@ var downloadUrlTool = {
7352
7070
  }
7353
7071
  const bytes = Buffer.from(await response.arrayBuffer());
7354
7072
  await ensureParentDirectory(targetPath);
7355
- await fs17.writeFile(targetPath, bytes);
7073
+ await fs18.writeFile(targetPath, bytes);
7356
7074
  return changedJsonResult({
7357
7075
  ok: response.ok,
7358
7076
  url,
@@ -7417,17 +7135,17 @@ var httpProbeTool = {
7417
7135
  };
7418
7136
 
7419
7137
  // src/extensions/tools/network/traceStore.ts
7420
- import fs18 from "fs/promises";
7421
- import path18 from "path";
7138
+ import fs19 from "fs/promises";
7139
+ import path19 from "path";
7422
7140
  async function writeNetworkTrace(rootDir, traceId, record) {
7423
7141
  const filePath = await networkTraceFilePath(rootDir, traceId);
7424
- await fs18.mkdir(path18.dirname(filePath), { recursive: true });
7425
- await fs18.writeFile(filePath, `${JSON.stringify(record, null, 2)}
7142
+ await fs19.mkdir(path19.dirname(filePath), { recursive: true });
7143
+ await fs19.writeFile(filePath, `${JSON.stringify(record, null, 2)}
7426
7144
  `, "utf8");
7427
7145
  return filePath;
7428
7146
  }
7429
7147
  async function networkTraceFilePath(rootDir, traceId) {
7430
- return path18.join(await ensureExtensionDir(rootDir, "network"), "traces", `${sanitizeStateSegment(traceId)}.json`);
7148
+ return path19.join(await ensureExtensionDir(rootDir, "network"), "traces", `${sanitizeStateSegment(traceId)}.json`);
7431
7149
  }
7432
7150
 
7433
7151
  // src/extensions/tools/network/tools/httpRequest.ts
@@ -7827,14 +7545,14 @@ function readStringMap2(value) {
7827
7545
  }
7828
7546
 
7829
7547
  // src/extensions/tools/network/openapi.ts
7830
- import fs19 from "fs/promises";
7548
+ import fs20 from "fs/promises";
7831
7549
  async function loadOpenApiDocument(source, context) {
7832
7550
  const normalizedSource = source.trim();
7833
7551
  if (!normalizedSource) {
7834
7552
  throw new ToolExecutionError("OpenAPI source is required.", { code: "OPENAPI_SOURCE_INVALID" });
7835
7553
  }
7836
7554
  const resolvedSource = /^https?:\/\//i.test(normalizedSource) ? normalizedSource : resolveUserPath(normalizedSource, context.cwd);
7837
- const raw = /^https?:\/\//i.test(normalizedSource) ? await (await fetchWithTimeout(normalizedSource, { method: "GET" }, 2e4, context.abortSignal)).text() : stripBom(await fs19.readFile(resolvedSource, "utf8"));
7555
+ const raw = /^https?:\/\//i.test(normalizedSource) ? await (await fetchWithTimeout(normalizedSource, { method: "GET" }, 2e4, context.abortSignal)).text() : stripBom(await fs20.readFile(resolvedSource, "utf8"));
7838
7556
  const parsed = parseOpenApiDocument(raw, normalizedSource);
7839
7557
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
7840
7558
  throw new ToolExecutionError("OpenAPI document root must be an object.", { code: "OPENAPI_ROOT_INVALID" });
@@ -8182,8 +7900,8 @@ async function recordSkillUse(rootDir, input) {
8182
7900
  }
8183
7901
 
8184
7902
  // src/extensions/tools/skills/tools/skillReadResource.ts
8185
- import fs20 from "fs/promises";
8186
- import path19 from "path";
7903
+ import fs21 from "fs/promises";
7904
+ import path20 from "path";
8187
7905
  var MAX_RESOURCE_CHARS = 24e3;
8188
7906
  var skillReadResourceTool = {
8189
7907
  definition: {
@@ -8220,8 +7938,8 @@ var skillReadResourceTool = {
8220
7938
  if (!resource) {
8221
7939
  throw new Error(`Skill "${name}" does not declare resource: ${requestedPath}`);
8222
7940
  }
8223
- const absolutePath = path19.resolve(context.projectContext.rootDir, resource.path);
8224
- const content = await fs20.readFile(absolutePath, "utf8");
7941
+ const absolutePath = path20.resolve(context.projectContext.rootDir, resource.path);
7942
+ const content = await fs21.readFile(absolutePath, "utf8");
8225
7943
  return jsonResult({
8226
7944
  ok: true,
8227
7945
  skill: {
@@ -8239,7 +7957,7 @@ function normalizeResourcePath(value) {
8239
7957
  }
8240
7958
 
8241
7959
  // src/extensions/tools/skills/tools/skillRunScript.ts
8242
- import path20 from "path";
7960
+ import path21 from "path";
8243
7961
  var skillRunScriptTool = {
8244
7962
  definition: {
8245
7963
  type: "function",
@@ -8283,12 +8001,12 @@ var skillRunScriptTool = {
8283
8001
  if (!resource) {
8284
8002
  throw new Error(`Skill "${name}" does not declare script resource: ${requestedPath}`);
8285
8003
  }
8286
- const skillDir = path20.dirname(skill.path);
8287
- const relativeToSkill = normalizeResourcePath2(path20.relative(skillDir, resource.path));
8004
+ const skillDir = path21.dirname(skill.path);
8005
+ const relativeToSkill = normalizeResourcePath2(path21.relative(skillDir, resource.path));
8288
8006
  if (!relativeToSkill.startsWith("scripts/")) {
8289
8007
  throw new Error(`Skill "${name}" resource is not executable because it is outside scripts/: ${requestedPath}`);
8290
8008
  }
8291
- const scriptPath = path20.resolve(context.projectContext.rootDir, resource.path);
8009
+ const scriptPath = path21.resolve(context.projectContext.rootDir, resource.path);
8292
8010
  const argumentText = typeof args.args === "string" ? args.args.trim() : "";
8293
8011
  const command = buildScriptCommand(scriptPath, argumentText);
8294
8012
  const result = await runCommandWithPolicy({
@@ -8363,7 +8081,7 @@ function quotePath(value) {
8363
8081
  return `"${value.replace(/"/g, '\\"')}"`;
8364
8082
  }
8365
8083
  function buildScriptCommand(scriptPath, argumentText) {
8366
- const extension = path20.extname(scriptPath).toLowerCase();
8084
+ const extension = path21.extname(scriptPath).toLowerCase();
8367
8085
  const quoted = quotePath(scriptPath);
8368
8086
  const suffix = argumentText ? ` ${argumentText}` : "";
8369
8087
  if (extension === ".js" || extension === ".mjs" || extension === ".cjs") {
@@ -8417,12 +8135,12 @@ var subagentCheckTool = {
8417
8135
 
8418
8136
  // src/execution/launch.ts
8419
8137
  import { spawn } from "child_process";
8420
- import path21 from "path";
8138
+ import path22 from "path";
8421
8139
  function spawnExecutionWorker(input) {
8422
8140
  if (process.env.KITTY_TEST_WORKER_MODE === "stub") {
8423
8141
  return process.pid;
8424
8142
  }
8425
- const cliEntry = path21.resolve(process.argv[1] ?? "");
8143
+ const cliEntry = path22.resolve(process.argv[1] ?? "");
8426
8144
  if (!cliEntry) {
8427
8145
  throw new Error("Unable to locate Kitty CLI entrypoint for execution worker.");
8428
8146
  }
@@ -8628,7 +8346,7 @@ function parseWorktreeBlock(block) {
8628
8346
  }
8629
8347
 
8630
8348
  // src/extensions/tools/worktree/state.ts
8631
- import path22 from "path";
8349
+ import path23 from "path";
8632
8350
  async function readWorktreeState(rootDir) {
8633
8351
  return normalizeWorktreeState(await readJsonFile(await stateFile(rootDir), {
8634
8352
  schemaVersion: 1,
@@ -8651,7 +8369,7 @@ async function recordWorktreeEvent(rootDir, event) {
8651
8369
  return writeWorktreeState(rootDir, state);
8652
8370
  }
8653
8371
  async function stateFile(rootDir) {
8654
- return path22.join(await ensureExtensionDir(rootDir, "worktree"), "state.json");
8372
+ return path23.join(await ensureExtensionDir(rootDir, "worktree"), "state.json");
8655
8373
  }
8656
8374
  function normalizeWorktreeState(value) {
8657
8375
  return {
@@ -9274,8 +8992,8 @@ function looksLikeToolProtocolText(content) {
9274
8992
  }
9275
8993
 
9276
8994
  // src/observability/crashRecorder.ts
9277
- import fs21 from "fs";
9278
- import path23 from "path";
8995
+ import fs22 from "fs";
8996
+ import path24 from "path";
9279
8997
  var activeCrashContexts = /* @__PURE__ */ new Map();
9280
8998
  var nextCrashContextId = 0;
9281
8999
  function enterCrashContext(context) {
@@ -9287,7 +9005,7 @@ function enterCrashContext(context) {
9287
9005
  }
9288
9006
 
9289
9007
  // src/observability/hostEvents.ts
9290
- import path24 from "path";
9008
+ import path25 from "path";
9291
9009
  async function recordHostTurnStarted(rootDir, input) {
9292
9010
  await recordObservabilityEvent(rootDir, {
9293
9011
  event: "host.turn",
@@ -9318,53 +9036,6 @@ async function recordHostTurnFinished(rootDir, input) {
9318
9036
  });
9319
9037
  }
9320
9038
 
9321
- // src/session/events.ts
9322
- import fs22 from "fs/promises";
9323
- import path25 from "path";
9324
- var SessionEventStore = class {
9325
- constructor(eventsDir) {
9326
- this.eventsDir = eventsDir;
9327
- }
9328
- async append(event) {
9329
- const record = {
9330
- id: createEventId(),
9331
- createdAt: event.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
9332
- type: event.type,
9333
- sessionId: event.sessionId,
9334
- cwd: event.cwd,
9335
- host: event.host,
9336
- message: event.message,
9337
- details: event.details
9338
- };
9339
- await fs22.mkdir(this.eventsDir, { recursive: true });
9340
- await fs22.appendFile(this.getSessionEventPath(event.sessionId), `${JSON.stringify(record)}
9341
- `, "utf8");
9342
- return record;
9343
- }
9344
- async list(sessionId, limit = 100) {
9345
- const filePath = this.getSessionEventPath(sessionId);
9346
- let raw = "";
9347
- try {
9348
- raw = await fs22.readFile(filePath, "utf8");
9349
- } catch (error) {
9350
- if (error.code === "ENOENT") {
9351
- return [];
9352
- }
9353
- throw error;
9354
- }
9355
- return raw.split(/\r?\n/).filter(Boolean).map((line) => JSON.parse(line)).slice(-limit);
9356
- }
9357
- getSessionEventPath(sessionId) {
9358
- return path25.join(this.eventsDir, `${sanitizeSessionId(sessionId)}.jsonl`);
9359
- }
9360
- };
9361
- function createEventId() {
9362
- return `${(/* @__PURE__ */ new Date()).toISOString().replace(/[-:.TZ]/g, "").slice(0, 14)}-${Math.random().toString(16).slice(2, 10)}`;
9363
- }
9364
- function sanitizeSessionId(sessionId) {
9365
- return sessionId.replace(/[^a-zA-Z0-9_.-]/g, "_");
9366
- }
9367
-
9368
9039
  // src/host/toolRegistry.ts
9369
9040
  async function createHostToolRegistry(config, options = {}) {
9370
9041
  const extraTools = options.extraTools ?? [];
@@ -10293,6 +9964,7 @@ export {
10293
9964
  getErrorMessage,
10294
9965
  ControlPlaneLedger,
10295
9966
  ExecutionStore,
9967
+ SessionEventStore,
10296
9968
  isProcessAlive,
10297
9969
  terminatePid,
10298
9970
  BackgroundExecutionStore,
@@ -10301,12 +9973,14 @@ export {
10301
9973
  summarizeExecution,
10302
9974
  summarizeExecutionSet,
10303
9975
  EXTENSION_ENV_KEYS,
10304
- SessionEventStore,
10305
9976
  runHostTurn,
10306
9977
  writeStdout,
10307
9978
  writeStdoutLine,
10308
9979
  writeStderrLine,
10309
9980
  createRuntimeUiEvent,
9981
+ tryParseJson,
9982
+ buildToolCallDisplay,
9983
+ buildToolResultDisplay,
10310
9984
  colorRuntimeUiText,
10311
9985
  createRuntimeUiTerminalRenderer,
10312
9986
  formatRuntimeUiEventLine