@robota-sdk/agent-cli 3.0.0-beta.25 → 3.0.0-beta.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/node/bin.cjs CHANGED
@@ -174,7 +174,7 @@ var import_agent_core3 = require("@robota-sdk/agent-core");
174
174
  var import_react = require("react");
175
175
  var import_agent_sdk = require("@robota-sdk/agent-sdk");
176
176
  var TOOL_ARG_DISPLAY_MAX = 80;
177
- var TOOL_ARG_TRUNCATE_AT = 77;
177
+ var TAIL_KEEP = 30;
178
178
  var NOOP_TERMINAL = {
179
179
  write: () => {
180
180
  },
@@ -233,13 +233,17 @@ function useSession(props) {
233
233
  if (event.toolArgs) {
234
234
  const firstVal = Object.values(event.toolArgs)[0];
235
235
  const raw = typeof firstVal === "string" ? firstVal : JSON.stringify(firstVal ?? "");
236
- firstArg = raw.length > TOOL_ARG_DISPLAY_MAX ? raw.slice(0, TOOL_ARG_TRUNCATE_AT) + "..." : raw;
236
+ firstArg = raw.length > TOOL_ARG_DISPLAY_MAX ? raw.slice(0, TOOL_ARG_DISPLAY_MAX - TAIL_KEEP - 3) + "..." + raw.slice(-TAIL_KEEP) : raw;
237
237
  }
238
- setActiveTools((prev) => [...prev, { toolName: event.toolName, firstArg, isRunning: true }]);
238
+ setActiveTools((prev) => [
239
+ ...prev,
240
+ { toolName: event.toolName, firstArg, isRunning: true }
241
+ ]);
239
242
  } else {
243
+ const result = event.denied ? "denied" : event.success === false ? "error" : "success";
240
244
  setActiveTools(
241
245
  (prev) => prev.map(
242
- (t) => t.toolName === event.toolName && t.isRunning ? { ...t, isRunning: false } : t
246
+ (t) => t.toolName === event.toolName && t.isRunning ? { ...t, isRunning: false, result } : t
243
247
  )
244
248
  );
245
249
  }
@@ -263,7 +267,13 @@ function useSession(props) {
263
267
  setStreamingText("");
264
268
  setActiveTools([]);
265
269
  }, []);
266
- return { session: sessionRef.current, permissionRequest, streamingText, clearStreamingText, activeTools };
270
+ return {
271
+ session: sessionRef.current,
272
+ permissionRequest,
273
+ streamingText,
274
+ clearStreamingText,
275
+ activeTools
276
+ };
267
277
  }
268
278
 
269
279
  // src/ui/hooks/useMessages.ts
@@ -594,7 +604,7 @@ var import_react4 = require("react");
594
604
 
595
605
  // src/utils/tool-call-extractor.ts
596
606
  var TOOL_ARG_MAX_LENGTH = 80;
