@tyvm/knowhow 0.0.83 → 0.0.84
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/package.json +4 -2
- package/src/agents/base/base.ts +72 -62
- package/src/agents/index.ts +30 -14
- package/src/agents/tools/startAgentTask.ts +3 -1
- package/src/chat/CliChatService.ts +20 -4
- package/src/chat/modules/AgentModule.ts +399 -357
- package/src/chat/modules/CustomCommandsModule.ts +0 -1
- package/src/chat/modules/InternalChatModule.ts +18 -2
- package/src/chat/modules/RendererModule.ts +109 -0
- package/src/chat/modules/SessionsModule.ts +854 -0
- package/src/chat/modules/SetupModule.ts +6 -8
- package/src/chat/modules/index.ts +1 -0
- package/src/chat/renderer/CompactRenderer.ts +209 -0
- package/src/chat/renderer/ConsoleRenderer.ts +141 -0
- package/src/chat/renderer/FancyRenderer.ts +421 -0
- package/src/chat/renderer/index.ts +5 -0
- package/src/chat/renderer/loadRenderer.ts +314 -0
- package/src/chat/renderer/messagesToRenderEvents.ts +96 -0
- package/src/chat/renderer/types.ts +88 -0
- package/src/chat/types.ts +5 -0
- package/src/chat.ts +69 -5
- package/src/cli.ts +24 -5
- package/src/config.ts +15 -0
- package/src/plugins/AgentsMdPlugin.ts +1 -1
- package/src/plugins/GitPlugin.ts +20 -20
- package/src/plugins/PluginBase.ts +11 -0
- package/src/plugins/SkillsPlugin.ts +150 -0
- package/src/plugins/asana.ts +4 -4
- package/src/plugins/embedding.ts +3 -5
- package/src/plugins/exec.ts +3 -3
- package/src/plugins/figma.ts +3 -7
- package/src/plugins/github.ts +18 -29
- package/src/plugins/jira.ts +2 -2
- package/src/plugins/language.ts +4 -4
- package/src/plugins/linear.ts +4 -4
- package/src/plugins/notion.ts +6 -8
- package/src/plugins/plugins.ts +29 -3
- package/src/plugins/url.ts +2 -2
- package/src/plugins/vim.ts +4 -3
- package/src/services/AgentService.ts +17 -0
- package/src/services/AgentSyncFs.ts +3 -0
- package/src/services/EventService.ts +168 -27
- package/src/services/KnowhowClient.ts +1 -0
- package/src/services/SessionManager.ts +51 -1
- package/src/services/SyncedAgentWatcher.ts +397 -0
- package/src/services/SyncerService.ts +147 -0
- package/src/services/index.ts +2 -0
- package/src/services/modules/index.ts +14 -3
- package/src/types.ts +25 -0
- package/src/worker.ts +80 -2
- package/src/workers/auth/PasskeySetup.ts +185 -0
- package/src/workers/auth/WorkerPasskeyAuth.ts +190 -0
- package/src/workers/auth/types.ts +58 -0
- package/src/workers/tools/getChallenge.ts +33 -0
- package/src/workers/tools/index.ts +8 -0
- package/src/workers/tools/lock.ts +31 -0
- package/src/workers/tools/unlock.ts +116 -0
- package/tests/unit/modules/moduleLoading.test.ts +226 -0
- package/tests/unit/plugins/pluginLoading.test.ts +151 -0
- package/ts_build/package.json +4 -2
- package/ts_build/src/agents/base/base.d.ts +4 -3
- package/ts_build/src/agents/base/base.js +54 -30
- package/ts_build/src/agents/base/base.js.map +1 -1
- package/ts_build/src/agents/index.d.ts +3 -0
- package/ts_build/src/agents/index.js +21 -11
- package/ts_build/src/agents/index.js.map +1 -1
- package/ts_build/src/agents/tools/startAgentTask.js +2 -1
- package/ts_build/src/agents/tools/startAgentTask.js.map +1 -1
- package/ts_build/src/chat/CliChatService.js +16 -5
- package/ts_build/src/chat/CliChatService.js.map +1 -1
- package/ts_build/src/chat/modules/AgentModule.d.ts +34 -17
- package/ts_build/src/chat/modules/AgentModule.js +248 -258
- package/ts_build/src/chat/modules/AgentModule.js.map +1 -1
- package/ts_build/src/chat/modules/CustomCommandsModule.js.map +1 -1
- package/ts_build/src/chat/modules/InternalChatModule.d.ts +3 -0
- package/ts_build/src/chat/modules/InternalChatModule.js +16 -1
- package/ts_build/src/chat/modules/InternalChatModule.js.map +1 -1
- package/ts_build/src/chat/modules/RendererModule.d.ts +16 -0
- package/ts_build/src/chat/modules/RendererModule.js +76 -0
- package/ts_build/src/chat/modules/RendererModule.js.map +1 -0
- package/ts_build/src/chat/modules/SessionsModule.d.ts +33 -0
- package/ts_build/src/chat/modules/SessionsModule.js +582 -0
- package/ts_build/src/chat/modules/SessionsModule.js.map +1 -0
- package/ts_build/src/chat/modules/SetupModule.d.ts +3 -3
- package/ts_build/src/chat/modules/SetupModule.js +4 -6
- package/ts_build/src/chat/modules/SetupModule.js.map +1 -1
- package/ts_build/src/chat/modules/index.d.ts +1 -0
- package/ts_build/src/chat/modules/index.js +3 -1
- package/ts_build/src/chat/modules/index.js.map +1 -1
- package/ts_build/src/chat/renderer/CompactRenderer.d.ts +23 -0
- package/ts_build/src/chat/renderer/CompactRenderer.js +167 -0
- package/ts_build/src/chat/renderer/CompactRenderer.js.map +1 -0
- package/ts_build/src/chat/renderer/ConsoleRenderer.d.ts +22 -0
- package/ts_build/src/chat/renderer/ConsoleRenderer.js +110 -0
- package/ts_build/src/chat/renderer/ConsoleRenderer.js.map +1 -0
- package/ts_build/src/chat/renderer/FancyRenderer.d.ts +23 -0
- package/ts_build/src/chat/renderer/FancyRenderer.js +328 -0
- package/ts_build/src/chat/renderer/FancyRenderer.js.map +1 -0
- package/ts_build/src/chat/renderer/index.d.ts +5 -0
- package/ts_build/src/chat/renderer/index.js +29 -0
- package/ts_build/src/chat/renderer/index.js.map +1 -0
- package/ts_build/src/chat/renderer/loadRenderer.d.ts +4 -0
- package/ts_build/src/chat/renderer/loadRenderer.js +246 -0
- package/ts_build/src/chat/renderer/loadRenderer.js.map +1 -0
- package/ts_build/src/chat/renderer/messagesToRenderEvents.d.ts +15 -0
- package/ts_build/src/chat/renderer/messagesToRenderEvents.js +72 -0
- package/ts_build/src/chat/renderer/messagesToRenderEvents.js.map +1 -0
- package/ts_build/src/chat/renderer/types.d.ts +75 -0
- package/ts_build/src/chat/renderer/types.js +3 -0
- package/ts_build/src/chat/renderer/types.js.map +1 -0
- package/ts_build/src/chat/types.d.ts +5 -0
- package/ts_build/src/chat.js +46 -4
- package/ts_build/src/chat.js.map +1 -1
- package/ts_build/src/cli.js +18 -5
- package/ts_build/src/cli.js.map +1 -1
- package/ts_build/src/config.d.ts +1 -0
- package/ts_build/src/config.js +17 -1
- package/ts_build/src/config.js.map +1 -1
- package/ts_build/src/plugins/AgentsMdPlugin.js +1 -1
- package/ts_build/src/plugins/AgentsMdPlugin.js.map +1 -1
- package/ts_build/src/plugins/GitPlugin.js +20 -20
- package/ts_build/src/plugins/GitPlugin.js.map +1 -1
- package/ts_build/src/plugins/PluginBase.d.ts +1 -0
- package/ts_build/src/plugins/PluginBase.js +13 -0
- package/ts_build/src/plugins/PluginBase.js.map +1 -1
- package/ts_build/src/plugins/SkillsPlugin.d.ts +13 -0
- package/ts_build/src/plugins/SkillsPlugin.js +149 -0
- package/ts_build/src/plugins/SkillsPlugin.js.map +1 -0
- package/ts_build/src/plugins/asana.js +4 -4
- package/ts_build/src/plugins/asana.js.map +1 -1
- package/ts_build/src/plugins/embedding.js +3 -3
- package/ts_build/src/plugins/embedding.js.map +1 -1
- package/ts_build/src/plugins/exec.js +3 -3
- package/ts_build/src/plugins/exec.js.map +1 -1
- package/ts_build/src/plugins/figma.js +3 -3
- package/ts_build/src/plugins/figma.js.map +1 -1
- package/ts_build/src/plugins/github.js +18 -18
- package/ts_build/src/plugins/github.js.map +1 -1
- package/ts_build/src/plugins/jira.js +2 -2
- package/ts_build/src/plugins/jira.js.map +1 -1
- package/ts_build/src/plugins/language.js +4 -4
- package/ts_build/src/plugins/language.js.map +1 -1
- package/ts_build/src/plugins/linear.js +4 -4
- package/ts_build/src/plugins/linear.js.map +1 -1
- package/ts_build/src/plugins/notion.js +6 -6
- package/ts_build/src/plugins/notion.js.map +1 -1
- package/ts_build/src/plugins/plugins.d.ts +3 -0
- package/ts_build/src/plugins/plugins.js +18 -3
- package/ts_build/src/plugins/plugins.js.map +1 -1
- package/ts_build/src/plugins/url.js +2 -2
- package/ts_build/src/plugins/url.js.map +1 -1
- package/ts_build/src/plugins/vim.js +2 -2
- package/ts_build/src/plugins/vim.js.map +1 -1
- package/ts_build/src/services/AgentService.d.ts +3 -0
- package/ts_build/src/services/AgentService.js +7 -0
- package/ts_build/src/services/AgentService.js.map +1 -1
- package/ts_build/src/services/AgentSyncFs.d.ts +1 -0
- package/ts_build/src/services/AgentSyncFs.js +2 -0
- package/ts_build/src/services/AgentSyncFs.js.map +1 -1
- package/ts_build/src/services/EventService.d.ts +25 -2
- package/ts_build/src/services/EventService.js +92 -14
- package/ts_build/src/services/EventService.js.map +1 -1
- package/ts_build/src/services/KnowhowClient.d.ts +1 -0
- package/ts_build/src/services/KnowhowClient.js.map +1 -1
- package/ts_build/src/services/SessionManager.d.ts +6 -0
- package/ts_build/src/services/SessionManager.js +39 -1
- package/ts_build/src/services/SessionManager.js.map +1 -1
- package/ts_build/src/services/SyncedAgentWatcher.d.ts +101 -0
- package/ts_build/src/services/SyncedAgentWatcher.js +312 -0
- package/ts_build/src/services/SyncedAgentWatcher.js.map +1 -0
- package/ts_build/src/services/SyncerService.d.ts +30 -0
- package/ts_build/src/services/SyncerService.js +72 -0
- package/ts_build/src/services/SyncerService.js.map +1 -0
- package/ts_build/src/services/index.d.ts +2 -0
- package/ts_build/src/services/index.js +2 -0
- package/ts_build/src/services/index.js.map +1 -1
- package/ts_build/src/services/modules/index.js +10 -2
- package/ts_build/src/services/modules/index.js.map +1 -1
- package/ts_build/src/types.d.ts +19 -0
- package/ts_build/src/types.js.map +1 -1
- package/ts_build/src/worker.d.ts +2 -0
- package/ts_build/src/worker.js +59 -4
- package/ts_build/src/worker.js.map +1 -1
- package/ts_build/src/workers/auth/PasskeySetup.d.ts +10 -0
- package/ts_build/src/workers/auth/PasskeySetup.js +131 -0
- package/ts_build/src/workers/auth/PasskeySetup.js.map +1 -0
- package/ts_build/src/workers/auth/WorkerPasskeyAuth.d.ts +35 -0
- package/ts_build/src/workers/auth/WorkerPasskeyAuth.js +129 -0
- package/ts_build/src/workers/auth/WorkerPasskeyAuth.js.map +1 -0
- package/ts_build/src/workers/auth/types.d.ts +36 -0
- package/ts_build/src/workers/auth/types.js +3 -0
- package/ts_build/src/workers/auth/types.js.map +1 -0
- package/ts_build/src/workers/tools/getChallenge.d.ts +9 -0
- package/ts_build/src/workers/tools/getChallenge.js +27 -0
- package/ts_build/src/workers/tools/getChallenge.js.map +1 -0
- package/ts_build/src/workers/tools/index.d.ts +6 -0
- package/ts_build/src/workers/tools/index.js +10 -0
- package/ts_build/src/workers/tools/index.js.map +1 -1
- package/ts_build/src/workers/tools/lock.d.ts +9 -0
- package/ts_build/src/workers/tools/lock.js +27 -0
- package/ts_build/src/workers/tools/lock.js.map +1 -0
- package/ts_build/src/workers/tools/unlock.d.ts +18 -0
- package/ts_build/src/workers/tools/unlock.js +78 -0
- package/ts_build/src/workers/tools/unlock.js.map +1 -0
- package/ts_build/tests/unit/modules/moduleLoading.test.d.ts +1 -0
- package/ts_build/tests/unit/modules/moduleLoading.test.js +187 -0
- package/ts_build/tests/unit/modules/moduleLoading.test.js.map +1 -0
- package/ts_build/tests/unit/plugins/pluginLoading.test.d.ts +1 -0
- package/ts_build/tests/unit/plugins/pluginLoading.test.js +123 -0
- package/ts_build/tests/unit/plugins/pluginLoading.test.js.map +1 -0
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FancyRenderer - A visually rich terminal renderer using box-drawing characters and ANSI colors.
|
|
3
|
+
*
|
|
4
|
+
* Features:
|
|
5
|
+
* - Colored agent messages with agent name badges
|
|
6
|
+
* - Tool calls displayed in bordered boxes
|
|
7
|
+
* - Tool results with syntax-aware truncation
|
|
8
|
+
* - Timing displayed inline
|
|
9
|
+
* - Cost/status line with spinner animation
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
AgentRenderer,
|
|
14
|
+
LogEvent,
|
|
15
|
+
AgentStatusEvent,
|
|
16
|
+
ToolCallEvent,
|
|
17
|
+
ToolResultEvent,
|
|
18
|
+
AgentMessageEvent,
|
|
19
|
+
AgentDoneEvent,
|
|
20
|
+
RenderEvent,
|
|
21
|
+
} from "./types";
|
|
22
|
+
import { EventEmitter } from "events";
|
|
23
|
+
|
|
24
|
+
// ANSI color/style codes
|
|
25
|
+
const c = {
|
|
26
|
+
reset: "\x1b[0m",
|
|
27
|
+
bold: "\x1b[1m",
|
|
28
|
+
dim: "\x1b[2m",
|
|
29
|
+
italic: "\x1b[3m",
|
|
30
|
+
underline: "\x1b[4m",
|
|
31
|
+
|
|
32
|
+
black: "\x1b[30m",
|
|
33
|
+
red: "\x1b[31m",
|
|
34
|
+
green: "\x1b[32m",
|
|
35
|
+
yellow: "\x1b[33m",
|
|
36
|
+
blue: "\x1b[34m",
|
|
37
|
+
magenta: "\x1b[35m",
|
|
38
|
+
cyan: "\x1b[36m",
|
|
39
|
+
white: "\x1b[37m",
|
|
40
|
+
gray: "\x1b[90m",
|
|
41
|
+
|
|
42
|
+
bgBlack: "\x1b[40m",
|
|
43
|
+
bgRed: "\x1b[41m",
|
|
44
|
+
bgGreen: "\x1b[42m",
|
|
45
|
+
bgYellow: "\x1b[43m",
|
|
46
|
+
bgBlue: "\x1b[44m",
|
|
47
|
+
bgMagenta: "\x1b[45m",
|
|
48
|
+
bgCyan: "\x1b[46m",
|
|
49
|
+
bgWhite: "\x1b[47m",
|
|
50
|
+
bgGray: "\x1b[100m",
|
|
51
|
+
|
|
52
|
+
brightBlue: "\x1b[94m",
|
|
53
|
+
brightCyan: "\x1b[96m",
|
|
54
|
+
brightGreen: "\x1b[92m",
|
|
55
|
+
brightYellow: "\x1b[93m",
|
|
56
|
+
brightMagenta: "\x1b[95m",
|
|
57
|
+
brightWhite: "\x1b[97m",
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// Box drawing characters
|
|
61
|
+
const box = {
|
|
62
|
+
tl: "╭", tr: "╮",
|
|
63
|
+
bl: "╰", br: "╯",
|
|
64
|
+
h: "─", v: "│",
|
|
65
|
+
ml: "├", mr: "┤",
|
|
66
|
+
cross: "┼",
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const toolBox = {
|
|
70
|
+
tl: "┌", tr: "┐",
|
|
71
|
+
bl: "└", br: "┘",
|
|
72
|
+
h: "─", v: "│",
|
|
73
|
+
ml: "├", mr: "┤",
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// Terminal width helper
|
|
77
|
+
function termWidth(): number {
|
|
78
|
+
return process.stdout.columns || 80;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function pad(str: string, len: number, char = " "): string {
|
|
82
|
+
while (str.length < len) str += char;
|
|
83
|
+
return str;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function truncate(str: string, maxLen: number): string {
|
|
87
|
+
if (str.length <= maxLen) return str;
|
|
88
|
+
return str.slice(0, maxLen - 3) + "...";
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function stripAnsi(str: string): string {
|
|
92
|
+
return str.replace(/\x1b\[[0-9;]*m/g, "");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function visibleLength(str: string): string {
|
|
96
|
+
return stripAnsi(str);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** Draw a horizontal rule with optional label */
|
|
100
|
+
function hRule(label = "", color = c.gray, width = termWidth()): string {
|
|
101
|
+
if (!label) {
|
|
102
|
+
return color + box.h.repeat(width) + c.reset;
|
|
103
|
+
}
|
|
104
|
+
const labelStr = ` ${label} `;
|
|
105
|
+
const side = Math.floor((width - labelStr.length) / 2);
|
|
106
|
+
const left = box.h.repeat(Math.max(0, side));
|
|
107
|
+
const right = box.h.repeat(Math.max(0, width - side - labelStr.length));
|
|
108
|
+
return color + left + c.reset + c.bold + color + labelStr + c.reset + color + right + c.reset;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Draw a box around content lines */
|
|
112
|
+
function drawBox(
|
|
113
|
+
lines: string[],
|
|
114
|
+
headerLabel: string,
|
|
115
|
+
headerColor: string,
|
|
116
|
+
width: number
|
|
117
|
+
): string {
|
|
118
|
+
const innerWidth = width - 2;
|
|
119
|
+
const headerText = ` ${headerLabel} `;
|
|
120
|
+
const headerPad = Math.max(0, innerWidth - stripAnsi(headerText).length);
|
|
121
|
+
const topLine =
|
|
122
|
+
headerColor + toolBox.tl + toolBox.h +
|
|
123
|
+
c.bold + headerColor + headerText + c.reset +
|
|
124
|
+
headerColor + toolBox.h.repeat(headerPad) +
|
|
125
|
+
toolBox.tr + c.reset;
|
|
126
|
+
|
|
127
|
+
const contentLines = lines.map((line) => {
|
|
128
|
+
const visible = stripAnsi(line);
|
|
129
|
+
const padLen = Math.max(0, innerWidth - visible.length);
|
|
130
|
+
return headerColor + toolBox.v + c.reset + " " + line + " ".repeat(padLen - 1) + headerColor + toolBox.v + c.reset;
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
const bottomLine = headerColor + toolBox.bl + toolBox.h.repeat(innerWidth) + toolBox.br + c.reset;
|
|
134
|
+
|
|
135
|
+
return [topLine, ...contentLines, bottomLine].join("\n");
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** Format JSON for display, with line limit */
|
|
139
|
+
function formatResult(result: any, maxLines = 20): string[] {
|
|
140
|
+
let str: string;
|
|
141
|
+
try {
|
|
142
|
+
str = typeof result === "string" ? result : JSON.stringify(result, null, 2);
|
|
143
|
+
} catch {
|
|
144
|
+
str = String(result);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const lines = str.split("\n");
|
|
148
|
+
if (lines.length <= maxLines) return lines;
|
|
149
|
+
|
|
150
|
+
const head = lines.slice(0, Math.floor(maxLines * 0.7));
|
|
151
|
+
const tail = lines.slice(lines.length - Math.floor(maxLines * 0.2));
|
|
152
|
+
const omitted = lines.length - head.length - tail.length;
|
|
153
|
+
return [
|
|
154
|
+
...head,
|
|
155
|
+
c.dim + ` ... (${omitted} lines omitted) ...` + c.reset,
|
|
156
|
+
...tail,
|
|
157
|
+
];
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** Colorize JSON string with basic syntax highlighting */
|
|
161
|
+
function colorizeJson(lines: string[]): string[] {
|
|
162
|
+
return lines.map((line) => {
|
|
163
|
+
// Already has ansi (dim omitted line)
|
|
164
|
+
if (line.includes("\x1b[")) return line;
|
|
165
|
+
|
|
166
|
+
return line
|
|
167
|
+
// Keys
|
|
168
|
+
.replace(/"([^"]+)":/g, `${c.cyan}"$1"${c.reset}:`)
|
|
169
|
+
// String values
|
|
170
|
+
.replace(/: "([^"]*)"/g, `: ${c.brightGreen}"$1"${c.reset}`)
|
|
171
|
+
// Numbers
|
|
172
|
+
.replace(/: (-?\d+\.?\d*)/g, `: ${c.brightYellow}$1${c.reset}`)
|
|
173
|
+
// Booleans
|
|
174
|
+
.replace(/: (true|false)/g, `: ${c.brightMagenta}$1${c.reset}`)
|
|
175
|
+
// Null
|
|
176
|
+
.replace(/: null/g, `: ${c.dim}null${c.reset}`);
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** Agent name → deterministic color */
|
|
181
|
+
const agentColors = [c.brightCyan, c.brightMagenta, c.brightGreen, c.brightYellow, c.brightBlue];
|
|
182
|
+
const agentColorMap = new Map<string, string>();
|
|
183
|
+
let agentColorIdx = 0;
|
|
184
|
+
function agentColor(name: string): string {
|
|
185
|
+
if (!agentColorMap.has(name)) {
|
|
186
|
+
agentColorMap.set(name, agentColors[agentColorIdx++ % agentColors.length]);
|
|
187
|
+
}
|
|
188
|
+
return agentColorMap.get(name)!;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** Keep track of tool call start times */
|
|
192
|
+
const toolTimers = new Map<string, number>();
|
|
193
|
+
|
|
194
|
+
export class FancyRenderer implements AgentRenderer {
|
|
195
|
+
private activeTaskId: string | undefined;
|
|
196
|
+
private emitter = new EventEmitter();
|
|
197
|
+
|
|
198
|
+
setActiveTaskId(taskId: string | undefined): void {
|
|
199
|
+
this.activeTaskId = taskId;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
getActiveTaskId(): string | undefined {
|
|
203
|
+
return this.activeTaskId;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
private isActiveTask(taskId: string): boolean {
|
|
207
|
+
if (!this.activeTaskId) return true;
|
|
208
|
+
return taskId === this.activeTaskId;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
onLog(handler: (event: LogEvent) => void): void {
|
|
212
|
+
this.emitter.on("log", handler);
|
|
213
|
+
}
|
|
214
|
+
onAgentStatus(handler: (event: AgentStatusEvent) => void): void {
|
|
215
|
+
this.emitter.on("agentStatus", handler);
|
|
216
|
+
}
|
|
217
|
+
onToolCall(handler: (event: ToolCallEvent) => void): void {
|
|
218
|
+
this.emitter.on("toolCall", handler);
|
|
219
|
+
}
|
|
220
|
+
onToolResult(handler: (event: ToolResultEvent) => void): void {
|
|
221
|
+
this.emitter.on("toolResult", handler);
|
|
222
|
+
}
|
|
223
|
+
onAgentMessage(handler: (event: AgentMessageEvent) => void): void {
|
|
224
|
+
this.emitter.on("agentMessage", handler);
|
|
225
|
+
}
|
|
226
|
+
onAgentDone(handler: (event: AgentDoneEvent) => void): void {
|
|
227
|
+
this.emitter.on("agentDone", handler);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
render(event: RenderEvent): void {
|
|
231
|
+
if (!this.isActiveTask(event.taskId)) return;
|
|
232
|
+
|
|
233
|
+
switch (event.type) {
|
|
234
|
+
case "log":
|
|
235
|
+
this.emitter.emit("log", event);
|
|
236
|
+
this.renderLog(event);
|
|
237
|
+
break;
|
|
238
|
+
case "agentStatus":
|
|
239
|
+
this.emitter.emit("agentStatus", event);
|
|
240
|
+
this.renderAgentStatus(event);
|
|
241
|
+
break;
|
|
242
|
+
case "toolCall":
|
|
243
|
+
this.emitter.emit("toolCall", event);
|
|
244
|
+
this.renderToolCall(event);
|
|
245
|
+
break;
|
|
246
|
+
case "toolResult":
|
|
247
|
+
this.emitter.emit("toolResult", event);
|
|
248
|
+
this.renderToolResult(event);
|
|
249
|
+
break;
|
|
250
|
+
case "agentMessage":
|
|
251
|
+
this.emitter.emit("agentMessage", event);
|
|
252
|
+
this.renderAgentMessage(event);
|
|
253
|
+
break;
|
|
254
|
+
case "agentDone":
|
|
255
|
+
this.emitter.emit("agentDone", event);
|
|
256
|
+
this.renderAgentDone(event);
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
private renderLog(event: LogEvent): void {
|
|
262
|
+
const width = termWidth();
|
|
263
|
+
const levelColors: Record<string, string> = {
|
|
264
|
+
info: c.brightBlue,
|
|
265
|
+
warn: c.brightYellow,
|
|
266
|
+
error: c.red,
|
|
267
|
+
};
|
|
268
|
+
const icons: Record<string, string> = {
|
|
269
|
+
info: "ℹ",
|
|
270
|
+
warn: "⚠",
|
|
271
|
+
error: "✖",
|
|
272
|
+
};
|
|
273
|
+
const col = levelColors[event.level] || c.gray;
|
|
274
|
+
const icon = icons[event.level] || "·";
|
|
275
|
+
const prefix = col + icon + c.reset + " " + c.dim + `[${event.agentName}]` + c.reset + " ";
|
|
276
|
+
const msg = event.message;
|
|
277
|
+
console.log(prefix + msg);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
private renderAgentStatus(event: AgentStatusEvent): void {
|
|
281
|
+
const agentCol = agentColor(event.agentName);
|
|
282
|
+
const cost = c.brightGreen + `$${event.details.totalCostUsd.toFixed(3)}` + c.reset;
|
|
283
|
+
const elapsed = c.brightYellow + `${Math.floor(event.details.elapsedMs / 1000)}s` + c.reset;
|
|
284
|
+
|
|
285
|
+
let extras = "";
|
|
286
|
+
if (event.details.remainingTimeMs !== undefined) {
|
|
287
|
+
extras += c.dim + ` ~${Math.floor(event.details.remainingTimeMs / 1000)}s left` + c.reset;
|
|
288
|
+
}
|
|
289
|
+
if (event.details.remainingTurns !== undefined) {
|
|
290
|
+
extras += c.dim + ` ${event.details.remainingTurns} turns` + c.reset;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const badge = `${c.dim}●${c.reset} ${agentCol}${event.agentName}${c.reset}`;
|
|
294
|
+
console.log(`\n${badge} ${cost} ${elapsed}${extras}`);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
private renderToolCall(event: ToolCallEvent): void {
|
|
298
|
+
const width = termWidth();
|
|
299
|
+
const toolName = event.toolCall.function.name;
|
|
300
|
+
const timerKey = `${event.taskId}:${toolName}:${Date.now()}`;
|
|
301
|
+
// Store start time under a stable key (last one wins per tool name per task)
|
|
302
|
+
toolTimers.set(`${event.taskId}:${toolName}`, Date.now());
|
|
303
|
+
|
|
304
|
+
let args: any;
|
|
305
|
+
try {
|
|
306
|
+
args = JSON.parse(event.toolCall.function.arguments || "{}");
|
|
307
|
+
} catch {
|
|
308
|
+
args = event.toolCall.function.arguments;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const agentCol = agentColor(event.agentName);
|
|
312
|
+
const headerLabel = `⚡ ${c.bold}${toolName}${c.reset}${c.brightYellow}`;
|
|
313
|
+
|
|
314
|
+
// Format args
|
|
315
|
+
const argsLines = colorizeJson(formatResult(args, 10));
|
|
316
|
+
|
|
317
|
+
const boxStr = drawBox(argsLines, `⚡ ${toolName}`, c.brightYellow, Math.min(width, 100));
|
|
318
|
+
console.log("");
|
|
319
|
+
console.log(
|
|
320
|
+
c.dim + agentCol + `[${event.agentName}]` + c.reset +
|
|
321
|
+
c.dim + " called tool:" + c.reset
|
|
322
|
+
);
|
|
323
|
+
console.log(boxStr);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
private renderToolResult(event: ToolResultEvent): void {
|
|
327
|
+
const width = termWidth();
|
|
328
|
+
const toolName = event.toolCall.function.name;
|
|
329
|
+
|
|
330
|
+
// Calculate elapsed time
|
|
331
|
+
const startTime = toolTimers.get(`${event.taskId}:${toolName}`);
|
|
332
|
+
const elapsed = startTime ? ((Date.now() - startTime) / 1000).toFixed(3) + "s" : "";
|
|
333
|
+
toolTimers.delete(`${event.taskId}:${toolName}`);
|
|
334
|
+
|
|
335
|
+
const resultLines = colorizeJson(formatResult(event.result, 25));
|
|
336
|
+
const elapsedStr = elapsed ? c.dim + ` ⏱ ${elapsed}` + c.reset : "";
|
|
337
|
+
const headerLabel = `✓ ${toolName}${elapsedStr}`;
|
|
338
|
+
|
|
339
|
+
const boxStr = drawBox(resultLines, `✓ ${toolName} ${elapsed}`, c.brightGreen, Math.min(width, 100));
|
|
340
|
+
console.log(boxStr);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
private renderAgentMessage(event: AgentMessageEvent): void {
|
|
344
|
+
const width = termWidth();
|
|
345
|
+
const agentCol = agentColor(event.agentName);
|
|
346
|
+
|
|
347
|
+
if (event.role === "assistant") {
|
|
348
|
+
// Decorative separator with agent badge
|
|
349
|
+
const badge = ` ${agentCol}${c.bold} ${event.agentName} ${c.reset} `;
|
|
350
|
+
const badgeLen = stripAnsi(badge).length;
|
|
351
|
+
const lineLen = Math.min(width, 80);
|
|
352
|
+
const leftPad = 2;
|
|
353
|
+
const rightPad = Math.max(0, lineLen - leftPad - badgeLen);
|
|
354
|
+
|
|
355
|
+
const separator =
|
|
356
|
+
c.gray + box.tl + box.h.repeat(leftPad) + c.reset +
|
|
357
|
+
badge +
|
|
358
|
+
c.gray + box.h.repeat(rightPad) + box.tr + c.reset;
|
|
359
|
+
|
|
360
|
+
console.log("\n" + separator);
|
|
361
|
+
|
|
362
|
+
// Word-wrap the message at width - 4
|
|
363
|
+
const wrapWidth = Math.min(width - 4, 76);
|
|
364
|
+
const words = event.message.split(" ");
|
|
365
|
+
const wrappedLines: string[] = [];
|
|
366
|
+
let currentLine = "";
|
|
367
|
+
|
|
368
|
+
for (const word of words) {
|
|
369
|
+
if (currentLine.length + word.length + 1 > wrapWidth) {
|
|
370
|
+
if (currentLine) wrappedLines.push(currentLine);
|
|
371
|
+
currentLine = word;
|
|
372
|
+
} else {
|
|
373
|
+
currentLine = currentLine ? currentLine + " " + word : word;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
if (currentLine) wrappedLines.push(currentLine);
|
|
377
|
+
|
|
378
|
+
for (const line of wrappedLines) {
|
|
379
|
+
console.log(c.gray + box.v + c.reset + " " + c.brightWhite + line + c.reset);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const bottomSep = c.gray + box.bl + box.h.repeat(lineLen - 2) + box.br + c.reset;
|
|
383
|
+
console.log(bottomSep);
|
|
384
|
+
} else {
|
|
385
|
+
// User message (less common to render, but support it)
|
|
386
|
+
console.log(c.dim + " › " + c.reset + event.message);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
private renderAgentDone(event: AgentDoneEvent): void {
|
|
391
|
+
const width = termWidth();
|
|
392
|
+
const agentCol = agentColor(event.agentName);
|
|
393
|
+
|
|
394
|
+
const costStr = event.totalCost
|
|
395
|
+
? c.brightGreen + `$${event.totalCost.toFixed(4)}` + c.reset
|
|
396
|
+
: "";
|
|
397
|
+
|
|
398
|
+
const label = ` ${agentCol}${c.bold}✔ ${event.agentName} done${c.reset}${costStr ? " " + costStr : ""} `;
|
|
399
|
+
console.log("\n" + hRule(stripAnsi(label), agentCol, Math.min(width, 80)));
|
|
400
|
+
if (event.totalCost) {
|
|
401
|
+
console.log(
|
|
402
|
+
c.dim + " Total cost: " + c.reset +
|
|
403
|
+
c.brightGreen + `$${event.totalCost.toFixed(4)}` + c.reset
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
console.log("");
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
logMessages(events: RenderEvent[], count: number = 10): void {
|
|
410
|
+
const recent = events.slice(-count);
|
|
411
|
+
process.stdout.write(`\n[logs] Last ${recent.length} messages:\n`);
|
|
412
|
+
process.stdout.write("-".repeat(60) + "\n");
|
|
413
|
+
for (const event of recent) {
|
|
414
|
+
this.render(event);
|
|
415
|
+
}
|
|
416
|
+
process.stdout.write("-".repeat(60) + "\n");
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
export default FancyRenderer;
|