@ai-setting/roy-agent-core 1.0.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 (378) hide show
  1. package/dist/index.js +99145 -0
  2. package/package.json +114 -0
  3. package/src/config/config-component.test.ts +627 -0
  4. package/src/config/config-component.ts +906 -0
  5. package/src/config/config-parser.test.ts +319 -0
  6. package/src/config/config-parser.ts +203 -0
  7. package/src/config/decentralized-config.test.ts +740 -0
  8. package/src/config/env-key.ts +210 -0
  9. package/src/config/env-source.test.ts +252 -0
  10. package/src/config/env-source.ts +301 -0
  11. package/src/config/file-source.test.ts +357 -0
  12. package/src/config/file-source.ts +421 -0
  13. package/src/config/index.ts +24 -0
  14. package/src/config/protocol-resolver.test.ts +217 -0
  15. package/src/config/protocol-resolver.ts +228 -0
  16. package/src/env/agent/agent-component.abort.test.ts +511 -0
  17. package/src/env/agent/agent-component.record-session.test.ts +349 -0
  18. package/src/env/agent/agent-component.test.ts +1389 -0
  19. package/src/env/agent/agent-component.tool-error.test.ts +327 -0
  20. package/src/env/agent/agent-component.ts +1711 -0
  21. package/src/env/agent/agent-config-registration.test.ts +226 -0
  22. package/src/env/agent/agent-config-registration.ts +46 -0
  23. package/src/env/agent/agent-reminder-plugin.integration.test.ts +243 -0
  24. package/src/env/agent/index.ts +10 -0
  25. package/src/env/agent/summary-agent.parse-hint.test.ts +360 -0
  26. package/src/env/agent/summary-agent.ts +508 -0
  27. package/src/env/agent/types.ts +536 -0
  28. package/src/env/commands/commands-component.test.ts +364 -0
  29. package/src/env/commands/commands-component.ts +604 -0
  30. package/src/env/commands/commands-config-registration.test.ts +198 -0
  31. package/src/env/commands/commands-config-registration.ts +38 -0
  32. package/src/env/commands/index.ts +21 -0
  33. package/src/env/commands/parser.test.ts +203 -0
  34. package/src/env/commands/parser.ts +115 -0
  35. package/src/env/commands/types.ts +184 -0
  36. package/src/env/commands-prompt-integration.test.ts +243 -0
  37. package/src/env/component-env.test.ts +119 -0
  38. package/src/env/component.ts +335 -0
  39. package/src/env/constants.test.ts +72 -0
  40. package/src/env/constants.ts +123 -0
  41. package/src/env/debug/debug-component.test.ts +114 -0
  42. package/src/env/debug/debug-component.ts +547 -0
  43. package/src/env/debug/formatters/index.ts +9 -0
  44. package/src/env/debug/formatters/repl-formatter.test.ts +139 -0
  45. package/src/env/debug/formatters/repl-formatter.ts +358 -0
  46. package/src/env/debug/formatters/trace-formatter.test.ts +119 -0
  47. package/src/env/debug/formatters/trace-formatter.ts +191 -0
  48. package/src/env/debug/formatters/tree-formatter.test.ts +107 -0
  49. package/src/env/debug/formatters/tree-formatter.ts +325 -0
  50. package/src/env/debug/index.ts +38 -0
  51. package/src/env/debug/parser/regex-parser.test.ts +201 -0
  52. package/src/env/debug/parser/regex-parser.ts +196 -0
  53. package/src/env/debug/parser/span-builder.test.ts +241 -0
  54. package/src/env/debug/parser/span-builder.ts +386 -0
  55. package/src/env/debug/reader/log-reader.test.ts +170 -0
  56. package/src/env/debug/reader/log-reader.ts +186 -0
  57. package/src/env/debug/reader/span-db-reader.test.ts +118 -0
  58. package/src/env/debug/reader/span-db-reader.ts +201 -0
  59. package/src/env/debug/types.test.ts +187 -0
  60. package/src/env/debug/types.ts +171 -0
  61. package/src/env/environment-init.test.ts +183 -0
  62. package/src/env/environment-lifecycle.test.ts +516 -0
  63. package/src/env/environment-service.test.ts +332 -0
  64. package/src/env/environment.handle-query.test.ts +96 -0
  65. package/src/env/environment.test.ts +232 -0
  66. package/src/env/environment.ts +708 -0
  67. package/src/env/errors.test.ts +165 -0
  68. package/src/env/errors.ts +157 -0
  69. package/src/env/event-source/event-source-agent-handler.test.ts +193 -0
  70. package/src/env/event-source/event-source-agent-handler.ts +111 -0
  71. package/src/env/event-source/event-source-component.process-cleanup.test.ts +236 -0
  72. package/src/env/event-source/event-source-component.stop.test.ts +346 -0
  73. package/src/env/event-source/event-source-component.test.ts +1207 -0
  74. package/src/env/event-source/event-source-component.ts +1379 -0
  75. package/src/env/event-source/event-source-config-registration.test.ts +242 -0
  76. package/src/env/event-source/event-source-config-registration.ts +37 -0
  77. package/src/env/event-source/event-source-integration.test.ts +320 -0
  78. package/src/env/event-source/event-source-platform.test.ts +630 -0
  79. package/src/env/event-source/types.ts +298 -0
  80. package/src/env/hook/global-hook-manager.ts +162 -0
  81. package/src/env/hook/hook-manager.test.ts +374 -0
  82. package/src/env/hook/hook-manager.ts +309 -0
  83. package/src/env/hook/index.ts +38 -0
  84. package/src/env/hook/types.ts +138 -0
  85. package/src/env/index.ts +144 -0
  86. package/src/env/interface.ts +203 -0
  87. package/src/env/llm/hooks.test.ts +293 -0
  88. package/src/env/llm/hooks.ts +316 -0
  89. package/src/env/llm/index.ts +61 -0
  90. package/src/env/llm/invoke-threshold-check.test.ts +88 -0
  91. package/src/env/llm/invoke-timeout.test.ts +54 -0
  92. package/src/env/llm/invoke.test.ts +71 -0
  93. package/src/env/llm/invoke.ts +1039 -0
  94. package/src/env/llm/llm-config.test.ts +523 -0
  95. package/src/env/llm/llm.test.ts +233 -0
  96. package/src/env/llm/llm.ts +568 -0
  97. package/src/env/llm/provider.test.ts +182 -0
  98. package/src/env/llm/provider.ts +108 -0
  99. package/src/env/llm/transform.test.ts +251 -0
  100. package/src/env/llm/transform.ts +286 -0
  101. package/src/env/llm/types.test.ts +580 -0
  102. package/src/env/llm/types.ts +424 -0
  103. package/src/env/log-trace/decorator-otel.test.ts +182 -0
  104. package/src/env/log-trace/decorator.ts +230 -0
  105. package/src/env/log-trace/index.ts +79 -0
  106. package/src/env/log-trace/log-trace-component.test.ts +242 -0
  107. package/src/env/log-trace/log-trace-component.ts +497 -0
  108. package/src/env/log-trace/log-trace-config-registration.test.ts +348 -0
  109. package/src/env/log-trace/log-trace-config-registration.ts +45 -0
  110. package/src/env/log-trace/logger.test.ts +149 -0
  111. package/src/env/log-trace/logger.ts +522 -0
  112. package/src/env/log-trace/opentelemetry/cli-propagation.test.ts +147 -0
  113. package/src/env/log-trace/opentelemetry/cli-propagation.ts +194 -0
  114. package/src/env/log-trace/opentelemetry/integration.test.ts +668 -0
  115. package/src/env/log-trace/opentelemetry/mod.ts +25 -0
  116. package/src/env/log-trace/opentelemetry/propagation-env.test.ts +181 -0
  117. package/src/env/log-trace/opentelemetry/propagation-env.ts +136 -0
  118. package/src/env/log-trace/opentelemetry/propagation.test.ts +259 -0
  119. package/src/env/log-trace/opentelemetry/propagation.ts +215 -0
  120. package/src/env/log-trace/opentelemetry/tracer-provider-context.test.ts +166 -0
  121. package/src/env/log-trace/opentelemetry/tracer-provider.test.ts +379 -0
  122. package/src/env/log-trace/opentelemetry/tracer-provider.ts +612 -0
  123. package/src/env/log-trace/span-storage.test.ts +145 -0
  124. package/src/env/log-trace/span-storage.ts +230 -0
  125. package/src/env/log-trace/trace-context.test.ts +187 -0
  126. package/src/env/log-trace/trace-context.ts +162 -0
  127. package/src/env/log-trace/types.test.ts +63 -0
  128. package/src/env/log-trace/types.ts +172 -0
  129. package/src/env/mcp/README.md +244 -0
  130. package/src/env/mcp/__integration__/mcp-component.integration.test.ts +373 -0
  131. package/src/env/mcp/config.test.ts +74 -0
  132. package/src/env/mcp/config.ts +116 -0
  133. package/src/env/mcp/index.ts +41 -0
  134. package/src/env/mcp/loader.test.ts +161 -0
  135. package/src/env/mcp/loader.ts +209 -0
  136. package/src/env/mcp/mcp-component.test.ts +111 -0
  137. package/src/env/mcp/mcp-component.ts +358 -0
  138. package/src/env/mcp/mcp-config-registration.test.ts +304 -0
  139. package/src/env/mcp/mcp-config-registration.ts +50 -0
  140. package/src/env/mcp/scanner.test.ts +170 -0
  141. package/src/env/mcp/scanner.ts +246 -0
  142. package/src/env/mcp/tool/adapter.test.ts +520 -0
  143. package/src/env/mcp/tool/adapter.ts +521 -0
  144. package/src/env/mcp/tool/index.ts +5 -0
  145. package/src/env/mcp/types.test.ts +171 -0
  146. package/src/env/mcp/types.ts +79 -0
  147. package/src/env/memory/README.md +177 -0
  148. package/src/env/memory/built-in/index.ts +59 -0
  149. package/src/env/memory/built-in/recall-memory.ts +103 -0
  150. package/src/env/memory/built-in/record-memory.ts +148 -0
  151. package/src/env/memory/index.ts +20 -0
  152. package/src/env/memory/memory-component.test.ts +239 -0
  153. package/src/env/memory/memory-component.ts +503 -0
  154. package/src/env/memory/memory-config-registration.test.ts +67 -0
  155. package/src/env/memory/memory-config-registration.ts +48 -0
  156. package/src/env/memory/memory-config.ts +45 -0
  157. package/src/env/memory/memory-file.test.ts +268 -0
  158. package/src/env/memory/plugin/index.ts +48 -0
  159. package/src/env/memory/plugin/memory-agent.test.ts +249 -0
  160. package/src/env/memory/plugin/memory-agent.ts +365 -0
  161. package/src/env/memory/plugin/memory-manager.ts +198 -0
  162. package/src/env/memory/plugin/memory-plugin-agent.test.ts +145 -0
  163. package/src/env/memory/plugin/memory-plugin.ts +210 -0
  164. package/src/env/memory/plugin/plugin-simplified.test.ts +51 -0
  165. package/src/env/memory/plugin/recall-memory.test.ts +106 -0
  166. package/src/env/memory/plugin/recall-memory.ts +53 -0
  167. package/src/env/memory/plugin/types.ts +101 -0
  168. package/src/env/memory/tools/memory-agent-tools.ts +228 -0
  169. package/src/env/memory/types.ts +85 -0
  170. package/src/env/paths.ts +118 -0
  171. package/src/env/prompt/index.ts +18 -0
  172. package/src/env/prompt/memory-prompts.test.ts +91 -0
  173. package/src/env/prompt/prompt-component.test.ts +491 -0
  174. package/src/env/prompt/prompt-component.ts +619 -0
  175. package/src/env/prompt/prompt-config-registration.test.ts +213 -0
  176. package/src/env/prompt/prompt-config-registration.ts +39 -0
  177. package/src/env/prompt/prompts-index.ts +504 -0
  178. package/src/env/prompt/renderer.ts +67 -0
  179. package/src/env/prompt/types.ts +136 -0
  180. package/src/env/session/hooks.ts +18 -0
  181. package/src/env/session/index.ts +37 -0
  182. package/src/env/session/search-query-parser.test.ts +425 -0
  183. package/src/env/session/search-query-parser.ts +171 -0
  184. package/src/env/session/session-checkpoint.test.ts +523 -0
  185. package/src/env/session/session-component.extract-recent-messages.test.ts +209 -0
  186. package/src/env/session/session-component.test.ts +132 -0
  187. package/src/env/session/session-component.ts +1249 -0
  188. package/src/env/session/session-config-registration.test.ts +138 -0
  189. package/src/env/session/session-config-registration.ts +52 -0
  190. package/src/env/session/session-message-converter.test.ts +763 -0
  191. package/src/env/session/session-message-converter.ts +415 -0
  192. package/src/env/session/session-message-e2e.test.ts +448 -0
  193. package/src/env/session/session-search.test.ts +391 -0
  194. package/src/env/session/session-store.test.ts +362 -0
  195. package/src/env/session/session-store.ts +141 -0
  196. package/src/env/session/storage/index.ts +6 -0
  197. package/src/env/session/storage/memory.ts +502 -0
  198. package/src/env/session/storage/sqlite.ts +794 -0
  199. package/src/env/session/types.ts +742 -0
  200. package/src/env/skill/config.ts +39 -0
  201. package/src/env/skill/index.ts +6 -0
  202. package/src/env/skill/parser.test.ts +116 -0
  203. package/src/env/skill/parser.ts +77 -0
  204. package/src/env/skill/scanner.test.ts +211 -0
  205. package/src/env/skill/scanner.ts +119 -0
  206. package/src/env/skill/skill-component.test.ts +234 -0
  207. package/src/env/skill/skill-component.ts +352 -0
  208. package/src/env/skill/skill-config-registration.test.ts +60 -0
  209. package/src/env/skill/skill-config-registration.ts +43 -0
  210. package/src/env/skill/tool/index.ts +1 -0
  211. package/src/env/skill/tool/skill-tool.test.ts +100 -0
  212. package/src/env/skill/tool/skill-tool.ts +72 -0
  213. package/src/env/skill/types.ts +64 -0
  214. package/src/env/task/delegate/delegate-tool.test.ts +498 -0
  215. package/src/env/task/delegate/delegate-tool.ts +1014 -0
  216. package/src/env/task/delegate/index.ts +18 -0
  217. package/src/env/task/delegate/stop-tool.test.ts +140 -0
  218. package/src/env/task/delegate/stop-tool.ts +119 -0
  219. package/src/env/task/delegate/task-events.test.ts +178 -0
  220. package/src/env/task/delegate/task-events.ts +143 -0
  221. package/src/env/task/hooks/contexts.test.ts +92 -0
  222. package/src/env/task/hooks/contexts.ts +192 -0
  223. package/src/env/task/hooks/index.ts +23 -0
  224. package/src/env/task/hooks/task-hook-points.test.ts +32 -0
  225. package/src/env/task/hooks/task-hook-points.ts +54 -0
  226. package/src/env/task/index.ts +7 -0
  227. package/src/env/task/plugins/index.ts +13 -0
  228. package/src/env/task/plugins/task-plugin.test.ts +74 -0
  229. package/src/env/task/plugins/task-plugin.ts +89 -0
  230. package/src/env/task/plugins/task-tag-plugin.test.ts +377 -0
  231. package/src/env/task/plugins/task-tag-plugin.ts +319 -0
  232. package/src/env/task/plugins/task-workflow-extractor.integration.test.ts +226 -0
  233. package/src/env/task/plugins/workflow-extractor-agent.test.ts +107 -0
  234. package/src/env/task/plugins/workflow-extractor-agent.ts +225 -0
  235. package/src/env/task/storage/index.ts +6 -0
  236. package/src/env/task/storage/sqlite-task-store.test.ts +283 -0
  237. package/src/env/task/storage/sqlite-task-store.ts +903 -0
  238. package/src/env/task/storage/task-search.test.ts +291 -0
  239. package/src/env/task/tag-service.test.ts +198 -0
  240. package/src/env/task/tag-service.ts +264 -0
  241. package/src/env/task/task-component.test.ts +193 -0
  242. package/src/env/task/task-component.ts +658 -0
  243. package/src/env/task/task-config-registration.test.ts +57 -0
  244. package/src/env/task/task-config-registration.ts +37 -0
  245. package/src/env/task/task-types.test.ts +137 -0
  246. package/src/env/task/tools/complete-tool.ts +44 -0
  247. package/src/env/task/tools/create-tool.ts +49 -0
  248. package/src/env/task/tools/delete-tool.ts +43 -0
  249. package/src/env/task/tools/get-tool.ts +59 -0
  250. package/src/env/task/tools/index.ts +10 -0
  251. package/src/env/task/tools/list-tool.ts +40 -0
  252. package/src/env/task/tools/operation/create-tool.ts +48 -0
  253. package/src/env/task/tools/operation/delete-tool.ts +43 -0
  254. package/src/env/task/tools/operation/get-tool.ts +43 -0
  255. package/src/env/task/tools/operation/index.ts +9 -0
  256. package/src/env/task/tools/operation/list-tool.ts +40 -0
  257. package/src/env/task/tools/operation/operation-tools.test.ts +274 -0
  258. package/src/env/task/tools/operation/operation-types.ts +75 -0
  259. package/src/env/task/tools/operation/update-tool.ts +47 -0
  260. package/src/env/task/tools/task-tools.test.ts +203 -0
  261. package/src/env/task/tools/task-types.test.ts +75 -0
  262. package/src/env/task/tools/task-types.ts +68 -0
  263. package/src/env/task/tools/update-tool.ts +70 -0
  264. package/src/env/task/types.ts +160 -0
  265. package/src/env/tool/built-in/bash.ts +201 -0
  266. package/src/env/tool/built-in/echo.ts +29 -0
  267. package/src/env/tool/built-in/edit-file.test.ts +136 -0
  268. package/src/env/tool/built-in/edit-file.ts +92 -0
  269. package/src/env/tool/built-in/glob.test.ts +94 -0
  270. package/src/env/tool/built-in/glob.ts +65 -0
  271. package/src/env/tool/built-in/grep.test.ts +122 -0
  272. package/src/env/tool/built-in/grep.ts +108 -0
  273. package/src/env/tool/built-in/index.ts +44 -0
  274. package/src/env/tool/built-in/read-file.test.ts +84 -0
  275. package/src/env/tool/built-in/read-file.ts +75 -0
  276. package/src/env/tool/built-in/write-file.test.ts +119 -0
  277. package/src/env/tool/built-in/write-file.ts +68 -0
  278. package/src/env/tool/index.ts +24 -0
  279. package/src/env/tool/registry.test.ts +257 -0
  280. package/src/env/tool/registry.ts +167 -0
  281. package/src/env/tool/tool-component.test.ts +559 -0
  282. package/src/env/tool/tool-component.ts +563 -0
  283. package/src/env/tool/tool-config-registration.test.ts +249 -0
  284. package/src/env/tool/tool-config-registration.ts +46 -0
  285. package/src/env/tool/types.ts +267 -0
  286. package/src/env/tool/validator.test.ts +143 -0
  287. package/src/env/tool/validator.ts +44 -0
  288. package/src/env/types.ts +180 -0
  289. package/src/env/workflow/ask-user-tool-registration.test.ts +216 -0
  290. package/src/env/workflow/complex-workflow.integration.test.ts +1900 -0
  291. package/src/env/workflow/decorators/decorator-node.ts +229 -0
  292. package/src/env/workflow/decorators/decorator.test.ts +196 -0
  293. package/src/env/workflow/decorators/edge.ts +82 -0
  294. package/src/env/workflow/decorators/index.ts +31 -0
  295. package/src/env/workflow/decorators/node-as.ts +98 -0
  296. package/src/env/workflow/decorators/workflow.ts +54 -0
  297. package/src/env/workflow/engine/dag-manager.test.ts +570 -0
  298. package/src/env/workflow/engine/dag-manager.ts +594 -0
  299. package/src/env/workflow/engine/engine.ts +1422 -0
  300. package/src/env/workflow/engine/event-bus.test.ts +359 -0
  301. package/src/env/workflow/engine/event-bus.ts +156 -0
  302. package/src/env/workflow/engine/executor-agent-session.test.ts +84 -0
  303. package/src/env/workflow/engine/executor.test.ts +619 -0
  304. package/src/env/workflow/engine/executor.ts +593 -0
  305. package/src/env/workflow/engine/index.ts +24 -0
  306. package/src/env/workflow/engine/node-registry.test.ts +560 -0
  307. package/src/env/workflow/engine/node-registry.ts +289 -0
  308. package/src/env/workflow/engine/resume-removed.test.ts +22 -0
  309. package/src/env/workflow/engine/scheduler.test.ts +715 -0
  310. package/src/env/workflow/engine/scheduler.ts +318 -0
  311. package/src/env/workflow/engine/workflow-engine.test.ts +815 -0
  312. package/src/env/workflow/extractor/workflow-converter.ts +306 -0
  313. package/src/env/workflow/fixtures.ts +380 -0
  314. package/src/env/workflow/index.ts +38 -0
  315. package/src/env/workflow/integration/run-resume-unified.test.ts +186 -0
  316. package/src/env/workflow/integration/service-integration.test.ts +267 -0
  317. package/src/env/workflow/metadata/keys.ts +12 -0
  318. package/src/env/workflow/nodes/agent-component-adapter.test.ts +318 -0
  319. package/src/env/workflow/nodes/agent-component-adapter.ts +448 -0
  320. package/src/env/workflow/nodes/agent-node.test.ts +371 -0
  321. package/src/env/workflow/nodes/agent-node.ts +598 -0
  322. package/src/env/workflow/nodes/ask-user-node.ts +113 -0
  323. package/src/env/workflow/nodes/condition-node.ts +200 -0
  324. package/src/env/workflow/nodes/index.ts +9 -0
  325. package/src/env/workflow/nodes/merge-node.ts +141 -0
  326. package/src/env/workflow/nodes/skill-node.test.ts +253 -0
  327. package/src/env/workflow/nodes/skill-node.ts +393 -0
  328. package/src/env/workflow/nodes/tool-node.test.ts +251 -0
  329. package/src/env/workflow/nodes/tool-node.ts +493 -0
  330. package/src/env/workflow/nodes/workflow-llm-history.test.ts +455 -0
  331. package/src/env/workflow/nodes/workflow-node.test.ts +315 -0
  332. package/src/env/workflow/nodes/workflow-node.ts +311 -0
  333. package/src/env/workflow/service/index.ts +27 -0
  334. package/src/env/workflow/service/registry.test.ts +133 -0
  335. package/src/env/workflow/service/registry.ts +71 -0
  336. package/src/env/workflow/service/workflow-service.test.ts +310 -0
  337. package/src/env/workflow/service/workflow-service.ts +393 -0
  338. package/src/env/workflow/storage/index.ts +28 -0
  339. package/src/env/workflow/storage/mock-repositories.ts +385 -0
  340. package/src/env/workflow/storage/sqlite.test.ts +179 -0
  341. package/src/env/workflow/storage/sqlite.ts +163 -0
  342. package/src/env/workflow/storage/workflow-repo.test.ts +780 -0
  343. package/src/env/workflow/storage/workflow-repo.ts +342 -0
  344. package/src/env/workflow/tools/ask-user-tool.ts +82 -0
  345. package/src/env/workflow/tools/index.ts +26 -0
  346. package/src/env/workflow/tools/run-workflow.test.ts +352 -0
  347. package/src/env/workflow/tools/run-workflow.ts +214 -0
  348. package/src/env/workflow/types/context.ts +18 -0
  349. package/src/env/workflow/types/decorators-types.ts +198 -0
  350. package/src/env/workflow/types/event.test.ts +515 -0
  351. package/src/env/workflow/types/event.ts +193 -0
  352. package/src/env/workflow/types/index.ts +49 -0
  353. package/src/env/workflow/types/run.test.ts +437 -0
  354. package/src/env/workflow/types/run.ts +173 -0
  355. package/src/env/workflow/types/workflow-hil.ts +114 -0
  356. package/src/env/workflow/types/workflow-message.test.ts +138 -0
  357. package/src/env/workflow/types/workflow-message.ts +196 -0
  358. package/src/env/workflow/types/workflow-session.test.ts +95 -0
  359. package/src/env/workflow/types/workflow-session.ts +59 -0
  360. package/src/env/workflow/types/workflow.test.ts +495 -0
  361. package/src/env/workflow/types/workflow.ts +195 -0
  362. package/src/env/workflow/types_compat.ts +51 -0
  363. package/src/env/workflow/utils/create-workflow.ts +47 -0
  364. package/src/env/workflow/utils/execution-state.ts +245 -0
  365. package/src/env/workflow/utils/index.ts +18 -0
  366. package/src/env/workflow/utils/node-registry-helper.ts +58 -0
  367. package/src/env/workflow/utils/recovery-validator.test.ts +460 -0
  368. package/src/env/workflow/utils/recovery-validator.ts +377 -0
  369. package/src/env/workflow/utils/session-parser.test.ts +111 -0
  370. package/src/env/workflow/utils/session-parser.ts +94 -0
  371. package/src/env/workflow/utils/session-recovery.test.ts +334 -0
  372. package/src/env/workflow/utils/session-recovery.ts +188 -0
  373. package/src/env/workflow/utils/template-resolver.test.ts +258 -0
  374. package/src/env/workflow/utils/template-resolver.ts +436 -0
  375. package/src/env/workflow/utils/validation-rules.ts +149 -0
  376. package/src/env/workflow/workflow-component.ts +544 -0
  377. package/src/index.ts +422 -0
  378. package/src/utils/id.ts +21 -0
