@jungjaehoon/mama-os 0.1.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 (356) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/README.md +643 -0
  3. package/dist/agent/agent-loop.d.ts +98 -0
  4. package/dist/agent/agent-loop.d.ts.map +1 -0
  5. package/dist/agent/agent-loop.js +417 -0
  6. package/dist/agent/agent-loop.js.map +1 -0
  7. package/dist/agent/auto-recall.d.ts +48 -0
  8. package/dist/agent/auto-recall.d.ts.map +1 -0
  9. package/dist/agent/auto-recall.js +178 -0
  10. package/dist/agent/auto-recall.js.map +1 -0
  11. package/dist/agent/claude-cli-wrapper.d.ts +130 -0
  12. package/dist/agent/claude-cli-wrapper.d.ts.map +1 -0
  13. package/dist/agent/claude-cli-wrapper.js +227 -0
  14. package/dist/agent/claude-cli-wrapper.js.map +1 -0
  15. package/dist/agent/claude-client.d.ts +50 -0
  16. package/dist/agent/claude-client.d.ts.map +1 -0
  17. package/dist/agent/claude-client.js +214 -0
  18. package/dist/agent/claude-client.js.map +1 -0
  19. package/dist/agent/gateway-tool-executor.d.ts +75 -0
  20. package/dist/agent/gateway-tool-executor.d.ts.map +1 -0
  21. package/dist/agent/gateway-tool-executor.js +348 -0
  22. package/dist/agent/gateway-tool-executor.js.map +1 -0
  23. package/dist/agent/index.d.ts +13 -0
  24. package/dist/agent/index.d.ts.map +1 -0
  25. package/dist/agent/index.js +18 -0
  26. package/dist/agent/index.js.map +1 -0
  27. package/dist/agent/mcp-executor.d.ts +75 -0
  28. package/dist/agent/mcp-executor.d.ts.map +1 -0
  29. package/dist/agent/mcp-executor.js +307 -0
  30. package/dist/agent/mcp-executor.js.map +1 -0
  31. package/dist/agent/session-pool.d.ts +148 -0
  32. package/dist/agent/session-pool.d.ts.map +1 -0
  33. package/dist/agent/session-pool.js +272 -0
  34. package/dist/agent/session-pool.js.map +1 -0
  35. package/dist/agent/streaming-callback-manager.d.ts +85 -0
  36. package/dist/agent/streaming-callback-manager.d.ts.map +1 -0
  37. package/dist/agent/streaming-callback-manager.js +103 -0
  38. package/dist/agent/streaming-callback-manager.js.map +1 -0
  39. package/dist/agent/types.d.ts +437 -0
  40. package/dist/agent/types.d.ts.map +1 -0
  41. package/dist/agent/types.js +29 -0
  42. package/dist/agent/types.js.map +1 -0
  43. package/dist/api/cron-handler.d.ts +44 -0
  44. package/dist/api/cron-handler.d.ts.map +1 -0
  45. package/dist/api/cron-handler.js +195 -0
  46. package/dist/api/cron-handler.js.map +1 -0
  47. package/dist/api/error-handler.d.ts +22 -0
  48. package/dist/api/error-handler.d.ts.map +1 -0
  49. package/dist/api/error-handler.js +104 -0
  50. package/dist/api/error-handler.js.map +1 -0
  51. package/dist/api/heartbeat-handler.d.ts +49 -0
  52. package/dist/api/heartbeat-handler.d.ts.map +1 -0
  53. package/dist/api/heartbeat-handler.js +91 -0
  54. package/dist/api/heartbeat-handler.js.map +1 -0
  55. package/dist/api/index.d.ts +61 -0
  56. package/dist/api/index.d.ts.map +1 -0
  57. package/dist/api/index.js +145 -0
  58. package/dist/api/index.js.map +1 -0
  59. package/dist/api/types.d.ts +156 -0
  60. package/dist/api/types.d.ts.map +1 -0
  61. package/dist/api/types.js +62 -0
  62. package/dist/api/types.js.map +1 -0
  63. package/dist/auth/index.d.ts +7 -0
  64. package/dist/auth/index.d.ts.map +1 -0
  65. package/dist/auth/index.js +11 -0
  66. package/dist/auth/index.js.map +1 -0
  67. package/dist/auth/oauth-manager.d.ts +59 -0
  68. package/dist/auth/oauth-manager.d.ts.map +1 -0
  69. package/dist/auth/oauth-manager.js +237 -0
  70. package/dist/auth/oauth-manager.js.map +1 -0
  71. package/dist/auth/types.d.ts +92 -0
  72. package/dist/auth/types.d.ts.map +1 -0
  73. package/dist/auth/types.js +23 -0
  74. package/dist/auth/types.js.map +1 -0
  75. package/dist/cli/commands/init.d.ts +19 -0
  76. package/dist/cli/commands/init.d.ts.map +1 -0
  77. package/dist/cli/commands/init.js +155 -0
  78. package/dist/cli/commands/init.js.map +1 -0
  79. package/dist/cli/commands/run.d.ts +19 -0
  80. package/dist/cli/commands/run.d.ts.map +1 -0
  81. package/dist/cli/commands/run.js +89 -0
  82. package/dist/cli/commands/run.js.map +1 -0
  83. package/dist/cli/commands/setup.d.ts +19 -0
  84. package/dist/cli/commands/setup.d.ts.map +1 -0
  85. package/dist/cli/commands/setup.js +134 -0
  86. package/dist/cli/commands/setup.js.map +1 -0
  87. package/dist/cli/commands/start.d.ts +24 -0
  88. package/dist/cli/commands/start.d.ts.map +1 -0
  89. package/dist/cli/commands/start.js +1073 -0
  90. package/dist/cli/commands/start.js.map +1 -0
  91. package/dist/cli/commands/status.d.ts +10 -0
  92. package/dist/cli/commands/status.d.ts.map +1 -0
  93. package/dist/cli/commands/status.js +85 -0
  94. package/dist/cli/commands/status.js.map +1 -0
  95. package/dist/cli/commands/stop.d.ts +10 -0
  96. package/dist/cli/commands/stop.d.ts.map +1 -0
  97. package/dist/cli/commands/stop.js +65 -0
  98. package/dist/cli/commands/stop.js.map +1 -0
  99. package/dist/cli/config/config-manager.d.ts +51 -0
  100. package/dist/cli/config/config-manager.d.ts.map +1 -0
  101. package/dist/cli/config/config-manager.js +216 -0
  102. package/dist/cli/config/config-manager.js.map +1 -0
  103. package/dist/cli/config/types.d.ts +172 -0
  104. package/dist/cli/config/types.d.ts.map +1 -0
  105. package/dist/cli/config/types.js +48 -0
  106. package/dist/cli/config/types.js.map +1 -0
  107. package/dist/cli/index.d.ts +8 -0
  108. package/dist/cli/index.d.ts.map +1 -0
  109. package/dist/cli/index.js +92 -0
  110. package/dist/cli/index.js.map +1 -0
  111. package/dist/cli/utils/pid-manager.d.ts +66 -0
  112. package/dist/cli/utils/pid-manager.d.ts.map +1 -0
  113. package/dist/cli/utils/pid-manager.js +167 -0
  114. package/dist/cli/utils/pid-manager.js.map +1 -0
  115. package/dist/concurrency/index.d.ts +13 -0
  116. package/dist/concurrency/index.d.ts.map +1 -0
  117. package/dist/concurrency/index.js +22 -0
  118. package/dist/concurrency/index.js.map +1 -0
  119. package/dist/concurrency/lane-manager.d.ts +113 -0
  120. package/dist/concurrency/lane-manager.d.ts.map +1 -0
  121. package/dist/concurrency/lane-manager.js +245 -0
  122. package/dist/concurrency/lane-manager.js.map +1 -0
  123. package/dist/concurrency/session-key.d.ts +41 -0
  124. package/dist/concurrency/session-key.d.ts.map +1 -0
  125. package/dist/concurrency/session-key.js +61 -0
  126. package/dist/concurrency/session-key.js.map +1 -0
  127. package/dist/concurrency/types.d.ts +69 -0
  128. package/dist/concurrency/types.d.ts.map +1 -0
  129. package/dist/concurrency/types.js +16 -0
  130. package/dist/concurrency/types.js.map +1 -0
  131. package/dist/gateways/channel-history.d.ts +102 -0
  132. package/dist/gateways/channel-history.d.ts.map +1 -0
  133. package/dist/gateways/channel-history.js +181 -0
  134. package/dist/gateways/channel-history.js.map +1 -0
  135. package/dist/gateways/context-injector.d.ts +74 -0
  136. package/dist/gateways/context-injector.d.ts.map +1 -0
  137. package/dist/gateways/context-injector.js +121 -0
  138. package/dist/gateways/context-injector.js.map +1 -0
  139. package/dist/gateways/discord.d.ts +122 -0
  140. package/dist/gateways/discord.d.ts.map +1 -0
  141. package/dist/gateways/discord.js +602 -0
  142. package/dist/gateways/discord.js.map +1 -0
  143. package/dist/gateways/index.d.ts +30 -0
  144. package/dist/gateways/index.d.ts.map +1 -0
  145. package/dist/gateways/index.js +49 -0
  146. package/dist/gateways/index.js.map +1 -0
  147. package/dist/gateways/message-router.d.ts +116 -0
  148. package/dist/gateways/message-router.d.ts.map +1 -0
  149. package/dist/gateways/message-router.js +315 -0
  150. package/dist/gateways/message-router.js.map +1 -0
  151. package/dist/gateways/message-splitter.d.ts +54 -0
  152. package/dist/gateways/message-splitter.d.ts.map +1 -0
  153. package/dist/gateways/message-splitter.js +146 -0
  154. package/dist/gateways/message-splitter.js.map +1 -0
  155. package/dist/gateways/plugin-loader.d.ts +76 -0
  156. package/dist/gateways/plugin-loader.d.ts.map +1 -0
  157. package/dist/gateways/plugin-loader.js +221 -0
  158. package/dist/gateways/plugin-loader.js.map +1 -0
  159. package/dist/gateways/session-store.d.ts +77 -0
  160. package/dist/gateways/session-store.d.ts.map +1 -0
  161. package/dist/gateways/session-store.js +233 -0
  162. package/dist/gateways/session-store.js.map +1 -0
  163. package/dist/gateways/slack.d.ts +90 -0
  164. package/dist/gateways/slack.d.ts.map +1 -0
  165. package/dist/gateways/slack.js +281 -0
  166. package/dist/gateways/slack.js.map +1 -0
  167. package/dist/gateways/telegram.d.ts +79 -0
  168. package/dist/gateways/telegram.d.ts.map +1 -0
  169. package/dist/gateways/telegram.js +207 -0
  170. package/dist/gateways/telegram.js.map +1 -0
  171. package/dist/gateways/types.d.ts +340 -0
  172. package/dist/gateways/types.d.ts.map +1 -0
  173. package/dist/gateways/types.js +6 -0
  174. package/dist/gateways/types.js.map +1 -0
  175. package/dist/index.d.ts +7 -0
  176. package/dist/index.d.ts.map +1 -0
  177. package/dist/index.js +26 -0
  178. package/dist/index.js.map +1 -0
  179. package/dist/memory/memory-logger.d.ts +47 -0
  180. package/dist/memory/memory-logger.d.ts.map +1 -0
  181. package/dist/memory/memory-logger.js +126 -0
  182. package/dist/memory/memory-logger.js.map +1 -0
  183. package/dist/onboarding/all-tools.d.ts +18 -0
  184. package/dist/onboarding/all-tools.d.ts.map +1 -0
  185. package/dist/onboarding/all-tools.js +149 -0
  186. package/dist/onboarding/all-tools.js.map +1 -0
  187. package/dist/onboarding/autonomous-discovery-tools.d.ts +13 -0
  188. package/dist/onboarding/autonomous-discovery-tools.d.ts.map +1 -0
  189. package/dist/onboarding/autonomous-discovery-tools.js +268 -0
  190. package/dist/onboarding/autonomous-discovery-tools.js.map +1 -0
  191. package/dist/onboarding/bootstrap-template.d.ts +5 -0
  192. package/dist/onboarding/bootstrap-template.d.ts.map +1 -0
  193. package/dist/onboarding/bootstrap-template.js +142 -0
  194. package/dist/onboarding/bootstrap-template.js.map +1 -0
  195. package/dist/onboarding/complete-autonomous-prompt.d.ts +13 -0
  196. package/dist/onboarding/complete-autonomous-prompt.d.ts.map +1 -0
  197. package/dist/onboarding/complete-autonomous-prompt.js +1220 -0
  198. package/dist/onboarding/complete-autonomous-prompt.js.map +1 -0
  199. package/dist/onboarding/onboarding-state.d.ts +70 -0
  200. package/dist/onboarding/onboarding-state.d.ts.map +1 -0
  201. package/dist/onboarding/onboarding-state.js +184 -0
  202. package/dist/onboarding/onboarding-state.js.map +1 -0
  203. package/dist/onboarding/personality-quiz.d.ts +35 -0
  204. package/dist/onboarding/personality-quiz.d.ts.map +1 -0
  205. package/dist/onboarding/personality-quiz.js +219 -0
  206. package/dist/onboarding/personality-quiz.js.map +1 -0
  207. package/dist/onboarding/phase-5-summary.d.ts +22 -0
  208. package/dist/onboarding/phase-5-summary.d.ts.map +1 -0
  209. package/dist/onboarding/phase-5-summary.js +151 -0
  210. package/dist/onboarding/phase-5-summary.js.map +1 -0
  211. package/dist/onboarding/phase-6-security.d.ts +33 -0
  212. package/dist/onboarding/phase-6-security.d.ts.map +1 -0
  213. package/dist/onboarding/phase-6-security.js +473 -0
  214. package/dist/onboarding/phase-6-security.js.map +1 -0
  215. package/dist/onboarding/phase-7-integrations.d.ts +66 -0
  216. package/dist/onboarding/phase-7-integrations.d.ts.map +1 -0
  217. package/dist/onboarding/phase-7-integrations.js +619 -0
  218. package/dist/onboarding/phase-7-integrations.js.map +1 -0
  219. package/dist/onboarding/phase-8-demo.d.ts +43 -0
  220. package/dist/onboarding/phase-8-demo.d.ts.map +1 -0
  221. package/dist/onboarding/phase-8-demo.js +346 -0
  222. package/dist/onboarding/phase-8-demo.js.map +1 -0
  223. package/dist/onboarding/phase-9-finalization.d.ts +22 -0
  224. package/dist/onboarding/phase-9-finalization.d.ts.map +1 -0
  225. package/dist/onboarding/phase-9-finalization.js +375 -0
  226. package/dist/onboarding/phase-9-finalization.js.map +1 -0
  227. package/dist/onboarding/ritual-prompt.d.ts +2 -0
  228. package/dist/onboarding/ritual-prompt.d.ts.map +1 -0
  229. package/dist/onboarding/ritual-prompt.js +285 -0
  230. package/dist/onboarding/ritual-prompt.js.map +1 -0
  231. package/dist/onboarding/ritual-tools.d.ts +13 -0
  232. package/dist/onboarding/ritual-tools.d.ts.map +1 -0
  233. package/dist/onboarding/ritual-tools.js +93 -0
  234. package/dist/onboarding/ritual-tools.js.map +1 -0
  235. package/dist/runners/cli-runner.d.ts +59 -0
  236. package/dist/runners/cli-runner.d.ts.map +1 -0
  237. package/dist/runners/cli-runner.js +190 -0
  238. package/dist/runners/cli-runner.js.map +1 -0
  239. package/dist/runners/index.d.ts +11 -0
  240. package/dist/runners/index.d.ts.map +1 -0
  241. package/dist/runners/index.js +15 -0
  242. package/dist/runners/index.js.map +1 -0
  243. package/dist/runners/types.d.ts +81 -0
  244. package/dist/runners/types.d.ts.map +1 -0
  245. package/dist/runners/types.js +31 -0
  246. package/dist/runners/types.js.map +1 -0
  247. package/dist/scheduler/cron-scheduler.d.ts +115 -0
  248. package/dist/scheduler/cron-scheduler.d.ts.map +1 -0
  249. package/dist/scheduler/cron-scheduler.js +320 -0
  250. package/dist/scheduler/cron-scheduler.js.map +1 -0
  251. package/dist/scheduler/heartbeat.d.ts +53 -0
  252. package/dist/scheduler/heartbeat.d.ts.map +1 -0
  253. package/dist/scheduler/heartbeat.js +160 -0
  254. package/dist/scheduler/heartbeat.js.map +1 -0
  255. package/dist/scheduler/index.d.ts +22 -0
  256. package/dist/scheduler/index.d.ts.map +1 -0
  257. package/dist/scheduler/index.js +31 -0
  258. package/dist/scheduler/index.js.map +1 -0
  259. package/dist/scheduler/job-lock.d.ts +85 -0
  260. package/dist/scheduler/job-lock.d.ts.map +1 -0
  261. package/dist/scheduler/job-lock.js +137 -0
  262. package/dist/scheduler/job-lock.js.map +1 -0
  263. package/dist/scheduler/recovery.d.ts +78 -0
  264. package/dist/scheduler/recovery.d.ts.map +1 -0
  265. package/dist/scheduler/recovery.js +124 -0
  266. package/dist/scheduler/recovery.js.map +1 -0
  267. package/dist/scheduler/schedule-store.d.ts +112 -0
  268. package/dist/scheduler/schedule-store.d.ts.map +1 -0
  269. package/dist/scheduler/schedule-store.js +259 -0
  270. package/dist/scheduler/schedule-store.js.map +1 -0
  271. package/dist/scheduler/token-keep-alive.d.ts +49 -0
  272. package/dist/scheduler/token-keep-alive.d.ts.map +1 -0
  273. package/dist/scheduler/token-keep-alive.js +102 -0
  274. package/dist/scheduler/token-keep-alive.js.map +1 -0
  275. package/dist/scheduler/types.d.ts +96 -0
  276. package/dist/scheduler/types.d.ts.map +1 -0
  277. package/dist/scheduler/types.js +21 -0
  278. package/dist/scheduler/types.js.map +1 -0
  279. package/dist/setup/setup-prompt.d.ts +2 -0
  280. package/dist/setup/setup-prompt.d.ts.map +1 -0
  281. package/dist/setup/setup-prompt.js +138 -0
  282. package/dist/setup/setup-prompt.js.map +1 -0
  283. package/dist/setup/setup-server.d.ts +8 -0
  284. package/dist/setup/setup-server.d.ts.map +1 -0
  285. package/dist/setup/setup-server.js +71 -0
  286. package/dist/setup/setup-server.js.map +1 -0
  287. package/dist/setup/setup-tools.d.ts +13 -0
  288. package/dist/setup/setup-tools.d.ts.map +1 -0
  289. package/dist/setup/setup-tools.js +103 -0
  290. package/dist/setup/setup-tools.js.map +1 -0
  291. package/dist/setup/setup-websocket.d.ts +6 -0
  292. package/dist/setup/setup-websocket.d.ts.map +1 -0
  293. package/dist/setup/setup-websocket.js +312 -0
  294. package/dist/setup/setup-websocket.js.map +1 -0
  295. package/dist/skills/index.d.ts +10 -0
  296. package/dist/skills/index.d.ts.map +1 -0
  297. package/dist/skills/index.js +26 -0
  298. package/dist/skills/index.js.map +1 -0
  299. package/dist/skills/skill-executor.d.ts +48 -0
  300. package/dist/skills/skill-executor.d.ts.map +1 -0
  301. package/dist/skills/skill-executor.js +483 -0
  302. package/dist/skills/skill-executor.js.map +1 -0
  303. package/dist/skills/skill-loader.d.ts +40 -0
  304. package/dist/skills/skill-loader.d.ts.map +1 -0
  305. package/dist/skills/skill-loader.js +225 -0
  306. package/dist/skills/skill-loader.js.map +1 -0
  307. package/dist/skills/skill-matcher.d.ts +33 -0
  308. package/dist/skills/skill-matcher.d.ts.map +1 -0
  309. package/dist/skills/skill-matcher.js +190 -0
  310. package/dist/skills/skill-matcher.js.map +1 -0
  311. package/dist/skills/types.d.ts +123 -0
  312. package/dist/skills/types.d.ts.map +1 -0
  313. package/dist/skills/types.js +12 -0
  314. package/dist/skills/types.js.map +1 -0
  315. package/dist/tools/browser-tool.d.ts +149 -0
  316. package/dist/tools/browser-tool.d.ts.map +1 -0
  317. package/dist/tools/browser-tool.js +257 -0
  318. package/dist/tools/browser-tool.js.map +1 -0
  319. package/package.json +84 -0
  320. package/public/favicon.ico +0 -0
  321. package/public/setup.html +1026 -0
  322. package/public/viewer/icons/icon-192.png +0 -0
  323. package/public/viewer/icons/icon-512.png +0 -0
  324. package/public/viewer/js/modules/chat.js +1587 -0
  325. package/public/viewer/js/modules/dashboard.js +275 -0
  326. package/public/viewer/js/modules/graph.js +997 -0
  327. package/public/viewer/js/modules/memory.js +353 -0
  328. package/public/viewer/js/modules/settings.js +255 -0
  329. package/public/viewer/js/utils/api.js +169 -0
  330. package/public/viewer/js/utils/dom.js +92 -0
  331. package/public/viewer/js/utils/format.js +192 -0
  332. package/public/viewer/manifest.json +26 -0
  333. package/public/viewer/sw.js +131 -0
  334. package/public/viewer/viewer.css +500 -0
  335. package/public/viewer/viewer.html +1535 -0
  336. package/scripts/postinstall.js +118 -0
  337. package/templates/skills/document-analyze.md +63 -0
  338. package/templates/skills/heartbeat-report.md +75 -0
  339. package/templates/skills/image-translate.md +67 -0
  340. package/templates/workspace/skill-forge/DESIGN.md +115 -0
  341. package/templates/workspace/skill-forge/agents/architect.ts +295 -0
  342. package/templates/workspace/skill-forge/agents/developer.ts +364 -0
  343. package/templates/workspace/skill-forge/agents/qa.ts +313 -0
  344. package/templates/workspace/skill-forge/claude-api.ts +353 -0
  345. package/templates/workspace/skill-forge/discord-ui.ts +580 -0
  346. package/templates/workspace/skill-forge/error-handler.ts +354 -0
  347. package/templates/workspace/skill-forge/mama-integration.ts +357 -0
  348. package/templates/workspace/skill-forge/orchestrator.ts +495 -0
  349. package/templates/workspace/skill-forge/output/generated-skills/skills/hello-world/README.md +24 -0
  350. package/templates/workspace/skill-forge/output/generated-skills/skills/hello-world/index.ts +79 -0
  351. package/templates/workspace/skill-forge/output/generated-skills/skills/hello-world/types.ts +17 -0
  352. package/templates/workspace/skill-forge/package.json +21 -0
  353. package/templates/workspace/skill-forge/state/session.json +132 -0
  354. package/templates/workspace/skill-forge/test-e2e.ts +139 -0
  355. package/templates/workspace/skill-forge/tsconfig.json +20 -0
  356. package/templates/workspace/skill-forge/types.ts +159 -0