597
- var TOOL_ARG_TRUNCATE_LENGTH = 77;
607
+ var TAIL_KEEP2 = 30;
598
608
  function extractToolCalls(history, startIndex) {
599
609
  const lines = [];
600
610
  for (let i = startIndex; i < history.length; i++) {
@@ -602,7 +612,7 @@ function extractToolCalls(history, startIndex) {
602
612
  if (msg.role === "assistant" && msg.toolCalls) {
603
613
  for (const tc of msg.toolCalls) {
604
614
  const value = parseFirstArgValue(tc.function.arguments);
605
- const truncated = value.length > TOOL_ARG_MAX_LENGTH ? value.slice(0, TOOL_ARG_TRUNCATE_LENGTH) + "..." : value;
615
+ const truncated = value.length > TOOL_ARG_MAX_LENGTH ? value.slice(0, TOOL_ARG_MAX_LENGTH - TAIL_KEEP2 - 3) + "..." + value.slice(-TAIL_KEEP2) : value;
606
616
  lines.push(`${tc.function.name}(${truncated})`);
607
617
  }
608
618
  }
@@ -730,6 +740,9 @@ function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamin
730
740
  }
731
741
  const prompt = await buildSkillPrompt(input, registry);
732
742
  if (!prompt) return;
743
+ const cmdName = input.slice(1).split(/\s+/)[0]?.toLowerCase() ?? "";
744
+ const qualifiedName = registry.resolveQualifiedName(cmdName);
745
+ const hookInput = qualifiedName ? `/${qualifiedName}${input.slice(1 + cmdName.length)}` : input;
733
746
  return runSessionPrompt(
734
747
  prompt,
735
748
  session,
@@ -737,7 +750,7 @@ function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamin
737
750
  clearStreamingText,
738
751
  setIsThinking,
739
752
  setContextState,
740
- input
753
+ hookInput
741
754
  );
742
755
  }
743
756
  addMessage({ role: "user", content: input });
@@ -784,6 +797,14 @@ var CommandRegistry = class {
784
797
  const lower = filter.toLowerCase();
785
798
  return all.filter((cmd) => cmd.name.toLowerCase().startsWith(lower));
786
799
  }
800
+ /** Resolve a short name to its fully qualified plugin:name form */
801
+ resolveQualifiedName(shortName) {
802
+ const matches = this.getCommands().filter(
803
+ (c) => c.source === "plugin" && c.name.includes(":") && c.name.endsWith(`:${shortName}`)
804
+ );
805
+ if (matches.length !== 1) return null;
806
+ return matches[0].name;
807
+ }
787
808
  /** Get subcommands for a specific command */
788
809
  getSubcommands(commandName) {
789
810
  const lower = commandName.toLowerCase();
@@ -1017,7 +1038,7 @@ var PluginCommandSource = class {
1017
1038
  const baseName = skill.name.includes("@") ? skill.name.split("@")[0] : skill.name;
1018
1039
  commands.push({
1019
1040
  name: baseName,
1020
- description: `${skill.description} (${plugin.manifest.name})`,
1041
+ description: `(${plugin.manifest.name}) ${skill.description}`,
1021
1042
  source: "plugin",
1022
1043
  skillContent: skill.skillContent,
1023
1044
  pluginDir: plugin.pluginDir
@@ -1217,13 +1238,39 @@ function RoleLabel({ role }) {
1217
1238
  " "
1218
1239
  ] });
1219
1240
  case "tool":
1220
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "magenta", bold: true, children: [
1241
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "white", bold: true, children: [
1221
1242
  "Tool:",
1222
1243
  " "
1223
1244
  ] });
1224
1245
  }
1225
1246
  }
