@chengchenccc/oh-my-agent 0.1.1-rc.1

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 (276) hide show
  1. package/README.md +79 -0
  2. package/dist/cli/args.d.ts +24 -0
  3. package/dist/cli/args.d.ts.map +1 -0
  4. package/dist/cli/args.js +120 -0
  5. package/dist/cli/initial-input.d.ts +32 -0
  6. package/dist/cli/initial-input.d.ts.map +1 -0
  7. package/dist/cli/initial-input.js +131 -0
  8. package/dist/cli.d.ts +3 -0
  9. package/dist/cli.d.ts.map +1 -0
  10. package/dist/cli.js +3 -0
  11. package/dist/core/__fixtures__/echo-model.d.ts +6 -0
  12. package/dist/core/__fixtures__/echo-model.d.ts.map +1 -0
  13. package/dist/core/__fixtures__/echo-model.js +10 -0
  14. package/dist/core/__fixtures__/mcp-echo-server.d.ts +2 -0
  15. package/dist/core/__fixtures__/mcp-echo-server.d.ts.map +1 -0
  16. package/dist/core/__fixtures__/mcp-echo-server.js +54 -0
  17. package/dist/core/agent-runtime.d.ts +21 -0
  18. package/dist/core/agent-runtime.d.ts.map +1 -0
  19. package/dist/core/agent-runtime.js +14 -0
  20. package/dist/core/memory/autonomous-memory.d.ts +21 -0
  21. package/dist/core/memory/autonomous-memory.d.ts.map +1 -0
  22. package/dist/core/memory/autonomous-memory.js +202 -0
  23. package/dist/core/persistence/in-memory-session-store.d.ts +3 -0
  24. package/dist/core/persistence/in-memory-session-store.d.ts.map +1 -0
  25. package/dist/core/persistence/in-memory-session-store.js +109 -0
  26. package/dist/core/persistence/session-store.contract.d.ts +5 -0
  27. package/dist/core/persistence/session-store.contract.d.ts.map +1 -0
  28. package/dist/core/persistence/session-store.contract.js +183 -0
  29. package/dist/core/persistence/session-store.d.ts +33 -0
  30. package/dist/core/persistence/session-store.d.ts.map +1 -0
  31. package/dist/core/persistence/session-store.js +22 -0
  32. package/dist/core/persistence/session-tree.d.ts +49 -0
  33. package/dist/core/persistence/session-tree.d.ts.map +1 -0
  34. package/dist/core/persistence/session-tree.js +1 -0
  35. package/dist/core/plugins/plugin-code.d.ts +13 -0
  36. package/dist/core/plugins/plugin-code.d.ts.map +1 -0
  37. package/dist/core/plugins/plugin-code.js +62 -0
  38. package/dist/core/plugins/plugin-marketplace.d.ts +72 -0
  39. package/dist/core/plugins/plugin-marketplace.d.ts.map +1 -0
  40. package/dist/core/plugins/plugin-marketplace.js +340 -0
  41. package/dist/core/plugins/plugin-resolve.d.ts +32 -0
  42. package/dist/core/plugins/plugin-resolve.d.ts.map +1 -0
  43. package/dist/core/plugins/plugin-resolve.js +101 -0
  44. package/dist/core/plugins/plugin-trust.d.ts +24 -0
  45. package/dist/core/plugins/plugin-trust.d.ts.map +1 -0
  46. package/dist/core/plugins/plugin-trust.js +89 -0
  47. package/dist/core/runtime/agent-event.d.ts +98 -0
  48. package/dist/core/runtime/agent-event.d.ts.map +1 -0
  49. package/dist/core/runtime/agent-event.js +1 -0
  50. package/dist/core/runtime/agent-loop.d.ts +142 -0
  51. package/dist/core/runtime/agent-loop.d.ts.map +1 -0
  52. package/dist/core/runtime/agent-loop.js +1008 -0
  53. package/dist/core/runtime/approval.d.ts +23 -0
  54. package/dist/core/runtime/approval.d.ts.map +1 -0
  55. package/dist/core/runtime/approval.js +25 -0
  56. package/dist/core/runtime/compaction.d.ts +22 -0
  57. package/dist/core/runtime/compaction.d.ts.map +1 -0
  58. package/dist/core/runtime/compaction.js +90 -0
  59. package/dist/core/runtime/context-estimate.d.ts +42 -0
  60. package/dist/core/runtime/context-estimate.d.ts.map +1 -0
  61. package/dist/core/runtime/context-estimate.js +34 -0
  62. package/dist/core/runtime/create-runtime.d.ts +81 -0
  63. package/dist/core/runtime/create-runtime.d.ts.map +1 -0
  64. package/dist/core/runtime/create-runtime.js +250 -0
  65. package/dist/core/runtime/fake-provider.d.ts +3 -0
  66. package/dist/core/runtime/fake-provider.d.ts.map +1 -0
  67. package/dist/core/runtime/fake-provider.js +87 -0
  68. package/dist/core/runtime/logger.d.ts +13 -0
  69. package/dist/core/runtime/logger.d.ts.map +1 -0
  70. package/dist/core/runtime/logger.js +38 -0
  71. package/dist/core/runtime/loop-input.d.ts +39 -0
  72. package/dist/core/runtime/loop-input.d.ts.map +1 -0
  73. package/dist/core/runtime/loop-input.js +38 -0
  74. package/dist/core/runtime/message-cache.d.ts +16 -0
  75. package/dist/core/runtime/message-cache.d.ts.map +1 -0
  76. package/dist/core/runtime/message-cache.js +23 -0
  77. package/dist/core/runtime/model-catalog.d.ts +10 -0
  78. package/dist/core/runtime/model-catalog.d.ts.map +1 -0
  79. package/dist/core/runtime/model-catalog.js +14 -0
  80. package/dist/core/runtime/plugin-runtime.d.ts +41 -0
  81. package/dist/core/runtime/plugin-runtime.d.ts.map +1 -0
  82. package/dist/core/runtime/plugin-runtime.js +1 -0
  83. package/dist/core/runtime/plugin.d.ts +86 -0
  84. package/dist/core/runtime/plugin.d.ts.map +1 -0
  85. package/dist/core/runtime/plugin.js +23 -0
  86. package/dist/core/runtime/process-tree.d.ts +12 -0
  87. package/dist/core/runtime/process-tree.d.ts.map +1 -0
  88. package/dist/core/runtime/process-tree.js +40 -0
  89. package/dist/core/runtime/prompt.d.ts +23 -0
  90. package/dist/core/runtime/prompt.d.ts.map +1 -0
  91. package/dist/core/runtime/prompt.js +29 -0
  92. package/dist/core/runtime/prompts.d.ts +16 -0
  93. package/dist/core/runtime/prompts.d.ts.map +1 -0
  94. package/dist/core/runtime/prompts.js +36 -0
  95. package/dist/core/runtime/retry.d.ts +20 -0
  96. package/dist/core/runtime/retry.d.ts.map +1 -0
  97. package/dist/core/runtime/retry.js +60 -0
  98. package/dist/core/runtime/run-runtime.d.ts +93 -0
  99. package/dist/core/runtime/run-runtime.d.ts.map +1 -0
  100. package/dist/core/runtime/run-runtime.js +664 -0
  101. package/dist/core/runtime/runtime-catalog.d.ts +12 -0
  102. package/dist/core/runtime/runtime-catalog.d.ts.map +1 -0
  103. package/dist/core/runtime/runtime-catalog.js +89 -0
  104. package/dist/core/runtime/stream-rules.d.ts +9 -0
  105. package/dist/core/runtime/stream-rules.d.ts.map +1 -0
  106. package/dist/core/runtime/stream-rules.js +44 -0
  107. package/dist/core/runtime/title.d.ts +7 -0
  108. package/dist/core/runtime/title.d.ts.map +1 -0
  109. package/dist/core/runtime/title.js +114 -0
  110. package/dist/core/runtime/todo.d.ts +16 -0
  111. package/dist/core/runtime/todo.d.ts.map +1 -0
  112. package/dist/core/runtime/todo.js +40 -0
  113. package/dist/core/runtime/tool-filter.d.ts +12 -0
  114. package/dist/core/runtime/tool-filter.d.ts.map +1 -0
  115. package/dist/core/runtime/tool-filter.js +23 -0
  116. package/dist/core/runtime/tool-pruning.d.ts +29 -0
  117. package/dist/core/runtime/tool-pruning.d.ts.map +1 -0
  118. package/dist/core/runtime/tool-pruning.js +105 -0
  119. package/dist/core/session/input-history.d.ts +8 -0
  120. package/dist/core/session/input-history.d.ts.map +1 -0
  121. package/dist/core/session/input-history.js +41 -0
  122. package/dist/core/session/session-file.d.ts +84 -0
  123. package/dist/core/session/session-file.d.ts.map +1 -0
  124. package/dist/core/session/session-file.js +392 -0
  125. package/dist/core/session/session-loop.d.ts +33 -0
  126. package/dist/core/session/session-loop.d.ts.map +1 -0
  127. package/dist/core/session/session-loop.js +30 -0
  128. package/dist/core/settings/project-settings.d.ts +46 -0
  129. package/dist/core/settings/project-settings.d.ts.map +1 -0
  130. package/dist/core/settings/project-settings.js +85 -0
  131. package/dist/core/settings/workspace-context.d.ts +10 -0
  132. package/dist/core/settings/workspace-context.d.ts.map +1 -0
  133. package/dist/core/settings/workspace-context.js +48 -0
  134. package/dist/core/tools/agent-fs-like.d.ts +15 -0
  135. package/dist/core/tools/agent-fs-like.d.ts.map +1 -0
  136. package/dist/core/tools/agent-fs-like.js +4 -0
  137. package/dist/core/tools/ask-question.d.ts +5 -0
  138. package/dist/core/tools/ask-question.d.ts.map +1 -0
  139. package/dist/core/tools/ask-question.js +51 -0
  140. package/dist/core/tools/bash.d.ts +5 -0
  141. package/dist/core/tools/bash.d.ts.map +1 -0
  142. package/dist/core/tools/bash.js +109 -0
  143. package/dist/core/tools/eval.d.ts +10 -0
  144. package/dist/core/tools/eval.d.ts.map +1 -0
  145. package/dist/core/tools/eval.js +83 -0
  146. package/dist/core/tools/file-tools.d.ts +18 -0
  147. package/dist/core/tools/file-tools.d.ts.map +1 -0
  148. package/dist/core/tools/file-tools.js +249 -0
  149. package/dist/core/tools/glob.d.ts +5 -0
  150. package/dist/core/tools/glob.d.ts.map +1 -0
  151. package/dist/core/tools/glob.js +54 -0
  152. package/dist/core/tools/grep.d.ts +5 -0
  153. package/dist/core/tools/grep.d.ts.map +1 -0
  154. package/dist/core/tools/grep.js +61 -0
  155. package/dist/core/tools/index.d.ts +14 -0
  156. package/dist/core/tools/index.d.ts.map +1 -0
  157. package/dist/core/tools/index.js +14 -0
  158. package/dist/core/tools/ls-tree.d.ts +10 -0
  159. package/dist/core/tools/ls-tree.d.ts.map +1 -0
  160. package/dist/core/tools/ls-tree.js +177 -0
  161. package/dist/core/tools/mcp-mount.d.ts +63 -0
  162. package/dist/core/tools/mcp-mount.d.ts.map +1 -0
  163. package/dist/core/tools/mcp-mount.js +287 -0
  164. package/dist/core/tools/read-image.d.ts +6 -0
  165. package/dist/core/tools/read-image.d.ts.map +1 -0
  166. package/dist/core/tools/read-image.js +98 -0
  167. package/dist/core/tools/skill.d.ts +11 -0
  168. package/dist/core/tools/skill.d.ts.map +1 -0
  169. package/dist/core/tools/skill.js +65 -0
  170. package/dist/core/tools/skills.d.ts +10 -0
  171. package/dist/core/tools/skills.d.ts.map +1 -0
  172. package/dist/core/tools/skills.js +116 -0
  173. package/dist/core/tools/todo-store.d.ts +8 -0
  174. package/dist/core/tools/todo-store.d.ts.map +1 -0
  175. package/dist/core/tools/todo-store.js +100 -0
  176. package/dist/core/tools/todo.d.ts +8 -0
  177. package/dist/core/tools/todo.d.ts.map +1 -0
  178. package/dist/core/tools/todo.js +91 -0
  179. package/dist/core/tools/url-guard.d.ts +12 -0
  180. package/dist/core/tools/url-guard.d.ts.map +1 -0
  181. package/dist/core/tools/url-guard.js +58 -0
  182. package/dist/core/tools/web-ports-std.d.ts +6 -0
  183. package/dist/core/tools/web-ports-std.d.ts.map +1 -0
  184. package/dist/core/tools/web-ports-std.js +145 -0
  185. package/dist/core/tools/web-ports.d.ts +56 -0
  186. package/dist/core/tools/web-ports.d.ts.map +1 -0
  187. package/dist/core/tools/web-ports.js +62 -0
  188. package/dist/core/tools/workspace-sandbox.d.ts +20 -0
  189. package/dist/core/tools/workspace-sandbox.d.ts.map +1 -0
  190. package/dist/core/tools/workspace-sandbox.js +84 -0
  191. package/dist/core/workflow/subagent-registry.d.ts +40 -0
  192. package/dist/core/workflow/subagent-registry.d.ts.map +1 -0
  193. package/dist/core/workflow/subagent-registry.js +118 -0
  194. package/dist/core/workflow/workflow-evaluator.d.ts +23 -0
  195. package/dist/core/workflow/workflow-evaluator.d.ts.map +1 -0
  196. package/dist/core/workflow/workflow-evaluator.js +21 -0
  197. package/dist/core/workflow/workflow-executor.d.ts +108 -0
  198. package/dist/core/workflow/workflow-executor.d.ts.map +1 -0
  199. package/dist/core/workflow/workflow-executor.js +549 -0
  200. package/dist/core/workflow/workflow-tools.d.ts +50 -0
  201. package/dist/core/workflow/workflow-tools.d.ts.map +1 -0
  202. package/dist/core/workflow/workflow-tools.js +217 -0
  203. package/dist/index.d.ts +14 -0
  204. package/dist/index.d.ts.map +1 -0
  205. package/dist/index.js +13 -0
  206. package/dist/main.d.ts +9 -0
  207. package/dist/main.d.ts.map +1 -0
  208. package/dist/main.js +97 -0
  209. package/dist/modes/json-mode.d.ts +5 -0
  210. package/dist/modes/json-mode.d.ts.map +1 -0
  211. package/dist/modes/json-mode.js +46 -0
  212. package/dist/modes/print-mode.d.ts +20 -0
  213. package/dist/modes/print-mode.d.ts.map +1 -0
  214. package/dist/modes/print-mode.js +82 -0
  215. package/dist/modes/rpc/jsonl.d.ts +23 -0
  216. package/dist/modes/rpc/jsonl.d.ts.map +1 -0
  217. package/dist/modes/rpc/jsonl.js +88 -0
  218. package/dist/modes/rpc/rpc-mode.d.ts +18 -0
  219. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -0
  220. package/dist/modes/rpc/rpc-mode.js +326 -0
  221. package/dist/modes/tui/settings-overlay.d.ts +23 -0
  222. package/dist/modes/tui/settings-overlay.d.ts.map +1 -0
  223. package/dist/modes/tui/settings-overlay.js +136 -0
  224. package/dist/modes/tui/tui-commands-session.d.ts +3 -0
  225. package/dist/modes/tui/tui-commands-session.d.ts.map +1 -0
  226. package/dist/modes/tui/tui-commands-session.js +191 -0
  227. package/dist/modes/tui/tui-commands.d.ts +52 -0
  228. package/dist/modes/tui/tui-commands.d.ts.map +1 -0
  229. package/dist/modes/tui/tui-commands.js +373 -0
  230. package/dist/modes/tui/tui-components.d.ts +81 -0
  231. package/dist/modes/tui/tui-components.d.ts.map +1 -0
  232. package/dist/modes/tui/tui-components.js +248 -0
  233. package/dist/modes/tui/tui-format.d.ts +65 -0
  234. package/dist/modes/tui/tui-format.d.ts.map +1 -0
  235. package/dist/modes/tui/tui-format.js +246 -0
  236. package/dist/modes/tui/tui-frame-provider.d.ts +16 -0
  237. package/dist/modes/tui/tui-frame-provider.d.ts.map +1 -0
  238. package/dist/modes/tui/tui-frame-provider.js +31 -0
  239. package/dist/modes/tui/tui-interactive.d.ts +16 -0
  240. package/dist/modes/tui/tui-interactive.d.ts.map +1 -0
  241. package/dist/modes/tui/tui-interactive.js +123 -0
  242. package/dist/modes/tui/tui-io.d.ts +12 -0
  243. package/dist/modes/tui/tui-io.d.ts.map +1 -0
  244. package/dist/modes/tui/tui-io.js +620 -0
  245. package/dist/modes/tui/tui-mode.d.ts +120 -0
  246. package/dist/modes/tui/tui-mode.d.ts.map +1 -0
  247. package/dist/modes/tui/tui-mode.js +391 -0
  248. package/dist/modes/tui/tui-render.d.ts +54 -0
  249. package/dist/modes/tui/tui-render.d.ts.map +1 -0
  250. package/dist/modes/tui/tui-render.js +399 -0
  251. package/dist/modes/tui/tui-slash.d.ts +12 -0
  252. package/dist/modes/tui/tui-slash.d.ts.map +1 -0
  253. package/dist/modes/tui/tui-slash.js +64 -0
  254. package/dist/modes/tui/tui-tool-render.d.ts +6 -0
  255. package/dist/modes/tui/tui-tool-render.d.ts.map +1 -0
  256. package/dist/modes/tui/tui-tool-render.js +79 -0
  257. package/dist/modes/tui/tui-transcript-reconciler.d.ts +25 -0
  258. package/dist/modes/tui/tui-transcript-reconciler.d.ts.map +1 -0
  259. package/dist/modes/tui/tui-transcript-reconciler.js +97 -0
  260. package/dist/modes/tui/view-state.d.ts +67 -0
  261. package/dist/modes/tui/view-state.d.ts.map +1 -0
  262. package/dist/modes/tui/view-state.js +353 -0
  263. package/dist/prompts/agents/subagent.md +26 -0
  264. package/dist/prompts/system/base.md +20 -0
  265. package/dist/prompts/system/memory.md +23 -0
  266. package/dist/prompts/system/safety.md +12 -0
  267. package/dist/protocol/index.d.ts +5 -0
  268. package/dist/protocol/index.d.ts.map +1 -0
  269. package/dist/protocol/index.js +2 -0
  270. package/dist/protocol/mapping.d.ts +25 -0
  271. package/dist/protocol/mapping.d.ts.map +1 -0
  272. package/dist/protocol/mapping.js +115 -0
  273. package/dist/protocol/transport.d.ts +1396 -0
  274. package/dist/protocol/transport.d.ts.map +1 -0
  275. package/dist/protocol/transport.js +170 -0
  276. package/package.json +49 -0