@@ -0,0 +1,386 @@
1
+ /**
2
+ * @fileoverview Span Builder
3
+ *
4
+ * Builds TraceEntry objects from parsed log lines and constructs call trees.
5
+ */
6
+
7
+ import type { ParsedLogLine, TraceEntry, TraceTreeNode } from '../types';
8
+ import { RegexParser } from './regex-parser';
9
+
10
+ /**
11
+ * Paired enter/quit entries
12
+ */
13
+ interface PairedSpan {
14
+ enter: TraceEntry;
15
+ quit: TraceEntry;
16
+ durationMs: number;
17
+ }
18
+
19
+ /**
20
+ * Span Builder for constructing trace entries and call trees
21
+ */
22
+ export class SpanBuilder {
23
+ private parser: RegexParser;
24
+
25
+ constructor() {
26
+ this.parser = new RegexParser();
27
+ }
28
+
29
+ /**
30
+ * Build trace entries from parsed log lines
31
+ */
32
+ buildTraceEntries(lines: ParsedLogLine[]): TraceEntry[] {
33
+ const entries: TraceEntry[] = [];
34
+
35
+ for (const line of lines) {
36
+ const entry = this.buildTraceEntry(line);
37
+ if (entry) {
38
+ entries.push(entry);
39
+ }
40
+ }
41
+
42
+ // Sort by timestamp
43
+ entries.sort((a, b) => a.timestamp.localeCompare(b.timestamp));
44
+
45
+ return entries;
46
+ }
47
+
48
+ /**
49
+ * Build a single trace entry from a parsed log line
50
+ */
51
+ private buildTraceEntry(line: ParsedLogLine): TraceEntry | null {
52
+ // Use requestId from parsed line if available, otherwise extract from raw line
53
+ const traceId = line.requestId || this.extractTraceId(line.raw);
54
+
55
+ const entry: TraceEntry = {
56
+ // Use traceId if available, otherwise generate a virtual one based on function and timestamp
57
+ traceId: traceId || this.generateVirtualTraceId(line.method, line.timestamp),
58
+ timestamp: line.timestamp,
59
+ function: line.method,
60
+ action: line.actionType,
61
+ };
62
+
63
+ // Parse args based on action type
64
+ switch (line.actionType) {
65
+ case 'enter':
66
+ entry.params = this.parser.parseArgs(line.rawArgs) as unknown[] | undefined;
67
+ break;
68
+ case 'quit':
69
+ entry.result = this.parser.parseArgs(line.rawArgs);
70
+ break;
71
+ case 'error':
72
+ entry.error = line.rawArgs;
73
+ break;
74
+ }
75
+
76
+ return entry;
77
+ }
78
+
79
+ /**
80
+ * Generate a virtual trace ID when no real traceId is present
81
+ * Uses function name and timestamp to create a pseudo-traceId
82
+ */
83
+ generateVirtualTraceId(functionName: string, timestamp: string): string {
84
+ // Create a hash-like ID from function name and timestamp
85
+ const base = `${functionName}:${timestamp}`;
86
+ let hash = 0;
87
+ for (let i = 0; i < base.length; i++) {
88
+ const char = base.charCodeAt(i);
89
+ hash = ((hash << 5) - hash) + char;
90
+ hash = hash & hash; // Convert to 32bit integer
91
+ }
92
+ return `vtrace_${Math.abs(hash).toString(36)}`;
93
+ }
94
+
95
+ /**
96
+ * Extract trace ID from log line
97
+ */
98
+ private extractTraceId(line: string): string | null {
99
+ return this.parser.extractTraceId(line);
100
+ }
101
+
102
+ /**
103
+ * Calculate duration between enter and quit entries
104
+ */
105
+ calculateDuration(enter: TraceEntry, quit: TraceEntry): number {
106
+ try {
107
+ const enterTime = new Date(enter.timestamp).getTime();
108
+ const quitTime = new Date(quit.timestamp).getTime();
109
+
110
+ if (isNaN(enterTime) || isNaN(quitTime)) {
111
+ return 0;
112
+ }
113
+
114
+ return quitTime - enterTime;
115
+ } catch {
116
+ return 0;
117
+ }
118
+ }
119
+
120
+ /**
121
+ * Pair enter and quit entries
122
+ */
123
+ pairEnterQuit(entries: TraceEntry[]): PairedSpan[] {
124
+ const paired: PairedSpan[] = [];
125
+ const enterStack: TraceEntry[] = [];
126
+
127
+ for (const entry of entries) {
128
+ if (entry.action === 'enter') {
129
+ enterStack.push(entry);
130
+ } else if (entry.action === 'quit' && enterStack.length > 0) {
131
+ // Match with the most recent unmatched enter
132
+ const enter = enterStack.pop()!;
133
+ const duration = this.calculateDuration(enter, entry);
134
+
135
+ paired.push({
136
+ enter,
137
+ quit: entry,
138
+ durationMs: duration,
139
+ });
140
+ }
141
+ }
142
+
143
+ return paired;
144
+ }
145
+
146
+ /**
147
+ * Build a call tree from trace entries using call stack tracking
148
+ *
149
+ * Enhanced to support both:
150
+ * 1. Traditional enter/quit pair-based tree building (from log files)
151
+ * 2. Parent-child hierarchy-based tree building (from SQLite spans)
152
+ */
153
+ buildCallTree(entries: TraceEntry[]): TraceTreeNode | null {
154
+ if (entries.length === 0) {
155
+ return null;
156
+ }
157
+
158
+ // Check if entries contain parent-child info (from SQLite spans)
159
+ // Entries from SQLite have spanId/parentSpanId as direct properties
160
+ const hasSpanHierarchy = entries.some(e =>
161
+ e.spanId !== undefined || e.parentSpanId !== undefined
162
+ );
163
+
164
+ if (hasSpanHierarchy) {
165
+ return this.buildCallTreeFromHierarchy(entries);
166
+ }
167
+
168
+ // Fall back to traditional enter/quit pairing
169
+ return this.buildCallTreeFromPairs(entries);
170
+ }
171
+
172
+ /**
173
+ * Build call tree from parent-child span hierarchy (for SQLite spans)
174
+ */
175
+ buildCallTreeFromHierarchy(entries: TraceEntry[]): TraceTreeNode | null {
176
+ // Build a map of spanId -> node
177
+ const nodeMap = new Map<string, TraceTreeNode>();
178
+ const rootNodes: TraceTreeNode[] = [];
179
+ const addedToRoots = new Set<string>();
180
+
181
+ // Create nodes from entries - only process 'enter' entries for the tree
182
+ const enterEntries = entries.filter(e => e.action === 'enter');
183
+
184
+ for (const entry of enterEntries) {
185
+ const spanId = entry.spanId;
186
+ const parentSpanId = entry.parentSpanId;
187
+
188
+ // Skip if already processed
189
+ if (spanId && nodeMap.has(spanId)) {
190
+ continue;
191
+ }
192
+
193
+ // Create node
194
+ const node: TraceTreeNode = {
195
+ traceId: entry.traceId,
196
+ function: entry.function,
197
+ startTime: entry.timestamp,
198
+ // Find corresponding quit entry for duration
199
+ endTime: undefined,
200
+ durationMs: entry.durationMs,
201
+ children: [],
202
+ entry,
203
+ spanId,
204
+ parentSpanId,
205
+ };
206
+
207
+ if (spanId) {
208
+ nodeMap.set(spanId, node);
209
+ }
210
+
211
+ // Track as root candidate if no parent or parent not in same trace
212
+ if (!parentSpanId || !nodeMap.has(parentSpanId)) {
213
+ rootNodes.push(node);
214
+ if (spanId) addedToRoots.add(spanId);
215
+ }
216
+ }
217
+
218
+ // Find quit entries and update endTime/duration
219
+ const quitEntries = entries.filter(e => e.action === 'quit');
220
+ for (const quit of quitEntries) {
221
+ if (quit.spanId) {
222
+ const node = nodeMap.get(quit.spanId);
223
+ if (node) {
224
+ node.endTime = quit.timestamp;
225
+ node.durationMs = quit.durationMs || (node.endTime && node.startTime
226
+ ? new Date(node.endTime).getTime() - new Date(node.startTime).getTime()
227
+ : undefined);
228
+ }
229
+ }
230
+ }
231
+
232
+ // Build parent-child relationships
233
+ // Only connect to parent if it belongs to the same trace
234
+ for (const node of nodeMap.values()) {
235
+ if (node.parentSpanId && nodeMap.has(node.parentSpanId)) {
236
+ const parent = nodeMap.get(node.parentSpanId)!;
237
+ // Only add as child if parent is in the same trace
238
+ if (parent.traceId === node.traceId) {
239
+ parent.children.push(node);
240
+ // Remove from roots if it was added there
241
+ rootNodes.splice(rootNodes.indexOf(node), 1);
242
+ }
243
+ }
244
+ }
245
+
246
+ // If no explicit roots, try to find from entries without parentSpanId
247
+ if (rootNodes.length === 0) {
248
+ for (const entry of enterEntries) {
249
+ if (!entry.parentSpanId) {
250
+ const spanId = entry.spanId;
251
+ if (spanId && nodeMap.has(spanId) && !addedToRoots.has(spanId)) {
252
+ rootNodes.push(nodeMap.get(spanId)!);
253
+ }
254
+ }
255
+ }
256
+ }
257
+
258
+ // Sort roots by start time
259
+ rootNodes.sort((a, b) => a.startTime.localeCompare(b.startTime));
260
+
261
+ // Merge multiple root nodes into a single tree if needed
262
+ if (rootNodes.length === 0) {
263
+ return null;
264
+ }
265
+
266
+ if (rootNodes.length === 1) {
267
+ return rootNodes[0];
268
+ }
269
+
270
+ // Create a virtual root node if multiple roots exist
271
+ const allStartTimes = rootNodes.map(n => new Date(n.startTime).getTime());
272
+ const allEndTimes = rootNodes.map(n => n.endTime ? new Date(n.endTime).getTime() : 0).filter(t => t > 0);
273
+
274
+ return {
275
+ traceId: entries[0]?.traceId || 'merged',
276
+ function: '(root)',
277
+ children: rootNodes,
278
+ startTime: new Date(Math.min(...allStartTimes)).toISOString(),
279
+ endTime: allEndTimes.length > 0
280
+ ? new Date(Math.max(...allEndTimes)).toISOString()
281
+ : undefined,
282
+ durationMs: allEndTimes.length > 0 && allStartTimes.length > 0
283
+ ? Math.max(...allEndTimes) - Math.min(...allStartTimes)
284
+ : undefined,
285
+ };
286
+ }
287
+
288
+ /**
289
+ * Build call tree from traditional enter/quit pairs (for log files)
290
+ */
291
+ buildCallTreeFromPairs(entries: TraceEntry[]): TraceTreeNode | null {
292
+ // Sort entries by timestamp to ensure correct call stack order
293
+ const sortedEntries = [...entries].sort((a, b) =>
294
+ a.timestamp.localeCompare(b.timestamp)
295
+ );
296
+
297
+ // Pair enter/quit entries first
298
+ const paired = this.pairEnterQuit(sortedEntries);
299
+
300
+ if (paired.length === 0) {
301
+ return null;
302
+ }
303
+
304
+ // Build tree using call stack simulation
305
+ const stack: { node: TraceTreeNode; paired: PairedSpan }[] = [];
306
+ let root: TraceTreeNode | null = null;
307
+
308
+ // Process sorted entries sequentially to track call depth
309
+ for (const entry of sortedEntries) {
310
+ if (entry.action === 'enter') {
311
+ // Find the paired quit for this enter
312
+ const span = paired.find(p => p.enter === entry);
313
+ if (!span) continue;
314
+
315
+ const node = this.buildNodeFromPaired(span);
316
+
317
+ if (stack.length === 0) {
318
+ // This is the root
319
+ root = node;
320
+ } else {
321
+ // Add to current parent's children
322
+ stack[stack.length - 1].node.children.push(node);
323
+ }
324
+
325
+ stack.push({ node, paired: span });
326
+ } else if (entry.action === 'quit' && stack.length > 0) {
327
+ // Pop the stack - the function is returning
328
+ stack.pop();
329
+ }
330
+ }
331
+
332
+ return root;
333
+ }
334
+
335
+ /**
336
+ * Build a tree node from a paired span
337
+ */
338
+ private buildNodeFromPaired(span: PairedSpan): TraceTreeNode {
339
+ return {
340
+ traceId: span.enter.traceId,
341
+ function: span.enter.function,
342
+ startTime: span.enter.timestamp,
343
+ endTime: span.quit.timestamp,
344
+ durationMs: span.durationMs,
345
+ children: [],
346
+ entry: span.enter,
347
+ };
348
+ }
349
+
350
+ /**
351
+ * Merge entries from multiple functions into a single call tree
352
+ */
353
+ buildMergedTree(entriesByFunction: Map<string, TraceEntry[]>): TraceTreeNode | null {
354
+ // Get all entries across functions, sorted by timestamp
355
+ const allEntries: TraceEntry[] = [];
356
+
357
+ for (const entries of entriesByFunction.values()) {
358
+ allEntries.push(...entries);
359
+ }
360
+
361
+ allEntries.sort((a, b) => a.timestamp.localeCompare(b.timestamp));
362
+
363
+ return this.buildCallTree(allEntries);
364
+ }
365
+
366
+ /**
367
+ * Get duration summary for entries
368
+ */
369
+ getDurationSummary(entries: TraceEntry[]): Map<string, { count: number; totalMs: number; avgMs: number }> {
370
+ const summary = new Map<string, { count: number; totalMs: number; avgMs: number }>();
371
+ const paired = this.pairEnterQuit(entries);
372
+
373
+ for (const span of paired) {
374
+ const func = span.enter.function;
375
+ const existing = summary.get(func) || { count: 0, totalMs: 0, avgMs: 0 };
376
+
377
+ existing.count++;
378
+ existing.totalMs += span.durationMs;
379
+ existing.avgMs = Math.round(existing.totalMs / existing.count);
380
+
381
+ summary.set(func, existing);
382
+ }
383
+
384
+ return summary;
385
+ }
386
+ }
@@ -0,0 +1,170 @@
1
+ import { describe, expect, test, beforeAll, afterAll } from 'bun:test';
2
+ import { writeFileSync, mkdirSync, rmSync } from 'fs';
3
+ import { join } from 'path';
4
+ import { LogReader } from './log-reader';
5
+
6
+ describe('LogReader', () => {
7
+ const testDir = '/tmp/roy-debug-test';
8
+ let reader: LogReader;
9
+
10
+ beforeAll(() => {
11
+ mkdirSync(testDir, { recursive: true });
12
+ reader = new LogReader({ logDir: testDir });
13
+ });
14
+
15
+ afterAll(() => {
16
+ rmSync(testDir, { recursive: true });
17
+ });
18
+
19
+ describe('getLogPath', () => {
20
+ test('should return default app.log path', () => {
21
+ const path = reader.getLogPath();
22
+ expect(path).toContain('app.log');
23
+ });
24
+
25
+ test('should return custom filename path', () => {
26
+ const path = reader.getLogPath('custom.log');
27
+ expect(path).toContain('custom.log');
28
+ });
29
+
30
+ test('should use absolute path directly', () => {
31
+ const absPath = '/absolute/path/server.log';
32
+ const path = reader.getLogPath(absPath);
33
+ expect(path).toBe(absPath);
34
+ });
35
+ });
36
+
37
+ describe('findLogFiles', () => {
38
+ test('should return array of files', async () => {
39
+ const files = await reader.findLogFiles();
40
+
41
+ expect(Array.isArray(files)).toBe(true);
42
+ });
43
+
44
+ test('should handle custom pattern', async () => {
45
+ // Create test log file
46
+ writeFileSync(join(testDir, 'custom.log'), 'test log');
47
+
48
+ const files = await reader.findLogFiles('custom.log');
49
+
50
+ expect(Array.isArray(files)).toBe(true);
51
+ });
52
+
53
+ test('should use forward slashes for glob pattern (Windows compatibility)', async () => {
54
+ // Create test log files
55
+ writeFileSync(join(testDir, 'app.log'), 'test');
56
+ writeFileSync(join(testDir, 'error.log'), 'test');
57
+
58
+ const files = await reader.findLogFiles('*.log');
59
+
60
+ // Verify files are found (proves glob pattern works)
61
+ expect(files.length).toBeGreaterThanOrEqual(2);
62
+
63
+ // Verify returned paths use forward slashes (not backslashes)
64
+ for (const file of files) {
65
+ expect(file).not.toContain('\\');
66
+ expect(file).toContain('/');
67
+ }
68
+ });
69
+ });
70
+
71
+ describe('readLines', () => {
72
+ test('should read lines from file', async () => {
73
+ const testFile = join(testDir, 'read-test.log');
74
+ writeFileSync(testFile, 'line1\nline2\nline3\n');
75
+
76
+ const lines: string[] = [];
77
+ for await (const line of reader.readLines(testFile)) {
78
+ lines.push(line);
79
+ }
80
+
81
+ expect(lines).toEqual(['line1', 'line2', 'line3']);
82
+ });
83
+
84
+ test('should handle empty file', async () => {
85
+ const testFile = join(testDir, 'empty.log');
86
+ writeFileSync(testFile, '');
87
+
88
+ const lines: string[] = [];
89
+ for await (const line of reader.readLines(testFile)) {
90
+ lines.push(line);
91
+ }
92
+
93
+ expect(lines).toEqual([]);
94
+ });
95
+
96
+ test('should handle file with trailing newline', async () => {
97
+ const testFile = join(testDir, 'trailing.log');
98
+ writeFileSync(testFile, 'line1\nline2\n');
99
+
100
+ const lines: string[] = [];
101
+ for await (const line of reader.readLines(testFile)) {
102
+ lines.push(line);
103
+ }
104
+
105
+ expect(lines).toEqual(['line1', 'line2']);
106
+ });
107
+ });
108
+
109
+ describe('filterByTime', () => {
110
+ test('should filter by since time', async () => {
111
+ const testFile = join(testDir, 'time-filter.log');
112
+ writeFileSync(testFile,
113
+ '2026-04-08 10:00:00.000 line1\n' +
114
+ '2026-04-08 11:00:00.000 line2\n' +
115
+ '2026-04-08 12:00:00.000 line3\n'
116
+ );
117
+
118
+ const lines: string[] = [];
119
+ for await (const line of reader.readLines(testFile, {
120
+ since: '2026-04-08T11:00:00'
121
+ })) {
122
+ lines.push(line);
123
+ }
124
+
125
+ expect(lines.length).toBe(2);
126
+ expect(lines[0]).toContain('11:00:00');
127
+ expect(lines[1]).toContain('12:00:00');
128
+ });
129
+
130
+ test('should filter by until time', async () => {
131
+ const testFile = join(testDir, 'until-filter.log');
132
+ writeFileSync(testFile,
133
+ '2026-04-08 10:00:00.000 line1\n' +
134
+ '2026-04-08 11:00:00.000 line2\n' +
135
+ '2026-04-08 12:00:00.000 line3\n'
136
+ );
137
+
138
+ const lines: string[] = [];
139
+ for await (const line of reader.readLines(testFile, {
140
+ until: '2026-04-08T11:30:00'
141
+ })) {
142
+ lines.push(line);
143
+ }
144
+
145
+ expect(lines.length).toBe(2);
146
+ expect(lines[0]).toContain('10:00:00');
147
+ expect(lines[1]).toContain('11:00:00');
148
+ });
149
+
150
+ test('should filter by both since and until', async () => {
151
+ const testFile = join(testDir, 'range-filter.log');
152
+ writeFileSync(testFile,
153
+ '2026-04-08 10:00:00.000 line1\n' +
154
+ '2026-04-08 11:00:00.000 line2\n' +
155
+ '2026-04-08 12:00:00.000 line3\n'
156
+ );
157
+
158
+ const lines: string[] = [];
159
+ for await (const line of reader.readLines(testFile, {
160
+ since: '2026-04-08T10:30:00',
161
+ until: '2026-04-08T11:30:00'
162
+ })) {
163
+ lines.push(line);
164
+ }
165
+
166
+ expect(lines.length).toBe(1);
167
+ expect(lines[0]).toContain('11:00:00');
168
+ });
169
+ });
170
+ });