agent-sh 0.5.0 → 0.6.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.
Files changed (37) hide show
  1. package/README.md +12 -43
  2. package/dist/agent/agent-loop.d.ts +1 -0
  3. package/dist/agent/agent-loop.js +119 -26
  4. package/dist/agent/subagent.js +3 -1
  5. package/dist/agent/system-prompt.d.ts +1 -1
  6. package/dist/agent/system-prompt.js +21 -16
  7. package/dist/agent/tools/bash.js +10 -1
  8. package/dist/agent/tools/display.d.ts +13 -0
  9. package/dist/agent/tools/display.js +70 -0
  10. package/dist/agent/tools/edit-file.js +60 -7
  11. package/dist/agent/tools/glob.js +39 -7
  12. package/dist/agent/tools/grep.js +111 -20
  13. package/dist/agent/tools/ls.js +31 -2
  14. package/dist/agent/tools/read-file.d.ts +9 -1
  15. package/dist/agent/tools/read-file.js +50 -4
  16. package/dist/agent/tools/user-shell.js +40 -13
  17. package/dist/agent/tools/write-file.js +9 -1
  18. package/dist/agent/types.d.ts +35 -1
  19. package/dist/core.d.ts +1 -3
  20. package/dist/core.js +7 -11
  21. package/dist/event-bus.d.ts +18 -3
  22. package/dist/extension-loader.d.ts +1 -1
  23. package/dist/extension-loader.js +1 -3
  24. package/dist/extensions/tui-renderer.js +341 -83
  25. package/dist/index.js +41 -36
  26. package/dist/input-handler.js +4 -2
  27. package/dist/settings.js +1 -1
  28. package/dist/shell.js +2 -2
  29. package/dist/utils/diff.js +10 -0
  30. package/dist/utils/markdown.d.ts +1 -0
  31. package/dist/utils/markdown.js +23 -1
  32. package/dist/utils/tool-display.d.ts +4 -0
  33. package/dist/utils/tool-display.js +22 -5
  34. package/examples/extensions/claude-code-bridge/index.ts +8 -12
  35. package/examples/extensions/pi-bridge/index.ts +10 -12
  36. package/examples/extensions/secret-guard.ts +100 -0
  37. package/package.json +1 -1
@@ -21,15 +21,36 @@ export interface ToolResult {
21
21
  exitCode: number | null;
22
22
  isError: boolean;
23
23
  }
24
+ /** Structured result display — returned by formatResult or computed by defaults. */
25
+ export interface ToolResultDisplay {
26
+ /** One-line summary shown next to ✓/✗ (e.g. "42 papers found", "+3/-1"). */
27
+ summary?: string;
28
+ /** Structured content to render below the status line. */
29
+ body?: ToolResultBody;
30
+ }
31
+ export type ToolResultBody = {
32
+ kind: "diff";
33
+ diff: unknown;
34
+ filePath: string;
35
+ } | {
36
+ kind: "lines";
37
+ lines: string[];
38
+ maxLines?: number;
39
+ };
24
40
  export interface ToolDisplayInfo {
25
- kind: "read" | "write" | "execute" | "search";
41
+ kind: "read" | "write" | "execute" | "search" | "display";
26
42
  locations?: {
27
43
  path: string;
28
44
  line?: number | null;
29
45
  }[];
46
+ /** Custom icon character for TUI display (e.g., "◆", "⌕"). When set, the TUI shows
47
+ * icon + detail only. When absent, the tool name is shown alongside the detail. */
48
+ icon?: string;
30
49
  }
