@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,354 @@
1
+ /**
2
+ * Skill Forge - Error Handler
3
+ *
4
+ * 톡합 μ—λŸ¬ 처리 + 볡ꡬ μ „λž΅
5
+ */
6
+
7
+ import { SessionPhase, SessionState } from './types';
8
+
9
+ // ===== Error Types =====
10
+
11
+ export type SkillForgeErrorCode =
12
+ | 'ARCHITECT_FAILED'
13
+ | 'DEVELOPER_FAILED'
14
+ | 'QA_FAILED'
15
+ | 'API_ERROR'
16
+ | 'TIMEOUT'
17
+ | 'INVALID_INPUT'
18
+ | 'FILE_ERROR'
19
+ | 'STATE_ERROR'
20
+ | 'UNKNOWN';
21
+
22
+ export interface SkillForgeError extends Error {
23
+ code: SkillForgeErrorCode;
24
+ phase?: SessionPhase;
25
+ retryable: boolean;
26
+ userMessage: string;
27
+ details?: Record<string, unknown>;
28
+ }
29
+
30
+ // ===== Error Factory =====
31
+
32
+ export function createError(
33
+ code: SkillForgeErrorCode,
34
+ message: string,
35
+ options?: {
36
+ phase?: SessionPhase;
37
+ retryable?: boolean;
38
+ details?: Record<string, unknown>;
39
+ }
40
+ ): SkillForgeError {
41
+ const error = new Error(message) as SkillForgeError;
42
+ error.code = code;
43
+ error.phase = options?.phase;
44
+ error.retryable = options?.retryable ?? false;
45
+ error.details = options?.details;
46
+ error.userMessage = getUserMessage(code, message);
47
+ return error;
48
+ }
49
+
50
+ function getUserMessage(code: SkillForgeErrorCode, original: string): string {
51
+ const messages: Record<SkillForgeErrorCode, string> = {
52
+ ARCHITECT_FAILED: 'πŸ—οΈ 섀계 λ‹¨κ³„μ—μ„œ 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€. λ‹€μ‹œ μ‹œλ„ν•΄ μ£Όμ„Έμš”.',
53
+ DEVELOPER_FAILED: 'πŸ’» μ½”λ“œ 생성 쀑 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€. 섀계λ₯Ό λ‹¨μˆœν™”ν•΄ λ³΄μ„Έμš”.',
54
+ QA_FAILED: 'πŸ” 검증 λ‹¨κ³„μ—μ„œ 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€.',
55
+ API_ERROR: 'πŸ”Œ API μ—°κ²° 였λ₯˜μž…λ‹ˆλ‹€. μž μ‹œ ν›„ λ‹€μ‹œ μ‹œλ„ν•΄ μ£Όμ„Έμš”.',
56
+ TIMEOUT: '⏱️ μ‹œκ°„ μ΄ˆκ³Όλ˜μ—ˆμŠ΅λ‹ˆλ‹€. μš”μ²­μ„ κ°„μ†Œν™”ν•΄ λ³΄μ„Έμš”.',
57
+ INVALID_INPUT: '❓ μž…λ ₯이 μ˜¬λ°”λ₯΄μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. ν˜•μ‹μ„ 확인해 μ£Όμ„Έμš”.',
58
+ FILE_ERROR: 'πŸ“ 파일 처리 쀑 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€.',
59
+ STATE_ERROR: '⚠️ μ„Έμ…˜ μƒνƒœ 였λ₯˜μž…λ‹ˆλ‹€. μƒˆλ‘œ μ‹œμž‘ν•΄ μ£Όμ„Έμš”.',
60
+ UNKNOWN: '❌ 예기치 μ•Šμ€ 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€.',
61
+ };
62
+ return messages[code];
63
+ }
64
+
65
+ // ===== Error Handler =====
66
+
67
+ export interface ErrorHandlerConfig {
68
+ maxRetries: number;
69
+ retryDelayMs: number;
70
+ onError?: (error: SkillForgeError) => void;
71
+ }
72
+
73
+ const DEFAULT_ERROR_CONFIG: ErrorHandlerConfig = {
74
+ maxRetries: 3,
75
+ retryDelayMs: 1000,
76
+ };
77
+
78
+ export class ErrorHandler {
79
+ private config: ErrorHandlerConfig;
80
+ private retryCount: Map<string, number> = new Map();
81
+
82
+ constructor(config?: Partial<ErrorHandlerConfig>) {
83
+ this.config = { ...DEFAULT_ERROR_CONFIG, ...config };
84
+ }
85
+
86
+ /**
87
+ * Handle an error with optional retry logic
88
+ */
89
+ async handle<T>(
90
+ key: string,
91
+ operation: () => Promise<T>,
92
+ options?: { phase?: SessionPhase }
93
+ ): Promise<T> {
94
+ const retries = this.retryCount.get(key) || 0;
95
+
96
+ try {
97
+ const result = await operation();
98
+ this.retryCount.delete(key); // Success - reset retry count
99
+ return result;
100
+ } catch (err) {
101
+ const error = this.wrapError(err, options?.phase);
102
+
103
+ // Notify handler
104
+ this.config.onError?.(error);
105
+
106
+ // Check if we should retry
107
+ if (error.retryable && retries < this.config.maxRetries) {
108
+ this.retryCount.set(key, retries + 1);
109
+ console.log(`[ErrorHandler] Retry ${retries + 1}/${this.config.maxRetries}: ${key}`);
110
+
111
+ await this.delay(this.config.retryDelayMs * (retries + 1));
112
+ return this.handle(key, operation, options);
113
+ }
114
+
115
+ this.retryCount.delete(key);
116
+ throw error;
117
+ }
118
+ }
119
+
120
+ /**
121
+ * Wrap unknown errors into SkillForgeError
122
+ */
123
+ wrapError(err: unknown, phase?: SessionPhase): SkillForgeError {
124
+ // Already wrapped
125
+ if (isSkillForgeError(err)) {
126
+ return err;
127
+ }
128
+
129
+ const message = err instanceof Error ? err.message : String(err);
130
+
131
+ // Detect error type from message
132
+ const code = this.detectErrorCode(message);
133
+
134
+ return createError(code, message, {
135
+ phase,
136
+ retryable: this.isRetryable(code, message),
137
+ details: { original: err },
138
+ });
139
+ }
140
+
141
+ private detectErrorCode(message: string): SkillForgeErrorCode {
142
+ const lower = message.toLowerCase();
143
+
144
+ if (lower.includes('timeout') || lower.includes('timed out')) {
145
+ return 'TIMEOUT';
146
+ }
147
+ if (lower.includes('api') || lower.includes('fetch') || lower.includes('network')) {
148
+ return 'API_ERROR';
149
+ }
150
+ if (lower.includes('file') || lower.includes('enoent') || lower.includes('permission')) {
151
+ return 'FILE_ERROR';
152
+ }
153
+ if (lower.includes('json') || lower.includes('parse') || lower.includes('invalid')) {
154
+ return 'INVALID_INPUT';
155
+ }
156
+ if (lower.includes('architect')) {
157
+ return 'ARCHITECT_FAILED';
158
+ }
159
+ if (lower.includes('developer')) {
160
+ return 'DEVELOPER_FAILED';
161
+ }
162
+ if (lower.includes('qa')) {
163
+ return 'QA_FAILED';
164
+ }
165
+
166
+ return 'UNKNOWN';
167
+ }
168
+
169
+ private isRetryable(code: SkillForgeErrorCode, message: string): boolean {
170
+ // These are generally retryable
171
+ const retryableCodes: SkillForgeErrorCode[] = ['API_ERROR', 'TIMEOUT'];
172
+
173
+ if (retryableCodes.includes(code)) {
174
+ return true;
175
+ }
176
+
177
+ // Check for rate limiting
178
+ if (message.includes('rate limit') || message.includes('429')) {
179
+ return true;
180
+ }
181
+
182
+ return false;
183
+ }
184
+
185
+ private delay(ms: number): Promise<void> {
186
+ return new Promise((resolve) => setTimeout(resolve, ms));
187
+ }
188
+ }
189
+
190
+ function isSkillForgeError(err: unknown): err is SkillForgeError {
191
+ return err instanceof Error && 'code' in err && 'retryable' in err;
192
+ }
193
+
194
+ // ===== Recovery Strategies =====
195
+
196
+ export interface RecoveryStrategy {
197
+ canRecover(error: SkillForgeError, state: SessionState): boolean;
198
+ recover(error: SkillForgeError, state: SessionState): SessionState;
199
+ }
200
+
201
+ /**
202
+ * Rollback to previous phase on error
203
+ */
204
+ export const rollbackStrategy: RecoveryStrategy = {
205
+ canRecover(error, state) {
206
+ return ['ARCHITECT_FAILED', 'DEVELOPER_FAILED', 'QA_FAILED'].includes(error.code);
207
+ },
208
+
209
+ recover(error, state) {
210
+ const rollbackMap: Partial<Record<SessionPhase, SessionPhase>> = {
211
+ architect: 'idle',
212
+ architect_review: 'architect',
213
+ developer: 'architect_review',
214
+ developer_review: 'developer',
215
+ qa: 'developer_review',
216
+ qa_review: 'qa',
217
+ };
218
+
219
+ const newPhase = rollbackMap[state.phase] || 'idle';
220
+ console.log(`[Recovery] Rolling back from ${state.phase} to ${newPhase}`);
221
+
222
+ return {
223
+ ...state,
224
+ phase: newPhase,
225
+ updatedAt: new Date().toISOString(),
226
+ };
227
+ },
228
+ };
229
+
230
+ /**
231
+ * Skip to next phase on non-critical error
232
+ */
233
+ export const skipStrategy: RecoveryStrategy = {
234
+ canRecover(error, state) {
235
+ // Only skip QA if it fails but we have developer output
236
+ return error.code === 'QA_FAILED' && !!state.artifacts.developerOutput;
237
+ },
238
+
239
+ recover(error, state) {
240
+ console.log(`[Recovery] Skipping QA, marking as completed with warning`);
241
+
242
+ return {
243
+ ...state,
244
+ phase: 'completed' as SessionPhase,
245
+ artifacts: {
246
+ ...state.artifacts,
247
+ qaOutput: {
248
+ passed: false,
249
+ checklist: [],
250
+ issues: [
251
+ {
252
+ severity: 'warning' as const,
253
+ description: 'QA 검증이 μ‹€νŒ¨ν–ˆμ§€λ§Œ μŠ€ν‚΅λ¨',
254
+ },
255
+ ],
256
+ recommendation: 'revise' as const,
257
+ },
258
+ },
259
+ updatedAt: new Date().toISOString(),
260
+ };
261
+ },
262
+ };
263
+
264
+ // ===== Error Formatters =====
265
+
266
+ export function formatErrorForDiscord(error: SkillForgeError): string {
267
+ const lines = [`## ❌ 였λ₯˜ λ°œμƒ`, '', error.userMessage, ''];
268
+
269
+ if (error.retryable) {
270
+ lines.push('> πŸ’‘ 이 였λ₯˜λŠ” μžλ™μœΌλ‘œ μž¬μ‹œλ„λ©λ‹ˆλ‹€.');
271
+ }
272
+
273
+ if (error.phase) {
274
+ lines.push(`πŸ“ **단계:** ${error.phase}`);
275
+ }
276
+
277
+ lines.push(`πŸ”– **μ½”λ“œ:** \`${error.code}\``);
278
+
279
+ return lines.join('\n');
280
+ }
281
+
282
+ export function formatErrorForLog(error: SkillForgeError): string {
283
+ return JSON.stringify({
284
+ code: error.code,
285
+ message: error.message,
286
+ phase: error.phase,
287
+ retryable: error.retryable,
288
+ timestamp: new Date().toISOString(),
289
+ details: error.details,
290
+ });
291
+ }
292
+
293
+ // ===== Test =====
294
+
295
+ async function runTest() {
296
+ console.log('πŸ›‘οΈ Error Handler Test\n');
297
+
298
+ const handler = new ErrorHandler({
299
+ maxRetries: 2,
300
+ retryDelayMs: 100,
301
+ onError: (err) => console.log(`[Callback] ${err.code}: ${err.message}`),
302
+ });
303
+
304
+ // Test 1: Successful operation
305
+ console.log('=== Test 1: Success ===');
306
+ const result1 = await handler.handle('test1', async () => 'success');
307
+ console.log('Result:', result1);
308
+
309
+ // Test 2: Retryable failure
310
+ console.log('\n=== Test 2: Retryable Failure ===');
311
+ let attempts = 0;
312
+ try {
313
+ await handler.handle('test2', async () => {
314
+ attempts++;
315
+ if (attempts < 3) {
316
+ throw new Error('API rate limit exceeded');
317
+ }
318
+ return 'success after retries';
319
+ });
320
+ } catch (err) {
321
+ console.log('Final error:', (err as SkillForgeError).code);
322
+ }
323
+ console.log('Attempts:', attempts);
324
+
325
+ // Test 3: Non-retryable failure
326
+ console.log('\n=== Test 3: Non-retryable ===');
327
+ try {
328
+ await handler.handle('test3', async () => {
329
+ throw new Error('Invalid input format');
330
+ });
331
+ } catch (err) {
332
+ const sfError = err as SkillForgeError;
333
+ console.log('Error code:', sfError.code);
334
+ console.log('Retryable:', sfError.retryable);
335
+ console.log('User message:', sfError.userMessage);
336
+ }
337
+
338
+ // Test 4: Error wrapping
339
+ console.log('\n=== Test 4: Error Wrapping ===');
340
+ const wrapped = handler.wrapError(new Error('Architect JSON parse failed'), 'architect');
341
+ console.log('Wrapped:', wrapped.code, wrapped.phase);
342
+
343
+ // Test 5: Discord format
344
+ console.log('\n=== Test 5: Discord Format ===');
345
+ const discordMsg = formatErrorForDiscord(wrapped);
346
+ console.log(discordMsg);
347
+
348
+ console.log('\nβœ… All error handler tests complete');
349
+ }
350
+
351
+ const isMainModule = import.meta.url === `file://${process.argv[1]}`;
352
+ if (isMainModule) {
353
+ runTest();
354
+ }
@@ -0,0 +1,357 @@
1
+ /**
2
+ * Skill Forge - MAMA Integration
3
+ *
4
+ * MAMA MCP μ„œλ²„μ™€ μ—°λ™ν•˜μ—¬ decision/checkpoint 관리
5
+ */
6
+
7
+ import { SessionState, ArchitectOutput, QAOutput } from './types';
8
+
9
+ // ===== MAMA Decision Types =====
10
+
11
+ export interface MAMADecision {
12
+ type: 'decision';
13
+ topic: string;
14
+ decision: string;
15
+ reasoning: string;
16
+ confidence: number;
17
+ }
18
+
19
+ export interface MAMACheckpoint {
20
+ type: 'checkpoint';
21
+ summary: string;
22
+ next_steps: string;
23
+ open_files: string[];
24
+ }
25
+
26
+ // ===== Decision Builders =====
27
+
28
+ export function buildSkillDecision(state: SessionState): MAMADecision {
29
+ const arch = state.artifacts.architectOutput;
30
+ const qa = state.artifacts.qaOutput;
31
+
32
+ if (!arch) {
33
+ throw new Error('No architect output available');
34
+ }
35
+
36
+ const decision = `skill_${arch.skillName}`;
37
+ const qaStatus = qa ? (qa.passed ? 'QA passed' : 'QA failed') : 'QA pending';
38
+
39
+ return {
40
+ type: 'decision',
41
+ topic: `skill_forge_${arch.skillName}`,
42
+ decision: `Created skill '${arch.skillName}' - ${arch.purpose}`,
43
+ reasoning: buildDecisionReasoning(arch, qa),
44
+ confidence: calculateConfidence(state),
45
+ };
46
+ }
47
+
48
+ function buildDecisionReasoning(arch: ArchitectOutput, qa?: QAOutput): string {
49
+ const sections: string[] = [];
50
+
51
+ // 1. Context
52
+ sections.push(`(1) Context - Skill Forgeλ₯Ό 톡해 '${arch.skillName}' μŠ€ν‚¬ 생성 μš”μ²­λ¨`);
53
+
54
+ // 2. Evidence
55
+ const evidence = [
56
+ `μ›Œν¬ν”Œλ‘œμš° ${arch.workflow.length}단계 섀계`,
57
+ `파일 ${arch.fileStructure.length}개 ꡬ쑰화`,
58
+ `λ³΅μž‘λ„: ${arch.estimatedComplexity}`,
59
+ ];
60
+ if (qa) {
61
+ evidence.push(
62
+ `QA 체크리슀트: ${qa.checklist.filter((c) => c.passed).length}/${qa.checklist.length} 톡과`
63
+ );
64
+ }
65
+ sections.push(`(2) Evidence - ${evidence.join(', ')}`);
66
+
67
+ // 3. Alternatives
68
+ sections.push(`(3) Alternatives - μˆ˜λ™ μž‘μ„± λŒ€λΉ„ μžλ™ν™”λœ ꡬ쑰 섀계 채택`);
69
+
70
+ // 4. Risks
71
+ const risks = qa?.issues.filter((i) => i.severity === 'critical').map((i) => i.description) || [];
72
+ sections.push(`(4) Risks - ${risks.length ? risks.join(', ') : 'μ£Όμš” 리슀크 μ—†μŒ'}`);
73
+
74
+ // 5. Rationale
75
+ sections.push(`(5) Rationale - Architectβ†’Developerβ†’QA νŒŒμ΄ν”„λΌμΈμœΌλ‘œ μΌκ΄€λœ ν’ˆμ§ˆ 보μž₯`);
76
+
77
+ return sections.join('; ');
78
+ }
79
+
80
+ function calculateConfidence(state: SessionState): number {
81
+ const qa = state.artifacts.qaOutput;
82
+
83
+ if (!qa) return 0.5;
84
+
85
+ if (qa.passed && qa.recommendation === 'approve') {
86
+ return 0.9;
87
+ } else if (qa.passed) {
88
+ return 0.7;
89
+ } else if (qa.recommendation === 'revise') {
90
+ return 0.5;
91
+ } else {
92
+ return 0.3;
93
+ }
94
+ }
95
+
96
+ // ===== Checkpoint Builders =====
97
+
98
+ export function buildSessionCheckpoint(state: SessionState): MAMACheckpoint {
99
+ const { phase, artifacts, request } = state;
100
+
101
+ // Summary with 4-section format
102
+ const summary = buildCheckpointSummary(state);
103
+
104
+ // Next steps
105
+ const nextSteps = buildNextSteps(state);
106
+
107
+ // Open files
108
+ const openFiles = buildOpenFiles(state);
109
+
110
+ return {
111
+ type: 'checkpoint',
112
+ summary,
113
+ next_steps: nextSteps,
114
+ open_files: openFiles,
115
+ };
116
+ }
117
+
118
+ function buildCheckpointSummary(state: SessionState): string {
119
+ const { phase, artifacts, request } = state;
120
+ const sections: string[] = [];
121
+
122
+ // 1. Goal & Progress
123
+ sections.push(`🎯 Goal & Progress - '${request.name}' μŠ€ν‚¬ 생성, ν˜„μž¬ ${phase} 단계`);
124
+
125
+ // 2. Evidence
126
+ const evidence: string[] = [];
127
+ if (artifacts.architectOutput) {
128
+ evidence.push(`Architect: Verified (${artifacts.architectOutput.workflow.length}단계 섀계)`);
129
+ }
130
+ if (artifacts.developerOutput) {
131
+ evidence.push(`Developer: Verified (${artifacts.developerOutput.files.length}개 파일)`);
132
+ }
133
+ if (artifacts.qaOutput) {
134
+ evidence.push(`QA: ${artifacts.qaOutput.passed ? 'Passed' : 'Failed'}`);
135
+ }
136
+ sections.push(`βœ… Evidence - ${evidence.join(', ') || 'Not run'}`);
137
+
138
+ // 3. Unfinished & Risks
139
+ const unfinished: string[] = [];
140
+ if (phase === 'architect' || phase === 'architect_review') {
141
+ unfinished.push('Developer μž‘μ—… λŒ€κΈ°');
142
+ unfinished.push('QA 검증 λŒ€κΈ°');
143
+ } else if (phase === 'developer' || phase === 'developer_review') {
144
+ unfinished.push('QA 검증 λŒ€κΈ°');
145
+ }
146
+ sections.push(`⏳ Unfinished & Risks - ${unfinished.join(', ') || 'μ—†μŒ'}`);
147
+
148
+ // 4. Related decisions
149
+ sections.push(`Related decisions: skill_forge_${request.name}`);
150
+
151
+ return sections.join('; ');
152
+ }
153
+
154
+ function buildNextSteps(state: SessionState): string {
155
+ const { phase, request } = state;
156
+ const steps: string[] = [];
157
+
158
+ // DoD
159
+ steps.push(`DoD: '${request.name}' μŠ€ν‚¬μ΄ QA 톡과 ν›„ output 폴더에 μ €μž₯`);
160
+
161
+ // Quick verification
162
+ steps.push(`Verification: cd ~/.mama/workspace/skill-forge && npx tsx test-e2e.ts`);
163
+
164
+ // Phase-specific
165
+ switch (phase) {
166
+ case 'architect':
167
+ case 'architect_review':
168
+ steps.push('Next: Architect 좜λ ₯ κ²€ν†  ν›„ Developer μ§„ν–‰');
169
+ break;
170
+ case 'developer':
171
+ case 'developer_review':
172
+ steps.push('Next: Developer 좜λ ₯ κ²€ν†  ν›„ QA μ§„ν–‰');
173
+ break;
174
+ case 'qa':
175
+ case 'qa_review':
176
+ steps.push('Next: QA κ²°κ³Ό 확인 ν›„ μ΅œμ’… 승인');
177
+ break;
178
+ case 'completed':
179
+ steps.push('Done: μƒμ„±λœ νŒŒμΌμ„ MAMA에 등둝');
180
+ break;
181
+ }
182
+
183
+ return steps.join('; ');
184
+ }
185
+
186
+ function buildOpenFiles(state: SessionState): string[] {
187
+ const files = [
188
+ '~/.mama/workspace/skill-forge/orchestrator.ts',
189
+ '~/.mama/workspace/skill-forge/types.ts',
190
+ ];
191
+
192
+ // Add generated files if any
193
+ const developerOutput = state.artifacts.developerOutput;
194
+ if (developerOutput) {
195
+ for (const file of developerOutput.files) {
196
+ files.push(`~/.mama/workspace/skill-forge/output/generated-skills/${file.path}`);
197
+ }
198
+ }
199
+
200
+ return files;
201
+ }
202
+
203
+ // ===== MCP Call Helpers =====
204
+
205
+ /**
206
+ * Format decision for MAMA MCP save call
207
+ */
208
+ export function formatDecisionForMCP(decision: MAMADecision): Record<string, unknown> {
209
+ return {
210
+ type: 'decision',
211
+ topic: decision.topic,
212
+ decision: decision.decision,
213
+ reasoning: decision.reasoning,
214
+ confidence: decision.confidence,
215
+ };
216
+ }
217
+
218
+ /**
219
+ * Format checkpoint for MAMA MCP save call
220
+ */
221
+ export function formatCheckpointForMCP(checkpoint: MAMACheckpoint): Record<string, unknown> {
222
+ return {
223
+ type: 'checkpoint',
224
+ summary: checkpoint.summary,
225
+ next_steps: checkpoint.next_steps,
226
+ open_files: checkpoint.open_files,
227
+ };
228
+ }
229
+
230
+ // ===== Integration Events =====
231
+
232
+ export type MAMAEvent =
233
+ | { type: 'DECISION_SAVED'; topic: string; id: string }
234
+ | { type: 'CHECKPOINT_SAVED'; id: string }
235
+ | { type: 'MAMA_ERROR'; error: string };
236
+
237
+ export interface MAMAIntegration {
238
+ saveDecision(state: SessionState): Promise<MAMAEvent>;
239
+ saveCheckpoint(state: SessionState): Promise<MAMAEvent>;
240
+ searchRelated(topic: string): Promise<string[]>;
241
+ }
242
+
243
+ /**
244
+ * Mock implementation for testing
245
+ * Real implementation would use MCP client
246
+ */
247
+ export function createMockMAMAIntegration(): MAMAIntegration {
248
+ let decisionCount = 0;
249
+ let checkpointCount = 0;
250
+
251
+ return {
252
+ async saveDecision(state: SessionState): Promise<MAMAEvent> {
253
+ const decision = buildSkillDecision(state);
254
+ decisionCount++;
255
+ console.log(`[MAMA] Saved decision: ${decision.topic}`);
256
+ console.log(`[MAMA] Reasoning: ${decision.reasoning}`);
257
+ return {
258
+ type: 'DECISION_SAVED',
259
+ topic: decision.topic,
260
+ id: `decision_${decisionCount}`,
261
+ };
262
+ },
263
+
264
+ async saveCheckpoint(state: SessionState): Promise<MAMAEvent> {
265
+ const checkpoint = buildSessionCheckpoint(state);
266
+ checkpointCount++;
267
+ console.log(`[MAMA] Saved checkpoint`);
268
+ console.log(`[MAMA] Summary: ${checkpoint.summary}`);
269
+ return {
270
+ type: 'CHECKPOINT_SAVED',
271
+ id: `checkpoint_${checkpointCount}`,
272
+ };
273
+ },
274
+
275
+ async searchRelated(topic: string): Promise<string[]> {
276
+ console.log(`[MAMA] Searching for: ${topic}`);
277
+ return []; // Mock returns empty
278
+ },
279
+ };
280
+ }
281
+
282
+ // ===== Test =====
283
+
284
+ async function runTest() {
285
+ console.log('πŸ”— MAMA Integration Test\n');
286
+
287
+ // Mock session state
288
+ const mockState: SessionState = {
289
+ id: 'test-123',
290
+ phase: 'completed',
291
+ request: {
292
+ name: 'hello-world',
293
+ description: 'κ°„λ‹¨ν•œ 인사 μŠ€ν‚¬',
294
+ triggers: ['/hello'],
295
+ capabilities: ['μΈμ‚¬ν•˜κΈ°'],
296
+ rawInput: '/forge hello-world',
297
+ },
298
+ artifacts: {
299
+ architectOutput: {
300
+ skillName: 'hello-world',
301
+ purpose: 'μœ μ €μ—κ²Œ μΈμ‚¬ν•˜λŠ” κ°„λ‹¨ν•œ μŠ€ν‚¬',
302
+ triggers: ['/hello', 'μ•ˆλ…•'],
303
+ workflow: [
304
+ { step: 1, action: 'parse', description: 'μž…λ ₯ νŒŒμ‹±' },
305
+ { step: 2, action: 'respond', description: '인사 응닡' },
306
+ ],
307
+ fileStructure: [
308
+ { path: 'skills/hello-world/index.ts', purpose: '메인 둜직' },
309
+ { path: 'skills/hello-world/types.ts', purpose: 'νƒ€μž… μ •μ˜' },
310
+ ],
311
+ toolsRequired: ['Read'],
312
+ estimatedComplexity: 'simple',
313
+ },
314
+ developerOutput: {
315
+ files: [
316
+ { path: 'skills/hello-world/index.ts', content: '...', language: 'typescript' },
317
+ { path: 'skills/hello-world/types.ts', content: '...', language: 'typescript' },
318
+ ],
319
+ installInstructions: ['npm install'],
320
+ testCommands: ['npm test'],
321
+ },
322
+ qaOutput: {
323
+ passed: true,
324
+ checklist: [
325
+ { item: 'νƒ€μž… μ •μ˜ μ™„λ£Œ', passed: true },
326
+ { item: '메인 ν•¨μˆ˜ 쑴재', passed: true },
327
+ ],
328
+ issues: [],
329
+ recommendation: 'approve',
330
+ },
331
+ },
332
+ countdown: null,
333
+ createdAt: new Date().toISOString(),
334
+ updatedAt: new Date().toISOString(),
335
+ };
336
+
337
+ const mama = createMockMAMAIntegration();
338
+
339
+ console.log('=== Decision ===\n');
340
+ const decision = buildSkillDecision(mockState);
341
+ console.log(JSON.stringify(decision, null, 2));
342
+
343
+ console.log('\n=== Checkpoint ===\n');
344
+ const checkpoint = buildSessionCheckpoint(mockState);
345
+ console.log(JSON.stringify(checkpoint, null, 2));
346
+
347
+ console.log('\n=== Save via Integration ===\n');
348
+ await mama.saveDecision(mockState);
349
+ await mama.saveCheckpoint(mockState);
350
+
351
+ console.log('\nβœ… Test complete');
352
+ }
353
+
354
+ const isMainModule = import.meta.url === `file://${process.argv[1]}`;
355
+ if (isMainModule) {
356
+ runTest();
357
+ }