@tyvm/knowhow 0.0.83 → 0.0.85

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 (237) hide show
  1. package/package.json +4 -2
  2. package/src/agents/base/base.ts +72 -62
  3. package/src/agents/index.ts +30 -14
  4. package/src/agents/researcher/researcher.ts +1 -2
  5. package/src/agents/tools/aiClient.ts +48 -0
  6. package/src/agents/tools/list.ts +57 -0
  7. package/src/agents/tools/startAgentTask.ts +3 -1
  8. package/src/chat/CliChatService.ts +20 -4
  9. package/src/chat/modules/AgentModule.ts +399 -357
  10. package/src/chat/modules/CustomCommandsModule.ts +0 -1
  11. package/src/chat/modules/InternalChatModule.ts +18 -2
  12. package/src/chat/modules/RendererModule.ts +109 -0
  13. package/src/chat/modules/SessionsModule.ts +854 -0
  14. package/src/chat/modules/SetupModule.ts +6 -8
  15. package/src/chat/modules/index.ts +1 -0
  16. package/src/chat/renderer/CompactRenderer.ts +209 -0
  17. package/src/chat/renderer/ConsoleRenderer.ts +141 -0
  18. package/src/chat/renderer/FancyRenderer.ts +421 -0
  19. package/src/chat/renderer/index.ts +5 -0
  20. package/src/chat/renderer/loadRenderer.ts +314 -0
  21. package/src/chat/renderer/messagesToRenderEvents.ts +96 -0
  22. package/src/chat/renderer/types.ts +88 -0
  23. package/src/chat/types.ts +5 -0
  24. package/src/chat.ts +69 -5
  25. package/src/cli.ts +24 -5
  26. package/src/clients/index.ts +91 -0
  27. package/src/clients/pricing/google.ts +81 -2
  28. package/src/clients/pricing/openai.ts +68 -0
  29. package/src/config.ts +15 -0
  30. package/src/plugins/AgentsMdPlugin.ts +1 -1
  31. package/src/plugins/GitPlugin.ts +20 -20
  32. package/src/plugins/PluginBase.ts +11 -0
  33. package/src/plugins/SkillsPlugin.ts +150 -0
  34. package/src/plugins/asana.ts +4 -4
  35. package/src/plugins/embedding.ts +3 -5
  36. package/src/plugins/exec.ts +3 -3
  37. package/src/plugins/figma.ts +3 -7
  38. package/src/plugins/github.ts +18 -29
  39. package/src/plugins/jira.ts +2 -2
  40. package/src/plugins/language.ts +4 -4
  41. package/src/plugins/linear.ts +4 -4
  42. package/src/plugins/notion.ts +6 -8
  43. package/src/plugins/plugins.ts +29 -3
  44. package/src/plugins/url.ts +2 -2
  45. package/src/plugins/vim.ts +4 -3
  46. package/src/services/AgentService.ts +17 -0
  47. package/src/services/AgentSyncFs.ts +3 -0
  48. package/src/services/EventService.ts +168 -27
  49. package/src/services/KnowhowClient.ts +1 -0
  50. package/src/services/SessionManager.ts +51 -1
  51. package/src/services/SyncedAgentWatcher.ts +397 -0
  52. package/src/services/SyncerService.ts +147 -0
  53. package/src/services/index.ts +2 -0
  54. package/src/services/modules/index.ts +14 -3
  55. package/src/types.ts +103 -5
  56. package/src/worker.ts +80 -2
  57. package/src/workers/auth/PasskeySetup.ts +185 -0
  58. package/src/workers/auth/WorkerPasskeyAuth.ts +190 -0
  59. package/src/workers/auth/types.ts +58 -0
  60. package/src/workers/tools/getChallenge.ts +33 -0
  61. package/src/workers/tools/index.ts +8 -0
  62. package/src/workers/tools/lock.ts +31 -0
  63. package/src/workers/tools/unlock.ts +116 -0
  64. package/tests/clients/pricing.test.ts +144 -0
  65. package/tests/unit/modules/moduleLoading.test.ts +226 -0
  66. package/tests/unit/plugins/pluginLoading.test.ts +151 -0
  67. package/ts_build/package.json +4 -2
  68. package/ts_build/src/agents/base/base.d.ts +4 -3
  69. package/ts_build/src/agents/base/base.js +54 -30
  70. package/ts_build/src/agents/base/base.js.map +1 -1
  71. package/ts_build/src/agents/index.d.ts +3 -0
  72. package/ts_build/src/agents/index.js +21 -11
  73. package/ts_build/src/agents/index.js.map +1 -1
  74. package/ts_build/src/agents/researcher/researcher.js +1 -1
  75. package/ts_build/src/agents/researcher/researcher.js.map +1 -1
  76. package/ts_build/src/agents/tools/aiClient.d.ts +3 -0
  77. package/ts_build/src/agents/tools/aiClient.js +31 -1
  78. package/ts_build/src/agents/tools/aiClient.js.map +1 -1
  79. package/ts_build/src/agents/tools/list.js +48 -0
  80. package/ts_build/src/agents/tools/list.js.map +1 -1
  81. package/ts_build/src/agents/tools/startAgentTask.js +2 -1
  82. package/ts_build/src/agents/tools/startAgentTask.js.map +1 -1
  83. package/ts_build/src/chat/CliChatService.js +16 -5
  84. package/ts_build/src/chat/CliChatService.js.map +1 -1
  85. package/ts_build/src/chat/modules/AgentModule.d.ts +34 -17
  86. package/ts_build/src/chat/modules/AgentModule.js +248 -258
  87. package/ts_build/src/chat/modules/AgentModule.js.map +1 -1
  88. package/ts_build/src/chat/modules/CustomCommandsModule.js.map +1 -1
  89. package/ts_build/src/chat/modules/InternalChatModule.d.ts +3 -0
  90. package/ts_build/src/chat/modules/InternalChatModule.js +16 -1
  91. package/ts_build/src/chat/modules/InternalChatModule.js.map +1 -1
  92. package/ts_build/src/chat/modules/RendererModule.d.ts +16 -0
  93. package/ts_build/src/chat/modules/RendererModule.js +76 -0
  94. package/ts_build/src/chat/modules/RendererModule.js.map +1 -0
  95. package/ts_build/src/chat/modules/SessionsModule.d.ts +33 -0
  96. package/ts_build/src/chat/modules/SessionsModule.js +582 -0
  97. package/ts_build/src/chat/modules/SessionsModule.js.map +1 -0
  98. package/ts_build/src/chat/modules/SetupModule.d.ts +3 -3
  99. package/ts_build/src/chat/modules/SetupModule.js +4 -6
  100. package/ts_build/src/chat/modules/SetupModule.js.map +1 -1
  101. package/ts_build/src/chat/modules/index.d.ts +1 -0
  102. package/ts_build/src/chat/modules/index.js +3 -1
  103. package/ts_build/src/chat/modules/index.js.map +1 -1
  104. package/ts_build/src/chat/renderer/CompactRenderer.d.ts +23 -0
  105. package/ts_build/src/chat/renderer/CompactRenderer.js +167 -0
  106. package/ts_build/src/chat/renderer/CompactRenderer.js.map +1 -0
  107. package/ts_build/src/chat/renderer/ConsoleRenderer.d.ts +22 -0
  108. package/ts_build/src/chat/renderer/ConsoleRenderer.js +110 -0
  109. package/ts_build/src/chat/renderer/ConsoleRenderer.js.map +1 -0
  110. package/ts_build/src/chat/renderer/FancyRenderer.d.ts +23 -0
  111. package/ts_build/src/chat/renderer/FancyRenderer.js +328 -0
  112. package/ts_build/src/chat/renderer/FancyRenderer.js.map +1 -0
  113. package/ts_build/src/chat/renderer/index.d.ts +5 -0
  114. package/ts_build/src/chat/renderer/index.js +29 -0
  115. package/ts_build/src/chat/renderer/index.js.map +1 -0
  116. package/ts_build/src/chat/renderer/loadRenderer.d.ts +4 -0
  117. package/ts_build/src/chat/renderer/loadRenderer.js +246 -0
  118. package/ts_build/src/chat/renderer/loadRenderer.js.map +1 -0
  119. package/ts_build/src/chat/renderer/messagesToRenderEvents.d.ts +15 -0
  120. package/ts_build/src/chat/renderer/messagesToRenderEvents.js +72 -0
  121. package/ts_build/src/chat/renderer/messagesToRenderEvents.js.map +1 -0
  122. package/ts_build/src/chat/renderer/types.d.ts +75 -0
  123. package/ts_build/src/chat/renderer/types.js +3 -0
  124. package/ts_build/src/chat/renderer/types.js.map +1 -0
  125. package/ts_build/src/chat/types.d.ts +5 -0
  126. package/ts_build/src/chat.js +46 -4
  127. package/ts_build/src/chat.js.map +1 -1
  128. package/ts_build/src/cli.js +18 -5
  129. package/ts_build/src/cli.js.map +1 -1
  130. package/ts_build/src/clients/gemini.d.ts +10 -10
  131. package/ts_build/src/clients/index.d.ts +10 -0
  132. package/ts_build/src/clients/index.js +58 -0
  133. package/ts_build/src/clients/index.js.map +1 -1
  134. package/ts_build/src/clients/pricing/google.d.ts +10 -10
  135. package/ts_build/src/clients/pricing/google.js +74 -2
  136. package/ts_build/src/clients/pricing/google.js.map +1 -1
  137. package/ts_build/src/clients/pricing/openai.js +65 -0
  138. package/ts_build/src/clients/pricing/openai.js.map +1 -1
  139. package/ts_build/src/config.d.ts +1 -0
  140. package/ts_build/src/config.js +17 -1
  141. package/ts_build/src/config.js.map +1 -1
  142. package/ts_build/src/plugins/AgentsMdPlugin.js +1 -1
  143. package/ts_build/src/plugins/AgentsMdPlugin.js.map +1 -1
  144. package/ts_build/src/plugins/GitPlugin.js +20 -20
  145. package/ts_build/src/plugins/GitPlugin.js.map +1 -1
  146. package/ts_build/src/plugins/PluginBase.d.ts +1 -0
  147. package/ts_build/src/plugins/PluginBase.js +13 -0
  148. package/ts_build/src/plugins/PluginBase.js.map +1 -1
  149. package/ts_build/src/plugins/SkillsPlugin.d.ts +13 -0
  150. package/ts_build/src/plugins/SkillsPlugin.js +149 -0
  151. package/ts_build/src/plugins/SkillsPlugin.js.map +1 -0
  152. package/ts_build/src/plugins/asana.js +4 -4
  153. package/ts_build/src/plugins/asana.js.map +1 -1
  154. package/ts_build/src/plugins/embedding.js +3 -3
  155. package/ts_build/src/plugins/embedding.js.map +1 -1
  156. package/ts_build/src/plugins/exec.js +3 -3
  157. package/ts_build/src/plugins/exec.js.map +1 -1
  158. package/ts_build/src/plugins/figma.js +3 -3
  159. package/ts_build/src/plugins/figma.js.map +1 -1
  160. package/ts_build/src/plugins/github.js +18 -18
  161. package/ts_build/src/plugins/github.js.map +1 -1
  162. package/ts_build/src/plugins/jira.js +2 -2
  163. package/ts_build/src/plugins/jira.js.map +1 -1
  164. package/ts_build/src/plugins/language.js +4 -4
  165. package/ts_build/src/plugins/language.js.map +1 -1
  166. package/ts_build/src/plugins/linear.js +4 -4
  167. package/ts_build/src/plugins/linear.js.map +1 -1
  168. package/ts_build/src/plugins/notion.js +6 -6
  169. package/ts_build/src/plugins/notion.js.map +1 -1
  170. package/ts_build/src/plugins/plugins.d.ts +3 -0
  171. package/ts_build/src/plugins/plugins.js +18 -3
  172. package/ts_build/src/plugins/plugins.js.map +1 -1
  173. package/ts_build/src/plugins/url.js +2 -2
  174. package/ts_build/src/plugins/url.js.map +1 -1
  175. package/ts_build/src/plugins/vim.js +2 -2
  176. package/ts_build/src/plugins/vim.js.map +1 -1
  177. package/ts_build/src/services/AgentService.d.ts +3 -0
  178. package/ts_build/src/services/AgentService.js +7 -0
  179. package/ts_build/src/services/AgentService.js.map +1 -1
  180. package/ts_build/src/services/AgentSyncFs.d.ts +1 -0
  181. package/ts_build/src/services/AgentSyncFs.js +2 -0
  182. package/ts_build/src/services/AgentSyncFs.js.map +1 -1
  183. package/ts_build/src/services/EventService.d.ts +25 -2
  184. package/ts_build/src/services/EventService.js +92 -14
  185. package/ts_build/src/services/EventService.js.map +1 -1
  186. package/ts_build/src/services/KnowhowClient.d.ts +1 -0
  187. package/ts_build/src/services/KnowhowClient.js.map +1 -1
  188. package/ts_build/src/services/SessionManager.d.ts +6 -0
  189. package/ts_build/src/services/SessionManager.js +39 -1
  190. package/ts_build/src/services/SessionManager.js.map +1 -1
  191. package/ts_build/src/services/SyncedAgentWatcher.d.ts +101 -0
  192. package/ts_build/src/services/SyncedAgentWatcher.js +312 -0
  193. package/ts_build/src/services/SyncedAgentWatcher.js.map +1 -0
  194. package/ts_build/src/services/SyncerService.d.ts +30 -0
  195. package/ts_build/src/services/SyncerService.js +72 -0
  196. package/ts_build/src/services/SyncerService.js.map +1 -0
  197. package/ts_build/src/services/index.d.ts +2 -0
  198. package/ts_build/src/services/index.js +2 -0
  199. package/ts_build/src/services/index.js.map +1 -1
  200. package/ts_build/src/services/modules/index.js +10 -2
  201. package/ts_build/src/services/modules/index.js.map +1 -1
  202. package/ts_build/src/types.d.ts +51 -2
  203. package/ts_build/src/types.js +73 -5
  204. package/ts_build/src/types.js.map +1 -1
  205. package/ts_build/src/worker.d.ts +2 -0
  206. package/ts_build/src/worker.js +59 -4
  207. package/ts_build/src/worker.js.map +1 -1
  208. package/ts_build/src/workers/auth/PasskeySetup.d.ts +10 -0
  209. package/ts_build/src/workers/auth/PasskeySetup.js +131 -0
  210. package/ts_build/src/workers/auth/PasskeySetup.js.map +1 -0
  211. package/ts_build/src/workers/auth/WorkerPasskeyAuth.d.ts +35 -0
  212. package/ts_build/src/workers/auth/WorkerPasskeyAuth.js +129 -0
  213. package/ts_build/src/workers/auth/WorkerPasskeyAuth.js.map +1 -0
  214. package/ts_build/src/workers/auth/types.d.ts +36 -0
  215. package/ts_build/src/workers/auth/types.js +3 -0
  216. package/ts_build/src/workers/auth/types.js.map +1 -0
  217. package/ts_build/src/workers/tools/getChallenge.d.ts +9 -0
  218. package/ts_build/src/workers/tools/getChallenge.js +27 -0
  219. package/ts_build/src/workers/tools/getChallenge.js.map +1 -0
  220. package/ts_build/src/workers/tools/index.d.ts +6 -0
  221. package/ts_build/src/workers/tools/index.js +10 -0
  222. package/ts_build/src/workers/tools/index.js.map +1 -1
  223. package/ts_build/src/workers/tools/lock.d.ts +9 -0
  224. package/ts_build/src/workers/tools/lock.js +27 -0
  225. package/ts_build/src/workers/tools/lock.js.map +1 -0
  226. package/ts_build/src/workers/tools/unlock.d.ts +18 -0
  227. package/ts_build/src/workers/tools/unlock.js +78 -0
  228. package/ts_build/src/workers/tools/unlock.js.map +1 -0
  229. package/ts_build/tests/clients/pricing.test.d.ts +1 -0
  230. package/ts_build/tests/clients/pricing.test.js +90 -0
  231. package/ts_build/tests/clients/pricing.test.js.map +1 -0
  232. package/ts_build/tests/unit/modules/moduleLoading.test.d.ts +1 -0
  233. package/ts_build/tests/unit/modules/moduleLoading.test.js +187 -0
  234. package/ts_build/tests/unit/modules/moduleLoading.test.js.map +1 -0
  235. package/ts_build/tests/unit/plugins/pluginLoading.test.d.ts +1 -0
  236. package/ts_build/tests/unit/plugins/pluginLoading.test.js +123 -0
  237. 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;
@@ -0,0 +1,5 @@
1
+ export * from "./types";
2
+ export { ConsoleRenderer } from "./ConsoleRenderer";
3
+ export { FancyRenderer } from "./FancyRenderer";
4
+ export { CompactRenderer } from "./CompactRenderer";
5
+ export { loadRenderer, loadRootModule, loadChatModule } from "./loadRenderer";