@agentuity/coder-tui 3.0.0-alpha.6 → 3.0.0-beta.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.
- package/dist/agentuity-cli.d.ts +12 -0
- package/dist/agentuity-cli.d.ts.map +1 -0
- package/dist/agentuity-cli.js +178 -0
- package/dist/agentuity-cli.js.map +1 -0
- package/dist/aigateway.d.ts +4 -0
- package/dist/aigateway.d.ts.map +1 -0
- package/dist/aigateway.js +178 -0
- package/dist/aigateway.js.map +1 -0
- package/dist/footer.d.ts +3 -2
- package/dist/footer.d.ts.map +1 -1
- package/dist/footer.js +50 -16
- package/dist/footer.js.map +1 -1
- package/dist/hub-overlay-state.d.ts.map +1 -1
- package/dist/hub-overlay-state.js +3 -1
- package/dist/hub-overlay-state.js.map +1 -1
- package/dist/hub-overlay.d.ts.map +1 -1
- package/dist/hub-overlay.js +12 -3
- package/dist/hub-overlay.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +53 -30
- package/dist/index.js.map +1 -1
- package/dist/local-init-filter.d.ts +5 -0
- package/dist/local-init-filter.d.ts.map +1 -0
- package/dist/local-init-filter.js +40 -0
- package/dist/local-init-filter.js.map +1 -0
- package/dist/protocol.d.ts +2 -0
- package/dist/protocol.d.ts.map +1 -1
- package/dist/remote-session.d.ts.map +1 -1
- package/dist/remote-session.js +12 -6
- package/dist/remote-session.js.map +1 -1
- package/dist/renderers.d.ts.map +1 -1
- package/dist/renderers.js +53 -1
- package/dist/renderers.js.map +1 -1
- package/dist/startup-logo.d.ts +3 -0
- package/dist/startup-logo.d.ts.map +1 -0
- package/dist/startup-logo.js +212 -0
- package/dist/startup-logo.js.map +1 -0
- package/dist/subagent-tool-selection.d.ts +3 -0
- package/dist/subagent-tool-selection.d.ts.map +1 -0
- package/dist/subagent-tool-selection.js +22 -0
- package/dist/subagent-tool-selection.js.map +1 -0
- package/package.json +6 -6
- package/src/agentuity-cli.ts +225 -0
- package/src/aigateway.ts +256 -0
- package/src/footer.ts +62 -15
- package/src/hub-overlay-state.ts +4 -1
- package/src/hub-overlay.ts +14 -3
- package/src/index.ts +59 -32
- package/src/local-init-filter.ts +54 -0
- package/src/protocol.ts +2 -0
- package/src/remote-session.ts +12 -6
- package/src/renderers.ts +61 -1
- package/src/startup-logo.ts +255 -0
- package/src/subagent-tool-selection.ts +33 -0
package/src/hub-overlay-state.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { formatToolDisplay } from './agentuity-cli.ts';
|
|
2
|
+
|
|
1
3
|
export interface StreamBuffer {
|
|
2
4
|
output: string;
|
|
3
5
|
thinking: string;
|
|
@@ -78,7 +80,8 @@ export function buildProjectionFromEntries(
|
|
|
78
80
|
const type = typeof entry.type === 'string' ? entry.type : '';
|
|
79
81
|
if (type === 'tool_call') {
|
|
80
82
|
const toolName = typeof entry.toolName === 'string' ? entry.toolName : 'tool';
|
|
81
|
-
|
|
83
|
+
const display = formatToolDisplay(toolName, entry.toolArgs);
|
|
84
|
+
append('output', `[tool_call] ${display.fullLabel}\n\n`, entry.taskId);
|
|
82
85
|
continue;
|
|
83
86
|
}
|
|
84
87
|
|
package/src/hub-overlay.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
type StreamProjectionSource,
|
|
11
11
|
} from './hub-overlay-state.ts';
|
|
12
12
|
import { applyCoderAuthHeaders } from './auth.ts';
|
|
13
|
+
import { formatToolDisplay } from './agentuity-cli.ts';
|
|
13
14
|
import { truncateToWidth } from './renderers.ts';
|
|
14
15
|
import type {
|
|
15
16
|
ConversationEntry as HubConversationEntry,
|
|
@@ -2128,6 +2129,13 @@ export class HubOverlay implements Component, Focusable {
|
|
|
2128
2129
|
? data.toolName
|
|
2129
2130
|
: 'tool';
|
|
2130
2131
|
const input = data?.args ?? data?.input;
|
|
2132
|
+
const display = formatToolDisplay(
|
|
2133
|
+
name,
|
|
2134
|
+
typeof input === 'string' || (input && typeof input === 'object')
|
|
2135
|
+
? (input as string | Record<string, unknown>)
|
|
2136
|
+
: undefined
|
|
2137
|
+
);
|
|
2138
|
+
if (display.branded) return `tool_call ${display.fullLabel}`;
|
|
2131
2139
|
const summarized = summarizeToolCall(name, input);
|
|
2132
2140
|
if (summarized) return summarized;
|
|
2133
2141
|
const argsPreview = summarizeArgs(input, 90);
|
|
@@ -2171,15 +2179,18 @@ export class HubOverlay implements Component, Focusable {
|
|
|
2171
2179
|
const failed = data?.isError === true || details?.error === true;
|
|
2172
2180
|
return `${header}\n${failed ? 'failed' : `done${duration}`}`;
|
|
2173
2181
|
}
|
|
2174
|
-
|
|
2182
|
+
const display = formatToolDisplay(name, input);
|
|
2183
|
+
return `tool_result ${display.toolName}`;
|
|
2175
2184
|
}
|
|
2176
2185
|
|
|
2177
2186
|
if (eventName === 'agent_progress') {
|
|
2178
2187
|
const agent = typeof data?.agentName === 'string' ? data.agentName : 'agent';
|
|
2179
2188
|
const status = typeof data?.status === 'string' ? data.status : 'progress';
|
|
2180
|
-
const
|
|
2189
|
+
const rawToolName = typeof data?.currentTool === 'string' ? data.currentTool : '';
|
|
2181
2190
|
const toolArgsRaw = typeof data?.currentToolArgs === 'string' ? data.currentToolArgs : '';
|
|
2182
|
-
const
|
|
2191
|
+
const display = formatToolDisplay(rawToolName, toolArgsRaw || undefined);
|
|
2192
|
+
const toolName = display.toolName;
|
|
2193
|
+
const toolArgs = display.toolArgs ? truncateToWidth(normalize(display.toolArgs), 80) : '';
|
|
2183
2194
|
|
|
2184
2195
|
// Deltas are already represented in rendered stream mode; skip them in event mode
|
|
2185
2196
|
// to avoid noisy, low-signal token lines.
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
createBashToolDefinition,
|
|
2
3
|
AgentToolResult,
|
|
3
4
|
ExtensionAPI,
|
|
4
5
|
ExtensionContext,
|
|
@@ -13,6 +14,7 @@ import { processActions } from './handlers.ts';
|
|
|
13
14
|
import { getToolRenderers } from './renderers.ts';
|
|
14
15
|
import { setupCoderFooter, type ObserverState } from './footer.ts';
|
|
15
16
|
import { setupTitlebar } from './titlebar.ts';
|
|
17
|
+
import { setupStartupLogo } from './startup-logo.ts';
|
|
16
18
|
import { registerAgentCommands } from './commands.ts';
|
|
17
19
|
import { AgentManagerOverlay } from './overlay.ts';
|
|
18
20
|
import { ChainEditorOverlay, type ChainResult } from './chain-preview.ts';
|
|
@@ -22,6 +24,10 @@ import { setNativeRemoteExtensionContext } from './native-remote-ui-context.ts';
|
|
|
22
24
|
import { handleRemoteUiRequest } from './remote-ui-handler.ts';
|
|
23
25
|
import { buildInboundRpcPromptText, getInboundRpcDeliverAs } from './inbound-rpc.ts';
|
|
24
26
|
import { applyCoderAuthHeaders, getCoderAuthCurlArgs } from './auth.ts';
|
|
27
|
+
import { formatToolDisplay } from './agentuity-cli.ts';
|
|
28
|
+
import { setupAIGateway } from './aigateway.ts';
|
|
29
|
+
import { adaptInitMessageForLocalTui } from './local-init-filter.ts';
|
|
30
|
+
import { selectSubAgentToolNames } from './subagent-tool-selection.ts';
|
|
25
31
|
import type {
|
|
26
32
|
HubAction,
|
|
27
33
|
HubResponse,
|
|
@@ -275,6 +281,15 @@ async function fetchInitMessage(hubUrl: string, agentRole?: string): Promise<Ini
|
|
|
275
281
|
}
|
|
276
282
|
|
|
277
283
|
export function agentuityCoderHub(pi: ExtensionAPI) {
|
|
284
|
+
process.env.AGENTUITY_AGENT_MODE = 'coder'; // let the agentuity cli know we're inside coder
|
|
285
|
+
|
|
286
|
+
// Register the startup header before Hub bootstrap so `pi -e .` works for
|
|
287
|
+
// local visual testing without Agentuity Coder environment variables.
|
|
288
|
+
setupStartupLogo(pi);
|
|
289
|
+
|
|
290
|
+
// Register the AI Gateway
|
|
291
|
+
setupAIGateway(pi);
|
|
292
|
+
|
|
278
293
|
const hubUrl = process.env[HUB_URL_ENV];
|
|
279
294
|
if (!hubUrl) return;
|
|
280
295
|
|
|
@@ -283,6 +298,7 @@ export function agentuityCoderHub(pi: ExtensionAPI) {
|
|
|
283
298
|
// to an existing sandbox session. The full UI is set up (tools, commands, /hub)
|
|
284
299
|
// but user input is relayed to the remote sandbox instead of the local Pi agent.
|
|
285
300
|
const remoteSessionId = process.env[REMOTE_SESSION_ENV] || null;
|
|
301
|
+
const isRemoteSession = Boolean(remoteSessionId);
|
|
286
302
|
const isNativeRemote = !!process.env[NATIVE_REMOTE_ENV];
|
|
287
303
|
if (remoteSessionId) {
|
|
288
304
|
log(`Remote mode: will connect as controller to session ${remoteSessionId}`);
|
|
@@ -298,7 +314,10 @@ export function agentuityCoderHub(pi: ExtensionAPI) {
|
|
|
298
314
|
// This is how we discover what tools/agents the server provides.
|
|
299
315
|
// ══════════════════════════════════════════════
|
|
300
316
|
|
|
301
|
-
const
|
|
317
|
+
const initialInitMsg = fetchInitMessageSync(hubUrl, agentRole);
|
|
318
|
+
const initMsg = initialInitMsg
|
|
319
|
+
? adaptInitMessageForLocalTui(initialInitMsg, { isRemoteSession })
|
|
320
|
+
: null;
|
|
302
321
|
|
|
303
322
|
if (!initMsg) {
|
|
304
323
|
log('Hub not reachable — no tools or agents registered');
|
|
@@ -411,6 +430,18 @@ export function agentuityCoderHub(pi: ExtensionAPI) {
|
|
|
411
430
|
// Titlebar: branding + spinner (registers its own event handlers)
|
|
412
431
|
setupTitlebar(pi);
|
|
413
432
|
|
|
433
|
+
// Override Pi's built-in bash call-row rendering so local transcript rows
|
|
434
|
+
// can brand Agentuity CLI invocations without changing bash execution/result behavior.
|
|
435
|
+
const hasBashTool = serverTools.some((tool) => tool.name === 'bash');
|
|
436
|
+
const localBashRenderers = hasBashTool ? getToolRenderers('bash') : undefined;
|
|
437
|
+
if (hasBashTool && localBashRenderers?.renderCall) {
|
|
438
|
+
const bashToolDefinition = createBashToolDefinition(process.cwd());
|
|
439
|
+
pi.registerTool({
|
|
440
|
+
...bashToolDefinition,
|
|
441
|
+
renderCall: localBashRenderers.renderCall as ToolDefinition['renderCall'],
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
|
|
414
445
|
// ══════════════════════════════════════════════
|
|
415
446
|
// WebSocket client for runtime communication (tool execution + events)
|
|
416
447
|
// ══════════════════════════════════════════════
|
|
@@ -453,9 +484,10 @@ export function agentuityCoderHub(pi: ExtensionAPI) {
|
|
|
453
484
|
}
|
|
454
485
|
|
|
455
486
|
function applyInitMessage(nextInit: InitMessage): void {
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
if (
|
|
487
|
+
const effectiveInit = adaptInitMessageForLocalTui(nextInit, { isRemoteSession });
|
|
488
|
+
cachedInitMessage = effectiveInit;
|
|
489
|
+
if (effectiveInit.sessionId) currentSessionId = effectiveInit.sessionId;
|
|
490
|
+
if (effectiveInit.config) hubConfig = effectiveInit.config;
|
|
459
491
|
}
|
|
460
492
|
|
|
461
493
|
client.onInitMessage = (nextInit) => {
|
|
@@ -1448,7 +1480,7 @@ export function agentuityCoderHub(pi: ExtensionAPI) {
|
|
|
1448
1480
|
}
|
|
1449
1481
|
|
|
1450
1482
|
// Set up Coder footer (powerline: model or active agent > branch > status + observer count)
|
|
1451
|
-
setupCoderFooter(ctx, getHubUiStatus, getObserverState);
|
|
1483
|
+
setupCoderFooter(pi, ctx, getHubUiStatus, getObserverState);
|
|
1452
1484
|
|
|
1453
1485
|
// Fire-and-forget: fetch session snapshot for label + initial observer count.
|
|
1454
1486
|
// Uses the Hub REST endpoint — non-blocking, best-effort.
|
|
@@ -1755,13 +1787,7 @@ async function runSubAgent(
|
|
|
1755
1787
|
const { piSdk, piAi } = await loadPiSdk();
|
|
1756
1788
|
// Runtime-resolved dynamic imports — exact types unavailable statically
|
|
1757
1789
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1758
|
-
const {
|
|
1759
|
-
createAgentSession,
|
|
1760
|
-
DefaultResourceLoader,
|
|
1761
|
-
SessionManager,
|
|
1762
|
-
createCodingTools,
|
|
1763
|
-
createReadOnlyTools,
|
|
1764
|
-
} = piSdk as any;
|
|
1790
|
+
const { createAgentSession, DefaultResourceLoader, getAgentDir, SessionManager } = piSdk as any;
|
|
1765
1791
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1766
1792
|
const { getModel } = piAi as any;
|
|
1767
1793
|
|
|
@@ -1783,13 +1809,16 @@ async function runSubAgent(
|
|
|
1783
1809
|
// Sub-agents get Hub tools (memory, context7, etc.) via extensionFactories
|
|
1784
1810
|
// so they work in both driver and TUI mode.
|
|
1785
1811
|
const hubTools = agentConfig.hubTools ?? [];
|
|
1812
|
+
const cwd = process.cwd();
|
|
1813
|
+
const agentDir = getAgentDir();
|
|
1786
1814
|
|
|
1787
1815
|
// Resource loader — no extensions (prevents recursive task tool registration),
|
|
1788
1816
|
// no skills, agent's system prompt injected directly.
|
|
1789
1817
|
// Hub tools are injected via extensionFactories so sub-agents can use
|
|
1790
1818
|
// memory_recall, context7_search, etc.
|
|
1791
1819
|
const subLoader = new DefaultResourceLoader({
|
|
1792
|
-
cwd
|
|
1820
|
+
cwd,
|
|
1821
|
+
agentDir,
|
|
1793
1822
|
noExtensions: true,
|
|
1794
1823
|
extensionFactories:
|
|
1795
1824
|
hubTools.length > 0
|
|
@@ -1808,9 +1837,12 @@ async function runSubAgent(
|
|
|
1808
1837
|
});
|
|
1809
1838
|
await subLoader.reload();
|
|
1810
1839
|
|
|
1811
|
-
//
|
|
1812
|
-
const
|
|
1813
|
-
const
|
|
1840
|
+
// Pi v0.68.x uses a name allowlist for both built-in and extension/custom tools.
|
|
1841
|
+
const builtInToolNames = selectSubAgentToolNames(agentConfig);
|
|
1842
|
+
const hubToolNames = hubTools
|
|
1843
|
+
.map((tool) => (typeof tool.name === 'string' ? tool.name.trim() : ''))
|
|
1844
|
+
.filter((name): name is string => name.length > 0);
|
|
1845
|
+
const tools = Array.from(new Set([...builtInToolNames, ...hubToolNames]));
|
|
1814
1846
|
|
|
1815
1847
|
const { session } = await createAgentSession({
|
|
1816
1848
|
// subModel is already untyped (from dynamic import) — createAgentSession is also dynamically imported
|
|
@@ -1824,7 +1856,8 @@ async function runSubAgent(
|
|
|
1824
1856
|
| 'xhigh',
|
|
1825
1857
|
tools,
|
|
1826
1858
|
resourceLoader: subLoader,
|
|
1827
|
-
|
|
1859
|
+
// Pi now tracks cwd per session, so bind in-memory sub-agents to the actual repo cwd.
|
|
1860
|
+
sessionManager: SessionManager.inMemory(cwd),
|
|
1828
1861
|
});
|
|
1829
1862
|
await session.bindExtensions({});
|
|
1830
1863
|
|
|
@@ -1860,25 +1893,19 @@ async function runSubAgent(
|
|
|
1860
1893
|
|
|
1861
1894
|
if (evt.type === 'tool_execution_start') {
|
|
1862
1895
|
const toolName = evt.toolName || evt.name || evt.tool || 'unknown';
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
else if (args.pattern) toolArgs = String(args.pattern).slice(0, 40);
|
|
1870
|
-
else {
|
|
1871
|
-
const first = Object.values(args)[0];
|
|
1872
|
-
if (first) toolArgs = String(first).slice(0, 40);
|
|
1873
|
-
}
|
|
1874
|
-
}
|
|
1896
|
+
const display = formatToolDisplay(
|
|
1897
|
+
toolName,
|
|
1898
|
+
typeof evt.args === 'string' || (evt.args && typeof evt.args === 'object')
|
|
1899
|
+
? (evt.args as string | Record<string, unknown>)
|
|
1900
|
+
: undefined
|
|
1901
|
+
);
|
|
1875
1902
|
|
|
1876
1903
|
onProgress({
|
|
1877
1904
|
agentName: agentConfig.name,
|
|
1878
1905
|
status: 'tool_start',
|
|
1879
1906
|
toolCallId: typeof evt.toolCallId === 'string' ? evt.toolCallId : undefined,
|
|
1880
|
-
currentTool: toolName,
|
|
1881
|
-
currentToolArgs: toolArgs,
|
|
1907
|
+
currentTool: display.toolName,
|
|
1908
|
+
currentToolArgs: display.toolArgs,
|
|
1882
1909
|
elapsed,
|
|
1883
1910
|
});
|
|
1884
1911
|
} else if (evt.type === 'tool_execution_end') {
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { AgentDefinition, HubToolDefinition, InitMessage } from './protocol.ts';
|
|
2
|
+
|
|
3
|
+
const LOCAL_TUI_HIDDEN_HUB_TOOL_NAMES = new Set(['sandbox_exec']);
|
|
4
|
+
|
|
5
|
+
function filterHubToolsForLocalTui(tools?: HubToolDefinition[]): HubToolDefinition[] | undefined {
|
|
6
|
+
if (!tools) return tools;
|
|
7
|
+
|
|
8
|
+
const filtered = tools.filter((tool) => !LOCAL_TUI_HIDDEN_HUB_TOOL_NAMES.has(tool.name));
|
|
9
|
+
return filtered.length === tools.length ? tools : filtered;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function filterAgentHubToolsForLocalTui(agents?: AgentDefinition[]): AgentDefinition[] | undefined {
|
|
13
|
+
if (!agents) return agents;
|
|
14
|
+
|
|
15
|
+
let changed = false;
|
|
16
|
+
const filteredAgents = agents.map((agent) => {
|
|
17
|
+
const filteredHubTools = filterHubToolsForLocalTui(agent.hubTools);
|
|
18
|
+
if (filteredHubTools === agent.hubTools) {
|
|
19
|
+
return agent;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
changed = true;
|
|
23
|
+
return {
|
|
24
|
+
...agent,
|
|
25
|
+
hubTools: filteredHubTools && filteredHubTools.length > 0 ? filteredHubTools : undefined,
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
return changed ? filteredAgents : agents;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function adaptInitMessageForLocalTui(
|
|
33
|
+
init: InitMessage,
|
|
34
|
+
options: {
|
|
35
|
+
isRemoteSession: boolean;
|
|
36
|
+
}
|
|
37
|
+
): InitMessage {
|
|
38
|
+
if (options.isRemoteSession) {
|
|
39
|
+
return init;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const tools = filterHubToolsForLocalTui(init.tools);
|
|
43
|
+
const agents = filterAgentHubToolsForLocalTui(init.agents);
|
|
44
|
+
|
|
45
|
+
if (tools === init.tools && agents === init.agents) {
|
|
46
|
+
return init;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
...init,
|
|
51
|
+
tools,
|
|
52
|
+
agents,
|
|
53
|
+
};
|
|
54
|
+
}
|
package/src/protocol.ts
CHANGED
|
@@ -75,6 +75,7 @@ export type HubAction =
|
|
|
75
75
|
export interface AgentDefinition {
|
|
76
76
|
name: string;
|
|
77
77
|
displayName?: string;
|
|
78
|
+
source?: 'builtin' | 'custom';
|
|
78
79
|
description: string;
|
|
79
80
|
systemPrompt: string;
|
|
80
81
|
model?: string;
|
|
@@ -84,6 +85,7 @@ export interface AgentDefinition {
|
|
|
84
85
|
readOnly?: boolean;
|
|
85
86
|
hubTools?: HubToolDefinition[];
|
|
86
87
|
capabilities?: string[];
|
|
88
|
+
strictToolSelection?: boolean;
|
|
87
89
|
status?: 'available' | 'busy' | 'offline';
|
|
88
90
|
}
|
|
89
91
|
|
package/src/remote-session.ts
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
type RemoteLifecycleState,
|
|
24
24
|
} from './remote-lifecycle.ts';
|
|
25
25
|
import { resolveCoderOrgId } from './auth.ts';
|
|
26
|
+
import { formatToolDisplay } from './agentuity-cli.ts';
|
|
26
27
|
|
|
27
28
|
const DEBUG = !!process.env['AGENTUITY_DEBUG'];
|
|
28
29
|
|
|
@@ -1001,18 +1002,23 @@ export async function setupRemoteMode(
|
|
|
1001
1002
|
break;
|
|
1002
1003
|
|
|
1003
1004
|
case 'tool_execution_start': {
|
|
1004
|
-
const
|
|
1005
|
-
|
|
1005
|
+
const rawTool = (event as { toolName?: string }).toolName ?? 'tool';
|
|
1006
|
+
const rawArgs = (event as { args?: string | Record<string, unknown> }).args;
|
|
1007
|
+
const display = formatToolDisplay(rawTool, rawArgs);
|
|
1008
|
+
currentTool = display.toolName;
|
|
1006
1009
|
if (extensionCtxRef?.hasUI) {
|
|
1007
|
-
setNonLifecycleWorkingMessage(`Running ${
|
|
1008
|
-
extensionCtxRef.ui.setStatus('remote_activity', `Running ${
|
|
1010
|
+
setNonLifecycleWorkingMessage(`Running ${display.fullLabel}...`);
|
|
1011
|
+
extensionCtxRef.ui.setStatus('remote_activity', `Running ${display.fullLabel}...`);
|
|
1009
1012
|
}
|
|
1010
|
-
log(`Tool: ${
|
|
1013
|
+
log(`Tool: ${display.fullLabel}`);
|
|
1011
1014
|
break;
|
|
1012
1015
|
}
|
|
1013
1016
|
|
|
1014
1017
|
case 'tool_execution_end': {
|
|
1015
|
-
const
|
|
1018
|
+
const rawTool = (event as { toolName?: string }).toolName ?? currentTool ?? 'tool';
|
|
1019
|
+
const rawArgs = (event as { args?: string | Record<string, unknown> }).args;
|
|
1020
|
+
const display = rawArgs ? formatToolDisplay(rawTool, rawArgs) : null;
|
|
1021
|
+
const tool = display?.fullLabel ?? currentTool ?? rawTool;
|
|
1016
1022
|
currentTool = null;
|
|
1017
1023
|
if (extensionCtxRef?.hasUI) {
|
|
1018
1024
|
clearWorkingMessage();
|
package/src/renderers.ts
CHANGED
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
AgentToolResult,
|
|
13
13
|
} from '@mariozechner/pi-coding-agent';
|
|
14
14
|
import { Box, Text, Container, type Component } from '@mariozechner/pi-tui';
|
|
15
|
+
import { formatToolDisplay } from './agentuity-cli.ts';
|
|
15
16
|
|
|
16
17
|
// ──────────────────────────────────────────────
|
|
17
18
|
// Line-safety helper — must be declared before SimpleText so
|
|
@@ -125,6 +126,32 @@ function truncate(str: string, max: number): string {
|
|
|
125
126
|
return str.slice(0, max - 1) + '\u2026';
|
|
126
127
|
}
|
|
127
128
|
|
|
129
|
+
function toSingleLinePreview(value: string): string {
|
|
130
|
+
return value.replace(/\s+/g, ' ').trim();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function isCommandToolName(toolName: string): boolean {
|
|
134
|
+
const normalized = toolName.trim().toLowerCase();
|
|
135
|
+
return normalized === 'bash' || normalized === 'execute_command' || normalized.includes('shell');
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function getCommandArg(args: Record<string, unknown>): string | undefined {
|
|
139
|
+
const value = args['command'] ?? args['cmd'];
|
|
140
|
+
return typeof value === 'string' && value.trim() ? value.trim() : undefined;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function getCommandTimeoutLabel(args: Record<string, unknown>): string | undefined {
|
|
144
|
+
const timeout = args['timeout'];
|
|
145
|
+
if (typeof timeout === 'number' && Number.isFinite(timeout) && timeout > 0) {
|
|
146
|
+
return `${timeout}s`;
|
|
147
|
+
}
|
|
148
|
+
if (typeof timeout === 'string' && timeout.trim()) {
|
|
149
|
+
const value = timeout.trim();
|
|
150
|
+
return /s$/i.test(value) ? value : `${value}s`;
|
|
151
|
+
}
|
|
152
|
+
return undefined;
|
|
153
|
+
}
|
|
154
|
+
|
|
128
155
|
// ──────────────────────────────────────────────
|
|
129
156
|
// Individual tool renderers
|
|
130
157
|
// ──────────────────────────────────────────────
|
|
@@ -709,6 +736,37 @@ function parallelTasksRenderers(): ToolRenderers {
|
|
|
709
736
|
};
|
|
710
737
|
}
|
|
711
738
|
|
|
739
|
+
function commandToolRenderers(toolName: string): ToolRenderers {
|
|
740
|
+
return {
|
|
741
|
+
renderCall(args, theme) {
|
|
742
|
+
const display = formatToolDisplay(toolName, args);
|
|
743
|
+
const timeout = getCommandTimeoutLabel(args);
|
|
744
|
+
|
|
745
|
+
if (display.branded) {
|
|
746
|
+
let text = theme.fg('toolTitle', theme.bold(display.toolName));
|
|
747
|
+
if (display.toolArgs) {
|
|
748
|
+
text += theme.fg('accent', ` ${display.toolArgs}`);
|
|
749
|
+
}
|
|
750
|
+
if (timeout) {
|
|
751
|
+
text += theme.fg('dim', ` (timeout ${timeout})`);
|
|
752
|
+
}
|
|
753
|
+
return new SimpleText(text);
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
let text = theme.fg('toolTitle', theme.bold('$ '));
|
|
757
|
+
const commandPreview = getCommandArg(args);
|
|
758
|
+
text += theme.fg(
|
|
759
|
+
'accent',
|
|
760
|
+
truncate(commandPreview ? toSingleLinePreview(commandPreview) : display.toolName, 80)
|
|
761
|
+
);
|
|
762
|
+
if (timeout) {
|
|
763
|
+
text += theme.fg('dim', ` (timeout ${timeout})`);
|
|
764
|
+
}
|
|
765
|
+
return new SimpleText(text);
|
|
766
|
+
},
|
|
767
|
+
};
|
|
768
|
+
}
|
|
769
|
+
|
|
712
770
|
// ──────────────────────────────────────────────
|
|
713
771
|
|
|
714
772
|
const RENDERERS: Record<string, () => ToolRenderers> = {
|
|
@@ -736,5 +794,7 @@ const RENDERERS: Record<string, () => ToolRenderers> = {
|
|
|
736
794
|
*/
|
|
737
795
|
export function getToolRenderers(toolName: string): ToolRenderers | undefined {
|
|
738
796
|
const factory = RENDERERS[toolName];
|
|
739
|
-
return factory
|
|
797
|
+
if (factory) return factory();
|
|
798
|
+
if (isCommandToolName(toolName)) return commandToolRenderers(toolName);
|
|
799
|
+
return undefined;
|
|
740
800
|
}
|