@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.
- package/CHANGELOG.md +67 -0
- package/README.md +643 -0
- package/dist/agent/agent-loop.d.ts +98 -0
- package/dist/agent/agent-loop.d.ts.map +1 -0
- package/dist/agent/agent-loop.js +417 -0
- package/dist/agent/agent-loop.js.map +1 -0
- package/dist/agent/auto-recall.d.ts +48 -0
- package/dist/agent/auto-recall.d.ts.map +1 -0
- package/dist/agent/auto-recall.js +178 -0
- package/dist/agent/auto-recall.js.map +1 -0
- package/dist/agent/claude-cli-wrapper.d.ts +130 -0
- package/dist/agent/claude-cli-wrapper.d.ts.map +1 -0
- package/dist/agent/claude-cli-wrapper.js +227 -0
- package/dist/agent/claude-cli-wrapper.js.map +1 -0
- package/dist/agent/claude-client.d.ts +50 -0
- package/dist/agent/claude-client.d.ts.map +1 -0
- package/dist/agent/claude-client.js +214 -0
- package/dist/agent/claude-client.js.map +1 -0
- package/dist/agent/gateway-tool-executor.d.ts +75 -0
- package/dist/agent/gateway-tool-executor.d.ts.map +1 -0
- package/dist/agent/gateway-tool-executor.js +348 -0
- package/dist/agent/gateway-tool-executor.js.map +1 -0
- package/dist/agent/index.d.ts +13 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +18 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/mcp-executor.d.ts +75 -0
- package/dist/agent/mcp-executor.d.ts.map +1 -0
- package/dist/agent/mcp-executor.js +307 -0
- package/dist/agent/mcp-executor.js.map +1 -0
- package/dist/agent/session-pool.d.ts +148 -0
- package/dist/agent/session-pool.d.ts.map +1 -0
- package/dist/agent/session-pool.js +272 -0
- package/dist/agent/session-pool.js.map +1 -0
- package/dist/agent/streaming-callback-manager.d.ts +85 -0
- package/dist/agent/streaming-callback-manager.d.ts.map +1 -0
- package/dist/agent/streaming-callback-manager.js +103 -0
- package/dist/agent/streaming-callback-manager.js.map +1 -0
- package/dist/agent/types.d.ts +437 -0
- package/dist/agent/types.d.ts.map +1 -0
- package/dist/agent/types.js +29 -0
- package/dist/agent/types.js.map +1 -0
- package/dist/api/cron-handler.d.ts +44 -0
- package/dist/api/cron-handler.d.ts.map +1 -0
- package/dist/api/cron-handler.js +195 -0
- package/dist/api/cron-handler.js.map +1 -0
- package/dist/api/error-handler.d.ts +22 -0
- package/dist/api/error-handler.d.ts.map +1 -0
- package/dist/api/error-handler.js +104 -0
- package/dist/api/error-handler.js.map +1 -0
- package/dist/api/heartbeat-handler.d.ts +49 -0
- package/dist/api/heartbeat-handler.d.ts.map +1 -0
- package/dist/api/heartbeat-handler.js +91 -0
- package/dist/api/heartbeat-handler.js.map +1 -0
- package/dist/api/index.d.ts +61 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +145 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/types.d.ts +156 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/api/types.js +62 -0
- package/dist/api/types.js.map +1 -0
- package/dist/auth/index.d.ts +7 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +11 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/oauth-manager.d.ts +59 -0
- package/dist/auth/oauth-manager.d.ts.map +1 -0
- package/dist/auth/oauth-manager.js +237 -0
- package/dist/auth/oauth-manager.js.map +1 -0
- package/dist/auth/types.d.ts +92 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +23 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/cli/commands/init.d.ts +19 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +155 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/run.d.ts +19 -0
- package/dist/cli/commands/run.d.ts.map +1 -0
- package/dist/cli/commands/run.js +89 -0
- package/dist/cli/commands/run.js.map +1 -0
- package/dist/cli/commands/setup.d.ts +19 -0
- package/dist/cli/commands/setup.d.ts.map +1 -0
- package/dist/cli/commands/setup.js +134 -0
- package/dist/cli/commands/setup.js.map +1 -0
- package/dist/cli/commands/start.d.ts +24 -0
- package/dist/cli/commands/start.d.ts.map +1 -0
- package/dist/cli/commands/start.js +1073 -0
- package/dist/cli/commands/start.js.map +1 -0
- package/dist/cli/commands/status.d.ts +10 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/status.js +85 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/commands/stop.d.ts +10 -0
- package/dist/cli/commands/stop.d.ts.map +1 -0
- package/dist/cli/commands/stop.js +65 -0
- package/dist/cli/commands/stop.js.map +1 -0
- package/dist/cli/config/config-manager.d.ts +51 -0
- package/dist/cli/config/config-manager.d.ts.map +1 -0
- package/dist/cli/config/config-manager.js +216 -0
- package/dist/cli/config/config-manager.js.map +1 -0
- package/dist/cli/config/types.d.ts +172 -0
- package/dist/cli/config/types.d.ts.map +1 -0
- package/dist/cli/config/types.js +48 -0
- package/dist/cli/config/types.js.map +1 -0
- package/dist/cli/index.d.ts +8 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +92 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/utils/pid-manager.d.ts +66 -0
- package/dist/cli/utils/pid-manager.d.ts.map +1 -0
- package/dist/cli/utils/pid-manager.js +167 -0
- package/dist/cli/utils/pid-manager.js.map +1 -0
- package/dist/concurrency/index.d.ts +13 -0
- package/dist/concurrency/index.d.ts.map +1 -0
- package/dist/concurrency/index.js +22 -0
- package/dist/concurrency/index.js.map +1 -0
- package/dist/concurrency/lane-manager.d.ts +113 -0
- package/dist/concurrency/lane-manager.d.ts.map +1 -0
- package/dist/concurrency/lane-manager.js +245 -0
- package/dist/concurrency/lane-manager.js.map +1 -0
- package/dist/concurrency/session-key.d.ts +41 -0
- package/dist/concurrency/session-key.d.ts.map +1 -0
- package/dist/concurrency/session-key.js +61 -0
- package/dist/concurrency/session-key.js.map +1 -0
- package/dist/concurrency/types.d.ts +69 -0
- package/dist/concurrency/types.d.ts.map +1 -0
- package/dist/concurrency/types.js +16 -0
- package/dist/concurrency/types.js.map +1 -0
- package/dist/gateways/channel-history.d.ts +102 -0
- package/dist/gateways/channel-history.d.ts.map +1 -0
- package/dist/gateways/channel-history.js +181 -0
- package/dist/gateways/channel-history.js.map +1 -0
- package/dist/gateways/context-injector.d.ts +74 -0
- package/dist/gateways/context-injector.d.ts.map +1 -0
- package/dist/gateways/context-injector.js +121 -0
- package/dist/gateways/context-injector.js.map +1 -0
- package/dist/gateways/discord.d.ts +122 -0
- package/dist/gateways/discord.d.ts.map +1 -0
- package/dist/gateways/discord.js +602 -0
- package/dist/gateways/discord.js.map +1 -0
- package/dist/gateways/index.d.ts +30 -0
- package/dist/gateways/index.d.ts.map +1 -0
- package/dist/gateways/index.js +49 -0
- package/dist/gateways/index.js.map +1 -0
- package/dist/gateways/message-router.d.ts +116 -0
- package/dist/gateways/message-router.d.ts.map +1 -0
- package/dist/gateways/message-router.js +315 -0
- package/dist/gateways/message-router.js.map +1 -0
- package/dist/gateways/message-splitter.d.ts +54 -0
- package/dist/gateways/message-splitter.d.ts.map +1 -0
- package/dist/gateways/message-splitter.js +146 -0
- package/dist/gateways/message-splitter.js.map +1 -0
- package/dist/gateways/plugin-loader.d.ts +76 -0
- package/dist/gateways/plugin-loader.d.ts.map +1 -0
- package/dist/gateways/plugin-loader.js +221 -0
- package/dist/gateways/plugin-loader.js.map +1 -0
- package/dist/gateways/session-store.d.ts +77 -0
- package/dist/gateways/session-store.d.ts.map +1 -0
- package/dist/gateways/session-store.js +233 -0
- package/dist/gateways/session-store.js.map +1 -0
- package/dist/gateways/slack.d.ts +90 -0
- package/dist/gateways/slack.d.ts.map +1 -0
- package/dist/gateways/slack.js +281 -0
- package/dist/gateways/slack.js.map +1 -0
- package/dist/gateways/telegram.d.ts +79 -0
- package/dist/gateways/telegram.d.ts.map +1 -0
- package/dist/gateways/telegram.js +207 -0
- package/dist/gateways/telegram.js.map +1 -0
- package/dist/gateways/types.d.ts +340 -0
- package/dist/gateways/types.d.ts.map +1 -0
- package/dist/gateways/types.js +6 -0
- package/dist/gateways/types.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/memory/memory-logger.d.ts +47 -0
- package/dist/memory/memory-logger.d.ts.map +1 -0
- package/dist/memory/memory-logger.js +126 -0
- package/dist/memory/memory-logger.js.map +1 -0
- package/dist/onboarding/all-tools.d.ts +18 -0
- package/dist/onboarding/all-tools.d.ts.map +1 -0
- package/dist/onboarding/all-tools.js +149 -0
- package/dist/onboarding/all-tools.js.map +1 -0
- package/dist/onboarding/autonomous-discovery-tools.d.ts +13 -0
- package/dist/onboarding/autonomous-discovery-tools.d.ts.map +1 -0
- package/dist/onboarding/autonomous-discovery-tools.js +268 -0
- package/dist/onboarding/autonomous-discovery-tools.js.map +1 -0
- package/dist/onboarding/bootstrap-template.d.ts +5 -0
- package/dist/onboarding/bootstrap-template.d.ts.map +1 -0
- package/dist/onboarding/bootstrap-template.js +142 -0
- package/dist/onboarding/bootstrap-template.js.map +1 -0
- package/dist/onboarding/complete-autonomous-prompt.d.ts +13 -0
- package/dist/onboarding/complete-autonomous-prompt.d.ts.map +1 -0
- package/dist/onboarding/complete-autonomous-prompt.js +1220 -0
- package/dist/onboarding/complete-autonomous-prompt.js.map +1 -0
- package/dist/onboarding/onboarding-state.d.ts +70 -0
- package/dist/onboarding/onboarding-state.d.ts.map +1 -0
- package/dist/onboarding/onboarding-state.js +184 -0
- package/dist/onboarding/onboarding-state.js.map +1 -0
- package/dist/onboarding/personality-quiz.d.ts +35 -0
- package/dist/onboarding/personality-quiz.d.ts.map +1 -0
- package/dist/onboarding/personality-quiz.js +219 -0
- package/dist/onboarding/personality-quiz.js.map +1 -0
- package/dist/onboarding/phase-5-summary.d.ts +22 -0
- package/dist/onboarding/phase-5-summary.d.ts.map +1 -0
- package/dist/onboarding/phase-5-summary.js +151 -0
- package/dist/onboarding/phase-5-summary.js.map +1 -0
- package/dist/onboarding/phase-6-security.d.ts +33 -0
- package/dist/onboarding/phase-6-security.d.ts.map +1 -0
- package/dist/onboarding/phase-6-security.js +473 -0
- package/dist/onboarding/phase-6-security.js.map +1 -0
- package/dist/onboarding/phase-7-integrations.d.ts +66 -0
- package/dist/onboarding/phase-7-integrations.d.ts.map +1 -0
- package/dist/onboarding/phase-7-integrations.js +619 -0
- package/dist/onboarding/phase-7-integrations.js.map +1 -0
- package/dist/onboarding/phase-8-demo.d.ts +43 -0
- package/dist/onboarding/phase-8-demo.d.ts.map +1 -0
- package/dist/onboarding/phase-8-demo.js +346 -0
- package/dist/onboarding/phase-8-demo.js.map +1 -0
- package/dist/onboarding/phase-9-finalization.d.ts +22 -0
- package/dist/onboarding/phase-9-finalization.d.ts.map +1 -0
- package/dist/onboarding/phase-9-finalization.js +375 -0
- package/dist/onboarding/phase-9-finalization.js.map +1 -0
- package/dist/onboarding/ritual-prompt.d.ts +2 -0
- package/dist/onboarding/ritual-prompt.d.ts.map +1 -0
- package/dist/onboarding/ritual-prompt.js +285 -0
- package/dist/onboarding/ritual-prompt.js.map +1 -0
- package/dist/onboarding/ritual-tools.d.ts +13 -0
- package/dist/onboarding/ritual-tools.d.ts.map +1 -0
- package/dist/onboarding/ritual-tools.js +93 -0
- package/dist/onboarding/ritual-tools.js.map +1 -0
- package/dist/runners/cli-runner.d.ts +59 -0
- package/dist/runners/cli-runner.d.ts.map +1 -0
- package/dist/runners/cli-runner.js +190 -0
- package/dist/runners/cli-runner.js.map +1 -0
- package/dist/runners/index.d.ts +11 -0
- package/dist/runners/index.d.ts.map +1 -0
- package/dist/runners/index.js +15 -0
- package/dist/runners/index.js.map +1 -0
- package/dist/runners/types.d.ts +81 -0
- package/dist/runners/types.d.ts.map +1 -0
- package/dist/runners/types.js +31 -0
- package/dist/runners/types.js.map +1 -0
- package/dist/scheduler/cron-scheduler.d.ts +115 -0
- package/dist/scheduler/cron-scheduler.d.ts.map +1 -0
- package/dist/scheduler/cron-scheduler.js +320 -0
- package/dist/scheduler/cron-scheduler.js.map +1 -0
- package/dist/scheduler/heartbeat.d.ts +53 -0
- package/dist/scheduler/heartbeat.d.ts.map +1 -0
- package/dist/scheduler/heartbeat.js +160 -0
- package/dist/scheduler/heartbeat.js.map +1 -0
- package/dist/scheduler/index.d.ts +22 -0
- package/dist/scheduler/index.d.ts.map +1 -0
- package/dist/scheduler/index.js +31 -0
- package/dist/scheduler/index.js.map +1 -0
- package/dist/scheduler/job-lock.d.ts +85 -0
- package/dist/scheduler/job-lock.d.ts.map +1 -0
- package/dist/scheduler/job-lock.js +137 -0
- package/dist/scheduler/job-lock.js.map +1 -0
- package/dist/scheduler/recovery.d.ts +78 -0
- package/dist/scheduler/recovery.d.ts.map +1 -0
- package/dist/scheduler/recovery.js +124 -0
- package/dist/scheduler/recovery.js.map +1 -0
- package/dist/scheduler/schedule-store.d.ts +112 -0
- package/dist/scheduler/schedule-store.d.ts.map +1 -0
- package/dist/scheduler/schedule-store.js +259 -0
- package/dist/scheduler/schedule-store.js.map +1 -0
- package/dist/scheduler/token-keep-alive.d.ts +49 -0
- package/dist/scheduler/token-keep-alive.d.ts.map +1 -0
- package/dist/scheduler/token-keep-alive.js +102 -0
- package/dist/scheduler/token-keep-alive.js.map +1 -0
- package/dist/scheduler/types.d.ts +96 -0
- package/dist/scheduler/types.d.ts.map +1 -0
- package/dist/scheduler/types.js +21 -0
- package/dist/scheduler/types.js.map +1 -0
- package/dist/setup/setup-prompt.d.ts +2 -0
- package/dist/setup/setup-prompt.d.ts.map +1 -0
- package/dist/setup/setup-prompt.js +138 -0
- package/dist/setup/setup-prompt.js.map +1 -0
- package/dist/setup/setup-server.d.ts +8 -0
- package/dist/setup/setup-server.d.ts.map +1 -0
- package/dist/setup/setup-server.js +71 -0
- package/dist/setup/setup-server.js.map +1 -0
- package/dist/setup/setup-tools.d.ts +13 -0
- package/dist/setup/setup-tools.d.ts.map +1 -0
- package/dist/setup/setup-tools.js +103 -0
- package/dist/setup/setup-tools.js.map +1 -0
- package/dist/setup/setup-websocket.d.ts +6 -0
- package/dist/setup/setup-websocket.d.ts.map +1 -0
- package/dist/setup/setup-websocket.js +312 -0
- package/dist/setup/setup-websocket.js.map +1 -0
- package/dist/skills/index.d.ts +10 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +26 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/skills/skill-executor.d.ts +48 -0
- package/dist/skills/skill-executor.d.ts.map +1 -0
- package/dist/skills/skill-executor.js +483 -0
- package/dist/skills/skill-executor.js.map +1 -0
- package/dist/skills/skill-loader.d.ts +40 -0
- package/dist/skills/skill-loader.d.ts.map +1 -0
- package/dist/skills/skill-loader.js +225 -0
- package/dist/skills/skill-loader.js.map +1 -0
- package/dist/skills/skill-matcher.d.ts +33 -0
- package/dist/skills/skill-matcher.d.ts.map +1 -0
- package/dist/skills/skill-matcher.js +190 -0
- package/dist/skills/skill-matcher.js.map +1 -0
- package/dist/skills/types.d.ts +123 -0
- package/dist/skills/types.d.ts.map +1 -0
- package/dist/skills/types.js +12 -0
- package/dist/skills/types.js.map +1 -0
- package/dist/tools/browser-tool.d.ts +149 -0
- package/dist/tools/browser-tool.d.ts.map +1 -0
- package/dist/tools/browser-tool.js +257 -0
- package/dist/tools/browser-tool.js.map +1 -0
- package/package.json +84 -0
- package/public/favicon.ico +0 -0
- package/public/setup.html +1026 -0
- package/public/viewer/icons/icon-192.png +0 -0
- package/public/viewer/icons/icon-512.png +0 -0
- package/public/viewer/js/modules/chat.js +1587 -0
- package/public/viewer/js/modules/dashboard.js +275 -0
- package/public/viewer/js/modules/graph.js +997 -0
- package/public/viewer/js/modules/memory.js +353 -0
- package/public/viewer/js/modules/settings.js +255 -0
- package/public/viewer/js/utils/api.js +169 -0
- package/public/viewer/js/utils/dom.js +92 -0
- package/public/viewer/js/utils/format.js +192 -0
- package/public/viewer/manifest.json +26 -0
- package/public/viewer/sw.js +131 -0
- package/public/viewer/viewer.css +500 -0
- package/public/viewer/viewer.html +1535 -0
- package/scripts/postinstall.js +118 -0
- package/templates/skills/document-analyze.md +63 -0
- package/templates/skills/heartbeat-report.md +75 -0
- package/templates/skills/image-translate.md +67 -0
- package/templates/workspace/skill-forge/DESIGN.md +115 -0
- package/templates/workspace/skill-forge/agents/architect.ts +295 -0
- package/templates/workspace/skill-forge/agents/developer.ts +364 -0
- package/templates/workspace/skill-forge/agents/qa.ts +313 -0
- package/templates/workspace/skill-forge/claude-api.ts +353 -0
- package/templates/workspace/skill-forge/discord-ui.ts +580 -0
- package/templates/workspace/skill-forge/error-handler.ts +354 -0
- package/templates/workspace/skill-forge/mama-integration.ts +357 -0
- package/templates/workspace/skill-forge/orchestrator.ts +495 -0
- package/templates/workspace/skill-forge/output/generated-skills/skills/hello-world/README.md +24 -0
- package/templates/workspace/skill-forge/output/generated-skills/skills/hello-world/index.ts +79 -0
- package/templates/workspace/skill-forge/output/generated-skills/skills/hello-world/types.ts +17 -0
- package/templates/workspace/skill-forge/package.json +21 -0
- package/templates/workspace/skill-forge/state/session.json +132 -0
- package/templates/workspace/skill-forge/test-e2e.ts +139 -0
- package/templates/workspace/skill-forge/tsconfig.json +20 -0
- 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
|
+
}
|