@swifty.js/swifty 0.0.22 → 0.0.23

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.
Files changed (35) hide show
  1. package/dist/{agent-5T7KNC7V.js → agent-RABW3Z3R.js} +1 -1
  2. package/dist/anthropic-V22T6E6E.js +4 -0
  3. package/dist/{checker-OJFS2MZY.js → checker-3RWAYF2U.js} +1 -1
  4. package/dist/{chunk-HJIGA37J.js → chunk-5KXBVL2A.js} +1 -1
  5. package/dist/{chunk-NLNH3IRT.js → chunk-CV7OKXYC.js} +1 -1
  6. package/dist/chunk-MJR2C7S7.js +130 -0
  7. package/dist/{chunk-GUXBLUNR.js → chunk-NR62AA5K.js} +1 -1
  8. package/dist/{chunk-NEAR6YPZ.js → chunk-OCQ6TYLT.js} +21 -20
  9. package/dist/chunk-QN27QEFS.js +4 -0
  10. package/dist/{chunk-LX2LK3TF.js → chunk-SIWLMWHH.js} +12 -11
  11. package/dist/chunk-Y43POSIW.js +389 -0
  12. package/dist/lib/agent-GHXYOARN.js +9 -0
  13. package/dist/lib/{anthropic-GFWP3ORB.js → anthropic-7YEN2QTU.js} +6 -6
  14. package/dist/lib/{checker-IIXJXQCB.js → checker-6BW4222R.js} +3 -3
  15. package/dist/lib/{chunk-LUEP4JMF.js → chunk-7IZEK7X5.js} +8 -12
  16. package/dist/lib/{chunk-C7IHCJZ3.js → chunk-BN4Q54G2.js} +259 -12
  17. package/dist/lib/{chunk-RR2CZ6CY.js → chunk-BO76JDFZ.js} +94 -75
  18. package/dist/lib/{chunk-6GOWRPYS.js → chunk-CYDNMEBC.js} +2 -2
  19. package/dist/lib/{chunk-EJLGB2EJ.js → chunk-EY7HE52Q.js} +14 -7
  20. package/dist/lib/{chunk-7URDLWQN.js → chunk-GNI7YX6F.js} +2 -2
  21. package/dist/lib/{chunk-UHVO63Y7.js → chunk-MF3YLQDS.js} +69 -38
  22. package/dist/lib/{chunk-UMFNTXKA.js → chunk-OO2CLOEE.js} +38 -38
  23. package/dist/lib/{chunk-GNBXECZN.js → chunk-PZ42NAFA.js} +2 -3
  24. package/dist/lib/index.d.ts +234 -237
  25. package/dist/lib/index.js +212 -224
  26. package/dist/lib/{openai-HXRMPNB7.js → openai-RDHZFJUT.js} +4 -4
  27. package/dist/main.js +203 -465
  28. package/dist/{openai-TVUUHRG7.js → openai-6NWVJ5LI.js} +15 -15
  29. package/dist/{server-ZTLHJWEQ.js → server-KQTLAXC6.js} +16 -16
  30. package/package.json +5 -5
  31. package/dist/anthropic-P2R4GW6F.js +0 -4
  32. package/dist/chunk-L73IHJF4.js +0 -386
  33. package/dist/chunk-YQQVB6VB.js +0 -127
  34. package/dist/chunk-ZZQE743W.js +0 -4
  35. package/dist/lib/agent-2AGRYN3R.js +0 -9
