@elizaos/cli 1.0.8 → 1.0.10

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 (242) hide show
  1. package/README.md +9 -16
  2. package/dist/assets/{index-CZAd5zm2.js → index-CmuPnu0u.js} +72 -89
  3. package/dist/assets/index-CmuPnu0u.js.br +0 -0
  4. package/dist/assets/index-CmuPnu0u.js.map +1 -0
  5. package/dist/assets/{index-CaEsCLCC.js → index-DDQnwxzL.js} +28798 -16391
  6. package/dist/assets/{index-CaEsCLCC.js.map → index-DDQnwxzL.js.map} +1 -1
  7. package/dist/assets/index-Df1AFSuJ.css +1 -0
  8. package/dist/assets/index-Df1AFSuJ.css.br +0 -0
  9. package/dist/assets/vendor-DSdxb8P-.js.map +1 -1
  10. package/dist/{chunk-REBZFQYE.js → chunk-7HYEGM5V.js} +967 -1597
  11. package/dist/{chunk-W3HS2NP6.js → chunk-B4KJXECB.js} +13 -18
  12. package/dist/{chunk-33BHGAF7.js → chunk-GWQB7PBK.js} +59 -32
  13. package/dist/{chunk-CVADLFW6.js → chunk-LQ6XHF53.js} +4543 -3043
  14. package/dist/{chunk-GYTAJJOD.js → chunk-RIAWNDYI.js} +16 -2
  15. package/dist/{chunk-IEKLJDUU.js → chunk-WS4DWCDZ.js} +54 -32
  16. package/dist/commands/agent/actions/index.d.ts +5 -1
  17. package/dist/commands/agent/actions/index.js +5 -4
  18. package/dist/commands/agent/index.js +3 -4
  19. package/dist/commands/create/actions/index.js +4 -5
  20. package/dist/commands/create/index.js +5 -6
  21. package/dist/{fileFromPath-DCRQMDLJ.js → fileFromPath-KB6XMTJ4.js} +1 -0
  22. package/dist/index.html +2 -2
  23. package/dist/index.js +9346 -102098
  24. package/dist/{migrator-KZLCVEIH.js → migrator-JREQPDN3.js} +42 -220
  25. package/dist/pglite.data +0 -0
  26. package/dist/pglite.wasm +0 -0
  27. package/dist/plugin-creator-T4K2673C.js +910 -0
  28. package/dist/{registry-XFOSZFU4.js → registry-CBMRMYCG.js} +3 -4
  29. package/dist/templates/plugin-starter/README.md +255 -0
  30. package/dist/templates/plugin-starter/bunfig.toml +6 -0
  31. package/dist/templates/plugin-starter/cypress.config.ts +18 -0
  32. package/dist/templates/plugin-starter/index.html +13 -0
  33. package/dist/templates/plugin-starter/package.json +95 -0
  34. package/dist/templates/plugin-starter/postcss.config.js +3 -0
  35. package/dist/templates/plugin-starter/scripts/test-e2e-manual.js +201 -0
  36. package/dist/templates/plugin-starter/src/__tests__/cypress/component/ExampleRoute.cy.tsx +404 -0
  37. package/dist/templates/plugin-starter/src/__tests__/cypress/component/PanelComponent.cy.tsx +287 -0
  38. package/dist/templates/plugin-starter/src/__tests__/cypress/support/commands.ts +38 -0
  39. package/dist/templates/plugin-starter/src/__tests__/cypress/support/component-index.html +11 -0
  40. package/dist/templates/plugin-starter/src/__tests__/cypress/support/component.ts +33 -0
  41. package/dist/templates/plugin-starter/src/__tests__/cypress/support/e2e.ts +11 -0
  42. package/dist/templates/plugin-starter/src/__tests__/cypress/tsconfig.json +10 -0
  43. package/dist/templates/plugin-starter/src/__tests__/e2e/README.md +47 -0
  44. package/dist/templates/plugin-starter/src/__tests__/e2e/starter-plugin.ts +320 -0
  45. package/{templates/plugin-starter → dist/templates/plugin-starter/src}/__tests__/integration.test.ts +22 -17
  46. package/{templates/plugin-starter → dist/templates/plugin-starter/src}/__tests__/plugin.test.ts +8 -8
  47. package/{templates/plugin-starter → dist/templates/plugin-starter/src}/__tests__/test-utils.ts +17 -17
  48. package/dist/templates/plugin-starter/src/frontend/index.css +77 -0
  49. package/dist/templates/plugin-starter/src/frontend/index.tsx +164 -0
  50. package/dist/templates/plugin-starter/src/frontend/utils.ts +6 -0
  51. package/dist/templates/plugin-starter/src/index.ts +274 -0
  52. package/dist/templates/plugin-starter/src/tests.ts +6 -0
  53. package/dist/templates/plugin-starter/tailwind.config.js +62 -0
  54. package/dist/templates/plugin-starter/tsconfig.build.json +11 -0
  55. package/dist/templates/plugin-starter/tsconfig.json +28 -0
  56. package/dist/templates/plugin-starter/tsup.config.ts +20 -0
  57. package/dist/templates/plugin-starter/vite.config.ts +20 -0
  58. package/dist/templates/project-starter/.env.example +153 -0
  59. package/dist/templates/project-starter/README.md +109 -0
  60. package/dist/templates/project-starter/bunfig.toml +6 -0
  61. package/dist/templates/project-starter/cypress.config.ts +31 -0
  62. package/dist/templates/project-starter/index.html +13 -0
  63. package/dist/templates/project-starter/package.json +83 -0
  64. package/dist/templates/project-starter/postcss.config.js +3 -0
  65. package/dist/templates/project-starter/scripts/test-all.sh +101 -0
  66. package/{templates/project-starter → dist/templates/project-starter/src}/__tests__/actions.test.ts +6 -6
  67. package/{templates/project-starter → dist/templates/project-starter/src}/__tests__/character.test.ts +3 -3
  68. package/{templates/project-starter → dist/templates/project-starter/src}/__tests__/config.test.ts +18 -18
  69. package/dist/templates/project-starter/src/__tests__/cypress/component/Accessibility.cy.tsx +271 -0
  70. package/dist/templates/project-starter/src/__tests__/cypress/component/ApiIntegration.cy.tsx +220 -0
  71. package/dist/templates/project-starter/src/__tests__/cypress/component/ExampleRoute.cy.tsx +146 -0
  72. package/dist/templates/project-starter/src/__tests__/cypress/component/PanelComponent.cy.tsx +51 -0
  73. package/dist/templates/project-starter/src/__tests__/cypress/e2e/agent-chat.cy.ts +235 -0
  74. package/dist/templates/project-starter/src/__tests__/cypress/e2e/dashboard.cy.ts +146 -0
  75. package/dist/templates/project-starter/src/__tests__/cypress/e2e/user-workflow.cy.ts +257 -0
  76. package/dist/templates/project-starter/src/__tests__/cypress/support/commands.ts +44 -0
  77. package/dist/templates/project-starter/src/__tests__/cypress/support/component-index.html +11 -0
  78. package/dist/templates/project-starter/src/__tests__/cypress/support/component.ts +33 -0
  79. package/dist/templates/project-starter/src/__tests__/cypress/support/e2e.ts +179 -0
  80. package/dist/templates/project-starter/src/__tests__/e2e/index.ts +14 -0
  81. package/dist/templates/project-starter/src/__tests__/e2e/natural-language.test.ts +246 -0
  82. package/dist/templates/project-starter/src/__tests__/e2e/project.test.ts +155 -0
  83. package/dist/templates/project-starter/src/__tests__/e2e/starter-plugin.test.ts +421 -0
  84. package/{templates/project-starter → dist/templates/project-starter/src}/__tests__/env.test.ts +2 -2
  85. package/{templates/project-starter → dist/templates/project-starter/src}/__tests__/error-handling.test.ts +17 -17
  86. package/{templates/project-starter → dist/templates/project-starter/src}/__tests__/events.test.ts +7 -7
  87. package/dist/templates/project-starter/src/__tests__/file-structure.test.ts +135 -0
  88. package/{templates/project-starter → dist/templates/project-starter/src}/__tests__/integration.test.ts +25 -25
  89. package/{templates/project-starter → dist/templates/project-starter/src}/__tests__/models.test.ts +6 -6
  90. package/{templates/project-starter → dist/templates/project-starter/src}/__tests__/plugin.test.ts +9 -9
  91. package/{templates/project-starter → dist/templates/project-starter/src}/__tests__/provider.test.ts +7 -7
  92. package/{templates/project-starter → dist/templates/project-starter/src}/__tests__/routes.test.ts +3 -3
  93. package/{templates/project-starter → dist/templates/project-starter/src}/__tests__/test-utils.ts +17 -17
  94. package/{templates/project-starter → dist/templates/project-starter/src}/__tests__/utils/core-test-utils.ts +3 -3
  95. package/dist/templates/project-starter/src/frontend/index.css +77 -0
  96. package/dist/templates/project-starter/src/frontend/index.html +19 -0
  97. package/dist/templates/project-starter/src/frontend/index.tsx +98 -0
  98. package/dist/templates/project-starter/src/frontend/utils.ts +6 -0
  99. package/dist/templates/project-starter/src/index.ts +153 -0
  100. package/dist/templates/project-starter/src/plugin.ts +255 -0
  101. package/dist/templates/project-starter/tailwind.config.js +62 -0
  102. package/dist/templates/project-starter/tsconfig.build.json +20 -0
  103. package/dist/templates/project-starter/tsconfig.json +39 -0
  104. package/dist/templates/project-starter/tsup.config.ts +19 -0
  105. package/dist/templates/project-starter/vite.config.ts +39 -0
  106. package/dist/templates/project-tee-starter/.dockerignore +20 -0
  107. package/dist/templates/project-tee-starter/.env.example +55 -0
  108. package/dist/templates/project-tee-starter/Dockerfile +66 -0
  109. package/dist/templates/project-tee-starter/GUIDE.md +235 -0
  110. package/dist/templates/project-tee-starter/README.md +173 -0
  111. package/dist/templates/project-tee-starter/__tests__/actions.test.ts +9 -0
  112. package/dist/templates/project-tee-starter/__tests__/character.test.ts +86 -0
  113. package/dist/templates/project-tee-starter/__tests__/config.test.ts +31 -0
  114. package/dist/templates/project-tee-starter/__tests__/env.test.ts +87 -0
  115. package/dist/templates/project-tee-starter/__tests__/error-handling.test.ts +30 -0
  116. package/dist/templates/project-tee-starter/__tests__/events.test.ts +21 -0
  117. package/{templates/project-starter → dist/templates/project-tee-starter}/__tests__/file-structure.test.ts +6 -6
  118. package/dist/templates/project-tee-starter/__tests__/integration.test.ts +205 -0
  119. package/dist/templates/project-tee-starter/__tests__/models.test.ts +22 -0
  120. package/dist/templates/project-tee-starter/__tests__/plugin.test.ts +38 -0
  121. package/dist/templates/project-tee-starter/__tests__/provider.test.ts +189 -0
  122. package/dist/templates/project-tee-starter/__tests__/routes.test.ts +21 -0
  123. package/dist/templates/project-tee-starter/__tests__/test-utils.ts +121 -0
  124. package/dist/templates/project-tee-starter/__tests__/utils/core-test-utils.ts +167 -0
  125. package/dist/templates/project-tee-starter/assets/mr-tee-portrait.jpg +0 -0
  126. package/dist/templates/project-tee-starter/bunfig.toml +6 -0
  127. package/dist/templates/project-tee-starter/docker-compose.yaml +57 -0
  128. package/dist/templates/project-tee-starter/e2e/project.test.ts +38 -0
  129. package/dist/templates/project-tee-starter/e2e/starter-plugin.test.ts +92 -0
  130. package/dist/templates/project-tee-starter/package.json +74 -0
  131. package/dist/templates/project-tee-starter/src/character.ts +257 -0
  132. package/dist/templates/project-tee-starter/src/index.ts +33 -0
  133. package/dist/templates/project-tee-starter/src/plugin.ts +169 -0
  134. package/dist/templates/project-tee-starter/tsconfig.build.json +13 -0
  135. package/dist/templates/project-tee-starter/tsconfig.json +30 -0
  136. package/dist/templates/project-tee-starter/tsup.config.ts +19 -0
  137. package/dist/{utils-DIZZ3HNZ.js → utils-TIALZU53.js} +9 -8
  138. package/package.json +29 -12
  139. package/templates/plugin-starter/README.md +38 -13
  140. package/templates/plugin-starter/bunfig.toml +6 -0
  141. package/templates/plugin-starter/cypress.config.ts +18 -0
  142. package/templates/plugin-starter/index.html +13 -0
  143. package/templates/plugin-starter/package.json +19 -7
  144. package/templates/plugin-starter/postcss.config.js +3 -0
  145. package/templates/plugin-starter/scripts/test-e2e-manual.js +201 -0
  146. package/templates/plugin-starter/src/__tests__/cypress/component/ExampleRoute.cy.tsx +404 -0
  147. package/templates/plugin-starter/src/__tests__/cypress/component/PanelComponent.cy.tsx +287 -0
  148. package/templates/plugin-starter/src/__tests__/cypress/support/commands.ts +38 -0
  149. package/templates/plugin-starter/src/__tests__/cypress/support/component-index.html +11 -0
  150. package/templates/plugin-starter/src/__tests__/cypress/support/component.ts +33 -0
  151. package/templates/plugin-starter/src/__tests__/cypress/support/e2e.ts +11 -0
  152. package/templates/plugin-starter/src/__tests__/cypress/tsconfig.json +10 -0
  153. package/templates/plugin-starter/src/__tests__/e2e/README.md +47 -0
  154. package/templates/plugin-starter/src/__tests__/e2e/starter-plugin.ts +320 -0
  155. package/templates/plugin-starter/src/__tests__/integration.test.ts +138 -0
  156. package/templates/plugin-starter/src/__tests__/plugin.test.ts +182 -0
  157. package/templates/plugin-starter/src/__tests__/test-utils.ts +162 -0
  158. package/templates/plugin-starter/src/frontend/index.css +77 -0
  159. package/templates/plugin-starter/src/frontend/index.tsx +164 -0
  160. package/templates/plugin-starter/src/frontend/utils.ts +6 -0
  161. package/templates/plugin-starter/src/index.ts +31 -8
  162. package/templates/plugin-starter/src/tests.ts +6 -0
  163. package/templates/plugin-starter/tailwind.config.js +62 -0
  164. package/templates/plugin-starter/tsconfig.json +8 -8
  165. package/templates/plugin-starter/vite.config.ts +20 -0
  166. package/templates/project-starter/bunfig.toml +6 -0
  167. package/templates/project-starter/cypress.config.ts +31 -0
  168. package/templates/project-starter/index.html +13 -0
  169. package/templates/project-starter/package.json +37 -14
  170. package/templates/project-starter/postcss.config.js +3 -0
  171. package/templates/project-starter/scripts/test-all.sh +101 -0
  172. package/templates/project-starter/src/__tests__/actions.test.ts +155 -0
  173. package/templates/project-starter/src/__tests__/character.test.ts +86 -0
  174. package/templates/project-starter/src/__tests__/config.test.ts +193 -0
  175. package/templates/project-starter/src/__tests__/cypress/component/Accessibility.cy.tsx +271 -0
  176. package/templates/project-starter/src/__tests__/cypress/component/ApiIntegration.cy.tsx +220 -0
  177. package/templates/project-starter/src/__tests__/cypress/component/ExampleRoute.cy.tsx +146 -0
  178. package/templates/project-starter/src/__tests__/cypress/component/PanelComponent.cy.tsx +51 -0
  179. package/templates/project-starter/src/__tests__/cypress/e2e/agent-chat.cy.ts +235 -0
  180. package/templates/project-starter/src/__tests__/cypress/e2e/dashboard.cy.ts +146 -0
  181. package/templates/project-starter/src/__tests__/cypress/e2e/user-workflow.cy.ts +257 -0
  182. package/templates/project-starter/src/__tests__/cypress/support/commands.ts +44 -0
  183. package/templates/project-starter/src/__tests__/cypress/support/component-index.html +11 -0
  184. package/templates/project-starter/src/__tests__/cypress/support/component.ts +33 -0
  185. package/templates/project-starter/src/__tests__/cypress/support/e2e.ts +179 -0
  186. package/templates/project-starter/src/__tests__/e2e/index.ts +14 -0
  187. package/templates/project-starter/src/__tests__/e2e/natural-language.test.ts +246 -0
  188. package/templates/project-starter/src/__tests__/e2e/project.test.ts +155 -0
  189. package/templates/project-starter/src/__tests__/e2e/starter-plugin.test.ts +421 -0
  190. package/templates/project-starter/src/__tests__/env.test.ts +87 -0
  191. package/templates/project-starter/src/__tests__/error-handling.test.ts +177 -0
  192. package/templates/project-starter/src/__tests__/events.test.ts +144 -0
  193. package/templates/project-starter/src/__tests__/file-structure.test.ts +135 -0
  194. package/templates/project-starter/src/__tests__/integration.test.ts +209 -0
  195. package/templates/project-starter/src/__tests__/models.test.ts +152 -0
  196. package/templates/project-starter/src/__tests__/plugin.test.ts +393 -0
  197. package/templates/project-starter/src/__tests__/provider.test.ts +325 -0
  198. package/templates/project-starter/src/__tests__/routes.test.ts +79 -0
  199. package/templates/project-starter/src/__tests__/test-utils.ts +121 -0
  200. package/templates/project-starter/src/__tests__/utils/core-test-utils.ts +180 -0
  201. package/templates/project-starter/src/frontend/index.css +77 -0
  202. package/templates/project-starter/src/frontend/index.html +19 -0
  203. package/templates/project-starter/src/frontend/index.tsx +98 -0
  204. package/templates/project-starter/src/frontend/utils.ts +6 -0
  205. package/templates/project-starter/src/index.ts +9 -1
  206. package/templates/project-starter/tailwind.config.js +62 -0
  207. package/templates/project-starter/tsconfig.build.json +9 -2
  208. package/templates/project-starter/tsconfig.json +15 -6
  209. package/templates/project-starter/tsup.config.ts +1 -1
  210. package/templates/project-starter/vite.config.ts +39 -0
  211. package/templates/project-tee-starter/__tests__/actions.test.ts +1 -1
  212. package/templates/project-tee-starter/__tests__/character.test.ts +1 -1
  213. package/templates/project-tee-starter/__tests__/config.test.ts +1 -1
  214. package/templates/project-tee-starter/__tests__/env.test.ts +2 -2
  215. package/templates/project-tee-starter/__tests__/error-handling.test.ts +1 -1
  216. package/templates/project-tee-starter/__tests__/events.test.ts +1 -1
  217. package/templates/project-tee-starter/__tests__/file-structure.test.ts +5 -5
  218. package/templates/project-tee-starter/__tests__/integration.test.ts +22 -26
  219. package/templates/project-tee-starter/__tests__/models.test.ts +1 -1
  220. package/templates/project-tee-starter/__tests__/plugin.test.ts +6 -12
  221. package/templates/project-tee-starter/__tests__/provider.test.ts +6 -6
  222. package/templates/project-tee-starter/__tests__/routes.test.ts +1 -1
  223. package/templates/project-tee-starter/__tests__/test-utils.ts +15 -15
  224. package/templates/project-tee-starter/__tests__/utils/core-test-utils.ts +3 -3
  225. package/templates/project-tee-starter/bunfig.toml +6 -0
  226. package/templates/project-tee-starter/package.json +10 -12
  227. package/dist/assets/index-CZAd5zm2.js.br +0 -0
  228. package/dist/assets/index-CZAd5zm2.js.map +0 -1
  229. package/dist/assets/index-DyA-lndn.css +0 -1
  230. package/dist/assets/index-DyA-lndn.css.br +0 -0
  231. package/dist/chunk-CEE6RKN5.js +0 -2746
  232. package/dist/chunk-MA2ZXPG6.js +0 -260
  233. package/dist/chunk-TUAYJIF2.js +0 -3649
  234. package/dist/lib-NAGYZHVV.js +0 -9
  235. package/dist/plugin-creator-IC42XOHG.js +0 -29165
  236. package/templates/plugin-starter/e2e/starter-plugin.test.ts +0 -171
  237. package/templates/plugin-starter/images/README.md +0 -24
  238. package/templates/plugin-starter/vitest.config.ts +0 -16
  239. package/templates/project-starter/e2e/project.test.ts +0 -34
  240. package/templates/project-starter/e2e/starter-plugin.test.ts +0 -217
  241. package/templates/project-starter/vitest.config.ts +0 -16
  242. package/templates/project-tee-starter/vitest.config.ts +0 -19
