@exreve/exk 1.0.47 → 1.0.48

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.
@@ -960,25 +960,25 @@ export class AgentSessionManager {
960
960
  }
961
961
  else if (message.type === 'user') {
962
962
  const msg = message;
963
- // SDK 0.2.x: tool results can appear in two places:
964
- // 1. msg.tool_use_result (top-level field, present in 0.1.x and some 0.2.x messages)
965
- // 2. msg.message.content array with type='tool_result' blocks (common in 0.2.x subagent calls)
963
+ // SDK 0.2.x: tool results appear in message.content as tool_result blocks.
964
+ // The tool_use_id is ALWAYS in message.content[].tool_use_id never in
965
+ // the top-level tool_use_result field. We must extract it from message.content
966
+ // first, then use either parsed content blocks or tool_use_result as the data source.
966
967
  let toolResult = null;
967
968
  let toolUseId = msg.parent_tool_use_id;
968
- // Check top-level tool_use_result first
969
- if (msg.tool_use_result) {
970
- toolResult = msg.tool_use_result;
969
+ // STEP 1: Always extract tool_use_id from message.content (authoritative source)
970
+ if (Array.isArray(msg.message?.content)) {
971
+ const contentBlocks = msg.message.content;
972
+ const toolResultBlock = contentBlocks.find((c) => c.type === 'tool_result');
973
+ if (toolResultBlock?.tool_use_id) {
974
+ toolUseId = toolResultBlock.tool_use_id;
975
+ }
971
976
  }
972
- // Check message.content for tool_result blocks (SDK 0.2.x nested calls)
973
- if (!toolResult && Array.isArray(msg.message?.content)) {
977
+ // STEP 2: Try to parse the actual result from message.content tool_result block
978
+ if (Array.isArray(msg.message?.content)) {
974
979
  const contentBlocks = msg.message.content;
975
980
  const toolResultBlock = contentBlocks.find((c) => c.type === 'tool_result');
976
981
  if (toolResultBlock) {
977
- // Extract tool use ID from the content block
978
- if (toolResultBlock.tool_use_id) {
979
- toolUseId = toolResultBlock.tool_use_id;
980
- }
981
- // The result content can be a string or array of content blocks
982
982
  if (typeof toolResultBlock.content === 'string') {
983
983
  try {
984
984
  toolResult = JSON.parse(toolResultBlock.content);
@@ -988,7 +988,7 @@ export class AgentSessionManager {
988
988
  }
989
989
  }
990
990
  else if (Array.isArray(toolResultBlock.content)) {
991
- // Extract text from content blocks
991
+ // Extract text from content blocks and try to parse as JSON
992
992
  const textParts = toolResultBlock.content
993
993
  .filter((c) => c.type === 'text')
994
994
  .map((c) => c.text);
@@ -1005,6 +1005,35 @@ export class AgentSessionManager {
1005
1005
  }
1006
1006
  }
1007
1007
  }
1008
+ // STEP 3: Fallback to top-level tool_use_result if message.content didn't yield a result
1009
+ // (present in SDK 0.1.x and some 0.2.x messages). Parse the raw content blocks.
1010
+ if (!toolResult && msg.tool_use_result) {
1011
+ const raw = msg.tool_use_result;
1012
+ if (Array.isArray(raw)) {
1013
+ // tool_use_result is [{type:"text", text:"..."}] — extract and parse text
1014
+ const textParts = raw
1015
+ .filter((c) => c.type === 'text')
1016
+ .map((c) => c.text);
1017
+ const rawContent = textParts.join('\n');
1018
+ try {
1019
+ toolResult = JSON.parse(rawContent);
1020
+ }
1021
+ catch {
1022
+ toolResult = { content: rawContent, type: 'text' };
1023
+ }
1024
+ }
1025
+ else if (typeof raw === 'string') {
1026
+ try {
1027
+ toolResult = JSON.parse(raw);
1028
+ }
1029
+ catch {
1030
+ toolResult = { content: raw, type: 'text' };
1031
+ }
1032
+ }
1033
+ else {
1034
+ toolResult = raw;
1035
+ }
1036
+ }
1008
1037
  if (toolResult) {
1009
1038
  const detectedName = extractToolName(toolResult);
1010
1039
  const resolvedName = detectedName !== 'unknown'
@@ -132,6 +132,9 @@ async function handleStatus(projectPath) {
132
132
  // empty
133
133
  }
134
134
  const changedFiles = parsePorcelainStatus(porcelainOutput);
135
+ const MAX_CHANGED_FILES = 1000;
136
+ const totalChangedFiles = changedFiles.length;
137
+ const truncated = totalChangedFiles > MAX_CHANGED_FILES ? changedFiles.slice(0, MAX_CHANGED_FILES) : changedFiles;
135
138
  return {
136
139
  success: true,
137
140
  status: {
@@ -140,9 +143,10 @@ async function handleStatus(projectPath) {
140
143
  remote: remote || undefined,
141
144
  ahead,
142
145
  behind,
143
- changedFiles,
146
+ changedFiles: truncated,
144
147
  stashCount,
145
148
  ghAvailable: ghOk,
149
+ ...(totalChangedFiles > MAX_CHANGED_FILES && { totalChangedFiles }),
146
150
  },
147
151
  };
148
152
  }
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exreve/exk",
3
- "version": "1.0.47",
3
+ "version": "1.0.48",
4
4
  "description": "exk - Control Claude CLI with voice and programmable interfaces",
5
5
  "type": "module",
6
6
  "bin": {
@@ -61,4 +61,4 @@
61
61
  "engines": {
62
62
  "node": ">=20.0.0"
63
63
  }
64
- }
64
+ }