31
50
  export interface ToolDefinition {
32
51
  name: string;
52
+ /** Short label for TUI display (e.g. "search" instead of "ads_search"). Defaults to name. */
53
+ displayName?: string;
33
54
  description: string;
34
55
  input_schema: Record<string, unknown>;
35
56
  execute(args: Record<string, unknown>, onChunk?: (chunk: string) => void): Promise<ToolResult>;
@@ -41,4 +62,17 @@ export interface ToolDefinition {
41
62
  requiresPermission?: boolean;
42
63
  /** Derive display metadata (icon kind, file paths) for the TUI. */
43
64
  getDisplayInfo?: (args: Record<string, unknown>) => ToolDisplayInfo;
65
+ /**
66
+ * Format a short display string for the TUI when this tool is called.
67
+ * Return a concise summary of the args (e.g. the query, the file path).
68
+ * When absent, the TUI derives the detail from common arg fields (command, path, pattern).
69
+ */
70
+ formatCall?: (args: Record<string, unknown>) => string;
71
+ /**
72
+ * Format result display for the TUI after execution completes.
73
+ * Return a summary string and/or structured body to render.
74
+ * When absent, defaults are computed based on tool kind.
75
+ * Extensions can further override via bus.onPipe("agent:tool-completed", ...).
76
+ */
77
+ formatResult?: (args: Record<string, unknown>, result: ToolResult) => ToolResultDisplay;
44
78
  }
package/dist/core.d.ts CHANGED
@@ -36,9 +36,7 @@ export interface AgentShellCore {
36
36
  /** Activate the agent backend (call after extensions load). */
37
37
  activateBackend(): void;
38
38
  /** Convenience: emit agent:submit and await the response. */
39
- query(text: string, opts?: {
40
- mode?: string;
41
- }): Promise<string>;
39
+ query(text: string): Promise<string>;
42
40
  /** Convenience: emit agent:cancel-request. */
43
41
  cancel(): void;
44
42
  /** Build an ExtensionContext for loading extensions against this core. */
package/dist/core.js CHANGED
@@ -221,12 +221,14 @@ export function createCore(config) {
221
221
  contextManager,
222
222
  llmClient,
223
223
  activateBackend() {
224
+ // Silent — backend info is shown in the startup banner.
225
+ // Runtime switches (config:switch-backend) still emit ui:info.
224
226
  const preferred = settings.defaultBackend;
225
227
  if (preferred && backends.has(preferred)) {
226
- activateByName(preferred);
228
+ activateByName(preferred, true);
227
229
  }
228
230
  else if (backends.size > 0 && !agentLoop) {
229
- activateByName(backends.keys().next().value);
231
+ activateByName(backends.keys().next().value, true);
230
232
  }
231
233
  else if (agentLoop) {
232
234
  agentLoop.wire();
@@ -234,13 +236,10 @@ export function createCore(config) {
234
236
  bus.emit("agent:info", { name: "agent-sh", version: "0.4", model: llmClient?.model, provider: activeProvider?.id, contextWindow: activeProvider?.contextWindow });
235
237
  }
236
238
  else if (backends.size > 0) {
237
- activateByName(backends.keys().next().value);
238
- }
239
- if (activeBackendName) {
240
- bus.emit("ui:info", { message: `Backend: ${activeBackendName}` });
239
+ activateByName(backends.keys().next().value, true);
241
240
  }
242
241
  },
243
- async query(text, opts) {
242
+ async query(text) {
244
243
  return new Promise((resolve, reject) => {
245
244
  let response = "";
246
245
  let settled = false;
@@ -271,10 +270,7 @@ export function createCore(config) {
271
270
  bus.on("agent:response-chunk", onChunk);
272
271
  bus.on("agent:processing-done", onDone);
273
272
  bus.on("agent:error", onError);
274
- bus.emit("agent:submit", {
275
- query: text,
276
- modeInstruction: opts?.mode,
277
- });
273
+ bus.emit("agent:submit", { query: text });
278
274
  });
279
275
  },
280
276
  cancel() {
@@ -1,4 +1,5 @@
1
1
  import type { AgentMode } from "./types.js";
2
+ import type { ToolResultDisplay } from "./agent/types.js";
2
3
  /**
3
4
  * Typed event map — every event has a known payload shape.
4
5
  */
@@ -23,8 +24,6 @@ export interface ShellEvents {
23
24
  "shell:agent-exec-done": Record<string, never>;
24
25
  "agent:submit": {
25
26
  query: string;
26
- modeInstruction?: string;
27
- modeLabel?: string;
28
27
  };
29
28
  "agent:cancel-request": {
30
29
  silent?: boolean;
@@ -32,7 +31,6 @@ export interface ShellEvents {
32
31
  "input-mode:register": import("./types.js").InputModeConfig;
33
32
  "agent:query": {
34
33
  query: string;
35
- modeLabel?: string;
36
34
  };
37
35
  "agent:thinking-chunk": {
38
36
  text: string;
@@ -63,21 +61,37 @@ export interface ShellEvents {
63
61
  output: string;
64
62
  exitCode: number | null;
65
63
  };
64
+ "agent:tool-batch": {
65
+ groups: Array<{
66
+ kind: string;
67
+ tools: Array<{
68
+ name: string;
69
+ displayDetail?: string;
70
+ }>;
71
+ }>;
72
+ };
66
73
  "agent:tool-started": {
67
74
  title: string;
68
75
  toolCallId?: string;
69
76
  kind?: string;
77
+ icon?: string;
70
78
  locations?: {
71
79
  path: string;
72
80
  line?: number | null;
73
81
  }[];
74
82
  rawInput?: unknown;
83
+ /** Pre-formatted display detail from tool's formatCall(). */
84
+ displayDetail?: string;
85
+ batchIndex?: number;
86
+ batchTotal?: number;
75
87
  };
76
88
  "agent:tool-completed": {
77
89
  toolCallId?: string;
78
90
  exitCode: number | null;
79
91
  rawOutput?: unknown;
80
92
  kind?: string;
93
+ /** Structured result display — set by formatResult or defaults, overridable via onPipe. */
94
+ resultDisplay?: ToolResultDisplay;
81
95
  };
82
96
  "agent:tool-output-chunk": {
83
97
  chunk: string;
@@ -123,6 +137,7 @@ export interface ShellEvents {
123
137
  command: string;
124
138
  output: string;
125
139
  cwd: string;
140
+ exitCode: number | null;
126
141
  done: boolean;
127
142
  };
128
143
  "agent:info": {
@@ -13,4 +13,4 @@ import type { ExtensionContext } from "./types.js";
13
13
  * Each module should export a default or named `activate(ctx)` function.
14
14
  * Errors are non-fatal — logged via ui:error and skipped.
15
15
  */
16
- export declare function loadExtensions(ctx: ExtensionContext, cliExtensions?: string[]): Promise<void>;
16
+ export declare function loadExtensions(ctx: ExtensionContext, cliExtensions?: string[]): Promise<string[]>;
@@ -102,9 +102,7 @@ export async function loadExtensions(ctx, cliExtensions) {
102
102
  });
103
103
  }
104
104
  }
105
- if (loaded.length > 0) {
106
- ctx.bus.emit("ui:info", { message: `Extensions: ${loaded.join(", ")}` });
107
- }
105
+ return loaded;
108
106
  }
109
107
  /**
110
108
  * Find an index file in a directory extension.