1247
+ function ToolMessage({ message }) {
1248
+ const lines = message.content.split("\n").filter((l) => l.trim());
1249
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Box, { flexDirection: "column", marginBottom: 1, children: [
1250
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Box, { children: [
1251
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "white", bold: true, children: [
1252
+ "Tool:",
1253
+ " "
1254
+ ] }),
1255
+ message.toolName && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "white", dimColor: true, children: [
1256
+ "[",
1257
+ message.toolName,
1258
+ "]"
1259
+ ] })
1260
+ ] }),
1261
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { children: " " }),
1262
+ lines.map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "green", children: [
1263
+ " ",
1264
+ "\u2713",
1265
+ " ",
1266
+ line
1267
+ ] }, i))
1268
+ ] });
1269
+ }
1226
1270
  function MessageItem({ message }) {
1271
+ if (message.role === "tool") {
1272
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToolMessage, { message });
1273
+ }
1227
1274
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Box, { flexDirection: "column", marginBottom: 1, children: [
1228
1275
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Box, { children: [
1229
1276
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RoleLabel, { role: message.role }),
@@ -1715,6 +1762,12 @@ function PermissionPrompt({ request }) {
1715
1762
  // src/ui/StreamingIndicator.tsx
1716
1763
  var import_ink9 = require("ink");
1717
1764
  var import_jsx_runtime9 = require("react/jsx-runtime");
1765
+ function getToolStyle(t) {
1766
+ if (t.isRunning) return { color: "yellow", icon: "\u27F3", strikethrough: false };
1767
+ if (t.result === "error") return { color: "red", icon: "\u2717", strikethrough: true };
1768
+ if (t.result === "denied") return { color: "yellowBright", icon: "\u2298", strikethrough: true };
1769
+ return { color: "green", icon: "\u2713", strikethrough: false };
1770
+ }
1718
1771
  function StreamingIndicator({ text, activeTools }) {
1719
1772
  const hasTools = activeTools.length > 0;
1720
1773
  const hasText = text.length > 0;
@@ -1723,17 +1776,20 @@ function StreamingIndicator({ text, activeTools }) {
1723
1776
  }
1724
1777
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Box, { flexDirection: "column", children: [
1725
1778
  hasTools && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Box, { flexDirection: "column", marginBottom: 1, children: [
1726
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { color: "gray", bold: true, children: "Tools:" }),
1779
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { color: "white", bold: true, children: "Tools:" }),
1727
1780
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { children: " " }),
1728
- activeTools.map((t, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Text, { color: t.isRunning ? "yellow" : "green", children: [
1729
- " ",
1730
- t.isRunning ? "\u27F3" : "\u2713",
1731
- " ",
1732
- t.toolName,
1733
- "(",
1734
- t.firstArg,
1735
- ")"
1736
- ] }, `${t.toolName}-${i}`))
1781
+ activeTools.map((t, i) => {
1782
+ const { color, icon, strikethrough } = getToolStyle(t);
1783
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Text, { color, strikethrough, children: [
1784
+ " ",
1785
+ icon,
1786
+ " ",
1787
+ t.toolName,
1788
+ "(",
1789
+ t.firstArg,
1790
+ ")"
1791
+ ] }, `${t.toolName}-${i}`);
1792
+ })
1737
1793
  ] }),
1738
1794
  hasText && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Box, { flexDirection: "column", marginBottom: 1, children: [
1739
1795
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { color: "cyan", bold: true, children: "Robota:" }),
package/dist/node/bin.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  startCli
4
- } from "./chunk-GJ3LG37H.js";
4
+ } from "./chunk-QTZS5QXJ.js";
5
5
 
6
6
  // src/bin.ts
7
7
  process.on("uncaughtException", (err) => {
@@ -157,7 +157,7 @@ import { getModelName } from "@robota-sdk/agent-core";
157
157
  import { useState, useCallback, useRef } from "react";
158
158
  import { createSession, FileSessionLogger, projectPaths } from "@robota-sdk/agent-sdk";
159
159
  var TOOL_ARG_DISPLAY_MAX = 80;
160
- var TOOL_ARG_TRUNCATE_AT = 77;
160
+ var TAIL_KEEP = 30;
161
161
  var NOOP_TERMINAL = {
162
162
  write: () => {
163
163
  },
@@ -216,13 +216,17 @@ function useSession(props) {
216
216
  if (event.toolArgs) {
217
217
  const firstVal = Object.values(event.toolArgs)[0];
218
218
  const raw = typeof firstVal === "string" ? firstVal : JSON.stringify(firstVal ?? "");
219
- firstArg = raw.length > TOOL_ARG_DISPLAY_MAX ? raw.slice(0, TOOL_ARG_TRUNCATE_AT) + "..." : raw;
219
+ firstArg = raw.length > TOOL_ARG_DISPLAY_MAX ? raw.slice(0, TOOL_ARG_DISPLAY_MAX - TAIL_KEEP - 3) + "..." + raw.slice(-TAIL_KEEP) : raw;
220
220
  }
221
- setActiveTools((prev) => [...prev, { toolName: event.toolName, firstArg, isRunning: true }]);
221
+ setActiveTools((prev) => [
222
+ ...prev,
223
+ { toolName: event.toolName, firstArg, isRunning: true }
224
+ ]);
222
225
  } else {
226
+ const result = event.denied ? "denied" : event.success === false ? "error" : "success";
223
227
  setActiveTools(
224
228
  (prev) => prev.map(
225
- (t) => t.toolName === event.toolName && t.isRunning ? { ...t, isRunning: false } : t
229
+ (t) => t.toolName === event.toolName && t.isRunning ? { ...t, isRunning: false, result } : t
226
230
  )
227
231
  );
228
232
  }
@@ -246,7 +250,13 @@ function useSession(props) {
246
250
  setStreamingText("");
247
251
  setActiveTools([]);
248
252
  }, []);
249
- return { session: sessionRef.current, permissionRequest, streamingText, clearStreamingText, activeTools };
253
+ return {
254
+ session: sessionRef.current,
255
+ permissionRequest,
256
+ streamingText,
257
+ clearStreamingText,
258
+ activeTools
259
+ };
250
260
  }
251
261
 
252
262
  // src/ui/hooks/useMessages.ts
@@ -577,7 +587,7 @@ import { useCallback as useCallback4 } from "react";
577
587
 
578
588
  // src/utils/tool-call-extractor.ts
579
589
  var TOOL_ARG_MAX_LENGTH = 80;
580
- var TOOL_ARG_TRUNCATE_LENGTH = 77;
590
+ var TAIL_KEEP2 = 30;
581
591
  function extractToolCalls(history, startIndex) {
582
592
  const lines = [];
583
593
  for (let i = startIndex; i < history.length; i++) {
@@ -585,7 +595,7 @@ function extractToolCalls(history, startIndex) {
585
595
  if (msg.role === "assistant" && msg.toolCalls) {
586
596
  for (const tc of msg.toolCalls) {
587
597
  const value = parseFirstArgValue(tc.function.arguments);
588
- const truncated = value.length > TOOL_ARG_MAX_LENGTH ? value.slice(0, TOOL_ARG_TRUNCATE_LENGTH) + "..." : value;
598
+ const truncated = value.length > TOOL_ARG_MAX_LENGTH ? value.slice(0, TOOL_ARG_MAX_LENGTH - TAIL_KEEP2 - 3) + "..." + value.slice(-TAIL_KEEP2) : value;
589
599
  lines.push(`${tc.function.name}(${truncated})`);
590
600
  }
591
601
  }
@@ -713,6 +723,9 @@ function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamin
713
723
  }
714
724
  const prompt = await buildSkillPrompt(input, registry);
715
725
  if (!prompt) return;
726
+ const cmdName = input.slice(1).split(/\s+/)[0]?.toLowerCase() ?? "";
727
+ const qualifiedName = registry.resolveQualifiedName(cmdName);
728
+ const hookInput = qualifiedName ? `/${qualifiedName}${input.slice(1 + cmdName.length)}` : input;
716
729
  return runSessionPrompt(
717
730
  prompt,
718
731
  session,
@@ -720,7 +733,7 @@ function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamin
720
733
  clearStreamingText,
721
734
  setIsThinking,
722
735
  setContextState,
723
- input
736
+ hookInput
724
737
  );
725
738
  }
726
739
  addMessage({ role: "user", content: input });
@@ -767,6 +780,14 @@ var CommandRegistry = class {
767
780
  const lower = filter.toLowerCase();
768
781
  return all.filter((cmd) => cmd.name.toLowerCase().startsWith(lower));
769
782
  }
783
+ /** Resolve a short name to its fully qualified plugin:name form */
784
+ resolveQualifiedName(shortName) {
785
+ const matches = this.getCommands().filter(
786
+ (c) => c.source === "plugin" && c.name.includes(":") && c.name.endsWith(`:${shortName}`)
787
+ );
788
+ if (matches.length !== 1) return null;
789
+ return matches[0].name;
790
+ }
770
791
  /** Get subcommands for a specific command */
771
792
  getSubcommands(commandName) {
772
793
  const lower = commandName.toLowerCase();
@@ -1000,7 +1021,7 @@ var PluginCommandSource = class {
1000
1021
  const baseName = skill.name.includes("@") ? skill.name.split("@")[0] : skill.name;
1001
1022
  commands.push({
1002
1023
  name: baseName,
1003
- description: `${skill.description} (${plugin.manifest.name})`,
1024
+ description: `(${plugin.manifest.name}) ${skill.description}`,
1004
1025
  source: "plugin",
1005
1026
  skillContent: skill.skillContent,
1006
1027
  pluginDir: plugin.pluginDir
@@ -1205,13 +1226,39 @@ function RoleLabel({ role }) {
1205
1226
  " "
1206
1227
  ] });
1207
1228
  case "tool":
1208
- return /* @__PURE__ */ jsxs(Text, { color: "magenta", bold: true, children: [
1229
+ return /* @__PURE__ */ jsxs(Text, { color: "white", bold: true, children: [
1209
1230
  "Tool:",
1210
1231
  " "
1211
1232
  ] });
1212
1233
  }
1213
1234
  }
1235
+ function ToolMessage({ message }) {
1236
+ const lines = message.content.split("\n").filter((l) => l.trim());
1237
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
1238
+ /* @__PURE__ */ jsxs(Box, { children: [
1239
+ /* @__PURE__ */ jsxs(Text, { color: "white", bold: true, children: [
1240
+ "Tool:",
1241
+ " "
1242
+ ] }),
1243
+ message.toolName && /* @__PURE__ */ jsxs(Text, { color: "white", dimColor: true, children: [
1244
+ "[",
1245
+ message.toolName,
1246
+ "]"
1247
+ ] })
1248
+ ] }),
1249
+ /* @__PURE__ */ jsx(Text, { children: " " }),
1250
+ lines.map((line, i) => /* @__PURE__ */ jsxs(Text, { color: "green", children: [
1251
+ " ",
1252
+ "\u2713",
1253
+ " ",
1254
+ line
1255
+ ] }, i))
1256
+ ] });
1257
+ }
1214
1258
  function MessageItem({ message }) {
1259
+ if (message.role === "tool") {
1260
+ return /* @__PURE__ */ jsx(ToolMessage, { message });
1261
+ }
1215
1262
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
1216
1263
  /* @__PURE__ */ jsxs(Box, { children: [
1217
1264
  /* @__PURE__ */ jsx(RoleLabel, { role: message.role }),
@@ -1703,6 +1750,12 @@ function PermissionPrompt({ request }) {
1703
1750
  // src/ui/StreamingIndicator.tsx
1704
1751
  import { Box as Box7, Text as Text9 } from "ink";
1705
1752
  import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
1753
+ function getToolStyle(t) {
1754
+ if (t.isRunning) return { color: "yellow", icon: "\u27F3", strikethrough: false };
1755
+ if (t.result === "error") return { color: "red", icon: "\u2717", strikethrough: true };
1756
+ if (t.result === "denied") return { color: "yellowBright", icon: "\u2298", strikethrough: true };
1757
+ return { color: "green", icon: "\u2713", strikethrough: false };
1758
+ }
1706
1759
  function StreamingIndicator({ text, activeTools }) {
1707
1760
  const hasTools = activeTools.length > 0;
1708
1761
  const hasText = text.length > 0;
@@ -1711,17 +1764,20 @@ function StreamingIndicator({ text, activeTools }) {
1711
1764
  }
1712
1765
  return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
1713
1766
  hasTools && /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", marginBottom: 1, children: [
1714
- /* @__PURE__ */ jsx9(Text9, { color: "gray", bold: true, children: "Tools:" }),
1767
+ /* @__PURE__ */ jsx9(Text9, { color: "white", bold: true, children: "Tools:" }),
1715
1768
  /* @__PURE__ */ jsx9(Text9, { children: " " }),
1716
- activeTools.map((t, i) => /* @__PURE__ */ jsxs7(Text9, { color: t.isRunning ? "yellow" : "green", children: [
1717
- " ",
1718
- t.isRunning ? "\u27F3" : "\u2713",
1719
- " ",
1720
- t.toolName,
1721
- "(",
1722
- t.firstArg,
1723
- ")"
1724
- ] }, `${t.toolName}-${i}`))
1769
+ activeTools.map((t, i) => {
1770
+ const { color, icon, strikethrough } = getToolStyle(t);
1771
+ return /* @__PURE__ */ jsxs7(Text9, { color, strikethrough, children: [
1772
+ " ",
1773
+ icon,
1774
+ " ",
1775
+ t.toolName,
1776
+ "(",
1777
+ t.firstArg,
1778
+ ")"
1779
+ ] }, `${t.toolName}-${i}`);
1780
+ })
1725
1781
  ] }),
1726
1782
  hasText && /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", marginBottom: 1, children: [
1727
1783
  /* @__PURE__ */ jsx9(Text9, { color: "cyan", bold: true, children: "Robota:" }),
@@ -190,7 +190,7 @@ var import_agent_core3 = require("@robota-sdk/agent-core");
190
190
  var import_react = require("react");
191
191
  var import_agent_sdk = require("@robota-sdk/agent-sdk");
192
192
  var TOOL_ARG_DISPLAY_MAX = 80;
193
- var TOOL_ARG_TRUNCATE_AT = 77;
193
+ var TAIL_KEEP = 30;
194
194
  var NOOP_TERMINAL = {
195
195
  write: () => {
196
196
  },
@@ -249,13 +249,17 @@ function useSession(props) {
249
249
  if (event.toolArgs) {
250
250
  const firstVal = Object.values(event.toolArgs)[0];
251
251
  const raw = typeof firstVal === "string" ? firstVal : JSON.stringify(firstVal ?? "");
252
- firstArg = raw.length > TOOL_ARG_DISPLAY_MAX ? raw.slice(0, TOOL_ARG_TRUNCATE_AT) + "..." : raw;
252
+ firstArg = raw.length > TOOL_ARG_DISPLAY_MAX ? raw.slice(0, TOOL_ARG_DISPLAY_MAX - TAIL_KEEP - 3) + "..." + raw.slice(-TAIL_KEEP) : raw;
253
253
  }
254
- setActiveTools((prev) => [...prev, { toolName: event.toolName, firstArg, isRunning: true }]);
254
+ setActiveTools((prev) => [
255
+ ...prev,
256
+ { toolName: event.toolName, firstArg, isRunning: true }
257
+ ]);
255
258
  } else {
259
+ const result = event.denied ? "denied" : event.success === false ? "error" : "success";
256
260
  setActiveTools(
257
261
  (prev) => prev.map(
258
- (t) => t.toolName === event.toolName && t.isRunning ? { ...t, isRunning: false } : t
262
+ (t) => t.toolName === event.toolName && t.isRunning ? { ...t, isRunning: false, result } : t
259
263
  )
260
264
  );
261
265
  }
@@ -279,7 +283,13 @@ function useSession(props) {
279
283
  setStreamingText("");
280
284
  setActiveTools([]);
281
285
  }, []);
282
- return { session: sessionRef.current, permissionRequest, streamingText, clearStreamingText, activeTools };
286
+ return {
287
+ session: sessionRef.current,
288
+ permissionRequest,
289
+ streamingText,
290
+ clearStreamingText,
291
+ activeTools
292
+ };
283
293
  }
284
294
 
285
295
  // src/ui/hooks/useMessages.ts
@@ -610,7 +620,7 @@ var import_react4 = require("react");
610
620
 
611
621
  // src/utils/tool-call-extractor.ts
612
622
  var TOOL_ARG_MAX_LENGTH = 80;
613
- var TOOL_ARG_TRUNCATE_LENGTH = 77;
623
+ var TAIL_KEEP2 = 30;
614
624
  function extractToolCalls(history, startIndex) {
615
625
  const lines = [];
616
626
  for (let i = startIndex; i < history.length; i++) {
@@ -618,7 +628,7 @@ function extractToolCalls(history, startIndex) {
618
628
  if (msg.role === "assistant" && msg.toolCalls) {
619
629
  for (const tc of msg.toolCalls) {
620
630
  const value = parseFirstArgValue(tc.function.arguments);
621
- const truncated = value.length > TOOL_ARG_MAX_LENGTH ? value.slice(0, TOOL_ARG_TRUNCATE_LENGTH) + "..." : value;
631
+ const truncated = value.length > TOOL_ARG_MAX_LENGTH ? value.slice(0, TOOL_ARG_MAX_LENGTH - TAIL_KEEP2 - 3) + "..." + value.slice(-TAIL_KEEP2) : value;
622
632
  lines.push(`${tc.function.name}(${truncated})`);
623
633
  }
624
634
  }
@@ -746,6 +756,9 @@ function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamin
746
756
  }
747
757
  const prompt = await buildSkillPrompt(input, registry);
748
758
  if (!prompt) return;
759
+ const cmdName = input.slice(1).split(/\s+/)[0]?.toLowerCase() ?? "";
760
+ const qualifiedName = registry.resolveQualifiedName(cmdName);
761
+ const hookInput = qualifiedName ? `/${qualifiedName}${input.slice(1 + cmdName.length)}` : input;
749
762
  return runSessionPrompt(
750
763
  prompt,
751
764
  session,
@@ -753,7 +766,7 @@ function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamin
753
766
  clearStreamingText,
754
767
  setIsThinking,
755
768
  setContextState,
756
- input
769
+ hookInput
757
770
  );
758
771
  }
759
772
  addMessage({ role: "user", content: input });
@@ -800,6 +813,14 @@ var CommandRegistry = class {
800
813
  const lower = filter.toLowerCase();
801
814
  return all.filter((cmd) => cmd.name.toLowerCase().startsWith(lower));
802
815
  }
816
+ /** Resolve a short name to its fully qualified plugin:name form */
817
+ resolveQualifiedName(shortName) {
818
+ const matches = this.getCommands().filter(
819
+ (c) => c.source === "plugin" && c.name.includes(":") && c.name.endsWith(`:${shortName}`)
820
+ );
821
+ if (matches.length !== 1) return null;
822
+ return matches[0].name;
823
+ }
803
824
  /** Get subcommands for a specific command */
804
825
  getSubcommands(commandName) {
805
826
  const lower = commandName.toLowerCase();
@@ -1033,7 +1054,7 @@ var PluginCommandSource = class {
1033
1054
  const baseName = skill.name.includes("@") ? skill.name.split("@")[0] : skill.name;
1034
1055
  commands.push({
1035
1056
  name: baseName,
1036
- description: `${skill.description} (${plugin.manifest.name})`,
1057
+ description: `(${plugin.manifest.name}) ${skill.description}`,
1037
1058
  source: "plugin",
1038
1059
  skillContent: skill.skillContent,
1039
1060
  pluginDir: plugin.pluginDir
@@ -1233,13 +1254,39 @@ function RoleLabel({ role }) {
1233
1254
  " "
1234
1255
  ] });
1235
1256
  case "tool":
1236
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "magenta", bold: true, children: [
1257
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "white", bold: true, children: [
1237
1258
  "Tool:",
1238
1259
  " "
1239
1260
  ] });
1240
1261
  }
1241
1262
  }
1263
+ function ToolMessage({ message }) {
1264
+ const lines = message.content.split("\n").filter((l) => l.trim());
1265
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Box, { flexDirection: "column", marginBottom: 1, children: [
1266
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Box, { children: [
1267
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "white", bold: true, children: [
1268
+ "Tool:",
1269
+ " "
1270
+ ] }),
1271
+ message.toolName && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "white", dimColor: true, children: [
1272
+ "[",
1273
+ message.toolName,
1274
+ "]"
1275
+ ] })
1276
+ ] }),
1277
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { children: " " }),
1278
+ lines.map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "green", children: [
1279
+ " ",
1280
+ "\u2713",
1281
+ " ",
1282
+ line
1283
+ ] }, i))
1284
+ ] });
1285
+ }
1242
1286
  function MessageItem({ message }) {
1287
+ if (message.role === "tool") {
1288
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToolMessage, { message });
1289
+ }
1243
1290
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Box, { flexDirection: "column", marginBottom: 1, children: [
1244
1291
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Box, { children: [
1245
1292
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RoleLabel, { role: message.role }),
@@ -1731,6 +1778,12 @@ function PermissionPrompt({ request }) {
1731
1778
  // src/ui/StreamingIndicator.tsx
1732
1779
  var import_ink9 = require("ink");
1733
1780
  var import_jsx_runtime9 = require("react/jsx-runtime");
1781
+ function getToolStyle(t) {
1782
+ if (t.isRunning) return { color: "yellow", icon: "\u27F3", strikethrough: false };
1783
+ if (t.result === "error") return { color: "red", icon: "\u2717", strikethrough: true };
1784
+ if (t.result === "denied") return { color: "yellowBright", icon: "\u2298", strikethrough: true };
1785
+ return { color: "green", icon: "\u2713", strikethrough: false };
1786
+ }
1734
1787
  function StreamingIndicator({ text, activeTools }) {
1735
1788
  const hasTools = activeTools.length > 0;
1736
1789
  const hasText = text.length > 0;
@@ -1739,17 +1792,20 @@ function StreamingIndicator({ text, activeTools }) {
1739
1792
  }
1740
1793
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Box, { flexDirection: "column", children: [
1741
1794
  hasTools && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Box, { flexDirection: "column", marginBottom: 1, children: [
1742
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { color: "gray", bold: true, children: "Tools:" }),
1795
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { color: "white", bold: true, children: "Tools:" }),
1743
1796
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { children: " " }),
1744
- activeTools.map((t, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Text, { color: t.isRunning ? "yellow" : "green", children: [
1745
- " ",
1746
- t.isRunning ? "\u27F3" : "\u2713",
1747
- " ",
1748
- t.toolName,
1749
- "(",
1750
- t.firstArg,
1751
- ")"
1752
- ] }, `${t.toolName}-${i}`))
1797
+ activeTools.map((t, i) => {
1798
+ const { color, icon, strikethrough } = getToolStyle(t);
1799
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Text, { color, strikethrough, children: [
1800
+ " ",
1801
+ icon,
1802
+ " ",
1803
+ t.toolName,
1804
+ "(",
1805
+ t.firstArg,
1806
+ ")"
1807
+ ] }, `${t.toolName}-${i}`);
1808
+ })
1753
1809
  ] }),
1754
1810
  hasText && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Box, { flexDirection: "column", marginBottom: 1, children: [
1755
1811
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { color: "cyan", bold: true, children: "Robota:" }),
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  startCli
3
- } from "./chunk-GJ3LG37H.js";
3
+ } from "./chunk-QTZS5QXJ.js";
4
4
 
5
5
  // src/index.ts
6
6
  import { Session, SessionStore, query, TRUST_TO_MODE } from "@robota-sdk/agent-sdk";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robota-sdk/agent-cli",
3
- "version": "3.0.0-beta.25",
3
+ "version": "3.0.0-beta.26",
4
4
  "description": "AI coding assistant CLI built on Robota SDK",
5
5
  "type": "module",
6
6
  "bin": {
@@ -35,8 +35,8 @@
35
35
  "marked-terminal": "^7.3.0",
36
36
  "react": "19.2.4",
37
37
  "string-width": "^8.2.0",
38
- "@robota-sdk/agent-core": "3.0.0-beta.25",
39
- "@robota-sdk/agent-sdk": "3.0.0-beta.25"
38
+ "@robota-sdk/agent-core": "3.0.0-beta.26",
39
+ "@robota-sdk/agent-sdk": "3.0.0-beta.26"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@types/marked": "^6.0.0",