agent-world 0.11.1 → 0.12.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 (267) hide show
  1. package/README.md +17 -7
  2. package/dist/cli/commands.d.ts +109 -0
  3. package/dist/cli/commands.js +2024 -0
  4. package/dist/cli/display.d.ts +124 -0
  5. package/dist/cli/display.js +381 -0
  6. package/dist/cli/hitl.d.ts +33 -0
  7. package/dist/cli/hitl.js +81 -0
  8. package/dist/cli/index.d.ts +2 -0
  9. package/dist/cli/stream.d.ts +41 -0
  10. package/dist/cli/stream.js +222 -0
  11. package/dist/core/activity-tracker.d.ts +16 -0
  12. package/dist/core/activity-tracker.d.ts.map +1 -0
  13. package/dist/core/activity-tracker.js +91 -0
  14. package/dist/core/activity-tracker.js.map +1 -0
  15. package/dist/core/ai-commands.d.ts +16 -0
  16. package/dist/core/ai-commands.d.ts.map +1 -0
  17. package/dist/core/ai-commands.js +24 -0
  18. package/dist/core/ai-commands.js.map +1 -0
  19. package/dist/core/ai-sdk-patch.d.ts +24 -0
  20. package/dist/core/ai-sdk-patch.d.ts.map +1 -0
  21. package/dist/core/ai-sdk-patch.js +169 -0
  22. package/dist/core/ai-sdk-patch.js.map +1 -0
  23. package/dist/core/anthropic-direct.d.ts +52 -0
  24. package/dist/core/anthropic-direct.d.ts.map +1 -0
  25. package/dist/core/anthropic-direct.js +301 -0
  26. package/dist/core/anthropic-direct.js.map +1 -0
  27. package/dist/core/approval-cache.d.ts +104 -0
  28. package/dist/core/approval-cache.d.ts.map +1 -0
  29. package/dist/core/approval-cache.js +150 -0
  30. package/dist/core/approval-cache.js.map +1 -0
  31. package/dist/core/chat-constants.d.ts +20 -0
  32. package/dist/core/chat-constants.d.ts.map +1 -0
  33. package/dist/core/chat-constants.js +22 -0
  34. package/dist/core/chat-constants.js.map +1 -0
  35. package/dist/core/create-agent-tool.d.ts +66 -0
  36. package/dist/core/create-agent-tool.d.ts.map +1 -0
  37. package/dist/core/create-agent-tool.js +212 -0
  38. package/dist/core/create-agent-tool.js.map +1 -0
  39. package/dist/core/events/approval-checker.d.ts +61 -0
  40. package/dist/core/events/approval-checker.d.ts.map +1 -0
  41. package/dist/core/events/approval-checker.js +226 -0
  42. package/dist/core/events/approval-checker.js.map +1 -0
  43. package/dist/core/events/index.d.ts +25 -0
  44. package/dist/core/events/index.d.ts.map +1 -0
  45. package/dist/core/events/index.js +30 -0
  46. package/dist/core/events/index.js.map +1 -0
  47. package/dist/core/events/memory-manager.d.ts +73 -0
  48. package/dist/core/events/memory-manager.d.ts.map +1 -0
  49. package/dist/core/events/memory-manager.js +1218 -0
  50. package/dist/core/events/memory-manager.js.map +1 -0
  51. package/dist/core/events/mention-logic.d.ts +39 -0
  52. package/dist/core/events/mention-logic.d.ts.map +1 -0
  53. package/dist/core/events/mention-logic.js +163 -0
  54. package/dist/core/events/mention-logic.js.map +1 -0
  55. package/dist/core/events/orchestrator.d.ts +69 -0
  56. package/dist/core/events/orchestrator.d.ts.map +1 -0
  57. package/dist/core/events/orchestrator.js +883 -0
  58. package/dist/core/events/orchestrator.js.map +1 -0
  59. package/dist/core/events/persistence.d.ts +41 -0
  60. package/dist/core/events/persistence.d.ts.map +1 -0
  61. package/dist/core/events/persistence.js +296 -0
  62. package/dist/core/events/persistence.js.map +1 -0
  63. package/dist/core/events/publishers.d.ts +81 -0
  64. package/dist/core/events/publishers.d.ts.map +1 -0
  65. package/dist/core/events/publishers.js +272 -0
  66. package/dist/core/events/publishers.js.map +1 -0
  67. package/dist/core/events/subscribers.d.ts +45 -0
  68. package/dist/core/events/subscribers.d.ts.map +1 -0
  69. package/dist/core/events/subscribers.js +288 -0
  70. package/dist/core/events/subscribers.js.map +1 -0
  71. package/dist/core/events/tool-bridge-logging.d.ts +28 -0
  72. package/dist/core/events/tool-bridge-logging.d.ts.map +1 -0
  73. package/dist/core/events/tool-bridge-logging.js +94 -0
  74. package/dist/core/events/tool-bridge-logging.js.map +1 -0
  75. package/dist/core/events-metadata.d.ts +72 -0
  76. package/dist/core/events-metadata.d.ts.map +1 -0
  77. package/dist/core/events-metadata.js +167 -0
  78. package/dist/core/events-metadata.js.map +1 -0
  79. package/dist/core/events.d.ts +186 -0
  80. package/dist/core/events.d.ts.map +1 -0
  81. package/dist/core/events.js +1248 -0
  82. package/dist/core/events.js.map +1 -0
  83. package/dist/core/export.d.ts +106 -0
  84. package/dist/core/export.d.ts.map +1 -0
  85. package/dist/core/export.js +705 -0
  86. package/dist/core/export.js.map +1 -0
  87. package/dist/core/file-tools.d.ts +114 -0
  88. package/dist/core/file-tools.d.ts.map +1 -0
  89. package/dist/core/file-tools.js +370 -0
  90. package/dist/core/file-tools.js.map +1 -0
  91. package/dist/core/google-direct.d.ts +58 -0
  92. package/dist/core/google-direct.d.ts.map +1 -0
  93. package/dist/core/google-direct.js +298 -0
  94. package/dist/core/google-direct.js.map +1 -0
  95. package/dist/core/hitl.d.ts +54 -0
  96. package/dist/core/hitl.d.ts.map +1 -0
  97. package/dist/core/hitl.js +153 -0
  98. package/dist/core/hitl.js.map +1 -0
  99. package/dist/core/index.d.ts +59 -0
  100. package/dist/core/index.d.ts.map +1 -0
  101. package/dist/core/index.js +70 -0
  102. package/dist/core/index.js.map +1 -0
  103. package/dist/core/llm-config.d.ts +128 -0
  104. package/dist/core/llm-config.d.ts.map +1 -0
  105. package/dist/core/llm-config.js +164 -0
  106. package/dist/core/llm-config.js.map +1 -0
  107. package/dist/core/llm-manager.d.ts +163 -0
  108. package/dist/core/llm-manager.d.ts.map +1 -0
  109. package/dist/core/llm-manager.js +669 -0
  110. package/dist/core/llm-manager.js.map +1 -0
  111. package/dist/core/load-skill-tool.d.ts +55 -0
  112. package/dist/core/load-skill-tool.d.ts.map +1 -0
  113. package/dist/core/load-skill-tool.js +468 -0
  114. package/dist/core/load-skill-tool.js.map +1 -0
  115. package/dist/core/logger.d.ts +88 -0
  116. package/dist/core/logger.d.ts.map +1 -0
  117. package/dist/core/logger.js +358 -0
  118. package/dist/core/logger.js.map +1 -0
  119. package/dist/core/managers.d.ts +131 -0
  120. package/dist/core/managers.d.ts.map +1 -0
  121. package/dist/core/managers.js +1223 -0
  122. package/dist/core/managers.js.map +1 -0
  123. package/dist/core/mcp-server-registry.d.ts +304 -0
  124. package/dist/core/mcp-server-registry.d.ts.map +1 -0
  125. package/dist/core/mcp-server-registry.js +1769 -0
  126. package/dist/core/mcp-server-registry.js.map +1 -0
  127. package/dist/core/mcp-tools.d.ts +56 -0
  128. package/dist/core/mcp-tools.d.ts.map +1 -0
  129. package/dist/core/mcp-tools.js +186 -0
  130. package/dist/core/mcp-tools.js.map +1 -0
  131. package/dist/core/message-prep.d.ts +81 -0
  132. package/dist/core/message-prep.d.ts.map +1 -0
  133. package/dist/core/message-prep.js +223 -0
  134. package/dist/core/message-prep.js.map +1 -0
  135. package/dist/core/message-processing-control.d.ts +54 -0
  136. package/dist/core/message-processing-control.d.ts.map +1 -0
  137. package/dist/core/message-processing-control.js +139 -0
  138. package/dist/core/message-processing-control.js.map +1 -0
  139. package/dist/core/openai-direct.d.ts +80 -0
  140. package/dist/core/openai-direct.d.ts.map +1 -0
  141. package/dist/core/openai-direct.js +374 -0
  142. package/dist/core/openai-direct.js.map +1 -0
  143. package/dist/core/shell-cmd-tool.d.ts +235 -0
  144. package/dist/core/shell-cmd-tool.d.ts.map +1 -0
  145. package/dist/core/shell-cmd-tool.js +1157 -0
  146. package/dist/core/shell-cmd-tool.js.map +1 -0
  147. package/dist/core/shell-process-registry.d.ts +88 -0
  148. package/dist/core/shell-process-registry.d.ts.map +1 -0
  149. package/dist/core/shell-process-registry.js +309 -0
  150. package/dist/core/shell-process-registry.js.map +1 -0
  151. package/dist/core/skill-registry.d.ts +75 -0
  152. package/dist/core/skill-registry.d.ts.map +1 -0
  153. package/dist/core/skill-registry.js +369 -0
  154. package/dist/core/skill-registry.js.map +1 -0
  155. package/dist/core/skill-script-runner.d.ts +89 -0
  156. package/dist/core/skill-script-runner.d.ts.map +1 -0
  157. package/dist/core/skill-script-runner.js +274 -0
  158. package/dist/core/skill-script-runner.js.map +1 -0
  159. package/dist/core/skill-selector.d.ts +65 -0
  160. package/dist/core/skill-selector.d.ts.map +1 -0
  161. package/dist/core/skill-selector.js +190 -0
  162. package/dist/core/skill-selector.js.map +1 -0
  163. package/dist/core/skill-settings.d.ts +20 -0
  164. package/dist/core/skill-settings.d.ts.map +1 -0
  165. package/dist/core/skill-settings.js +40 -0
  166. package/dist/core/skill-settings.js.map +1 -0
  167. package/dist/core/storage/agent-storage.d.ts +134 -0
  168. package/dist/core/storage/agent-storage.d.ts.map +1 -0
  169. package/dist/core/storage/agent-storage.js +498 -0
  170. package/dist/core/storage/agent-storage.js.map +1 -0
  171. package/dist/core/storage/eventStorage/fileEventStorage.d.ts +100 -0
  172. package/dist/core/storage/eventStorage/fileEventStorage.d.ts.map +1 -0
  173. package/dist/core/storage/eventStorage/fileEventStorage.js +494 -0
  174. package/dist/core/storage/eventStorage/fileEventStorage.js.map +1 -0
  175. package/dist/core/storage/eventStorage/index.d.ts +31 -0
  176. package/dist/core/storage/eventStorage/index.d.ts.map +1 -0
  177. package/dist/core/storage/eventStorage/index.js +31 -0
  178. package/dist/core/storage/eventStorage/index.js.map +1 -0
  179. package/dist/core/storage/eventStorage/memoryEventStorage.d.ts +87 -0
  180. package/dist/core/storage/eventStorage/memoryEventStorage.d.ts.map +1 -0
  181. package/dist/core/storage/eventStorage/memoryEventStorage.js +244 -0
  182. package/dist/core/storage/eventStorage/memoryEventStorage.js.map +1 -0
  183. package/dist/core/storage/eventStorage/sqliteEventStorage.d.ts +45 -0
  184. package/dist/core/storage/eventStorage/sqliteEventStorage.d.ts.map +1 -0
  185. package/dist/core/storage/eventStorage/sqliteEventStorage.js +301 -0
  186. package/dist/core/storage/eventStorage/sqliteEventStorage.js.map +1 -0
  187. package/dist/core/storage/eventStorage/types.d.ts +142 -0
  188. package/dist/core/storage/eventStorage/types.d.ts.map +1 -0
  189. package/dist/core/storage/eventStorage/types.js +43 -0
  190. package/dist/core/storage/eventStorage/types.js.map +1 -0
  191. package/dist/core/storage/eventStorage/validation.d.ts +30 -0
  192. package/dist/core/storage/eventStorage/validation.d.ts.map +1 -0
  193. package/dist/core/storage/eventStorage/validation.js +68 -0
  194. package/dist/core/storage/eventStorage/validation.js.map +1 -0
  195. package/dist/core/storage/legacy-migrations.d.ts +45 -0
  196. package/dist/core/storage/legacy-migrations.d.ts.map +1 -0
  197. package/dist/core/storage/legacy-migrations.js +295 -0
  198. package/dist/core/storage/legacy-migrations.js.map +1 -0
  199. package/dist/core/storage/memory-storage.d.ts +105 -0
  200. package/dist/core/storage/memory-storage.d.ts.map +1 -0
  201. package/dist/core/storage/memory-storage.js +415 -0
  202. package/dist/core/storage/memory-storage.js.map +1 -0
  203. package/dist/core/storage/migration-runner.d.ts +96 -0
  204. package/dist/core/storage/migration-runner.d.ts.map +1 -0
  205. package/dist/core/storage/migration-runner.js +306 -0
  206. package/dist/core/storage/migration-runner.js.map +1 -0
  207. package/dist/core/storage/queue-storage.d.ts +147 -0
  208. package/dist/core/storage/queue-storage.d.ts.map +1 -0
  209. package/dist/core/storage/queue-storage.js +290 -0
  210. package/dist/core/storage/queue-storage.js.map +1 -0
  211. package/dist/core/storage/skill-storage.d.ts +136 -0
  212. package/dist/core/storage/skill-storage.d.ts.map +1 -0
  213. package/dist/core/storage/skill-storage.js +474 -0
  214. package/dist/core/storage/skill-storage.js.map +1 -0
  215. package/dist/core/storage/sqlite-schema.d.ts +95 -0
  216. package/dist/core/storage/sqlite-schema.d.ts.map +1 -0
  217. package/dist/core/storage/sqlite-schema.js +156 -0
  218. package/dist/core/storage/sqlite-schema.js.map +1 -0
  219. package/dist/core/storage/sqlite-storage.d.ts +146 -0
  220. package/dist/core/storage/sqlite-storage.d.ts.map +1 -0
  221. package/dist/core/storage/sqlite-storage.js +709 -0
  222. package/dist/core/storage/sqlite-storage.js.map +1 -0
  223. package/dist/core/storage/storage-factory.d.ts +61 -0
  224. package/dist/core/storage/storage-factory.d.ts.map +1 -0
  225. package/dist/core/storage/storage-factory.js +794 -0
  226. package/dist/core/storage/storage-factory.js.map +1 -0
  227. package/dist/core/storage/validation.d.ts +36 -0
  228. package/dist/core/storage/validation.d.ts.map +1 -0
  229. package/dist/core/storage/validation.js +79 -0
  230. package/dist/core/storage/validation.js.map +1 -0
  231. package/dist/core/storage/world-storage.d.ts +114 -0
  232. package/dist/core/storage/world-storage.d.ts.map +1 -0
  233. package/dist/core/storage/world-storage.js +378 -0
  234. package/dist/core/storage/world-storage.js.map +1 -0
  235. package/dist/core/subscription.d.ts +43 -0
  236. package/dist/core/subscription.d.ts.map +1 -0
  237. package/dist/core/subscription.js +227 -0
  238. package/dist/core/subscription.js.map +1 -0
  239. package/dist/core/tool-utils.d.ts +80 -0
  240. package/dist/core/tool-utils.d.ts.map +1 -0
  241. package/dist/core/tool-utils.js +273 -0
  242. package/dist/core/tool-utils.js.map +1 -0
  243. package/dist/core/types.d.ts +595 -0
  244. package/dist/core/types.d.ts.map +1 -0
  245. package/dist/core/types.js +158 -0
  246. package/dist/core/types.js.map +1 -0
  247. package/dist/core/utils.d.ts +138 -0
  248. package/dist/core/utils.d.ts.map +1 -0
  249. package/dist/core/utils.js +478 -0
  250. package/dist/core/utils.js.map +1 -0
  251. package/dist/core/world-class.d.ts +43 -0
  252. package/dist/core/world-class.d.ts.map +1 -0
  253. package/dist/core/world-class.js +90 -0
  254. package/dist/core/world-class.js.map +1 -0
  255. package/dist/index.d.ts +18 -0
  256. package/dist/public/assets/agent-sprites-DJFgj-zP.png +0 -0
  257. package/dist/public/assets/border-KHK37r8y.svg +83 -0
  258. package/dist/public/assets/index-C9kPXL6G.css +1 -0
  259. package/dist/public/assets/index-DOQEHGWt.js +96 -0
  260. package/dist/public/index.html +21 -0
  261. package/dist/server/api.d.ts +2 -0
  262. package/dist/server/api.js +1124 -0
  263. package/dist/server/index.d.ts +29 -0
  264. package/dist/server/sse-handler.d.ts +62 -0
  265. package/dist/server/sse-handler.js +234 -0
  266. package/package.json +15 -3
  267. package/scripts/launch-electron.js +0 -58
