agent-world 0.13.0 → 0.15.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 (263) hide show
  1. package/README.md +90 -17
  2. package/dist/cli/commands.d.ts +7 -1
  3. package/dist/cli/commands.js +27 -10
  4. package/dist/cli/hitl.d.ts +4 -1
  5. package/dist/cli/hitl.js +55 -20
  6. package/dist/cli/index.js +249 -97
  7. package/dist/cli/system-events.d.ts +27 -0
  8. package/dist/cli/system-events.js +63 -0
  9. package/dist/core/activity-tracker.d.ts +26 -0
  10. package/dist/core/activity-tracker.d.ts.map +1 -1
  11. package/dist/core/activity-tracker.js +21 -4
  12. package/dist/core/activity-tracker.js.map +1 -1
  13. package/dist/core/anthropic-direct.d.ts +2 -0
  14. package/dist/core/anthropic-direct.d.ts.map +1 -1
  15. package/dist/core/anthropic-direct.js +43 -1
  16. package/dist/core/anthropic-direct.js.map +1 -1
  17. package/dist/core/chat-constants.d.ts +12 -0
  18. package/dist/core/chat-constants.d.ts.map +1 -1
  19. package/dist/core/chat-constants.js +5 -0
  20. package/dist/core/chat-constants.js.map +1 -1
  21. package/dist/core/create-agent-tool.d.ts +5 -0
  22. package/dist/core/create-agent-tool.d.ts.map +1 -1
  23. package/dist/core/create-agent-tool.js +57 -34
  24. package/dist/core/create-agent-tool.js.map +1 -1
  25. package/dist/core/events/index.d.ts +5 -2
  26. package/dist/core/events/index.d.ts.map +1 -1
  27. package/dist/core/events/index.js +5 -2
  28. package/dist/core/events/index.js.map +1 -1
  29. package/dist/core/events/memory-manager.d.ts +26 -1
  30. package/dist/core/events/memory-manager.d.ts.map +1 -1
  31. package/dist/core/events/memory-manager.js +877 -72
  32. package/dist/core/events/memory-manager.js.map +1 -1
  33. package/dist/core/events/orchestrator.d.ts +8 -0
  34. package/dist/core/events/orchestrator.d.ts.map +1 -1
  35. package/dist/core/events/orchestrator.js +203 -36
  36. package/dist/core/events/orchestrator.js.map +1 -1
  37. package/dist/core/events/persistence.d.ts +21 -14
  38. package/dist/core/events/persistence.d.ts.map +1 -1
  39. package/dist/core/events/persistence.js +100 -35
  40. package/dist/core/events/persistence.js.map +1 -1
  41. package/dist/core/events/publishers.d.ts +13 -7
  42. package/dist/core/events/publishers.d.ts.map +1 -1
  43. package/dist/core/events/publishers.js +53 -37
  44. package/dist/core/events/publishers.js.map +1 -1
  45. package/dist/core/events/subscribers.d.ts +17 -14
  46. package/dist/core/events/subscribers.d.ts.map +1 -1
  47. package/dist/core/events/subscribers.js +61 -148
  48. package/dist/core/events/subscribers.js.map +1 -1
  49. package/dist/core/events/title-scheduler.d.ts +27 -0
  50. package/dist/core/events/title-scheduler.d.ts.map +1 -0
  51. package/dist/core/events/title-scheduler.js +135 -0
  52. package/dist/core/events/title-scheduler.js.map +1 -0
  53. package/dist/core/events/tool-bridge-logging.d.ts +4 -1
  54. package/dist/core/events/tool-bridge-logging.d.ts.map +1 -1
  55. package/dist/core/events/tool-bridge-logging.js +112 -13
  56. package/dist/core/events/tool-bridge-logging.js.map +1 -1
  57. package/dist/core/events-metadata.d.ts.map +1 -1
  58. package/dist/core/events-metadata.js +8 -4
  59. package/dist/core/events-metadata.js.map +1 -1
  60. package/dist/core/export.d.ts +1 -1
  61. package/dist/core/export.d.ts.map +1 -1
  62. package/dist/core/export.js +2 -15
  63. package/dist/core/export.js.map +1 -1
  64. package/dist/core/feature-path-logging.d.ts +50 -0
  65. package/dist/core/feature-path-logging.d.ts.map +1 -0
  66. package/dist/core/feature-path-logging.js +130 -0
  67. package/dist/core/feature-path-logging.js.map +1 -0
  68. package/dist/core/file-tools.d.ts +57 -1
  69. package/dist/core/file-tools.d.ts.map +1 -1
  70. package/dist/core/file-tools.js +329 -29
  71. package/dist/core/file-tools.js.map +1 -1
  72. package/dist/core/google-direct.d.ts +6 -1
  73. package/dist/core/google-direct.d.ts.map +1 -1
  74. package/dist/core/google-direct.js +76 -7
  75. package/dist/core/google-direct.js.map +1 -1
  76. package/dist/core/heartbeat.d.ts +34 -0
  77. package/dist/core/heartbeat.d.ts.map +1 -0
  78. package/dist/core/heartbeat.js +153 -0
  79. package/dist/core/heartbeat.js.map +1 -0
  80. package/dist/core/hitl-tool.d.ts +6 -12
  81. package/dist/core/hitl-tool.d.ts.map +1 -1
  82. package/dist/core/hitl-tool.js +66 -88
  83. package/dist/core/hitl-tool.js.map +1 -1
  84. package/dist/core/hitl.d.ts +61 -4
  85. package/dist/core/hitl.d.ts.map +1 -1
  86. package/dist/core/hitl.js +324 -60
  87. package/dist/core/hitl.js.map +1 -1
  88. package/dist/core/index.d.ts +11 -7
  89. package/dist/core/index.d.ts.map +1 -1
  90. package/dist/core/index.js +10 -6
  91. package/dist/core/index.js.map +1 -1
  92. package/dist/core/llm-manager.d.ts +15 -0
  93. package/dist/core/llm-manager.d.ts.map +1 -1
  94. package/dist/core/llm-manager.js +325 -40
  95. package/dist/core/llm-manager.js.map +1 -1
  96. package/dist/core/load-skill-tool.d.ts +36 -3
  97. package/dist/core/load-skill-tool.d.ts.map +1 -1
  98. package/dist/core/load-skill-tool.js +807 -93
  99. package/dist/core/load-skill-tool.js.map +1 -1
  100. package/dist/core/logger.d.ts +14 -0
  101. package/dist/core/logger.d.ts.map +1 -1
  102. package/dist/core/logger.js +15 -0
  103. package/dist/core/logger.js.map +1 -1
  104. package/dist/core/managers.d.ts +18 -50
  105. package/dist/core/managers.d.ts.map +1 -1
  106. package/dist/core/managers.js +340 -502
  107. package/dist/core/managers.js.map +1 -1
  108. package/dist/core/mcp-server-registry.d.ts +16 -1
  109. package/dist/core/mcp-server-registry.d.ts.map +1 -1
  110. package/dist/core/mcp-server-registry.js +162 -12
  111. package/dist/core/mcp-server-registry.js.map +1 -1
  112. package/dist/core/message-cutoff.d.ts +29 -0
  113. package/dist/core/message-cutoff.d.ts.map +1 -0
  114. package/dist/core/message-cutoff.js +63 -0
  115. package/dist/core/message-cutoff.js.map +1 -0
  116. package/dist/core/message-edit-manager.d.ts +54 -0
  117. package/dist/core/message-edit-manager.d.ts.map +1 -0
  118. package/dist/core/message-edit-manager.js +602 -0
  119. package/dist/core/message-edit-manager.js.map +1 -0
  120. package/dist/core/message-prep.d.ts +2 -0
  121. package/dist/core/message-prep.d.ts.map +1 -1
  122. package/dist/core/message-prep.js +39 -12
  123. package/dist/core/message-prep.js.map +1 -1
  124. package/dist/core/message-processing-control.d.ts +1 -0
  125. package/dist/core/message-processing-control.d.ts.map +1 -1
  126. package/dist/core/message-processing-control.js +23 -6
  127. package/dist/core/message-processing-control.js.map +1 -1
  128. package/dist/core/openai-direct.d.ts +9 -3
  129. package/dist/core/openai-direct.d.ts.map +1 -1
  130. package/dist/core/openai-direct.js +267 -33
  131. package/dist/core/openai-direct.js.map +1 -1
  132. package/dist/core/optional-tracers/opik-runtime.d.ts +32 -0
  133. package/dist/core/optional-tracers/opik-runtime.d.ts.map +1 -0
  134. package/dist/core/optional-tracers/opik-runtime.js +141 -0
  135. package/dist/core/optional-tracers/opik-runtime.js.map +1 -0
  136. package/dist/core/queue-manager.d.ts +84 -0
  137. package/dist/core/queue-manager.d.ts.map +1 -0
  138. package/dist/core/queue-manager.js +814 -0
  139. package/dist/core/queue-manager.js.map +1 -0
  140. package/dist/core/reasoning-controls.d.ts +30 -0
  141. package/dist/core/reasoning-controls.d.ts.map +1 -0
  142. package/dist/core/reasoning-controls.js +118 -0
  143. package/dist/core/reasoning-controls.js.map +1 -0
  144. package/dist/core/reliability-config.d.ts +82 -0
  145. package/dist/core/reliability-config.d.ts.map +1 -0
  146. package/dist/core/reliability-config.js +106 -0
  147. package/dist/core/reliability-config.js.map +1 -0
  148. package/dist/core/reliability-runtime.d.ts +53 -0
  149. package/dist/core/reliability-runtime.d.ts.map +1 -0
  150. package/dist/core/reliability-runtime.js +92 -0
  151. package/dist/core/reliability-runtime.js.map +1 -0
  152. package/dist/core/security/guardrails.d.ts +21 -0
  153. package/dist/core/security/guardrails.d.ts.map +1 -0
  154. package/dist/core/security/guardrails.js +111 -0
  155. package/dist/core/security/guardrails.js.map +1 -0
  156. package/dist/core/send-message-tool.d.ts +79 -0
  157. package/dist/core/send-message-tool.d.ts.map +1 -0
  158. package/dist/core/send-message-tool.js +222 -0
  159. package/dist/core/send-message-tool.js.map +1 -0
  160. package/dist/core/shell-cmd-tool.d.ts +82 -1
  161. package/dist/core/shell-cmd-tool.d.ts.map +1 -1
  162. package/dist/core/shell-cmd-tool.js +854 -42
  163. package/dist/core/shell-cmd-tool.js.map +1 -1
  164. package/dist/core/skill-registry.d.ts +2 -0
  165. package/dist/core/skill-registry.d.ts.map +1 -1
  166. package/dist/core/skill-registry.js +52 -2
  167. package/dist/core/skill-registry.js.map +1 -1
  168. package/dist/core/storage/eventStorage/fileEventStorage.d.ts +5 -0
  169. package/dist/core/storage/eventStorage/fileEventStorage.d.ts.map +1 -1
  170. package/dist/core/storage/eventStorage/fileEventStorage.js +61 -0
  171. package/dist/core/storage/eventStorage/fileEventStorage.js.map +1 -1
  172. package/dist/core/storage/eventStorage/memoryEventStorage.d.ts +5 -0
  173. package/dist/core/storage/eventStorage/memoryEventStorage.d.ts.map +1 -1
  174. package/dist/core/storage/eventStorage/memoryEventStorage.js +34 -0
  175. package/dist/core/storage/eventStorage/memoryEventStorage.js.map +1 -1
  176. package/dist/core/storage/eventStorage/sqliteEventStorage.d.ts +1 -0
  177. package/dist/core/storage/eventStorage/sqliteEventStorage.d.ts.map +1 -1
  178. package/dist/core/storage/eventStorage/sqliteEventStorage.js +19 -2
  179. package/dist/core/storage/eventStorage/sqliteEventStorage.js.map +1 -1
  180. package/dist/core/storage/eventStorage/types.d.ts +6 -0
  181. package/dist/core/storage/eventStorage/types.d.ts.map +1 -1
  182. package/dist/core/storage/eventStorage/types.js +1 -0
  183. package/dist/core/storage/eventStorage/types.js.map +1 -1
  184. package/dist/core/storage/eventStorage/validation.d.ts.map +1 -1
  185. package/dist/core/storage/eventStorage/validation.js +2 -1
  186. package/dist/core/storage/eventStorage/validation.js.map +1 -1
  187. package/dist/core/storage/github-world-import.d.ts +84 -0
  188. package/dist/core/storage/github-world-import.d.ts.map +1 -0
  189. package/dist/core/storage/github-world-import.js +365 -0
  190. package/dist/core/storage/github-world-import.js.map +1 -0
  191. package/dist/core/storage/memory-storage.d.ts +19 -8
  192. package/dist/core/storage/memory-storage.d.ts.map +1 -1
  193. package/dist/core/storage/memory-storage.js +147 -49
  194. package/dist/core/storage/memory-storage.js.map +1 -1
  195. package/dist/core/storage/queue-storage.d.ts +1 -0
  196. package/dist/core/storage/queue-storage.d.ts.map +1 -1
  197. package/dist/core/storage/queue-storage.js +3 -2
  198. package/dist/core/storage/queue-storage.js.map +1 -1
  199. package/dist/core/storage/sqlite-storage.d.ts +14 -9
  200. package/dist/core/storage/sqlite-storage.d.ts.map +1 -1
  201. package/dist/core/storage/sqlite-storage.js +131 -154
  202. package/dist/core/storage/sqlite-storage.js.map +1 -1
  203. package/dist/core/storage/storage-factory.d.ts +3 -0
  204. package/dist/core/storage/storage-factory.d.ts.map +1 -1
  205. package/dist/core/storage/storage-factory.js +175 -89
  206. package/dist/core/storage/storage-factory.js.map +1 -1
  207. package/dist/core/storage/world-storage.d.ts +1 -1
  208. package/dist/core/storage/world-storage.d.ts.map +1 -1
  209. package/dist/core/storage/world-storage.js +5 -1
  210. package/dist/core/storage/world-storage.js.map +1 -1
  211. package/dist/core/storage-init.d.ts +11 -0
  212. package/dist/core/storage-init.d.ts.map +1 -0
  213. package/dist/core/storage-init.js +122 -0
  214. package/dist/core/storage-init.js.map +1 -0
  215. package/dist/core/subscription.d.ts +8 -1
  216. package/dist/core/subscription.d.ts.map +1 -1
  217. package/dist/core/subscription.js +130 -23
  218. package/dist/core/subscription.js.map +1 -1
  219. package/dist/core/tool-approval.d.ts +45 -0
  220. package/dist/core/tool-approval.d.ts.map +1 -0
  221. package/dist/core/tool-approval.js +223 -0
  222. package/dist/core/tool-approval.js.map +1 -0
  223. package/dist/core/tool-execution-envelope.d.ts +87 -0
  224. package/dist/core/tool-execution-envelope.d.ts.map +1 -0
  225. package/dist/core/tool-execution-envelope.js +168 -0
  226. package/dist/core/tool-execution-envelope.js.map +1 -0
  227. package/dist/core/tool-utils.d.ts +7 -2
  228. package/dist/core/tool-utils.d.ts.map +1 -1
  229. package/dist/core/tool-utils.js +81 -17
  230. package/dist/core/tool-utils.js.map +1 -1
  231. package/dist/core/types.d.ts +67 -19
  232. package/dist/core/types.d.ts.map +1 -1
  233. package/dist/core/types.js +3 -0
  234. package/dist/core/types.js.map +1 -1
  235. package/dist/core/utils.d.ts +7 -0
  236. package/dist/core/utils.d.ts.map +1 -1
  237. package/dist/core/utils.js +71 -21
  238. package/dist/core/utils.js.map +1 -1
  239. package/dist/core/web-fetch-tool.d.ts +72 -0
  240. package/dist/core/web-fetch-tool.d.ts.map +1 -0
  241. package/dist/core/web-fetch-tool.js +491 -0
  242. package/dist/core/web-fetch-tool.js.map +1 -0
  243. package/dist/core/world-registry.d.ts +84 -0
  244. package/dist/core/world-registry.d.ts.map +1 -0
  245. package/dist/core/world-registry.js +247 -0
  246. package/dist/core/world-registry.js.map +1 -0
  247. package/dist/public/assets/index-Be-1xtV-.js +104 -0
  248. package/dist/public/assets/index-tsDdiXDU.css +1 -0
  249. package/dist/public/index.html +2 -2
  250. package/dist/public/mcp-sandbox-proxy.html +148 -0
  251. package/dist/server/api.js +260 -18
  252. package/dist/server/error-response.d.ts +27 -0
  253. package/dist/server/error-response.js +77 -0
  254. package/dist/server/index.d.ts +2 -1
  255. package/dist/server/index.js +6 -2
  256. package/dist/server/sse-handler.d.ts +11 -1
  257. package/dist/server/sse-handler.js +194 -34
  258. package/migrations/0015_add_message_queue.sql +36 -0
  259. package/migrations/0016_add_world_heartbeat.sql +13 -0
  260. package/migrations/0017_add_title_provenance.sql +7 -0
  261. package/package.json +31 -10
  262. package/dist/public/assets/index-BW41BxMy.css +0 -1
  263. package/dist/public/assets/index-kO6UJFwK.js +0 -96
