@jun133/kitty 0.0.14 → 0.0.15

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.
@@ -1,27 +1,20 @@
1
1
  import {
2
- PROJECT_STATE_DIR_NAME,
3
- PROJECT_STATE_IGNORE_FILE_NAME,
4
2
  applyCurrentTurnFrame,
5
3
  buildRunTurnResult,
4
+ collapseContentParts,
6
5
  createEmptyAssistantResponseTransition,
7
6
  createExecutionWaitYieldTransition,
8
7
  createFinalizeTransition,
9
8
  createInternalReminder,
10
9
  createMessage,
11
- createProviderClientPool,
12
10
  createProviderRecoveryTransition,
13
11
  createToolMessage,
14
- ensureProjectStateDirectories,
15
12
  expandStartToToolBoundary,
16
- fetchAssistantResponse,
17
13
  fingerprintFocus,
18
14
  formatSessionMemorySectionList,
19
15
  formatSessionMemorySectionTemplate,
20
16
  formatTodoBlock,
21
- getProjectStatePaths,
22
- isAbortError,
23
17
  isInternalMessage,
24
- isRetryableApiError,
25
18
  normalizeCheckpoint,
26
19
  normalizeText,
27
20
  normalizeTodoItems,
@@ -31,20 +24,20 @@ import {
31
24
  noteCheckpointTransition,
32
25
  noteCheckpointTurnInput,
33
26
  noteSessionDiff,
27
+ readReasoningContent,
34
28
  readUserInput,
35
- recordObservabilityEvent,
36
29
  recordSessionWorksetFile,
30
+ resolveModelProfile,
31
+ resolveProviderCapabilities,
37
32
  shouldIncludeStoredAssistantReasoning,
38
- sleepWithSignal,
39
33
  sliceCurrentUserInputFrame,
40
34
  takeLastUnique,
41
- throwIfAborted,
42
35
  updateSessionMemory
43
- } from "./chunk-3KMC6H5K.mjs";
36
+ } from "./chunk-S4QTRPZ7.mjs";
44
37
 
45
38
  // src/context/projectContext.ts
46
- import fs5 from "fs/promises";
47
- import path6 from "path";
39
+ import fs6 from "fs/promises";
40
+ import path7 from "path";
48
41
 
49
42
  // src/context/repoRoots.ts
50
43
  import fs from "fs/promises";
@@ -248,13 +241,67 @@ function formatList(values) {
248
241
  }
249
242
 
250
243
  // src/skills/discovery.ts
251
- import fs4 from "fs/promises";
252
- import path5 from "path";
244
+ import fs5 from "fs/promises";
245
+ import path6 from "path";
253
246
  import fg2 from "fast-glob";
254
247
 
255
248
  // src/utils/ignore.ts
249
+ import fs4 from "fs/promises";
250
+ import path4 from "path";
251
+
252
+ // src/project/statePaths.ts
256
253
  import fs3 from "fs/promises";
257
254
  import path3 from "path";
255
+ var PROJECT_STATE_DIR_NAME = ".kitty";
256
+ var PROJECT_STATE_ENV_FILE_NAME = ".env";
257
+ var PROJECT_STATE_ENV_EXAMPLE_FILE_NAME = ".env.example";
258
+ var PROJECT_STATE_IGNORE_FILE_NAME = ".kittyignore";
259
+ var PRESERVED_PROJECT_STATE_ENTRY_NAMES = [
260
+ PROJECT_STATE_ENV_FILE_NAME,
261
+ PROJECT_STATE_ENV_EXAMPLE_FILE_NAME
262
+ ];
263
+ function getProjectStatePaths(rootDir) {
264
+ const normalizedRoot = path3.resolve(rootDir);
265
+ const kittyDir = path3.join(normalizedRoot, PROJECT_STATE_DIR_NAME);
266
+ const extensionsDir = path3.join(kittyDir, "extensions");
267
+ const memoryDir = path3.join(kittyDir, "memory");
268
+ const observabilityDir = path3.join(kittyDir, "observability");
269
+ return {
270
+ rootDir: normalizedRoot,
271
+ kittyDir,
272
+ cacheDir: path3.join(kittyDir, "cache"),
273
+ sessionsDir: path3.join(kittyDir, "sessions"),
274
+ changesDir: path3.join(kittyDir, "changes"),
275
+ eventsDir: path3.join(kittyDir, "events"),
276
+ extensionsDir,
277
+ memoryDir,
278
+ evidenceMemoryDir: path3.join(memoryDir, "evidence"),
279
+ projectMemoryDir: path3.join(memoryDir, "project"),
280
+ sessionMemoryDir: path3.join(memoryDir, "sessions"),
281
+ userMemoryDir: path3.join(memoryDir, "user"),
282
+ controlPlaneLedgerFile: path3.join(kittyDir, "control-plane.sqlite"),
283
+ observabilityDir,
284
+ observabilityEventsDir: path3.join(observabilityDir, "events"),
285
+ observabilityCrashesDir: path3.join(observabilityDir, "crashes")
286
+ };
287
+ }
288
+ async function ensureProjectStateDirectories(rootDir) {
289
+ const paths = getProjectStatePaths(rootDir);
290
+ await fs3.mkdir(paths.extensionsDir, { recursive: true });
291
+ await fs3.mkdir(paths.cacheDir, { recursive: true });
292
+ await fs3.mkdir(paths.sessionsDir, { recursive: true });
293
+ await fs3.mkdir(paths.changesDir, { recursive: true });
294
+ await fs3.mkdir(paths.eventsDir, { recursive: true });
295
+ await fs3.mkdir(paths.evidenceMemoryDir, { recursive: true });
296
+ await fs3.mkdir(paths.projectMemoryDir, { recursive: true });
297
+ await fs3.mkdir(paths.sessionMemoryDir, { recursive: true });
298
+ await fs3.mkdir(paths.userMemoryDir, { recursive: true });
299
+ await fs3.mkdir(paths.observabilityEventsDir, { recursive: true });
300
+ await fs3.mkdir(paths.observabilityCrashesDir, { recursive: true });
301
+ return paths;
302
+ }
303
+
304
+ // src/utils/ignore.ts
258
305
  var BUILTIN_PATTERNS = [
259
306
  ".git/",
260
307
  "node_modules/",
@@ -268,11 +315,11 @@ async function loadProjectIgnoreRules(rootDir, cwd) {
268
315
  })).filter((rule) => Boolean(rule));
269
316
  const candidateFiles = uniqueIgnoreFiles([
270
317
  {
271
- path: path3.join(rootDir, PROJECT_STATE_DIR_NAME, PROJECT_STATE_IGNORE_FILE_NAME),
318
+ path: path4.join(rootDir, PROJECT_STATE_DIR_NAME, PROJECT_STATE_IGNORE_FILE_NAME),
272
319
  baseDir: rootDir
273
320
  },
274
321
  {
275
- path: path3.join(cwd, PROJECT_STATE_DIR_NAME, PROJECT_STATE_IGNORE_FILE_NAME),
322
+ path: path4.join(cwd, PROJECT_STATE_DIR_NAME, PROJECT_STATE_IGNORE_FILE_NAME),
276
323
  baseDir: cwd
277
324
  }
278
325
  ]);
@@ -332,7 +379,7 @@ function buildFastGlobIgnorePatterns(baseDir, rules) {
332
379
  }