@@ -0,0 +1,124 @@
1
+ /**
2
+ * CLI Display Module — Formatting Utilities, Spinner, and Status Line Manager
3
+ *
4
+ * Provides terminal display primitives for the CLI interactive mode, inspired
5
+ * by the Electron desktop app UX patterns. All display logic is centralized
6
+ * here so that `index.ts` handles event routing and `stream.ts` handles
7
+ * streaming data management.
8
+ *
9
+ * FEATURES:
10
+ * - Pure formatting functions: tool names, elapsed time, tool icons, truncation
11
+ * - Braille spinner with configurable label
12
+ * - Unified status line manager combining spinner, elapsed timer, agent queue,
13
+ * and active tools on a single rewritable terminal line
14
+ * - Readline coordination via pause/resume to avoid prompt corruption
15
+ *
16
+ * NOTES:
17
+ * - Leaf module with no internal project imports (only Node built-ins)
18
+ * - All side-effectful output uses process.stdout.write (no console.log)
19
+ * - Unicode symbols chosen for consistent terminal width (no emoji)
20
+ *
21
+ * CHANGES:
22
+ * - 2026-02-11: Initial creation — Phase 1-3 of CLI UX improvement plan
23
+ */
24
+ /** Entry describing an active or completed tool in the status line. */
25
+ export interface ToolDisplayEntry {
26
+ name: string;
27
+ status: 'running' | 'done' | 'error';
28
+ detail?: string;
29
+ }
30
+ /** Entry describing an agent in the status line. */
31
+ export interface AgentDisplayEntry {
32
+ name: string;
33
+ active: boolean;
34
+ }
35
+ /** Full snapshot of what the status line should render. */
36
+ export interface StatusLineState {
37
+ spinner: {
38
+ label: string;
39
+ active: boolean;
40
+ };
41
+ elapsedMs: number;
42
+ agents: AgentDisplayEntry[];
43
+ tools: ToolDisplayEntry[];
44
+ }
45
+ /**
46
+ * Convert a tool name from snake_case / camelCase to Title Case for display.
47
+ *
48
+ * Examples:
49
+ * read_file → Read File
50
+ * shell_cmd → Shell Cmd
51
+ * searchAndReplace → Search And Replace
52
+ * listDir → List Dir
53
+ */
54
+ export declare function formatToolName(toolName: string): string;
55
+ /**
56
+ * Format elapsed milliseconds as a human-readable duration string.
57
+ *
58
+ * Examples:
59
+ * 0 → 0:00
60
+ * 5000 → 0:05
61
+ * 65000 → 1:05
62
+ * 3661000 → 1:01:01
63
+ */
64
+ export declare function formatElapsed(ms: number): string;
65
+ /**
66
+ * Return a Unicode icon for a tool based on its name pattern.
67
+ *
68
+ * Uses fixed-width Unicode symbols (not emoji) for consistent terminal rendering.
69
+ */
70
+ export declare function getToolIcon(toolName: string): string;
71
+ /**
72
+ * Truncate a string to fit within `maxWidth` columns, appending "…" if trimmed.
73
+ *
74
+ * Uses simple character count (not full Unicode width detection) which is
75
+ * correct for the fixed-width symbols we use in the status line.
76
+ */
77
+ export declare function truncateToWidth(text: string, maxWidth: number): string;
78
+ export interface Spinner {
79
+ start: (label: string) => void;
80
+ stop: () => void;
81
+ isRunning: () => boolean;
82
+ cleanup: () => void;
83
+ }
84
+ /**
85
+ * Create a braille-character spinner that writes to a single rewritable line.
86
+ *
87
+ * The spinner renders frame + label via `process.stdout.write('\r\x1b[K…')`
88
+ * at 80 ms intervals. Calling `stop()` clears the line. `cleanup()` is an
89
+ * alias for `stop()` that also nullifies internal references.
90
+ */
91
+ export declare function createSpinner(): Spinner;
92
+ export interface StatusLineManager {
93
+ setSpinner: (label: string | null) => void;
94
+ setElapsed: (ms: number) => void;
95
+ setAgents: (agents: AgentDisplayEntry[]) => void;
96
+ addTool: (name: string) => void;
97
+ removeTool: (name: string, status: 'done' | 'error', detail?: string) => void;
98
+ render: () => void;
99
+ clear: () => void;
100
+ pause: () => void;
101
+ resume: () => void;
102
+ startElapsedTimer: () => void;
103
+ stopElapsedTimer: () => void;
104
+ reset: () => void;
105
+ cleanup: () => void;
106
+ }
107
+ /**
108
+ * Create a unified status line manager that composes spinner, elapsed time,
109
+ * agent queue, and active tools into a single rewritable terminal line.
110
+ *
111
+ * Status line format example:
112
+ * ⠋ AgentA is thinking... [0:12] | ▸ Read File ⟳
113
+ *
114
+ * Supports pause/resume for readline prompt coordination: pause clears the
115
+ * status line so `console.log()` or `rl.prompt()` output is clean, resume
116
+ * redraws it.
117
+ */
118
+ export declare function createStatusLineManager(): StatusLineManager;
119
+ /**
120
+ * Print permanent output while preserving the status line.
121
+ *
122
+ * Usage: `log(statusLine, 'Hello', someVar)` instead of `console.log(...)`.
123
+ */
124
+ export declare function log(statusLine: StatusLineManager, ...args: unknown[]): void;
@@ -0,0 +1,381 @@
1
+ /**
2
+ * CLI Display Module — Formatting Utilities, Spinner, and Status Line Manager
3
+ *
4
+ * Provides terminal display primitives for the CLI interactive mode, inspired
5
+ * by the Electron desktop app UX patterns. All display logic is centralized
6
+ * here so that `index.ts` handles event routing and `stream.ts` handles
7
+ * streaming data management.
8
+ *
9
+ * FEATURES:
10
+ * - Pure formatting functions: tool names, elapsed time, tool icons, truncation
11
+ * - Braille spinner with configurable label
12
+ * - Unified status line manager combining spinner, elapsed timer, agent queue,
13
+ * and active tools on a single rewritable terminal line
14
+ * - Readline coordination via pause/resume to avoid prompt corruption
15
+ *
16
+ * NOTES:
17
+ * - Leaf module with no internal project imports (only Node built-ins)
18
+ * - All side-effectful output uses process.stdout.write (no console.log)
19
+ * - Unicode symbols chosen for consistent terminal width (no emoji)
20
+ *
21
+ * CHANGES:
22
+ * - 2026-02-11: Initial creation — Phase 1-3 of CLI UX improvement plan
23
+ */
24
+ // ---------------------------------------------------------------------------
25
+ // Color helpers (duplicated here to keep display.ts a leaf module)
26
+ // ---------------------------------------------------------------------------
27
+ const gray = (text) => `\x1b[90m${text}\x1b[0m`;
28
+ const cyan = (text) => `\x1b[36m${text}\x1b[0m`;
29
+ const yellow = (text) => `\x1b[33m${text}\x1b[0m`;
30
+ const green = (text) => `\x1b[32m${text}\x1b[0m`;
31
+ const red = (text) => `\x1b[31m${text}\x1b[0m`;
32
+ const bold = (text) => `\x1b[1m${text}\x1b[0m`;
33
+ const boldGreen = (text) => `\x1b[1m\x1b[32m${text}\x1b[0m`;
34
+ // ---------------------------------------------------------------------------
35
+ // Phase 1 — Pure Formatting Functions
36
+ // ---------------------------------------------------------------------------
37
+ /**
38
+ * Convert a tool name from snake_case / camelCase to Title Case for display.
39
+ *
40
+ * Examples:
41
+ * read_file → Read File
42
+ * shell_cmd → Shell Cmd
43
+ * searchAndReplace → Search And Replace
44
+ * listDir → List Dir
45
+ */
46
+ export function formatToolName(toolName) {
47
+ if (!toolName)
48
+ return '';
49
+ // Split on underscores and camelCase boundaries
50
+ const words = toolName
51
+ .replace(/_/g, ' ')
52
+ .replace(/([a-z])([A-Z])/g, '$1 $2')
53
+ .split(/\s+/)
54
+ .filter(Boolean);
55
+ return words
56
+ .map(w => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())
57
+ .join(' ');
58
+ }
59
+ /**
60
+ * Format elapsed milliseconds as a human-readable duration string.
61
+ *
62
+ * Examples:
63
+ * 0 → 0:00
64
+ * 5000 → 0:05
65
+ * 65000 → 1:05
66
+ * 3661000 → 1:01:01
67
+ */
68
+ export function formatElapsed(ms) {
69
+ if (ms < 0)
70
+ ms = 0;
71
+ const totalSeconds = Math.floor(ms / 1000);
72
+ const hours = Math.floor(totalSeconds / 3600);
73
+ const minutes = Math.floor((totalSeconds % 3600) / 60);
74
+ const seconds = totalSeconds % 60;
75
+ const pad = (n) => n.toString().padStart(2, '0');
76
+ if (hours > 0) {
77
+ return `${hours}:${pad(minutes)}:${pad(seconds)}`;
78
+ }
79
+ return `${minutes}:${pad(seconds)}`;
80
+ }
81
+ /**
82
+ * Return a Unicode icon for a tool based on its name pattern.
83
+ *
84
+ * Uses fixed-width Unicode symbols (not emoji) for consistent terminal rendering.
85
+ */
86
+ export function getToolIcon(toolName) {
87
+ const lower = toolName.toLowerCase();
88
+ // More specific patterns first to avoid false matches
89
+ if (lower.includes('write') || lower.includes('create') || lower.includes('edit') || lower.includes('save'))
90
+ return '▹';
91
+ if (lower.includes('delete') || lower.includes('remove'))
92
+ return '✕';
93
+ if (lower.includes('move') || lower.includes('rename') || lower.includes('copy'))
94
+ return '↔';
95
+ if (lower.includes('shell') || lower.includes('exec') || lower.includes('run') || lower.includes('cmd'))
96
+ return '⚡';
97
+ if (lower.includes('search') || lower.includes('find') || lower.includes('grep') || lower.includes('list'))
98
+ return '◈';
99
+ if (lower.includes('web') || lower.includes('fetch') || lower.includes('http') || lower.includes('url'))
100
+ return '◇';
101
+ if (lower.includes('read') || lower.includes('file') || lower.includes('cat'))
102
+ return '▸';
103
+ return '●';
104
+ }
105
+ /**
106
+ * Truncate a string to fit within `maxWidth` columns, appending "…" if trimmed.
107
+ *
108
+ * Uses simple character count (not full Unicode width detection) which is
109
+ * correct for the fixed-width symbols we use in the status line.
110
+ */
111
+ export function truncateToWidth(text, maxWidth) {
112
+ if (maxWidth <= 0)
113
+ return '';
114
+ if (text.length <= maxWidth)
115
+ return text;
116
+ if (maxWidth <= 1)
117
+ return '…';
118
+ return text.slice(0, maxWidth - 1) + '…';
119
+ }
120
+ // ---------------------------------------------------------------------------
121
+ // Phase 2 — Spinner Factory
122
+ // ---------------------------------------------------------------------------
123
+ const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
124
+ const SPINNER_INTERVAL_MS = 80;
125
+ /**
126
+ * Create a braille-character spinner that writes to a single rewritable line.
127
+ *
128
+ * The spinner renders frame + label via `process.stdout.write('\r\x1b[K…')`
129
+ * at 80 ms intervals. Calling `stop()` clears the line. `cleanup()` is an
130
+ * alias for `stop()` that also nullifies internal references.
131
+ */
132
+ export function createSpinner() {
133
+ let frameIndex = 0;
134
+ let intervalId = null;
135
+ let currentLabel = '';
136
+ function render() {
137
+ const frame = SPINNER_FRAMES[frameIndex % SPINNER_FRAMES.length];
138
+ frameIndex++;
139
+ const line = `${cyan(frame)} ${currentLabel}`;
140
+ process.stdout.write(`\r\x1b[K${line}`);
141
+ }
142
+ function start(label) {
143
+ // Idempotent: if already running just update label
144
+ currentLabel = label;
145
+ if (intervalId !== null)
146
+ return;
147
+ frameIndex = 0;
148
+ render();
149
+ intervalId = setInterval(render, SPINNER_INTERVAL_MS);
150
+ }
151
+ function stop() {
152
+ if (intervalId !== null) {
153
+ clearInterval(intervalId);
154
+ intervalId = null;
155
+ }
156
+ // Clear the spinner line
157
+ process.stdout.write('\r\x1b[K');
158
+ currentLabel = '';
159
+ }
160
+ function isRunning() {
161
+ return intervalId !== null;
162
+ }
163
+ function cleanup() {
164
+ stop();
165
+ }
166
+ return { start, stop, isRunning, cleanup };
167
+ }
168
+ /**
169
+ * Create a unified status line manager that composes spinner, elapsed time,
170
+ * agent queue, and active tools into a single rewritable terminal line.
171
+ *
172
+ * Status line format example:
173
+ * ⠋ AgentA is thinking... [0:12] | ▸ Read File ⟳
174
+ *
175
+ * Supports pause/resume for readline prompt coordination: pause clears the
176
+ * status line so `console.log()` or `rl.prompt()` output is clean, resume
177
+ * redraws it.
178
+ */
179
+ export function createStatusLineManager() {
180
+ // Internal state
181
+ let spinnerLabel = null;
182
+ let spinnerFrameIndex = 0;
183
+ let spinnerIntervalId = null;
184
+ let elapsedMs = 0;
185
+ let elapsedStartTime = null;
186
+ let elapsedIntervalId = null;
187
+ let agents = [];
188
+ let tools = [];
189
+ let paused = false;
190
+ let lineVisible = false;
191
+ // ---- Rendering ----
192
+ function composeLine() {
193
+ const parts = [];
194
+ // Spinner + label
195
+ if (spinnerLabel) {
196
+ const frame = SPINNER_FRAMES[spinnerFrameIndex % SPINNER_FRAMES.length];
197
+ parts.push(`${cyan(frame)} ${spinnerLabel}`);
198
+ }
199
+ // Elapsed timer
200
+ if (elapsedStartTime !== null) {
201
+ const now = Date.now();
202
+ const currentElapsed = now - elapsedStartTime;
203
+ parts.push(gray(`[${formatElapsed(currentElapsed)}]`));
204
+ }
205
+ else if (elapsedMs > 0) {
206
+ parts.push(gray(`[${formatElapsed(elapsedMs)}]`));
207
+ }
208
+ // Active agents (beyond the spinner label agent)
209
+ const activeAgents = agents.filter(a => a.active);
210
+ if (activeAgents.length > 1) {
211
+ const names = activeAgents.map(a => a.name).join(', ');
212
+ parts.push(gray(`agents: ${names}`));
213
+ }
214
+ // Active tools (max 3 displayed)
215
+ const runningTools = tools.filter(t => t.status === 'running');
216
+ const displayTools = runningTools.slice(0, 3);
217
+ if (displayTools.length > 0) {
218
+ const toolText = displayTools
219
+ .map(t => `${getToolIcon(t.name)} ${formatToolName(t.name)} ⟳`)
220
+ .join(' ');
221
+ parts.push(toolText);
222
+ if (runningTools.length > 3) {
223
+ parts.push(gray(`+${runningTools.length - 3} more`));
224
+ }
225
+ }
226
+ return parts.join(gray(' | '));
227
+ }
228
+ function render() {
229
+ if (paused)
230
+ return;
231
+ const line = composeLine();
232
+ if (!line) {
233
+ if (lineVisible) {
234
+ process.stdout.write('\r\x1b[K');
235
+ lineVisible = false;
236
+ }
237
+ return;
238
+ }
239
+ // Truncate to terminal width
240
+ const maxWidth = process.stdout.columns || 80;
241
+ // Strip ANSI for length measurement, truncate raw if needed
242
+ // Note: When truncated, ANSI color codes are lost (graceful degradation).
243
+ // This is acceptable because narrow terminals are uncommon for dev CLIs.
244
+ const stripped = line.replace(/\x1b\[[0-9;]*m/g, '');
245
+ let output = line;
246
+ if (stripped.length > maxWidth) {
247
+ output = truncateToWidth(stripped, maxWidth);
248
+ }
249
+ process.stdout.write(`\r\x1b[K${output}`);
250
+ lineVisible = true;
251
+ }
252
+ function clear() {
253
+ if (lineVisible) {
254
+ process.stdout.write('\r\x1b[K');
255
+ lineVisible = false;
256
+ }
257
+ }
258
+ function pause() {
259
+ paused = true;
260
+ clear();
261
+ }
262
+ function resume() {
263
+ paused = false;
264
+ render();
265
+ }
266
+ // ---- Spinner ----
267
+ function tickSpinner() {
268
+ spinnerFrameIndex++;
269
+ render();
270
+ }
271
+ function setSpinner(label) {
272
+ spinnerLabel = label;
273
+ if (label) {
274
+ if (spinnerIntervalId === null) {
275
+ spinnerFrameIndex = 0;
276
+ spinnerIntervalId = setInterval(tickSpinner, SPINNER_INTERVAL_MS);
277
+ }
278
+ }
279
+ else {
280
+ if (spinnerIntervalId !== null) {
281
+ clearInterval(spinnerIntervalId);
282
+ spinnerIntervalId = null;
283
+ }
284
+ }
285
+ render();
286
+ }
287
+ // ---- Elapsed timer ----
288
+ function startElapsedTimer() {
289
+ elapsedStartTime = Date.now();
290
+ if (elapsedIntervalId === null) {
291
+ elapsedIntervalId = setInterval(() => {
292
+ if (elapsedStartTime !== null) {
293
+ elapsedMs = Date.now() - elapsedStartTime;
294
+ }
295
+ render();
296
+ }, 1000);
297
+ }
298
+ }
299
+ function stopElapsedTimer() {
300
+ if (elapsedIntervalId !== null) {
301
+ clearInterval(elapsedIntervalId);
302
+ elapsedIntervalId = null;
303
+ }
304
+ elapsedStartTime = null;
305
+ }
306
+ function setElapsed(ms) {
307
+ elapsedMs = ms;
308
+ render();
309
+ }
310
+ // ---- Agents ----
311
+ function setAgents(newAgents) {
312
+ agents = newAgents;
313
+ render();
314
+ }
315
+ // ---- Tools ----
316
+ function addTool(name) {
317
+ // Avoid duplicates
318
+ if (!tools.some(t => t.name === name && t.status === 'running')) {
319
+ tools.push({ name, status: 'running' });
320
+ }
321
+ render();
322
+ }
323
+ function removeTool(name, status, detail) {
324
+ const idx = tools.findIndex(t => t.name === name && t.status === 'running');
325
+ if (idx >= 0) {
326
+ tools[idx] = { name, status, detail };
327
+ }
328
+ // Remove completed/errored tools after a brief moment (or immediately for cleanliness)
329
+ tools = tools.filter(t => t.status === 'running');
330
+ render();
331
+ }
332
+ // ---- Lifecycle ----
333
+ function reset() {
334
+ setSpinner(null);
335
+ stopElapsedTimer();
336
+ elapsedMs = 0;
337
+ agents = [];
338
+ tools = [];
339
+ clear();
340
+ }
341
+ function cleanup() {
342
+ reset();
343
+ // Extra safety: clear any remaining intervals
344
+ if (spinnerIntervalId !== null) {
345
+ clearInterval(spinnerIntervalId);
346
+ spinnerIntervalId = null;
347
+ }
348
+ if (elapsedIntervalId !== null) {
349
+ clearInterval(elapsedIntervalId);
350
+ elapsedIntervalId = null;
351
+ }
352
+ }
353
+ return {
354
+ setSpinner,
355
+ setElapsed,
356
+ setAgents,
357
+ addTool,
358
+ removeTool,
359
+ render,
360
+ clear,
361
+ pause,
362
+ resume,
363
+ startElapsedTimer,
364
+ stopElapsedTimer,
365
+ reset,
366
+ cleanup,
367
+ };
368
+ }
369
+ // ---------------------------------------------------------------------------
370
+ // Console.log wrapper — pause/resume status line for permanent output
371
+ // ---------------------------------------------------------------------------
372
+ /**
373
+ * Print permanent output while preserving the status line.
374
+ *
375
+ * Usage: `log(statusLine, 'Hello', someVar)` instead of `console.log(...)`.
376
+ */
377
+ export function log(statusLine, ...args) {
378
+ statusLine.pause();
379
+ console.log(...args);
380
+ statusLine.resume();
381
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * CLI HITL Helpers
3
+ *
4
+ * Purpose:
5
+ * - Provide pure parsing/selection helpers for HITL option requests used by the CLI.
6
+ *
7
+ * Key Features:
8
+ * - Parse `hitl-option-request` system payloads into normalized structures.
9
+ * - Resolve user input into option IDs (by number or option id).
10
+ * - Provide deterministic fallback option resolution.
11
+ *
12
+ * Implementation Notes:
13
+ * - Parser accepts generic event payloads and rejects incomplete requests.
14
+ * - Fallback defaults to explicit `no` when available, otherwise first option.
15
+ *
16
+ * Recent Changes:
17
+ * - 2026-02-14: Added initial helper module for CLI HITL response flow support.
18
+ */
19
+ export interface HitlOptionPayload {
20
+ id: string;
21
+ label: string;
22
+ description?: string;
23
+ }
24
+ export interface HitlOptionRequestPayload {
25
+ requestId: string;
26
+ title: string;
27
+ message: string;
28
+ chatId: string | null;
29
+ options: HitlOptionPayload[];
30
+ defaultOptionId: string;
31
+ }
32
+ export declare function parseHitlOptionRequest(eventData: unknown): HitlOptionRequestPayload | null;
33
+ export declare function resolveHitlOptionSelectionInput(options: HitlOptionPayload[], rawInput: string, fallbackOptionId: string): string | null;
@@ -0,0 +1,81 @@
1
+ /**
2
+ * CLI HITL Helpers
3
+ *
4
+ * Purpose:
5
+ * - Provide pure parsing/selection helpers for HITL option requests used by the CLI.
6
+ *
7
+ * Key Features:
8
+ * - Parse `hitl-option-request` system payloads into normalized structures.
9
+ * - Resolve user input into option IDs (by number or option id).
10
+ * - Provide deterministic fallback option resolution.
11
+ *
12
+ * Implementation Notes:
13
+ * - Parser accepts generic event payloads and rejects incomplete requests.
14
+ * - Fallback defaults to explicit `no` when available, otherwise first option.
15
+ *
16
+ * Recent Changes:
17
+ * - 2026-02-14: Added initial helper module for CLI HITL response flow support.
18
+ */
19
+ export function parseHitlOptionRequest(eventData) {
20
+ if (!eventData || typeof eventData !== 'object') {
21
+ return null;
22
+ }
23
+ const payload = eventData;
24
+ const content = payload.content && typeof payload.content === 'object'
25
+ ? payload.content
26
+ : null;
27
+ if (!content || String(content.eventType || '').trim() !== 'hitl-option-request') {
28
+ return null;
29
+ }
30
+ const requestId = String(content.requestId || '').trim();
31
+ if (!requestId) {
32
+ return null;
33
+ }
34
+ const options = Array.isArray(content.options)
35
+ ? content.options
36
+ .map((option) => {
37
+ const optionRecord = option && typeof option === 'object'
38
+ ? option
39
+ : null;
40
+ return {
41
+ id: String(optionRecord?.id || '').trim(),
42
+ label: String(optionRecord?.label || '').trim(),
43
+ description: optionRecord?.description ? String(optionRecord.description) : undefined
44
+ };
45
+ })
46
+ .filter((option) => option.id.length > 0 && option.label.length > 0)
47
+ : [];
48
+ if (options.length === 0) {
49
+ return null;
50
+ }
51
+ const preferredDefault = String(content.defaultOptionId || '').trim();
52
+ const defaultOptionId = options.some((option) => option.id === preferredDefault)
53
+ ? preferredDefault
54
+ : (options.find((option) => option.id === 'no')?.id || options[0].id);
55
+ return {
56
+ requestId,
57
+ title: String(content.title || 'Approval required').trim() || 'Approval required',
58
+ message: String(content.message || '').trim(),
59
+ chatId: payload.chatId ? String(payload.chatId) : null,
60
+ options,
61
+ defaultOptionId
62
+ };
63
+ }
64
+ export function resolveHitlOptionSelectionInput(options, rawInput, fallbackOptionId) {
65
+ const normalizedInput = String(rawInput || '').trim();
66
+ if (!normalizedInput) {
67
+ return fallbackOptionId;
68
+ }
69
+ const asNumber = Number(normalizedInput);
70
+ if (Number.isFinite(asNumber)) {
71
+ const index = Math.floor(asNumber) - 1;
72
+ if (index >= 0 && index < options.length) {
73
+ return options[index].id;
74
+ }
75
+ }
76
+ const byId = options.find((option) => option.id.toLowerCase() === normalizedInput.toLowerCase());
77
+ if (byId) {
78
+ return byId.id;
79
+ }
80
+ return null;
81
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,41 @@
1
+ /**
2
+ * CLI Streaming Module - Real-time Agent Response Display
3
+ *
4
+ * Manages streaming display for CLI interface with real-time chunk accumulation,
5
+ * visual feedback, and comprehensive event processing.
6
+ *
7
+ * FEATURES:
8
+ * - Real-time streaming with visual feedback and state tracking
9
+ * - Comprehensive event processing (chunk, end, error)
10
+ * - Tool streaming output display for shell_cmd (stdout/stderr)
11
+ * - Color-coded streaming indicators and status messages
12
+ * - Enhanced tool display with Unicode icons and formatted names
13
+ * - Tool output truncation at 50K characters
14
+ * - Modular design for reuse across CLI components
15
+ * - Event-driven display (no timer dependencies)
16
+ * CHANGES:
17
+ * - 2026-02-11: Enhanced tool display with icons, formatted names, stderr prefix, 50K truncation
18
+ * - 2026-02-08: Added tool streaming support for shell_cmd real-time output display
19
+ * - 2025-02-06: Track last streamed message to prevent duplicate MESSAGE events after streaming output
20
+ */
21
+ import { type StatusLineManager } from './display.js';
22
+ export interface StreamingState {
23
+ isActive: boolean;
24
+ content: string;
25
+ sender?: string;
26
+ messageId?: string;
27
+ lastStreamedMessageId?: string;
28
+ lastStreamedContent?: string;
29
+ lastStreamedSender?: string;
30
+ lastStreamedAt?: number;
31
+ }
32
+ export declare function createStreamingState(): StreamingState;
33
+ export declare function handleStreamingEvents(eventData: any, streaming: StreamingState, statusLine?: StatusLineManager): void;
34
+ export declare function handleToolEvents(eventData: any): void;
35
+ export declare function handleToolStreamEvents(eventData: any): void;
36
+ /** Reset tool stream tracking (call on tool-start or new tool execution). */
37
+ export declare function resetToolStreamTracking(): void;
38
+ export declare function handleActivityEvents(eventData: any): void;
39
+ export declare function handleWorldEventWithStreaming(eventType: string, eventData: any, streaming: StreamingState, statusLine?: StatusLineManager): boolean;
40
+ export declare function resetStreamingState(streaming: StreamingState): void;
41
+ export declare function isStreamingActive(streaming: StreamingState): boolean;