package/dist/cli/index.js CHANGED
@@ -13,10 +13,15 @@
13
13
  * - Work with loaded world without importing (uses external storage path)
14
14
  *
15
15
  * Changes:
16
+ * - 2026-03-06: Routed runtime chat selection through explicit CLI state; removed live listener/send fallback to `world.currentChatId`.
17
+ * - 2026-02-27: Added active-chat event scoping in CLI listeners to prevent cross-chat message/system/SSE/tool leakage.
18
+ * - 2026-02-25: Added fallback shorthand attempt `@awesome-agent-world/<input>` when a provided local path does not exist.
19
+ * - 2026-02-25: Added GitHub shorthand world source import support (`@awesome-agent-world/<world-name>`) with safe remote staging and automatic import mode.
16
20
  * - 2026-02-20: Enforced options-only HITL handling in interactive and pipeline modes.
17
21
  * - 2026-02-14: Added interactive + pipeline HITL option response handling for generic approval requests.
18
22
  * - 2026-02-11: Fixed tool-stream timeout: extendTimeout() resets idle timeout on streaming data
19
23
  * - 2026-02-11: Pipeline mode now listens for tool-stream SSE events to extend timeout
24
+ * - 2026-02-21: Extended timeout-refresh detection to include shell assistant-stream SSE events (`start`/`chunk`/`end` with `toolName='shell_cmd'`) in addition to legacy `tool-stream`.
20
25
  * - 2026-01-09: Added --streaming flag for explicit streaming control (overrides TTY auto-detection)
