@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,39 @@
1
+ import path from "path";
2
+ import os from "os";
3
+ import { type SkillConfig } from "./types";
4
+
5
+ /**
6
+ * 默认配置
7
+ */
8
+ export const DEFAULT_SKILL_CONFIG: SkillConfig = {
9
+ skillPaths: [
10
+ // 用户路径 (~/.config/roy-agent/skills/)
11
+ {
12
+ type: "user",
13
+ path: path.join(os.homedir(), ".config", "roy-agent", "skills"),
14
+ },
15
+ // 项目路径 (.roy/skills/)
16
+ {
17
+ type: "project",
18
+ path: ".roy/skills",
19
+ },
20
+ ],
21
+ recursive: true,
22
+ cacheEnabled: true,
23
+ };
24
+
25
+ /**
26
+ * 优先级映射(后面的优先级更高)
27
+ */
28
+ export const SOURCE_PRIORITY: Record<string, number> = {
29
+ "built-in": 0,
30
+ "user": 1,
31
+ "project": 2,
32
+ };
33
+
34
+ /**
35
+ * 获取来源优先级
36
+ */
37
+ export function getSourcePriority(source: string): number {
38
+ return SOURCE_PRIORITY[source] ?? 0;
39
+ }
@@ -0,0 +1,6 @@
1
+ export { SkillComponent } from "./skill-component";
2
+ export * from "./types";
3
+ export * from "./config";
4
+ export * from "./parser";
5
+ export * from "./scanner";
6
+ export * from "./tool";
@@ -0,0 +1,116 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
+ import fs from "fs/promises";
3
+ import path from "path";
4
+ import { parseFrontmatter, parseSkillFile } from "./parser";
5
+ import type { SkillSource } from "./types";
6
+
7
+ describe("parser", () => {
8
+ const testDir = path.join(__dirname, "__test_temp__");
9
+
10
+ beforeEach(async () => {
11
+ await fs.mkdir(testDir, { recursive: true });
12
+ });
13
+
14
+ afterEach(async () => {
15
+ try {
16
+ await fs.rm(testDir, { recursive: true, force: true });
17
+ } catch {
18
+ // ignore
19
+ }
20
+ });
21
+
22
+ describe("parseFrontmatter", () => {
23
+ it("should parse simple frontmatter with quoted values", () => {
24
+ const text = `name: brainstorming
25
+ description: "Use before any creative work..."`;
26
+
27
+ const result = parseFrontmatter(text);
28
+
29
+ expect(result.name).toBe("brainstorming");
30
+ expect(result.description).toBe("Use before any creative work...");
31
+ });
32
+
33
+ it("should parse frontmatter with unquoted values", () => {
34
+ const text = `name: tdd
35
+ description: Use when implementing features`;
36
+
37
+ const result = parseFrontmatter(text);
38
+
39
+ expect(result.name).toBe("tdd");
40
+ expect(result.description).toBe("Use when implementing features");
41
+ });
42
+
43
+ it("should handle empty text", () => {
44
+ const result = parseFrontmatter("");
45
+
46
+ expect(Object.keys(result).length).toBe(0);
47
+ });
48
+ });
49
+
50
+ describe("parseSkillFile", () => {
51
+ it("should parse valid SKILL.md file", async () => {
52
+ const filePath = path.join(testDir, "test-skill.md");
53
+ const content = `---
54
+ name: test-skill
55
+ description: A test skill for unit testing
56
+ ---
57
+ # Test Skill
58
+
59
+ This is the skill content.`;
60
+
61
+ await fs.writeFile(filePath, content);
62
+ const result = await parseSkillFile(filePath, "user");
63
+
64
+ expect(result).not.toBeNull();
65
+ expect(result!.name).toBe("test-skill");
66
+ expect(result!.description).toBe("A test skill for unit testing");
67
+ expect(result!.source).toBe("user");
68
+ expect(result!.content).toContain("# Test Skill");
69
+ expect(result!.content).not.toContain("---");
70
+ });
71
+
72
+ it("should return null for missing frontmatter", async () => {
73
+ const filePath = path.join(testDir, "no-frontmatter.md");
74
+ const content = `# No Frontmatter
75
+
76
+ This file has no frontmatter.`;
77
+
78
+ await fs.writeFile(filePath, content);
79
+ const result = await parseSkillFile(filePath, "user");
80
+
81
+ expect(result).toBeNull();
82
+ });
83
+
84
+ it("should return null for missing name", async () => {
85
+ const filePath = path.join(testDir, "no-name.md");
86
+ const content = `---
87
+ description: Has description but no name
88
+ ---
89
+ Content`;
90
+
91
+ await fs.writeFile(filePath, content);
92
+ const result = await parseSkillFile(filePath, "user");
93
+
94
+ expect(result).toBeNull();
95
+ });
96
+
97
+ it("should return null for missing description", async () => {
98
+ const filePath = path.join(testDir, "no-description.md");
99
+ const content = `---
100
+ name: skill-without-description
101
+ ---
102
+ Content`;
103
+
104
+ await fs.writeFile(filePath, content);
105
+ const result = await parseSkillFile(filePath, "user");
106
+
107
+ expect(result).toBeNull();
108
+ });
109
+
110
+ it("should handle non-existent file", async () => {
111
+ const result = await parseSkillFile("/non/existent/path.md", "user");
112
+
113
+ expect(result).toBeNull();
114
+ });
115
+ });
116
+ });
@@ -0,0 +1,77 @@
1
+ import fs from "fs/promises";
2
+ import { createLogger } from "../log-trace/logger";
3
+ import type { SkillEntry, SkillSource } from "./types";
4
+
5
+ const logger = createLogger("skill-parser");
6
+
7
+ /**
8
+ * 解析 frontmatter 文本
9
+ */
10
+ export function parseFrontmatter(text: string): Record<string, string> {
11
+ const result: Record<string, string> = {};
12
+ const lines = text.split("\n");
13
+
14
+ for (const line of lines) {
15
+ // 匹配 key: value 格式
16
+ const match = line.match(/^(\w+):\s*"?(.+?)"?\s*$/);
17
+ if (match) {
18
+ const key = match[1];
19
+ let value = match[2];
20
+ // 移除首尾引号
21
+ if (value.startsWith('"') && value.endsWith('"')) {
22
+ value = value.slice(1, -1);
23
+ }
24
+ result[key] = value;
25
+ }
26
+ }
27
+
28
+ return result;
29
+ }
30
+
31
+ /**
32
+ * 解析 SKILL.md 文件
33
+ */
34
+ export async function parseSkillFile(
35
+ filePath: string,
36
+ source: SkillSource
37
+ ): Promise<SkillEntry | null> {
38
+ try {
39
+ const content = await fs.readFile(filePath, "utf-8");
40
+
41
+ // 匹配 frontmatter: --- ... ---
42
+ const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---\n?/);
43
+ if (!frontmatterMatch) {
44
+ logger.warn(`[SkillParser] Missing frontmatter in: ${filePath}`);
45
+ return null;
46
+ }
47
+
48
+ const frontmatter = parseFrontmatter(frontmatterMatch[1]);
49
+ const name = frontmatter.name;
50
+ const description = frontmatter.description;
51
+
52
+ if (!name) {
53
+ logger.warn(`[SkillParser] Missing name in frontmatter: ${filePath}`);
54
+ return null;
55
+ }
56
+
57
+ if (!description) {
58
+ logger.warn(`[SkillParser] Missing description in frontmatter: ${filePath}`);
59
+ return null;
60
+ }
61
+
62
+ // 移除 frontmatter 获取实际内容
63
+ const actualContent = content.replace(/^---\n[\s\S]*?\n---\n?/, "");
64
+
65
+ return {
66
+ name,
67
+ description,
68
+ filePath,
69
+ content: actualContent,
70
+ source,
71
+ loadedAt: Date.now(),
72
+ };
73
+ } catch (error) {
74
+ logger.error(`[SkillParser] Failed to parse file: ${filePath}`, error);
75
+ return null;
76
+ }
77
+ }
@@ -0,0 +1,211 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import fs from "fs/promises";
3
+ import path from "path";
4
+ import { SkillScanner } from "./scanner";
5
+ import type { SkillConfig } from "./types";
6
+
7
+ /**
8
+ * Helper: Build glob pattern using the same logic as scanner
9
+ * This mimics the Windows behavior to test cross-platform compatibility
10
+ */
11
+ function buildGlobPattern(expandedPath: string, recursive: boolean): string {
12
+ const sep = "/";
13
+ const basePattern = expandedPath.replace(/\\/g, "/");
14
+ return recursive
15
+ ? `${basePattern}${sep}**${sep}SKILL.md`
16
+ : `${basePattern}${sep}SKILL.md`;
17
+ }
18
+
19
+ describe("SkillScanner", () => {
20
+ const testBaseDir = path.join(__dirname, "__test_scanner__");
21
+ const userSkillsDir = path.join(testBaseDir, "user", "skills");
22
+ const projectSkillsDir = path.join(testBaseDir, "project", "skills");
23
+
24
+ const config: SkillConfig = {
25
+ skillPaths: [
26
+ { type: "user", path: userSkillsDir },
27
+ { type: "project", path: projectSkillsDir },
28
+ ],
29
+ recursive: true,
30
+ cacheEnabled: true,
31
+ };
32
+
33
+ beforeEach(async () => {
34
+ // 创建测试目录结构
35
+ await fs.mkdir(path.join(userSkillsDir, "brainstorming"), { recursive: true });
36
+ await fs.mkdir(path.join(projectSkillsDir, "tdd"), { recursive: true });
37
+
38
+ // 写入测试 SKILL.md 文件
39
+ await fs.writeFile(
40
+ path.join(userSkillsDir, "brainstorming", "SKILL.md"),
41
+ `---
42
+ name: brainstorming
43
+ description: Use before any creative work
44
+ ---
45
+ # Brainstorming Skill
46
+
47
+ This is the brainstorming skill content.`
48
+ );
49
+
50
+ await fs.writeFile(
51
+ path.join(projectSkillsDir, "tdd", "SKILL.md"),
52
+ `---
53
+ name: tdd
54
+ description: Use when implementing any feature
55
+ ---
56
+ # TDD Skill
57
+
58
+ This is the TDD skill content.`
59
+ );
60
+ });
61
+
62
+ afterEach(async () => {
63
+ try {
64
+ await fs.rm(testBaseDir, { recursive: true, force: true });
65
+ } catch {
66
+ // ignore
67
+ }
68
+ });
69
+
70
+ describe("expandPath", () => {
71
+ it("should expand ~ to home directory", async () => {
72
+ const scanner = new SkillScanner({
73
+ ...config,
74
+ skillPaths: [{ type: "user", path: "~/test-skills" }],
75
+ });
76
+
77
+ const skills = await scanner.scan();
78
+ expect(skills.size).toBeGreaterThanOrEqual(0);
79
+ });
80
+ });
81
+
82
+ describe("glob pattern generation", () => {
83
+ it("should use forward slashes for glob patterns (Windows compatibility)", () => {
84
+ // Simulate Windows path with backslashes
85
+ const windowsPath = "C:\\Users\\test\\skills";
86
+
87
+ const patternRecursive = buildGlobPattern(windowsPath, true);
88
+ const patternNonRecursive = buildGlobPattern(windowsPath, false);
89
+
90
+ // Pattern must use forward slashes for glob compatibility
91
+ expect(patternRecursive).toBe("C:/Users/test/skills/**/SKILL.md");
92
+ expect(patternNonRecursive).toBe("C:/Users/test/skills/SKILL.md");
93
+
94
+ // Must NOT contain backslashes (glob doesn't support them)
95
+ expect(patternRecursive).not.toContain("\\");
96
+ expect(patternNonRecursive).not.toContain("\\");
97
+ });
98
+
99
+ it("should preserve forward slashes in Unix paths", () => {
100
+ const unixPath = "/home/user/skills";
101
+
102
+ const patternRecursive = buildGlobPattern(unixPath, true);
103
+ const patternNonRecursive = buildGlobPattern(unixPath, false);
104
+
105
+ expect(patternRecursive).toBe("/home/user/skills/**/SKILL.md");
106
+ expect(patternNonRecursive).toBe("/home/user/skills/SKILL.md");
107
+ });
108
+
109
+ it("should normalize mixed slashes to forward slashes", () => {
110
+ const mixedPath = "/home\\user/skills\\nested";
111
+
112
+ const patternRecursive = buildGlobPattern(mixedPath, true);
113
+
114
+ // All backslashes should be converted to forward slashes
115
+ expect(patternRecursive).not.toContain("\\");
116
+ expect(patternRecursive).toContain("/");
117
+ });
118
+
119
+ it("should generate patterns without backslashes for Unix paths", async () => {
120
+ // Test with real Unix path
121
+ const scanner = new SkillScanner({
122
+ ...config,
123
+ skillPaths: [{ type: "user", path: userSkillsDir }],
124
+ recursive: true,
125
+ cacheEnabled: false,
126
+ });
127
+
128
+ // The scanner should find skills without issues
129
+ const skills = await scanner.scan();
130
+ expect(skills.size).toBeGreaterThan(0);
131
+
132
+ // Verify no backslashes in resulting paths
133
+ for (const skill of skills.values()) {
134
+ expect(skill.filePath).not.toContain("\\");
135
+ expect(skill.filePath).toContain("/");
136
+ }
137
+ });
138
+ });
139
+
140
+ describe("scan", () => {
141
+ it("should scan directory and find SKILL.md files", async () => {
142
+ const scanner = new SkillScanner(config);
143
+ const skills = await scanner.scan();
144
+
145
+ expect(skills.size).toBe(2);
146
+ });
147
+
148
+ it("should load skill with correct properties", async () => {
149
+ const scanner = new SkillScanner(config);
150
+ const skills = await scanner.scan();
151
+
152
+ const brainstorming = skills.get("brainstorming");
153
+ expect(brainstorming).toBeDefined();
154
+ expect(brainstorming!.name).toBe("brainstorming");
155
+ expect(brainstorming!.description).toBe("Use before any creative work");
156
+ expect(brainstorming!.source).toBe("user");
157
+ expect(brainstorming!.content).toContain("Brainstorming Skill");
158
+ });
159
+
160
+ it("should skip non-existing paths gracefully", async () => {
161
+ const scanner = new SkillScanner({
162
+ ...config,
163
+ skillPaths: [
164
+ { type: "user", path: "/non/existent/path" },
165
+ ],
166
+ });
167
+
168
+ const skills = await scanner.scan();
169
+ expect(skills.size).toBe(0);
170
+ });
171
+
172
+ it("should handle multiple SKILL.md in subdirectories", async () => {
173
+ // 添加子目录中的 skill
174
+ await fs.mkdir(path.join(userSkillsDir, "parent", "child"), { recursive: true });
175
+ await fs.writeFile(
176
+ path.join(userSkillsDir, "parent", "child", "SKILL.md"),
177
+ `---
178
+ name: nested-skill
179
+ description: A skill in a nested directory
180
+ ---
181
+ # Nested Skill Content`
182
+ );
183
+
184
+ const scanner = new SkillScanner(config);
185
+ const skills = await scanner.scan();
186
+
187
+ expect(skills.get("nested-skill")).toBeDefined();
188
+ });
189
+
190
+ it("should deduplicate by name with higher priority source", async () => {
191
+ // 在 project 目录添加同名 skill(应该覆盖 user 目录的)
192
+ await fs.mkdir(path.join(projectSkillsDir, "brainstorming"), { recursive: true });
193
+ await fs.writeFile(
194
+ path.join(projectSkillsDir, "brainstorming", "SKILL.md"),
195
+ `---
196
+ name: brainstorming
197
+ description: Project version of brainstorming
198
+ ---
199
+ # Project Brainstorming`
200
+ );
201
+
202
+ const scanner = new SkillScanner(config);
203
+ const skills = await scanner.scan();
204
+
205
+ // project 优先级高于 user
206
+ const brainstorming = skills.get("brainstorming");
207
+ expect(brainstorming!.source).toBe("project");
208
+ expect(brainstorming!.description).toBe("Project version of brainstorming");
209
+ });
210
+ });
211
+ });
@@ -0,0 +1,119 @@
1
+ import fs from "fs/promises";
2
+ import path from "path";
3
+ import { glob } from "glob";
4
+ import { createLogger } from "../log-trace/logger";
5
+ import { parseSkillFile } from "./parser";
6
+ import { getSourcePriority } from "./config";
7
+ import type { SkillConfig, SkillEntry, SkillPath, SkillSource } from "./types";
8
+
9
+ const logger = createLogger("skill-scanner");
10
+
11
+ /**
12
+ * 展开路径(支持 ~ 展开)
13
+ */
14
+ function expandPath(inputPath: string): string {
15
+ if (inputPath.startsWith("~/")) {
16
+ const home = process.env.HOME || process.env.USERPROFILE || "";
17
+ return path.join(home, inputPath.slice(2));
18
+ }
19
+ return path.resolve(inputPath);
20
+ }
21
+
22
+ /**
23
+ * 检查路径是否存在
24
+ */
25
+ async function pathExists(p: string): Promise<boolean> {
26
+ try {
27
+ await fs.access(p);
28
+ return true;
29
+ } catch {
30
+ return false;
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Skill 扫描器
36
+ */
37
+ export class SkillScanner {
38
+ private config: SkillConfig;
39
+ private skillsMap: Map<string, SkillEntry>;
40
+
41
+ constructor(config: SkillConfig) {
42
+ this.config = config;
43
+ this.skillsMap = new Map();
44
+ }
45
+
46
+ /**
47
+ * 扫描所有 skillPaths 并加载 skills
48
+ */
49
+ async scan(): Promise<Map<string, SkillEntry>> {
50
+ this.skillsMap.clear();
51
+
52
+ for (const skillPath of this.config.skillPaths) {
53
+ await this.scanPath(skillPath);
54
+ }
55
+
56
+ return this.skillsMap;
57
+ }
58
+
59
+ /**
60
+ * 扫描单个路径
61
+ */
62
+ private async scanPath(skillPath: SkillPath): Promise<void> {
63
+ const expandedPath = expandPath(skillPath.path);
64
+
65
+ if (!(await pathExists(expandedPath))) {
66
+ logger.info(`[SkillScanner] Path not found, skipping: ${expandedPath}`);
67
+ return;
68
+ }
69
+
70
+ logger.info(`[SkillScanner] Scanning: ${expandedPath}`);
71
+
72
+ // 使用正斜杠构建 glob pattern,确保 Windows 兼容性
73
+ // glob 库需要正斜杠路径,不能使用 path.join(Windows 会用反斜杠)
74
+ const sep = "/";
75
+ const basePattern = expandedPath.replace(/\\/g, "/");
76
+ const pattern = this.config.recursive
77
+ ? `${basePattern}${sep}**${sep}SKILL.md`
78
+ : `${basePattern}${sep}SKILL.md`;
79
+
80
+ const files = await glob(pattern, {
81
+ absolute: true,
82
+ ignore: ["**/node_modules/**"],
83
+ });
84
+
85
+ logger.info(`[SkillScanner] Found ${files.length} SKILL.md files`);
86
+
87
+ for (const filePath of files) {
88
+ await this.processFile(filePath, skillPath.type);
89
+ }
90
+ }
91
+
92
+ /**
93
+ * 处理单个 SKILL.md 文件
94
+ */
95
+ private async processFile(
96
+ filePath: string,
97
+ source: SkillSource
98
+ ): Promise<void> {
99
+ const entry = await parseSkillFile(filePath, source);
100
+
101
+ if (!entry) {
102
+ return;
103
+ }
104
+
105
+ // 按优先级合并去重
106
+ const existing = this.skillsMap.get(entry.name);
107
+ if (!existing || getSourcePriority(source) > getSourcePriority(existing.source)) {
108
+ this.skillsMap.set(entry.name, entry);
109
+ logger.debug(`[SkillScanner] Loaded skill: ${entry.name} (${source})`);
110
+ }
111
+ }
112
+
113
+ /**
114
+ * 获取扫描结果
115
+ */
116
+ getSkills(): Map<string, SkillEntry> {
117
+ return this.skillsMap;
118
+ }
119
+ }