@sideboard-ai/core 0.1.244 → 0.1.245

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.
@@ -46,7 +46,7 @@ import {
46
46
  resolveLoginCommand,
47
47
  resolveQuotaFallbackAgent,
48
48
  whichOnPath
49
- } from "./chunk-CYYQ6577.js";
49
+ } from "./chunk-QRWVKBGP.js";
50
50
  import "./chunk-GFRC6JQN.js";
51
51
  import "./chunk-E6C5NR46.js";
52
52
  import "./chunk-6K64FJDD.js";
@@ -55,7 +55,7 @@ import {
55
55
  resolveQuotaFallbackAgent,
56
56
  turnCostUsdFromCursorUsage,
57
57
  whichOnPath
58
- } from "./chunk-2QRU4IFI.js";
58
+ } from "./chunk-3ZEBUVUI.js";
59
59
  import "./chunk-576S3HJ7.js";
60
60
  import "./chunk-J5GON4SU.js";
61
61
  import "./chunk-P2BSMNHB.js";
@@ -1697,23 +1697,38 @@ function looksLikeComposerSkillExpansion(text) {
1697
1697
  const t = text.trim();
1698
1698
  return /^## Skill: \//m.test(t) && /Follow this skill for the request above:/i.test(t);
1699
1699
  }