21
26
  * - 2025-02-06: Prevented duplicate MESSAGE output when streaming already rendered agent responses
22
27
  * - 2025-11-01: Added multi-world selection in loadWorldFromFile
@@ -77,14 +82,17 @@ import path from 'path';
77
82
  import { fileURLToPath } from 'url';
78
83
  import { program } from 'commander';
79
84
  import readline from 'readline';
80
- import { listWorlds, subscribeWorld, submitWorldHitlResponse, createCategoryLogger, LLMProvider, enableStreaming, disableStreaming } from '../core/index.js';
85
+ import { listWorlds, deleteWorld, subscribeWorld, submitWorldHitlResponse, GitHubWorldImportError, stageGitHubWorldFromShorthand, createCategoryLogger, LLMProvider, enableStreaming, disableStreaming } from '../core/index.js';
81
86
  import { EventType } from '../core/types.js';
82
87
  import { getDefaultRootPath } from '../core/storage/storage-factory.js';
88
+ // Opik integration: optional tracer attach for CLI world subscriptions.
89
+ import { attachOptionalOpikTracer } from '../core/optional-tracers/opik-runtime.js';
83
90
  import { processCLIInput, displayChatMessages } from './commands.js';
84
91
  import { createStreamingState, handleWorldEventWithStreaming, handleToolEvents, } from './stream.js';
