@stigmer/ink 2.0.0 → 3.0.0

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.
@@ -13,9 +13,10 @@ export interface ApprovalPromptProps {
13
13
  * HITL approval prompt for tool call authorization.
14
14
  *
15
15
  * Displays the tool name and args preview, then presents
16
- * Approve/Reject/Skip options navigable via arrow keys or
17
- * shortcut keys (y/n/s). Press Enter to confirm the highlighted
18
- * selection.
16
+ * Approve/Approve-all/Reject/Skip options navigable via arrow keys
17
+ * or shortcut keys (y/a/n/s). Press Enter to confirm the highlighted
18
+ * selection. "Approve & don't ask again" (a) maps to APPROVE_ALL, which
19
+ * stops gating the rest of the run.
19
20
  */
20
21
  export declare function ApprovalPrompt({ pendingApproval, onSubmit, isSubmitting, }: ApprovalPromptProps): import("react/jsx-runtime").JSX.Element;
21
22
  //# sourceMappingURL=ApprovalPrompt.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ApprovalPrompt.d.ts","sourceRoot":"","sources":["../../src/components/ApprovalPrompt.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kEAAkE,CAAC;AACxG,OAAO,EAAE,cAAc,EAAE,MAAM,8DAA8D,CAAC;AAE9F,wCAAwC;AACxC,MAAM,WAAW,mBAAmB;IAClC,8CAA8C;IAC9C,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;IAC1C,8CAA8C;IAC9C,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,IAAI,CAAC;IACpD,gEAAgE;IAChE,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC;CACjC;AA8BD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,EAC7B,eAAe,EACf,QAAQ,EACR,YAAoB,GACrB,EAAE,mBAAmB,2CAmFrB"}
1
+ {"version":3,"file":"ApprovalPrompt.d.ts","sourceRoot":"","sources":["../../src/components/ApprovalPrompt.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kEAAkE,CAAC;AACxG,OAAO,EAAE,cAAc,EAAE,MAAM,8DAA8D,CAAC;AAE9F,wCAAwC;AACxC,MAAM,WAAW,mBAAmB;IAClC,8CAA8C;IAC9C,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;IAC1C,8CAA8C;IAC9C,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,IAAI,CAAC;IACpD,gEAAgE;IAChE,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC;CACjC;AAoCD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,EAC7B,eAAe,EACf,QAAQ,EACR,YAAoB,GACrB,EAAE,mBAAmB,2CAmFrB"}
@@ -9,6 +9,12 @@ const OPTIONS = [
9
9
  color: "green",
10
10
  shortcut: "y",
11
11
  },
12
+ {
13
+ label: "Approve & don't ask again",
14
+ action: ApprovalAction.APPROVE_ALL,
15
+ color: "green",
16
+ shortcut: "a",
17
+ },
12
18
  {
13
19
  label: "Reject",
14
20
  action: ApprovalAction.REJECT,
@@ -26,9 +32,10 @@ const OPTIONS = [
26
32
  * HITL approval prompt for tool call authorization.
27
33
  *
28
34
  * Displays the tool name and args preview, then presents
29
- * Approve/Reject/Skip options navigable via arrow keys or
30
- * shortcut keys (y/n/s). Press Enter to confirm the highlighted
31
- * selection.
35
+ * Approve/Approve-all/Reject/Skip options navigable via arrow keys
36
+ * or shortcut keys (y/a/n/s). Press Enter to confirm the highlighted
37
+ * selection. "Approve & don't ask again" (a) maps to APPROVE_ALL, which
38
+ * stops gating the rest of the run.
32
39
  */
33
40
  export function ApprovalPrompt({ pendingApproval, onSubmit, isSubmitting = false, }) {
34
41
  const [selectedIndex, setSelectedIndex] = useState(0);
@@ -1 +1 @@
1
- {"version":3,"file":"ApprovalPrompt.js","sourceRoot":"","sources":["../../src/components/ApprovalPrompt.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ApprovalPrompt.js","sourceRoot":"","sources":["../../src/components/ApprovalPrompt.tsx"],"names":[],"mappings":"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"}
@@ -7,8 +7,10 @@ export interface ToolCallItemProps {
7
7
  readonly expanded?: boolean;
8
8
  }
9
9
  /**
10
- * Renders a single tool call with a status indicator, name, and
11
- * optional expanded args/result preview.
10
+ * Renders a single tool call with a status indicator, label, and an optional
11
+ * expanded result. Labels and results come from the shared `@stigmer/sdk` view
12
+ * model, so a terminal session shows the same semantics (diffs, exit codes,
13
+ * match counts) as the web console.
12
14
  */
13
15
  export declare function ToolCallItem({ toolCall, expanded }: ToolCallItemProps): import("react/jsx-runtime").JSX.Element;
14
16
  //# sourceMappingURL=ToolCallItem.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ToolCallItem.d.ts","sourceRoot":"","sources":["../../src/components/ToolCallItem.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iEAAiE,CAAC;AAGhG,sCAAsC;AACtC,MAAM,WAAW,iBAAiB;IAChC,+BAA+B;IAC/B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,4DAA4D;IAC5D,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AAQD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,QAAgB,EAAE,EAAE,iBAAiB,2CA4C7E"}
1
+ {"version":3,"file":"ToolCallItem.d.ts","sourceRoot":"","sources":["../../src/components/ToolCallItem.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iEAAiE,CAAC;AAKhG,sCAAsC;AACtC,MAAM,WAAW,iBAAiB;IAChC,+BAA+B;IAC/B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,4DAA4D;IAC5D,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AA0BD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,QAAgB,EAAE,EAAE,iBAAiB,2CAoC7E"}
@@ -1,33 +1,84 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Box, Text } from "ink";
3
3
  import { ToolCallStatus } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
4
+ import { ToolKind, resolveToolKind, normalizeToolResult } from "@stigmer/sdk";
4
5
  const STATUS_INDICATOR = {
5
6
  [ToolCallStatus.TOOL_CALL_RUNNING]: { symbol: "⠋", color: "yellow" },
6
7
  [ToolCallStatus.TOOL_CALL_COMPLETED]: { symbol: "✓", color: "green" },
7
8
  [ToolCallStatus.TOOL_CALL_FAILED]: { symbol: "✗", color: "red" },
8
9
  };
10
+ // Harness-agnostic labels per kind. Classification is shared with the runner,
11
+ // React, and the Go CLI via @stigmer/sdk's resolveToolKind, so Cursor's
12
+ // PascalCase tools render with the same labels as native tools here.
13
+ const KIND_LABEL = {
14
+ [ToolKind.FILE_READ]: "Read",
15
+ [ToolKind.FILE_WRITE]: "Write",
16
+ [ToolKind.FILE_EDIT]: "Edit",
17
+ [ToolKind.FILE_DELETE]: "Delete",
18
+ [ToolKind.SHELL]: "Shell",
19
+ [ToolKind.SEARCH]: "Search",
20
+ [ToolKind.LIST]: "List",
21
+ [ToolKind.FETCH]: "Fetch",
22
+ [ToolKind.WEB_SEARCH]: "Web Search",
23
+ [ToolKind.THINK]: "Thinking",
24
+ [ToolKind.TODO]: "Todos",
25
+ [ToolKind.SUBAGENT]: "Sub-agent",
26
+ };
9
27
  /**
10
- * Renders a single tool call with a status indicator, name, and
11
- * optional expanded args/result preview.
28
+ * Renders a single tool call with a status indicator, label, and an optional
29
+ * expanded result. Labels and results come from the shared `@stigmer/sdk` view
30
+ * model, so a terminal session shows the same semantics (diffs, exit codes,
31
+ * match counts) as the web console.
12
32
  */
13
33
  export function ToolCallItem({ toolCall, expanded = false }) {
14
- const indicator = STATUS_INDICATOR[toolCall.status] ?? {
15
- symbol: "○",
16
- };
17
- const serverSlug = toolCall.mcpServerSlug;
18
- const label = serverSlug
19
- ? `${serverSlug}/${toolCall.name}`
20
- : toolCall.name;
21
- return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: indicator.color, children: indicator.symbol }), _jsx(Text, { children: label }), toolCall.status === ToolCallStatus.TOOL_CALL_RUNNING && (_jsx(Text, { dimColor: true, children: "running" }))] }), expanded && toolCall.argsPreview && (_jsx(Box, { paddingLeft: 3, children: _jsx(Text, { dimColor: true, wrap: "truncate-end", children: toolCall.argsPreview }) })), expanded &&
22
- toolCall.status === ToolCallStatus.TOOL_CALL_COMPLETED &&
23
- toolCall.result && (_jsx(Box, { paddingLeft: 3, children: _jsx(Text, { dimColor: true, wrap: "truncate-end", children: truncateResult(toolCall.result) }) })), expanded &&
24
- toolCall.status === ToolCallStatus.TOOL_CALL_FAILED &&
25
- toolCall.error && (_jsx(Box, { paddingLeft: 3, children: _jsx(Text, { color: "red", children: toolCall.error }) }))] }));
34
+ const indicator = STATUS_INDICATOR[toolCall.status] ?? { symbol: "○" };
35
+ const kind = resolveToolKind(toolCall);
36
+ const label = toolLabel(toolCall, kind);
37
+ const view = normalizeToolResult(toolCall);
38
+ const resultText = expanded ? describeResultView(view) : null;
39
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: indicator.color, children: indicator.symbol }), _jsx(Text, { children: label }), toolCall.status === ToolCallStatus.TOOL_CALL_RUNNING && (_jsx(Text, { dimColor: true, children: "running" }))] }), view.type === "error" ? (expanded && (_jsx(Box, { paddingLeft: 3, children: _jsx(Text, { color: "red", wrap: "truncate-end", children: view.message }) }))) : (resultText && (_jsx(Box, { paddingLeft: 3, children: _jsx(Text, { dimColor: true, wrap: "truncate-end", children: resultText }) })))] }));
40
+ }
41
+ function toolLabel(toolCall, kind) {
42
+ if (toolCall.mcpServerSlug) {
43
+ return `${toolCall.mcpServerSlug}/${toolCall.name}`;
44
+ }
45
+ return KIND_LABEL[kind] ?? toolCall.name;
46
+ }
47
+ // Renders a concise, terminal-friendly description of a normalized result view.
48
+ function describeResultView(view) {
49
+ switch (view.type) {
50
+ case "diff": {
51
+ const stats = view.linesAdded !== undefined || view.linesRemoved !== undefined
52
+ ? ` (+${view.linesAdded ?? 0} -${view.linesRemoved ?? 0})`
53
+ : "";
54
+ return `${view.path}${stats}`;
55
+ }
56
+ case "terminal": {
57
+ const exit = view.exitCode !== undefined && view.exitCode !== 0 ? `[exit ${view.exitCode}] ` : "";
58
+ return exit + truncate(view.stdout || view.stderr);
59
+ }
60
+ case "search":
61
+ return `${view.count} ${view.count === 1 ? "match" : "matches"}`;
62
+ case "list":
63
+ return `${view.count} ${view.count === 1 ? "item" : "items"}`;
64
+ case "file":
65
+ return view.path || null;
66
+ case "contentBlocks":
67
+ return truncate(view.blocks.map((b) => b.text ?? `[${b.type}]`).join(" "));
68
+ case "text":
69
+ return truncate(view.text);
70
+ case "json":
71
+ return truncate(JSON.stringify(view.value));
72
+ case "error":
73
+ return view.message;
74
+ case "empty":
75
+ return null;
76
+ }
26
77
  }