@@ -0,0 +1,495 @@
1
+ /**
2
+ * Skill Forge - Orchestrator
3
+ *
4
+ * 멀티 에이전트 조율: Architect → Developer → QA
5
+ * 각 단계 사이 5초 카운트다운으로 유저 검토 기회 제공
6
+ */
7
+
8
+ import {
9
+ SessionState,
10
+ SessionPhase,
11
+ SkillRequest,
12
+ OrchestratorEvent,
13
+ DiscordAction,
14
+ SkillForgeConfig,
15
+ DEFAULT_CONFIG,
16
+ ArchitectOutput,
17
+ DeveloperOutput,
18
+ QAOutput,
19
+ } from './types';
20
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
21
+ import { dirname } from 'path';
22
+ import { randomUUID } from 'crypto';
23
+ import { createArchitectAgent } from './agents/architect';
24
+ import { createDeveloperAgent } from './agents/developer';
25
+ import { createQAAgent } from './agents/qa';
26
+ import { ErrorHandler, createError, SkillForgeError, rollbackStrategy } from './error-handler';
27
+ import { createMockMAMAIntegration, MAMAIntegration } from './mama-integration';
28
+
29
+ export class Orchestrator {
30
+ private state: SessionState | null = null;
31
+ private config: SkillForgeConfig;
32
+ private eventHandlers: ((event: OrchestratorEvent) => void)[] = [];
33
+ private countdownTimer: NodeJS.Timeout | null = null;
34
+ private errorHandler: ErrorHandler;
35
+ private mama: MAMAIntegration;
36
+
37
+ constructor(config: Partial<SkillForgeConfig> = {}) {
38
+ this.config = { ...DEFAULT_CONFIG, ...config };
39
+ this.errorHandler = new ErrorHandler({
40
+ maxRetries: 3,
41
+ retryDelayMs: 1000,
42
+ onError: (err) => this.emit({ type: 'ERROR', error: err.userMessage }),
43
+ });
44
+ this.mama = createMockMAMAIntegration();
45
+ }
46
+
47
+ // ===== Event System =====
48
+
49
+ onEvent(handler: (event: OrchestratorEvent) => void): void {
50
+ this.eventHandlers.push(handler);
51
+ }
52
+
53
+ private emit(event: OrchestratorEvent): void {
54
+ for (const handler of this.eventHandlers) {
55
+ try {
56
+ handler(event);
57
+ } catch (error) {
58
+ console.error('[Orchestrator] Event handler error:', error);
59
+ }
60
+ }
61
+ }
62
+
63
+ // ===== Session Management =====
64
+
65
+ async startSession(request: SkillRequest): Promise<SessionState> {
66
+ this.state = {
67
+ id: randomUUID(),
68
+ phase: 'idle',
69
+ request,
70
+ artifacts: {},
71
+ countdown: null,
72
+ createdAt: new Date().toISOString(),
73
+ updatedAt: new Date().toISOString(),
74
+ };
75
+
76
+ this.emit({ type: 'REQUEST_RECEIVED', request });
77
+ this.saveState();
78
+
79
+ await this.transitionTo('architect');
80
+ return this.state;
81
+ }
82
+
83
+ getState(): SessionState | null {
84
+ return this.state;
85
+ }
86
+
87
+ // ===== Phase Transitions =====
88
+
89
+ private async transitionTo(phase: SessionPhase): Promise<void> {
90
+ if (!this.state) {
91
+ throw new Error('No active session');
92
+ }
93
+
94
+ this.state.phase = phase;
95
+ this.state.updatedAt = new Date().toISOString();
96
+ this.saveState();
97
+
98
+ switch (phase) {
99
+ case 'architect':
100
+ await this.runArchitect();
101
+ break;
102
+ case 'architect_review':
103
+ this.startCountdown('architect_review');
104
+ break;
105
+ case 'developer':
106
+ await this.runDeveloper();
107
+ break;
108
+ case 'developer_review':
109
+ this.startCountdown('developer_review');
110
+ break;
111
+ case 'qa':
112
+ await this.runQA();
113
+ break;
114
+ case 'qa_review':
115
+ this.startCountdown('qa_review');
116
+ break;
117
+ case 'completed':
118
+ this.emit({ type: 'SESSION_COMPLETE', success: true });
119
+ await this.saveGeneratedFiles();
120
+ // MAMA 연동: decision 저장
121
+ await this.saveToMAMA();
122
+ break;
123
+ case 'cancelled':
124
+ this.emit({ type: 'SESSION_COMPLETE', success: false });
125
+ break;
126
+ }
127
+ }
128
+
129
+ // ===== Agent Execution =====
130
+
131
+ private async runArchitect(): Promise<void> {
132
+ this.emit({ type: 'AGENT_START', agent: 'architect' });
133
+
134
+ try {
135
+ const output = await this.errorHandler.handle(
136
+ 'architect',
137
+ async () => {
138
+ const architect = createArchitectAgent();
139
+ return architect.design(this.state!.request);
140
+ },
141
+ { phase: 'architect' }
142
+ );
143
+
144
+ this.state!.artifacts.architectOutput = output;
145
+ this.emit({ type: 'AGENT_COMPLETE', agent: 'architect', output });
146
+
147
+ await this.transitionTo('architect_review');
148
+ } catch (error) {
149
+ await this.handleAgentError(error as SkillForgeError, 'architect');
150
+ }
151
+ }
152
+
153
+ private async runDeveloper(): Promise<void> {
154
+ this.emit({ type: 'AGENT_START', agent: 'developer' });
155
+
156
+ try {
157
+ const architectOutput = this.state!.artifacts.architectOutput;
158
+ if (!architectOutput) {
159
+ throw createError('STATE_ERROR', 'Architect output not found', { phase: 'developer' });
160
+ }
161
+
162
+ const output = await this.errorHandler.handle(
163
+ 'developer',
164
+ async () => {
165
+ const developer = createDeveloperAgent();
166
+ return developer.develop(architectOutput, this.state!.request);
167
+ },
168
+ { phase: 'developer' }
169
+ );
170
+
171
+ this.state!.artifacts.developerOutput = output;
172
+ this.emit({ type: 'AGENT_COMPLETE', agent: 'developer', output });
173
+
174
+ await this.transitionTo('developer_review');
175
+ } catch (error) {
176
+ await this.handleAgentError(error as SkillForgeError, 'developer');
177
+ }
178
+ }
179
+
180
+ private async runQA(): Promise<void> {
181
+ this.emit({ type: 'AGENT_START', agent: 'qa' });
182
+
183
+ try {
184
+ const architectOutput = this.state!.artifacts.architectOutput;
185
+ const developerOutput = this.state!.artifacts.developerOutput;
186
+
187
+ if (!architectOutput || !developerOutput) {
188
+ throw createError('STATE_ERROR', 'Previous outputs not found', { phase: 'qa' });
189
+ }
190
+
191
+ const output = await this.errorHandler.handle(
192
+ 'qa',
193
+ async () => {
194
+ const qa = createQAAgent();
195
+ return qa.verify(developerOutput, architectOutput);
196
+ },
197
+ { phase: 'qa' }
198
+ );
199
+
200
+ this.state!.artifacts.qaOutput = output;
201
+ this.emit({ type: 'AGENT_COMPLETE', agent: 'qa', output });
202
+
203
+ await this.transitionTo('qa_review');
204
+ } catch (error) {
205
+ await this.handleAgentError(error as SkillForgeError, 'qa');
206
+ }
207
+ }
208
+
209
+ // ===== Error Recovery =====
210
+
211
+ private async handleAgentError(error: SkillForgeError, agent: string): Promise<void> {
212
+ console.error(`[Orchestrator] ${agent} failed:`, error.message);
213
+
214
+ // Try recovery
215
+ if (rollbackStrategy.canRecover(error, this.state!)) {
216
+ this.state = rollbackStrategy.recover(error, this.state!);
217
+ this.saveState();
218
+ this.emit({ type: 'ERROR', error: `${error.userMessage} (롤백됨)` });
219
+ } else {
220
+ // Cannot recover - cancel session
221
+ await this.transitionTo('cancelled');
222
+ }
223
+ }
224
+
225
+ // ===== MAMA Integration =====
226
+
227
+ private async saveToMAMA(): Promise<void> {
228
+ if (!this.state) return;
229
+
230
+ try {
231
+ await this.mama.saveDecision(this.state);
232
+ console.log('[Orchestrator] Saved decision to MAMA');
233
+ } catch (error) {
234
+ console.error('[Orchestrator] Failed to save to MAMA:', error);
235
+ // Non-critical - don't fail the session
236
+ }
237
+ }
238
+
239
+ // ===== File Generation =====
240
+
241
+ private async saveGeneratedFiles(): Promise<void> {
242
+ const developerOutput = this.state?.artifacts.developerOutput;
243
+ if (!developerOutput || !developerOutput.files) return;
244
+
245
+ const outputDir = this.config.outputDir.replace('~', process.env.HOME || '');
246
+
247
+ for (const file of developerOutput.files) {
248
+ const fullPath = `${outputDir}/${file.path}`;
249
+ const dir = dirname(fullPath);
250
+
251
+ // 디렉토리 생성
252
+ if (!existsSync(dir)) {
253
+ mkdirSync(dir, { recursive: true });
254
+ }
255
+
256
+ writeFileSync(fullPath, file.content);
257
+ console.log(`[Orchestrator] Saved: ${fullPath}`);
258
+ }
259
+ }
260
+
261
+ // ===== Countdown System =====
262
+
263
+ private startCountdown(phase: SessionPhase): void {
264
+ this.emit({ type: 'COUNTDOWN_START', phase });
265
+
266
+ this.state!.countdown = {
267
+ startedAt: new Date().toISOString(),
268
+ durationMs: this.config.countdownMs,
269
+ };
270
+ this.saveState();
271
+
272
+ this.countdownTimer = setTimeout(() => {
273
+ this.onCountdownExpire();
274
+ }, this.config.countdownMs);
275
+ }
276
+
277
+ private stopCountdown(): void {
278
+ if (this.countdownTimer) {
279
+ clearTimeout(this.countdownTimer);
280
+ this.countdownTimer = null;
281
+ }
282
+ if (this.state) {
283
+ this.state.countdown = null;
284
+ }
285
+ }
286
+
287
+ private async onCountdownExpire(): Promise<void> {
288
+ this.emit({ type: 'COUNTDOWN_EXPIRE' });
289
+ this.stopCountdown();
290
+
291
+ const nextPhase = this.getNextPhase();
292
+ if (nextPhase) {
293
+ await this.transitionTo(nextPhase);
294
+ }
295
+ }
296
+
297
+ private getNextPhase(): SessionPhase | null {
298
+ if (!this.state) return null;
299
+
300
+ const transitions: Partial<Record<SessionPhase, SessionPhase>> = {
301
+ architect_review: 'developer',
302
+ developer_review: 'qa',
303
+ qa_review: 'completed',
304
+ };
305
+
306
+ return transitions[this.state.phase] || null;
307
+ }
308
+
309
+ // ===== User Actions =====
310
+
311
+ async handleUserAction(action: DiscordAction): Promise<void> {
312
+ if (!this.state) {
313
+ throw new Error('No active session');
314
+ }
315
+
316
+ this.emit({ type: 'USER_ACTION', action });
317
+ this.stopCountdown();
318
+
319
+ switch (action.type) {
320
+ case 'approve':
321
+ const nextPhase = this.getNextPhase();
322
+ if (nextPhase) {
323
+ await this.transitionTo(nextPhase);
324
+ }
325
+ break;
326
+
327
+ case 'revise':
328
+ await this.retryCurrentPhase();
329
+ break;
330
+
331
+ case 'cancel':
332
+ await this.transitionTo('cancelled');
333
+ break;
334
+
335
+ case 'extend':
336
+ this.startCountdown(this.state.phase);
337
+ break;
338
+ }
339
+ }
340
+
341
+ private async retryCurrentPhase(): Promise<void> {
342
+ if (!this.state) return;
343
+
344
+ const retryMap: Partial<Record<SessionPhase, SessionPhase>> = {
345
+ architect_review: 'architect',
346
+ developer_review: 'developer',
347
+ qa_review: 'qa',
348
+ };
349
+
350
+ const retryPhase = retryMap[this.state.phase];
351
+ if (retryPhase) {
352
+ await this.transitionTo(retryPhase);
353
+ }
354
+ }
355
+
356
+ // ===== State Persistence =====
357
+
358
+ private saveState(): void {
359
+ if (!this.state) return;
360
+
361
+ const statePath = this.config.stateFile.replace('~', process.env.HOME || '');
362
+ const dir = dirname(statePath);
363
+
364
+ if (!existsSync(dir)) {
365
+ mkdirSync(dir, { recursive: true });
366
+ }
367
+
368
+ writeFileSync(statePath, JSON.stringify(this.state, null, 2));
369
+ }
370
+
371
+ loadState(): SessionState | null {
372
+ const statePath = this.config.stateFile.replace('~', process.env.HOME || '');
373
+
374
+ if (!existsSync(statePath)) {
375
+ return null;
376
+ }
377
+
378
+ try {
379
+ const data = readFileSync(statePath, 'utf-8');
380
+ this.state = JSON.parse(data);
381
+ return this.state;
382
+ } catch {
383
+ return null;
384
+ }
385
+ }
386
+
387
+ // ===== Debug / Info =====
388
+
389
+ getPhaseDescription(phase: SessionPhase): string {
390
+ const descriptions: Record<SessionPhase, string> = {
391
+ idle: '⏸️ 대기 중',
392
+ architect: '🏗️ Architect가 구조를 설계 중...',
393
+ architect_review: '👀 구조 검토 중 (5초 카운트다운)',
394
+ developer: '💻 Developer가 코드 작성 중...',
395
+ developer_review: '👀 코드 검토 중 (5초 카운트다운)',
396
+ qa: '🔍 QA가 검증 중...',
397
+ qa_review: '👀 검증 결과 검토 중 (5초 카운트다운)',
398
+ completed: '✅ 완료!',
399
+ cancelled: '❌ 취소됨',
400
+ };
401
+ return descriptions[phase];
402
+ }
403
+
404
+ // ===== Summary =====
405
+
406
+ getSummary(): string {
407
+ if (!this.state) return '세션 없음';
408
+
409
+ const arch = this.state.artifacts.architectOutput;
410
+ const dev = this.state.artifacts.developerOutput;
411
+ const qa = this.state.artifacts.qaOutput;
412
+
413
+ let summary = `## Skill Forge 결과\n\n`;
414
+ summary += `**스킬명:** ${this.state.request.name}\n`;
415
+ summary += `**상태:** ${this.getPhaseDescription(this.state.phase)}\n\n`;
416
+
417
+ if (arch) {
418
+ summary += `### 🏗️ Architect\n`;
419
+ summary += `- 목적: ${arch.purpose}\n`;
420
+ summary += `- 복잡도: ${arch.estimatedComplexity}\n`;
421
+ summary += `- 워크플로우: ${arch.workflow.length}단계\n\n`;
422
+ }
423
+
424
+ if (dev) {
425
+ summary += `### 💻 Developer\n`;
426
+ summary += `- 생성 파일: ${dev.files.length}개\n`;
427
+ dev.files.forEach((f) => {
428
+ summary += ` - ${f.path}\n`;
429
+ });
430
+ summary += `\n`;
431
+ }
432
+
433
+ if (qa) {
434
+ summary += `### 🔍 QA\n`;
435
+ summary += `- 통과: ${qa.passed ? '✅' : '❌'}\n`;
436
+ summary += `- 권고: ${qa.recommendation}\n`;
437
+ summary += `- 체크리스트: ${qa.checklist.filter((c) => c.passed).length}/${qa.checklist.length}\n`;
438
+ }
439
+
440
+ return summary;
441
+ }
442
+ }
443
+
444
+ // ===== Factory =====
445
+
446
+ export function createOrchestrator(config?: Partial<SkillForgeConfig>): Orchestrator {
447
+ return new Orchestrator(config);
448
+ }
449
+
450
+ // ===== Test CLI =====
451
+
452
+ async function runTest() {
453
+ console.log('🔥 Skill Forge - Full Pipeline Test\n');
454
+
455
+ const orchestrator = createOrchestrator({
456
+ countdownMs: 2000, // 테스트용 2초
457
+ });
458
+
459
+ // 이벤트 로깅
460
+ orchestrator.onEvent((event) => {
461
+ const emoji: Record<string, string> = {
462
+ REQUEST_RECEIVED: '📥',
463
+ AGENT_START: '🚀',
464
+ AGENT_COMPLETE: '✅',
465
+ COUNTDOWN_START: '⏱️',
466
+ COUNTDOWN_EXPIRE: '⏰',
467
+ SESSION_COMPLETE: '🎉',
468
+ ERROR: '❌',
469
+ };
470
+ console.log(`${emoji[event.type] || '•'} ${event.type}`);
471
+ });
472
+
473
+ try {
474
+ await orchestrator.startSession({
475
+ name: 'hello-world',
476
+ description: '간단한 인사 스킬',
477
+ triggers: ['/hello', '안녕'],
478
+ capabilities: ['인사하기', '이름 받기'],
479
+ rawInput: '/forge hello-world - 간단한 인사 스킬',
480
+ });
481
+
482
+ // 전체 파이프라인 완료 대기
483
+ await new Promise((resolve) => setTimeout(resolve, 10000));
484
+
485
+ console.log('\n' + '='.repeat(50));
486
+ console.log(orchestrator.getSummary());
487
+ } catch (err) {
488
+ console.error('❌ Error:', err);
489
+ }
490
+ }
491
+
492
+ const isMainModule = import.meta.url === `file://${process.argv[1]}`;
493
+ if (isMainModule) {
494
+ runTest();
495
+ }
@@ -0,0 +1,24 @@
1
+ # hello-world
2
+
3
+ > 간단한 인사 스킬
4
+
5
+ ## 트리거
6
+
7
+ - `/hello`
8
+ - `안녕`
9
+
10
+ ## 워크플로우
11
+
12
+ 1. **parse**: 사용자 입력 파싱
13
+ 2. **validate**: 입력 검증
14
+ 3. **execute**: 핵심 로직 실행
15
+ 4. **format**: 결과 포맷팅
16
+ 5. **respond**: 응답 반환
17
+
18
+ ## 필요한 도구
19
+
20
+ - discord_send
21
+
22
+ ---
23
+
24
+ Generated by Skill Forge 🔥
@@ -0,0 +1,79 @@
1
+ /**
2
+ * hello-world - 간단한 인사 스킬
3
+ *
4
+ * @triggers /hello, 안녕
5
+ * @complexity simple
6
+ */
7
+
8
+ import { SkillContext, SkillResult } from './types';
9
+
10
+ // ===== Skill Definition =====
11
+
12
+ export const skill = {
13
+ name: 'hello-world',
14
+ description: '간단한 인사 스킬',
15
+ triggers: ['/hello', '안녕'],
16
+
17
+ async execute(context: SkillContext): Promise<SkillResult> {
18
+ try {
19
+ console.log('[hello-world] 시작:', context.input);
20
+
21
+ // Workflow Steps
22
+ // Step 1: parse - 사용자 입력 파싱
23
+ const step1 = await parse(context.input);
24
+ // Step 2: validate - 입력 검증
25
+ const step2 = await validate(step1);
26
+ // Step 3: execute - 핵심 로직 실행
27
+ const step3 = await execute(step2);
28
+ // Step 4: format - 결과 포맷팅
29
+ const step4 = await format(step3);
30
+ // Step 5: respond - 응답 반환
31
+ const step5 = await respond(step4);
32
+
33
+ return {
34
+ success: true,
35
+ message: String(step5),
36
+ };
37
+ } catch (error) {
38
+ console.error('[hello-world] 에러:', error);
39
+ return {
40
+ success: false,
41
+ error: error instanceof Error ? error.message : '알 수 없는 에러',
42
+ };
43
+ }
44
+ },
45
+ };
46
+
47
+ // ===== Helper Functions =====
48
+
49
+ async function parse(input: unknown): Promise<unknown> {
50
+ // 사용자 입력 파싱
51
+ console.log('[parse]', input);
52
+ return input;
53
+ }
54
+
55
+ async function validate(input: unknown): Promise<unknown> {
56
+ // 입력 검증
57
+ console.log('[validate]', input);
58
+ return input;
59
+ }
60
+
61
+ async function execute(input: unknown): Promise<unknown> {
62
+ // 핵심 로직 실행
63
+ console.log('[execute]', input);
64
+ return input;
65
+ }
66
+
67
+ async function format(input: unknown): Promise<unknown> {
68
+ // 결과 포맷팅
69
+ console.log('[format]', input);
70
+ return input;
71
+ }
72
+
73
+ async function respond(input: unknown): Promise<unknown> {
74
+ // 응답 반환
75
+ console.log('[respond]', input);
76
+ return input;
77
+ }
78
+
79
+ export default skill;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * hello-world - Type Definitions
3
+ */
4
+
5
+ export interface SkillContext {
6
+ input: string;
7
+ channelId?: string;
8
+ userId?: string;
9
+ metadata?: Record<string, unknown>;
10
+ }
11
+
12
+ export interface SkillResult {
13
+ success: boolean;
14
+ message?: string;
15
+ error?: string;
16
+ data?: unknown;
17
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "skill-forge",
3
+ "version": "0.1.0",
4
+ "description": "Multi-Agent Skill Generator for OpenClaw",
5
+ "type": "module",
6
+ "main": "dist/orchestrator.js",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "test": "npx tsx orchestrator.ts",
10
+ "dev": "npx tsx --watch orchestrator.ts"
11
+ },
12
+ "dependencies": {},
13
+ "devDependencies": {
14
+ "typescript": "^5.3.0",
15
+ "@types/node": "^20.10.0",
16
+ "tsx": "^4.7.0"
17
+ },
18
+ "engines": {
19
+ "node": ">=18.0.0"
20
+ }
21
+ }