@@ -0,0 +1,15 @@
1
+ /** Virtual filesystem interface for agent tools. */
2
+ export interface AgentFsLike {
3
+ read(path: string): Promise<string | null>;
4
+ write(path: string, content: string): Promise<void>;
5
+ list(path: string): Promise<string[]>;
6
+ stat(path: string): Promise<{
7
+ mtimeMs: number;
8
+ size: number;
9
+ } | null>;
10
+ exists(path: string): Promise<boolean>;
11
+ mkdirp(path: string): Promise<void>;
12
+ }
13
+ /** Join path segments with "/", collapsing duplicate slashes. */
14
+ export declare function pjoin(...segments: string[]): string;
15
+ //# sourceMappingURL=agent-fs-like.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-fs-like.d.ts","sourceRoot":"","sources":["../../../src/core/tools/agent-fs-like.ts"],"names":[],"mappings":"AAAA,oDAAoD;AACpD,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC3C,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACtC,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IACtE,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACvC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACrC;AAED,iEAAiE;AACjE,wBAAgB,KAAK,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAEnD"}
@@ -0,0 +1,4 @@
1
+ /** Join path segments with "/", collapsing duplicate slashes. */
2
+ export function pjoin(...segments) {
3
+ return segments.join("/").replace(/\/+/g, "/").replace(/\/$/, "") || "/";
4
+ }
@@ -0,0 +1,5 @@
1
+ import type { PluginTool } from "../agent-runtime.js";
2
+ /** Native ask_question tool (oh-my-pi style). Executes through the HITL ask
3
+ * pipeline (`options.ask`); absent pipeline = fail closed. */
4
+ export declare function createAskQuestionTool(): PluginTool;
5
+ //# sourceMappingURL=ask-question.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ask-question.d.ts","sourceRoot":"","sources":["../../../src/core/tools/ask-question.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAyBtD;+DAC+D;AAC/D,wBAAgB,qBAAqB,IAAI,UAAU,CA8BlD"}
@@ -0,0 +1,51 @@
1
+ function normalizeInput(args) {
2
+ const raw = args.questions;
3
+ if (!Array.isArray(raw) || raw.length === 0)
4
+ return { error: "questions must be a non-empty array" };
5
+ const questions = [];
6
+ for (const q of raw) {
7
+ if (typeof q !== "object" || q === null)
8
+ return { error: "each question must be an object" };
9
+ const item = q;
10
+ if (typeof item.id !== "string" || typeof item.question !== "string") {
11
+ return { error: "each question needs string id and question" };
12
+ }
13
+ const kind = item.kind === "text" ? "text" : "select";
14
+ if (kind === "select") {
15
+ const options = Array.isArray(item.options) ? item.options : [];
16
+ if (options.length === 0)
17
+ return { error: `question ${item.id}: select needs options` };
18
+ }
19
+ questions.push(item);
20
+ }
21
+ return { questions };
22
+ }
23
+ /** Native ask_question tool (oh-my-pi style). Executes through the HITL ask
24
+ * pipeline (`options.ask`); absent pipeline = fail closed. */
25
+ export function createAskQuestionTool() {
26
+ return {
27
+ name: "ask_question",
28
+ description: "Ask the user structured questions and wait for answers. Questions are select (options, optional multi/recommended/other) or text (free input). Returns {answers:[{id,selectedValues,freeText}]}.",
29
+ inputSchema: {
30
+ type: "object",
31
+ properties: {
32
+ questions: {
33
+ type: "array",
34
+ items: { type: "object" },
35
+ },
36
+ },
37
+ required: ["questions"],
38
+ },
39
+ async execute(args, _signal, options) {
40
+ const normalized = normalizeInput(args);
41
+ if ("error" in normalized)
42
+ return normalized;
43
+ if (!options?.ask)
44
+ return { error: "no ask pipeline configured" };
45
+ const result = await options.ask(normalized);
46
+ if (!result)
47
+ return { error: "ask pipeline returned no answer" };
48
+ return result;
49
+ },
50
+ };
51
+ }
@@ -0,0 +1,5 @@
1
+ import type { Tool } from "@chengchenccc/message";
2
+ export declare function createBashTool(opts: {
3
+ workspaceRoot: string;
4
+ }): Tool;
5
+ //# sourceMappingURL=bash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../../src/core/tools/bash.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAwBlD,wBAAgB,cAAc,CAAC,IAAI,EAAE;IAAE,aAAa,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAqGpE"}
@@ -0,0 +1,109 @@
1
+ import { WorkspaceSandbox } from "./workspace-sandbox.js";
2
+ const descriptionParam = {
3
+ type: "string",
4
+ description: "Must be the first parameter. A short human-readable summary explaining why this command is being run.",
5
+ };
6
+ function envMs(name, fallback) {
7
+ const raw = process.env[name];
8
+ if (raw === undefined)
9
+ return fallback;
10
+ const n = Number(raw);
11
+ return Number.isFinite(n) ? n : fallback;
12
+ }
13
+ function defaultBashTimeoutMs() {
14
+ return envMs("OMA_BASH_TIMEOUT_MS", 30_000);
15
+ }
16
+ function maxToolTimeoutMs() {
17
+ return envMs("OMA_MAX_TOOL_TIMEOUT_MS", 0);
18
+ }
19
+ export function createBashTool(opts) {
20
+ const sandbox = new WorkspaceSandbox(opts.workspaceRoot);
21
+ return {
22
+ name: "bash",
23
+ description: "Execute a bash shell command. Returns exit code, stdout, and stderr. Default timeout 30s, max 600s.",
24
+ inputSchema: {
25
+ type: "object",
26
+ properties: {
27
+ description: descriptionParam,
28
+ command: {
29
+ type: "string",
30
+ description: "The shell command to execute",
31
+ },
32
+ timeout: {
33
+ type: "number",
34
+ description: "Timeout in milliseconds (default 30000, max 600000)",
35
+ },
36
+ cwd: {
37
+ type: "string",
38
+ description: "Working directory (relative to workspace root)",
39
+ },
40
+ },
41
+ required: ["description", "command"],
42
+ },
43
+ async execute(input, signal, options) {
44
+ const { command, timeout = defaultBashTimeoutMs(), cwd, } = input;
45
+ // Validate cwd against the fixed workspace sandbox. Out-of-bounds cwd
46
+ // is a tool error, never a silent fallback to process cwd.
47
+ let validatedCwd = opts.workspaceRoot;
48
+ if (cwd) {
49
+ try {
50
+ validatedCwd = sandbox.validateCwd(cwd);
51
+ }
52
+ catch {
53
+ return {
54
+ content: `Error: cwd escapes workspace root: ${String(cwd)}`,
55
+ isError: true,
56
+ };
57
+ }
58
+ }
59
+ const upper = maxToolTimeoutMs();
60
+ const cap = upper > 0 ? Math.min(upper, 600_000) : 600_000;
61
+ const clamped = Math.min(Math.max(timeout, 1), cap);
62
+ const hasSetsid = Bun.which("setsid") !== null;
63
+ const proc = Bun.spawn(hasSetsid ? ["setsid", "bash", "-c", command] : ["bash", "-c", command], { stdout: "pipe", stderr: "pipe", cwd: validatedCwd });
64
+ // Kill the process group on timeout OR abort signal.
65
+ const killGroup = () => {
66
+ proc.kill();
67
+ try {
68
+ process.kill(-proc.pid, "SIGKILL");
69
+ }
70
+ catch {
71
+ /* */
72
+ }
73
+ };
74
+ const timer = setTimeout(killGroup, clamped);
75
+ const onAbort = () => killGroup();
76
+ if (signal?.aborted)
77
+ killGroup();
78
+ signal?.addEventListener("abort", onAbort, { once: true });
79
+ try {
80
+ const stderrPromise = new Response(proc.stderr).text();
81
+ let stdout = "";
82
+ if (options?.onOutput) {
83
+ const reader = proc.stdout.getReader();
84
+ for (;;) {
85
+ const { done, value } = await reader.read();
86
+ if (done)
87
+ break;
88
+ const chunk = new TextDecoder().decode(value);
89
+ stdout += chunk;
90
+ options.onOutput(chunk);
91
+ }
92
+ }
93
+ else {
94
+ stdout = await new Response(proc.stdout).text();
95
+ }
96
+ const stderr = await stderrPromise;
97
+ const exitCode = await proc.exited;
98
+ return {
99
+ content: `${stdout}\n[exit: ${exitCode}]${stderr ? `\n${stderr}` : ""}`,
100
+ isError: exitCode !== 0,
101
+ };
102
+ }
103
+ finally {
104
+ clearTimeout(timer);
105
+ signal?.removeEventListener("abort", onAbort);
106
+ }
107
+ },
108
+ };
109
+ }
@@ -0,0 +1,10 @@
1
+ import type { Tool } from "@chengchenccc/message";
2
+ /** eval: run a TS/JS snippet in a process sandbox (spawned bun subprocess,
3
+ * minimal env, hard timeout). The snippet must `export default (ctx) => out`
4
+ * where ctx is the JSON `input` object. Output is the returned value; stdout
5
+ * and stderr are reported alongside. Files written next to the script live
6
+ * only for the run unless keepWorkspace is set (cwd = workspace eval dir). */
7
+ export declare function createEvalTool(_opts: {
8
+ workspaceRoot: string;
9
+ }): Tool;
10
+ //# sourceMappingURL=eval.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eval.d.ts","sourceRoot":"","sources":["../../../src/core/tools/eval.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAgBlD;;;;+EAI+E;AAC/E,wBAAgB,cAAc,CAAC,KAAK,EAAE;IAAE,aAAa,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAuErE"}
@@ -0,0 +1,83 @@
1
+ import { runInSandbox } from "@chengchenccc/sandbox";
2
+ const descriptionParam = {
3
+ type: "string",
4
+ description: "Must be the first parameter. A short human-readable summary explaining what this code evaluates.",
5
+ };
6
+ function envMs(name, fallback) {
7
+ const raw = process.env[name];
8
+ if (raw === undefined)
9
+ return fallback;
10
+ const n = Number(raw);
11
+ return Number.isFinite(n) ? n : fallback;
12
+ }
13
+ /** eval: run a TS/JS snippet in a process sandbox (spawned bun subprocess,
14
+ * minimal env, hard timeout). The snippet must `export default (ctx) => out`
15
+ * where ctx is the JSON `input` object. Output is the returned value; stdout
16
+ * and stderr are reported alongside. Files written next to the script live
17
+ * only for the run unless keepWorkspace is set (cwd = workspace eval dir). */
18
+ export function createEvalTool(_opts) {
19
+ return {
20
+ name: "eval",
21
+ description: "Evaluate a TypeScript/JavaScript snippet in an isolated sandbox process. The code must `export default async (ctx) => result` — ctx is the provided input object and result must be JSON-serializable. Use for computations, data shaping, and quick experiments instead of bash one-liners.",
22
+ inputSchema: {
23
+ type: "object",
24
+ properties: {
25
+ description: descriptionParam,
26
+ code: {
27
+ type: "string",
28
+ description: "TS/JS module source. Must `export default async (ctx) => result`.",
29
+ },
30
+ input: {
31
+ type: "object",
32
+ description: "JSON object passed to the snippet as ctx",
33
+ additionalProperties: true,
34
+ },
35
+ timeout: {
36
+ type: "number",
37
+ description: "Timeout in milliseconds (default 30000)",
38
+ },
39
+ keepWorkspace: {
40
+ type: "boolean",
41
+ description: "Keep the sandbox working dir across this session (default false)",
42
+ },
43
+ },
44
+ required: ["description", "code"],
45
+ },
46
+ async execute(input, signal) {
47
+ const { code, input: ctxInput, timeout = envMs("OMA_EVAL_TIMEOUT_MS", 30_000), keepWorkspace = false, } = input;
48
+ if (typeof code !== "string" || code.trim() === "") {
49
+ return { content: "eval requires non-empty code", isError: true };
50
+ }
51
+ if (signal?.aborted)
52
+ return { content: "aborted", isError: true };
53
+ try {
54
+ const r = await runInSandbox({
55
+ code,
56
+ input: ctxInput ?? {},
57
+ timeoutMs: timeout,
58
+ keepCwd: keepWorkspace,
59
+ });
60
+ const parts = [];
61
+ if (r.output !== null)
62
+ parts.push(JSON.stringify(r.output, null, 2));
63
+ if (r.stdout.trim())
64
+ parts.push(`stdout:\n${r.stdout.trim()}`);
65
+ if (r.stderr.trim())
66
+ parts.push(`stderr:\n${r.stderr.trim()}`);
67
+ const ok = r.exitCode === 0;
68
+ return {
69
+ content: ok
70
+ ? parts.join("\n\n") || "(no output)"
71
+ : `eval failed (exit ${r.exitCode}):\n${parts.join("\n\n")}`,
72
+ isError: !ok,
73
+ };
74
+ }
75
+ catch (err) {
76
+ return {
77
+ content: `eval error: ${err instanceof Error ? err.message : String(err)}`,
78
+ isError: true,
79
+ };
80
+ }
81
+ },
82
+ };
83
+ }
@@ -0,0 +1,18 @@
1
+ import type { Tool } from "@chengchenccc/message";
2
+ /** Simple cwd-based default - tools resolve relative paths against this. */
3
+ export declare function withDefaultCwd(tool: Tool, cwd: string): Tool;
4
+ /** Resolve a path against a fixed workspace root using realpath containment. */
5
+ export declare function resolveWorkspacePath(root: string, userPath: string): string | null;
6
+ /** Create a read-file tool scoped to a cwd. */
7
+ export declare function createReadTool(opts: {
8
+ cwd: string;
9
+ }): Tool;
10
+ /** Create a write-file tool scoped to a cwd. */
11
+ export declare function createWriteTool(opts: {
12
+ cwd: string;
13
+ }): Tool;
14
+ /** Create an edit-file tool scoped to a cwd. */
15
+ export declare function createEditTool(opts: {
16
+ cwd: string;
17
+ }): Tool;
18
+ //# sourceMappingURL=file-tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-tools.d.ts","sourceRoot":"","sources":["../../../src/core/tools/file-tools.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAKlD,4EAA4E;AAC5E,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAQ5D;AAkBD,gFAAgF;AAChF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMlF;AAuBD,+CAA+C;AAC/C,wBAAgB,cAAc,CAAC,IAAI,EAAE;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAyE1D;AAID,gDAAgD;AAChD,wBAAgB,eAAe,CAAC,IAAI,EAAE;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAsC3D;AAID,gDAAgD;AAChD,wBAAgB,cAAc,CAAC,IAAI,EAAE;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CA4E1D"}
@@ -0,0 +1,249 @@
1
+ import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
2
+ import { extname, resolve } from "node:path";
3
+ import { WorkspaceSandbox } from "./workspace-sandbox.js";
4
+ /** Simple cwd-based default - tools resolve relative paths against this. */
5
+ export function withDefaultCwd(tool, cwd) {
6
+ return {
7
+ ...tool,
8
+ execute: async (input, signal) => {
9
+ const rec = input;
10
+ return tool.execute({ ...rec, cwd: rec.cwd ?? cwd }, signal);
11
+ },
12
+ };
13
+ }
14
+ function safePath(cwd, userPath) {
15
+ try {
16
+ const sandbox = new WorkspaceSandbox(cwd);
17
+ return sandbox.validate(userPath);
18
+ }
19
+ catch {
20
+ return null;
21
+ }
22
+ }
23
+ function safePathNew(cwd, userPath) {
24
+ try {
25
+ const sandbox = new WorkspaceSandbox(cwd);
26
+ return sandbox.validateNew(userPath);
27
+ }
28
+ catch {
29
+ return null;
30
+ }
31
+ }
32
+ /** Resolve a path against a fixed workspace root using realpath containment. */
33
+ export function resolveWorkspacePath(root, userPath) {
34
+ try {
35
+ return new WorkspaceSandbox(root).validate(userPath);
36
+ }
37
+ catch {
38
+ return null;
39
+ }
40
+ }
41
+ const IMAGE_EXTENSIONS = new Set([
42
+ ".png",
43
+ ".jpg",
44
+ ".jpeg",
45
+ ".gif",
46
+ ".webp",
47
+ ".bmp",
48
+ ".svg",
49
+ ".ico",
50
+ ]);
51
+ const READ_MAX_SIZE_BYTES = 256 * 1024;
52
+ /** Shared "description" parameter - forces the model to explain its intent before each tool call. */
53
+ const descriptionParam = {
54
+ type: "string",
55
+ description: "Must be the first parameter. A short human-readable summary explaining why this tool is being called.",
56
+ };
57
+ // ─── read ──────────────────────────────────────────────────────
58
+ /** Create a read-file tool scoped to a cwd. */
59
+ export function createReadTool(opts) {
60
+ const { cwd } = opts;
61
+ return {
62
+ name: "read",
63
+ description: "Read a file from the workspace. Returns file contents with line numbers (line\\tcontent). " +
64
+ "For images, returns a placeholder with file size. Output capped at 256KB; use offset/limit for large files.",
65
+ inputSchema: {
66
+ type: "object",
67
+ properties: {
68
+ description: descriptionParam,
69
+ path: {
70
+ type: "string",
71
+ description: "Path to the file to read, relative to workspace root",
72
+ },
73
+ offset: {
74
+ type: "number",
75
+ description: "1-based line number to start reading from. Defaults to 1.",
76
+ },
77
+ limit: {
78
+ type: "number",
79
+ description: "Maximum number of lines to read from offset.",
80
+ },
81
+ },
82
+ required: ["path"],
83
+ },
84
+ async execute(input) {
85
+ const rec = input;
86
+ const full = safePath(cwd, String(rec.path ?? ""));
87
+ if (!full)
88
+ return { content: "Error: path escapes workspace", isError: true };
89
+ try {
90
+ const stat = statSync(full);
91
+ if (stat.isDirectory()) {
92
+ return { content: `Error: ${rec.path} is a directory, not a file.`, isError: true };
93
+ }
94
+ if (IMAGE_EXTENSIONS.has(extname(full).toLowerCase())) {
95
+ return { content: `[image file: ${rec.path} (${stat.size} bytes)]` };
96
+ }
97
+ const content = readFileSync(full, "utf-8");
98
+ const lines = content.split("\n");
99
+ const offset = typeof rec.offset === "number" ? rec.offset : undefined;
100
+ const limit = typeof rec.limit === "number" ? rec.limit : undefined;
101
+ const start = offset && offset > 1 ? offset - 1 : 0;
102
+ const end = limit !== undefined ? start + Math.max(0, limit) : lines.length;
103
+ const selected = lines.slice(start, Math.max(start, end));
104
+ const out = [];
105
+ let bytes = 0;
106
+ let truncated = false;
107
+ for (let i = 0; i < selected.length; i++) {
108
+ const rendered = `${start + i + 1}\t${selected[i]}`;
109
+ const size = Buffer.byteLength(rendered, "utf8") + 1;
110
+ if (out.length > 0 && bytes + size > READ_MAX_SIZE_BYTES) {
111
+ truncated = true;
112
+ break;
113
+ }
114
+ bytes += size;
115
+ out.push(rendered);
116
+ }
117
+ let result = out.join("\n");
118
+ if (truncated) {
119
+ result += `\n... [truncated at ${READ_MAX_SIZE_BYTES} bytes; pass offset/limit to read a specific range]`;
120
+ }
121
+ return { content: result };
122
+ }
123
+ catch (err) {
124
+ return {
125
+ content: `Error reading file: ${err instanceof Error ? err.message : err}`,
126
+ isError: true,
127
+ };
128
+ }
129
+ },
130
+ };
131
+ }
132
+ // ─── write ─────────────────────────────────────────────────────
133
+ /** Create a write-file tool scoped to a cwd. */
134
+ export function createWriteTool(opts) {
135
+ const { cwd } = opts;
136
+ return {
137
+ name: "write",
138
+ description: "Write content to a file in the workspace. Creates parent directories if needed. Overwrites if file exists.",
139
+ inputSchema: {
140
+ type: "object",
141
+ properties: {
142
+ description: descriptionParam,
143
+ path: {
144
+ type: "string",
145
+ description: "Path to the file to write, relative to workspace root",
146
+ },
147
+ content: {
148
+ type: "string",
149
+ description: "Content to write to the file",
150
+ },
151
+ },
152
+ required: ["path", "content"],
153
+ },
154
+ async execute(input) {
155
+ const rec = input;
156
+ const full = safePathNew(cwd, String(rec.path ?? ""));
157
+ if (!full)
158
+ return { content: "Error: path escapes workspace", isError: true };
159
+ try {
160
+ mkdirSync(resolve(full, ".."), { recursive: true });
161
+ const content = String(rec.content ?? "");
162
+ writeFileSync(full, content, "utf-8");
163
+ return { content: `Wrote ${Buffer.byteLength(content, "utf8")} bytes to ${rec.path}` };
164
+ }
165
+ catch (err) {
166
+ return {
167
+ content: `Error writing file: ${err instanceof Error ? err.message : err}`,
168
+ isError: true,
169
+ };
170
+ }
171
+ },
172
+ };
173
+ }
174
+ // ─── edit ──────────────────────────────────────────────────────
175
+ /** Create an edit-file tool scoped to a cwd. */
176
+ export function createEditTool(opts) {
177
+ const { cwd } = opts;
178
+ return {
179
+ name: "edit",
180
+ description: "Perform exact string replacement in a file. old_string must match exactly and be unique " +
181
+ "unless replace_all is set. Use for surgical edits; prefer write for full replacement.",
182
+ inputSchema: {
183
+ type: "object",
184
+ properties: {
185
+ description: descriptionParam,
186
+ path: {
187
+ type: "string",
188
+ description: "Path to the file to edit, relative to workspace root",
189
+ },
190
+ old_string: {
191
+ type: "string",
192
+ description: "The exact text to replace (must be unique unless replace_all is true)",
193
+ },
194
+ new_string: {
195
+ type: "string",
196
+ description: "The replacement text (must differ from old_string)",
197
+ },
198
+ replace_all: {
199
+ type: "boolean",
200
+ description: "Replace all occurrences. Defaults to false (first match only).",
201
+ },
202
+ },
203
+ required: ["path", "old_string", "new_string"],
204
+ },
205
+ async execute(input) {
206
+ const rec = input;
207
+ const full = safePath(cwd, String(rec.path ?? ""));
208
+ if (!full)
209
+ return { content: "Error: path escapes workspace", isError: true };
210
+ try {
211
+ if (!existsSync(full)) {
212
+ return { content: `Error: file not found: ${rec.path}`, isError: true };
213
+ }
214
+ const oldStr = String(rec.old_string ?? "");
215
+ const newStr = String(rec.new_string ?? "");
216
+ const replaceAll = rec.replace_all === true;
217
+ if (oldStr === newStr) {
218
+ return { content: "Error: new_string must differ from old_string.", isError: true };
219
+ }
220
+ const content = readFileSync(full, "utf-8");
221
+ const occurrences = content.split(oldStr).length - 1;
222
+ if (occurrences === 0) {
223
+ return {
224
+ content: "Error: old_string not found in file. The file may have changed since you last read it.",
225
+ isError: true,
226
+ };
227
+ }
228
+ if (!replaceAll && occurrences > 1) {
229
+ return {
230
+ content: `Error: old_string is not unique (${occurrences} matches). Provide a larger unique string or set replace_all.`,
231
+ isError: true,
232
+ };
233
+ }
234
+ const newContent = replaceAll
235
+ ? content.split(oldStr).join(newStr)
236
+ : content.replace(oldStr, newStr);
237
+ writeFileSync(full, newContent, "utf-8");
238
+ const count = replaceAll ? occurrences : 1;
239
+ return { content: `Replaced ${count} occurrence${count === 1 ? "" : "s"} in ${rec.path}` };
240
+ }
241
+ catch (err) {
242
+ return {
243
+ content: `Error editing file: ${err instanceof Error ? err.message : err}`,
244
+ isError: true,
245
+ };
246
+ }
247
+ },
248
+ };
249
+ }
@@ -0,0 +1,5 @@
1
+ import type { Tool } from "@chengchenccc/message";
2
+ export declare function createGlobTool(opts: {
3
+ workspaceRoot: string;
4
+ }): Tool;
5
+ //# sourceMappingURL=glob.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glob.d.ts","sourceRoot":"","sources":["../../../src/core/tools/glob.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AASlD,wBAAgB,cAAc,CAAC,IAAI,EAAE;IAAE,aAAa,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAkDpE"}
@@ -0,0 +1,54 @@
1
+ import { WorkspaceSandbox } from "./workspace-sandbox.js";
2
+ const descriptionParam = {
3
+ type: "string",
4
+ description: "Must be the first parameter. A short human-readable summary explaining why this search is being performed.",
5
+ };
6
+ export function createGlobTool(opts) {
7
+ const sandbox = new WorkspaceSandbox(opts.workspaceRoot);
8
+ return {
9
+ name: "glob",
10
+ description: "Find files matching a glob pattern. Returns newline-separated paths. Results are capped at 500.",
11
+ inputSchema: {
12
+ type: "object",
13
+ properties: {
14
+ description: descriptionParam,
15
+ pattern: { type: "string", description: "The glob pattern to match (e.g. '**/*.ts')" },
16
+ cwd: {
17
+ type: "string",
18
+ description: "Subdirectory to search from (relative to workspace root)",
19
+ },
20
+ },
21
+ required: ["pattern"],
22
+ },
23
+ async execute(input) {
24
+ const { pattern, cwd } = input;
25
+ let validatedCwd = opts.workspaceRoot;
26
+ if (cwd) {
27
+ try {
28
+ validatedCwd = sandbox.validateCwd(cwd);
29
+ }
30
+ catch {
31
+ return {
32
+ content: `Error: cwd escapes workspace root: ${String(cwd)}`,
33
+ isError: true,
34
+ };
35
+ }
36
+ }
37
+ const LIMIT = 500;
38
+ const glob = new Bun.Glob(pattern);
39
+ const matches = [];
40
+ let truncated = false;
41
+ for await (const m of glob.scan({ cwd: validatedCwd, absolute: false, onlyFiles: true })) {
42
+ if (matches.length >= LIMIT) {
43
+ truncated = true;
44
+ break;
45
+ }
46
+ matches.push(m);
47
+ }
48
+ if (matches.length === 0)
49
+ return { content: "(no matches)" };
50
+ const body = matches.join("\n");
51
+ return { content: truncated ? `${body}\n... (truncated at ${LIMIT})` : body };
52
+ },
53
+ };
54
+ }
@@ -0,0 +1,5 @@
1
+ import type { Tool } from "@chengchenccc/message";
2
+ export declare function createGrepTool(opts: {
3
+ workspaceRoot: string;
4
+ }): Tool;
5
+ //# sourceMappingURL=grep.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grep.d.ts","sourceRoot":"","sources":["../../../src/core/tools/grep.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AASlD,wBAAgB,cAAc,CAAC,IAAI,EAAE;IAAE,aAAa,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAkEpE"}