@@ -0,0 +1,910 @@
1
+
2
+ import { createRequire } from 'module';
3
+ const require = createRequire(import.meta.url);
4
+
5
+ import {
6
+ esm_default,
7
+ ora,
8
+ sdk_default
9
+ } from "./chunk-LQ6XHF53.js";
10
+ import "./chunk-2GXSCVA2.js";
11
+ import {
12
+ runBunCommand
13
+ } from "./chunk-RIAWNDYI.js";
14
+ import "./chunk-WS4DWCDZ.js";
15
+ import "./chunk-567UPUC7.js";
16
+
17
+ // src/utils/plugin-creator.ts
18
+ import { logger } from "@elizaos/core";
19
+ import { execa } from "execa";
20
+ import * as fs from "fs-extra";
21
+ import inquirer from "inquirer";
22
+ import * as path from "path";
23
+ import * as os from "os";
24
+ var MAX_BUILD_ITERATIONS = 5;
25
+ var MAX_TEST_ITERATIONS = 5;
26
+ var MAX_REVISION_ITERATIONS = 3;
27
+ var CLAUDE_CODE_TIMEOUT = 15 * 60 * 1e3;
28
+ var MIN_DISK_SPACE_GB = 2;
29
+ var PluginCreator = class {
30
+ git;
31
+ pluginPath = null;
32
+ anthropic = null;
33
+ activeClaudeProcess = null;
34
+ options;
35
+ constructor(options = {}) {
36
+ this.git = esm_default();
37
+ this.options = options;
38
+ this.registerCleanupHandlers();
39
+ }
40
+ registerCleanupHandlers() {
41
+ const cleanup = async () => {
42
+ logger.info("Cleaning up plugin creation process...");
43
+ if (this.activeClaudeProcess) {
44
+ try {
45
+ this.activeClaudeProcess.kill();
46
+ logger.info("Terminated active Claude Code process");
47
+ } catch (error) {
48
+ logger.error("Failed to terminate Claude Code process:", error);
49
+ }
50
+ }
51
+ process.exit(1);
52
+ };
53
+ process.on("SIGINT", cleanup);
54
+ process.on("SIGTERM", cleanup);
55
+ process.on("uncaughtException", async (error) => {
56
+ logger.error("Uncaught exception:", error);
57
+ await cleanup();
58
+ });
59
+ }
60
+ async initializeAnthropic() {
61
+ const apiKey = process.env.ANTHROPIC_API_KEY;
62
+ if (!apiKey) {
63
+ logger.error("ANTHROPIC_API_KEY not found in environment.");
64
+ throw new Error("ANTHROPIC_API_KEY is required for plugin generation");
65
+ }
66
+ this.anthropic = new sdk_default({ apiKey });
67
+ }
68
+ async create(pluginSpec) {
69
+ const spinner = ora("Initializing plugin creator...").start();
70
+ try {
71
+ await this.initializeAnthropic();
72
+ spinner.info("Checking disk space...");
73
+ await this.checkDiskSpace();
74
+ try {
75
+ await execa("claude", ["--version"], { stdio: "pipe" });
76
+ } catch {
77
+ throw new Error(
78
+ "Claude Code is required for plugin generation. Install with: bun install -g @anthropic-ai/claude-code"
79
+ );
80
+ }
81
+ spinner.info("Collecting plugin specification...");
82
+ const spec = pluginSpec || this.options.spec || await this.collectPluginSpecification();
83
+ spinner.succeed("Plugin specification collected");
84
+ spinner.info("Creating plugin from template...");
85
+ await this.createFromTemplate(spec.name);
86
+ spinner.succeed("Plugin structure created");
87
+ spinner.info("Generating detailed plugin specification...");
88
+ const detailedSpec = await this.generateDetailedSpecification(spec);
89
+ spinner.succeed("Detailed specification generated");
90
+ spinner.info("Creating plugin specification document...");
91
+ await this.createSpecificationDocument(spec, detailedSpec);
92
+ spinner.succeed("Specification document created");
93
+ spinner.info("Generating plugin code...");
94
+ const generationSuccess = await this.runGenerationWithValidation();
95
+ if (!generationSuccess) {
96
+ throw new Error("Plugin generation failed after maximum iterations");
97
+ }
98
+ spinner.succeed("Plugin code generated and validated");
99
+ const targetPath = await this.copyToCWD();
100
+ logger.info(`\u2705 Plugin successfully created!`);
101
+ logger.info(`\u{1F4C1} Plugin location: ${targetPath}`);
102
+ logger.info(`
103
+ \u{1F4CC} Next steps:`);
104
+ logger.info(`1. cd ${path.basename(targetPath)}`);
105
+ logger.info(`2. Review the generated code`);
106
+ logger.info(`3. Run tests: bun test`);
107
+ logger.info(`4. Add to your ElizaOS project
108
+ `);
109
+ return {
110
+ success: true,
111
+ pluginName: spec.name,
112
+ pluginPath: targetPath
113
+ };
114
+ } catch (error) {
115
+ spinner.fail("Plugin creation failed");
116
+ logger.error("Error creating plugin:", error);
117
+ return {
118
+ success: false,
119
+ pluginName: "",
120
+ pluginPath: "",
121
+ error
122
+ };
123
+ }
124
+ }
125
+ async collectPluginSpecification() {
126
+ if (this.options.skipPrompts) {
127
+ throw new Error("Plugin specification required when skipping prompts");
128
+ }
129
+ const answers = await inquirer.prompt([
130
+ {
131
+ type: "input",
132
+ name: "name",
133
+ message: 'Plugin name (without "plugin-" prefix):',
134
+ validate: (input) => {
135
+ if (!input || input.trim() === "") {
136
+ return "Plugin name is required";
137
+ }
138
+ return true;
139
+ },
140
+ filter: (input) => input.toLowerCase().replace(/\s+/g, "-")
141
+ },
142
+ {
143
+ type: "input",
144
+ name: "description",
145
+ message: "Plugin description:",
146
+ validate: (input) => input.length > 0 || "Description is required"
147
+ },
148
+ {
149
+ type: "input",
150
+ name: "features",
151
+ message: "Main features (comma-separated):",
152
+ filter: (input) => input.split(",").map((f) => f.trim()).filter((f) => f)
153
+ },
154
+ {
155
+ type: "checkbox",
156
+ name: "components",
157
+ message: "Which components will this plugin include?",
158
+ choices: [
159
+ { name: "Actions", value: "actions" },
160
+ { name: "Providers", value: "providers" },
161
+ { name: "Evaluators", value: "evaluators" },
162
+ { name: "Services", value: "services" }
163
+ ],
164
+ default: ["actions", "providers"]
165
+ }
166
+ ]);
167
+ const spec = {
168
+ name: answers.name,
169
+ description: answers.description,
170
+ features: answers.features
171
+ };
172
+ if (answers.components.includes("actions")) {
173
+ const actionAnswers = await inquirer.prompt([
174
+ {
175
+ type: "input",
176
+ name: "actions",
177
+ message: "Action names (comma-separated):",
178
+ filter: (input) => input.split(",").map((a) => a.trim()).filter((a) => a)
179
+ }
180
+ ]);
181
+ spec.actions = actionAnswers.actions;
182
+ }
183
+ if (answers.components.includes("providers")) {
184
+ const providerAnswers = await inquirer.prompt([
185
+ {
186
+ type: "input",
187
+ name: "providers",
188
+ message: "Provider names (comma-separated):",
189
+ filter: (input) => input.split(",").map((p) => p.trim()).filter((p) => p)
190
+ }
191
+ ]);
192
+ spec.providers = providerAnswers.providers;
193
+ }
194
+ if (answers.components.includes("evaluators")) {
195
+ const evaluatorAnswers = await inquirer.prompt([
196
+ {
197
+ type: "input",
198
+ name: "evaluators",
199
+ message: "Evaluator names (comma-separated):",
200
+ filter: (input) => input.split(",").map((e) => e.trim()).filter((e) => e)
201
+ }
202
+ ]);
203
+ spec.evaluators = evaluatorAnswers.evaluators;
204
+ }
205
+ if (answers.components.includes("services")) {
206
+ const serviceAnswers = await inquirer.prompt([
207
+ {
208
+ type: "input",
209
+ name: "services",
210
+ message: "Service names (comma-separated):",
211
+ filter: (input) => input.split(",").map((s) => s.trim()).filter((s) => s)
212
+ }
213
+ ]);
214
+ spec.services = serviceAnswers.services;
215
+ }
216
+ return spec;
217
+ }
218
+ async createFromTemplate(pluginName) {
219
+ const tempDir = path.join(os.tmpdir(), `plugin-${pluginName}-${Date.now()}`);
220
+ await fs.ensureDir(tempDir);
221
+ this.pluginPath = path.join(tempDir, `plugin-${pluginName}`);
222
+ try {
223
+ await execa(
224
+ "bunx",
225
+ ["@elizaos/cli", "create", `plugin-${pluginName}`, "-t", "plugin-starter"],
226
+ {
227
+ cwd: tempDir,
228
+ stdio: "pipe"
229
+ }
230
+ );
231
+ } catch (error) {
232
+ logger.warn("Failed to use elizaos create, creating structure manually");
233
+ await this.createPluginStructureManually(pluginName);
234
+ }
235
+ this.git = esm_default(this.pluginPath);
236
+ await this.git.init();
237
+ await this.git.add(".");
238
+ await this.git.commit("Initial commit from plugin-starter template");
239
+ }
240
+ async createPluginStructureManually(pluginName) {
241
+ await fs.ensureDir(this.pluginPath);
242
+ const dirs = ["src", "src/actions", "src/providers", "src/evaluators", "src/services", "tests"];
243
+ for (const dir of dirs) {
244
+ await fs.ensureDir(path.join(this.pluginPath, dir));
245
+ }
246
+ const packageJson = {
247
+ name: `@elizaos/plugin-${pluginName}`,
248
+ version: "0.1.0",
249
+ description: `ElizaOS ${pluginName} plugin`,
250
+ main: "dist/index.js",
251
+ types: "dist/index.d.ts",
252
+ scripts: {
253
+ build: "tsup",
254
+ dev: "tsup --watch",
255
+ test: "bun test",
256
+ "test:watch": "bun test --watch"
257
+ },
258
+ dependencies: {
259
+ "@elizaos/core": "^1.0.0"
260
+ },
261
+ devDependencies: {
262
+ tsup: "^8.4.0",
263
+ typescript: "^5.3.0",
264
+ "@types/bun": "^1.0.0",
265
+ "@types/node": "^20.0.0"
266
+ },
267
+ peerDependencies: {
268
+ "@elizaos/core": "1.x"
269
+ },
270
+ files: ["dist", "README.md"]
271
+ };
272
+ await fs.writeJSON(path.join(this.pluginPath, "package.json"), packageJson, { spaces: 2 });
273
+ const tsconfig = {
274
+ extends: "../../tsconfig.json",
275
+ compilerOptions: {
276
+ outDir: "./dist",
277
+ rootDir: "./src"
278
+ },
279
+ include: ["src/**/*"],
280
+ exclude: ["node_modules", "dist"]
281
+ };
282
+ await fs.writeJSON(path.join(this.pluginPath, "tsconfig.json"), tsconfig, { spaces: 2 });
283
+ const tsupConfig = `import { defineConfig } from 'tsup';
284
+
285
+ export default defineConfig({
286
+ entry: ['src/index.ts'],
287
+ format: ['cjs', 'esm'],
288
+ dts: true,
289
+ sourcemap: true,
290
+ clean: true,
291
+ external: ['@elizaos/core'],
292
+ });
293
+ `;
294
+ await fs.writeFile(path.join(this.pluginPath, "tsup.config.ts"), tsupConfig);
295
+ const gitignore = `node_modules/
296
+ dist/
297
+ *.log
298
+ .env
299
+ .DS_Store
300
+ coverage/
301
+ `;
302
+ await fs.writeFile(path.join(this.pluginPath, ".gitignore"), gitignore);
303
+ const readme = `# @elizaos/plugin-${pluginName}
304
+
305
+ ElizaOS ${pluginName} plugin
306
+
307
+ ## Installation
308
+
309
+ \`\`\`bash
310
+ bun install @elizaos/plugin-${pluginName}
311
+ \`\`\`
312
+
313
+ ## Usage
314
+
315
+ \`\`\`typescript
316
+ import { plugin${pluginName.split("-").map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join("")} } from '@elizaos/plugin-${pluginName}';
317
+
318
+ // Add to your ElizaOS configuration
319
+ \`\`\`
320
+ `;
321
+ await fs.writeFile(path.join(this.pluginPath, "README.md"), readme);
322
+ const indexContent = `import { Plugin } from '@elizaos/core';
323
+
324
+ export const plugin${pluginName.split("-").map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join("")}: Plugin = {
325
+ name: 'plugin-${pluginName}',
326
+ version: '0.1.0',
327
+ actions: [],
328
+ providers: [],
329
+ evaluators: [],
330
+ services: [],
331
+ };
332
+
333
+ export default plugin${pluginName.split("-").map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join("")};
334
+ `;
335
+ await fs.writeFile(path.join(this.pluginPath, "src/index.ts"), indexContent);
336
+ }
337
+ async generateDetailedSpecification(spec) {
338
+ const prompt = `You are creating a detailed technical specification for an ElizaOS plugin.
339
+
340
+ ## Plugin Overview
341
+ Name: ${spec.name}
342
+ Description: ${spec.description}
343
+ Features: ${spec.features.join(", ")}
344
+
345
+ ${spec.actions ? `Actions: ${spec.actions.join(", ")}` : ""}
346
+ ${spec.providers ? `Providers: ${spec.providers.join(", ")}` : ""}
347
+ ${spec.evaluators ? `Evaluators: ${spec.evaluators.join(", ")}` : ""}
348
+ ${spec.services ? `Services: ${spec.services.join(", ")}` : ""}
349
+
350
+ ## CRITICAL REQUIREMENTS
351
+
352
+ ### 1. Database Compatibility (MANDATORY)
353
+ This plugin MUST work with both Pglite and PostgreSQL. The specification must include:
354
+ - Database-agnostic design patterns
355
+ - Use of runtime APIs only (no direct database access)
356
+ - Memory operations using runtime.createMemory(), runtime.searchMemories()
357
+ - Goal operations using runtime.createGoal(), runtime.updateGoal()
358
+ - Relationship operations using runtime.ensureConnection()
359
+ - NO database-specific code or SQL queries
360
+ - NO direct database adapter imports
361
+
362
+ ### 2. Import Requirements (MANDATORY)
363
+ - ALL imports must come from @elizaos/core ONLY
364
+ - NO imports from @elizaos/plugin, @elizaos/types, @elizaos/logger (these don't exist)
365
+ - Use: import { Plugin, Action, AgentRuntime, logger, Memory, State } from '@elizaos/core'
366
+
367
+ ## Task
368
+ Generate a detailed technical specification that includes:
369
+
370
+ 1. **Architecture Overview**: How the plugin components work together (database-agnostic)
371
+ 2. **Component Specifications**: Detailed specs for each action, provider, evaluator, and service
372
+ 3. **Data Flow**: How data moves through the plugin using runtime APIs
373
+ 4. **Integration Points**: How the plugin integrates with ElizaOS runtime
374
+ 5. **Implementation Details**: Specific algorithms, APIs, or techniques to use (database-agnostic)
375
+ 6. **Database Abstraction**: How to use runtime APIs for all data operations
376
+ 7. **Testing Strategy**: What tests are needed (including database compatibility tests)
377
+ 8. **Error Handling**: How errors should be handled
378
+ 9. **Configuration**: Any configuration options needed
379
+
380
+ ## Database Abstraction Examples:
381
+ \`\`\`typescript
382
+ // Memory operations - works with both Pglite and PostgreSQL
383
+ await runtime.createMemory({
384
+ entityId: message.entityId,
385
+ agentId: runtime.agentId,
386
+ content: { text: 'Important information' },
387
+ roomId: message.roomId,
388
+ embedding: await runtime.embed('Important information'),
389
+ });
390
+
391
+ // Search memories - database-agnostic
392
+ const memories = await runtime.searchMemories({
393
+ text: query,
394
+ entityId: message.entityId,
395
+ count: 10,
396
+ });
397
+
398
+ // Goal operations - database-agnostic
399
+ await runtime.createGoal({
400
+ entityId: message.entityId,
401
+ agentId: runtime.agentId,
402
+ name: 'Complete task',
403
+ status: 'IN_PROGRESS',
404
+ });
405
+ \`\`\`
406
+
407
+ Be extremely detailed and specific. This specification will be used to generate the actual code.
408
+ Remember: The plugin must work with BOTH Pglite and PostgreSQL without any code changes.`;
409
+ const message = await this.anthropic.messages.create({
410
+ model: "claude-opus-4-20250514",
411
+ max_tokens: 8192,
412
+ temperature: 0.3,
413
+ messages: [
414
+ {
415
+ role: "user",
416
+ content: prompt
417
+ }
418
+ ]
419
+ });
420
+ return message.content.map((block) => block.type === "text" ? block.text : "").join("");
421
+ }
422
+ async createSpecificationDocument(spec, detailedSpec) {
423
+ const content = `# Plugin Specification: ${spec.name}
424
+
425
+ ## Overview
426
+ ${spec.description}
427
+
428
+ ## Features
429
+ ${spec.features.map((f) => `- ${f}`).join("\n")}
430
+
431
+ ## Components
432
+ ${spec.actions ? `### Actions
433
+ ${spec.actions.map((a) => `- ${a}`).join("\n")}` : ""}
434
+ ${spec.providers ? `### Providers
435
+ ${spec.providers.map((p) => `- ${p}`).join("\n")}` : ""}
436
+ ${spec.evaluators ? `### Evaluators
437
+ ${spec.evaluators.map((e) => `- ${e}`).join("\n")}` : ""}
438
+ ${spec.services ? `### Services
439
+ ${spec.services.map((s) => `- ${s}`).join("\n")}` : ""}
440
+
441
+ ## CRITICAL REQUIREMENTS
442
+
443
+ ### Database Compatibility (MANDATORY)
444
+ This plugin MUST work with both Pglite and PostgreSQL without any code changes.
445
+
446
+ #### Database Abstraction Rules:
447
+ - \u2705 Use ONLY runtime.databaseAdapter for database operations
448
+ - \u2705 Use runtime.createMemory(), runtime.searchMemories(), runtime.createGoal()
449
+ - \u2705 Use runtime.ensureConnection() for relationships
450
+ - \u274C NEVER import database adapters directly (PgliteDatabaseAdapter, PgDatabaseAdapter)
451
+ - \u274C NEVER use database-specific SQL or queries
452
+ - \u274C NEVER make assumptions about database type
453
+
454
+ #### Example Database-Agnostic Code:
455
+ \`\`\`typescript
456
+ // \u2705 CORRECT - Memory operations
457
+ await runtime.createMemory({
458
+ entityId: message.entityId,
459
+ agentId: runtime.agentId,
460
+ content: { text: 'Information to store' },
461
+ roomId: message.roomId,
462
+ embedding: await runtime.embed('Information to store'),
463
+ });
464
+
465
+ // \u2705 CORRECT - Search operations
466
+ const memories = await runtime.searchMemories({
467
+ text: searchQuery,
468
+ entityId: message.entityId,
469
+ count: 10,
470
+ });
471
+
472
+ // \u274C WRONG - Direct database imports
473
+ import { PgliteDatabaseAdapter } from '@elizaos/plugin-sql';
474
+ \`\`\`
475
+
476
+ ### Import Requirements (MANDATORY)
477
+ ALL imports must come from @elizaos/core ONLY:
478
+
479
+ \`\`\`typescript
480
+ // \u2705 CORRECT - All from @elizaos/core
481
+ import {
482
+ Plugin,
483
+ Action,
484
+ AgentRuntime,
485
+ logger,
486
+ Memory,
487
+ State,
488
+ Content,
489
+ HandlerCallback,
490
+ Service,
491
+ } from '@elizaos/core';
492
+
493
+ // \u274C WRONG - These packages don't exist
494
+ import { logger } from '@elizaos/logger';
495
+ import { Action } from '@elizaos/types';
496
+ import { PgliteDatabaseAdapter } from '@elizaos/plugin-sql';
497
+ \`\`\`
498
+
499
+ ## Detailed Technical Specification
500
+
501
+ ${detailedSpec}
502
+
503
+ ## Implementation Instructions
504
+
505
+ You are now going to implement this plugin following ElizaOS 1.0.0 best practices:
506
+
507
+ ### 1. Core Implementation
508
+ - **Use TypeScript** for all code
509
+ - **Follow the ElizaOS plugin structure** exactly
510
+ - **Implement all components** specified above
511
+ - **Create comprehensive tests** for each component
512
+ - **Use proper error handling** throughout
513
+ - **Add detailed logging** using the ElizaOS logger
514
+
515
+ ### 2. Database Compatibility
516
+ - **MANDATORY**: Plugin must work with both Pglite and PostgreSQL
517
+ - **Use ONLY runtime APIs** for all data operations
518
+ - **NO direct database imports** or database-specific code
519
+ - **Test with both databases** in test suite
520
+
521
+ ### 3. Import Compliance
522
+ - **ALL imports from @elizaos/core ONLY**
523
+ - **NO imports from non-existent packages**
524
+ - **Follow import examples above exactly**
525
+
526
+ ### 4. Component Requirements
527
+ - **Services**: Must extend the base Service class with lifecycle methods (initialize, start, stop)
528
+ - **Actions**: Must implement validate and handler functions
529
+ - **Providers**: Must return formatted context strings using runtime APIs
530
+ - **Evaluators**: Run after interactions, store data using runtime APIs
531
+ - **All components**: Must be properly exported in index.ts
532
+
533
+ ### 5. Testing Requirements
534
+ - **Tests must use bun test** and cover all functionality
535
+ - **Database compatibility tests**:
536
+ \`\`\`typescript
537
+ describe('Database Compatibility', () => {
538
+ it('should work with Pglite', async () => {
539
+ process.env.PGLITE_DATA_DIR = './.test-db';
540
+ delete process.env.POSTGRES_URL;
541
+ // Test plugin functionality
542
+ });
543
+
544
+ it('should work with PostgreSQL', async () => {
545
+ process.env.POSTGRES_URL = 'postgresql://test:test@localhost:5432/test';
546
+ delete process.env.PGLITE_DATA_DIR;
547
+ // Test plugin functionality
548
+ });
549
+ });
550
+ \`\`\`
551
+
552
+ ### 6. Quality Requirements
553
+ - **NO stubs or incomplete code**
554
+ - **Production-ready implementation**
555
+ - **Proper error handling**
556
+ - **Clean, well-organized code**
557
+
558
+ ## Production Readiness Checklist
559
+
560
+ Before considering implementation complete, verify:
561
+
562
+ - \u2705 All imports come from @elizaos/core only
563
+ - \u2705 No direct database adapter imports
564
+ - \u2705 Uses runtime APIs for all data operations
565
+ - \u2705 Works with both Pglite and PostgreSQL
566
+ - \u2705 Has comprehensive tests for both database types
567
+ - \u2705 No database-specific code or SQL
568
+ - \u2705 Proper error handling throughout
569
+ - \u2705 No stubs or incomplete code
570
+ - \u2705 Services extend base Service class
571
+ - \u2705 Actions have validation and handlers
572
+ - \u2705 All components properly exported
573
+
574
+ Work systematically through each component, implementing it completely before moving to the next.
575
+ Remember: Database compatibility is MANDATORY - the plugin MUST work with both Pglite and PostgreSQL.
576
+ `;
577
+ await fs.writeFile(path.join(this.pluginPath, "PLUGIN_SPEC.md"), content);
578
+ }
579
+ async runGenerationWithValidation() {
580
+ await this.runClaudeCode();
581
+ if (!await this.runBuildLoop()) {
582
+ return false;
583
+ }
584
+ if (!this.options.skipTests && !await this.runTestLoop()) {
585
+ return false;
586
+ }
587
+ if (!this.options.skipValidation && !await this.runProductionValidationLoop()) {
588
+ return false;
589
+ }
590
+ return true;
591
+ }
592
+ async runBuildLoop() {
593
+ let buildIteration = 0;
594
+ let buildSuccess = false;
595
+ while (buildIteration < MAX_BUILD_ITERATIONS && !buildSuccess) {
596
+ buildIteration++;
597
+ logger.info(`Build iteration ${buildIteration}/${MAX_BUILD_ITERATIONS}`);
598
+ if (buildIteration > 1) {
599
+ const buildErrors = await this.getBuildErrors();
600
+ await this.runClaudeCodeWithContext(buildErrors);
601
+ }
602
+ const buildResult = await this.runBuild();
603
+ buildSuccess = buildResult.success;
604
+ if (buildSuccess) {
605
+ logger.info("\u2705 Build successful!");
606
+ return true;
607
+ } else {
608
+ logger.warn(`Build failed. ${MAX_BUILD_ITERATIONS - buildIteration} attempts remaining.`);
609
+ }
610
+ }
611
+ return buildSuccess;
612
+ }
613
+ async runTestLoop() {
614
+ let testIteration = 0;
615
+ let allTestsPass = false;
616
+ while (testIteration < MAX_TEST_ITERATIONS && !allTestsPass) {
617
+ testIteration++;
618
+ logger.info(`Test iteration ${testIteration}/${MAX_TEST_ITERATIONS}`);
619
+ if (testIteration > 1) {
620
+ const testErrors = await this.getTestErrors();
621
+ await this.runClaudeCodeWithContext(testErrors);
622
+ }
623
+ const testResult = await this.runTests();
624
+ allTestsPass = testResult.success;
625
+ if (allTestsPass) {
626
+ logger.info("\u2705 All tests passing!");
627
+ return true;
628
+ } else {
629
+ logger.warn(`Tests failed. ${MAX_TEST_ITERATIONS - testIteration} attempts remaining.`);
630
+ }
631
+ }
632
+ return allTestsPass;
633
+ }
634
+ async runProductionValidationLoop() {
635
+ let revisionIteration = 0;
636
+ let productionReady = false;
637
+ while (revisionIteration < MAX_REVISION_ITERATIONS && !productionReady) {
638
+ revisionIteration++;
639
+ logger.info(
640
+ `Production validation iteration ${revisionIteration}/${MAX_REVISION_ITERATIONS}`
641
+ );
642
+ const validationResult = await this.validateProductionReadiness();
643
+ productionReady = validationResult.production_ready;
644
+ if (productionReady) {
645
+ logger.info("\u2705 Plugin validated as production ready!");
646
+ return true;
647
+ } else if (validationResult.revision_instructions) {
648
+ logger.warn("Plugin needs revisions. Applying changes...");
649
+ await this.runClaudeCodeWithContext(validationResult.revision_instructions);
650
+ if (!await this.runBuildLoop() || !this.options.skipTests && !await this.runTestLoop()) {
651
+ return false;
652
+ }
653
+ }
654
+ }
655
+ return productionReady;
656
+ }
657
+ async runClaudeCode() {
658
+ const prompt = `Please read the PLUGIN_SPEC.md file in this repository and implement the complete plugin as specified. Create all components, tests, and ensure everything is production-ready with no stubs or incomplete code.`;
659
+ await this.runClaudeCodeWithPrompt(prompt);
660
+ }
661
+ async runClaudeCodeWithContext(context) {
662
+ const prompt = `Please read the PLUGIN_SPEC.md file and fix the following issues:
663
+
664
+ ${context}
665
+
666
+ Make all necessary changes to fix the issues and ensure the plugin builds and all tests pass.`;
667
+ await this.runClaudeCodeWithPrompt(prompt);
668
+ }
669
+ async runClaudeCodeWithPrompt(prompt) {
670
+ process.chdir(this.pluginPath);
671
+ logger.info("\u{1F916} Starting Claude Code execution...");
672
+ logger.info(`\u{1F4C1} Working directory: ${this.pluginPath}`);
673
+ const timeoutPromise = new Promise((_, reject) => {
674
+ setTimeout(() => {
675
+ reject(
676
+ new Error(`Claude Code execution timed out after ${CLAUDE_CODE_TIMEOUT / 1e3} seconds`)
677
+ );
678
+ }, CLAUDE_CODE_TIMEOUT);
679
+ });
680
+ const executePromise = (async () => {
681
+ try {
682
+ const claudeArgs = [
683
+ "--print",
684
+ "--max-turns",
685
+ "30",
686
+ "--verbose",
687
+ "--model",
688
+ "opus",
689
+ "--dangerously-skip-permissions",
690
+ prompt
691
+ ];
692
+ logger.info(`\u{1F680} Executing: claude ${claudeArgs.join(" ")}`);
693
+ this.activeClaudeProcess = execa("claude", claudeArgs, {
694
+ stdio: "inherit",
695
+ cwd: this.pluginPath
696
+ });
697
+ await this.activeClaudeProcess;
698
+ this.activeClaudeProcess = null;
699
+ logger.info("\u2705 Claude Code execution completed successfully");
700
+ } catch (error) {
701
+ this.activeClaudeProcess = null;
702
+ if (error.code === "ENOENT") {
703
+ throw new Error(
704
+ "Claude Code not found! Install with: bun install -g @anthropic-ai/claude-code"
705
+ );
706
+ }
707
+ throw error;
708
+ }
709
+ })();
710
+ try {
711
+ await Promise.race([executePromise, timeoutPromise]);
712
+ } catch (error) {
713
+ if (this.activeClaudeProcess) {
714
+ try {
715
+ this.activeClaudeProcess.kill();
716
+ this.activeClaudeProcess = null;
717
+ logger.warn("\u{1F6D1} Claude Code process terminated due to timeout");
718
+ } catch (killError) {
719
+ logger.error("Failed to kill timed-out process:", killError);
720
+ }
721
+ }
722
+ logger.error("\u274C Claude Code execution failed:", error);
723
+ throw error;
724
+ }
725
+ }
726
+ async runBuild() {
727
+ try {
728
+ logger.info("Installing dependencies with bun...");
729
+ await runBunCommand(["install"], this.pluginPath);
730
+ logger.info("Running build with bun...");
731
+ await runBunCommand(["run", "build"], this.pluginPath);
732
+ return { success: true };
733
+ } catch (error) {
734
+ const errorOutput = (error.stdout || "") + "\n" + (error.stderr || "");
735
+ logger.error("Build failed:", errorOutput);
736
+ return { success: false, errors: errorOutput };
737
+ }
738
+ }
739
+ async getBuildErrors() {
740
+ const result = await this.runBuild();
741
+ return result.errors || "Build failed but no specific errors captured";
742
+ }
743
+ async runTests() {
744
+ try {
745
+ logger.info("Running tests with bun...");
746
+ await runBunCommand(["test"], this.pluginPath);
747
+ return { success: true };
748
+ } catch (error) {
749
+ const errorOutput = (error.stdout || "") + "\n" + (error.stderr || "");
750
+ logger.error("Tests failed:", errorOutput);
751
+ return { success: false, errors: errorOutput };
752
+ }
753
+ }
754
+ async getTestErrors() {
755
+ const result = await this.runTests();
756
+ return result.errors || "Tests failed but no specific errors captured";
757
+ }
758
+ async validateProductionReadiness() {
759
+ const allFiles = await this.getAllPluginFiles();
760
+ const prompt = `You are reviewing a newly generated ElizaOS plugin for production readiness.
761
+
762
+ ## Plugin Files:
763
+ ${allFiles}
764
+
765
+ ## Evaluation Criteria:
766
+
767
+ ### 1. Import Compliance (CRITICAL - MANDATORY)
768
+ - \u2705 ALL imports must come from @elizaos/core ONLY
769
+ - \u274C NO imports from @elizaos/plugin, @elizaos/types, @elizaos/logger, etc. (these don't exist)
770
+ - \u274C NO direct database adapter imports (PgliteDatabaseAdapter, PgDatabaseAdapter)
771
+ - \u2705 Correct import format: import { Plugin, Action, AgentRuntime, logger } from '@elizaos/core'
772
+
773
+ ### 2. Database Compatibility (CRITICAL - MANDATORY)
774
+ - \u2705 Plugin must work with both Pglite and PostgreSQL without code changes
775
+ - \u2705 Uses ONLY runtime.databaseAdapter for database operations
776
+ - \u2705 Uses runtime.createMemory(), runtime.searchMemories(), runtime.createGoal()
777
+ - \u2705 Uses runtime.ensureConnection() for relationships
778
+ - \u274C NO database-specific SQL or queries
779
+ - \u274C NO assumptions about database type
780
+ - \u274C NO direct database adapter usage
781
+ - \u2705 Database compatibility tests for both Pglite and PostgreSQL
782
+
783
+ ### 3. Component Implementation
784
+ - \u2705 All components are fully implemented (no stubs or TODOs)
785
+ - \u2705 Services extend base Service class with lifecycle methods (initialize, start, stop)
786
+ - \u2705 Actions have proper validation and handlers
787
+ - \u2705 Providers return formatted context using runtime APIs
788
+ - \u2705 Evaluators store data using runtime APIs
789
+
790
+ ### 4. Testing Coverage
791
+ - \u2705 Comprehensive tests exist for all functionality
792
+ - \u2705 Tests use bun test framework
793
+ - \u2705 Database compatibility tests included
794
+ - \u2705 Tests cover main plugin functionality
795
+ - \u2705 Error handling tests included
796
+
797
+ ### 5. Code Quality
798
+ - \u2705 Proper error handling throughout
799
+ - \u2705 Follows ElizaOS 1.0.0 patterns and best practices
800
+ - \u2705 Documentation is complete
801
+ - \u2705 Code is clean and well-organized
802
+ - \u2705 Plugin exports are correct
803
+ - \u2705 No stubs or incomplete code remains
804
+
805
+ ## Response Format:
806
+ Respond with a JSON object:
807
+ {
808
+ "production_ready": boolean,
809
+ "revision_instructions": "Detailed instructions for what needs to be fixed (only if not production ready)"
810
+ }
811
+
812
+ ## Validation Priority (ALL MUST PASS):
813
+ 1. Import compliance is MANDATORY - any non-@elizaos/core imports = NOT production ready
814
+ 2. Database compatibility is MANDATORY - must work with both Pglite and PostgreSQL
815
+ 3. All components must be fully implemented
816
+ 4. Comprehensive tests must exist
817
+ 5. All other criteria must also pass
818
+
819
+ If ANY of the CRITICAL requirements fail, the plugin is NOT production ready.`;
820
+ const message = await this.anthropic.messages.create({
821
+ model: "claude-opus-4-20250514",
822
+ max_tokens: 8192,
823
+ temperature: 0,
824
+ messages: [
825
+ {
826
+ role: "user",
827
+ content: prompt
828
+ }
829
+ ]
830
+ });
831
+ try {
832
+ const responseText = message.content.map((block) => block.type === "text" ? block.text : "").join("");
833
+ const jsonMatch = responseText.match(/\{[\s\S]*\}/);
834
+ if (jsonMatch) {
835
+ return JSON.parse(jsonMatch[0]);
836
+ }
837
+ throw new Error("No JSON found in response");
838
+ } catch (error) {
839
+ logger.error("Failed to parse validation response:", error);
840
+ return {
841
+ production_ready: false,
842
+ revision_instructions: "Failed to parse validation response. Please review manually."
843
+ };
844
+ }
845
+ }
846
+ async getAllPluginFiles() {
847
+ let content = "";
848
+ const files = await fs.readdir(this.pluginPath, { recursive: true });
849
+ for (const file of files) {
850
+ if (typeof file !== "string") continue;
851
+ const filePath = path.join(this.pluginPath, file);
852
+ const stat2 = await fs.stat(filePath);
853
+ if (stat2.isFile() && !file.includes("node_modules") && !file.includes(".git")) {
854
+ const ext = path.extname(file);
855
+ if ([".ts", ".js", ".json", ".md"].includes(ext)) {
856
+ const fileContent = await fs.readFile(filePath, "utf-8");
857
+ content += `
858
+ ### File: ${file}
859
+ \`\`\`${ext.slice(1)}
860
+ ${fileContent}
861
+ \`\`\`
862
+ `;
863
+ }
864
+ }
865
+ }
866
+ return content;
867
+ }
868
+ async copyToCWD() {
869
+ const pluginName = path.basename(this.pluginPath);
870
+ const targetPath = path.join(process.cwd(), pluginName);
871
+ if (await fs.pathExists(targetPath)) {
872
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
873
+ const backupPath = `${targetPath}-backup-${timestamp}`;
874
+ logger.info(`Backing up existing ${pluginName} to ${path.basename(backupPath)}`);
875
+ await fs.move(targetPath, backupPath);
876
+ }
877
+ logger.info(`Copying plugin to ${targetPath}`);
878
+ await fs.copy(this.pluginPath, targetPath, {
879
+ filter: (src) => {
880
+ const relativePath = path.relative(this.pluginPath, src);
881
+ return !relativePath.includes(".git") && !relativePath.includes("node_modules");
882
+ }
883
+ });
884
+ return targetPath;
885
+ }
886
+ async checkDiskSpace() {
887
+ const diskSpace = await this.getAvailableDiskSpace();
888
+ if (diskSpace < MIN_DISK_SPACE_GB) {
889
+ throw new Error(
890
+ `Insufficient disk space. Need at least ${MIN_DISK_SPACE_GB}GB free, but only ${diskSpace.toFixed(2)}GB available.`
891
+ );
892
+ }
893
+ }
894
+ async getAvailableDiskSpace() {
895
+ try {
896
+ const result = await execa("df", ["-k", os.tmpdir()]);
897
+ const lines = result.stdout.split("\n");
898
+ const dataLine = lines[1];
899
+ const parts = dataLine.split(/\s+/);
900
+ const availableKB = parseInt(parts[3]);
901
+ return availableKB / 1024 / 1024;
902
+ } catch (error) {
903
+ logger.warn("Could not check disk space, proceeding anyway");
904
+ return MIN_DISK_SPACE_GB + 1;
905
+ }
906
+ }
907
+ };
908
+ export {
909
+ PluginCreator
910
+ };