package/dist/lib/index.js CHANGED
@@ -2,6 +2,7 @@ import {
2
2
  Agent,
3
3
  RecoveryState,
4
4
  StreamingExecutor,
5
+ TOOL_RESULT_PREVIEW_CHARS,
5
6
  applyBudget,
6
7
  buildPlanModeExitReminder,
7
8
  buildPlanModeReentryReminder,
@@ -13,9 +14,11 @@ import {
13
14
  loadPlan,
14
15
  persistLargeResult,
15
16
  planExists,
17
+ replaceToolResultContent,
16
18
  resetPlanPath,
17
- savePlan
18
- } from "./chunk-UHVO63Y7.js";
19
+ savePlan,
20
+ toDisplayPreview
21
+ } from "./chunk-MF3YLQDS.js";
19
22
  import {
20
23
  AnthropicClient,
21
24
  CHARS_PER_TOKEN,
@@ -32,11 +35,12 @@ import {
32
35
  markToolsForCache,
33
36
  measureSchemaChars,
34
37
  needsToolSearchBeta
35
- } from "./chunk-LUEP4JMF.js";
38
+ } from "./chunk-7IZEK7X5.js";
36
39
  import {
37
40
  AutoCompactTrackingState,
38
41
  COMPACT_BOUNDARY,
39
42
  ConversationManager,
43
+ SKIP_DIRS,
40
44
  cleanExpiredSessions,
41
45
  computeCompactThreshold,
42
46
  computeKeepStartIndex,
@@ -45,22 +49,24 @@ import {
45
49
  estimateTokens,
46
50
  forceCompact,
47
51
  getSessionFilePath,
52
+ isToolResultContentBlock,
48
53
  listSessions,
49
54
  loadSession,
50
55
  manageContext,
51
56
  newSessionId,
57
+ normalizeToolResultContentBlock,
52
58
  rebuildFromSession,
53
59
  saveCompactBoundary,
54
60
  saveMessage,
55
61
  toolResultsToRecords,
56
62
  toolUsesToRecords
57
- } from "./chunk-C7IHCJZ3.js";
63
+ } from "./chunk-BN4Q54G2.js";
58
64
  import {
59
65
  OpenAIClient,
60
66
  OpenAICompatClient,
61
67
  buildChatCompletionMessages,
62
68
  buildOpenAIInput
63
- } from "./chunk-RR2CZ6CY.js";
69
+ } from "./chunk-BO76JDFZ.js";
64
70
  import {
65
71
  ConfigError,
66
72
  HookConfigSchema,
@@ -74,7 +80,7 @@ import {
74
80
  lookupModelContextWindow,
75
81
  mergeConfig,
76
82
  resolveAPIKey
77
- } from "./chunk-6GOWRPYS.js";
83
+ } from "./chunk-CYDNMEBC.js";
78
84
  import {
79
85
  AuthenticationError,
80
86
  ContextTooLongError,
@@ -84,7 +90,7 @@ import {
84
90
  REJECTED_TOOL_RESULT,
85
91
  RateLimitError,
86
92
  ensureToolPairing
87
- } from "./chunk-UMFNTXKA.js";
93
+ } from "./chunk-OO2CLOEE.js";
88
94
  import {
89
95
  PathSandbox,
90
96
  PermissionChecker,
@@ -92,7 +98,7 @@ import {
92
98
  evaluateRules,
93
99
  extractContent,
94
100
  isSafeCommand
95
- } from "./chunk-7URDLWQN.js";
101
+ } from "./chunk-GNI7YX6F.js";
96
102
  import {
97
103
  MCPToolWrapper,
98
104
  MCP_NAME_SEP,
@@ -104,9 +110,8 @@ import {
104
110
  mcpCallPermissionContent,
105
111
  mcpToolNamePrefix,
106
112
  sanitizeSegment
107
- } from "./chunk-GNBXECZN.js";
113
+ } from "./chunk-PZ42NAFA.js";
108
114
  import {
109
- DANGEROUSLY_JSON,
110
115
  asError,
111
116
  asErrorString,
112
117
  asRecord,
@@ -126,7 +131,7 @@ import {
126
131
  strArg,
127
132
  strList,
128
133
  toTry
129
- } from "./chunk-EJLGB2EJ.js";
134
+ } from "./chunk-EY7HE52Q.js";
130
135
  import {
131
136
  ASYNC_AGENT_ALLOWED_TOOLS,
132
137
  CUSTOM_AGENT_DISALLOWED_TOOLS,
@@ -1937,6 +1942,17 @@ var FileHistory = class {
1937
1942
  }
1938
1943
  }
1939
1944
  }
1945
+ const createdAfterTarget = [...this.trackedFiles.keys()].filter((p) => !(p in target.backups));
1946
+ for (const filePath of createdAfterTarget) {
1947
+ if (existsSync4(filePath)) {
1948
+ try {
1949
+ unlinkSync(filePath);
1950
+ changed.push(filePath);
1951
+ } catch {
1952
+ }
1953
+ }
1954
+ this.trackedFiles.delete(filePath);
1955
+ }
1940
1956
  this.snapshots = this.snapshots.slice(0, snapshotIndex + 1);
