@jun133/kitty 0.0.12 → 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.
package/dist/cli.js CHANGED
@@ -40,7 +40,7 @@ var init_package = __esm({
40
40
  "package.json"() {
41
41
  package_default = {
42
42
  name: "@jun133/kitty",
43
- version: "0.0.12",
43
+ version: "0.0.14",
44
44
  description: "Agent",
45
45
  license: "MIT",
46
46
  keywords: [
@@ -1917,14 +1917,21 @@ async function launchCommand(command, cwd, timeoutMs, abortSignal) {
1917
1917
  function encodePowerShellCommand(command) {
1918
1918
  const wrapped = [
1919
1919
  "$ProgressPreference = 'SilentlyContinue'",
1920
+ "$ErrorActionPreference = 'Stop'",
1920
1921
  "[Console]::InputEncoding = [System.Text.Encoding]::UTF8",
1921
1922
  "[Console]::OutputEncoding = [System.Text.Encoding]::UTF8",
1922
1923
  "$OutputEncoding = [System.Text.Encoding]::UTF8",
1923
1924
  "try { chcp 65001 > $null } catch { }",
1925
+ "$code = 0",
1926
+ "try {",
1924
1927
  `& { ${command} }`,
1925
1928
  "$code = if ($null -ne $LASTEXITCODE) { [int]$LASTEXITCODE } elseif ($?) { 0 } else { 1 }",
1929
+ "} catch {",
1930
+ "[Console]::Error.WriteLine($_.Exception.Message)",
1931
+ "$code = 1",
1932
+ "}",
1926
1933
  "exit $code"
1927
- ].join("; ");
1934
+ ].join("\n");
1928
1935
  return Buffer.from(wrapped, "utf16le").toString("base64");
1929
1936
  }
1930
1937
  function buildCommandEnvironment() {
@@ -1943,6 +1950,26 @@ var init_launch = __esm({
1943
1950
  }
1944
1951
  });
1945
1952
 
1953
+ // src/utils/commandRunner/output.ts
1954
+ function normalizeCommandOutput(output) {
1955
+ if (!output.includes("#< CLIXML")) {
1956
+ return output;
1957
+ }
1958
+ const errors = [...output.matchAll(/<S\s+S="Error">([\s\S]*?)<\/S>/g)].map((match) => decodePowerShellText(match[1] ?? "")).map((line) => line.trimEnd()).filter(Boolean);
1959
+ if (errors.length === 0) {
1960
+ return output;
1961
+ }
1962
+ return errors.join("\n").replace(/\n{3,}/g, "\n\n").trim();
1963
+ }
1964
+ function decodePowerShellText(value) {
1965
+ 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, "&");
1966
+ }
1967
+ var init_output = __esm({
1968
+ "src/utils/commandRunner/output.ts"() {
1969
+ "use strict";
1970
+ }
1971
+ });
1972
+
1946
1973
  // src/extensions/tools/background/tools/backgroundRun.ts
1947
1974
  function createBackgroundOutputTracker(onOutput) {
1948
1975
  let buffer = "";
@@ -1978,6 +2005,7 @@ var init_backgroundRun = __esm({
1978
2005
  "src/extensions/tools/background/tools/backgroundRun.ts"() {
1979
2006
  "use strict";
1980
2007
  init_launch();
2008
+ init_output();
1981
2009
  init_fs();
1982
2010
  init_shared2();
1983
2011
  init_background();
@@ -2016,9 +2044,10 @@ var init_backgroundRun = __esm({
2016
2044
  registerBackgroundProcess(job.id, subprocess);
2017
2045
  store.markRunning(job.id, { pid: subprocess.pid ?? 0 });
2018
2046
  const outputTracker = createBackgroundOutputTracker((output) => {
2047
+ const normalizedOutput = normalizeCommandOutput(output);
2019
2048
  store.updateRunningOutput(job.id, {
2020
- output,
2021
- summary: summarizeBackgroundOutput(output),
2049
+ output: normalizedOutput,
2050
+ summary: summarizeBackgroundOutput(normalizedOutput),
2022
2051
  lastOutputAt: (/* @__PURE__ */ new Date()).toISOString()
2023
2052
  });
2024
2053
  });
@@ -2028,7 +2057,7 @@ var init_backgroundRun = __esm({
2028
2057
  void subprocess.then(async (result) => {
2029
2058
  outputTracker.flush();
2030
2059
  const running2 = store.load(job.id);
2031
- const resultOutput = typeof result.all === "string" ? result.all : "";
2060
+ const resultOutput = normalizeCommandOutput(typeof result.all === "string" ? result.all : "");
2032
2061
  const output = resultOutput || running2?.output || "";
2033
2062
  store.close(job.id, {
2034
2063
  status: result.exitCode === 0 ? "completed" : "failed",
@@ -2040,7 +2069,7 @@ var init_backgroundRun = __esm({
2040
2069
  }, async (error) => {
2041
2070
  outputTracker.flush();
2042
2071
  const running2 = store.load(job.id);
2043
- const errorOutput = typeof error.all === "string" ? error.all : "";
2072
+ const errorOutput = normalizeCommandOutput(typeof error.all === "string" ? error.all : "");
2044
2073
  const output = errorOutput || running2?.output || String(error.message);
2045
2074
  store.close(job.id, {
2046
2075
  status: "failed",
@@ -3878,439 +3907,17 @@ var init_outputCapture = __esm({
3878
3907
  }
3879
3908
  });
3880
3909
 
3881
- // src/utils/commandRunner/platformArgs.ts
3882
- function splitByAndAnd(command) {
3883
- const segments = [];
3884
- let current = "";
3885
- let inSingle = false;
3886
- let inDouble = false;
3887
- for (let index = 0; index < command.length; index += 1) {
3888
- const char = command.charAt(index);
3889
- if (char === "'" && !inDouble) {
3890
- inSingle = !inSingle;
3891
- current += char;
3892
- continue;
3893
- }
3894
- if (char === '"' && !inSingle) {
3895
- inDouble = !inDouble;
3896
- current += char;
3897
- continue;
3898
- }
3899
- if (!inSingle && !inDouble && char === "&" && command.charAt(index + 1) === "&") {
3900
- if (current.trim()) {
3901
- segments.push(current.trim());
3902
- }
3903
- current = "";
3904
- index += 1;
3905
- continue;
3906
- }
3907
- current += char;
3908
- }
3909
- if (current.trim()) {
3910
- segments.push(current.trim());
3911
- }
3912
- return segments.length > 0 ? segments : [command];
3913
- }
3914
- function joinWithAndSemantics(segments) {
3915
- if (segments.length <= 1) {
3916
- return segments[0] ?? "";
3917
- }
3918
- let script = segments[0] ?? "";
3919
- for (let index = 1; index < segments.length; index += 1) {
3920
- const segment = segments[index];
3921
- script += `; if ($?) { ${segment} }`;
3922
- }
3923
- return script;
3924
- }
3925
- function splitArgs(command) {
3926
- const args = [];
3927
- let current = "";
3928
- let inSingle = false;
3929
- let inDouble = false;
3930
- for (let index = 0; index < command.length; index += 1) {
3931
- const char = command.charAt(index);
3932
- if (char === "'" && !inDouble) {
3933
- inSingle = !inSingle;
3934
- continue;
3935
- }
3936
- if (char === '"' && !inSingle) {
3937
- inDouble = !inDouble;
3938
- continue;
3939
- }
3940
- if (!inSingle && !inDouble && /\s/.test(char)) {
3941
- if (current) {
3942
- args.push(current);
3943
- current = "";
3944
- }
3945
- continue;
3946
- }
3947
- current += char;
3948
- }
3949
- if (current) {
3950
- args.push(current);
3951
- }
3952
- return args;
3953
- }
3954
- function expandPaths(paths) {
3955
- return paths.flatMap((targetPath) => expandBraces(targetPath));
3956
- }
3957
- function normalizeWindowsPath(value) {
3958
- if (value.includes("://")) {
3959
- return value;
3960
- }
3961
- return value.replace(/\//g, "\\");
3962
- }
3963
- function quotePowerShell(value) {
3964
- const escaped = value.replace(/'/g, "''");
3965
- return `'${escaped}'`;
3966
- }
3967
- function expandBraces(input) {
3968
- const start = findBraceStart(input);
3969
- if (start === -1) {
3970
- return [input];
3971
- }
3972
- const end = findMatchingBrace(input, start);
3973
- if (end === -1) {
3974
- return [input];
3975
- }
3976
- const prefix = input.slice(0, start);
3977
- const suffix = input.slice(end + 1);
3978
- const body = input.slice(start + 1, end);
3979
- const parts = splitBraceParts(body);
3980
- const expandedSuffix = expandBraces(suffix);
3981
- const results = [];
3982
- for (const part of parts) {
3983
- for (const expandedPart of expandBraces(part)) {
3984
- for (const tail of expandedSuffix) {
3985
- results.push(`${prefix}${expandedPart}${tail}`);
3986
- }
3987
- }
3988
- }
3989
- return results;
3990
- }
3991
- function findBraceStart(input) {
3992
- let inSingle = false;
3993
- let inDouble = false;
3994
- for (let index = 0; index < input.length; index += 1) {
3995
- const char = input.charAt(index);
3996
- if (char === "'" && !inDouble) {
3997
- inSingle = !inSingle;
3998
- continue;
3999
- }
4000
- if (char === '"' && !inSingle) {
4001
- inDouble = !inDouble;
4002
- continue;
4003
- }
4004
- if (!inSingle && !inDouble && char === "{") {
4005
- return index;
4006
- }
4007
- }
4008
- return -1;
4009
- }
4010
- function findMatchingBrace(input, start) {
4011
- let depth = 0;
4012
- let inSingle = false;
4013
- let inDouble = false;
4014
- for (let index = start; index < input.length; index += 1) {
4015
- const char = input.charAt(index);
4016
- if (char === "'" && !inDouble) {
4017
- inSingle = !inSingle;
4018
- continue;
4019
- }
4020
- if (char === '"' && !inSingle) {
4021
- inDouble = !inDouble;
4022
- continue;
4023
- }
4024
- if (inSingle || inDouble) {
4025
- continue;
4026
- }
4027
- if (char === "{") {
4028
- depth += 1;
4029
- } else if (char === "}") {
4030
- depth -= 1;
4031
- if (depth === 0) {
4032
- return index;
4033
- }
4034
- }
4035
- }
4036
- return -1;
4037
- }
4038
- function splitBraceParts(input) {
4039
- const parts = [];
4040
- let current = "";
4041
- let depth = 0;
4042
- for (let index = 0; index < input.length; index += 1) {
4043
- const char = input.charAt(index);
4044
- if (char === "{") {
4045
- depth += 1;
4046
- current += char;
4047
- continue;
4048
- }
4049
- if (char === "}") {
4050
- depth -= 1;
4051
- current += char;
4052
- continue;
4053
- }
4054
- if (char === "," && depth === 0) {
4055
- parts.push(current);
4056
- current = "";
4057
- continue;
4058
- }
4059
- current += char;
4060
- }
4061
- if (current) {
4062
- parts.push(current);
4063
- }
4064
- return parts.length > 0 ? parts : [input];
4065
- }
4066
- var init_platformArgs = __esm({
4067
- "src/utils/commandRunner/platformArgs.ts"() {
4068
- "use strict";
4069
- }
4070
- });
4071
-
4072
- // src/utils/commandRunner/platformTransforms.ts
4073
- function startsWithExplicitShell(command) {
4074
- return /^\s*(cmd(?:\.exe)?\s+\/c|powershell(?:\.exe)?\b|pwsh\b|bash\b)/i.test(command);
4075
- }
4076
- function normalizeWindowsSegment(segment) {
4077
- const trimmed = segment.trim();
4078
- if (!trimmed) {
4079
- return segment;
4080
- }
4081
- const lowered = trimmed.toLowerCase();
4082
- if (lowered.startsWith("get-childitem") || lowered.startsWith("new-item")) {
4083
- return segment;
4084
- }
4085
- if (lowered.startsWith("ls")) {
4086
- return normalizeLsSegment(trimmed);
4087
- }
4088
- if (lowered.startsWith("mkdir") || lowered.startsWith("md ")) {
4089
- return normalizeMkdirSegment(trimmed);
4090
- }
4091
- if (lowered.startsWith("rm ")) {
4092
- return normalizeRemoveSegment(trimmed);
4093
- }
4094
- if (lowered.startsWith("cp ")) {
4095
- return normalizeCopySegment(trimmed);
4096
- }
4097
- if (lowered.startsWith("mv ")) {
4098
- return normalizeMoveSegment(trimmed);
4099
- }
4100
- if (lowered.startsWith("touch ")) {
4101
- return normalizeTouchSegment(trimmed);
4102
- }
4103
- if (lowered.startsWith("cat ")) {
4104
- return normalizeCatSegment(trimmed);
4105
- }
4106
- return segment;
4107
- }
4108
- function normalizeLsSegment(segment) {
4109
- const args = splitArgs(segment).slice(1);
4110
- const flags = args.filter((arg) => arg.startsWith("-"));
4111
- const paths = args.filter((arg) => !arg.startsWith("-"));
4112
- const force = flags.some((flag) => flag.includes("a"));
4113
- const targetPath = paths[0];
4114
- let command = "Get-ChildItem";
4115
- if (force) {
4116
- command += " -Force";
4117
- }
4118
- if (targetPath) {
4119
- command += ` -LiteralPath ${quotePowerShell(normalizeWindowsPath(targetPath))}`;
4120
- }
4121
- return command;
4122
- }
4123
- function normalizeMkdirSegment(segment) {
4124
- const args = splitArgs(segment);
4125
- if (args.length <= 1) {
4126
- return segment;
4127
- }
4128
- const rest = args.slice(1);
4129
- let hasParents = false;
4130
- const paths = rest.filter((arg) => {
4131
- const lowered = arg.toLowerCase();
4132
- if (lowered === "-p" || lowered === "--parents") {
4133
- hasParents = true;
4134
- return false;
4135
- }
4136
- return true;
4137
- });
4138
- const needsNormalization = hasParents || paths.some((targetPath) => targetPath.includes("{"));
4139
- if (!needsNormalization) {
4140
- return segment;
4141
- }
4142
- const expanded = expandPaths(paths);
4143
- if (expanded.length === 0) {
4144
- return segment;
4145
- }
4146
- const normalizedPaths = expanded.map((targetPath) => quotePowerShell(normalizeWindowsPath(targetPath)));
4147
- return `New-Item -ItemType Directory -Force -Path ${normalizedPaths.join(", ")}`;
4148
- }
4149
- function normalizeRemoveSegment(segment) {
4150
- const args = splitArgs(segment);
4151
- if (args.length <= 1) {
4152
- return segment;
4153
- }
4154
- const flags = args.slice(1).filter((arg) => arg.startsWith("-"));
4155
- const paths = args.slice(1).filter((arg) => !arg.startsWith("-"));
4156
- if (paths.length === 0) {
4157
- return segment;
4158
- }
4159
- const recurse = flags.some((flag) => /r/i.test(flag));
4160
- const force = flags.some((flag) => /f/i.test(flag));
4161
- let command = "Remove-Item";
4162
- if (recurse) {
4163
- command += " -Recurse";
4164
- }
4165
- if (force) {
4166
- command += " -Force";
4167
- }
4168
- command += ` -LiteralPath ${paths.map((targetPath) => quotePowerShell(normalizeWindowsPath(targetPath))).join(", ")}`;
4169
- return command;
4170
- }
4171
- function normalizeCopySegment(segment) {
4172
- const args = splitArgs(segment);
4173
- if (args.length < 3) {
4174
- return segment;
4175
- }
4176
- const flags = args.slice(1).filter((arg) => arg.startsWith("-"));
4177
- const paths = args.slice(1).filter((arg) => !arg.startsWith("-"));
4178
- if (paths.length < 2) {
4179
- return segment;
4180
- }
4181
- const recurse = flags.some((flag) => /r/i.test(flag));
4182
- const force = flags.some((flag) => /f/i.test(flag));
4183
- const destination = paths[paths.length - 1];
4184
- if (!destination) {
4185
- return segment;
4186
- }
4187
- const sources = paths.slice(0, -1);
4188
- let command = "Copy-Item";
4189
- if (recurse) {
4190
- command += " -Recurse";
4191
- }
4192
- if (force) {
4193
- command += " -Force";
4194
- }
4195
- command += ` -Path ${sources.map((targetPath) => quotePowerShell(normalizeWindowsPath(targetPath))).join(", ")}`;
4196
- command += ` -Destination ${quotePowerShell(normalizeWindowsPath(destination))}`;
4197
- return command;
4198
- }
4199
- function normalizeMoveSegment(segment) {
4200
- const args = splitArgs(segment);
4201
- if (args.length < 3) {
4202
- return segment;
4203
- }
4204
- const flags = args.slice(1).filter((arg) => arg.startsWith("-"));
4205
- const paths = args.slice(1).filter((arg) => !arg.startsWith("-"));
4206
- if (paths.length < 2) {
4207
- return segment;
4208
- }
4209
- const force = flags.some((flag) => /f/i.test(flag));
4210
- const destination = paths[paths.length - 1];
4211
- if (!destination) {
4212
- return segment;
4213
- }
4214
- const sources = paths.slice(0, -1);
4215
- let command = "Move-Item";
4216
- if (force) {
4217
- command += " -Force";
4218
- }
4219
- command += ` -Path ${sources.map((targetPath) => quotePowerShell(normalizeWindowsPath(targetPath))).join(", ")}`;
4220
- command += ` -Destination ${quotePowerShell(normalizeWindowsPath(destination))}`;
4221
- return command;
4222
- }
4223
- function normalizeTouchSegment(segment) {
4224
- const args = splitArgs(segment).slice(1);
4225
- if (args.length === 0) {
4226
- return segment;
4227
- }
4228
- const expanded = expandPaths(args);
4229
- if (expanded.length === 0) {
4230
- return segment;
4231
- }
4232
- const paths = expanded.map((targetPath) => quotePowerShell(normalizeWindowsPath(targetPath)));
4233
- return `New-Item -ItemType File -Force -Path ${paths.join(", ")}`;
4234
- }
4235
- function normalizeCatSegment(segment) {
4236
- const args = splitArgs(segment).slice(1);
4237
- if (args.length === 0) {
4238
- return segment;
4239
- }
4240
- const targetPath = args[0];
4241
- if (!targetPath) {
4242
- return segment;
4243
- }
4244
- return `Get-Content -LiteralPath ${quotePowerShell(normalizeWindowsPath(targetPath))}`;
4245
- }
4246
- var init_platformTransforms = __esm({
4247
- "src/utils/commandRunner/platformTransforms.ts"() {
4248
- "use strict";
4249
- init_platformArgs();
4250
- }
4251
- });
4252
-
4253
- // src/utils/commandRunner/platform.ts
4254
- function normalizeCommandForPlatform(command) {
4255
- if (process.platform !== "win32") {
4256
- return command;
4257
- }
4258
- const trimmed = command.trim();
4259
- if (!trimmed) {
4260
- return command;
4261
- }
4262
- const normalized = normalizeWindowsCommand(trimmed);
4263
- return normalizeNpmCommandNames(normalized);
4264
- }
4265
- function normalizeWindowsCommand(command) {
4266
- if (startsWithExplicitShell(command)) {
4267
- return command;
4268
- }
4269
- const segments = splitByAndAnd(command);
4270
- const normalizedSegments = segments.map((segment) => normalizeWindowsSegment(segment));
4271
- return joinWithAndSemantics(normalizedSegments);
4272
- }
4273
- function normalizeNpmCommandNames(command) {
4274
- const commandNames = {
4275
- npm: "npm.cmd",
4276
- npx: "npx.cmd",
4277
- pnpm: "pnpm.cmd",
4278
- yarn: "yarn.cmd"
4279
- };
4280
- const pattern = /(^|[;&|]|\&\&)\s*(npm|npx|pnpm|yarn)(?=\s|$)/gi;
4281
- return command.replace(pattern, (match, prefix, tool) => {
4282
- const replacement = commandNames[String(tool).toLowerCase()];
4283
- if (!replacement) {
4284
- return match;
4285
- }
4286
- if (!prefix) {
4287
- return replacement;
4288
- }
4289
- return `${prefix} ${replacement}`;
4290
- });
4291
- }
4292
- var init_platform = __esm({
4293
- "src/utils/commandRunner/platform.ts"() {
4294
- "use strict";
4295
- init_platformArgs();
4296
- init_platformTransforms();
4297
- }
4298
- });
4299
-
4300
3910
  // src/utils/commandRunner/run.ts
4301
3911
  async function runCommandWithPolicy(options) {
4302
- const normalizedCommand = normalizeCommandForPlatform(options.command);
4303
- return runCommandOnce({
4304
- ...options,
4305
- command: normalizedCommand
4306
- });
3912
+ return runCommandOnce(options);
4307
3913
  }
4308
3914
  async function runCommandOnce(options) {
4309
3915
  const start = Date.now();
4310
3916
  let stalled = false;
4311
3917
  let stallTimer = null;
4312
3918
  let forceKillTimer = null;
4313
- const { subprocess } = await launchCommand(options.command, options.cwd, options.timeoutMs, options.abortSignal);
3919
+ const launched = await launchCommand(options.command, options.cwd, options.timeoutMs, options.abortSignal);
3920
+ const { subprocess } = launched;
4314
3921
  const outputCapture = await createBashOutputCapture(options.outputCapture ?? {});
4315
3922
  const clearTimers = () => {
4316
3923
  if (stallTimer) {
@@ -4363,9 +3970,11 @@ async function runCommandOnce(options) {
4363
3970
  const result = await subprocess;
4364
3971
  clearTimers();
4365
3972
  const shellOutput = await outputCapture.finalize();
3973
+ const output = normalizeCommandOutput(shellOutput.outputPreview);
4366
3974
  return {
3975
+ command: options.command,
4367
3976
  exitCode: typeof result.exitCode === "number" ? result.exitCode : null,
4368
- output: shellOutput.outputPreview,
3977
+ output,
4369
3978
  outputPath: shellOutput.outputPath,
4370
3979
  truncated: shellOutput.truncated,
4371
3980
  outputChars: shellOutput.outputChars,
@@ -4380,9 +3989,12 @@ async function runCommandOnce(options) {
4380
3989
  const timedOut = isTimedOutError(error);
4381
3990
  clearTimers();
4382
3991
  const shellOutput = await outputCapture.finalize();
3992
+ const fallbackOutput = shellOutput.outputChars > 0 ? shellOutput.outputPreview : readProcessOutput(error);
3993
+ const output = normalizeCommandOutput(fallbackOutput);
4383
3994
  return {
3995
+ command: options.command,
4384
3996
  exitCode: readExitCode(error),
4385
- output: shellOutput.outputChars > 0 ? shellOutput.outputPreview : readProcessOutput(error),
3997
+ output,
4386
3998
  outputPath: shellOutput.outputPath,
4387
3999
  truncated: shellOutput.truncated,
4388
4000
  outputChars: shellOutput.outputChars,
@@ -4423,7 +4035,7 @@ var init_run = __esm({
4423
4035
  init_abort();
4424
4036
  init_outputCapture();
4425
4037
  init_launch();
4426
- init_platform();
4038
+ init_output();
4427
4039
  STALL_KILL_TIMEOUT_MS = 5e3;
4428
4040
  }
4429
4041
  });
@@ -9928,7 +9540,7 @@ var init_projectContext = __esm({
9928
9540
 
9929
9541
  // src/runtime/scene.ts
9930
9542
  function buildRuntimeScene(status) {
9931
- const executions = status.executions.active.map(buildExecutionScene);
9543
+ const executions = readSceneExecutions(status);
9932
9544
  const blockedExecutions = executions.filter((execution) => execution.risk === "blocked");
9933
9545
  const watchExecutions = executions.filter((execution) => execution.risk === "watch");
9934
9546
  const activeBackground = executions.filter((execution) => execution.kind === "background");
@@ -9959,6 +9571,19 @@ function buildRuntimeScene(status) {
9959
9571
  executions
9960
9572
  };
9961
9573
  }
9574
+ function readSceneExecutions(status) {
9575
+ const byId = /* @__PURE__ */ new Map();
9576
+ for (const execution of status.executions.active) {
9577
+ byId.set(execution.id, buildExecutionScene(execution));
9578
+ }
9579
+ for (const execution of status.executions.recent) {
9580
+ const scene = buildExecutionScene(execution);
9581
+ if (scene.risk !== "none" && !byId.has(scene.id)) {
9582
+ byId.set(scene.id, scene);
9583
+ }
9584
+ }
9585
+ return [...byId.values()];
9586
+ }
9962
9587
  function buildExecutionScene(execution) {
9963
9588
  const risk = readExecutionRisk(execution);
9964
9589
  return {
@@ -9973,9 +9598,6 @@ function buildExecutionScene(execution) {
9973
9598
  };
9974
9599
  }
9975
9600
  function buildHeadline(status, blockedExecutions, watchExecutions) {
9976
- if (!status.sessions.latest) {
9977
- return "No active session yet.";
9978
- }
9979
9601
  if (blockedExecutions.length > 0) {
9980
9602
  return `${blockedExecutions.length} execution(s) need attention.`;
9981
9603
  }
@@ -9985,6 +9607,9 @@ function buildHeadline(status, blockedExecutions, watchExecutions) {
9985
9607
  if (status.executions.active.length > 0) {
9986
9608
  return `${status.executions.active.length} execution(s) are running.`;
9987
9609
  }
9610
+ if (!status.sessions.latest) {
9611
+ return "No active session yet.";
9612
+ }
9988
9613
  return "Ready to continue the latest session.";
9989
9614
  }
9990
9615
  function readFocus(status) {
@@ -12072,6 +11697,7 @@ function buildToolBlock() {
12072
11697
  function buildCommunicationBlock() {
12073
11698
  return [
12074
11699
  "Always reply in Simplified Chinese.",
11700
+ "No Markdown in user-facing conversational replies; prefer plain text whenever possible.",
12075
11701
  "Provide concise progress updates during multi-step work.",
12076
11702
  "Make every sentence carry decision, execution, evidence, or understanding.",
12077
11703
  "Claim changed files, passed commands, and successful tools only when tool evidence supports them.",
@@ -12512,6 +12138,9 @@ function formatRuntimeStatusText(status) {
12512
12138
  lines.push("Current workspace:");
12513
12139
  lines.push(`- Focus: ${status.scene.focus}`);
12514
12140
  lines.push(`- Session: ${readSessionLine(status)}`);
12141
+ if (status.sessions.skipped > 0) {
12142
+ lines.push(`- Sessions: ${status.sessions.total} total, ${status.sessions.skipped} skipped`);
12143
+ }
12515
12144
  lines.push(`- Next: ${status.scene.nextAction}`);
12516
12145
  lines.push(`- Blocked: ${status.scene.blocked}`);
12517
12146
  lines.push(`- Context budget: ${readContextBudgetLine(status)}`);
@@ -12636,9 +12265,9 @@ function formatRuntimeStatusText(status) {
12636
12265
  ].filter(Boolean).join(" "));
12637
12266
  }
12638
12267
  }
12639
- if (status.executions.active.length > 0) {
12268
+ if (status.scene.executions.length > 0) {
12640
12269
  lines.push("");
12641
- lines.push("Active executions:");
12270
+ lines.push("Scene executions:");
12642
12271
  for (const execution of status.scene.executions) {
12643
12272
  lines.push([
12644
12273
  execution.id,
@@ -14016,7 +13645,7 @@ var init_bash = __esm({
14016
13645
  const status = result.aborted ? "aborted" : result.stalled ? "stalled" : result.timedOut ? "timed_out" : result.exitCode === 0 ? "completed" : "failed";
14017
13646
  const outputGovernance = governToolOutput({
14018
13647
  toolName: "bash",
14019
- command,
13648
+ command: result.command,
14020
13649
  status,
14021
13650
  exitCode: result.exitCode,
14022
13651
  durationMs: result.durationMs,
@@ -14044,7 +13673,7 @@ var init_bash = __esm({
14044
13673
  return okResult(
14045
13674
  JSON.stringify(
14046
13675
  {
14047
- command,
13676
+ command: result.command,
14048
13677
  cwd: resolvedCwd,
14049
13678
  exitCode: result.exitCode,
14050
13679
  status,
@@ -226392,6 +226021,63 @@ var init_toolBatch = __esm({
226392
226021
  }
226393
226022
  });
226394
226023
 
226024
+ // src/session/events.ts
226025
+ var events_exports = {};
226026
+ __export(events_exports, {
226027
+ SessionEventStore: () => SessionEventStore
226028
+ });
226029
+ function createEventId() {
226030
+ return `${(/* @__PURE__ */ new Date()).toISOString().replace(/[-:.TZ]/g, "").slice(0, 14)}-${Math.random().toString(16).slice(2, 10)}`;
226031
+ }
226032
+ function sanitizeSessionId2(sessionId) {
226033
+ return sessionId.replace(/[^a-zA-Z0-9_.-]/g, "_");
226034
+ }
226035
+ var import_promises30, import_node_path42, SessionEventStore;
226036
+ var init_events = __esm({
226037
+ "src/session/events.ts"() {
226038
+ "use strict";
226039
+ import_promises30 = __toESM(require("fs/promises"));
226040
+ import_node_path42 = __toESM(require("path"));
226041
+ SessionEventStore = class {
226042
+ constructor(eventsDir) {
226043
+ this.eventsDir = eventsDir;
226044
+ }
226045
+ async append(event) {
226046
+ const record = {
226047
+ id: createEventId(),
226048
+ createdAt: event.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
226049
+ type: event.type,
226050
+ sessionId: event.sessionId,
226051
+ cwd: event.cwd,
226052
+ host: event.host,
226053
+ message: event.message,
226054
+ details: event.details
226055
+ };
226056
+ await import_promises30.default.mkdir(this.eventsDir, { recursive: true });
226057
+ await import_promises30.default.appendFile(this.getSessionEventPath(event.sessionId), `${JSON.stringify(record)}
226058
+ `, "utf8");
226059
+ return record;
226060
+ }
226061
+ async list(sessionId, limit = 100) {
226062
+ const filePath = this.getSessionEventPath(sessionId);
226063
+ let raw = "";
226064
+ try {
226065
+ raw = await import_promises30.default.readFile(filePath, "utf8");
226066
+ } catch (error) {
226067
+ if (error.code === "ENOENT") {
226068
+ return [];
226069
+ }
226070
+ throw error;
226071
+ }
226072
+ return raw.split(/\r?\n/).filter(Boolean).map((line) => JSON.parse(line)).slice(-limit);
226073
+ }
226074
+ getSessionEventPath(sessionId) {
226075
+ return import_node_path42.default.join(this.eventsDir, `${sanitizeSessionId2(sessionId)}.jsonl`);
226076
+ }
226077
+ };
226078
+ }
226079
+ });
226080
+
226395
226081
  // src/agent/turn/toolFailure.ts
226396
226082
  function readToolFailureError(output) {
226397
226083
  try {
@@ -226432,9 +226118,16 @@ async function processToolCallBatch(input) {
226432
226118
  const batchToolMessages = [];
226433
226119
  const batchModelOutputs = [];
226434
226120
  const batchChangedPaths = /* @__PURE__ */ new Set();
226121
+ const sessionEvents = new SessionEventStore(options.config.paths.eventsDir);
226435
226122
  const leadWaitExecutionsBefore = identity.kind === "lead" ? listLeadWaitExecutions(projectContext.stateRootDir) : [];
226436
226123
  for (const toolCall of response.toolCalls) {
226437
226124
  throwIfAborted(options.abortSignal, "Turn aborted by user.");
226125
+ await sessionEvents.append({
226126
+ type: "tool.started",
226127
+ sessionId: session.id,
226128
+ cwd: options.cwd,
226129
+ details: buildToolStartedEventDetails(toolCall, identity)
226130
+ });
226438
226131
  options.callbacks?.onToolCall?.(toolCall.function.name, toolCall.function.arguments);
226439
226132
  await recordObservabilityEvent(projectContext.stateRootDir, {
226440
226133
  event: "tool.execution",
@@ -226468,6 +226161,7 @@ async function processToolCallBatch(input) {
226468
226161
  } else if (metadata?.sessionDiff) {
226469
226162
  session = await options.sessionStore.save(noteSessionDiff(session, metadata.sessionDiff));
226470
226163
  }
226164
+ const failureError = result.ok ? void 0 : readToolFailureError(result.output);
226471
226165
  await recordObservabilityEvent(projectContext.stateRootDir, {
226472
226166
  event: "tool.execution",
226473
226167
  status: result.ok ? "completed" : "failed",
@@ -226476,11 +226170,23 @@ async function processToolCallBatch(input) {
226476
226170
  identityName: identity.name,
226477
226171
  toolName: toolCall.function.name,
226478
226172
  durationMs,
226479
- error: result.ok ? void 0 : readToolFailureError(result.output),
226173
+ error: failureError,
226480
226174
  details: {
226481
226175
  changedPathCount: metadata?.changedPaths?.length ?? 0
226482
226176
  }
226483
226177
  });
226178
+ await sessionEvents.append({
226179
+ type: result.ok ? "tool.completed" : "tool.failed",
226180
+ sessionId: session.id,
226181
+ cwd: options.cwd,
226182
+ details: buildToolFinishedEventDetails({
226183
+ toolCall,
226184
+ identity,
226185
+ durationMs,
226186
+ changedPathCount: metadata?.changedPaths?.length ?? 0,
226187
+ error: failureError ? formatToolFailureError(failureError) : void 0
226188
+ })
226189
+ });
226484
226190
  if (metadata?.outputGovernance) {
226485
226191
  await recordObservabilityEvent(projectContext.stateRootDir, {
226486
226192
  event: "tool.output",
@@ -226574,6 +226280,33 @@ async function processToolCallBatch(input) {
226574
226280
  }
226575
226281
  };
226576
226282
  }
226283
+ function buildToolStartedEventDetails(toolCall, identity) {
226284
+ return {
226285
+ toolName: toolCall.function.name,
226286
+ toolCallId: toolCall.id,
226287
+ identityKind: identity.kind,
226288
+ identityName: identity.name,
226289
+ argumentsPreview: previewToolArguments(toolCall.function.arguments)
226290
+ };
226291
+ }
226292
+ function buildToolFinishedEventDetails(input) {
226293
+ return {
226294
+ toolName: input.toolCall.function.name,
226295
+ toolCallId: input.toolCall.id,
226296
+ identityKind: input.identity.kind,
226297
+ identityName: input.identity.name,
226298
+ durationMs: input.durationMs,
226299
+ changedPathCount: input.changedPathCount,
226300
+ error: input.error
226301
+ };
226302
+ }
226303
+ function previewToolArguments(rawArgs) {
226304
+ const normalized = rawArgs.replace(/\s+/g, " ").trim();
226305
+ return normalized.length > 240 ? `${normalized.slice(0, 237)}...` : normalized;
226306
+ }
226307
+ function formatToolFailureError(error) {
226308
+ return error.code ? `${error.code}: ${error.message}` : error.message;
226309
+ }
226577
226310
  var init_toolBatchLifecycle = __esm({
226578
226311
  "src/agent/turn/toolBatchLifecycle.ts"() {
226579
226312
  "use strict";
@@ -226586,6 +226319,7 @@ var init_toolBatchLifecycle = __esm({
226586
226319
  init_persistence();
226587
226320
  init_toolBatch();
226588
226321
  init_writer();
226322
+ init_events();
226589
226323
  init_abort();
226590
226324
  init_toolFailure();
226591
226325
  }
@@ -226701,13 +226435,13 @@ function createChangeId() {
226701
226435
  const random = import_node_crypto4.default.randomUUID().slice(0, 8);
226702
226436
  return `${date}-${random}`;
226703
226437
  }
226704
- var import_node_crypto4, import_promises30, import_node_path42, ChangeStore;
226438
+ var import_node_crypto4, import_promises31, import_node_path43, ChangeStore;
226705
226439
  var init_store5 = __esm({
226706
226440
  "src/agent/changes/store.ts"() {
226707
226441
  "use strict";
226708
226442
  import_node_crypto4 = __toESM(require("crypto"));
226709
- import_promises30 = __toESM(require("fs/promises"));
226710
- import_node_path42 = __toESM(require("path"));
226443
+ import_promises31 = __toESM(require("fs/promises"));
226444
+ import_node_path43 = __toESM(require("path"));
226711
226445
  ChangeStore = class {
226712
226446
  constructor(changesDir) {
226713
226447
  this.changesDir = changesDir;
@@ -226715,8 +226449,8 @@ var init_store5 = __esm({
226715
226449
  async record(input) {
226716
226450
  const id = createChangeId();
226717
226451
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
226718
- const blobDir = import_node_path42.default.join(this.changesDir, id);
226719
- await import_promises30.default.mkdir(blobDir, { recursive: true });
226452
+ const blobDir = import_node_path43.default.join(this.changesDir, id);
226453
+ await import_promises31.default.mkdir(blobDir, { recursive: true });
226720
226454
  const operations = await Promise.all(
226721
226455
  input.operations.map(async (operation, index) => {
226722
226456
  const beforeSnapshotPath = await this.writeSnapshot(
@@ -226756,21 +226490,21 @@ var init_store5 = __esm({
226756
226490
  preview: input.preview,
226757
226491
  operations
226758
226492
  };
226759
- await import_promises30.default.mkdir(this.changesDir, { recursive: true });
226760
- await import_promises30.default.writeFile(this.getMetadataPath(id), `${JSON.stringify(record, null, 2)}
226493
+ await import_promises31.default.mkdir(this.changesDir, { recursive: true });
226494
+ await import_promises31.default.writeFile(this.getMetadataPath(id), `${JSON.stringify(record, null, 2)}
226761
226495
  `, "utf8");
226762
226496
  return record;
226763
226497
  }
226764
226498
  async list(limit = 20) {
226765
- await import_promises30.default.mkdir(this.changesDir, { recursive: true });
226766
- const entries = await import_promises30.default.readdir(this.changesDir, { withFileTypes: true });
226499
+ await import_promises31.default.mkdir(this.changesDir, { recursive: true });
226500
+ const entries = await import_promises31.default.readdir(this.changesDir, { withFileTypes: true });
226767
226501
  const changes = await Promise.all(
226768
- entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map(async (entry) => this.load(import_node_path42.default.basename(entry.name, ".json")))
226502
+ entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map(async (entry) => this.load(import_node_path43.default.basename(entry.name, ".json")))
226769
226503
  );
226770
226504
  return changes.sort((left, right) => right.createdAt.localeCompare(left.createdAt)).slice(0, limit);
226771
226505
  }
226772
226506
  async load(id) {
226773
- const raw = await import_promises30.default.readFile(this.getMetadataPath(id), "utf8");
226507
+ const raw = await import_promises31.default.readFile(this.getMetadataPath(id), "utf8");
226774
226508
  return JSON.parse(raw);
226775
226509
  }
226776
226510
  async loadLatestUndoable() {
@@ -226794,17 +226528,17 @@ var init_store5 = __esm({
226794
226528
  restoredPaths.push(operation.path);
226795
226529
  if (operation.beforeSnapshotPath) {
226796
226530
  const buffer = await this.readSnapshot(operation.beforeSnapshotPath);
226797
- await import_promises30.default.mkdir(import_node_path42.default.dirname(operation.path), { recursive: true });
226798
- await import_promises30.default.writeFile(operation.path, buffer);
226531
+ await import_promises31.default.mkdir(import_node_path43.default.dirname(operation.path), { recursive: true });
226532
+ await import_promises31.default.writeFile(operation.path, buffer);
226799
226533
  continue;
226800
226534
  }
226801
- await import_promises30.default.rm(operation.path, { force: true });
226535
+ await import_promises31.default.rm(operation.path, { force: true });
226802
226536
  }
226803
226537
  const updated = {
226804
226538
  ...record,
226805
226539
  undoneAt: (/* @__PURE__ */ new Date()).toISOString()
226806
226540
  };
226807
- await import_promises30.default.writeFile(this.getMetadataPath(updated.id), `${JSON.stringify(updated, null, 2)}
226541
+ await import_promises31.default.writeFile(this.getMetadataPath(updated.id), `${JSON.stringify(updated, null, 2)}
226808
226542
  `, "utf8");
226809
226543
  return {
226810
226544
  record: updated,
@@ -226812,19 +226546,19 @@ var init_store5 = __esm({
226812
226546
  };
226813
226547
  }
226814
226548
  getMetadataPath(id) {
226815
- return import_node_path42.default.join(this.changesDir, `${id}.json`);
226549
+ return import_node_path43.default.join(this.changesDir, `${id}.json`);
226816
226550
  }
226817
226551
  async writeSnapshot(blobDir, label, buffer) {
226818
226552
  if (!buffer) {
226819
226553
  return void 0;
226820
226554
  }
226821
226555
  const fileName = `${label}.bin`;
226822
- const absolutePath = import_node_path42.default.join(blobDir, fileName);
226823
- await import_promises30.default.writeFile(absolutePath, buffer);
226824
- return import_node_path42.default.relative(this.changesDir, absolutePath);
226556
+ const absolutePath = import_node_path43.default.join(blobDir, fileName);
226557
+ await import_promises31.default.writeFile(absolutePath, buffer);
226558
+ return import_node_path43.default.relative(this.changesDir, absolutePath);
226825
226559
  }
226826
226560
  async readSnapshot(relativePath) {
226827
- return import_promises30.default.readFile(import_node_path42.default.join(this.changesDir, relativePath));
226561
+ return import_promises31.default.readFile(import_node_path43.default.join(this.changesDir, relativePath));
226828
226562
  }
226829
226563
  };
226830
226564
  }
@@ -227216,14 +226950,14 @@ async function recordHostTurnFinished(rootDir, input) {
227216
226950
  });
227217
226951
  }
227218
226952
  function resolveHostStateRoot(stateDir, fallbackCwd) {
227219
- const kittyDir = import_node_path43.default.dirname(stateDir);
227220
- return import_node_path43.default.basename(kittyDir).toLowerCase() === PROJECT_STATE_DIR_NAME ? import_node_path43.default.dirname(kittyDir) : fallbackCwd;
226953
+ const kittyDir = import_node_path44.default.dirname(stateDir);
226954
+ return import_node_path44.default.basename(kittyDir).toLowerCase() === PROJECT_STATE_DIR_NAME ? import_node_path44.default.dirname(kittyDir) : fallbackCwd;
227221
226955
  }
227222
- var import_node_path43, QueuedHostMessageRecorder;
226956
+ var import_node_path44, QueuedHostMessageRecorder;
227223
226957
  var init_hostEvents = __esm({
227224
226958
  "src/observability/hostEvents.ts"() {
227225
226959
  "use strict";
227226
- import_node_path43 = __toESM(require("path"));
226960
+ import_node_path44 = __toESM(require("path"));
227227
226961
  init_writer();
227228
226962
  init_statePaths();
227229
226963
  QueuedHostMessageRecorder = class {
@@ -227253,63 +226987,6 @@ var init_hostEvents = __esm({
227253
226987
  }
227254
226988
  });
227255
226989
 
227256
- // src/session/events.ts
227257
- var events_exports = {};
227258
- __export(events_exports, {
227259
- SessionEventStore: () => SessionEventStore
227260
- });
227261
- function createEventId() {
227262
- return `${(/* @__PURE__ */ new Date()).toISOString().replace(/[-:.TZ]/g, "").slice(0, 14)}-${Math.random().toString(16).slice(2, 10)}`;
227263
- }
227264
- function sanitizeSessionId2(sessionId) {
227265
- return sessionId.replace(/[^a-zA-Z0-9_.-]/g, "_");
227266
- }
227267
- var import_promises31, import_node_path44, SessionEventStore;
227268
- var init_events = __esm({
227269
- "src/session/events.ts"() {
227270
- "use strict";
227271
- import_promises31 = __toESM(require("fs/promises"));
227272
- import_node_path44 = __toESM(require("path"));
227273
- SessionEventStore = class {
227274
- constructor(eventsDir) {
227275
- this.eventsDir = eventsDir;
227276
- }
227277
- async append(event) {
227278
- const record = {
227279
- id: createEventId(),
227280
- createdAt: event.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
227281
- type: event.type,
227282
- sessionId: event.sessionId,
227283
- cwd: event.cwd,
227284
- host: event.host,
227285
- message: event.message,
227286
- details: event.details
227287
- };
227288
- await import_promises31.default.mkdir(this.eventsDir, { recursive: true });
227289
- await import_promises31.default.appendFile(this.getSessionEventPath(event.sessionId), `${JSON.stringify(record)}
227290
- `, "utf8");
227291
- return record;
227292
- }
227293
- async list(sessionId, limit = 100) {
227294
- const filePath = this.getSessionEventPath(sessionId);
227295
- let raw = "";
227296
- try {
227297
- raw = await import_promises31.default.readFile(filePath, "utf8");
227298
- } catch (error) {
227299
- if (error.code === "ENOENT") {
227300
- return [];
227301
- }
227302
- throw error;
227303
- }
227304
- return raw.split(/\r?\n/).filter(Boolean).map((line) => JSON.parse(line)).slice(-limit);
227305
- }
227306
- getSessionEventPath(sessionId) {
227307
- return import_node_path44.default.join(this.eventsDir, `${sanitizeSessionId2(sessionId)}.jsonl`);
227308
- }
227309
- };
227310
- }
227311
- });
227312
-
227313
226990
  // src/host/toolRegistry.ts
227314
226991
  async function createHostToolRegistry(config, options = {}) {
227315
226992
  const extraTools = options.extraTools ?? [];
@@ -231023,7 +230700,7 @@ function createCliOutputPort() {
231023
230700
  }
231024
230701
  };
231025
230702
  }
231026
- var init_output = __esm({
230703
+ var init_output2 = __esm({
231027
230704
  "src/shell/cli/output.ts"() {
231028
230705
  "use strict";
231029
230706
  init_console();
@@ -231370,7 +231047,7 @@ function createCliInteractionShell() {
231370
231047
  var init_shell = __esm({
231371
231048
  "src/shell/cli/shell.ts"() {
231372
231049
  "use strict";
231373
- init_output();
231050
+ init_output2();
231374
231051
  init_readlineInput();
231375
231052
  init_turnDisplay();
231376
231053
  }
@@ -231624,6 +231301,9 @@ function formatSessionEventsForCli(result) {
231624
231301
  return result.events.map(formatSessionEventForCli).join("\n");
231625
231302
  }
231626
231303
  function formatSessionEventForCli(event) {
231304
+ if (isToolEvent(event)) {
231305
+ return formatToolEventForCli(event);
231306
+ }
231627
231307
  const parts = [
231628
231308
  event.createdAt,
231629
231309
  event.type,
@@ -231633,10 +231313,39 @@ function formatSessionEventForCli(event) {
231633
231313
  ];
231634
231314
  return parts.filter(Boolean).join(" ");
231635
231315
  }
231316
+ function formatToolEventForCli(event) {
231317
+ const details = event.details ?? {};
231318
+ const toolName = readString7(details.toolName);
231319
+ const toolCallId = readString7(details.toolCallId);
231320
+ const durationMs = readNumber3(details.durationMs);
231321
+ const changedPathCount = readNumber3(details.changedPathCount);
231322
+ const error = readString7(details.error);
231323
+ const parts = [
231324
+ event.createdAt,
231325
+ event.type,
231326
+ toolName ? `tool=${toolName}` : void 0,
231327
+ toolCallId ? `call=${toolCallId}` : void 0,
231328
+ durationMs === void 0 ? void 0 : `duration=${durationMs}ms`,
231329
+ changedPathCount === void 0 ? void 0 : `changed=${changedPathCount}`,
231330
+ error ? `error=${formatInline(error)}` : void 0,
231331
+ event.host ? `host=${event.host}` : void 0,
231332
+ event.message ? `message=${formatInline(event.message)}` : void 0
231333
+ ];
231334
+ return parts.filter(Boolean).join(" ");
231335
+ }
231336
+ function isToolEvent(event) {
231337
+ return event.type === "tool.started" || event.type === "tool.completed" || event.type === "tool.failed";
231338
+ }
231636
231339
  function formatInline(value) {
231637
231340
  const normalized = value.replace(/\s+/g, " ").trim();
231638
231341
  return normalized.length > 120 ? `${normalized.slice(0, 117)}...` : normalized;
231639
231342
  }
231343
+ function readString7(value) {
231344
+ return typeof value === "string" && value.length > 0 ? value : void 0;
231345
+ }
231346
+ function readNumber3(value) {
231347
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
231348
+ }
231640
231349
  var init_events3 = __esm({
231641
231350
  "src/cli/commands/events.ts"() {
231642
231351
  "use strict";