85
92
  import { configureLLMProvider } from '../core/llm-config.js';
86
93
  import { createStatusLineManager, log as statusLog, } from './display.js';
87
- import { parseHitlPromptRequest, resolveHitlOptionSelectionInput, } from './hitl.js';
94
+ import { getSystemEventDisplayText } from './system-events.js';
95
+ import { markHitlRequestHandled, parseHitlPromptFromToolEvent, resolveHitlOptionSelectionInput, } from './hitl.js';
88
96
  // Create CLI category logger after logger auto-initialization
89
97
  const logger = createCategoryLogger('cli');
90
98
  function createGlobalState() {
@@ -395,11 +403,87 @@ function printCLIResult(result) {
395
403
  * @param rl - Readline interface for interactive mode (undefined for pipeline mode)
396
404
  * @returns Map of event types to listener functions for cleanup
397
405
  */
398
- function attachCLIListeners(world, streaming, globalState, activityMonitor, statusLine, rl) {
406
+ function attachCLIListeners(world, streaming, globalState, activityMonitor, statusLine, getSelectedChatId, rl) {
399
407
  const listeners = new Map();
400
408
  let hitlPromptChain = Promise.resolve();
409
+ const handledHitlRequestIds = new Set();
410
+ const isChatEventInScope = (eventChatId, includeUnscopedWhenScoped = false) => {
411
+ const activeChatId = getSelectedChatId();
412
+ if (!activeChatId) {
413
+ return true;
414
+ }
415
+ if (eventChatId === undefined || eventChatId === null) {
416
+ return includeUnscopedWhenScoped;
417
+ }
418
+ const normalizedEventChatId = String(eventChatId).trim();
419
+ if (!normalizedEventChatId) {
420
+ return includeUnscopedWhenScoped;
421
+ }
422
+ return normalizedEventChatId === activeChatId;
423
+ };
424
+ const shouldHandleWorldEvent = (eventData) => {
425
+ const eventType = String(eventData?.type || '').trim().toLowerCase();
426
+ if (eventType === 'response-start' || eventType === 'response-end' || eventType === 'idle' || eventType === 'info') {
427
+ return isChatEventInScope(eventData?.chatId, true);
428
+ }
429
+ if (eventType.startsWith('tool-')) {
430
+ return isChatEventInScope(eventData?.chatId, false);
431
+ }
432
+ return isChatEventInScope(eventData?.chatId, true);
433
+ };
401
434
  // World activity events
402
435
  const worldListener = (eventData) => {
436
+ if (!shouldHandleWorldEvent(eventData)) {
437
+ return;
438
+ }
439
+ const hitlRequest = parseHitlPromptFromToolEvent(eventData);
440
+ if (hitlRequest) {
441
+ if (!markHitlRequestHandled(handledHitlRequestIds, hitlRequest.requestId)) {
442
+ return;
443
+ }
444
+ hitlPromptChain = hitlPromptChain
445
+ .then(async () => {
446
+ if (streaming && globalState && rl && statusLine) {
447
+ globalState.hitlPromptActive = true;
448
+ try {
449
+ const result = submitWorldHitlResponse({
450
+ worldId: world.id,
451
+ requestId: hitlRequest.requestId,
452
+ optionId: await promptHitlOptionSelection(hitlRequest, statusLine, rl),
453
+ chatId: hitlRequest.chatId,
454
+ });
455
+ if (!result.accepted) {
456
+ statusLine.pause();
457
+ console.log(boldRed(`Failed to submit approval response: ${result.reason || 'unknown error'}`));
458
+ statusLine.resume();
459
+ return;
460
+ }
461
+ statusLine.pause();
462
+ console.log(green('Submitted HITL option response.'));
463
+ statusLine.resume();
464
+ return;
465
+ }
466
+ finally {
467
+ globalState.hitlPromptActive = false;
468
+ }
469
+ }
470
+ const result = submitWorldHitlResponse({
471
+ worldId: world.id,
472
+ requestId: hitlRequest.requestId,
473
+ optionId: hitlRequest.defaultOptionId,
474
+ chatId: hitlRequest.chatId,
475
+ });
476
+ if (!result.accepted) {
477
+ console.error(boldRed(`Failed to auto-respond HITL request: ${result.reason || 'unknown error'}`));
478
+ return;
479
+ }
480
+ console.log(`${gray('● system:')} Auto-selected HITL option "${hitlRequest.defaultOptionId}"`);
481
+ })
482
+ .catch((error) => {
483
+ console.error(boldRed(`Error handling HITL request: ${error instanceof Error ? error.message : String(error)}`));
484
+ });
485
+ return;
486
+ }
403
487
  activityMonitor.handle(eventData);
404
488
  // Only render activity progress in interactive mode
405
489
  if (streaming && globalState && rl && statusLine) {
@@ -412,6 +496,9 @@ function attachCLIListeners(world, streaming, globalState, activityMonitor, stat
412
496
  listeners.set(EventType.WORLD, worldListener);
413
497
  // Message events
414
498
  const messageListener = (eventData) => {
499
+ if (!isChatEventInScope(eventData?.chatId, false)) {
500
+ return;
501
+ }
415
502
  if (eventData.content &&
416
503
  typeof eventData.content === 'string' &&
417
504
  eventData.content.includes('Success message sent'))
@@ -435,8 +522,14 @@ function attachCLIListeners(world, streaming, globalState, activityMonitor, stat
435
522
  // SSE events (interactive mode only - pipeline mode uses non-streaming LLM calls)
436
523
  if (streaming && globalState && rl && statusLine) {
437
524
  const sseListener = (eventData) => {
438
- // Extend timeout when tool-stream data arrives (keeps long-running tools alive)
439
- if (eventData.type === 'tool-stream') {
525
+ if (!isChatEventInScope(eventData?.chatId, false)) {
526
+ return;
527
+ }
528
+ // Extend timeout when long-running shell stream activity arrives.
529
+ const isLegacyToolStream = eventData.type === 'tool-stream';
530
+ const isShellAssistantStream = eventData.toolName === 'shell_cmd' &&
531
+ (eventData.type === 'start' || eventData.type === 'chunk' || eventData.type === 'end');
532
+ if (isLegacyToolStream || isShellAssistantStream) {
440
533
  activityMonitor.extendTimeout();
441
534
  }
442
535
  handleWorldEvent(EventType.SSE, eventData, streaming, globalState, activityMonitor, statusLine, rl)
@@ -446,9 +539,15 @@ function attachCLIListeners(world, streaming, globalState, activityMonitor, stat
446
539
  listeners.set(EventType.SSE, sseListener);
447
540
  }
448
541
  else {
449
- // Pipeline mode: listen for tool-stream events to extend timeout on long-running commands
542
+ // Pipeline mode: listen for shell stream events to extend timeout on long-running commands.
450
543
  const sseTimeoutListener = (eventData) => {
451
- if (eventData.type === 'tool-stream') {
544
+ if (!isChatEventInScope(eventData?.chatId, false)) {
545
+ return;
546
+ }
547
+ const isLegacyToolStream = eventData.type === 'tool-stream';
548
+ const isShellAssistantStream = eventData.toolName === 'shell_cmd' &&
549
+ (eventData.type === 'start' || eventData.type === 'chunk' || eventData.type === 'end');
550
+ if (isLegacyToolStream || isShellAssistantStream) {
452
551
  activityMonitor.extendTimeout();
453
552
  }
454
553
  };
@@ -457,50 +556,7 @@ function attachCLIListeners(world, streaming, globalState, activityMonitor, stat
457
556
  }
458
557
  // System events
459
558
  const systemListener = (eventData) => {
460
- const hitlRequest = parseHitlPromptRequest(eventData);
461
- if (hitlRequest) {
462
- hitlPromptChain = hitlPromptChain
463
- .then(async () => {
464
- if (streaming && globalState && rl && statusLine) {
465
- globalState.hitlPromptActive = true;
466
- try {
467
- const result = submitWorldHitlResponse({
468
- worldId: world.id,
469
- requestId: hitlRequest.requestId,
470
- optionId: await promptHitlOptionSelection(hitlRequest, statusLine, rl),
471
- chatId: hitlRequest.chatId,
472
- });
473
- if (!result.accepted) {
474
- statusLine.pause();
475
- console.log(boldRed(`Failed to submit approval response: ${result.reason || 'unknown error'}`));
476
- statusLine.resume();
477
- return;
478
- }
479
- statusLine.pause();
480
- console.log(green('Submitted HITL option response.'));
481
- statusLine.resume();
482
- return;
483
- }
484
- finally {
485
- globalState.hitlPromptActive = false;
486
- }
487
- }
488
- // Pipeline/non-interactive mode: auto-respond with default option to avoid blocking.
489
- const result = submitWorldHitlResponse({
490
- worldId: world.id,
491
- requestId: hitlRequest.requestId,
492
- optionId: hitlRequest.defaultOptionId,
493
- chatId: hitlRequest.chatId,
494
- });
495
- if (!result.accepted) {
496
- console.error(boldRed(`Failed to auto-respond HITL request: ${result.reason || 'unknown error'}`));
497
- return;
498
- }
499
- console.log(`${gray('● system:')} Auto-selected HITL option "${hitlRequest.defaultOptionId}"`);
500
- })
501
- .catch((error) => {
502
- console.error(boldRed(`Error handling HITL request: ${error instanceof Error ? error.message : String(error)}`));
503
- });
559
+ if (!isChatEventInScope(eventData?.chatId, false)) {
504
560
  return;
505
561
  }
506
562
  if (eventData.content &&
@@ -511,8 +567,11 @@ function attachCLIListeners(world, streaming, globalState, activityMonitor, stat
511
567
  handleWorldEvent(EventType.SYSTEM, eventData, streaming, globalState, activityMonitor, statusLine, rl)
512
568
  .catch(err => console.error('Error handling system event:', err));
513
569
  }
514
- else if (eventData.message || eventData.content) {
515
- // Pipeline mode: system messages are handled by message listener
570
+ else {
571
+ const systemText = getSystemEventDisplayText(eventData);
572
+ if (systemText) {
573
+ console.log(`${boldRed('● system:')} ${systemText}`);
574
+ }
516
575
  }
517
576
  };
518
577
  world.eventEmitter.on(EventType.SYSTEM, systemListener);
@@ -537,6 +596,7 @@ async function runPipelineMode(options, messageFromArgs) {
537
596
  let worldSubscription = null;
538
597
  let cliListeners = null;
539
598
  const activityMonitor = new WorldActivityMonitor();
599
+ const opikEnabledOverride = parseOptionalBoolean(options.opikEnabled);
540
600
  try {
541
601
  if (options.world) {
542
602
  // Subscribe to world lifecycle but do not request forwarding callbacks
@@ -546,9 +606,11 @@ async function runPipelineMode(options, messageFromArgs) {
546
606
  process.exit(1);
547
607
  }
548
608
  world = worldSubscription.world;
609
+ await attachOptionalOpikTracer(world, { source: 'cli', enabledOverride: opikEnabledOverride });
549
610
  // Attach direct listeners to the world.eventEmitter for pipeline handling
550
611
  // Note: Pipeline mode uses non-streaming LLM calls, so SSE events are not needed
551
- cliListeners = attachCLIListeners(world, null, null, activityMonitor, null);
612
+ const selectedChatId = String(world?.currentChatId || '').trim() || null;
613
+ cliListeners = attachCLIListeners(world, null, null, activityMonitor, null, () => selectedChatId);
552
614
  }
553
615
  // Execute command from --command option
554
616
  if (options.command) {
@@ -557,7 +619,7 @@ async function runPipelineMode(options, messageFromArgs) {
557
619
  process.exit(1);
558
620
  }
559
621
  const snapshot = activityMonitor.captureSnapshot();
560
- const result = await processCLIInput(options.command, world, 'human');
622
+ const result = await processCLIInput(options.command, world, 'human', String(world?.currentChatId || '').trim() || null);
561
623
  printCLIResult(result);
562
624
  if (!options.command.startsWith('/') && world) {
563
625
  try {
@@ -590,7 +652,7 @@ async function runPipelineMode(options, messageFromArgs) {
590
652
  process.exit(1);
591
653
  }
592
654
  const snapshot = activityMonitor.captureSnapshot();
593
- const result = await processCLIInput(messageFromArgs, world, 'human');
655
+ const result = await processCLIInput(messageFromArgs, world, 'human', String(world?.currentChatId || '').trim() || null);
594
656
  printCLIResult(result);
595
657
  try {
596
658
  // Event-driven completion: wait for world idle state
@@ -621,7 +683,7 @@ async function runPipelineMode(options, messageFromArgs) {
621
683
  process.exit(1);
622
684
  }
623
685
  const snapshot = activityMonitor.captureSnapshot();
624
- const result = await processCLIInput(input.trim(), world, 'HUMAN');
686
+ const result = await processCLIInput(input.trim(), world, 'HUMAN', String(world?.currentChatId || '').trim() || null);
625
687
  printCLIResult(result);
626
688
  try {
627
689
  // Event-driven completion: wait for world idle state
@@ -681,20 +743,26 @@ function cleanupWorldSubscription(worldState) {
681
743
  * @param rl - Readline interface for interactive input
682
744
  * @returns WorldState with subscription and world instance
683
745
  */
684
- async function handleSubscribe(rootPath, worldName, streaming, globalState, activityMonitor, statusLine, rl) {
746
+ async function handleSubscribe(rootPath, worldName, streaming, globalState, activityMonitor, statusLine, opikEnabledOverride, rl) {
685
747
  // Subscribe to world lifecycle but do not request forwarding callbacks
686
748
  const subscription = await subscribeWorld(worldName, { isOpen: true });
687
749
  if (!subscription)
688
750
  throw new Error('Failed to load world');
689
751
  const world = subscription.world;
752
+ await attachOptionalOpikTracer(world, { source: 'cli', enabledOverride: opikEnabledOverride });
690
753
  // Store world in globalState for access in interactive event handlers.
691
754
  if (globalState) {
692
755
  globalState.world = world;
693
756
  }
694
757
  // Attach direct listeners to the world.eventEmitter for CLI handling
695
758
  // Interactive mode needs all event types including SSE for streaming responses
696
- attachCLIListeners(world, streaming, globalState, activityMonitor, statusLine, rl);
697
- return { subscription, world };
759
+ const worldState = {
760
+ subscription,
761
+ world,
762
+ selectedChatId: String(world.currentChatId || '').trim() || null,
763
+ };
764
+ attachCLIListeners(world, streaming, globalState, activityMonitor, statusLine, () => worldState.selectedChatId, rl);
765
+ return worldState;
698
766
  }
699
767
  // Handle world events with streaming support
700
768
  async function handleWorldEvent(eventType, eventData, streaming, globalState, activityMonitor, statusLine, rl) {
@@ -812,8 +880,18 @@ async function handleWorldEvent(eventType, eventData, streaming, globalState, ac
812
880
  }
813
881
  return;
814
882
  }
815
- if ((eventType === 'system' || eventType === 'world') && (eventData.message || eventData.content)) {
816
- // existing logic
883
+ if (eventType === 'system') {
884
+ const systemText = getSystemEventDisplayText(eventData);
885
+ if (systemText) {
886
+ statusLog(statusLine, `${boldRed('● system:')} ${systemText}`);
887
+ }
888
+ return;
889
+ }
890
+ if (eventType === 'world' && (eventData.message || eventData.content)) {
891
+ const worldText = getSystemEventDisplayText(eventData);
892
+ if (worldText) {
893
+ statusLog(statusLine, `${gray('[World]')} ${worldText}`);
894
+ }
817
895
  }
818
896
  }
819
897
  // World discovery and selection
@@ -878,9 +956,13 @@ async function selectWorld(rootPath, rl) {
878
956
  // Load world from external file folder
879
957
  async function loadWorldFromFile(currentRootPath, rl) {
880
958
  const fs = await import('fs');
959
+ void currentRootPath;
960
+ let stagedGitHubWorld = null;
961
+ let resolvedSourcePath = '';
962
+ let importIsRequired = false;
881
963
  // Get world folder path
882
- const folderPath = await new Promise((resolve) => {
883
- rl.question(`\n${boldMagenta('Enter path to world folder:')} `, (answer) => {
964
+ const sourceInput = await new Promise((resolve) => {
965
+ rl.question(`\n${boldMagenta('Enter path to world folder (or @awesome-agent-world/<world-name>):')} `, (answer) => {
884
966
  const trimmed = answer.trim();
885
967
  if (trimmed === '') {
886
968
  resolve(null);
@@ -890,28 +972,57 @@ async function loadWorldFromFile(currentRootPath, rl) {
890
972
  }
891
973
  });
892
974
  });
893
- if (!folderPath) {
975
+ if (!sourceInput) {
894
976
  console.log(boldRed('Load cancelled.'));
895
977
  return null;
896
978
  }
897
- // Validate folder exists
898
- if (!fs.existsSync(folderPath)) {
899
- console.log(boldRed(`Folder does not exist: ${folderPath}`));
900
- return null;
901
- }
902
979
  try {
980
+ if (sourceInput.startsWith('@')) {
981
+ stagedGitHubWorld = await stageGitHubWorldFromShorthand(sourceInput);
982
+ resolvedSourcePath = stagedGitHubWorld.stagingRootPath;
983
+ importIsRequired = true;
984
+ console.log(green(`Fetched world source from GitHub: ${sourceInput}`));
985
+ if (stagedGitHubWorld.source.commitSha) {
986
+ console.log(` ${yellow('Source commit:')} ${stagedGitHubWorld.source.commitSha}`);
987
+ }
988
+ }
989
+ else {
990
+ resolvedSourcePath = sourceInput;
991
+ if (!fs.existsSync(resolvedSourcePath)) {
992
+ const fallbackShorthand = `@awesome-agent-world/${sourceInput}`;
993
+ try {
994
+ stagedGitHubWorld = await stageGitHubWorldFromShorthand(fallbackShorthand);
995
+ resolvedSourcePath = stagedGitHubWorld.stagingRootPath;
996
+ importIsRequired = true;
997
+ console.log(yellow(`Folder does not exist locally: ${sourceInput}`));
998
+ console.log(green(`Trying GitHub shorthand: ${fallbackShorthand}`));
999
+ if (stagedGitHubWorld.source.commitSha) {
1000
+ console.log(` ${yellow('Source commit:')} ${stagedGitHubWorld.source.commitSha}`);
1001
+ }
1002
+ }
1003
+ catch (fallbackError) {
1004
+ if (!(fallbackError instanceof GitHubWorldImportError)) {
1005
+ throw fallbackError;
1006
+ }
1007
+ }
1008
+ }
1009
+ }
1010
+ if (!fs.existsSync(resolvedSourcePath)) {
1011
+ console.log(boldRed(`Folder does not exist: ${resolvedSourcePath}`));
1012
+ return null;
1013
+ }
903
1014
  // Import necessary functions
904
1015
  const { createStorage } = await import('../core/storage/storage-factory.js');
905
- const { checkTargetExists, deleteExistingData } = await import('./commands.js');
1016
+ const { createStorageFromEnv } = await import('../core/storage/storage-factory.js');
906
1017
  // Create storage instance for source folder
907
1018
  const sourceStorage = await createStorage({
908
1019
  type: 'file',
909
- rootPath: folderPath
1020
+ rootPath: resolvedSourcePath
910
1021
  });
911
1022
  // List worlds in the source folder
912
1023
  const worldsInFolder = await sourceStorage.listWorlds();
913
1024
  if (worldsInFolder.length === 0) {
914
- console.log(boldRed(`No worlds found in: ${folderPath}`));
1025
+ console.log(boldRed(`No worlds found in: ${resolvedSourcePath}`));
915
1026
  return null;
916
1027
  }
917
1028
  // Select world if multiple
@@ -959,20 +1070,25 @@ async function loadWorldFromFile(currentRootPath, rl) {
959
1070
  const chats = await sourceStorage.listChats(worldData.id);
960
1071
  console.log(` ${yellow('Chats:')} ${chats.length}`);
961
1072
  // Ask if user wants to import
962
- const shouldImport = await new Promise((resolve) => {
963
- rl.question(`\n${boldMagenta('Import this world to current storage?')} ${boldMagenta('(yes/no):')} `, (answer) => {
964
- const trimmed = answer.trim().toLowerCase();
965
- resolve(trimmed === 'yes' || trimmed === 'y');
1073
+ const shouldImport = importIsRequired
1074
+ ? true
1075
+ : await new Promise((resolve) => {
1076
+ rl.question(`\n${boldMagenta('Import this world to current storage?')} ${boldMagenta('(yes/no):')} `, (answer) => {
1077
+ const trimmed = answer.trim().toLowerCase();
1078
+ resolve(trimmed === 'yes' || trimmed === 'y');
1079
+ });
966
1080
  });
967
- });
968
1081
  if (!shouldImport) {
969
1082
  console.log(yellow('World loaded from external storage (not imported).'));
970
1083
  // Return world name with external path to use that storage
971
- return { worldName: worldData.name, externalPath: folderPath };
1084
+ return { worldName: worldData.id, externalPath: resolvedSourcePath };
972
1085
  }
973
- // Check if world already exists in current storage
974
- const checkResult = await checkTargetExists(currentRootPath, 'file', worldData.id);
975
- if (checkResult.exists) {
1086
+ // Check if world already exists in active runtime storage
1087
+ const existingWorlds = await listWorlds();
1088
+ const idConflict = existingWorlds.find((world) => String(world?.id || '') === String(worldData?.id || ''));
1089
+ const nameConflict = existingWorlds.find((world) => String(world?.name || '').trim().toLowerCase() === String(worldData?.name || '').trim().toLowerCase());
1090
+ const existingWorld = idConflict || nameConflict;
1091
+ if (existingWorld) {
976
1092
  // Confirm overwrite
977
1093
  const shouldOverwrite = await new Promise((resolve) => {
978
1094
  rl.question(`\n${boldYellow(`World '${worldData.name}' already exists. Overwrite?`)} ${boldMagenta('(yes/no):')} `, (answer) => {
@@ -983,17 +1099,18 @@ async function loadWorldFromFile(currentRootPath, rl) {
983
1099
  if (!shouldOverwrite) {
984
1100
  console.log(yellow('Import cancelled. Loading from external storage instead.'));
985
1101
  // Return world name with external path to use that storage
986
- return { worldName: worldData.name, externalPath: folderPath };
1102
+ return { worldName: worldData.id, externalPath: resolvedSourcePath };
987
1103
  }
988
1104
  // Delete existing world
989
- await deleteExistingData(currentRootPath, 'file', worldData.id);
990
- console.log(green(`Deleted existing world '${worldData.name}'`));
1105
+ const deleted = await deleteWorld(String(existingWorld.id));
1106
+ if (!deleted) {
1107
+ console.log(boldRed(`Failed to delete existing world '${existingWorld.id}' before import.`));
1108
+ return null;
1109
+ }
1110
+ console.log(green(`Deleted existing world '${existingWorld.name || existingWorld.id}'`));
991
1111
  }
992
- // Create storage instance for target
993
- const targetStorage = await createStorage({
994
- type: 'file',
995
- rootPath: currentRootPath
996
- });
1112
+ // Create storage instance for active runtime target
1113
+ const targetStorage = await createStorageFromEnv();
997
1114
  // Save world
998
1115
  await targetStorage.saveWorld(worldData);
999
1116
  // Save all agents
@@ -1033,12 +1150,29 @@ async function loadWorldFromFile(currentRootPath, rl) {
1033
1150
  console.log(` ${yellow('Agents:')} ${agents.length}`);
1034
1151
  console.log(` ${yellow('Chats:')} ${chats.length}`);
1035
1152
  console.log(` ${yellow('Events:')} ${eventCount}`);
1036
- return { worldName: worldData.name };
1153
+ return { worldName: worldData.id };
1037
1154
  }
1038
1155
  catch (error) {
1156
+ if (error instanceof GitHubWorldImportError) {
1157
+ console.log(boldRed(`Error loading world: ${error.message}`));
1158
+ const details = error.details || {};
1159
+ const owner = String(details.owner || '');
1160
+ const repo = String(details.repo || '');
1161
+ const branch = String(details.branch || '');
1162
+ const worldPath = String(details.worldPath || '');
1163
+ if (owner && repo && branch && worldPath) {
1164
+ console.log(` ${yellow('Resolved source:')} ${owner}/${repo}@${branch}:${worldPath}`);
1165
+ }
1166
+ return null;
1167
+ }
1039
1168
  console.log(boldRed(`Error loading world: ${error instanceof Error ? error.message : String(error)}`));
1040
1169
  return null;
1041
1170
  }
1171
+ finally {
1172
+ if (stagedGitHubWorld) {
1173
+ await stagedGitHubWorld.cleanup();
1174
+ }
1175
+ }
1042
1176
  }
1043
1177
  // Chat discovery and selection
1044
1178
  async function selectChat(world, chats, currentChatId, rl) {
@@ -1143,6 +1277,7 @@ async function confirmOverwrite(message, rl) {
1143
1277
  // Interactive mode: console-based interface
1144
1278
  async function runInteractiveMode(options) {
1145
1279
  const rootPath = options.root || DEFAULT_ROOT_PATH;
1280
+ const opikEnabledOverride = parseOptionalBoolean(options.opikEnabled);
1146
1281
  const globalState = createGlobalState();
1147
1282
  const streaming = createStreamingState();
1148
1283
  const activityMonitor = new WorldActivityMonitor();
@@ -1164,7 +1299,7 @@ async function runInteractiveMode(options) {
1164
1299
  try {
1165
1300
  activityMonitor.reset();
1166
1301
  statusLine.reset();
1167
- worldState = await handleSubscribe(rootPath, options.world, streaming, globalState, activityMonitor, statusLine, rl);
1302
+ worldState = await handleSubscribe(rootPath, options.world, streaming, globalState, activityMonitor, statusLine, opikEnabledOverride, rl);
1168
1303
  currentWorldName = options.world;
1169
1304
  console.log(success(`Connected to world: ${currentWorldName}`));
1170
1305
  if (worldState?.world) {
@@ -1190,7 +1325,7 @@ async function runInteractiveMode(options) {
1190
1325
  try {
1191
1326
  activityMonitor.reset();
1192
1327
  statusLine.reset();
1193
- worldState = await handleSubscribe(effectiveRootPath, selectedWorld.worldName, streaming, globalState, activityMonitor, statusLine, rl);
1328
+ worldState = await handleSubscribe(effectiveRootPath, selectedWorld.worldName, streaming, globalState, activityMonitor, statusLine, opikEnabledOverride, rl);
1194
1329
  currentWorldName = selectedWorld.worldName;
1195
1330
  console.log(success(`Connected to world: ${currentWorldName}`));
1196
1331
  if (selectedWorld.externalPath) {
@@ -1218,7 +1353,7 @@ async function runInteractiveMode(options) {
1218
1353
  console.log('');
1219
1354
  // Display current chat messages after Quick Start tips
1220
1355
  if (worldState?.world) {
1221
- await displayChatMessages(worldState.world.id, worldState.world.currentChatId);
1356
+ await displayChatMessages(worldState.world.id, worldState.selectedChatId);
1222
1357
  }
1223
1358
  console.log(); // Empty line before prompt
1224
1359
  rl.prompt();
@@ -1252,7 +1387,7 @@ async function runInteractiveMode(options) {
1252
1387
  snapshot = activityMonitor.captureSnapshot();
1253
1388
  }
1254
1389
  try {
1255
- const result = await processCLIInput(trimmedInput, worldState?.world || null, 'HUMAN');
1390
+ const result = await processCLIInput(trimmedInput, worldState?.world || null, 'HUMAN', worldState?.selectedChatId || null);
1256
1391
  // Handle exit commands from result (redundant, but keep for safety)
1257
1392
  if (result.data?.exit) {
1258
1393
  if (isExiting)
@@ -1290,7 +1425,7 @@ async function runInteractiveMode(options) {
1290
1425
  logger.debug(`Subscribing to world: ${selectedWorld.worldName}...`);
1291
1426
  activityMonitor.reset();
1292
1427
  statusLine.reset();
1293
- worldState = await handleSubscribe(effectiveRootPath, selectedWorld.worldName, streaming, globalState, activityMonitor, statusLine, rl);
1428
+ worldState = await handleSubscribe(effectiveRootPath, selectedWorld.worldName, streaming, globalState, activityMonitor, statusLine, opikEnabledOverride, rl);
1294
1429
  currentWorldName = selectedWorld.worldName;
1295
1430
  console.log(success(`Connected to world: ${currentWorldName}`));
1296
1431
  if (selectedWorld.externalPath) {
@@ -1299,7 +1434,7 @@ async function runInteractiveMode(options) {
1299
1434
  if (worldState?.world) {
1300
1435
  console.log(`${gray('Agents:')} ${yellow(String(worldState.world.agents?.size || 0))} ${gray('| Turn Limit:')} ${yellow(String(worldState.world.turnLimit || 'N/A'))}`);
1301
1436
  // Display current chat messages
1302
- await displayChatMessages(worldState.world.id, worldState.world.currentChatId);
1437
+ await displayChatMessages(worldState.world.id, worldState.selectedChatId);
1303
1438
  }
1304
1439
  }
1305
1440
  catch (err) {
@@ -1337,6 +1472,7 @@ async function runInteractiveMode(options) {
1337
1472
  // console.log(boldBlue('Refreshing world state...'));
1338
1473
  const refreshedWorld = await worldState.subscription.refresh(rootPath);
1339
1474
  worldState.world = refreshedWorld;
1475
+ worldState.selectedChatId = selectedChatId;
1340
1476
  console.log(success('World state refreshed'));
1341
1477
  }
1342
1478
  }
@@ -1449,6 +1585,8 @@ async function runInteractiveMode(options) {
1449
1585
  // Use the subscription's refresh method to properly destroy old world and create new
1450
1586
  const refreshedWorld = await worldState.subscription.refresh(rootPath);
1451
1587
  worldState.world = refreshedWorld;
1588
+ const refreshedChatId = String(result.data?.currentChatId || refreshedWorld?.currentChatId || '').trim();
1589
+ worldState.selectedChatId = refreshedChatId || worldState.selectedChatId;
1452
1590
  console.log(success('World state refreshed'));
1453
1591
  }
1454
1592
  catch (err) {
@@ -1539,6 +1677,19 @@ function determineStreamingMode(streamingFlag, isTTY) {
1539
1677
  // Auto-detect: enable streaming for interactive (TTY), disable for pipeline
1540
1678
  return isTTY;
1541
1679
  }
1680
+ function parseOptionalBoolean(value) {
1681
+ if (!value) {
1682
+ return undefined;
1683
+ }
1684
+ const normalized = value.trim().toLowerCase();
1685
+ if (['true', '1', 'yes', 'on'].includes(normalized)) {
1686
+ return true;
1687
+ }
1688
+ if (['false', '0', 'no', 'off'].includes(normalized)) {
1689
+ return false;
1690
+ }
1691
+ return undefined;
1692
+ }
1542
1693
  // Main CLI entry point
1543
1694
  async function main() {
1544
1695
  // Configure LLM providers from environment variables at startup
@@ -1555,6 +1706,7 @@ async function main() {
1555
1706
  .option('-c, --command <cmd>', 'Command to execute in pipeline mode')
1556
1707
  .option('-l, --logLevel <level>', 'Set log level (trace, debug, info, warn, error)', 'error')
1557
1708
  .option('--streaming', 'Enable streaming responses (default: auto-detected from TTY)')
1709
+ .option('--opik-enabled <true|false>', 'Override OPIK_ENABLED for this CLI run')
1558
1710
  .option('-s, --server', 'Launch the server before running CLI')
1559
1711
  .allowUnknownOption()
1560
1712
  .allowExcessArguments()
@@ -0,0 +1,27 @@
1
+ /**
2
+ * CLI System Event Formatting Helpers
3
+ *
4
+ * Purpose:
5
+ * - Convert runtime `system` event payloads into readable CLI output text.
6
+ *
7
+ * Key Features:
8
+ * - Supports plain-string and structured-object system payloads.
9
+ * - Preserves important status families such as title updates and queue failures.
10
+ * - Keeps formatting pure so both interactive and pipeline paths share the same logic.
11
+ *
12
+ * Notes on Implementation:
13
+ * - Leaf helper with no terminal side effects.
14
+ * - Unknown payloads return `null` so callers can skip empty/noise events.
15
+ *
16
+ * Summary of Recent Changes:
17
+ * - 2026-03-12: Created for cross-client system-status parity.
18
+ */
19
+ export interface CliSystemEventPayload {
20
+ message?: unknown;
21
+ content?: unknown;
22
+ eventType?: unknown;
23
+ type?: unknown;
24
+ title?: unknown;
25
+ [key: string]: unknown;
26
+ }
27
+ export declare function getSystemEventDisplayText(eventData: CliSystemEventPayload | null | undefined): string | null;