27
- function truncateResult(result, maxLines = 5) {
28
- const lines = result.split("\n");
78
+ function truncate(s, maxLines = 5) {
79
+ const lines = s.split("\n");
29
80
  if (lines.length <= maxLines)
30
- return result;
81
+ return s;
31
82
  return lines.slice(0, maxLines).join("\n") + `\n... (${lines.length - maxLines} more lines)`;
32
83
  }
33
84
  //# sourceMappingURL=ToolCallItem.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ToolCallItem.js","sourceRoot":"","sources":["../../src/components/ToolCallItem.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAEhC,OAAO,EAAE,cAAc,EAAE,MAAM,8DAA8D,CAAC;AAU9F,MAAM,gBAAgB,GAAuD;IAC3E,CAAC,cAAc,CAAC,iBAAiB,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE;IACpE,CAAC,cAAc,CAAC,mBAAmB,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE;IACrE,CAAC,cAAc,CAAC,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE;CACjE,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,EAAE,QAAQ,EAAE,QAAQ,GAAG,KAAK,EAAqB;IAC5E,MAAM,SAAS,GAAG,gBAAgB,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI;QACrD,MAAM,EAAE,GAAG;KACZ,CAAC;IAEF,MAAM,UAAU,GAAG,QAAQ,CAAC,aAAa,CAAC;IAC1C,MAAM,KAAK,GAAG,UAAU;QACtB,CAAC,CAAC,GAAG,UAAU,IAAI,QAAQ,CAAC,IAAI,EAAE;QAClC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;IAElB,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,aACzB,MAAC,GAAG,IAAC,GAAG,EAAE,CAAC,aACT,KAAC,IAAI,IAAC,KAAK,EAAE,SAAS,CAAC,KAAK,YAAG,SAAS,CAAC,MAAM,GAAQ,EACvD,KAAC,IAAI,cAAE,KAAK,GAAQ,EACnB,QAAQ,CAAC,MAAM,KAAK,cAAc,CAAC,iBAAiB,IAAI,CACvD,KAAC,IAAI,IAAC,QAAQ,8BAAe,CAC9B,IACG,EACL,QAAQ,IAAI,QAAQ,CAAC,WAAW,IAAI,CACnC,KAAC,GAAG,IAAC,WAAW,EAAE,CAAC,YACjB,KAAC,IAAI,IAAC,QAAQ,QAAC,IAAI,EAAC,cAAc,YAC/B,QAAQ,CAAC,WAAW,GAChB,GACH,CACP,EACA,QAAQ;gBACP,QAAQ,CAAC,MAAM,KAAK,cAAc,CAAC,mBAAmB;gBACtD,QAAQ,CAAC,MAAM,IAAI,CACjB,KAAC,GAAG,IAAC,WAAW,EAAE,CAAC,YACjB,KAAC,IAAI,IAAC,QAAQ,QAAC,IAAI,EAAC,cAAc,YAC/B,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,GAC3B,GACH,CACP,EACF,QAAQ;gBACP,QAAQ,CAAC,MAAM,KAAK,cAAc,CAAC,gBAAgB;gBACnD,QAAQ,CAAC,KAAK,IAAI,CAChB,KAAC,GAAG,IAAC,WAAW,EAAE,CAAC,YACjB,KAAC,IAAI,IAAC,KAAK,EAAC,KAAK,YAAE,QAAQ,CAAC,KAAK,GAAQ,GACrC,CACP,IACC,CACP,CAAC;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,MAAc,EAAE,QAAQ,GAAG,CAAC;IAClD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACjC,IAAI,KAAK,CAAC,MAAM,IAAI,QAAQ;QAAE,OAAO,MAAM,CAAC;IAC5C,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,UAAU,KAAK,CAAC,MAAM,GAAG,QAAQ,cAAc,CAAC;AAC/F,CAAC"}
1
+ {"version":3,"file":"ToolCallItem.js","sourceRoot":"","sources":["../../src/components/ToolCallItem.tsx"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stigmer/ink",
3
- "version": "2.0.0",
3
+ "version": "3.0.0",
4
4
  "description": "Ink (React for terminals) components for rendering Stigmer agent sessions in the terminal",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -32,7 +32,7 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "@connectrpc/connect-node": "^2.1.1",
35
- "@stigmer/react": "2.0.0",
35
+ "@stigmer/react": "3.0.0",
36
36
  "ink-spinner": "^5.0.0",
37
37
  "ink-text-input": "^6.0.0",
38
38
  "marked": "^15.0.7",
@@ -40,8 +40,8 @@
40
40
  },
41
41
  "peerDependencies": {
42
42
  "@bufbuild/protobuf": "^2.0.0",
43
- "@stigmer/protos": "2.0.0",
44
- "@stigmer/sdk": "2.0.0",
43
+ "@stigmer/protos": "3.0.0",
44
+ "@stigmer/sdk": "3.0.0",
45
45
  "ink": "^7.0.0",
46
46
  "react": ">=19.0.0"
47
47
  }
@@ -1,14 +1,16 @@
1
1
  import React from "react";
2
- import { describe, it, expect } from "vitest";
2
+ import { describe, it, expect, vi } from "vitest";
3
3
  import { render } from "ink-testing-library";
4
4
  import { Text, Box } from "ink";
5
5
  import { create } from "@bufbuild/protobuf";
6
6
  import { AgentMessageSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";
7
- import { MessageType, ExecutionPhase, ToolCallStatus } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
7
+ import { MessageType, ExecutionPhase, ToolCallStatus, ApprovalAction } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
8
8
  import { ToolCallSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";
9
+ import { PendingApprovalSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/approval_pb";
9
10
  import { MessageEntry } from "../components/MessageEntry.js";
10
11
  import { ExecutionProgress } from "../components/ExecutionProgress.js";
11
12
  import { ToolCallItem } from "../components/ToolCallItem.js";
13
+ import { ApprovalPrompt } from "../components/ApprovalPrompt.js";
12
14
 
13
15
  describe("MessageEntry", () => {
14
16
  it("renders a human message with 'You' prefix", () => {
@@ -120,7 +122,7 @@ describe("ToolCallItem", () => {
120
122
 
121
123
  const { lastFrame } = render(<ToolCallItem toolCall={tc} />);
122
124
  const output = lastFrame() ?? "";
123
- expect(output).toContain("read_file");
125
+ expect(output).toContain("Read");
124
126
  expect(output).toContain("✓");
125
127
  });
126
128
 
@@ -132,7 +134,7 @@ describe("ToolCallItem", () => {
132
134
 
133
135
  const { lastFrame } = render(<ToolCallItem toolCall={tc} />);
134
136
  const output = lastFrame() ?? "";
135
- expect(output).toContain("write_file");
137
+ expect(output).toContain("Write");
136
138
  expect(output).toContain("running");
137
139
  });
138
140
 
@@ -160,3 +162,48 @@ describe("ToolCallItem", () => {
160
162
  expect(output).toContain("github/list_resources");
161
163
  });
162
164
  });
165
+
166
+ describe("ApprovalPrompt", () => {
167
+ it("offers Approve, Approve & don't ask again, Reject, and Skip", () => {
168
+ const pending = create(PendingApprovalSchema);
169
+ pending.toolCallId = "tc-1";
170
+ pending.toolName = "write_file";
171
+
172
+ const { lastFrame } = render(
173
+ <ApprovalPrompt pendingApproval={pending} onSubmit={() => {}} />,
174
+ );
175
+ const output = lastFrame() ?? "";
176
+ expect(output).toContain("[y] Approve");
177
+ expect(output).toContain("[a] Approve & don't ask again");
178
+ expect(output).toContain("[n] Reject");
179
+ expect(output).toContain("[s] Skip");
180
+ });
181
+
182
+ it("submits APPROVE_ALL when the 'a' shortcut is pressed", () => {
183
+ const pending = create(PendingApprovalSchema);
184
+ pending.toolCallId = "tc-1";
185
+ pending.toolName = "write_file";
186
+ const onSubmit = vi.fn();
187
+
188
+ const { stdin } = render(
189
+ <ApprovalPrompt pendingApproval={pending} onSubmit={onSubmit} />,
190
+ );
191
+ stdin.write("a");
192
+
193
+ expect(onSubmit).toHaveBeenCalledWith(ApprovalAction.APPROVE_ALL);
194
+ });
195
+
196
+ it("submits APPROVE when the 'y' shortcut is pressed", () => {
197
+ const pending = create(PendingApprovalSchema);
198
+ pending.toolCallId = "tc-1";
199
+ pending.toolName = "write_file";
200
+ const onSubmit = vi.fn();
201
+
202
+ const { stdin } = render(
203
+ <ApprovalPrompt pendingApproval={pending} onSubmit={onSubmit} />,
204
+ );
205
+ stdin.write("y");
206
+
207
+ expect(onSubmit).toHaveBeenCalledWith(ApprovalAction.APPROVE);
208
+ });
209
+ });
@@ -27,6 +27,12 @@ const OPTIONS: readonly ActionOption[] = [
27
27
  color: "green",
28
28
  shortcut: "y",
29
29
  },
30
+ {
31
+ label: "Approve & don't ask again",
32
+ action: ApprovalAction.APPROVE_ALL,
33
+ color: "green",
34
+ shortcut: "a",
35
+ },
30
36
  {
31
37
  label: "Reject",
32
38
  action: ApprovalAction.REJECT,
@@ -45,9 +51,10 @@ const OPTIONS: readonly ActionOption[] = [
45
51
  * HITL approval prompt for tool call authorization.
46
52
  *
47
53
  * Displays the tool name and args preview, then presents
48
- * Approve/Reject/Skip options navigable via arrow keys or
49
- * shortcut keys (y/n/s). Press Enter to confirm the highlighted
50
- * selection.
54
+ * Approve/Approve-all/Reject/Skip options navigable via arrow keys
55
+ * or shortcut keys (y/a/n/s). Press Enter to confirm the highlighted
56
+ * selection. "Approve & don't ask again" (a) maps to APPROVE_ALL, which
57
+ * stops gating the rest of the run.
51
58
  */
52
59
  export function ApprovalPrompt({
53
60
  pendingApproval,
@@ -2,6 +2,8 @@ import React from "react";
2
2
  import { Box, Text } from "ink";
3
3
  import type { ToolCall } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";
4
4
  import { ToolCallStatus } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
5
+ import { ToolKind, resolveToolKind, normalizeToolResult } from "@stigmer/sdk";
6
+ import type { ToolResultView } from "@stigmer/sdk";
5
7
 
6
8
  /** Props for {@link ToolCallItem}. */
7
9
  export interface ToolCallItemProps {
@@ -17,19 +19,37 @@ const STATUS_INDICATOR: Record<number, { symbol: string; color?: string }> = {
17
19
  [ToolCallStatus.TOOL_CALL_FAILED]: { symbol: "✗", color: "red" },
18
20
  };
19
21
 
22
+ // Harness-agnostic labels per kind. Classification is shared with the runner,
23
+ // React, and the Go CLI via @stigmer/sdk's resolveToolKind, so Cursor's
24
+ // PascalCase tools render with the same labels as native tools here.
25
+ const KIND_LABEL: Partial<Record<ToolKind, string>> = {
26
+ [ToolKind.FILE_READ]: "Read",
27
+ [ToolKind.FILE_WRITE]: "Write",
28
+ [ToolKind.FILE_EDIT]: "Edit",
29
+ [ToolKind.FILE_DELETE]: "Delete",
30
+ [ToolKind.SHELL]: "Shell",
31
+ [ToolKind.SEARCH]: "Search",
32
+ [ToolKind.LIST]: "List",
33
+ [ToolKind.FETCH]: "Fetch",
34
+ [ToolKind.WEB_SEARCH]: "Web Search",
35
+ [ToolKind.THINK]: "Thinking",
36
+ [ToolKind.TODO]: "Todos",
37
+ [ToolKind.SUBAGENT]: "Sub-agent",
38
+ };
39
+
20
40
  /**
21
- * Renders a single tool call with a status indicator, name, and
22
- * optional expanded args/result preview.
41
+ * Renders a single tool call with a status indicator, label, and an optional
42
+ * expanded result. Labels and results come from the shared `@stigmer/sdk` view
43
+ * model, so a terminal session shows the same semantics (diffs, exit codes,
44
+ * match counts) as the web console.
23
45
  */
24
46
  export function ToolCallItem({ toolCall, expanded = false }: ToolCallItemProps) {
25
- const indicator = STATUS_INDICATOR[toolCall.status] ?? {
26
- symbol: "○",
27
- };
47
+ const indicator = STATUS_INDICATOR[toolCall.status] ?? { symbol: "○" };
28
48
 
29
- const serverSlug = toolCall.mcpServerSlug;
30
- const label = serverSlug
31
- ? `${serverSlug}/${toolCall.name}`
32
- : toolCall.name;
49
+ const kind = resolveToolKind(toolCall);
50
+ const label = toolLabel(toolCall, kind);
51
+ const view = normalizeToolResult(toolCall);
52
+ const resultText = expanded ? describeResultView(view) : null;
33
53
 
34
54
  return (
35
55
  <Box flexDirection="column">
@@ -40,35 +60,70 @@ export function ToolCallItem({ toolCall, expanded = false }: ToolCallItemProps)
40
60
  <Text dimColor>running</Text>
41
61
  )}
42
62
  </Box>
43
- {expanded && toolCall.argsPreview && (
44
- <Box paddingLeft={3}>
45
- <Text dimColor wrap="truncate-end">
46
- {toolCall.argsPreview}
47
- </Text>
48
- </Box>
49
- )}
50
- {expanded &&
51
- toolCall.status === ToolCallStatus.TOOL_CALL_COMPLETED &&
52
- toolCall.result && (
63
+ {view.type === "error" ? (
64
+ expanded && (
53
65
  <Box paddingLeft={3}>
54
- <Text dimColor wrap="truncate-end">
55
- {truncateResult(toolCall.result)}
66
+ <Text color="red" wrap="truncate-end">
67
+ {view.message}
56
68
  </Text>
57
69
  </Box>
58
- )}
59
- {expanded &&
60
- toolCall.status === ToolCallStatus.TOOL_CALL_FAILED &&
61
- toolCall.error && (
70
+ )
71
+ ) : (
72
+ resultText && (
62
73
  <Box paddingLeft={3}>
63
- <Text color="red">{toolCall.error}</Text>
74
+ <Text dimColor wrap="truncate-end">
75
+ {resultText}
76
+ </Text>
64
77
  </Box>
65
- )}
78
+ )
79
+ )}
66
80
  </Box>
67
81
  );
68
82
  }
69
83
 
70
- function truncateResult(result: string, maxLines = 5): string {
71
- const lines = result.split("\n");
72
- if (lines.length <= maxLines) return result;
84
+ function toolLabel(toolCall: ToolCall, kind: ToolKind): string {
85
+ if (toolCall.mcpServerSlug) {
86
+ return `${toolCall.mcpServerSlug}/${toolCall.name}`;
87
+ }
88
+ return KIND_LABEL[kind] ?? toolCall.name;
89
+ }
90
+
91
+ // Renders a concise, terminal-friendly description of a normalized result view.
92
+ function describeResultView(view: ToolResultView): string | null {
93
+ switch (view.type) {
94
+ case "diff": {
95
+ const stats =
96
+ view.linesAdded !== undefined || view.linesRemoved !== undefined
97
+ ? ` (+${view.linesAdded ?? 0} -${view.linesRemoved ?? 0})`
98
+ : "";
99
+ return `${view.path}${stats}`;
100
+ }
101
+ case "terminal": {
102
+ const exit =
103
+ view.exitCode !== undefined && view.exitCode !== 0 ? `[exit ${view.exitCode}] ` : "";
104
+ return exit + truncate(view.stdout || view.stderr);
105
+ }
106
+ case "search":
107
+ return `${view.count} ${view.count === 1 ? "match" : "matches"}`;
108
+ case "list":
109
+ return `${view.count} ${view.count === 1 ? "item" : "items"}`;
110
+ case "file":
111
+ return view.path || null;
112
+ case "contentBlocks":
113
+ return truncate(view.blocks.map((b) => b.text ?? `[${b.type}]`).join(" "));
114
+ case "text":
115
+ return truncate(view.text);
116
+ case "json":
117
+ return truncate(JSON.stringify(view.value));
118
+ case "error":
119
+ return view.message;
120
+ case "empty":
121
+ return null;
122
+ }
123
+ }
124
+
125
+ function truncate(s: string, maxLines = 5): string {
126
+ const lines = s.split("\n");
127
+ if (lines.length <= maxLines) return s;
73
128
  return lines.slice(0, maxLines).join("\n") + `\n... (${lines.length - maxLines} more lines)`;
74
129
  }