1700
+ var SKILL_FRONTMATTER_NAME = /^\s*name\s*:\s*['"]?([A-Za-z0-9][A-Za-z0-9._-]*)['"]?\s*$/m;
1701
+ function skillNameFromFrontmatter(text) {
1702
+ const t = text.trim();
1703
+ if (!t) return void 0;
1704
+ let yaml = t;
1705
+ if (!yaml.startsWith("---")) {
1706
+ const at = t.search(/(?:^|\n)---(?:\r?\n)/);
1707
+ if (at < 0 || at > 800) return void 0;
1708
+ yaml = t.slice(at).replace(/^\n/, "");
1709
+ }
1710
+ if (!yaml.startsWith("---")) return void 0;
1711
+ const close = yaml.indexOf("\n---", 3);
1712
+ if (close < 0) return void 0;
1713
+ return yaml.slice(3, close).match(SKILL_FRONTMATTER_NAME)?.[1];
1714
+ }
1715
+ function skillCommandFromBody(text) {
1716
+ return skillNameFromFrontmatter(text) ?? text.match(/^## Skill: \/([A-Za-z0-9][A-Za-z0-9._-]*)/m)?.[1] ?? text.match(/^Launching skill:\s*\/?([A-Za-z0-9][A-Za-z0-9._-]*)/im)?.[1];
1717
+ }
1700
1718
  function looksLikeSkillBody(text) {
1701
1719
  const t = text.trim();
1702
1720
  if (!t) return false;
1703
1721
  if (looksLikeComposerSkillExpansion(t)) return true;
1704
- return skillNameFromFrontmatter(t) != null;
1722
+ if (skillNameFromFrontmatter(t) != null) return true;
1723
+ return /^Launching skill:/im.test(t) && /Base directory for this skill:/i.test(t);
1705
1724
  }
1706
- function skillNameFromFrontmatter(text) {
1725
+ function looksLikeIncompleteSkillDump(text) {
1707
1726
  const t = text.trim();
1708
- if (!t.startsWith("---")) return void 0;
1709
- const close = t.indexOf("\n---", 3);
1710
- if (close < 0) return void 0;
1711
- const fm = t.slice(3, close);
1712
- const m = fm.match(/^\s*name\s*:\s*['"]?([A-Za-z0-9][A-Za-z0-9._-]*)['"]?\s*$/m);
1713
- return m?.[1];
1714
- }
1715
- function skillCommandFromBody(text) {
1716
- return skillNameFromFrontmatter(text) ?? text.match(/^## Skill: \/([A-Za-z0-9][A-Za-z0-9._-]*)/m)?.[1];
1727
+ if (!t || looksLikeSkillBody(t)) return false;
1728
+ if (/^## Skill: \//m.test(t)) return true;
1729
+ if (/^Launching skill:/im.test(t)) return true;
1730
+ if (/Base directory for this skill:/i.test(t)) return true;
1731
+ return t.startsWith("---") && SKILL_FRONTMATTER_NAME.test(t);
1717
1732
  }
1718
1733
  function isCompactToolName(name) {
1719
1734
  const short = (name ?? "").replace(/^mcp__[^_]+__/, "").trim();
@@ -2032,22 +2047,70 @@ function withPartTimes(next, prev) {
2032
2047
  const startedAt = prev && typeof prev.startedAt === "number" ? prev.startedAt : now;
2033
2048
  return { ...next, startedAt, updatedAt: now };
2034
2049
  }
2035
- function skillToolFromTextPart(part, id) {
2050
+ function skillToolFromTextPart(part, id, status = "done") {
2036
2051
  const command = skillCommandFromBody(part.text);
2037
2052
  const input = command ? { skill: command } : void 0;
2038
2053
  return {
2039
2054
  type: "tool",
2040
- id,
2055
+ id: command ? `skill-${command}` : id,
2041
2056
  name: "Skill",
2042
2057
  input,
2043
2058
  description: toolDescription("Skill", input),
2044
- status: "done",
2059
+ status,
2045
2060
  result: clipToolResultForStore(part.text),
2046
2061
  ...part.parentId ? { parentId: part.parentId } : {},
2047
2062
  startedAt: part.startedAt,
2048
2063
  updatedAt: Date.now()
2049
2064
  };
2050
2065
  }
2066
+ function lastSkillToolIndex(parts, parentId) {
2067
+ for (let i = parts.length - 1; i >= 0; i--) {
2068
+ const p = parts[i];
2069
+ if (p.type === "tool" && isSkillToolName(p.name) && sameParentId(p.parentId, parentId)) {
2070
+ return i;
2071
+ }
2072
+ }
2073
+ return -1;
2074
+ }
2075
+ function lastRunningSkillIndex(parts, parentId) {
2076
+ for (let i = parts.length - 1; i >= 0; i--) {
2077
+ const p = parts[i];
2078
+ if (p.type === "tool" && isSkillToolName(p.name) && p.status === "running" && sameParentId(p.parentId, parentId)) {
2079
+ return i;
2080
+ }
2081
+ }
2082
+ return -1;
2083
+ }
2084
+ function promoteOrFoldSkillText(parts, textIdx) {
2085
+ const acc = parts[textIdx];
2086
+ if (acc?.type !== "text") return parts;
2087
+ const complete = looksLikeSkillBody(acc.text);
2088
+ const incomplete = looksLikeIncompleteSkillDump(acc.text);
2089
+ if (!complete && !incomplete) return parts;
2090
+ const existing = lastSkillToolIndex(parts, acc.parentId);
2091
+ if (existing >= 0 && existing !== textIdx) {
2092
+ const prev = parts[existing];
2093
+ const next2 = parts.filter((_, i) => i !== textIdx);
2094
+ const existingIdx = lastSkillToolIndex(next2, acc.parentId);
2095
+ if (existingIdx < 0) return parts;
2096
+ next2[existingIdx] = withPartTimes(
2097
+ {
2098
+ ...prev,
2099
+ status: complete ? "done" : prev.status,
2100
+ result: clipToolResultForStore(acc.text) ?? prev.result
2101
+ },
2102
+ prev
2103
+ );
2104
+ return next2;
2105
+ }
2106
+ const next = [...parts];
2107
+ next[textIdx] = skillToolFromTextPart(
2108
+ acc,
2109
+ `skill-${next.length}`,
2110
+ complete ? "done" : "running"
2111
+ );
2112
+ return next;
2113
+ }
2051
2114
  function compactSummaryPart(text, id = "compact-summary") {
2052
2115
  return compactToolPart(text, id, { status: "done" });
2053
2116
  }
@@ -2136,6 +2199,21 @@ function applyAgentEvent(parts, event) {
2136
2199
  })
2137
2200
  ];
2138
2201
  }
2202
+ const runningSkillIdx = lastRunningSkillIndex(parts, event.parentId);
2203
+ if (runningSkillIdx >= 0) {
2204
+ const prev = parts[runningSkillIdx];
2205
+ const result = `${prev.result ?? ""}${data}`;
2206
+ const next2 = [...parts];
2207
+ next2[runningSkillIdx] = withPartTimes(
2208
+ {
2209
+ ...prev,
2210
+ result: clipToolResultForStore(result),
2211
+ status: looksLikeSkillBody(result) ? "done" : prev.status
2212
+ },
2213
+ prev
2214
+ );
2215
+ return next2;
2216
+ }
2139
2217
  const next = [...parts];
2140
2218
  const last = next[next.length - 1];
2141
2219
  if (last?.type === "text" && sameParentId(last.parentId, event.parentId)) {
@@ -2157,9 +2235,10 @@ function applyAgentEvent(parts, event) {
2157
2235
  );
2158
2236
  }
2159
2237
  const acc = next[next.length - 1];
2160
- if (acc?.type === "text" && looksLikeComposerSkillExpansion(acc.text)) {
2161
- next[next.length - 1] = skillToolFromTextPart(acc, `skill-${next.length}`);
2162
- } else if (acc?.type === "text" && looksLikeConversationSummary(acc.text)) {
2238
+ if (acc?.type === "text" && (looksLikeSkillBody(acc.text) || looksLikeIncompleteSkillDump(acc.text))) {
2239
+ return promoteOrFoldSkillText(next, next.length - 1);
2240
+ }
2241
+ if (acc?.type === "text" && looksLikeConversationSummary(acc.text)) {
2163
2242
  next[next.length - 1] = compactToolPart(acc.text, `compact-${next.length}`, {
2164
2243
  parentId: acc.parentId,
2165
2244
  status: "done",
@@ -2534,13 +2613,17 @@ function eventsFromInjectedUserText(text, parentId) {
2534
2613
  if (looksLikeConversationSummary(text)) return compactToolEventsFromBody(text, parentId);
2535
2614
  return [];
2536
2615
  }
2616
+ function eventsFromAssistantText(text, parentId) {
2617
+ if (looksLikeSkillBody(text)) return skillToolEventsFromBody(text, parentId);
2618
+ return [withEventParentId({ type: "stdout", data: text }, parentId)];
2619
+ }
2537
2620
  function eventsFromUserContent(content, parentId) {
2538
2621
  if (typeof content === "string" && content.trim()) {
2539
2622
  return eventsFromInjectedUserText(content, parentId);
2540
2623
  }
2541
2624
  if (!Array.isArray(content) || content.length === 0) return [];
2542
2625
  const out = [];
2543
- const textBlocks = [];
2626
+ const injected = [];
2544
2627
  for (const block of content) {
2545
2628
  if (!block?.type) continue;
2546
2629
  if (block.type === "tool_use" && block.id && block.name) {
@@ -2571,13 +2654,12 @@ function eventsFromUserContent(content, parentId) {
2571
2654
  );
2572
2655
  continue;
2573
2656
  }
2574
- if (block.type === "text" && block.text) textBlocks.push(block.text);
2575
- }
2576
- if (out.length > 0) return out;
2577
- for (const text of textBlocks) {
2578
- out.push(...eventsFromInjectedUserText(text, parentId));
2657
+ if (block.type === "text" && block.text) {
2658
+ injected.push(...eventsFromInjectedUserText(block.text, parentId));
2659
+ }
2579
2660
  }
2580
- return out;
2661
+ if (out.length === 0 && injected.length === 0) return [];
2662
+ return [...out, ...injected];
2581
2663
  }
2582
2664
  function eventsFromContentBlocks(blocks, parentId) {
2583
2665
  if (!blocks?.length) return [];
@@ -2585,7 +2667,7 @@ function eventsFromContentBlocks(blocks, parentId) {
2585
2667
  for (const block of blocks) {
2586
2668
  if (!block?.type) continue;
2587
2669
  if (block.type === "text" && block.text) {
2588
- out.push(withEventParentId({ type: "stdout", data: block.text }, parentId));
2670
+ out.push(...eventsFromAssistantText(block.text, parentId));
2589
2671
  continue;
2590
2672
  }
2591
2673
  if ((block.type === "thinking" || block.type === "redacted_thinking") && block.thinking) {
@@ -3014,7 +3096,9 @@ var claudeAdapter = {
3014
3096
  events.push({ type: "stderr", data: errorDetail });
3015
3097
  } else {
3016
3098
  const text = obj.result;
3017
- if (typeof text === "string" && text) events.push({ type: "stdout", data: text });
3099
+ if (typeof text === "string" && text) {
3100
+ events.push(...eventsFromAssistantText(text));
3101
+ }
3018
3102
  }
3019
3103
  const usage = usageFromClaude(obj.usage);
3020
3104
  if (usage) {
@@ -44,7 +44,7 @@ import {
44
44
  summarizeTurnStderr,
45
45
  toolDescription,
46
46
  turnFailChatText
47
- } from "./chunk-2QRU4IFI.js";
47
+ } from "./chunk-3ZEBUVUI.js";
48
48
  import {
49
49
  SLACK_REPLY_FORMATTING,
50
50
  addWorkspace,
@@ -606,9 +606,11 @@ async function spawnAgentTurn(thread, input, onEvent) {
606
606
  if (assistantText && (parsed.data === assistantText || assistantText.endsWith(parsed.data))) {
607
607
  continue;
608
608
  }
609
- assistantText += parsed.data;
610
609
  }
611
610
  parts = applyAgentEvent(parts, parsed);
611
+ if (parsed.type === "stdout") {
612
+ assistantText = partsToAssistantText(parts);
613
+ }
612
614
  outbound.push(parsed);
613
615
  }
614
616
  });
@@ -7058,7 +7060,7 @@ function formatScheduledPrompt(name, prompt) {
7058
7060
  ${prompt}`;
7059
7061
  }
7060
7062
  async function defaultDeps() {
7061
- const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-ZJ6SYGW7.js");
7063
+ const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-5ROSTGGH.js");
7062
7064
  const orch = getOrchestrator2();
7063
7065
  return {
7064
7066
  findThread: (id) => findThreadByRef(id),
@@ -25,7 +25,7 @@ import {
25
25
  resolveQuotaFallbackAgent,
26
26
  stripBrightsyNdjsonNoise,
27
27
  toolDescription
28
- } from "./chunk-CYYQ6577.js";
28
+ } from "./chunk-QRWVKBGP.js";
29
29
  import {
30
30
  SLACK_REPLY_FORMATTING,
31
31
  addWorkspace,
@@ -558,9 +558,11 @@ async function spawnAgentTurn(thread, input, onEvent) {
558
558
  if (assistantText && (parsed.data === assistantText || assistantText.endsWith(parsed.data))) {
559
559
  continue;
560
560
  }
561
- assistantText += parsed.data;
562
561
  }
563
562
  parts = applyAgentEvent(parts, parsed);
563
+ if (parsed.type === "stdout") {
564
+ assistantText = partsToAssistantText(parts);
565
+ }
564
566
  outbound.push(parsed);
565
567
  }
566
568
  });
@@ -4221,7 +4223,7 @@ async function createThread(input, _onSetupLine) {
4221
4223
  return readThread(thread.id) ?? thread;
4222
4224
  }
4223
4225
  async function listLinearIssues(agent, repoPath) {
4224
- const { getAdapter: getAdapter2 } = await import("./agents-Q23R4WOR.js");
4226
+ const { getAdapter: getAdapter2 } = await import("./agents-BOIIFMNG.js");
4225
4227
  await requireAgent(agent, { requireLinear: true });
4226
4228
  const adapter = getAdapter2(agent);
4227
4229
  if (!adapter.listLinearIssues) {
@@ -7406,7 +7408,7 @@ function formatScheduledPrompt(name, prompt) {
7406
7408
  ${prompt}`;
7407
7409
  }
7408
7410
  async function defaultDeps() {
7409
- const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-ABF6QFE6.js");
7411
+ const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-7YCQ7V5S.js");
7410
7412
  const orch = getOrchestrator2();
7411
7413
  return {
7412
7414
  findThread: (id) => findThreadByRef(id),
@@ -1187,23 +1187,38 @@ function looksLikeComposerSkillExpansion(text) {
1187
1187
  const t = text.trim();
1188
1188
  return /^## Skill: \//m.test(t) && /Follow this skill for the request above:/i.test(t);
1189
1189
  }
1190
+ var SKILL_FRONTMATTER_NAME = /^\s*name\s*:\s*['"]?([A-Za-z0-9][A-Za-z0-9._-]*)['"]?\s*$/m;
1191
+ function skillNameFromFrontmatter(text) {
1192
+ const t = text.trim();
1193
+ if (!t) return void 0;
1194
+ let yaml = t;
1195
+ if (!yaml.startsWith("---")) {
1196
+ const at = t.search(/(?:^|\n)---(?:\r?\n)/);
1197
+ if (at < 0 || at > 800) return void 0;
1198
+ yaml = t.slice(at).replace(/^\n/, "");
1199
+ }
1200
+ if (!yaml.startsWith("---")) return void 0;
1201
+ const close = yaml.indexOf("\n---", 3);
1202
+ if (close < 0) return void 0;
1203
+ return yaml.slice(3, close).match(SKILL_FRONTMATTER_NAME)?.[1];
1204
+ }
1205
+ function skillCommandFromBody(text) {
1206
+ return skillNameFromFrontmatter(text) ?? text.match(/^## Skill: \/([A-Za-z0-9][A-Za-z0-9._-]*)/m)?.[1] ?? text.match(/^Launching skill:\s*\/?([A-Za-z0-9][A-Za-z0-9._-]*)/im)?.[1];
1207
+ }
1190
1208
  function looksLikeSkillBody(text) {
1191
1209
  const t = text.trim();
1192
1210
  if (!t) return false;
1193
1211
  if (looksLikeComposerSkillExpansion(t)) return true;
1194
- return skillNameFromFrontmatter(t) != null;
1212
+ if (skillNameFromFrontmatter(t) != null) return true;
1213
+ return /^Launching skill:/im.test(t) && /Base directory for this skill:/i.test(t);
1195
1214
  }
1196
- function skillNameFromFrontmatter(text) {
1215
+ function looksLikeIncompleteSkillDump(text) {
1197
1216
  const t = text.trim();
1198
- if (!t.startsWith("---")) return void 0;
1199
- const close = t.indexOf("\n---", 3);
1200
- if (close < 0) return void 0;
1201
- const fm = t.slice(3, close);
1202
- const m = fm.match(/^\s*name\s*:\s*['"]?([A-Za-z0-9][A-Za-z0-9._-]*)['"]?\s*$/m);
1203
- return m?.[1];
1204
- }
1205
- function skillCommandFromBody(text) {
1206
- return skillNameFromFrontmatter(text) ?? text.match(/^## Skill: \/([A-Za-z0-9][A-Za-z0-9._-]*)/m)?.[1];
1217
+ if (!t || looksLikeSkillBody(t)) return false;
1218
+ if (/^## Skill: \//m.test(t)) return true;
1219
+ if (/^Launching skill:/im.test(t)) return true;
1220
+ if (/Base directory for this skill:/i.test(t)) return true;
1221
+ return t.startsWith("---") && SKILL_FRONTMATTER_NAME.test(t);
1207
1222
  }
1208
1223
  function isCompactToolName(name) {
1209
1224
  const short = (name ?? "").replace(/^mcp__[^_]+__/, "").trim();
@@ -1605,22 +1620,70 @@ function withPartTimes(next, prev) {
1605
1620
  const startedAt = prev && typeof prev.startedAt === "number" ? prev.startedAt : now;
1606
1621
  return { ...next, startedAt, updatedAt: now };
1607
1622
  }
1608
- function skillToolFromTextPart(part, id) {
1623
+ function skillToolFromTextPart(part, id, status = "done") {
1609
1624
  const command = skillCommandFromBody(part.text);
1610
1625
  const input = command ? { skill: command } : void 0;
1611
1626
  return {
1612
1627
  type: "tool",
1613
- id,
1628
+ id: command ? `skill-${command}` : id,
1614
1629
  name: "Skill",
1615
1630
  input,
1616
1631
  description: toolDescription("Skill", input),
1617
- status: "done",
1632
+ status,
1618
1633
  result: clipToolResultForStore(part.text),
1619
1634
  ...part.parentId ? { parentId: part.parentId } : {},
1620
1635
  startedAt: part.startedAt,
1621
1636
  updatedAt: Date.now()
1622
1637
  };
1623
1638
  }
1639
+ function lastSkillToolIndex(parts, parentId) {
1640
+ for (let i = parts.length - 1; i >= 0; i--) {
1641
+ const p = parts[i];
1642
+ if (p.type === "tool" && isSkillToolName(p.name) && sameParentId(p.parentId, parentId)) {
1643
+ return i;
1644
+ }
1645
+ }
1646
+ return -1;
1647
+ }
1648
+ function lastRunningSkillIndex(parts, parentId) {
1649
+ for (let i = parts.length - 1; i >= 0; i--) {
1650
+ const p = parts[i];
1651
+ if (p.type === "tool" && isSkillToolName(p.name) && p.status === "running" && sameParentId(p.parentId, parentId)) {
1652
+ return i;
1653
+ }
1654
+ }
1655
+ return -1;
1656
+ }
1657
+ function promoteOrFoldSkillText(parts, textIdx) {
1658
+ const acc = parts[textIdx];
1659
+ if (acc?.type !== "text") return parts;
1660
+ const complete = looksLikeSkillBody(acc.text);
1661
+ const incomplete = looksLikeIncompleteSkillDump(acc.text);
1662
+ if (!complete && !incomplete) return parts;
1663
+ const existing = lastSkillToolIndex(parts, acc.parentId);
1664
+ if (existing >= 0 && existing !== textIdx) {
1665
+ const prev = parts[existing];
1666
+ const next2 = parts.filter((_, i) => i !== textIdx);
1667
+ const existingIdx = lastSkillToolIndex(next2, acc.parentId);
1668
+ if (existingIdx < 0) return parts;
1669
+ next2[existingIdx] = withPartTimes(
1670
+ {
1671
+ ...prev,
1672
+ status: complete ? "done" : prev.status,
1673
+ result: clipToolResultForStore(acc.text) ?? prev.result
1674
+ },
1675
+ prev
1676
+ );
1677
+ return next2;
1678
+ }
1679
+ const next = [...parts];
1680
+ next[textIdx] = skillToolFromTextPart(
1681
+ acc,
1682
+ `skill-${next.length}`,
1683
+ complete ? "done" : "running"
1684
+ );
1685
+ return next;
1686
+ }
1624
1687
  function compactSummaryPart(text, id = "compact-summary") {
1625
1688
  return compactToolPart(text, id, { status: "done" });
1626
1689
  }
@@ -1716,6 +1779,21 @@ function applyAgentEvent(parts, event) {
1716
1779
  })
1717
1780
  ];
1718
1781
  }
1782
+ const runningSkillIdx = lastRunningSkillIndex(parts, event.parentId);
1783
+ if (runningSkillIdx >= 0) {
1784
+ const prev = parts[runningSkillIdx];
1785
+ const result = `${prev.result ?? ""}${data}`;
1786
+ const next2 = [...parts];
1787
+ next2[runningSkillIdx] = withPartTimes(
1788
+ {
1789
+ ...prev,
1790
+ result: clipToolResultForStore(result),
1791
+ status: looksLikeSkillBody(result) ? "done" : prev.status
1792
+ },
1793
+ prev
1794
+ );
1795
+ return next2;
1796
+ }
1719
1797
  const next = [...parts];
1720
1798
  const last = next[next.length - 1];
1721
1799
  if (last?.type === "text" && sameParentId(last.parentId, event.parentId)) {
@@ -1737,9 +1815,10 @@ function applyAgentEvent(parts, event) {
1737
1815
  );
1738
1816
  }
1739
1817
  const acc = next[next.length - 1];
1740
- if (acc?.type === "text" && looksLikeComposerSkillExpansion(acc.text)) {
1741
- next[next.length - 1] = skillToolFromTextPart(acc, `skill-${next.length}`);
1742
- } else if (acc?.type === "text" && looksLikeConversationSummary(acc.text)) {
1818
+ if (acc?.type === "text" && (looksLikeSkillBody(acc.text) || looksLikeIncompleteSkillDump(acc.text))) {
1819
+ return promoteOrFoldSkillText(next, next.length - 1);
1820
+ }
1821
+ if (acc?.type === "text" && looksLikeConversationSummary(acc.text)) {
1743
1822
  next[next.length - 1] = compactToolPart(acc.text, `compact-${next.length}`, {
1744
1823
  parentId: acc.parentId,
1745
1824
  status: "done",
@@ -1908,6 +1987,12 @@ function partsToAssistantText(parts) {
1908
1987
  (p) => p.type === "text" && !messagePartParentId(p)
1909
1988
  ).map((p) => p.text).join("").trim();
1910
1989
  }
1990
+ function visibleAssistantText(text, parts) {
1991
+ const fromParts = partsToAssistantText(parts ?? []);
1992
+ if (fromParts) return fromParts;
1993
+ if (parts?.some((p) => p.type === "tool" || p.type === "thinking")) return "";
1994
+ return (text ?? "").trim();
1995
+ }
1911
1996
  function lastAssistantMessageText(parts) {
1912
1997
  if (!parts?.length) return "";
1913
1998
  for (let i = parts.length - 1; i >= 0; i--) {
@@ -2114,13 +2199,17 @@ function eventsFromInjectedUserText(text, parentId) {
2114
2199
  if (looksLikeConversationSummary(text)) return compactToolEventsFromBody(text, parentId);
2115
2200
  return [];
2116
2201
  }
2202
+ function eventsFromAssistantText(text, parentId) {
2203
+ if (looksLikeSkillBody(text)) return skillToolEventsFromBody(text, parentId);
2204
+ return [withEventParentId({ type: "stdout", data: text }, parentId)];
2205
+ }
2117
2206
  function eventsFromUserContent(content, parentId) {
2118
2207
  if (typeof content === "string" && content.trim()) {
2119
2208
  return eventsFromInjectedUserText(content, parentId);
2120
2209
  }
2121
2210
  if (!Array.isArray(content) || content.length === 0) return [];
2122
2211
  const out = [];
2123
- const textBlocks = [];
2212
+ const injected = [];
2124
2213
  for (const block of content) {
2125
2214
  if (!block?.type) continue;
2126
2215
  if (block.type === "tool_use" && block.id && block.name) {
@@ -2151,13 +2240,12 @@ function eventsFromUserContent(content, parentId) {
2151
2240
  );
2152
2241
  continue;
2153
2242
  }
2154
- if (block.type === "text" && block.text) textBlocks.push(block.text);
2155
- }
2156
- if (out.length > 0) return out;
2157
- for (const text of textBlocks) {
2158
- out.push(...eventsFromInjectedUserText(text, parentId));
2243
+ if (block.type === "text" && block.text) {
2244
+ injected.push(...eventsFromInjectedUserText(block.text, parentId));
2245
+ }
2159
2246
  }
2160
- return out;
2247
+ if (out.length === 0 && injected.length === 0) return [];
2248
+ return [...out, ...injected];
2161
2249
  }
2162
2250
  function eventsFromContentBlocks(blocks, parentId) {
2163
2251
  if (!blocks?.length) return [];
@@ -2165,7 +2253,7 @@ function eventsFromContentBlocks(blocks, parentId) {
2165
2253
  for (const block of blocks) {
2166
2254
  if (!block?.type) continue;
2167
2255
  if (block.type === "text" && block.text) {
2168
- out.push(withEventParentId({ type: "stdout", data: block.text }, parentId));
2256
+ out.push(...eventsFromAssistantText(block.text, parentId));
2169
2257
  continue;
2170
2258
  }
2171
2259
  if ((block.type === "thinking" || block.type === "redacted_thinking") && block.thinking) {
@@ -2594,7 +2682,9 @@ var claudeAdapter = {
2594
2682
  events.push({ type: "stderr", data: errorDetail });
2595
2683
  } else {
2596
2684
  const text = obj.result;
2597
- if (typeof text === "string" && text) events.push({ type: "stdout", data: text });
2685
+ if (typeof text === "string" && text) {
2686
+ events.push(...eventsFromAssistantText(text));
2687
+ }
2598
2688
  }
2599
2689
  const usage = usageFromClaude(obj.usage);
2600
2690
  if (usage) {
@@ -4419,9 +4509,10 @@ export {
4419
4509
  isSkillToolName,
4420
4510
  skillCommandFromInput,
4421
4511
  looksLikeComposerSkillExpansion,
4422
- looksLikeSkillBody,
4423
4512
  skillNameFromFrontmatter,
4424
4513
  skillCommandFromBody,
4514
+ looksLikeSkillBody,
4515
+ looksLikeIncompleteSkillDump,
4425
4516
  isCompactToolName,
4426
4517
  isContextCompactDone,
4427
4518
  isContextCompactInProgress,
@@ -4447,6 +4538,7 @@ export {
4447
4538
  compactPartsForSummaryMessage,
4448
4539
  applyAgentEvent,
4449
4540
  partsToAssistantText,
4541
+ visibleAssistantText,
4450
4542
  lastAssistantMessageText,
4451
4543
  stripBrightsyNdjsonNoise,
4452
4544
  isBrightsyNdjsonLine,