1941
1957
  for (const [filePath, backup] of Object.entries(target.backups)) {
1942
1958
  this.trackedFiles.set(filePath, backup.version);
@@ -1960,7 +1976,7 @@ import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, mkdirSy
1960
1976
  import { join as join6 } from "path";
1961
1977
  import { parse as parse3, z as z4 } from "zod";
1962
1978
  var log9 = createChildLogger({ module: "history" });
1963
- var MAX_ENTRIES = 200;
1979
+ var MAX_HISTORY_ENTRIES = 200;
1964
1980
  var FILENAME = "prompt_history.jsonl";
1965
1981
  var JSONLSchema = z4.looseObject({ text: z4.string() });
1966
1982
  function load(dir) {
@@ -1979,7 +1995,7 @@ function load(dir) {
1979
1995
  log9.error({ err }, "parse history line failed");
1980
1996
  return "";
1981
1997
  }
1982
- });
1998
+ }).filter(Boolean).slice(-MAX_HISTORY_ENTRIES);
1983
1999
  } catch (err2) {
1984
2000
  log9.error({ err: err2 }, "load history failed");
1985
2001
  return [];
@@ -1989,15 +2005,13 @@ function append(dir, text) {
1989
2005
  const filePath = join6(dir, FILENAME);
1990
2006
  mkdirSync4(dir, { recursive: true });
1991
2007
  const entries = load(dir);
1992
- if (entries.length > 0 && entries[entries.length - 1] === text) {
1993
- return;
1994
- }
1995
- entries.push(text);
1996
- while (entries.length > MAX_ENTRIES) {
1997
- entries.shift();
2008
+ if (entries.length === 0 || entries[entries.length - 1] !== text) {
2009
+ entries.push(text);
1998
2010
  }
1999
- const lines = entries.map((t) => JSON.stringify({ text: t })).join("\n") + "\n";
2011
+ const retained = entries.slice(-MAX_HISTORY_ENTRIES);
2012
+ const lines = retained.map((entry) => JSON.stringify({ text: entry })).join("\n") + "\n";
2000
2013
  writeFileSync4(filePath, lines, "utf-8");
2014
+ return retained;
2001
2015
  }
2002
2016
 
2003
2017
  // src/hooks/hooks.ts
@@ -2538,15 +2552,15 @@ async function saveClipboardImage(workDir, sessionId) {
2538
2552
  async function createClient(config, systemPrompt) {
2539
2553
  switch (config.protocol) {
2540
2554
  case "anthropic": {
2541
- const { AnthropicClient: AnthropicClient2 } = await import("./anthropic-GFWP3ORB.js");
2555
+ const { AnthropicClient: AnthropicClient2 } = await import("./anthropic-7YEN2QTU.js");
2542
2556
  return new AnthropicClient2(config, systemPrompt);
2543
2557
  }
2544
2558
  case "openai": {
2545
- const { OpenAIClient: OpenAIClient2 } = await import("./openai-HXRMPNB7.js");
2559
+ const { OpenAIClient: OpenAIClient2 } = await import("./openai-RDHZFJUT.js");
2546
2560
  return new OpenAIClient2(config, systemPrompt);
2547
2561
  }
2548
2562
  case "openai-compat": {
2549
- const { OpenAICompatClient: OpenAICompatClient2 } = await import("./openai-HXRMPNB7.js");
2563
+ const { OpenAICompatClient: OpenAICompatClient2 } = await import("./openai-RDHZFJUT.js");
2550
2564
  return new OpenAICompatClient2(config, systemPrompt);
2551
2565
  }
2552
2566
  default:
@@ -2595,7 +2609,7 @@ var PackageJsonSchema = z5.object({
2595
2609
  });
2596
2610
  function resolveVersion() {
2597
2611
  if (true) {
2598
- return "0.0.22";
2612
+ return "0.0.23";
2599
2613
  }
2600
2614
  const here = path.dirname(fileURLToPath(import.meta.url));
2601
2615
  for (const levels of ["..", "../.."]) {
@@ -2631,7 +2645,8 @@ function asDict(obj) {
2631
2645
  var MCP_IMAGE_MEDIA_TYPES = /* @__PURE__ */ new Set(["image/png", "image/jpeg", "image/gif", "image/webp"]);
2632
2646
  async function mcpContentToToolOutput(content) {
2633
2647
  const textParts = [];
2634
- const imageBlocks = [];
2648
+ const contentBlocks = [];
2649
+ let hasImage = false;
2635
2650
  for (const raw of content) {
2636
2651
  const c = isRecord(raw) ? raw : {};
2637
2652
  if (c.type === "image" && typeof c.data === "string" && typeof c.mimeType === "string" && MCP_IMAGE_MEDIA_TYPES.has(c.mimeType)) {
@@ -2640,7 +2655,7 @@ async function mcpContentToToolOutput(content) {
2640
2655
  Buffer.from(c.data, "base64"),
2641
2656
  asImageMediaType(c.mimeType)
2642
2657
  );
2643
- imageBlocks.push({
2658
+ contentBlocks.push({
2644
2659
  type: "image",
2645
2660
  source: {
2646
2661
  type: "base64",
@@ -2648,20 +2663,31 @@ async function mcpContentToToolOutput(content) {
2648
2663
  data: resized.data
2649
2664
  }
2650
2665
  });
2666
+ textParts.push(`[Image: ${resized.mediaType}]`);
2667
+ hasImage = true;
2651
2668
  continue;
2652
2669
  } catch (err) {
2653
2670
  log11.warn({ err }, "mcp image dropped (too large to fit the API limit)");
2654
- textParts.push("[note: an image returned by the tool was too large and was dropped]");
2671
+ const note = "[note: an image returned by the tool was too large and was dropped]";
2672
+ textParts.push(note);
2673
+ contentBlocks.push({ type: "text", text: note });
2655
2674
  continue;
2656
2675
  }
2657
2676
  }
2658
- textParts.push(c.type === "text" && typeof c.text === "string" ? c.text : JSON.stringify(raw));
2659
- }
2660
- const text = textParts.join("\n");
2661
- if (imageBlocks.length === 0) {
2662
- return text;
2677
+ if (c.type === "image") {
2678
+ const mimeType = typeof c.mimeType === "string" ? c.mimeType : "unknown";
2679
+ const note = `[Unsupported image: ${mimeType}]`;
2680
+ textParts.push(note);
2681
+ contentBlocks.push({ type: "text", text: note });
2682
+ continue;
2683
+ }
2684
+ const serialized = JSON.stringify(raw);
2685
+ const text = c.type === "text" && typeof c.text === "string" ? c.text : typeof serialized === "string" ? serialized : String(raw);
2686
+ textParts.push(text);
2687
+ contentBlocks.push({ type: "text", text });
2663
2688
  }
2664
- return [...text ? [{ type: "text", text }] : [], ...imageBlocks];
2689
+ const output = textParts.join("\n");
2690
+ return hasImage ? { output, contentBlocks } : { output };
2665
2691
  }
2666
2692
  var MCPClient = class {
2667
2693
  name;
@@ -2726,22 +2752,14 @@ var MCPClient = class {
2726
2752
  })
2727
2753
  );
2728
2754
  }
2729
- /** Calls a tool and returns { output, isError }. isError mirrors the MCP
2730
- * protocol's isError flag so the model knows when a tool failed.
2731
- * Image content blocks pass through as provider-style blocks instead of
2732
- * being flattened to JSON text. */
2755
+ /** Calls a tool and preserves both its text fallback and provider-native rich content. */
2733
2756
  async callTool(name, args) {
2734
2757
  if (!this.client) {
2735
2758
  throw new Error("Not connected");
2736
2759
  }
2737
2760
  const result = await this.client.callTool({ name, arguments: args });
2738
- let output;
2739
- if (result.content && Array.isArray(result.content)) {
2740
- output = await mcpContentToToolOutput(result.content);
2741
- } else {
2742
- output = JSON.stringify(result);
2743
- }
2744
- return { output, isError: result.isError === true };
2761
+ const converted = result.content && Array.isArray(result.content) ? await mcpContentToToolOutput(result.content) : { output: JSON.stringify(result) };
2762
+ return { ...converted, isError: result.isError === true };
2745
2763
  }
2746
2764
  async disconnect() {
2747
2765
  try {
@@ -2949,36 +2967,6 @@ Usage Notes
2949
2967
  - Use this instead of grep or rg commands via Bash.
2950
2968
  `;
2951
2969
 
2952
- // src/tools/types.ts
2953
- var SKIP_DIRS = /* @__PURE__ */ new Set([
2954
- ".claude",
2955
- // Claude Code
2956
- ".git",
2957
- // Git
2958
- ".swifty",
2959
- // Swifty
2960
- ".next",
2961
- // Next.js
2962
- ".venv",
2963
- // Python venv
2964
- ".mypy_cache",
2965
- // Python mypy
2966
- ".tox",
2967
- // Python tox
2968
- "__pycache__",
2969
- // Python
2970
- "build",
2971
- // C++
2972
- "dist",
2973
- // Webpack, Vite
2974
- "node_modules",
2975
- // Node.js
2976
- "vendor",
2977
- // Go
2978
- "venv"
2979
- // Python venv
2980
- ]);
2981
-
2982
2970
  // src/tools/bash.ts
2983
2971
  var MAX_TIMEOUT = 600;
2984
2972
  var KILL_GRACE_MS = 3e3;
@@ -3691,7 +3679,11 @@ var ReadFileTool = class {
3691
3679
  data: attachment.data
3692
3680
  }
3693
3681
  };
3694
- return { output: [imageBlock], isError: false };
3682
+ return {
3683
+ output: `[Image: ${attachment.mediaType}]`,
3684
+ contentBlocks: [imageBlock],
3685
+ isError: false
3686
+ };
3695
3687
  } catch (err) {
3696
3688
  log14.error({ err }, "image read failed");
3697
3689
  return {
@@ -4494,6 +4486,7 @@ function extractWrittenPaths(messages) {
4494
4486
  import { readdirSync as readdirSync4, readFileSync as readFileSync13, existsSync as existsSync11, mkdirSync as mkdirSync8, writeFileSync as writeFileSync8 } from "fs";
4495
4487
  import { homedir as homedir4 } from "os";
4496
4488
  import { join as join12, basename as basename4 } from "path";
4489
+ import yaml3 from "js-yaml";
4497
4490
 
4498
4491
  // src/memory/manager.ts
4499
4492
  import {
@@ -4575,38 +4568,63 @@ Respond with valid JSON only, no markdown, in this exact shape: {"selected_memor
4575
4568
  var MemoryManager = class {
4576
4569
  userDir;
4577
4570
  projectDir;
4571
+ malformedFingerprints = /* @__PURE__ */ new Map();
4578
4572
  constructor(workDir) {
4579
4573
  this.userDir = join11(homedir3(), ".swifty", "memory");
4580
4574
  this.projectDir = join11(workDir, ".swifty", "memory");
4581
4575
  }
4582
- loadAll() {
4576
+ readMemory(fullPath) {
4577
+ let fingerprint = "unknown";
4578
+ try {
4579
+ const stat3 = statSync8(fullPath);
4580
+ fingerprint = `${String(stat3.mtimeMs)}:${String(stat3.size)}`;
4581
+ const parsed = parseFrontmatter(readFileSync12(fullPath, "utf-8"));
4582
+ this.malformedFingerprints.delete(fullPath);
4583
+ return {
4584
+ memory: {
4585
+ path: fullPath,
4586
+ name: parsed.name ?? basename3(fullPath, ".md"),
4587
+ description: parsed.description ?? "",
4588
+ type: parsed.type ?? "reference",
4589
+ content: parsed.body
4590
+ },
4591
+ mtimeMs: stat3.mtimeMs
4592
+ };
4593
+ } catch (err) {
4594
+ if (this.malformedFingerprints.get(fullPath) !== fingerprint) {
4595
+ this.malformedFingerprints.set(fullPath, fingerprint);
4596
+ log19.error({ err, path: fullPath }, "memory operation failed");
4597
+ }
4598
+ return null;
4599
+ }
4600
+ }
4601
+ scanAllMemories() {
4583
4602
  const memories = [];
4584
4603
  for (const dir of [this.userDir, this.projectDir]) {
4585
4604
  if (!existsSync10(dir)) {
4586
4605
  continue;
4587
4606
  }
4588
- const files = readdirSync3(dir).filter((f) => f.endsWith(".md") && f !== MEMORY_INDEX_NAME);
4607
+ let files;
4608
+ try {
4609
+ files = readdirSync3(dir).filter(
4610
+ (file) => file.endsWith(".md") && file !== MEMORY_INDEX_NAME
4611
+ );
4612
+ } catch (err) {
4613
+ log19.error({ err, path: dir }, "memory operation failed");
4614
+ continue;
4615
+ }
4589
4616
  for (const file of files) {
4590
- const fullPath = join11(dir, file);
4591
- try {
4592
- const raw = readFileSync12(fullPath, "utf-8");
4593
- const parsed = parseFrontmatter(raw);
4594
- if (parsed) {
4595
- memories.push({
4596
- path: fullPath,
4597
- name: parsed.name ?? file.replace(".md", ""),
4598
- description: parsed.description ?? "",
4599
- type: parsed.type ?? "reference",
4600
- content: parsed.body
4601
- });
4602
- }
4603
- } catch (err) {
4604
- log19.error({ err }, "memory operation failed");
4605
- continue;
4617
+ const loaded = this.readMemory(join11(dir, file));
4618
+ if (loaded) {
4619
+ memories.push(loaded.memory);
4606
4620
  }
4607
4621
  }
4608
4622
  }
4609
- this.rebuildIndex();
4623
+ return memories;
4624
+ }
4625
+ loadAll() {
4626
+ const memories = this.scanAllMemories();
4627
+ this.writeIndex(memories);
4610
4628
  return memories;
4611
4629
  }
4612
4630
  getMemories() {
@@ -4676,47 +4694,29 @@ ${body}
4676
4694
  * alphabetically by name, truncated at MAX_ENTRYPOINT_LINES / MAX_ENTRYPOINT_BYTES.
4677
4695
  */
4678
4696
  rebuildIndex() {
4679
- const entries = [];
4680
- for (const dir of [this.userDir, this.projectDir]) {
4681
- if (!existsSync10(dir)) {
4682
- continue;
4683
- }
4684
- const files = readdirSync3(dir).filter((f) => f.endsWith(".md") && f !== MEMORY_INDEX_NAME);
4697
+ this.writeIndex(this.scanAllMemories());
4698
+ }
4699
+ writeIndex(memories) {
4700
+ const entries = memories.map((memory) => ({
4701
+ name: memory.name,
4702
+ relPath: relative2(this.projectDir, memory.path) || basename3(memory.path),
4703
+ description: memory.description
4704
+ })).toSorted((a, b) => a.name.localeCompare(b.name, void 0, { sensitivity: "base" }));
4705
+ const lines = entries.map(
4706
+ (entry) => entry.description ? `- [${entry.name}](${entry.relPath}) \u2014 ${entry.description}` : `- [${entry.name}](${entry.relPath})`
4707
+ );
4708
+ const content = capEntrypoint(lines.slice(0, MAX_ENTRYPOINT_LINES2).join("\n")) + "\n";
4709
+ const indexPath = join11(this.projectDir, MEMORY_INDEX_NAME);
4710
+ mkdirSync7(this.projectDir, { recursive: true });
4711
+ if (existsSync10(indexPath)) {
4685
4712
  try {
4686
- for (const file of files) {
4687
- const fullPath = join11(dir, file);
4688
- try {
4689
- const raw = readFileSync12(fullPath, "utf-8");
4690
- const parsed = parseFrontmatter(raw);
4691
- if (!parsed) {
4692
- continue;
4693
- }
4694
- const name = parsed.name ?? file.replace(".md", "");
4695
- const description = parsed.description ?? "";
4696
- const relativePath = relative2(this.projectDir, fullPath) || file;
4697
- entries.push({ name, relPath: relativePath, description });
4698
- } catch (err) {
4699
- log19.error({ err }, "memory operation failed");
4700
- continue;
4701
- }
4713
+ if (readFileSync12(indexPath, "utf-8") === content) {
4714
+ return;
4702
4715
  }
4703
- } catch (err2) {
4704
- log19.error({ err: err2 }, "memory operation failed");
4705
- continue;
4706
- }
4707
- }
4708
- entries.sort((a, b) => a.name.localeCompare(b.name, void 0, { sensitivity: "base" }));
4709
- const lines = [];
4710
- for (const e of entries) {
4711
- if (e.description) {
4712
- lines.push(`- [${e.name}](${e.relPath}) \u2014 ${e.description}`);
4713
- } else {
4714
- lines.push(`- [${e.name}](${e.relPath})`);
4716
+ } catch {
4715
4717
  }
4716
4718
  }
4717
- const content = capEntrypoint(lines.slice(0, MAX_ENTRYPOINT_LINES2).join("\n"));
4718
- mkdirSync7(this.projectDir, { recursive: true });
4719
- writeFileSync7(join11(this.projectDir, MEMORY_INDEX_NAME), content + "\n", "utf-8");
4719
+ writeFileSync7(indexPath, content, "utf-8");
4720
4720
  }
4721
4721
  // ── Feature 2: findRelevantMemories ────────────────────────────────
4722
4722
  /**
@@ -4730,7 +4730,7 @@ ${body}
4730
4730
  [this.userDir, "user"],
4731
4731
  [this.projectDir, "project"]
4732
4732
  ]) {
4733
- const headers = scanMemoryHeaders(dir, scope);
4733
+ const headers = this.scanMemoryHeaders(dir, scope);
4734
4734
  allHeaders.push(...headers);
4735
4735
  }
4736
4736
  const candidates = allHeaders.filter((h) => !alreadySurfaced.has(h.filePath));
@@ -4789,6 +4789,35 @@ ${manifest}${toolsSection}`;
4789
4789
  }
4790
4790
  return selected;
4791
4791
  }
4792
+ scanMemoryHeaders(dir, scope) {
4793
+ if (!existsSync10(dir)) {
4794
+ return [];
4795
+ }
4796
+ let files;
4797
+ try {
4798
+ files = readdirSync3(dir).filter((file) => file.endsWith(".md") && file !== MEMORY_INDEX_NAME);
4799
+ } catch (err) {
4800
+ log19.error({ err, path: dir }, "memory operation failed");
4801
+ return [];
4802
+ }
4803
+ const headers = [];
4804
+ for (const file of files) {
4805
+ const loaded = this.readMemory(join11(dir, file));
4806
+ if (!loaded) {
4807
+ continue;
4808
+ }
4809
+ headers.push({
4810
+ filename: file,
4811
+ filePath: loaded.memory.path,
4812
+ scope,
4813
+ mtimeMs: loaded.mtimeMs,
4814
+ description: loaded.memory.description,
4815
+ type: loaded.memory.type
4816
+ });
4817
+ }
4818
+ headers.sort((a, b) => b.mtimeMs - a.mtimeMs);
4819
+ return headers.slice(0, MAX_ENTRYPOINT_LINES2);
4820
+ }
4792
4821
  renderReminder(memories) {
4793
4822
  if (memories.length === 0) {
4794
4823
  return "";
@@ -4815,49 +4844,6 @@ ${manifest}${toolsSection}`;
4815
4844
  return parts.join("\n");
4816
4845
  }
4817
4846
  };
4818
- function scanMemoryHeaders(dir, scope) {
4819
- if (!existsSync10(dir)) {
4820
- return [];
4821
- }
4822
- let files;
4823
- try {
4824
- files = readdirSync3(dir).filter((f) => f.endsWith(".md") && f !== MEMORY_INDEX_NAME);
4825
- } catch (err) {
4826
- log19.error({ err }, "memory operation failed");
4827
- return [];
4828
- }
4829
- const headers = [];
4830
- for (const file of files) {
4831
- const fullPath = join11(dir, file);
4832
- try {
4833
- const stat3 = statSync8(fullPath);
4834
- if (!stat3.isFile()) {
4835
- continue;
4836
- }
4837
- const raw = readFileSync12(fullPath, "utf-8");
4838
- const parsed = parseFrontmatter(raw);
4839
- if (!parsed) {
4840
- continue;
4841
- }
4842
- headers.push({
4843
- filename: file,
4844
- filePath: fullPath,
4845
- scope,
4846
- mtimeMs: stat3.mtimeMs,
4847
- description: parsed.description ?? "",
4848
- type: parsed.type ?? ""
4849
- });
4850
- } catch (err) {
4851
- log19.error({ err }, "memory operation failed");
4852
- continue;
4853
- }
4854
- }
4855
- headers.sort((a, b) => b.mtimeMs - a.mtimeMs);
4856
- if (headers.length > MAX_ENTRYPOINT_LINES2) {
4857
- headers.length = MAX_ENTRYPOINT_LINES2;
4858
- }
4859
- return headers;
4860
- }
4861
4847
  function formatMemoryManifest(memories) {
4862
4848
  if (memories.length === 0) {
4863
4849
  return "";
@@ -4903,27 +4889,22 @@ function parseFrontmatter(content) {
4903
4889
  if (!content.startsWith("---")) {
4904
4890
  return { body: content };
4905
4891
  }
4906
- const endIdx = content.indexOf("---", 3);
4907
- if (endIdx === -1) {
4908
- return { body: content };
4909
- }
4910
- const frontmatter = content.slice(3, endIdx).trim();
4911
- const body = content.slice(endIdx + 3).trim();
4912
- try {
4913
- const raw = yaml2.load(frontmatter);
4914
- const parsed = parse4(FrontmatterSchema, raw);
4915
- const topType = parsed.type;
4916
- const nestedType = parsed.metadata?.type;
4917
- return {
4918
- name: parsed.name,
4919
- description: parsed.description,
4920
- type: topType ?? nestedType,
4921
- body
4922
- };
4923
- } catch (err) {
4924
- log19.error({ err }, "memory operation failed");
4925
- return { body: content };
4892
+ const match = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/.exec(content);
4893
+ if (!match) {
4894
+ throw new Error("Memory frontmatter is missing its closing delimiter");
4926
4895
  }
4896
+ const frontmatter = match[1];
4897
+ const body = content.slice(match[0].length).trim();
4898
+ const raw = yaml2.load(frontmatter);
4899
+ const parsed = parse4(FrontmatterSchema, raw);
4900
+ const topType = parsed.type;
4901
+ const nestedType = parsed.metadata?.type;
4902
+ return {
4903
+ name: parsed.name,
4904
+ description: parsed.description,
4905
+ type: topType ?? nestedType,
4906
+ body
4907
+ };
4927
4908
  }
4928
4909
 
4929
4910
  // src/memory/extractor.ts
@@ -5046,10 +5027,10 @@ Check this list before writing \u2014 update an existing file rather than creati
5046
5027
  ``,
5047
5028
  "```markdown",
5048
5029
  `---`,
5049
- `name: {{short-kebab-case-slug}}`,
5050
- `description: {{one-line summary}}`,
5030
+ `name: "{{short-kebab-case-slug}}"`,
5031
+ `description: "{{one-line summary with YAML special characters escaped}}"`,
5051
5032
  `metadata:`,
5052
- ` type: {{user, feedback, project, reference}}`,
5033
+ ` type: "{{user, feedback, project, reference}}"`,
5053
5034
  `---`,
5054
5035
  ``,
5055
5036
  `{{memory content}}`,
@@ -5211,16 +5192,15 @@ Check this list before writing \u2014 update an existing file rather than creati
5211
5192
  }
5212
5193
  /** Format a memory file: frontmatter (name/description/type) + body */
5213
5194
  formatMemoryFile(mem) {
5214
- return [
5215
- "---",
5216
- `name: ${mem.name}`,
5217
- `description: ${mem.description}`,
5218
- `type: ${mem.type}`,
5219
- "---",
5220
- "",
5221
- mem.body,
5222
- ""
5223
- ].join("\n");
5195
+ const frontmatter = yaml3.dump(
5196
+ { name: mem.name, description: mem.description, type: mem.type },
5197
+ { forceQuotes: true, lineWidth: -1, noRefs: true, quotingType: '"' }
5198
+ );
5199
+ return `---
5200
+ ${frontmatter}---
5201
+
5202
+ ${mem.body}
5203
+ `;
5224
5204
  }
5225
5205
  };
5226
5206
 
@@ -6666,7 +6646,7 @@ async function copyWorktreeIncludeFiles(repoRoot, worktreePath) {
6666
6646
  import { readdirSync as readdirSync5, readFileSync as readFileSync15, existsSync as existsSync13 } from "fs";
6667
6647
  import { homedir as homedir6 } from "os";
6668
6648
  import { join as join15 } from "path";
6669
- import yaml3 from "js-yaml";
6649
+ import yaml4 from "js-yaml";
6670
6650
  import z7, { parse as parse5 } from "zod";
6671
6651
 
6672
6652
  // src/subagent/definition.ts
@@ -6766,7 +6746,7 @@ function parseAgentDefinition(content) {
6766
6746
  const frontmatter = content.slice(3, endIdx).trim();
6767
6747
  const body = content.slice(endIdx + 3).trim();
6768
6748
  try {
6769
- const raw = yaml3.load(frontmatter);
6749
+ const raw = yaml4.load(frontmatter);
6770
6750
  const parsed = parse5(YamlFrontmatterSchema2, raw);
6771
6751
  return {
6772
6752
  name: parsed.name,
@@ -7905,7 +7885,7 @@ function serializeConversation(conversation) {
7905
7885
  if (msg.toolResults && msg.toolResults.length > 0) {
7906
7886
  entry.tool_results = msg.toolResults.map((tr) => ({
7907
7887
  tool_use_id: tr.toolUseId,
7908
- content: contentToText(tr.content),
7888
+ content: tr.content,
7909
7889
  is_error: tr.isError || void 0
7910
7890
  }));
7911
7891
  }
@@ -8593,10 +8573,12 @@ var ToolSearchTool = class {
8593
8573
  return Promise.resolve({
8594
8574
  output: `Loaded ${String(mcpNames.length)} tool(s): ${mcpNames.join(", ")}. You can call them directly now.`,
8595
8575
  isError: false,
8596
- contentBlocks: mcpNames.map((name) => ({
8597
- type: "tool_reference",
8598
- tool_name: name
8599
- }))
8576
+ contentBlocks: mcpNames.map(
8577
+ (name) => ({
8578
+ type: "tool_reference",
8579
+ tool_name: name
8580
+ })
8581
+ )
8600
8582
  });
8601
8583
  }
8602
8584
  const schemas2 = tools2.map((t) => JSON.stringify(t.schema(), null, 2));
@@ -8816,7 +8798,7 @@ function emitStreamJson(event) {
8816
8798
  JSON.stringify({
8817
8799
  type: "tool_result",
8818
8800
  tool_name: event.toolName,
8819
- output: contentToText(event.output),
8801
+ output: event.output,
8820
8802
  is_error: event.isError,
8821
8803
  elapsed: event.elapsed
8822
8804
  })
@@ -8914,7 +8896,7 @@ var AgentEventLogger = class {
8914
8896
  if (!ev.isError) {
8915
8897
  return;
8916
8898
  }
8917
- const output = contentToText(ev.output);
8899
+ const output = ev.output;
8918
8900
  this.log.warn({
8919
8901
  event: "tool_result",
8920
8902
  tool: ev.toolName,
@@ -8954,7 +8936,7 @@ import z17 from "zod";
8954
8936
  import { readdirSync as readdirSync6, readFileSync as readFileSync21, existsSync as existsSync18, statSync as statSync11 } from "fs";
8955
8937
  import { homedir as homedir8 } from "os";
8956
8938
  import { join as join21 } from "path";
8957
- import yaml4 from "js-yaml";
8939
+ import yaml5 from "js-yaml";
8958
8940
  import { parse as parse8, z as z13 } from "zod";
8959
8941
  var log30 = createChildLogger({ module: "skills" });
8960
8942
  var SkillCatalog = class {
@@ -9140,7 +9122,7 @@ function parseSkillFile(content) {
9140
9122
  const frontmatter = content.slice(3, endIdx).trim();
9141
9123
  const body = content.slice(endIdx + 3).trim();
9142
9124
  try {
9143
- const raw = yaml4.load(frontmatter);
9125
+ const raw = yaml5.load(frontmatter);
9144
9126
  const data = parse8(YamlFrontmatterSchema3, raw);
9145
9127
  return {
9146
9128
  meta: {
@@ -10117,8 +10099,8 @@ async function createRemoteAgent(opts) {
10117
10099
  if (!client) {
10118
10100
  throw new Error("no llm client (provider not initialized)");
10119
10101
  }
10120
- const { PermissionChecker: PC } = await import("./checker-IIXJXQCB.js");
10121
- const { Agent: AgentClass } = await import("./agent-2AGRYN3R.js");
10102
+ const { PermissionChecker: PC } = await import("./checker-6BW4222R.js");
10103
+ const { Agent: AgentClass } = await import("./agent-GHXYOARN.js");
10122
10104
  const subConv = new ConversationManager();
10123
10105
  subConv.addUserMessage(prompt);
10124
10106
  const subAgent = new AgentClass({
@@ -10579,7 +10561,7 @@ var RemoteServer = class {
10579
10561
  data: {
10580
10562
  toolId: ev.toolId,
10581
10563
  toolName: ev.toolName,
10582
- output: contentToText(ev.output),
10564
+ output: ev.output,
10583
10565
  isError: ev.isError,
10584
10566
  elapsed: ev.elapsed
10585
10567
  }
@@ -10983,7 +10965,8 @@ Explore the codebase and design your approach.`
10983
10965
  msg.toolResults.map((tr) => ({
10984
10966
  toolUseId: tr.toolUseId,
10985
10967
  content: tr.content,
10986
- isError: tr.isError ?? false
10968
+ ...tr.contentBlocks?.length ? { contentBlocks: tr.contentBlocks } : {},
10969
+ isError: tr.isError
10987
10970
  }))
10988
10971
  );
10989
10972
  } else if (msg.role === "user") {
@@ -11720,7 +11703,6 @@ export {
11720
11703
  ConfigError,
11721
11704
  ContextTooLongError,
11722
11705
  ConversationManager,
11723
- DANGEROUSLY_JSON,
11724
11706
  DEFAULT_EAGER_THRESHOLD_PERCENT,
11725
11707
  EDIT_FILE_DESCRIPTION,
11726
11708
  EditFileTool,
@@ -11744,6 +11726,7 @@ export {
11744
11726
  ListTeamsTool,
11745
11727
  LoadSkillTool,
11746
11728
  MAX_DIMENSION_PX,
11729
+ MAX_HISTORY_ENTRIES,
11747
11730
  MAX_IMAGES_PER_MESSAGE,
11748
11731
  MAX_IMAGE_BYTES_PASSTHROUGH,
11749
11732
  MCPClient,
@@ -11791,6 +11774,7 @@ export {
11791
11774
  StreamingExecutor,
11792
11775
  SyntheticOutputTool,
11793
11776
  TEAMMATE_DISALLOWED_TOOLS,
11777
+ TOOL_RESULT_PREVIEW_CHARS,
11794
11778
  TOOL_SEARCH_TOOL_NAME,
11795
11779
  TaskCreateTool2 as TaskCreateTool,
11796
11780
  TaskGetTool2 as TaskGetTool,
@@ -11912,6 +11896,7 @@ export {
11912
11896
  isSafeCommand,
11913
11897
  isShutdownRequest,
11914
11898
  isSpillReadback,
11899
+ isToolResultContentBlock,
11915
11900
  listSessions,
11916
11901
  load,
11917
11902
  loadAgentDefinitions,
@@ -11939,6 +11924,7 @@ export {
11939
11924
  needsToolSearchBeta,
11940
11925
  newRequestId,
11941
11926
  newSessionId,
11927
+ normalizeToolResultContentBlock,
11942
11928
  outputEfficiencySection,
11943
11929
  parse,
11944
11930
  parsePrintFlags,
@@ -11961,6 +11947,7 @@ export {
11961
11947
  recover,
11962
11948
  removeAgentWorktree,
11963
11949
  renderBody,
11950
+ replaceToolResultContent,
11964
11951
  resetPlanPath,
11965
11952
  resolveAPIKey,
11966
11953
  resolveGitDir,
@@ -11991,6 +11978,7 @@ export {
11991
11978
  teamConfigPath,
11992
11979
  teamDir,
11993
11980
  teamsBaseDir,
11981
+ toDisplayPreview,
11994
11982
  toTry,
11995
11983
  toneStyleSection,
11996
11984
  toolResultsToRecords,