333
380
  async function tryReadUtf8File(filePath) {
334
381
  try {
335
- return await fs3.readFile(filePath, "utf8");
382
+ return await fs4.readFile(filePath, "utf8");
336
383
  } catch (error) {
337
384
  const errno = error;
338
385
  if (errno.code === "ENOENT") {
@@ -383,11 +430,11 @@ function compileIgnoreRule(rawPattern, options) {
383
430
  };
384
431
  }
385
432
  function toRelativePosix(baseDir, targetPath) {
386
- const relativePath = path3.relative(path3.resolve(baseDir), path3.resolve(targetPath));
433
+ const relativePath = path4.relative(path4.resolve(baseDir), path4.resolve(targetPath));
387
434
  if (!relativePath || relativePath === ".") {
388
435
  return "";
389
436
  }
390
- if (relativePath.startsWith("..") || path3.isAbsolute(relativePath)) {
437
+ if (relativePath.startsWith("..") || path4.isAbsolute(relativePath)) {
391
438
  return null;
392
439
  }
393
440
  return relativePath.replace(/\\/g, "/");
@@ -453,21 +500,21 @@ function uniqueIgnoreFiles(files) {
453
500
  const seen = /* @__PURE__ */ new Set();
454
501
  const unique = [];
455
502
  for (const file of files) {
456
- const normalizedPath = path3.normalize(file.path);
503
+ const normalizedPath = path4.normalize(file.path);
457
504
  if (seen.has(normalizedPath)) {
458
505
  continue;
459
506
  }
460
507
  seen.add(normalizedPath);
461
508
  unique.push({
462
509
  path: normalizedPath,
463
- baseDir: path3.resolve(file.baseDir)
510
+ baseDir: path4.resolve(file.baseDir)
464
511
  });
465
512
  }
466
513
  return unique;
467
514
  }
468
515
 
469
516
  // src/skills/schema.ts
470
- import path4 from "path";
517
+ import path5 from "path";
471
518
  var FRONTMATTER_PATTERN = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/;
472
519
  var SkillSchemaError = class extends Error {
473
520
  constructor(message, filePath) {
@@ -487,7 +534,7 @@ function parseSkillSource(text, input) {
487
534
  return {
488
535
  name,
489
536
  description,
490
- path: path4.relative(input.rootDir, input.absolutePath) || "SKILL.md",
537
+ path: path5.relative(input.rootDir, input.absolutePath) || "SKILL.md",
491
538
  absolutePath: input.absolutePath,
492
539
  body,
493
540
  dependencies: parseDependencies(metadata.requires),
@@ -557,12 +604,12 @@ async function discoverSkills(rootDir, cwd, ignoreRules) {
557
604
  const seenNames = /* @__PURE__ */ new Map();
558
605
  const skills = [];
559
606
  for (const skillFile of skillFiles) {
560
- const normalizedPath = path5.normalize(skillFile);
607
+ const normalizedPath = path6.normalize(skillFile);
561
608
  if (seenPaths.has(normalizedPath) || isPathIgnored(normalizedPath, ignoreRules)) {
562
609
  continue;
563
610
  }
564
611
  seenPaths.add(normalizedPath);
565
- const skill = parseSkillSource(await fs4.readFile(normalizedPath, "utf8"), {
612
+ const skill = parseSkillSource(await fs5.readFile(normalizedPath, "utf8"), {
566
613
  absolutePath: normalizedPath,
567
614
  rootDir
568
615
  });
@@ -578,7 +625,7 @@ async function discoverSkills(rootDir, cwd, ignoreRules) {
578
625
  return skills.sort((left, right) => left.name.localeCompare(right.name));
579
626
  }
580
627
  async function listSkillResources(skillPath, rootDir, ignoreRules) {
581
- const skillDir = path5.dirname(skillPath);
628
+ const skillDir = path6.dirname(skillPath);
582
629
  const files = await fg2([...SKILL_RESOURCE_GLOBS], {
583
630
  cwd: skillDir,
584
631
  absolute: true,
@@ -592,11 +639,11 @@ async function listSkillResources(skillPath, rootDir, ignoreRules) {
592
639
  if (isPathIgnored(file, ignoreRules)) {
593
640
  continue;
594
641
  }
595
- const stat = await fs4.stat(file);
642
+ const stat = await fs5.stat(file);
596
643
  resources.push({
597
- path: path5.relative(rootDir, file),
644
+ path: path6.relative(rootDir, file),
598
645
  size: stat.size,
599
- kind: readSkillResourceKind(path5.relative(skillDir, file))
646
+ kind: readSkillResourceKind(path6.relative(skillDir, file))
600
647
  });
601
648
  }
602
649
  return resources;
@@ -643,14 +690,14 @@ function buildSkillPackageHealth(skill) {
643
690
  }
644
691
  async function findSkillFiles(rootDir, cwd) {
645
692
  const candidates = uniquePaths([
646
- path5.join(rootDir, "SKILL.md"),
647
- path5.join(cwd, "SKILL.md")
693
+ path6.join(rootDir, "SKILL.md"),
694
+ path6.join(cwd, "SKILL.md")
648
695
  ]);
649
696
  const roots = uniquePaths([
650
- path5.join(rootDir, ".skills"),
651
- path5.join(rootDir, "skills"),
652
- path5.join(cwd, ".skills"),
653
- path5.join(cwd, "skills")
697
+ path6.join(rootDir, ".skills"),
698
+ path6.join(rootDir, "skills"),
699
+ path6.join(cwd, ".skills"),
700
+ path6.join(cwd, "skills")
654
701
  ]);
655
702
  const files = [];
656
703
  for (const candidate of candidates) {
@@ -675,20 +722,20 @@ async function findSkillFiles(rootDir, cwd) {
675
722
  }
676
723
  async function isRegularFile(filePath) {
677
724
  try {
678
- return (await fs4.stat(filePath)).isFile();
725
+ return (await fs5.stat(filePath)).isFile();
679
726
  } catch {
680
727
  return false;
681
728
  }
682
729
  }
683
730
  async function isDirectory2(filePath) {
684
731
  try {
685
- return (await fs4.stat(filePath)).isDirectory();
732
+ return (await fs5.stat(filePath)).isDirectory();
686
733
  } catch {
687
734
  return false;
688
735
  }
689
736
  }
690
737
  function uniquePaths(paths) {
691
- return [...new Set(paths.map((item) => path5.normalize(item)))];
738
+ return [...new Set(paths.map((item) => path6.normalize(item)))];
692
739
  }
693
740
 
694
741
  // src/context/projectContext.ts
@@ -717,8 +764,8 @@ async function getInstructionFiles(rootDir, cwd) {
717
764
  const directories = getDirectoriesFromRootToCwd(rootDir, cwd);
718
765
  const results = [];
719
766
  for (const directory of directories) {
720
- const overridePath = path6.join(directory, "AGENTS.override.md");
721
- const agentsPath = path6.join(directory, "AGENTS.md");
767
+ const overridePath = path7.join(directory, "AGENTS.override.md");
768
+ const agentsPath = path7.join(directory, "AGENTS.md");
722
769
  if (await isRegularFile2(overridePath)) {
723
770
  results.push(await readInstructionFile(rootDir, overridePath, "AGENTS.override.md"));
724
771
  continue;
@@ -730,22 +777,22 @@ async function getInstructionFiles(rootDir, cwd) {
730
777
  return results;
731
778
  }
732
779
  function getDirectoriesFromRootToCwd(rootDir, cwd) {
733
- const absoluteRoot = path6.resolve(rootDir);
734
- const absoluteCwd = path6.resolve(cwd);
735
- const relativePath = path6.relative(absoluteRoot, absoluteCwd);
780
+ const absoluteRoot = path7.resolve(rootDir);
781
+ const absoluteCwd = path7.resolve(cwd);
782
+ const relativePath = path7.relative(absoluteRoot, absoluteCwd);
736
783
  if (!relativePath || relativePath === ".") {
737
784
  return [absoluteRoot];
738
785
  }
739
- const parts = relativePath.split(path6.sep).filter(Boolean);
786
+ const parts = relativePath.split(path7.sep).filter(Boolean);
740
787
  const directories = [absoluteRoot];
741
788
  for (let index = 0; index < parts.length; index += 1) {
742
- directories.push(path6.join(absoluteRoot, ...parts.slice(0, index + 1)));
789
+ directories.push(path7.join(absoluteRoot, ...parts.slice(0, index + 1)));
743
790
  }
744
791
  return directories;
745
792
  }
746
793
  async function isRegularFile2(filePath) {
747
794
  try {
748
- const stat = await fs5.stat(filePath);
795
+ const stat = await fs6.stat(filePath);
749
796
  return stat.isFile();
750
797
  } catch {
751
798
  return false;
@@ -754,9 +801,9 @@ async function isRegularFile2(filePath) {
754
801
  async function readInstructionFile(rootDir, absolutePath, filename) {
755
802
  return {
756
803
  path: absolutePath,
757
- relativePath: path6.relative(rootDir, absolutePath) || filename,
804
+ relativePath: path7.relative(rootDir, absolutePath) || filename,
758
805
  filename,
759
- content: await fs5.readFile(absolutePath, "utf8")
806
+ content: await fs6.readFile(absolutePath, "utf8")
760
807
  };
761
808
  }
762
809
  function concatInstructionFiles(files, maxBytes) {
@@ -832,7 +879,7 @@ function getErrorMessage(error) {
832
879
  return "Environment error: network connection failed; the current provider/base URL is unreachable. Check network, proxy settings, or `KITTY_BASE_URL`.";
833
880
  }
834
881
  if (status === 404 || lower.includes("returned 404")) {
835
- return "User-fixable error: provider returned 404. Check whether `KITTY_BASE_URL` is the correct OpenAI-compatible API base URL.";
882
+ return "User-fixable error: provider endpoint returned 404. Check `KITTY_PROVIDER`, `KITTY_MODEL`, and `KITTY_BASE_URL` as one provider profile; the selected provider may use Responses instead of Chat Completions.";
836
883
  }
837
884
  if (typeof status === "number" && status >= 500) {
838
885
  return `Provider error: service returned ${status}. Retry later or confirm the provider service is healthy.`;
@@ -919,6 +966,1116 @@ function hasVisibleAssistantResult(content) {
919
966
  return typeof content === "string" && content.trim().length > 0;
920
967
  }
921
968
 
969
+ // src/utils/abort.ts
970
+ function createAbortError(message = "Operation aborted") {
971
+ const error = new Error(message);
972
+ error.name = "AbortError";
973
+ error.code = "ABORT_ERR";
974
+ return error;
975
+ }
976
+ function isAbortError(error) {
977
+ if (!error) {
978
+ return false;
979
+ }
980
+ if (error instanceof Error) {
981
+ if (error.name === "AbortError") {
982
+ return true;
983
+ }
984
+ const code = String(error.code ?? "");
985
+ if (code === "ABORT_ERR" || code === "ERR_ABORTED" || code === "ABORTED") {
986
+ return true;
987
+ }
988
+ const message = error.message.toLowerCase();
989
+ if (message.includes("abort") || message.includes("aborted") || message.includes("cancelled") || message.includes("canceled")) {
990
+ return true;
991
+ }
992
+ }
993
+ if (typeof error === "object" && error && "cause" in error) {
994
+ return isAbortError(error.cause);
995
+ }
996
+ return false;
997
+ }
998
+ function throwIfAborted(signal, message) {
999
+ if (signal?.aborted) {
1000
+ throw createAbortError(message ?? "Operation aborted");
1001
+ }
1002
+ }
1003
+ function sleepWithSignal(ms, signal) {
1004
+ if (!signal) {
1005
+ return new Promise((resolve) => {
1006
+ setTimeout(resolve, ms);
1007
+ });
1008
+ }
1009
+ if (signal.aborted) {
1010
+ return Promise.reject(createAbortError("Sleep aborted"));
1011
+ }
1012
+ return new Promise((resolve, reject) => {
1013
+ const timer = setTimeout(() => {
1014
+ signal.removeEventListener("abort", onAbort);
1015
+ resolve();
1016
+ }, ms);
1017
+ const onAbort = () => {
1018
+ clearTimeout(timer);
1019
+ signal.removeEventListener("abort", onAbort);
1020
+ reject(createAbortError("Sleep aborted"));
1021
+ };
1022
+ signal.addEventListener("abort", onAbort);
1023
+ });
1024
+ }
1025
+
1026
+ // src/provider/apiRetry.ts
1027
+ var API_MAX_RETRIES = 3;
1028
+ var API_RETRY_BASE_DELAY_MS = 1200;
1029
+ async function withApiRetries(operation, abortSignal) {
1030
+ let lastError;
1031
+ for (let attempt = 1; attempt <= API_MAX_RETRIES; attempt += 1) {
1032
+ try {
1033
+ return await operation();
1034
+ } catch (error) {
1035
+ if (isAbortError(error)) {
1036
+ throw error;
1037
+ }
1038
+ lastError = error;
1039
+ if (!isRetryableApiError(error) || attempt === API_MAX_RETRIES) {
1040
+ break;
1041
+ }
1042
+ await sleepWithSignal(API_RETRY_BASE_DELAY_MS * attempt, abortSignal);
1043
+ }
1044
+ }
1045
+ throw lastError;
1046
+ }
1047
+ function isRetryableApiError(error) {
1048
+ const status = error.status;
1049
+ if (typeof status === "number") {
1050
+ return status === 408 || status === 409 || status === 429 || status >= 500;
1051
+ }
1052
+ const message = String(error.message ?? error).toLowerCase();
1053
+ return message.includes("timeout") || message.includes("network") || message.includes("connection error") || message.includes("connection reset") || message.includes("econnreset") || message.includes("econnrefused") || message.includes("connect timeout") || message.includes("temporarily") || message.includes("rate limit") || message.includes("overloaded");
1054
+ }
1055
+
1056
+ // src/provider/usageNormalizer.ts
1057
+ function normalizeProviderUsage(usage) {
1058
+ if (!usage || typeof usage !== "object") {
1059
+ return void 0;
1060
+ }
1061
+ const record = usage;
1062
+ const promptDetails = readObject(record.prompt_tokens_details);
1063
+ const completionDetails = readObject(record.completion_tokens_details);
1064
+ const outputDetails = readObject(record.output_tokens_details);
1065
+ const cacheCreation = readObject(record.cache_creation);
1066
+ const inputTokens = readUsageNumber(record.prompt_tokens ?? record.input_tokens);
1067
+ const outputTokens = readUsageNumber(record.completion_tokens ?? record.output_tokens);
1068
+ const totalTokens = readUsageNumber(record.total_tokens);
1069
+ const reasoningTokens = readUsageNumber(
1070
+ completionDetails?.reasoning_tokens ?? outputDetails?.reasoning_tokens
1071
+ );
1072
+ const openAiCachedTokens = readUsageNumber(promptDetails?.cached_tokens);
1073
+ const deepSeekHitTokens = readUsageNumber(record.prompt_cache_hit_tokens);
1074
+ const deepSeekMissTokens = readUsageNumber(record.prompt_cache_miss_tokens);
1075
+ const anthropicCacheReadTokens = readUsageNumber(record.cache_read_input_tokens);
1076
+ const anthropicCacheCreationTokens = readUsageNumber(record.cache_creation_input_tokens) ?? sumUsageNumbers([
1077
+ cacheCreation?.ephemeral_1h_input_tokens,
1078
+ cacheCreation?.ephemeral_5m_input_tokens
1079
+ ]);
1080
+ const geminiCachedTokens = readUsageNumber(record.cachedContentTokenCount ?? record.cached_content_token_count);
1081
+ const cacheReadTokens = firstNumber(
1082
+ anthropicCacheReadTokens,
1083
+ openAiCachedTokens,
1084
+ geminiCachedTokens
1085
+ );
1086
+ const cacheHitTokens = firstNumber(deepSeekHitTokens, cacheReadTokens);
1087
+ const cacheMissTokens = deepSeekMissTokens;
1088
+ const cacheCreationTokens = anthropicCacheCreationTokens;
1089
+ const snapshot = {
1090
+ inputTokens,
1091
+ outputTokens,
1092
+ totalTokens,
1093
+ reasoningTokens,
1094
+ cacheReadTokens,
1095
+ cacheCreationTokens,
1096
+ cacheHitTokens,
1097
+ cacheMissTokens
1098
+ };
1099
+ const cacheHitRate = computeCacheHitRate(snapshot);
1100
+ if (cacheHitRate !== void 0) {
1101
+ snapshot.cacheHitRate = cacheHitRate;
1102
+ }
1103
+ return Object.values(snapshot).some((value) => typeof value === "number") ? snapshot : void 0;
1104
+ }
1105
+ function hasProviderUsageSnapshot(usage) {
1106
+ return Boolean(usage && Object.values(usage).some((value) => typeof value === "number"));
1107
+ }
1108
+ function computeCacheHitRate(snapshot) {
1109
+ if (typeof snapshot.cacheHitTokens === "number" && typeof snapshot.cacheMissTokens === "number") {
1110
+ return ratio(snapshot.cacheHitTokens, snapshot.cacheHitTokens + snapshot.cacheMissTokens);
1111
+ }
1112
+ if (typeof snapshot.cacheReadTokens === "number") {
1113
+ const denominator = (snapshot.inputTokens ?? 0) + snapshot.cacheReadTokens + (snapshot.cacheCreationTokens ?? 0);
1114
+ return ratio(snapshot.cacheReadTokens, denominator);
1115
+ }
1116
+ return void 0;
1117
+ }
1118
+ function ratio(numerator, denominator) {
1119
+ if (denominator <= 0) {
1120
+ return void 0;
1121
+ }
1122
+ return Math.round(numerator / denominator * 1e4) / 1e4;
1123
+ }
1124
+ function readObject(value) {
1125
+ return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
1126
+ }
1127
+ function firstNumber(...values) {
1128
+ return values.find((value) => typeof value === "number");
1129
+ }
1130
+ function sumUsageNumbers(values) {
1131
+ const numbers = values.map(readUsageNumber).filter((value) => typeof value === "number");
1132
+ if (numbers.length === 0) {
1133
+ return void 0;
1134
+ }
1135
+ return numbers.reduce((total, value) => total + value, 0);
1136
+ }
1137
+ function readUsageNumber(value) {
1138
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.round(value) : void 0;
1139
+ }
1140
+
1141
+ // src/observability/writer.ts
1142
+ import fs7 from "fs/promises";
1143
+ import path8 from "path";
1144
+
1145
+ // src/observability/schema.ts
1146
+ var OBSERVABILITY_VERSION = 1;
1147
+ function buildObservabilityEventRecord(input) {
1148
+ return {
1149
+ version: OBSERVABILITY_VERSION,
1150
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1151
+ event: normalizeText2(input.event, "unknown"),
1152
+ status: normalizeText2(input.status, "unknown"),
1153
+ host: normalizeOptionalText(input.host),
1154
+ sessionId: normalizeOptionalText(input.sessionId),
1155
+ executionId: normalizeOptionalText(input.executionId),
1156
+ identityKind: normalizeOptionalText(input.identityKind),
1157
+ identityName: normalizeOptionalText(input.identityName),
1158
+ durationMs: normalizeOptionalNumber(input.durationMs),
1159
+ toolName: normalizeOptionalText(input.toolName),
1160
+ model: normalizeOptionalText(input.model),
1161
+ error: normalizeObservabilityError(input.error),
1162
+ details: normalizeDetails(input.details)
1163
+ };
1164
+ }
1165
+ function normalizeObservabilityError(error) {
1166
+ if (error == null) {
1167
+ return void 0;
1168
+ }
1169
+ if (typeof error === "object" && error !== null && "message" in error) {
1170
+ const record = error;
1171
+ const message2 = normalizeText2(record.message, "");
1172
+ if (!message2) {
1173
+ return void 0;
1174
+ }
1175
+ return {
1176
+ message: message2,
1177
+ code: normalizeOptionalText(record.code),
1178
+ details: normalizeValue(record.details)
1179
+ };
1180
+ }
1181
+ const message = readErrorMessage(error);
1182
+ return message ? { message } : void 0;
1183
+ }
1184
+ function normalizeDetails(details) {
1185
+ if (!details || typeof details !== "object") {
1186
+ return void 0;
1187
+ }
1188
+ const normalized = normalizeValue(details);
1189
+ return normalized && typeof normalized === "object" && !Array.isArray(normalized) ? normalized : void 0;
1190
+ }
1191
+ function normalizeValue(value, depth = 0) {
1192
+ if (value == null) {
1193
+ return void 0;
1194
+ }
1195
+ if (depth >= 4) {
1196
+ return "[truncated]";
1197
+ }
1198
+ if (typeof value === "string") {
1199
+ return value.length <= 2e3 ? value : `${value.slice(0, 1997)}...`;
1200
+ }
1201
+ if (typeof value === "number") {
1202
+ return Number.isFinite(value) ? value : void 0;
1203
+ }
1204
+ if (typeof value === "boolean") {
1205
+ return value;
1206
+ }
1207
+ if (value instanceof Error) {
1208
+ return {
1209
+ name: normalizeText2(value.name, "Error"),
1210
+ message: normalizeText2(value.message, "Unknown error"),
1211
+ stack: normalizeValue(value.stack, depth + 1)
1212
+ };
1213
+ }
1214
+ if (Array.isArray(value)) {
1215
+ return value.slice(0, 20).map((item) => normalizeValue(item, depth + 1)).filter((item) => item !== void 0);
1216
+ }
1217
+ if (typeof value === "object") {
1218
+ const entries = Object.entries(value).slice(0, 30);
1219
+ const normalizedEntries = entries.map(([key, item]) => [key, normalizeValue(item, depth + 1)]).filter(([, item]) => item !== void 0);
1220
+ return Object.fromEntries(normalizedEntries);
1221
+ }
1222
+ return normalizeText2(String(value), "");
1223
+ }
1224
+ function normalizeText2(value, fallback) {
1225
+ const normalized = String(value ?? "").trim();
1226
+ return normalized || fallback;
1227
+ }
1228
+ function normalizeOptionalText(value) {
1229
+ const normalized = String(value ?? "").trim();
1230
+ return normalized || void 0;
1231
+ }
1232
+ function normalizeOptionalNumber(value) {
1233
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.round(value) : void 0;
1234
+ }
1235
+ function readErrorMessage(error) {
1236
+ if (error instanceof Error) {
1237
+ return normalizeText2(error.message, error.name || "Unknown error");
1238
+ }
1239
+ if (typeof error === "object" && error !== null && "message" in error) {
1240
+ return normalizeText2(error.message, "Unknown error");
1241
+ }
1242
+ return normalizeText2(String(error ?? "Unknown error"), "Unknown error");
1243
+ }
1244
+
1245
+ // src/observability/writer.ts
1246
+ async function appendObservabilityEvent(rootDir, input) {
1247
+ const paths = await ensureProjectStateDirectories(rootDir);
1248
+ const record = buildObservabilityEventRecord(input);
1249
+ const filePath = path8.join(paths.observabilityEventsDir, `${record.timestamp.slice(0, 10)}.jsonl`);
1250
+ await fs7.appendFile(filePath, `${JSON.stringify(record)}
1251
+ `, "utf8");
1252
+ return record;
1253
+ }
1254
+ async function recordObservabilityEvent(rootDir, input) {
1255
+ try {
1256
+ await appendObservabilityEvent(rootDir, input);
1257
+ } catch {
1258
+ }
1259
+ }
1260
+
1261
+ // src/provider/cachePolicy.ts
1262
+ function resolveProviderCachePolicy(input) {
1263
+ const profile = resolveModelProfile(input);
1264
+ if (profile.model.capabilities.cache === "prompt-cache-key") {
1265
+ return {
1266
+ provider: "openai",
1267
+ automaticPrefixCache: true,
1268
+ promptCacheKey: buildPromptCacheKey(input)
1269
+ };
1270
+ }
1271
+ if (profile.model.capabilities.cache === "provider-automatic") {
1272
+ return {
1273
+ provider: profile.provider.id === "deepseek" ? "deepseek" : "generic",
1274
+ automaticPrefixCache: true
1275
+ };
1276
+ }
1277
+ return {
1278
+ provider: "generic",
1279
+ automaticPrefixCache: false
1280
+ };
1281
+ }
1282
+ function buildPromptCacheKey(input) {
1283
+ const seed = input.sessionId || input.projectRoot;
1284
+ if (!seed) {
1285
+ return void 0;
1286
+ }
1287
+ return `kitty:${stableHash(seed)}`;
1288
+ }
1289
+ function stableHash(value) {
1290
+ let hash = 2166136261;
1291
+ for (let index = 0; index < value.length; index += 1) {
1292
+ hash ^= value.charCodeAt(index);
1293
+ hash = Math.imul(hash, 16777619);
1294
+ }
1295
+ return (hash >>> 0).toString(16).padStart(8, "0");
1296
+ }
1297
+
1298
+ // src/provider/chatRequestBody.ts
1299
+ function buildProviderRequestBody(input) {
1300
+ const capabilities = resolveProviderCapabilities(input);
1301
+ const thinking = capabilities.provider === "deepseek" ? resolveDeepSeekThinking(input.messages, input.thinking ?? "enabled") : input.thinking;
1302
+ const body = {
1303
+ model: input.model,
1304
+ messages: toChatCompletionMessages(input.messages),
1305
+ tools: input.tools,
1306
+ stream: input.stream
1307
+ };
1308
+ if (capabilities.provider !== "deepseek" && input.tools?.length) {
1309
+ body.tool_choice = "auto";
1310
+ }
1311
+ if (input.stream) {
1312
+ body.stream_options = {
1313
+ include_usage: true
1314
+ };
1315
+ }
1316
+ const cachePolicy = resolveProviderCachePolicy(input);
1317
+ if (cachePolicy.promptCacheKey) {
1318
+ body.prompt_cache_key = cachePolicy.promptCacheKey;
1319
+ }
1320
+ if (typeof input.maxOutputTokens === "number" && Number.isFinite(input.maxOutputTokens)) {
1321
+ body.max_tokens = Math.max(1, Math.trunc(input.maxOutputTokens));
1322
+ }
1323
+ if (capabilities.provider === "deepseek") {
1324
+ body.thinking = { type: thinking };
1325
+ if (thinking === "enabled") {
1326
+ body.reasoning_effort = normalizeDeepSeekReasoningEffort(input.reasoningEffort ?? capabilities.defaultReasoningEffort);
1327
+ }
1328
+ } else if (input.forceReasoning || capabilities.defaultReasoningEnabled) {
1329
+ body.thinking = { type: "enabled" };
1330
+ }
1331
+ return body;
1332
+ }
1333
+ function resolveDeepSeekThinking(messages, requested) {
1334
+ if (requested === "disabled") {
1335
+ return "disabled";
1336
+ }
1337
+ if (hasUnreplayableAssistantReasoning(messages)) {
1338
+ throw new Error("DeepSeek thinking tool-call replay requires stored reasoning_content. Start a new turn or disable KITTY_THINKING.");
1339
+ }
1340
+ return "enabled";
1341
+ }
1342
+ function hasUnreplayableAssistantReasoning(messages) {
1343
+ return messages.some(
1344
+ (message) => message.role === "assistant" && Array.isArray(message.toolCalls) && message.toolCalls.length > 0 && message.reasoningContent === void 0
1345
+ );
1346
+ }
1347
+ function normalizeDeepSeekReasoningEffort(effort) {
1348
+ if (effort === void 0 || effort === "minimal" || effort === "low" || effort === "medium" || effort === "high") {
1349
+ return "high";
1350
+ }
1351
+ if (effort === "xhigh" || effort === "max") {
1352
+ return "max";
1353
+ }
1354
+ return "high";
1355
+ }
1356
+
1357
+ // src/provider/chatCompletionsAdapter.ts
1358
+ var chatCompletionsAdapter = {
1359
+ wireApi: "chat.completions",
1360
+ async fetchStreaming(client, request) {
1361
+ const startedAt = Date.now();
1362
+ let usage;
1363
+ throwIfAborted(request.abortSignal, "Streaming request aborted");
1364
+ try {
1365
+ const stream = await client.chat.completions.create(
1366
+ {
1367
+ ...buildProviderRequestBody({
1368
+ provider: request.provider,
1369
+ model: request.model,
1370
+ messages: request.messages,
1371
+ tools: request.tools,
1372
+ stream: true,
1373
+ forceReasoning: request.forceReasoning,
1374
+ thinking: request.thinking,
1375
+ reasoningEffort: request.reasoningEffort,
1376
+ maxOutputTokens: request.maxOutputTokens,
1377
+ sessionId: request.sessionId,
1378
+ projectRoot: request.projectRoot
1379
+ }),
1380
+ signal: request.abortSignal
1381
+ }
1382
+ );
1383
+ if (request.abortSignal?.aborted) {
1384
+ abortStream(stream);
1385
+ throw createAbortError("Streaming aborted");
1386
+ }
1387
+ let content = "";
1388
+ let reasoningContent = "";
1389
+ const toolCallParts = /* @__PURE__ */ new Map();
1390
+ for await (const chunk of stream) {
1391
+ if (request.abortSignal?.aborted) {
1392
+ abortStream(stream);
1393
+ throw createAbortError("Streaming aborted");
1394
+ }
1395
+ usage = normalizeProviderUsage(chunk.usage) ?? usage;
1396
+ const delta = chunk.choices?.[0]?.delta;
1397
+ if (!delta) {
1398
+ continue;
1399
+ }
1400
+ if (typeof delta.content === "string" && delta.content.length > 0) {
1401
+ content += delta.content;
1402
+ request.callbacks?.onAssistantDelta?.(delta.content);
1403
+ }
1404
+ if (typeof delta.reasoning_content === "string" && delta.reasoning_content.length > 0) {
1405
+ reasoningContent += delta.reasoning_content;
1406
+ request.callbacks?.onReasoningDelta?.(delta.reasoning_content);
1407
+ }
1408
+ if (Array.isArray(delta.tool_calls)) {
1409
+ for (const toolCall of delta.tool_calls) {
1410
+ const index = typeof toolCall.index === "number" ? toolCall.index : 0;
1411
+ const existing = toolCallParts.get(index) ?? {
1412
+ id: toolCall.id ?? `tool-${index}`,
1413
+ name: "",
1414
+ arguments: ""
1415
+ };
1416
+ if (toolCall.id) {
1417
+ existing.id = toolCall.id;
1418
+ }
1419
+ if (toolCall.function?.name) {
1420
+ existing.name += toolCall.function.name;
1421
+ }
1422
+ if (toolCall.function?.arguments) {
1423
+ existing.arguments += toolCall.function.arguments;
1424
+ }
1425
+ toolCallParts.set(index, existing);
1426
+ }
1427
+ }
1428
+ }
1429
+ return {
1430
+ content: content.length > 0 ? content : null,
1431
+ reasoningContent: reasoningContent.length > 0 ? reasoningContent : void 0,
1432
+ streamedAssistantContent: content.length > 0,
1433
+ streamedReasoningContent: reasoningContent.length > 0,
1434
+ toolCalls: [...toolCallParts.entries()].sort((left, right) => left[0] - right[0]).map(([, toolCall]) => ({
1435
+ id: toolCall.id,
1436
+ type: "function",
1437
+ function: {
1438
+ name: toolCall.name,
1439
+ arguments: toolCall.arguments
1440
+ }
1441
+ }))
1442
+ };
1443
+ } finally {
1444
+ request.onRequestMetric?.({
1445
+ durationMs: Date.now() - startedAt,
1446
+ usage
1447
+ });
1448
+ }
1449
+ },
1450
+ async fetchNonStreaming(client, request) {
1451
+ const startedAt = Date.now();
1452
+ let usage;
1453
+ throwIfAborted(request.abortSignal, "Request aborted");
1454
+ try {
1455
+ const completion = await client.chat.completions.create(
1456
+ {
1457
+ ...buildProviderRequestBody({
1458
+ provider: request.provider,
1459
+ model: request.model,
1460
+ messages: request.messages,
1461
+ tools: request.tools,
1462
+ stream: false,
1463
+ forceReasoning: request.forceReasoning,
1464
+ thinking: request.thinking,
1465
+ reasoningEffort: request.reasoningEffort,
1466
+ maxOutputTokens: request.maxOutputTokens,
1467
+ sessionId: request.sessionId,
1468
+ projectRoot: request.projectRoot
1469
+ }),
1470
+ signal: request.abortSignal
1471
+ }
1472
+ );
1473
+ usage = normalizeProviderUsage(completion.usage);
1474
+ const message = completion.choices[0]?.message;
1475
+ if (!message) {
1476
+ throw new Error("API returned no message.");
1477
+ }
1478
+ return {
1479
+ content: typeof message.content === "string" ? message.content : collapseContentParts(message.content),
1480
+ reasoningContent: readReasoningContent(message),
1481
+ streamedAssistantContent: false,
1482
+ streamedReasoningContent: false,
1483
+ toolCalls: (message.tool_calls ?? []).filter((call) => call.type === "function").map((call) => ({
1484
+ id: call.id,
1485
+ type: "function",
1486
+ function: {
1487
+ name: call.function.name,
1488
+ arguments: call.function.arguments
1489
+ }
1490
+ }))
1491
+ };
1492
+ } finally {
1493
+ request.onRequestMetric?.({
1494
+ durationMs: Date.now() - startedAt,
1495
+ usage
1496
+ });
1497
+ }
1498
+ }
1499
+ };
1500
+ function abortStream(stream) {
1501
+ try {
1502
+ stream?.controller?.abort();
1503
+ } catch {
1504
+ }
1505
+ }
1506
+ function toChatCompletionMessages(messages) {
1507
+ return messages.map((message) => {
1508
+ if (message.role === "tool") {
1509
+ return {
1510
+ role: "tool",
1511
+ content: message.content ?? "",
1512
+ tool_call_id: message.toolCallId ?? ""
1513
+ };
1514
+ }
1515
+ if (message.role === "assistant" && message.toolCalls?.length) {
1516
+ const assistantMessage = {
1517
+ role: "assistant",
1518
+ content: message.content ?? "",
1519
+ tool_calls: message.toolCalls
1520
+ };
1521
+ if (message.reasoningContent !== void 0) {
1522
+ assistantMessage.reasoning_content = message.reasoningContent;
1523
+ }
1524
+ return assistantMessage;
1525
+ }
1526
+ const baseMessage = {
1527
+ role: message.role,
1528
+ content: message.content ?? "",
1529
+ name: message.name
1530
+ };
1531
+ if (message.role === "assistant" && message.reasoningContent !== void 0) {
1532
+ baseMessage.reasoning_content = message.reasoningContent;
1533
+ }
1534
+ return baseMessage;
1535
+ });
1536
+ }
1537
+
1538
+ // src/provider/responsesAdapter.ts
1539
+ var responsesAdapter = {
1540
+ wireApi: "responses",
1541
+ async fetchStreaming(client, request) {
1542
+ const startedAt = Date.now();
1543
+ let usage;
1544
+ throwIfAborted(request.abortSignal, "Streaming request aborted");
1545
+ try {
1546
+ const stream = await client.responses.create(
1547
+ {
1548
+ ...buildResponsesRequestBody(request),
1549
+ stream: true
1550
+ },
1551
+ {
1552
+ signal: request.abortSignal
1553
+ }
1554
+ );
1555
+ if (request.abortSignal?.aborted) {
1556
+ abortStream2(stream);
1557
+ throw createAbortError("Streaming aborted");
1558
+ }
1559
+ let content = "";
1560
+ let reasoningContent = "";
1561
+ const toolCalls = /* @__PURE__ */ new Map();
1562
+ for await (const event of stream) {
1563
+ if (request.abortSignal?.aborted) {
1564
+ abortStream2(stream);
1565
+ throw createAbortError("Streaming aborted");
1566
+ }
1567
+ usage = normalizeProviderUsage(event.response?.usage) ?? usage;
1568
+ if (event.type === "response.output_text.delta" && typeof event.delta === "string") {
1569
+ content += event.delta;
1570
+ request.callbacks?.onAssistantDelta?.(event.delta);
1571
+ continue;
1572
+ }
1573
+ if ((event.type === "response.reasoning_text.delta" || event.type === "response.reasoning_summary_text.delta") && typeof event.delta === "string") {
1574
+ reasoningContent += event.delta;
1575
+ request.callbacks?.onReasoningDelta?.(event.delta);
1576
+ continue;
1577
+ }
1578
+ if (event.type === "response.function_call_arguments.delta" && typeof event.delta === "string") {
1579
+ const index = typeof event.output_index === "number" ? event.output_index : 0;
1580
+ const existing = toolCalls.get(index) ?? {
1581
+ id: event.item_id ?? `tool-${index}`,
1582
+ name: "",
1583
+ arguments: ""
1584
+ };
1585
+ existing.arguments += event.delta;
1586
+ toolCalls.set(index, existing);
1587
+ continue;
1588
+ }
1589
+ if (event.type === "response.function_call_arguments.done") {
1590
+ const index = typeof event.output_index === "number" ? event.output_index : 0;
1591
+ const existing = toolCalls.get(index) ?? {
1592
+ id: event.item_id ?? `tool-${index}`,
1593
+ name: "",
1594
+ arguments: ""
1595
+ };
1596
+ if (typeof event.name === "string") {
1597
+ existing.name = event.name;
1598
+ }
1599
+ if (typeof event.arguments === "string" && event.arguments.length > 0) {
1600
+ existing.arguments = event.arguments;
1601
+ }
1602
+ toolCalls.set(index, existing);
1603
+ continue;
1604
+ }
1605
+ if (event.type === "response.output_item.done" && event.item?.type === "function_call") {
1606
+ const index = typeof event.output_index === "number" ? event.output_index : 0;
1607
+ toolCalls.set(index, {
1608
+ id: event.item.call_id ?? event.item.id ?? `tool-${index}`,
1609
+ name: event.item.name ?? "",
1610
+ arguments: event.item.arguments ?? ""
1611
+ });
1612
+ }
1613
+ }
1614
+ return {
1615
+ content: content.length > 0 ? content : null,
1616
+ reasoningContent: reasoningContent.length > 0 ? reasoningContent : void 0,
1617
+ streamedAssistantContent: content.length > 0,
1618
+ streamedReasoningContent: reasoningContent.length > 0,
1619
+ toolCalls: [...toolCalls.entries()].sort((left, right) => left[0] - right[0]).map(([, toolCall]) => ({
1620
+ id: toolCall.id,
1621
+ type: "function",
1622
+ function: {
1623
+ name: toolCall.name,
1624
+ arguments: toolCall.arguments
1625
+ }
1626
+ }))
1627
+ };
1628
+ } finally {
1629
+ request.onRequestMetric?.({
1630
+ durationMs: Date.now() - startedAt,
1631
+ usage
1632
+ });
1633
+ }
1634
+ },
1635
+ async fetchNonStreaming(client, request) {
1636
+ const startedAt = Date.now();
1637
+ let usage;
1638
+ throwIfAborted(request.abortSignal, "Request aborted");
1639
+ try {
1640
+ const response = await client.responses.create(
1641
+ {
1642
+ ...buildResponsesRequestBody(request),
1643
+ stream: false
1644
+ },
1645
+ {
1646
+ signal: request.abortSignal
1647
+ }
1648
+ );
1649
+ usage = normalizeProviderUsage(response.usage);
1650
+ return {
1651
+ content: normalizeOutputText(response),
1652
+ reasoningContent: readResponseReasoning(response),
1653
+ streamedAssistantContent: false,
1654
+ streamedReasoningContent: false,
1655
+ toolCalls: readResponseToolCalls(response)
1656
+ };
1657
+ } finally {
1658
+ request.onRequestMetric?.({
1659
+ durationMs: Date.now() - startedAt,
1660
+ usage
1661
+ });
1662
+ }
1663
+ }
1664
+ };
1665
+ function buildResponsesRequestBody(request) {
1666
+ const capabilities = resolveProviderCapabilities({
1667
+ provider: request.provider,
1668
+ model: request.model
1669
+ });
1670
+ const body = {
1671
+ model: request.model,
1672
+ input: toResponsesInput(request.messages),
1673
+ tools: request.tools?.map((tool) => ({
1674
+ type: "function",
1675
+ name: tool.function.name,
1676
+ description: tool.function.description,
1677
+ parameters: tool.function.parameters ?? null,
1678
+ strict: false
1679
+ })),
1680
+ tool_choice: request.tools?.length ? "auto" : void 0
1681
+ };
1682
+ if (typeof request.maxOutputTokens === "number" && Number.isFinite(request.maxOutputTokens)) {
1683
+ body.max_output_tokens = Math.max(1, Math.trunc(request.maxOutputTokens));
1684
+ }
1685
+ const cachePolicy = resolveProviderCachePolicy({
1686
+ provider: request.provider,
1687
+ model: request.model,
1688
+ sessionId: request.sessionId,
1689
+ projectRoot: request.projectRoot
1690
+ });
1691
+ if (cachePolicy.promptCacheKey) {
1692
+ body.prompt_cache_key = cachePolicy.promptCacheKey;
1693
+ }
1694
+ const reasoningEffort = request.thinking === "disabled" ? void 0 : normalizeResponsesReasoningEffort(
1695
+ request.reasoningEffort ?? capabilities.defaultReasoningEffort
1696
+ );
1697
+ if (request.thinking !== "disabled" && (request.forceReasoning || capabilities.defaultReasoningEnabled || request.thinking === "enabled" || reasoningEffort)) {
1698
+ body.reasoning = {
1699
+ effort: reasoningEffort ?? "high",
1700
+ summary: "detailed"
1701
+ };
1702
+ }
1703
+ return body;
1704
+ }
1705
+ function normalizeResponsesReasoningEffort(effort) {
1706
+ if (effort === "xhigh") {
1707
+ return "xhigh";
1708
+ }
1709
+ return effort === "max" ? void 0 : effort;
1710
+ }
1711
+ function toResponsesInput(messages) {
1712
+ const items = [];
1713
+ for (const message of messages) {
1714
+ if (message.role === "tool") {
1715
+ items.push({
1716
+ type: "function_call_output",
1717
+ call_id: message.toolCallId ?? "",
1718
+ output: message.content ?? ""
1719
+ });
1720
+ continue;
1721
+ }
1722
+ if (message.role === "assistant" && message.toolCalls?.length) {
1723
+ if (typeof message.content === "string" && message.content.trim().length > 0) {
1724
+ items.push({
1725
+ type: "message",
1726
+ role: "assistant",
1727
+ content: message.content
1728
+ });
1729
+ }
1730
+ for (const toolCall of message.toolCalls) {
1731
+ items.push({
1732
+ type: "function_call",
1733
+ call_id: toolCall.id,
1734
+ name: toolCall.function.name,
1735
+ arguments: toolCall.function.arguments
1736
+ });
1737
+ }
1738
+ continue;
1739
+ }
1740
+ items.push({
1741
+ type: "message",
1742
+ role: message.role,
1743
+ content: message.content ?? ""
1744
+ });
1745
+ }
1746
+ return items;
1747
+ }
1748
+ function normalizeOutputText(response) {
1749
+ const outputText = response.output_text;
1750
+ if (typeof outputText === "string" && outputText.trim().length > 0) {
1751
+ return outputText;
1752
+ }
1753
+ const output = response.output;
1754
+ if (!Array.isArray(output)) {
1755
+ return null;
1756
+ }
1757
+ const fragments = output.flatMap((item) => {
1758
+ if (!item || typeof item !== "object" || item.type !== "message") {
1759
+ return [];
1760
+ }
1761
+ const content = item.content;
1762
+ if (!Array.isArray(content)) {
1763
+ return [];
1764
+ }
1765
+ return content.flatMap((part) => {
1766
+ if (!part || typeof part !== "object" || part.type !== "output_text") {
1767
+ return [];
1768
+ }
1769
+ return typeof part.text === "string" ? [part.text] : [];
1770
+ });
1771
+ });
1772
+ return fragments.length > 0 ? fragments.join("") : null;
1773
+ }
1774
+ function readResponseToolCalls(response) {
1775
+ const output = response.output;
1776
+ if (!Array.isArray(output)) {
1777
+ return [];
1778
+ }
1779
+ return output.filter((item) => Boolean(item) && typeof item === "object" && item.type === "function_call").map((item) => ({
1780
+ id: item.call_id ?? item.id ?? crypto.randomUUID(),
1781
+ type: "function",
1782
+ function: {
1783
+ name: item.name ?? "",
1784
+ arguments: item.arguments ?? ""
1785
+ }
1786
+ }));
1787
+ }
1788
+ function readResponseReasoning(response) {
1789
+ const output = response.output;
1790
+ if (!Array.isArray(output)) {
1791
+ return void 0;
1792
+ }
1793
+ const fragments = output.flatMap((item) => {
1794
+ if (!item || typeof item !== "object" || item.type !== "reasoning") {
1795
+ return [];
1796
+ }
1797
+ const reasoningItem = item;
1798
+ const summary = Array.isArray(reasoningItem.summary) ? reasoningItem.summary.map((entry) => typeof entry?.text === "string" ? entry.text : "").filter(Boolean) : [];
1799
+ const content = Array.isArray(reasoningItem.content) ? reasoningItem.content.map((entry) => typeof entry?.text === "string" ? entry.text : "").filter(Boolean) : [];
1800
+ return [...content, ...summary];
1801
+ });
1802
+ return fragments.length > 0 ? fragments.join("") : void 0;
1803
+ }
1804
+ function abortStream2(stream) {
1805
+ try {
1806
+ stream?.controller?.abort();
1807
+ } catch {
1808
+ }
1809
+ }
1810
+
1811
+ // src/provider/client.ts
1812
+ import OpenAI from "openai";
1813
+
1814
+ // src/provider/connection.ts
1815
+ function buildProviderBaseUrlCandidates(baseUrl) {
1816
+ const normalized = trimTrailingSlash(baseUrl);
1817
+ if (!normalized) {
1818
+ return [normalized];
1819
+ }
1820
+ const candidates = [normalized];
1821
+ try {
1822
+ const parsed = new URL(normalized);
1823
+ if (parsed.pathname === "" || parsed.pathname === "/") {
1824
+ candidates.push(trimTrailingSlash(new URL("v1", ensureTrailingSlash2(parsed.toString())).toString()));
1825
+ }
1826
+ } catch {
1827
+ return candidates;
1828
+ }
1829
+ return [...new Set(candidates)];
1830
+ }
1831
+ function ensureTrailingSlash2(baseUrl) {
1832
+ return baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
1833
+ }
1834
+ function trimTrailingSlash(baseUrl) {
1835
+ const trimmed = String(baseUrl ?? "").trim();
1836
+ if (!trimmed) {
1837
+ return trimmed;
1838
+ }
1839
+ return trimmed.endsWith("/") ? trimmed.slice(0, -1) : trimmed;
1840
+ }
1841
+
1842
+ // src/provider/client.ts
1843
+ function createProviderClientPool(config) {
1844
+ const capabilities = resolveProviderCapabilities({
1845
+ provider: config.provider,
1846
+ model: config.model
1847
+ });
1848
+ const baseUrls = buildProviderBaseUrlCandidates(config.baseUrl);
1849
+ const clients = /* @__PURE__ */ new Map();
1850
+ let preferredBaseUrl;
1851
+ return {
1852
+ candidates() {
1853
+ const ordered = preferredBaseUrl ? [preferredBaseUrl, ...baseUrls.filter((baseUrl) => baseUrl !== preferredBaseUrl)] : baseUrls;
1854
+ return ordered.map((baseUrl) => ({
1855
+ baseUrl,
1856
+ client: getOrCreateClient(baseUrl)
1857
+ }));
1858
+ },
1859
+ markHealthy(baseUrl) {
1860
+ preferredBaseUrl = baseUrl;
1861
+ }
1862
+ };
1863
+ function getOrCreateClient(baseUrl) {
1864
+ const existing = clients.get(baseUrl);
1865
+ if (existing) {
1866
+ return existing;
1867
+ }
1868
+ const client = new OpenAI({
1869
+ apiKey: config.apiKey,
1870
+ baseURL: baseUrl,
1871
+ timeout: capabilities.requestTimeoutMs,
1872
+ maxRetries: 0
1873
+ });
1874
+ clients.set(baseUrl, client);
1875
+ return client;
1876
+ }
1877
+ }
1878
+ function isProviderClientPool(value) {
1879
+ return Boolean(
1880
+ value && typeof value === "object" && typeof value.candidates === "function" && typeof value.markHealthy === "function"
1881
+ );
1882
+ }
1883
+
1884
+ // src/provider/request.ts
1885
+ async function fetchAssistantResponse(client, messages, request, tools, callbacks, abortSignal, onRequestMetric, observability) {
1886
+ const capabilities = resolveProviderCapabilities(request);
1887
+ const adapter = selectProviderWireAdapter(capabilities.wireApi);
1888
+ return tryFetch(
1889
+ adapter,
1890
+ client,
1891
+ messages,
1892
+ request,
1893
+ tools,
1894
+ callbacks,
1895
+ false,
1896
+ abortSignal,
1897
+ onRequestMetric,
1898
+ observability
1899
+ );
1900
+ }
1901
+ async function tryFetch(adapter, client, messages, request, tools, callbacks, forceReasoning, abortSignal, onRequestMetric, observability) {
1902
+ const startedAt = Date.now();
1903
+ let latestMetric;
1904
+ let resolvedBaseUrl;
1905
+ const forwardMetric = (metric) => {
1906
+ latestMetric = metric;
1907
+ onRequestMetric?.(metric);
1908
+ };
1909
+ if (observability) {
1910
+ await recordObservabilityEvent(observability.rootDir, {
1911
+ event: "model.request",
1912
+ status: "started",
1913
+ sessionId: observability.sessionId,
1914
+ identityKind: observability.identityKind,
1915
+ identityName: observability.identityName,
1916
+ model: request.model,
1917
+ details: {
1918
+ provider: request.provider,
1919
+ configuredModel: observability.configuredModel,
1920
+ requestModel: request.model,
1921
+ wireApi: adapter.wireApi,
1922
+ baseUrl: resolvedBaseUrl
1923
+ }
1924
+ });
1925
+ }
1926
+ try {
1927
+ const response = await withApiRetries(
1928
+ () => invokeWithProviderClients(client, async (providerClient, baseUrl) => {
1929
+ resolvedBaseUrl = baseUrl;
1930
+ return adapter.fetchStreaming(providerClient, {
1931
+ provider: request.provider,
1932
+ model: request.model,
1933
+ messages,
1934
+ tools,
1935
+ callbacks,
1936
+ forceReasoning,
1937
+ thinking: request.thinking,
1938
+ reasoningEffort: request.reasoningEffort,
1939
+ maxOutputTokens: request.maxOutputTokens,
1940
+ sessionId: request.sessionId,
1941
+ projectRoot: request.projectRoot,
1942
+ abortSignal,
1943
+ onRequestMetric: forwardMetric
1944
+ });
1945
+ }),
1946
+ abortSignal
1947
+ );
1948
+ if (observability) {
1949
+ await recordObservabilityEvent(observability.rootDir, {
1950
+ event: "model.request",
1951
+ status: "completed",
1952
+ sessionId: observability.sessionId,
1953
+ identityKind: observability.identityKind,
1954
+ identityName: observability.identityName,
1955
+ model: request.model,
1956
+ durationMs: Date.now() - startedAt,
1957
+ details: {
1958
+ provider: request.provider,
1959
+ configuredModel: observability.configuredModel,
1960
+ requestModel: request.model,
1961
+ wireApi: adapter.wireApi,
1962
+ baseUrl: resolvedBaseUrl,
1963
+ usage: latestMetric?.usage,
1964
+ usageAvailable: hasProviderUsageSnapshot(latestMetric?.usage)
1965
+ }
1966
+ });
1967
+ }
1968
+ return response;
1969
+ } catch (error) {
1970
+ if (isAbortError(error)) {
1971
+ throw error;
1972
+ }
1973
+ try {
1974
+ const response = await withApiRetries(
1975
+ () => invokeWithProviderClients(client, async (providerClient, baseUrl) => {
1976
+ resolvedBaseUrl = baseUrl;
1977
+ return adapter.fetchNonStreaming(providerClient, {
1978
+ provider: request.provider,
1979
+ model: request.model,
1980
+ messages,
1981
+ tools,
1982
+ callbacks,
1983
+ forceReasoning,
1984
+ thinking: request.thinking,
1985
+ reasoningEffort: request.reasoningEffort,
1986
+ maxOutputTokens: request.maxOutputTokens,
1987
+ sessionId: request.sessionId,
1988
+ projectRoot: request.projectRoot,
1989
+ abortSignal,
1990
+ onRequestMetric: forwardMetric
1991
+ });
1992
+ }),
1993
+ abortSignal
1994
+ );
1995
+ if (observability) {
1996
+ await recordObservabilityEvent(observability.rootDir, {
1997
+ event: "model.request",
1998
+ status: "completed",
1999
+ sessionId: observability.sessionId,
2000
+ identityKind: observability.identityKind,
2001
+ identityName: observability.identityName,
2002
+ model: request.model,
2003
+ durationMs: Date.now() - startedAt,
2004
+ details: {
2005
+ provider: request.provider,
2006
+ configuredModel: observability.configuredModel,
2007
+ requestModel: request.model,
2008
+ wireApi: adapter.wireApi,
2009
+ baseUrl: resolvedBaseUrl,
2010
+ usage: latestMetric?.usage,
2011
+ usageAvailable: hasProviderUsageSnapshot(latestMetric?.usage)
2012
+ }
2013
+ });
2014
+ }
2015
+ return response;
2016
+ } catch (fallbackError) {
2017
+ if (!isAbortError(fallbackError) && observability) {
2018
+ await recordObservabilityEvent(observability.rootDir, {
2019
+ event: "model.request",
2020
+ status: "failed",
2021
+ sessionId: observability.sessionId,
2022
+ identityKind: observability.identityKind,
2023
+ identityName: observability.identityName,
2024
+ model: request.model,
2025
+ durationMs: Date.now() - startedAt,
2026
+ error: fallbackError,
2027
+ details: {
2028
+ provider: request.provider,
2029
+ configuredModel: observability.configuredModel,
2030
+ requestModel: request.model,
2031
+ wireApi: adapter.wireApi,
2032
+ baseUrl: resolvedBaseUrl,
2033
+ usage: latestMetric?.usage,
2034
+ usageAvailable: hasProviderUsageSnapshot(latestMetric?.usage)
2035
+ }
2036
+ });
2037
+ }
2038
+ throw fallbackError;
2039
+ }
2040
+ }
2041
+ }
2042
+ function selectProviderWireAdapter(wireApi) {
2043
+ if (wireApi === "responses") {
2044
+ return responsesAdapter;
2045
+ }
2046
+ return chatCompletionsAdapter;
2047
+ }
2048
+ async function invokeWithProviderClients(client, operation) {
2049
+ if (!isProviderClientPool(client)) {
2050
+ return operation(client, void 0);
2051
+ }
2052
+ let lastError;
2053
+ const candidates = client.candidates();
2054
+ for (let index = 0; index < candidates.length; index += 1) {
2055
+ const candidate = candidates[index];
2056
+ try {
2057
+ const result = await operation(candidate.client, candidate.baseUrl);
2058
+ client.markHealthy(candidate.baseUrl);
2059
+ return result;
2060
+ } catch (error) {
2061
+ lastError = error;
2062
+ if (isAbortError(error)) {
2063
+ throw error;
2064
+ }
2065
+ const hasMoreCandidates = index < candidates.length - 1;
2066
+ if (!hasMoreCandidates || !canRetryWithAlternateBaseUrl(error)) {
2067
+ throw error;
2068
+ }
2069
+ }
2070
+ }
2071
+ throw lastError;
2072
+ }
2073
+ function canRetryWithAlternateBaseUrl(error) {
2074
+ const status = error.status;
2075
+ const message = String(error.message ?? error).toLowerCase();
2076
+ return status === 404 || status === 405 || message.includes("404") || message.includes("not found");
2077
+ }
2078
+
922
2079
  // src/provider/retryPolicy.ts
923
2080
  function isRecoverableTurnError(error) {
924
2081
  if (isRetryableApiError(error)) {
@@ -1650,7 +2807,8 @@ function buildCompressedContextRequest(systemPrompt, messages, config) {
1650
2807
  const safeMaxChars = Math.max(8e3, config.maxContextChars);
1651
2808
  const conversation = buildVisibleConversationWindow(messages);
1652
2809
  const conversationMessages = conversation.messages;
1653
- const fullMessages = composeChatMessages(systemPrompt, conversationMessages, config.model);
2810
+ const provider = config.provider ?? "openai-compatible";
2811
+ const fullMessages = composeChatMessages(systemPrompt, conversationMessages, config.model, provider);
1654
2812
  const initialEstimatedChars = estimateChatMessagesChars(fullMessages);
1655
2813
  const initialPromptMetrics = measureSystemPrompt(systemPrompt);
1656
2814
  const initialSources = buildBudgetSources(systemPrompt, conversationMessages);
@@ -1679,7 +2837,7 @@ function buildCompressedContextRequest(systemPrompt, messages, config) {
1679
2837
  const summary = compressedFrameHead.length > 0 ? summarizeConversation(compressedFrameHead, config.contextSummaryChars) : void 0;
1680
2838
  const summaryPrompt = appendSummary(systemPrompt, summary);
1681
2839
  let workingTail = compactTailMessages(tailMessages, "normal");
1682
- let requestMessages = composeChatMessages(summaryPrompt, workingTail, config.model);
2840
+ let requestMessages = composeChatMessages(summaryPrompt, workingTail, config.model, provider);
1683
2841
  let estimatedChars = estimateChatMessagesChars(requestMessages);
1684
2842
  let promptMetrics = measureSystemPrompt(summaryPrompt);
1685
2843
  let cacheLayout = buildCacheLayoutReport(summaryPrompt, workingTail);
@@ -1704,7 +2862,7 @@ function buildCompressedContextRequest(systemPrompt, messages, config) {
1704
2862
  };
1705
2863
  }
1706
2864
  workingTail = compactTailMessages(tailMessages, "aggressive");
1707
- requestMessages = composeChatMessages(summaryPrompt, workingTail, config.model);
2865
+ requestMessages = composeChatMessages(summaryPrompt, workingTail, config.model, provider);
1708
2866
  estimatedChars = estimateChatMessagesChars(requestMessages);
1709
2867
  promptMetrics = measureSystemPrompt(summaryPrompt);
1710
2868
  cacheLayout = buildCacheLayoutReport(summaryPrompt, workingTail);
@@ -1740,7 +2898,8 @@ function buildCompressedContextRequest(systemPrompt, messages, config) {
1740
2898
  const hardMessages = composeChatMessages(
1741
2899
  hardPrompt,
1742
2900
  compactedHardTail,
1743
- config.model
2901
+ config.model,
2902
+ provider
1744
2903
  );
1745
2904
  const hardEstimatedChars = estimateChatMessagesChars(hardMessages);
1746
2905
  const hardCacheLayout = buildCacheLayoutReport(hardPrompt, compactedHardTail);
@@ -1775,7 +2934,7 @@ function sliceTailMessages(messages, tailCount) {
1775
2934
  const safeStartIndex = expandStartToToolBoundary(messages, startIndex);
1776
2935
  return messages.slice(safeStartIndex);
1777
2936
  }
1778
- function composeChatMessages(systemPrompt, messages, model) {
2937
+ function composeChatMessages(systemPrompt, messages, model, provider) {
1779
2938
  return [
1780
2939
  {
1781
2940
  role: "system",
@@ -1787,7 +2946,7 @@ function composeChatMessages(systemPrompt, messages, model) {
1787
2946
  name: message.name,
1788
2947
  toolCallId: message.tool_call_id,
1789
2948
  toolCalls: message.tool_calls,
1790
- reasoningContent: shouldIncludeStoredAssistantReasoning(messages, index, model) ? message.reasoningContent : void 0
2949
+ reasoningContent: shouldIncludeStoredAssistantReasoning(messages, index, model, provider) ? message.reasoningContent : void 0
1791
2950
  }))
1792
2951
  ];
1793
2952
  }
@@ -1934,8 +3093,8 @@ function buildCacheLayoutReport(systemPrompt, messages) {
1934
3093
  }))
1935
3094
  });
1936
3095
  return {
1937
- stablePrefixFingerprint: stableHash(stablePrefix),
1938
- volatileTailFingerprint: stableHash(volatileTail),
3096
+ stablePrefixFingerprint: stableHash2(stablePrefix),
3097
+ volatileTailFingerprint: stableHash2(volatileTail),
1939
3098
  stablePrefixChars: stablePrefix.length,
1940
3099
  volatileTailChars: volatileTail.length,
1941
3100
  stableSources: typeof systemPrompt === "string" ? ["systemPrompt"] : [
@@ -1966,7 +3125,7 @@ function renderVolatileRuntimeFacts(systemPrompt) {
1966
3125
  joinBlocks(systemPrompt.runtimeFactBlocks)
1967
3126
  ].join("\n").trim();
1968
3127
  }
1969
- function stableHash(value) {
3128
+ function stableHash2(value) {
1970
3129
  let hash = 2166136261;
1971
3130
  for (let index = 0; index < value.length; index += 1) {
1972
3131
  hash ^= value.charCodeAt(index);
@@ -2202,6 +3361,7 @@ async function updateSessionMemoryAfterTurn(input) {
2202
3361
  identityName: input.identity.name,
2203
3362
  model: input.requestModel
2204
3363
  });
3364
+ input.options.callbacks?.onStatus?.("\u603B\u7ED3\u4E2D");
2205
3365
  try {
2206
3366
  const memoryResponse = input.options.fetchSessionMemoryResponse ? await input.options.fetchSessionMemoryResponse(modelRequest) : await fetchAssistantResponse(
2207
3367
  input.client,
@@ -2252,6 +3412,8 @@ async function updateSessionMemoryAfterTurn(input) {
2252
3412
  error
2253
3413
  });
2254
3414
  return input.session;
3415
+ } finally {
3416
+ input.options.callbacks?.onStatus?.("");
2255
3417
  }
2256
3418
  }
2257
3419
  async function updateSessionTitleAfterTurn(input) {
@@ -2299,6 +3461,7 @@ async function updateSessionTitleAfterTurn(input) {
2299
3461
  identityName: input.identity.name,
2300
3462
  model: input.requestModel
2301
3463
  });
3464
+ input.options.callbacks?.onStatus?.("\u6807\u9898\u751F\u6210\u4E2D");
2302
3465
  try {
2303
3466
  const titleResponse = input.options.fetchSessionTitleResponse ? await input.options.fetchSessionTitleResponse(modelRequest) : await fetchAssistantResponse(
2304
3467
  input.client,
@@ -2350,15 +3513,17 @@ async function updateSessionTitleAfterTurn(input) {
2350
3513
  error
2351
3514
  });
2352
3515
  return input.session;
3516
+ } finally {
3517
+ input.options.callbacks?.onStatus?.("");
2353
3518
  }
2354
3519
  }
2355
3520
 
2356
3521
  // src/control/ledger.ts
2357
3522
  import Database from "better-sqlite3";
2358
- import fs6 from "fs";
3523
+ import fs8 from "fs";
2359
3524
 
2360
3525
  // src/control/executions.ts
2361
- import path7 from "path";
3526
+ import path9 from "path";
2362
3527
 
2363
3528
  // src/protocol/leadWait.ts
2364
3529
  var LEAD_WAIT_PROTOCOL = "kitty.lead-wait-policy";
@@ -2587,7 +3752,7 @@ var ExecutionLedgerRepo = class {
2587
3752
  prompt: input.prompt,
2588
3753
  actorName: input.actorName,
2589
3754
  actorRole: input.actorRole,
2590
- cwd: path7.resolve(input.cwd),
3755
+ cwd: path9.resolve(input.cwd),
2591
3756
  requestedBy: input.requestedBy,
2592
3757
  sessionId: input.sessionId,
2593
3758
  pid: input.pid,
@@ -2618,10 +3783,10 @@ var ExecutionLedgerRepo = class {
2618
3783
  }
2619
3784
  list(input = {}) {
2620
3785
  const rows = this.db.prepare("SELECT * FROM executions ORDER BY created_at ASC").all();
2621
- const cwd = input.cwd ? path7.resolve(input.cwd) : void 0;
3786
+ const cwd = input.cwd ? path9.resolve(input.cwd) : void 0;
2622
3787
  const statuses = new Set(input.statuses ?? []);
2623
3788
  const kinds = new Set(input.kinds ?? []);
2624
- return rows.map(fromExecutionRow).filter((record) => !input.kind || record.kind === input.kind).filter((record) => kinds.size === 0 || kinds.has(record.kind)).filter((record) => statuses.size === 0 || statuses.has(record.status)).filter((record) => !cwd || isSameOrDescendant(path7.resolve(record.cwd), cwd) || isSameOrDescendant(cwd, path7.resolve(record.cwd)));
3789
+ return rows.map(fromExecutionRow).filter((record) => !input.kind || record.kind === input.kind).filter((record) => kinds.size === 0 || kinds.has(record.kind)).filter((record) => statuses.size === 0 || statuses.has(record.status)).filter((record) => !cwd || isSameOrDescendant(path9.resolve(record.cwd), cwd) || isSameOrDescendant(cwd, path9.resolve(record.cwd)));
2625
3790
  }
2626
3791
  markRunning(id, input) {
2627
3792
  const current = requireExecution(this.load(id), id);
@@ -2699,8 +3864,8 @@ function requireExecution(record, id) {
2699
3864
  return record;
2700
3865
  }
2701
3866
  function isSameOrDescendant(targetPath, possibleAncestor) {
2702
- const relative = path7.relative(possibleAncestor, targetPath);
2703
- return relative === "" || !relative.startsWith("..") && !path7.isAbsolute(relative);
3867
+ const relative = path9.relative(possibleAncestor, targetPath);
3868
+ return relative === "" || !relative.startsWith("..") && !path9.isAbsolute(relative);
2704
3869
  }
2705
3870
 
2706
3871
  // src/control/schema.ts
@@ -2814,7 +3979,7 @@ var TaskLifecycleLedgerRepo = class {
2814
3979
  stage: existing?.stage === "completed" || !existing ? "normal_work" : existing.stage,
2815
3980
  scope: existing?.scope,
2816
3981
  boundary: existing?.boundary,
2817
- reason: normalizeText2(input.reason) ?? existing?.reason ?? "turn_started",
3982
+ reason: normalizeText3(input.reason) ?? existing?.reason ?? "turn_started",
2818
3983
  activeExecutionIds: existing?.activeExecutionIds ?? [],
2819
3984
  activeTodoIds: existing?.activeTodoIds ?? [],
2820
3985
  verificationFacts: existing?.verificationFacts ?? [],
@@ -2843,9 +4008,9 @@ var TaskLifecycleLedgerRepo = class {
2843
4008
  return this.save({
2844
4009
  ...current,
2845
4010
  stage: input.stage ?? current.stage,
2846
- scope: normalizeText2(input.scope) ?? current.scope,
2847
- boundary: normalizeText2(input.boundary) ?? current.boundary,
2848
- reason: normalizeText2(input.reason) ?? current.reason,
4011
+ scope: normalizeText3(input.scope) ?? current.scope,
4012
+ boundary: normalizeText3(input.boundary) ?? current.boundary,
4013
+ reason: normalizeText3(input.reason) ?? current.reason,
2849
4014
  activeExecutionIds: normalizeStringList2(input.activeExecutionIds ?? current.activeExecutionIds),
2850
4015
  activeTodoIds: normalizeStringList2(input.activeTodoIds ?? current.activeTodoIds),
2851
4016
  verificationFacts: normalizeStringList2(input.verificationFacts ?? current.verificationFacts),
@@ -2961,7 +4126,7 @@ function normalizeStringList2(value) {
2961
4126
  const seen = /* @__PURE__ */ new Set();
2962
4127
  const items = [];
2963
4128
  for (const item of value) {
2964
- const text = normalizeText2(item);
4129
+ const text = normalizeText3(item);
2965
4130
  if (!text || seen.has(text)) {
2966
4131
  continue;
2967
4132
  }
@@ -2970,7 +4135,7 @@ function normalizeStringList2(value) {
2970
4135
  }
2971
4136
  return items;
2972
4137
  }
2973
- function normalizeText2(value) {
4138
+ function normalizeText3(value) {
2974
4139
  return typeof value === "string" && value.trim() ? value.replace(/\s+/g, " ").trim() : void 0;
2975
4140
  }
2976
4141
 
@@ -3010,7 +4175,7 @@ var ControlPlaneLedger = class {
3010
4175
  db;
3011
4176
  constructor(rootDir) {
3012
4177
  const statePaths = getProjectStatePaths(rootDir);
3013
- fs6.mkdirSync(statePaths.kittyDir, { recursive: true });
4178
+ fs8.mkdirSync(statePaths.kittyDir, { recursive: true });
3014
4179
  this.db = new Database(statePaths.controlPlaneLedgerFile);
3015
4180
  this.db.pragma("journal_mode = WAL");
3016
4181
  this.db.pragma("foreign_keys = ON");
@@ -3177,11 +4342,11 @@ function truncateWakeFact(value) {
3177
4342
  }
3178
4343
 
3179
4344
  // src/utils/fs.ts
3180
- import fs7 from "fs/promises";
3181
- import path8 from "path";
4345
+ import fs9 from "fs/promises";
4346
+ import path10 from "path";
3182
4347
  async function fileExists(targetPath) {
3183
4348
  try {
3184
- await fs7.access(targetPath);
4349
+ await fs9.access(targetPath);
3185
4350
  return true;
3186
4351
  } catch {
3187
4352
  return false;
@@ -3189,10 +4354,10 @@ async function fileExists(targetPath) {
3189
4354
  }
3190
4355
  function resolveUserPath(inputPath, cwd) {
3191
4356
  const cleanPath = normalizeUserPathInput(inputPath);
3192
- if (path8.isAbsolute(cleanPath)) {
3193
- return path8.normalize(cleanPath);
4357
+ if (path10.isAbsolute(cleanPath)) {
4358
+ return path10.normalize(cleanPath);
3194
4359
  }
3195
- return path8.resolve(cwd, cleanPath);
4360
+ return path10.resolve(cwd, cleanPath);
3196
4361
  }
3197
4362
  function normalizeUserPathInput(inputPath) {
3198
4363
  const trimmed = inputPath.trim();
@@ -3206,7 +4371,7 @@ function normalizeUserPathInput(inputPath) {
3206
4371
  return trimmed;
3207
4372
  }
3208
4373
  async function ensureParentDirectory(filePath) {
3209
- await fs7.mkdir(path8.dirname(filePath), { recursive: true });
4374
+ await fs9.mkdir(path10.dirname(filePath), { recursive: true });
3210
4375
  }
3211
4376
  function truncateText(input, maxChars) {
3212
4377
  if (input.length <= maxChars) {
@@ -3258,7 +4423,7 @@ function projectToolResultForModel(input) {
3258
4423
  }
3259
4424
  }
3260
4425
  function projectExecutionAction(payload) {
3261
- const execution = readObject(payload.execution) ?? payload;
4426
+ const execution = readObject2(payload.execution) ?? payload;
3262
4427
  return joinLines([
3263
4428
  readString(execution.id) ?? "execution",
3264
4429
  readString(execution.kind),
@@ -3266,7 +4431,7 @@ function projectExecutionAction(payload) {
3266
4431
  readString(execution.command),
3267
4432
  readString(execution.summary),
3268
4433
  readString(execution.outputPreview),
3269
- readObject(execution.health) ? readString(readObject(execution.health)?.message) : void 0,
4434
+ readObject2(execution.health) ? readString(readObject2(execution.health)?.message) : void 0,
3270
4435
  readString(execution.error)
3271
4436
  ]);
3272
4437
  }
@@ -3293,10 +4458,10 @@ function projectExecutionCheck(payload) {
3293
4458
  ]);
3294
4459
  }
3295
4460
  function projectRead(payload) {
3296
- const path27 = readString(payload.path) ?? readString(payload.requestedPath) ?? "file";
4461
+ const path29 = readString(payload.path) ?? readString(payload.requestedPath) ?? "file";
3297
4462
  if (payload.readable === false) {
3298
4463
  return joinLines([
3299
- `${path27}: not readable`,
4464
+ `${path29}: not readable`,
3300
4465
  readString(payload.reason),
3301
4466
  readString(payload.detectedCapability) ? `capability: ${readString(payload.detectedCapability)}` : void 0
3302
4467
  ]);
@@ -3304,35 +4469,35 @@ function projectRead(payload) {
3304
4469
  const startLine = readNumber(payload.startLine);
3305
4470
  const endLine = readNumber(payload.endLine);
3306
4471
  const content = readString(payload.content) ?? "";
3307
- const continuation = readObject(payload.continuation);
3308
- const continuationArgs = readObject(continuation?.continuationArgs);
4472
+ const continuation = readObject2(payload.continuation);
4473
+ const continuationArgs = readObject2(continuation?.continuationArgs);
3309
4474
  return joinLines([
3310
- `${path27}${startLine && endLine ? `:${startLine}-${endLine}` : ""}`,
4475
+ `${path29}${startLine && endLine ? `:${startLine}-${endLine}` : ""}`,
3311
4476
  truncateText(content, DEFAULT_MAX_CHARS),
3312
4477
  continuationArgs ? `next: read ${JSON.stringify(continuationArgs)}` : void 0
3313
4478
  ]);
3314
4479
  }
3315
4480
  function projectEdit(payload) {
3316
- const path27 = readString(payload.path) ?? "file";
4481
+ const path29 = readString(payload.path) ?? "file";
3317
4482
  const applied = readNumber(payload.appliedEdits) ?? readNumber(payload.requestedEdits);
3318
4483
  const diff = readString(payload.diff) ?? readString(payload.preview);
3319
4484
  return joinLines([
3320
- `edited ${path27}${applied ? ` (${applied} replacement${applied === 1 ? "" : "s"})` : ""}`,
4485
+ `edited ${path29}${applied ? ` (${applied} replacement${applied === 1 ? "" : "s"})` : ""}`,
3321
4486
  diff ? truncateText(diff, DIFF_MAX_CHARS) : void 0
3322
4487
  ]);
3323
4488
  }
3324
4489
  function projectWrite(payload) {
3325
- const path27 = readString(payload.path) ?? "file";
4490
+ const path29 = readString(payload.path) ?? "file";
3326
4491
  const bytes = readNumber(payload.bytes);
3327
4492
  const existed = payload.existed === true;
3328
4493
  const diff = readString(payload.diff) ?? readString(payload.preview);
3329
4494
  return joinLines([
3330
- `${existed ? "wrote" : "created"} ${path27}${bytes !== void 0 ? ` (${bytes} bytes)` : ""}`,
4495
+ `${existed ? "wrote" : "created"} ${path29}${bytes !== void 0 ? ` (${bytes} bytes)` : ""}`,
3331
4496
  diff ? truncateText(diff, DIFF_MAX_CHARS) : void 0
3332
4497
  ]);
3333
4498
  }
3334
4499
  function projectBash(payload) {
3335
- const governance = readObject(payload.outputGovernance);
4500
+ const governance = readObject2(payload.outputGovernance);
3336
4501
  const projection = readString(governance?.projection);
3337
4502
  if (projection) {
3338
4503
  return projection;
@@ -3353,13 +4518,13 @@ function projectBash(payload) {
3353
4518
  return joinLines(lines);
3354
4519
  }
3355
4520
  function projectSkillLoad(payload) {
3356
- const skill = readObject(payload.skill);
4521
+ const skill = readObject2(payload.skill);
3357
4522
  const name = readString(skill?.name) ?? "skill";
3358
4523
  const description = readString(skill?.description);
3359
- const path27 = readString(skill?.path);
4524
+ const path29 = readString(skill?.path);
3360
4525
  const body = readString(payload.body) ?? "";
3361
4526
  return joinLines([
3362
- `loaded skill: ${name}${path27 ? ` (${path27})` : ""}`,
4527
+ `loaded skill: ${name}${path29 ? ` (${path29})` : ""}`,
3363
4528
  description,
3364
4529
  truncateText(body, SKILL_BODY_MAX_CHARS)
3365
4530
  ]);
@@ -3389,8 +4554,8 @@ function projectFailure(toolName, rawOutput, payload) {
3389
4554
  if (!payload) {
3390
4555
  return truncateText(rawOutput.trim(), DEFAULT_MAX_CHARS);
3391
4556
  }
3392
- const details = readObject(payload.details);
3393
- const readArgs = readObject(details?.readArgs);
4557
+ const details = readObject2(payload.details);
4558
+ const readArgs = readObject2(details?.readArgs);
3394
4559
  const suggestions = readArray(details?.suggestions);
3395
4560
  const lines = [
3396
4561
  `${toolName} failed: ${readString(payload.error) ?? "unknown error"}`,
@@ -3412,7 +4577,7 @@ function parseObject(raw) {
3412
4577
  return null;
3413
4578
  }
3414
4579
  }
3415
- function readObject(value) {
4580
+ function readObject2(value) {
3416
4581
  return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
3417
4582
  }
3418
4583
  function readArray(value) {
@@ -3447,14 +4612,14 @@ var ToolExecutionError = class extends Error {
3447
4612
  };
3448
4613
 
3449
4614
  // src/tools/outputCapture.ts
3450
- import crypto from "crypto";
3451
- import fs8 from "fs/promises";
3452
- import path9 from "path";
4615
+ import crypto2 from "crypto";
4616
+ import fs10 from "fs/promises";
4617
+ import path11 from "path";
3453
4618
  var DEFAULT_BASH_OUTPUT_PREVIEW_CHARS = 12e3;
3454
4619
  async function createBashOutputCapture(input) {
3455
4620
  const maxPreviewChars = typeof input.maxPreviewChars === "number" && Number.isFinite(input.maxPreviewChars) && input.maxPreviewChars > 0 ? Math.trunc(input.maxPreviewChars) : DEFAULT_BASH_OUTPUT_PREVIEW_CHARS;
3456
4621
  const absoluteOutputPath = input.stateRootDir && input.sessionId ? await createAbsoluteOutputPath(input.stateRootDir, input.sessionId) : void 0;
3457
- const outputPath = absoluteOutputPath && input.stateRootDir ? path9.relative(input.stateRootDir, absoluteOutputPath) || void 0 : void 0;
4622
+ const outputPath = absoluteOutputPath && input.stateRootDir ? path11.relative(input.stateRootDir, absoluteOutputPath) || void 0 : void 0;
3458
4623
  let preview = "";
3459
4624
  let bufferedOutput = "";
3460
4625
  let totalChars = 0;
@@ -3498,7 +4663,7 @@ async function createBashOutputCapture(input) {
3498
4663
  if (!absoluteOutputPath) {
3499
4664
  return;
3500
4665
  }
3501
- pendingWrite = pendingWrite.then(() => fs8.appendFile(absoluteOutputPath, chunk, "utf8"));
4666
+ pendingWrite = pendingWrite.then(() => fs10.appendFile(absoluteOutputPath, chunk, "utf8"));
3502
4667
  }
3503
4668
  return {
3504
4669
  append,
@@ -3507,9 +4672,9 @@ async function createBashOutputCapture(input) {
3507
4672
  }
3508
4673
  async function createAbsoluteOutputPath(stateRootDir, sessionId) {
3509
4674
  const paths = getProjectStatePaths(stateRootDir);
3510
- const sessionDir = path9.join(paths.observabilityDir, "command-output", sessionId);
3511
- await fs8.mkdir(sessionDir, { recursive: true });
3512
- return path9.join(sessionDir, `${Date.now()}-bash-output-${crypto.randomUUID().slice(0, 8)}.txt`);
4675
+ const sessionDir = path11.join(paths.observabilityDir, "command-output", sessionId);
4676
+ await fs10.mkdir(sessionDir, { recursive: true });
4677
+ return path11.join(sessionDir, `${Date.now()}-bash-output-${crypto2.randomUUID().slice(0, 8)}.txt`);
3513
4678
  }
3514
4679
 
3515
4680
  // src/utils/commandRunner/shellRuntime.ts
@@ -3723,8 +4888,8 @@ function isAbortedProcessResult(value, signal) {
3723
4888
  }
3724
4889
 
3725
4890
  // src/tools/core/shared.ts
3726
- import fs9 from "fs/promises";
3727
- import path10 from "path";
4891
+ import fs11 from "fs/promises";
4892
+ import path12 from "path";
3728
4893
  import { diffLines } from "diff";
3729
4894
 
3730
4895
  // src/utils/text.ts
@@ -3938,15 +5103,15 @@ function comparePathForDiscovery(root, left, right) {
3938
5103
  if (leftDepth !== rightDepth) {
3939
5104
  return leftDepth - rightDepth;
3940
5105
  }
3941
- const leftName = path10.posix.basename(leftRelative).toLowerCase();
3942
- const rightName = path10.posix.basename(rightRelative).toLowerCase();
5106
+ const leftName = path12.posix.basename(leftRelative).toLowerCase();
5107
+ const rightName = path12.posix.basename(rightRelative).toLowerCase();
3943
5108
  if (leftName !== rightName) {
3944
5109
  return leftName.localeCompare(rightName);
3945
5110
  }
3946
5111
  return leftRelative.localeCompare(rightRelative);
3947
5112
  }
3948
5113
  function toPosixRelative(root, targetPath) {
3949
- return (path10.relative(root, targetPath) || path10.basename(targetPath)).replace(/\\/g, "/");
5114
+ return (path12.relative(root, targetPath) || path12.basename(targetPath)).replace(/\\/g, "/");
3950
5115
  }
3951
5116
  function pathDepth(relativePath) {
3952
5117
  return relativePath.split("/").filter(Boolean).length;
@@ -4307,7 +5472,7 @@ var bashToolDefinition = {
4307
5472
  };
4308
5473
 
4309
5474
  // src/tools/edit.ts
4310
- import fs11 from "fs/promises";
5475
+ import fs13 from "fs/promises";
4311
5476
 
4312
5477
  // src/tools/core/changeTracking.ts
4313
5478
  async function recordToolChange(context, input) {
@@ -4348,13 +5513,13 @@ function encodeUtf8(value) {
4348
5513
  }
4349
5514
 
4350
5515
  // src/tools/core/pathDisplay.ts
4351
- import path11 from "path";
5516
+ import path13 from "path";
4352
5517
  function toToolRelativePath(cwd, targetPath) {
4353
- const relative = path11.relative(cwd, targetPath);
5518
+ const relative = path13.relative(cwd, targetPath);
4354
5519
  if (!relative || relative === "") {
4355
5520
  return ".";
4356
5521
  }
4357
- if (relative.startsWith("..") || path11.isAbsolute(relative)) {
5522
+ if (relative.startsWith("..") || path13.isAbsolute(relative)) {
4358
5523
  return targetPath;
4359
5524
  }
4360
5525
  return relative.replace(/\\/g, "/");
@@ -4381,8 +5546,8 @@ function buildToolChangeFeedback(input) {
4381
5546
  }
4382
5547
 
4383
5548
  // src/tools/writeDiagnostics.ts
4384
- import fs10 from "fs/promises";
4385
- import path12 from "path";
5549
+ import fs12 from "fs/promises";
5550
+ import path14 from "path";
4386
5551
  var TYPE_SCRIPT_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
4387
5552
  async function collectWriteDiagnostics(paths) {
4388
5553
  const uniquePaths2 = takeUniquePaths(paths);
@@ -4429,7 +5594,7 @@ function createEmptyDiagnosticsReport(status) {
4429
5594
  }
4430
5595
  async function collectFileDiagnostics(targetPath) {
4431
5596
  try {
4432
- const extension = path12.extname(targetPath).toLowerCase();
5597
+ const extension = path14.extname(targetPath).toLowerCase();
4433
5598
  if (extension === ".json") {
4434
5599
  return await collectJsonDiagnostics(targetPath);
4435
5600
  }
@@ -4445,7 +5610,7 @@ async function collectFileDiagnostics(targetPath) {
4445
5610
  return null;
4446
5611
  }
4447
5612
  async function collectJsonDiagnostics(targetPath) {
4448
- const content = await fs10.readFile(targetPath, "utf8");
5613
+ const content = await fs12.readFile(targetPath, "utf8");
4449
5614
  const diagnostics = [];
4450
5615
  try {
4451
5616
  JSON.parse(content);
@@ -4466,7 +5631,7 @@ async function collectJsonDiagnostics(targetPath) {
4466
5631
  async function collectTypeScriptDiagnostics(targetPath) {
4467
5632
  const diagnostics = [];
4468
5633
  const TypeScript = await import("typescript");
4469
- const content = await fs10.readFile(targetPath, "utf8");
5634
+ const content = await fs12.readFile(targetPath, "utf8");
4470
5635
  const transpiled = TypeScript.transpileModule(content, {
4471
5636
  fileName: targetPath,
4472
5637
  compilerOptions: {
@@ -4583,7 +5748,7 @@ var editToolDefinition = {
4583
5748
  const resolved = resolveUserPath(targetPath, context.cwd);
4584
5749
  const displayPath = toToolRelativePath(context.cwd, resolved);
4585
5750
  return withFileEditLock(resolved, async () => {
4586
- const beforeBuffer = await fs11.readFile(resolved);
5751
+ const beforeBuffer = await fs13.readFile(resolved);
4587
5752
  const beforeEnvelope = decodeTextFileEnvelope(beforeBuffer);
4588
5753
  if (!beforeEnvelope) {
4589
5754
  throw new ToolExecutionError(`edit cannot edit binary or unsupported text encoding for ${displayPath}`, {
@@ -4601,7 +5766,7 @@ var editToolDefinition = {
4601
5766
  });
4602
5767
  }
4603
5768
  const diff = buildDiffPreview(before, after);
4604
- await fs11.writeFile(resolved, encodeTextFileEnvelope(after, beforeEnvelope));
5769
+ await fs13.writeFile(resolved, encodeTextFileEnvelope(after, beforeEnvelope));
4605
5770
  const changeRecord = await recordToolChange(context, {
4606
5771
  toolName: "edit",
4607
5772
  summary: `edit ${displayPath}`,
@@ -4755,9 +5920,9 @@ function lineForOffset(input, offset) {
4755
5920
  }
4756
5921
  return line;
4757
5922
  }
4758
- function buildReadArgs(path27, line) {
5923
+ function buildReadArgs(path29, line) {
4759
5924
  return {
4760
- path: path27,
5925
+ path: path29,
4761
5926
  offset: Math.max(1, (line ?? 1) - 20),
4762
5927
  limit: 60
4763
5928
  };
@@ -4811,8 +5976,8 @@ async function withFileEditLock(filePath, action) {
4811
5976
  }
4812
5977
 
4813
5978
  // src/tools/core/fileIntrospection.ts
4814
- import fs12 from "fs/promises";
4815
- import path13 from "path";
5979
+ import fs14 from "fs/promises";
5980
+ import path15 from "path";
4816
5981
  var KNOWN_BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
4817
5982
  ".epub",
4818
5983
  ".mobi",
@@ -4830,8 +5995,8 @@ var KNOWN_BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
4830
5995
  ".bin"
4831
5996
  ]);
4832
5997
  async function inspectTextFile(filePath, _maxBytes) {
4833
- const stat = await fs12.stat(filePath);
4834
- const extension = path13.extname(filePath).toLowerCase();
5998
+ const stat = await fs14.stat(filePath);
5999
+ const extension = path15.extname(filePath).toLowerCase();
4835
6000
  if (KNOWN_BINARY_EXTENSIONS.has(extension)) {
4836
6001
  return {
4837
6002
  readable: false,
@@ -4841,7 +6006,7 @@ async function inspectTextFile(filePath, _maxBytes) {
4841
6006
  extension
4842
6007
  };
4843
6008
  }
4844
- const buffer = await fs12.readFile(filePath);
6009
+ const buffer = await fs14.readFile(filePath);
4845
6010
  const decoded = decodeTextFileEnvelope(buffer);
4846
6011
  if (!decoded) {
4847
6012
  return {
@@ -4865,11 +6030,11 @@ async function inspectTextFile(filePath, _maxBytes) {
4865
6030
  }
4866
6031
 
4867
6032
  // src/tools/core/pathSuggestions.ts
4868
- import path14 from "path";
6033
+ import path16 from "path";
4869
6034
  import fg3 from "fast-glob";
4870
6035
  async function findPathSuggestions(cwd, requestedPath, projectContext, limit = 8) {
4871
6036
  const normalized = normalizeUserPathInput(requestedPath).replace(/\\/g, "/");
4872
- const baseName = path14.basename(normalized).trim();
6037
+ const baseName = path16.basename(normalized).trim();
4873
6038
  const needle = baseName.length > 0 ? baseName : normalized.trim();
4874
6039
  if (!needle) {
4875
6040
  return [];
@@ -4886,8 +6051,8 @@ async function findPathSuggestions(cwd, requestedPath, projectContext, limit = 8
4886
6051
  suppressErrors: true,
4887
6052
  ignore: buildFastGlobIgnorePatterns(cwd, projectContext.ignoreRules)
4888
6053
  });
4889
- for (const entry of entries.sort((left, right) => comparePathForDiscovery(cwd, path14.resolve(cwd, left), path14.resolve(cwd, right)))) {
4890
- const absolutePath = path14.resolve(cwd, entry);
6054
+ for (const entry of entries.sort((left, right) => comparePathForDiscovery(cwd, path16.resolve(cwd, left), path16.resolve(cwd, right)))) {
6055
+ const absolutePath = path16.resolve(cwd, entry);
4891
6056
  const isDirectory3 = entry.endsWith("/");
4892
6057
  if (isPathIgnored(absolutePath, projectContext.ignoreRules, isDirectory3)) {
4893
6058
  continue;
@@ -5052,7 +6217,7 @@ function fitWindowWithinBudget(lines, start, requestedEndExclusive, maxChars) {
5052
6217
  }
5053
6218
 
5054
6219
  // src/tools/write.ts
5055
- import fs13 from "fs/promises";
6220
+ import fs15 from "fs/promises";
5056
6221
  var writeToolDefinition = {
5057
6222
  definition: {
5058
6223
  type: "function",
@@ -5088,12 +6253,12 @@ var writeToolDefinition = {
5088
6253
  const resolved = resolveUserPath(targetPath, context.cwd);
5089
6254
  const displayPath = toToolRelativePath(context.cwd, resolved);
5090
6255
  const existed = await fileExists(resolved);
5091
- const before = existed ? await fs13.readFile(resolved, "utf8") : "";
6256
+ const before = existed ? await fs15.readFile(resolved, "utf8") : "";
5092
6257
  const preview = buildDiffPreview(before, content);
5093
6258
  if (createDirectories) {
5094
6259
  await ensureParentDirectory(resolved);
5095
6260
  }
5096
- await fs13.writeFile(resolved, content, "utf8");
6261
+ await fs15.writeFile(resolved, content, "utf8");
5097
6262
  const changeRecord = await recordToolChange(context, {
5098
6263
  toolName: "write",
5099
6264
  summary: `write ${displayPath}`,
@@ -5148,7 +6313,7 @@ var writeToolDefinition = {
5148
6313
  };
5149
6314
 
5150
6315
  // src/tools/sendFile.ts
5151
- import fs14 from "fs/promises";
6316
+ import fs16 from "fs/promises";
5152
6317
  var sendFileToolDefinition = {
5153
6318
  definition: {
5154
6319
  type: "function",
@@ -5191,7 +6356,7 @@ var sendFileToolDefinition = {
5191
6356
  };
5192
6357
  }
5193
6358
  try {
5194
- await fs14.access(filePath);
6359
+ await fs16.access(filePath);
5195
6360
  } catch {
5196
6361
  return {
5197
6362
  ok: false,
@@ -5724,8 +6889,8 @@ async function executeToolBatch(params) {
5724
6889
  }
5725
6890
 
5726
6891
  // src/session/events.ts
5727
- import fs15 from "fs/promises";
5728
- import path15 from "path";
6892
+ import fs17 from "fs/promises";
6893
+ import path17 from "path";
5729
6894
  var SessionEventStore = class {
5730
6895
  constructor(eventsDir) {
5731
6896
  this.eventsDir = eventsDir;
@@ -5741,8 +6906,8 @@ var SessionEventStore = class {
5741
6906
  message: event.message,
5742
6907
  details: event.details
5743
6908
  };
5744
- await fs15.mkdir(this.eventsDir, { recursive: true });
5745
- await fs15.appendFile(this.getSessionEventPath(event.sessionId), `${JSON.stringify(record)}
6909
+ await fs17.mkdir(this.eventsDir, { recursive: true });
6910
+ await fs17.appendFile(this.getSessionEventPath(event.sessionId), `${JSON.stringify(record)}
5746
6911
  `, "utf8");
5747
6912
  return record;
5748
6913
  }
@@ -5750,7 +6915,7 @@ var SessionEventStore = class {
5750
6915
  const filePath = this.getSessionEventPath(sessionId);
5751
6916
  let raw = "";
5752
6917
  try {
5753
- raw = await fs15.readFile(filePath, "utf8");
6918
+ raw = await fs17.readFile(filePath, "utf8");
5754
6919
  } catch (error) {
5755
6920
  if (error.code === "ENOENT") {
5756
6921
  return [];
@@ -5760,7 +6925,7 @@ var SessionEventStore = class {
5760
6925
  return raw.split(/\r?\n/).filter(Boolean).map((line) => JSON.parse(line)).slice(-limit);
5761
6926
  }
5762
6927
  getSessionEventPath(sessionId) {
5763
- return path15.join(this.eventsDir, `${sanitizeSessionId(sessionId)}.jsonl`);
6928
+ return path17.join(this.eventsDir, `${sanitizeSessionId(sessionId)}.jsonl`);
5764
6929
  }
5765
6930
  };
5766
6931
  function createEventId() {
@@ -6079,9 +7244,9 @@ function normalizeToolArguments(raw) {
6079
7244
  }
6080
7245
 
6081
7246
  // src/agent/changes/store.ts
6082
- import crypto2 from "crypto";
6083
- import fs16 from "fs/promises";
6084
- import path16 from "path";
7247
+ import crypto3 from "crypto";
7248
+ import fs18 from "fs/promises";
7249
+ import path18 from "path";
6085
7250
  var ChangeStore = class {
6086
7251
  constructor(changesDir) {
6087
7252
  this.changesDir = changesDir;
@@ -6089,8 +7254,8 @@ var ChangeStore = class {
6089
7254
  async record(input) {
6090
7255
  const id = createChangeId();
6091
7256
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
6092
- const blobDir = path16.join(this.changesDir, id);
6093
- await fs16.mkdir(blobDir, { recursive: true });
7257
+ const blobDir = path18.join(this.changesDir, id);
7258
+ await fs18.mkdir(blobDir, { recursive: true });
6094
7259
  const operations = await Promise.all(
6095
7260
  input.operations.map(async (operation, index) => {
6096
7261
  const beforeSnapshotPath = await this.writeSnapshot(
@@ -6130,21 +7295,21 @@ var ChangeStore = class {
6130
7295
  preview: input.preview,
6131
7296
  operations
6132
7297
  };
6133
- await fs16.mkdir(this.changesDir, { recursive: true });
6134
- await fs16.writeFile(this.getMetadataPath(id), `${JSON.stringify(record, null, 2)}
7298
+ await fs18.mkdir(this.changesDir, { recursive: true });
7299
+ await fs18.writeFile(this.getMetadataPath(id), `${JSON.stringify(record, null, 2)}
6135
7300
  `, "utf8");
6136
7301
  return record;
6137
7302
  }
6138
7303
  async list(limit = 20) {
6139
- await fs16.mkdir(this.changesDir, { recursive: true });
6140
- const entries = await fs16.readdir(this.changesDir, { withFileTypes: true });
7304
+ await fs18.mkdir(this.changesDir, { recursive: true });
7305
+ const entries = await fs18.readdir(this.changesDir, { withFileTypes: true });
6141
7306
  const changes = await Promise.all(
6142
- entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map(async (entry) => this.load(path16.basename(entry.name, ".json")))
7307
+ entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map(async (entry) => this.load(path18.basename(entry.name, ".json")))
6143
7308
  );
6144
7309
  return changes.sort((left, right) => right.createdAt.localeCompare(left.createdAt)).slice(0, limit);
6145
7310
  }
6146
7311
  async load(id) {
6147
- const raw = await fs16.readFile(this.getMetadataPath(id), "utf8");
7312
+ const raw = await fs18.readFile(this.getMetadataPath(id), "utf8");
6148
7313
  return JSON.parse(raw);
6149
7314
  }
6150
7315
  async loadLatestUndoable() {
@@ -6168,17 +7333,17 @@ var ChangeStore = class {
6168
7333
  restoredPaths.push(operation.path);
6169
7334
  if (operation.beforeSnapshotPath) {
6170
7335
  const buffer = await this.readSnapshot(operation.beforeSnapshotPath);
6171
- await fs16.mkdir(path16.dirname(operation.path), { recursive: true });
6172
- await fs16.writeFile(operation.path, buffer);
7336
+ await fs18.mkdir(path18.dirname(operation.path), { recursive: true });
7337
+ await fs18.writeFile(operation.path, buffer);
6173
7338
  continue;
6174
7339
  }
6175
- await fs16.rm(operation.path, { force: true });
7340
+ await fs18.rm(operation.path, { force: true });
6176
7341
  }
6177
7342
  const updated = {
6178
7343
  ...record,
6179
7344
  undoneAt: (/* @__PURE__ */ new Date()).toISOString()
6180
7345
  };
6181
- await fs16.writeFile(this.getMetadataPath(updated.id), `${JSON.stringify(updated, null, 2)}
7346
+ await fs18.writeFile(this.getMetadataPath(updated.id), `${JSON.stringify(updated, null, 2)}
6182
7347
  `, "utf8");
6183
7348
  return {
6184
7349
  record: updated,
@@ -6186,24 +7351,24 @@ var ChangeStore = class {
6186
7351
  };
6187
7352
  }
6188
7353
  getMetadataPath(id) {
6189
- return path16.join(this.changesDir, `${id}.json`);
7354
+ return path18.join(this.changesDir, `${id}.json`);
6190
7355
  }
6191
7356
  async writeSnapshot(blobDir, label, buffer) {
6192
7357
  if (!buffer) {
6193
7358
  return void 0;
6194
7359
  }
6195
7360
  const fileName = `${label}.bin`;
6196
- const absolutePath = path16.join(blobDir, fileName);
6197
- await fs16.writeFile(absolutePath, buffer);
6198
- return path16.relative(this.changesDir, absolutePath);
7361
+ const absolutePath = path18.join(blobDir, fileName);
7362
+ await fs18.writeFile(absolutePath, buffer);
7363
+ return path18.relative(this.changesDir, absolutePath);
6199
7364
  }
6200
7365
  async readSnapshot(relativePath) {
6201
- return fs16.readFile(path16.join(this.changesDir, relativePath));
7366
+ return fs18.readFile(path18.join(this.changesDir, relativePath));
6202
7367
  }
6203
7368
  };
6204
7369
  function createChangeId() {
6205
7370
  const date = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:.TZ]/g, "").slice(0, 14);
6206
- const random = crypto2.randomUUID().slice(0, 8);
7371
+ const random = crypto3.randomUUID().slice(0, 8);
6207
7372
  return `${date}-${random}`;
6208
7373
  }
6209
7374
 
@@ -6777,20 +7942,20 @@ function createBackgroundTools() {
6777
7942
  }
6778
7943
 
6779
7944
  // src/extensions/tools/network/tools/downloadUrl.ts
6780
- import fs18 from "fs/promises";
7945
+ import fs20 from "fs/promises";
6781
7946
 
6782
7947
  // src/extensions/shared.ts
6783
- import fs17 from "fs/promises";
6784
- import path17 from "path";
7948
+ import fs19 from "fs/promises";
7949
+ import path19 from "path";
6785
7950
  async function ensureExtensionDir(rootDir, extensionId) {
6786
7951
  const paths = await ensureProjectStateDirectories(rootDir);
6787
- const dir = path17.join(paths.extensionsDir, extensionId);
6788
- await fs17.mkdir(dir, { recursive: true });
7952
+ const dir = path19.join(paths.extensionsDir, extensionId);
7953
+ await fs19.mkdir(dir, { recursive: true });
6789
7954
  return dir;
6790
7955
  }
6791
7956
  async function readJsonFile(filePath, fallback) {
6792
7957
  try {
6793
- return JSON.parse(await fs17.readFile(filePath, "utf8"));
7958
+ return JSON.parse(await fs19.readFile(filePath, "utf8"));
6794
7959
  } catch (error) {
6795
7960
  if (error.code === "ENOENT") {
6796
7961
  return fallback;
@@ -6799,8 +7964,8 @@ async function readJsonFile(filePath, fallback) {
6799
7964
  }
6800
7965
  }
6801
7966
  async function writeJsonFile(filePath, value) {
6802
- await fs17.mkdir(path17.dirname(filePath), { recursive: true });
6803
- await fs17.writeFile(filePath, `${JSON.stringify(value, null, 2)}
7967
+ await fs19.mkdir(path19.dirname(filePath), { recursive: true });
7968
+ await fs19.writeFile(filePath, `${JSON.stringify(value, null, 2)}
6804
7969
  `, "utf8");
6805
7970
  }
6806
7971
  function jsonResult(value) {
@@ -6816,7 +7981,7 @@ function sanitizeStateSegment(value) {
6816
7981
  }
6817
7982
 
6818
7983
  // src/extensions/tools/network/session.ts
6819
- import path18 from "path";
7984
+ import path20 from "path";
6820
7985
  async function listHttpSessions(rootDir) {
6821
7986
  const state = await readJsonFile(await sessionFile(rootDir), { sessions: [] });
6822
7987
  return Array.isArray(state.sessions) ? state.sessions.map(normalizeSession) : [];
@@ -6841,7 +8006,7 @@ async function getHttpSessionStateFile(rootDir) {
6841
8006
  return sessionFile(rootDir);
6842
8007
  }
6843
8008
  async function sessionFile(rootDir) {
6844
- return path18.join(await ensureExtensionDir(rootDir, "network"), "http-sessions.json");
8009
+ return path20.join(await ensureExtensionDir(rootDir, "network"), "http-sessions.json");
6845
8010
  }
6846
8011
  function normalizeSession(value) {
6847
8012
  return {
@@ -7070,7 +8235,7 @@ var downloadUrlTool = {
7070
8235
  }
7071
8236
  const bytes = Buffer.from(await response.arrayBuffer());
7072
8237
  await ensureParentDirectory(targetPath);
7073
- await fs18.writeFile(targetPath, bytes);
8238
+ await fs20.writeFile(targetPath, bytes);
7074
8239
  return changedJsonResult({
7075
8240
  ok: response.ok,
7076
8241
  url,
@@ -7135,17 +8300,17 @@ var httpProbeTool = {
7135
8300
  };
7136
8301
 
7137
8302
  // src/extensions/tools/network/traceStore.ts
7138
- import fs19 from "fs/promises";
7139
- import path19 from "path";
8303
+ import fs21 from "fs/promises";
8304
+ import path21 from "path";
7140
8305
  async function writeNetworkTrace(rootDir, traceId, record) {
7141
8306
  const filePath = await networkTraceFilePath(rootDir, traceId);
7142
- await fs19.mkdir(path19.dirname(filePath), { recursive: true });
7143
- await fs19.writeFile(filePath, `${JSON.stringify(record, null, 2)}
8307
+ await fs21.mkdir(path21.dirname(filePath), { recursive: true });
8308
+ await fs21.writeFile(filePath, `${JSON.stringify(record, null, 2)}
7144
8309
  `, "utf8");
7145
8310
  return filePath;
7146
8311
  }
7147
8312
  async function networkTraceFilePath(rootDir, traceId) {
7148
- return path19.join(await ensureExtensionDir(rootDir, "network"), "traces", `${sanitizeStateSegment(traceId)}.json`);
8313
+ return path21.join(await ensureExtensionDir(rootDir, "network"), "traces", `${sanitizeStateSegment(traceId)}.json`);
7149
8314
  }
7150
8315
 
7151
8316
  // src/extensions/tools/network/tools/httpRequest.ts
@@ -7545,14 +8710,14 @@ function readStringMap2(value) {
7545
8710
  }
7546
8711
 
7547
8712
  // src/extensions/tools/network/openapi.ts
7548
- import fs20 from "fs/promises";
8713
+ import fs22 from "fs/promises";
7549
8714
  async function loadOpenApiDocument(source, context) {
7550
8715
  const normalizedSource = source.trim();
7551
8716
  if (!normalizedSource) {
7552
8717
  throw new ToolExecutionError("OpenAPI source is required.", { code: "OPENAPI_SOURCE_INVALID" });
7553
8718
  }
7554
8719
  const resolvedSource = /^https?:\/\//i.test(normalizedSource) ? normalizedSource : resolveUserPath(normalizedSource, context.cwd);
7555
- const raw = /^https?:\/\//i.test(normalizedSource) ? await (await fetchWithTimeout(normalizedSource, { method: "GET" }, 2e4, context.abortSignal)).text() : stripBom(await fs20.readFile(resolvedSource, "utf8"));
8720
+ const raw = /^https?:\/\//i.test(normalizedSource) ? await (await fetchWithTimeout(normalizedSource, { method: "GET" }, 2e4, context.abortSignal)).text() : stripBom(await fs22.readFile(resolvedSource, "utf8"));
7556
8721
  const parsed = parseOpenApiDocument(raw, normalizedSource);
7557
8722
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
7558
8723
  throw new ToolExecutionError("OpenAPI document root must be an object.", { code: "OPENAPI_ROOT_INVALID" });
@@ -7900,8 +9065,8 @@ async function recordSkillUse(rootDir, input) {
7900
9065
  }
7901
9066
 
7902
9067
  // src/extensions/tools/skills/tools/skillReadResource.ts
7903
- import fs21 from "fs/promises";
7904
- import path20 from "path";
9068
+ import fs23 from "fs/promises";
9069
+ import path22 from "path";
7905
9070
  var MAX_RESOURCE_CHARS = 24e3;
7906
9071
  var skillReadResourceTool = {
7907
9072
  definition: {
@@ -7938,8 +9103,8 @@ var skillReadResourceTool = {
7938
9103
  if (!resource) {
7939
9104
  throw new Error(`Skill "${name}" does not declare resource: ${requestedPath}`);
7940
9105
  }
7941
- const absolutePath = path20.resolve(context.projectContext.rootDir, resource.path);
7942
- const content = await fs21.readFile(absolutePath, "utf8");
9106
+ const absolutePath = path22.resolve(context.projectContext.rootDir, resource.path);
9107
+ const content = await fs23.readFile(absolutePath, "utf8");
7943
9108
  return jsonResult({
7944
9109
  ok: true,
7945
9110
  skill: {
@@ -7957,7 +9122,7 @@ function normalizeResourcePath(value) {
7957
9122
  }
7958
9123
 
7959
9124
  // src/extensions/tools/skills/tools/skillRunScript.ts
7960
- import path21 from "path";
9125
+ import path23 from "path";
7961
9126
  var skillRunScriptTool = {
7962
9127
  definition: {
7963
9128
  type: "function",
@@ -8001,12 +9166,12 @@ var skillRunScriptTool = {
8001
9166
  if (!resource) {
8002
9167
  throw new Error(`Skill "${name}" does not declare script resource: ${requestedPath}`);
8003
9168
  }
8004
- const skillDir = path21.dirname(skill.path);
8005
- const relativeToSkill = normalizeResourcePath2(path21.relative(skillDir, resource.path));
9169
+ const skillDir = path23.dirname(skill.path);
9170
+ const relativeToSkill = normalizeResourcePath2(path23.relative(skillDir, resource.path));
8006
9171
  if (!relativeToSkill.startsWith("scripts/")) {
8007
9172
  throw new Error(`Skill "${name}" resource is not executable because it is outside scripts/: ${requestedPath}`);
8008
9173
  }
8009
- const scriptPath = path21.resolve(context.projectContext.rootDir, resource.path);
9174
+ const scriptPath = path23.resolve(context.projectContext.rootDir, resource.path);
8010
9175
  const argumentText = typeof args.args === "string" ? args.args.trim() : "";
8011
9176
  const command = buildScriptCommand(scriptPath, argumentText);
8012
9177
  const result = await runCommandWithPolicy({
@@ -8081,7 +9246,7 @@ function quotePath(value) {
8081
9246
  return `"${value.replace(/"/g, '\\"')}"`;
8082
9247
  }
8083
9248
  function buildScriptCommand(scriptPath, argumentText) {
8084
- const extension = path21.extname(scriptPath).toLowerCase();
9249
+ const extension = path23.extname(scriptPath).toLowerCase();
8085
9250
  const quoted = quotePath(scriptPath);
8086
9251
  const suffix = argumentText ? ` ${argumentText}` : "";
8087
9252
  if (extension === ".js" || extension === ".mjs" || extension === ".cjs") {
@@ -8135,12 +9300,12 @@ var subagentCheckTool = {
8135
9300
 
8136
9301
  // src/execution/launch.ts
8137
9302
  import { spawn } from "child_process";
8138
- import path22 from "path";
9303
+ import path24 from "path";
8139
9304
  function spawnExecutionWorker(input) {
8140
9305
  if (process.env.KITTY_TEST_WORKER_MODE === "stub") {
8141
9306
  return process.pid;
8142
9307
  }
8143
- const cliEntry = path22.resolve(process.argv[1] ?? "");
9308
+ const cliEntry = path24.resolve(process.argv[1] ?? "");
8144
9309
  if (!cliEntry) {
8145
9310
  throw new Error("Unable to locate Kitty CLI entrypoint for execution worker.");
8146
9311
  }
@@ -8346,7 +9511,7 @@ function parseWorktreeBlock(block) {
8346
9511
  }
8347
9512
 
8348
9513
  // src/extensions/tools/worktree/state.ts
8349
- import path23 from "path";
9514
+ import path25 from "path";
8350
9515
  async function readWorktreeState(rootDir) {
8351
9516
  return normalizeWorktreeState(await readJsonFile(await stateFile(rootDir), {
8352
9517
  schemaVersion: 1,
@@ -8369,7 +9534,7 @@ async function recordWorktreeEvent(rootDir, event) {
8369
9534
  return writeWorktreeState(rootDir, state);
8370
9535
  }
8371
9536
  async function stateFile(rootDir) {
8372
- return path23.join(await ensureExtensionDir(rootDir, "worktree"), "state.json");
9537
+ return path25.join(await ensureExtensionDir(rootDir, "worktree"), "state.json");
8373
9538
  }
8374
9539
  function normalizeWorktreeState(value) {
8375
9540
  return {
@@ -8992,8 +10157,8 @@ function looksLikeToolProtocolText(content) {
8992
10157
  }
8993
10158
 
8994
10159
  // src/observability/crashRecorder.ts
8995
- import fs22 from "fs";
8996
- import path24 from "path";
10160
+ import fs24 from "fs";
10161
+ import path26 from "path";
8997
10162
  var activeCrashContexts = /* @__PURE__ */ new Map();
8998
10163
  var nextCrashContextId = 0;
8999
10164
  function enterCrashContext(context) {
@@ -9005,7 +10170,7 @@ function enterCrashContext(context) {
9005
10170
  }
9006
10171
 
9007
10172
  // src/observability/hostEvents.ts
9008
- import path25 from "path";
10173
+ import path27 from "path";
9009
10174
  async function recordHostTurnStarted(rootDir, input) {
9010
10175
  await recordObservabilityEvent(rootDir, {
9011
10176
  event: "host.turn",
@@ -9356,7 +10521,7 @@ function tryParseJson(input) {
9356
10521
  }
9357
10522
 
9358
10523
  // src/runtime-ui/pathDisplay.ts
9359
- import path26 from "path";
10524
+ import path28 from "path";
9360
10525
  function normalizeDisplayPath(value, cwd) {
9361
10526
  if (!value) {
9362
10527
  return value;
@@ -9364,10 +10529,10 @@ function normalizeDisplayPath(value, cwd) {
9364
10529
  if (!cwd) {
9365
10530
  return value;
9366
10531
  }
9367
- const normalizedCwd = path26.resolve(cwd);
9368
- const normalizedValue = path26.resolve(value);
9369
- if (normalizedValue === normalizedCwd || normalizedValue.startsWith(`${normalizedCwd}${path26.sep}`)) {
9370
- return path26.relative(normalizedCwd, normalizedValue) || ".";
10532
+ const normalizedCwd = path28.resolve(cwd);
10533
+ const normalizedValue = path28.resolve(value);
10534
+ if (normalizedValue === normalizedCwd || normalizedValue.startsWith(`${normalizedCwd}${path28.sep}`)) {
10535
+ return path28.relative(normalizedCwd, normalizedValue) || ".";
9371
10536
  }
9372
10537
  return value;
9373
10538
  }
@@ -9375,7 +10540,7 @@ function rewriteAbsolutePaths(value, cwd) {
9375
10540
  if (!cwd) {
9376
10541
  return value;
9377
10542
  }
9378
- const normalizedCwd = path26.resolve(cwd).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
10543
+ const normalizedCwd = path28.resolve(cwd).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
9379
10544
  const pattern = new RegExp(`${normalizedCwd}(?:\\\\[^\\s"']*|/[^\\s"']*)*`, "g");
9380
10545
  return value.replace(pattern, (match) => normalizeDisplayPath(match, cwd) ?? match);
9381
10546
  }
@@ -9435,24 +10600,24 @@ function buildToolCallDisplay(name, rawArgs, maxChars, cwd) {
9435
10600
  };
9436
10601
  }
9437
10602
  const args = parsed;
9438
- const path27 = normalizeDisplayPath(readStringField(args, "path"), cwd);
10603
+ const path29 = normalizeDisplayPath(readStringField(args, "path"), cwd);
9439
10604
  switch (name) {
9440
10605
  case "read": {
9441
10606
  const offset = typeof args.offset === "number" ? Math.trunc(args.offset) : void 0;
9442
10607
  const limit = typeof args.limit === "number" ? Math.trunc(args.limit) : void 0;
9443
10608
  const range = offset === void 0 ? "" : limit === void 0 ? `:${offset}` : `:${offset}-${Math.max(offset, offset + limit - 1)}`;
9444
10609
  return {
9445
- summary: `${name} ${path27 ?? "(missing path)"}${range}`
10610
+ summary: `${name} ${path29 ?? "(missing path)"}${range}`
9446
10611
  };
9447
10612
  }
9448
10613
  case "write":
9449
10614
  return {
9450
- summary: `${name} ${path27 ?? "(missing path)"}`
10615
+ summary: `${name} ${path29 ?? "(missing path)"}`
9451
10616
  };
9452
10617
  case "edit": {
9453
10618
  const edits = Array.isArray(args.edits) ? args.edits : [];
9454
10619
  return {
9455
- summary: `${name} ${path27 ?? "(missing path)"}` + (edits.length > 0 ? ` edits=${edits.length}` : "")
10620
+ summary: `${name} ${path29 ?? "(missing path)"}` + (edits.length > 0 ? ` edits=${edits.length}` : "")
9456
10621
  };
9457
10622
  }
9458
10623
  case "bash": {
@@ -9464,7 +10629,7 @@ function buildToolCallDisplay(name, rawArgs, maxChars, cwd) {
9464
10629
  }
9465
10630
  case "download_url":
9466
10631
  return {
9467
- summary: `${name} ${readStringField(args, "url") ?? "(missing url)"} -> ${path27 ?? "(missing path)"}`
10632
+ summary: `${name} ${readStringField(args, "url") ?? "(missing url)"} -> ${path29 ?? "(missing path)"}`
9468
10633
  };
9469
10634
  case "http_probe": {
9470
10635
  const method = readStringField(args, "method") ?? "HEAD";
@@ -9505,14 +10670,14 @@ function buildToolCallDisplay(name, rawArgs, maxChars, cwd) {
9505
10670
  case "worktree_create": {
9506
10671
  const branch = readStringField(args, "branch");
9507
10672
  return {
9508
- summary: `${name} ${path27 ?? "(missing path)"}${branch ? ` branch=${branch}` : ""}`
10673
+ summary: `${name} ${path29 ?? "(missing path)"}${branch ? ` branch=${branch}` : ""}`
9509
10674
  };
9510
10675
  }
9511
10676
  case "worktree_get":
9512
10677
  case "worktree_keep":
9513
10678
  case "worktree_remove":
9514
10679
  return {
9515
- summary: `${name} ${path27 ?? "(missing path)"}`
10680
+ summary: `${name} ${path29 ?? "(missing path)"}`
9516
10681
  };
9517
10682
  case "worktree_events": {
9518
10683
  const limit = typeof args.limit === "number" ? Math.trunc(args.limit) : void 0;
@@ -9651,7 +10816,7 @@ function colorizeMarker(marker) {
9651
10816
  }
9652
10817
 
9653
10818
  // src/utils/stdio.ts
9654
- import fs23 from "fs";
10819
+ import fs25 from "fs";
9655
10820
  var stdoutBroken = false;
9656
10821
  var stderrBroken = false;
9657
10822
  function writeStdout(text) {
@@ -9677,7 +10842,7 @@ function writeToFd(fd, text, stream) {
9677
10842
  if (target.isTTY) {
9678
10843
  return target.write(text);
9679
10844
  }
9680
- fs23.writeSync(fd, text, void 0, "utf8");
10845
+ fs25.writeSync(fd, text, void 0, "utf8");
9681
10846
  return true;
9682
10847
  } catch (error) {
9683
10848
  if (isIgnorableStreamError(error)) {
@@ -9960,6 +11125,12 @@ function formatRuntimeUiMessage(prefix, summary, detail) {
9960
11125
  export {
9961
11126
  resolveProjectRoots,
9962
11127
  buildProjectMap,
11128
+ PROJECT_STATE_DIR_NAME,
11129
+ PROJECT_STATE_ENV_FILE_NAME,
11130
+ PROJECT_STATE_ENV_EXAMPLE_FILE_NAME,
11131
+ PROJECT_STATE_IGNORE_FILE_NAME,
11132
+ PRESERVED_PROJECT_STATE_ENTRY_NAMES,
11133
+ getProjectStatePaths,
9963
11134
  loadProjectContext,
9964
11135
  getErrorMessage,
9965
11136
  ControlPlaneLedger,