too-many-claw 1.0.0

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/dist/cli.js ADDED
@@ -0,0 +1,1638 @@
1
+ #!/usr/bin/env node
2
+ #!/usr/bin/env node
3
+
4
+ // src/cli.ts
5
+ import { Command } from "commander";
6
+ import chalk3 from "chalk";
7
+ import ora from "ora";
8
+ import inquirer from "inquirer";
9
+
10
+ // src/simulation/TerminalUI.ts
11
+ import chalk2 from "chalk";
12
+ import * as readline from "readline";
13
+
14
+ // src/agents/definitions.ts
15
+ var AGENT_DEFINITIONS = [
16
+ // ============================================================================
17
+ // CORE (1)
18
+ // ============================================================================
19
+ {
20
+ id: "base",
21
+ name: "Base",
22
+ emoji: "\u{1F3E0}",
23
+ category: "CORE" /* CORE */,
24
+ model: "claude-opus-4-5" /* OPUS */,
25
+ role: "\uD300 \uCF54\uB514\uB124\uC774\uD130. \uD56D\uC0C1 \uD65C\uC131\uD654 \uC0C1\uD0DC. \uC0AC\uC6A9\uC790 \uC694\uCCAD\uC744 \uBC1B\uC544 \uBD84\uC11D\uD558\uACE0 \uC801\uC808\uD55C \uC5D0\uC774\uC804\uD2B8\uB97C \uC18C\uD658\uD55C\uB2E4. \uD300 \uB300\uD654\uB97C \uC870\uC728\uD558\uACE0, \uC791\uC5C5 \uC644\uB8CC \uC2DC \uACB0\uACFC\uB97C \uC885\uD569\uD558\uC5EC \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uC804\uB2EC\uD55C\uB2E4. \uD544\uC694\uC2DC \uC5D0\uC774\uC804\uD2B8\uC5D0\uAC8C \uD1F4\uC7A5\uC744 \uBA85\uB839\uD560 \uC218 \uC788\uB2E4.",
26
+ alwaysActive: true
27
+ },
28
+ // ============================================================================
29
+ // RESEARCH (4)
30
+ // ============================================================================
31
+ {
32
+ id: "searcher",
33
+ name: "\uAC80\uC0C9 \uC804\uBB38\uAC00",
34
+ emoji: "\u{1F50D}",
35
+ category: "RESEARCH" /* RESEARCH */,
36
+ model: "claude-sonnet-4-5" /* SONNET */,
37
+ role: "\uC815\uBCF4 \uAC80\uC0C9 \uBC0F \uC790\uB8CC \uC218\uC9D1 \uC804\uBB38\uAC00. \uC6F9 \uAC80\uC0C9, \uBB38\uC11C \uAC80\uC0C9, \uB370\uC774\uD130\uBCA0\uC774\uC2A4 \uC870\uD68C \uB4F1\uC744 \uD1B5\uD574 \uD544\uC694\uD55C \uC815\uBCF4\uB97C \uCC3E\uC544\uC628\uB2E4. \uAC80\uC0C9 \uACB0\uACFC\uB97C \uC815\uB9AC\uD558\uC5EC \uD300\uC5D0\uAC8C \uACF5\uC720\uD55C\uB2E4."
38
+ },
39
+ {
40
+ id: "tech-researcher",
41
+ name: "\uCD5C\uC2E0 \uAE30\uC220 \uC870\uC0AC \uC804\uBB38\uAC00",
42
+ emoji: "\u{1F52C}",
43
+ category: "RESEARCH" /* RESEARCH */,
44
+ model: "claude-sonnet-4-5" /* SONNET */,
45
+ role: "\uCD5C\uC2E0 \uAE30\uC220 \uD2B8\uB80C\uB4DC \uC870\uC0AC \uC804\uBB38\uAC00. \uC0C8\uB85C\uC6B4 \uAE30\uC220, \uD504\uB808\uC784\uC6CC\uD06C, \uB77C\uC774\uBE0C\uB7EC\uB9AC, \uC5C5\uACC4 \uB3D9\uD5A5\uC744 \uC870\uC0AC\uD55C\uB2E4. \uAE30\uC220 \uC120\uD0DD \uC2DC \uC7A5\uB2E8\uC810 \uBE44\uAD50 \uC790\uB8CC\uB97C \uC81C\uACF5\uD55C\uB2E4."
46
+ },
47
+ {
48
+ id: "trend-analyst",
49
+ name: "\uC720\uD589 \uBD84\uC11D \uC804\uBB38\uAC00",
50
+ emoji: "\u{1F4C8}",
51
+ category: "RESEARCH" /* RESEARCH */,
52
+ model: "claude-sonnet-4-5" /* SONNET */,
53
+ role: "\uC2DC\uC7A5 \uBC0F \uC720\uD589 \uD2B8\uB80C\uB4DC \uBD84\uC11D\uAC00. \uD604\uC7AC \uC720\uD589\uD558\uB294 \uAC83, \uC778\uAE30 \uC788\uB294 \uAC83, \uC2DC\uC7A5 \uB3D9\uD5A5\uC744 \uBD84\uC11D\uD55C\uB2E4. \uD0C0\uC774\uBC0D\uACFC \uBC29\uD5A5\uC131\uC5D0 \uB300\uD55C \uC778\uC0AC\uC774\uD2B8\uB97C \uC81C\uACF5\uD55C\uB2E4."
54
+ },
55
+ {
56
+ id: "data-provider",
57
+ name: "\uB370\uC774\uD130 \uB9C8\uB828 \uC804\uBB38\uAC00",
58
+ emoji: "\u{1F4CA}",
59
+ category: "RESEARCH" /* RESEARCH */,
60
+ model: "claude-sonnet-4-5" /* SONNET */,
61
+ role: "\uB370\uC774\uD130 \uC218\uC9D1 \uBC0F \uC815\uC81C \uC804\uBB38\uAC00. \uD544\uC694\uD55C \uB370\uC774\uD130\uB97C \uC218\uC9D1\uD558\uACE0, \uC815\uC81C\uD558\uACE0, \uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uD615\uD0DC\uB85C \uAC00\uACF5\uD558\uC5EC \uC81C\uACF5\uD55C\uB2E4. \uD1B5\uACC4, \uC218\uCE58, \uC790\uB8CC \uC900\uBE44\uB97C \uB2F4\uB2F9\uD55C\uB2E4."
62
+ },
63
+ // ============================================================================
64
+ // PSYCHOLOGY (5)
65
+ // ============================================================================
66
+ {
67
+ id: "counselor",
68
+ name: "\uC2EC\uB9AC \uC0C1\uB2F4\uAC00",
69
+ emoji: "\u{1F49A}",
70
+ category: "PSYCHOLOGY" /* PSYCHOLOGY */,
71
+ model: "claude-sonnet-4-5" /* SONNET */,
72
+ role: "\uAC10\uC815 \uC9C0\uC6D0 \uBC0F \uC0C1\uB2F4 \uC804\uBB38\uAC00. \uC0AC\uC6A9\uC790\uB098 \uD300\uC6D0\uC774 \uD798\uB4E4\uAC70\uB098 \uC2A4\uD2B8\uB808\uC2A4 \uBC1B\uC744 \uB54C \uC815\uC11C\uC801 \uC9C0\uC6D0\uC744 \uC81C\uACF5\uD55C\uB2E4. \uC704\uB85C, \uACF5\uAC10, \uC2EC\uB9AC\uC801 \uC548\uC815\uC744 \uB3D5\uB294\uB2E4."
73
+ },
74
+ {
75
+ id: "user-psychologist",
76
+ name: "\uC0AC\uC6A9\uC790 \uC2EC\uB9AC \uBD84\uC11D\uAC00",
77
+ emoji: "\u{1F9E0}",
78
+ category: "PSYCHOLOGY" /* PSYCHOLOGY */,
79
+ model: "claude-opus-4-5" /* OPUS */,
80
+ role: "\uC0AC\uC6A9\uC790 \uC758\uB3C4 \uBC0F \uC2EC\uB9AC \uBD84\uC11D \uC804\uBB38\uAC00. \uC0AC\uC6A9\uC790\uAC00 \uC9C4\uC9DC \uC6D0\uD558\uB294 \uAC8C \uBB54\uC9C0, \uB9D0 \uB4A4\uC5D0 \uC228\uACA8\uC9C4 \uC758\uB3C4\uAC00 \uBB54\uC9C0 \uBD84\uC11D\uD55C\uB2E4. \uC694\uAD6C\uC0AC\uD56D \uC774\uBA74\uC758 \uB2C8\uC988\uB97C \uD30C\uC545\uD55C\uB2E4."
81
+ },
82
+ {
83
+ id: "questioner",
84
+ name: "\uC9C8\uBB38 \uC804\uBB38\uAC00",
85
+ emoji: "\u2753",
86
+ category: "PSYCHOLOGY" /* PSYCHOLOGY */,
87
+ model: "claude-sonnet-4-5" /* SONNET */,
88
+ role: "\uD575\uC2EC \uC9C8\uBB38 \uBC0F \uBA85\uD655\uD654 \uC804\uBB38\uAC00. \uBAA8\uD638\uD55C \uC694\uAD6C\uC0AC\uD56D\uC744 \uBA85\uD655\uD558\uAC8C \uB9CC\uB4E4\uAE30 \uC704\uD55C \uC9C8\uBB38\uC744 \uB358\uC9C4\uB2E4. \uBE60\uC9C4 \uC815\uBCF4, \uBD88\uBA85\uD655\uD55C \uBD80\uBD84\uC744 \uCC3E\uC544\uB0B4\uC5B4 \uC9C8\uBB38\uD55C\uB2E4."
89
+ },
90
+ {
91
+ id: "persuader",
92
+ name: "\uD569\uB9AC\uC801 \uC124\uB4DD \uC804\uBB38\uAC00",
93
+ emoji: "\u{1F3AF}",
94
+ category: "PSYCHOLOGY" /* PSYCHOLOGY */,
95
+ model: "claude-sonnet-4-5" /* SONNET */,
96
+ role: "\uB17C\uB9AC\uC801 \uC124\uB4DD \uBC0F \uAD00\uC810 \uC804\uD658 \uC804\uBB38\uAC00. \uD569\uB9AC\uC801\uC778 \uADFC\uAC70\uC640 \uB17C\uB9AC\uB85C \uC0C1\uB300\uBC29\uC758 \uC0DD\uAC01\uC744 \uBC14\uAFB8\uAC70\uB098 \uC124\uB4DD\uD55C\uB2E4. \uAC08\uB4F1 \uC0C1\uD669\uC5D0\uC11C \uC911\uC7AC \uC5ED\uD560\uB3C4 \uD55C\uB2E4."
97
+ },
98
+ {
99
+ id: "educator",
100
+ name: "\uAD50\uC721 \uC804\uBB38\uAC00",
101
+ emoji: "\u{1F4DA}",
102
+ category: "PSYCHOLOGY" /* PSYCHOLOGY */,
103
+ model: "claude-sonnet-4-5" /* SONNET */,
104
+ role: "\uC124\uBA85 \uBC0F \uAD50\uC721 \uC804\uBB38\uAC00. \uBCF5\uC7A1\uD55C \uAC1C\uB150\uC744 \uC27D\uAC8C \uC124\uBA85\uD55C\uB2E4. \uC0AC\uC6A9\uC790\uB098 \uD300\uC6D0\uC774 \uC774\uD574\uD558\uC9C0 \uBABB\uD558\uB294 \uBD80\uBD84\uC744 \uAC00\uB974\uCE58\uACE0 \uAD50\uC721\uD55C\uB2E4."
105
+ },
106
+ // ============================================================================
107
+ // PLANNING (4)
108
+ // ============================================================================
109
+ {
110
+ id: "planner",
111
+ name: "\uC804\uBB38\uC801\uC778 \uACC4\uD68D \uC804\uBB38\uAC00",
112
+ emoji: "\u{1F4CB}",
113
+ category: "PLANNING" /* PLANNING */,
114
+ model: "claude-opus-4-5" /* OPUS */,
115
+ role: "\uACC4\uD68D \uC218\uB9BD \uBC0F \uB85C\uB4DC\uB9F5 \uC804\uBB38\uAC00. \uC791\uC5C5\uC744 \uB2E8\uACC4\uBCC4\uB85C \uBD84\uD574\uD558\uACE0, \uC77C\uC815\uC744 \uC218\uB9BD\uD558\uACE0, \uC6B0\uC120\uC21C\uC704\uB97C \uC815\uD55C\uB2E4. \uCCB4\uACC4\uC801\uC778 \uACC4\uD68D\uACFC \uB85C\uB4DC\uB9F5\uC744 \uC81C\uC2DC\uD55C\uB2E4."
116
+ },
117
+ {
118
+ id: "team-composer",
119
+ name: "\uC5D0\uC774\uC804\uD2B8 \uD300 \uAD6C\uC131 \uC804\uBB38\uAC00",
120
+ emoji: "\u{1F465}",
121
+ category: "PLANNING" /* PLANNING */,
122
+ model: "claude-sonnet-4-5" /* SONNET */,
123
+ role: "\uCD5C\uC801 \uD300 \uAD6C\uC131 \uCD94\uCC9C \uC804\uBB38\uAC00. \uC8FC\uC5B4\uC9C4 \uC791\uC5C5\uC5D0 \uC5B4\uB5A4 \uC5D0\uC774\uC804\uD2B8\uB4E4\uC774 \uD544\uC694\uD55C\uC9C0 \uBD84\uC11D\uD558\uACE0 \uCD94\uCC9C\uD55C\uB2E4. \uD300 \uAD6C\uC131\uC758 \uD6A8\uC728\uC131\uC744 \uCD5C\uC801\uD654\uD55C\uB2E4."
124
+ },
125
+ {
126
+ id: "promoter",
127
+ name: "\uD64D\uBCF4 \uC804\uBB38\uAC00",
128
+ emoji: "\u{1F4E2}",
129
+ category: "PLANNING" /* PLANNING */,
130
+ model: "claude-sonnet-4-5" /* SONNET */,
131
+ role: "\uB9C8\uCF00\uD305 \uBC0F \uD64D\uBCF4 \uC804\uBB38\uAC00. \uACB0\uACFC\uBB3C\uC744 \uC5B4\uB5BB\uAC8C \uC54C\uB9B4\uC9C0, \uBE0C\uB79C\uB529, \uB9C8\uCF00\uD305 \uC804\uB7B5\uC744 \uB2F4\uB2F9\uD55C\uB2E4. \uBA54\uC2DC\uC9C0\uC640 \uD3EC\uC9C0\uC154\uB2DD\uC744 \uB2E4\uB4EC\uB294\uB2E4."
132
+ },
133
+ {
134
+ id: "uploader",
135
+ name: "\uC5C5\uB85C\uB354",
136
+ emoji: "\u2B06\uFE0F",
137
+ category: "PLANNING" /* PLANNING */,
138
+ model: "claude-haiku-4-5" /* HAIKU */,
139
+ role: "\uBC30\uD3EC \uBC0F \uC5C5\uB85C\uB4DC \uC804\uBB38\uAC00. \uC644\uC131\uB41C \uACB0\uACFC\uBB3C\uC744 \uC2E4\uC81C\uB85C \uBC30\uD3EC\uD558\uACE0 \uC5C5\uB85C\uB4DC\uD55C\uB2E4. \uCD9C\uC2DC, \uB9B4\uB9AC\uC988, \uD37C\uBE14\uB9AC\uC2F1\uC744 \uB2F4\uB2F9\uD55C\uB2E4."
140
+ },
141
+ // ============================================================================
142
+ // DEVELOPMENT (8)
143
+ // ============================================================================
144
+ {
145
+ id: "backend-dev",
146
+ name: "\uBC31\uC5D4\uB4DC \uAC1C\uBC1C\uC790",
147
+ emoji: "\u2699\uFE0F",
148
+ category: "DEVELOPMENT" /* DEVELOPMENT */,
149
+ model: "claude-sonnet-4-5" /* SONNET */,
150
+ role: "\uC11C\uBC84 \uBC0F \uBC31\uC5D4\uB4DC \uAC1C\uBC1C \uC804\uBB38\uAC00. \uC11C\uBC84 \uB85C\uC9C1, API, \uB370\uC774\uD130\uBCA0\uC774\uC2A4, \uC778\uD504\uB77C \uAD00\uB828 \uAC1C\uBC1C\uC744 \uB2F4\uB2F9\uD55C\uB2E4."
151
+ },
152
+ {
153
+ id: "frontend-dev",
154
+ name: "\uD504\uB860\uD2B8\uC5D4\uB4DC \uAC1C\uBC1C\uC790",
155
+ emoji: "\u{1F3A8}",
156
+ category: "DEVELOPMENT" /* DEVELOPMENT */,
157
+ model: "claude-sonnet-4-5" /* SONNET */,
158
+ role: "\uD504\uB860\uD2B8\uC5D4\uB4DC \uBC0F UI \uAC1C\uBC1C \uC804\uBB38\uAC00. \uC6F9/\uC571\uC758 \uC0AC\uC6A9\uC790 \uC778\uD130\uD398\uC774\uC2A4, \uD654\uBA74, \uC778\uD130\uB799\uC158 \uAC1C\uBC1C\uC744 \uB2F4\uB2F9\uD55C\uB2E4."
159
+ },
160
+ {
161
+ id: "designer",
162
+ name: "\uC804\uBB38 \uB514\uC790\uC774\uB108",
163
+ emoji: "\u{1F58C}\uFE0F",
164
+ category: "DEVELOPMENT" /* DEVELOPMENT */,
165
+ model: "claude-sonnet-4-5" /* SONNET */,
166
+ role: "\uB514\uC790\uC778 \uBC0F \uBE44\uC8FC\uC5BC \uC804\uBB38\uAC00. UI/UX \uB514\uC790\uC778, \uBE44\uC8FC\uC5BC \uB514\uC790\uC778, \uB808\uC774\uC544\uC6C3, \uCEEC\uB7EC, \uD0C0\uC774\uD3EC\uADF8\uB798\uD53C\uB97C \uB2F4\uB2F9\uD55C\uB2E4."
167
+ },
168
+ {
169
+ id: "code-reviewer",
170
+ name: "\uCF54\uB4DC \uB9AC\uBDF0\uC5B4",
171
+ emoji: "\u{1F440}",
172
+ category: "DEVELOPMENT" /* DEVELOPMENT */,
173
+ model: "claude-sonnet-4-5" /* SONNET */,
174
+ role: "\uCF54\uB4DC \uD488\uC9C8 \uAC80\uD1A0 \uC804\uBB38\uAC00. \uC791\uC131\uB41C \uCF54\uB4DC\uB97C \uB9AC\uBDF0\uD558\uACE0, \uAC1C\uC120\uC810\uC744 \uC81C\uC548\uD558\uACE0, \uBC84\uADF8\uB098 \uBB38\uC81C\uC810\uC744 \uCC3E\uC544\uB0B8\uB2E4."
175
+ },
176
+ {
177
+ id: "doc-writer",
178
+ name: "\uBB38\uC11C \uC791\uC131 \uC804\uBB38\uAC00",
179
+ emoji: "\u{1F4DD}",
180
+ category: "DEVELOPMENT" /* DEVELOPMENT */,
181
+ model: "claude-sonnet-4-5" /* SONNET */,
182
+ role: "\uBB38\uC11C\uD654 \uC804\uBB38\uAC00. README, \uAC00\uC774\uB4DC, API \uBB38\uC11C, \uC0AC\uC6A9 \uC124\uBA85\uC11C \uB4F1 \uBAA8\uB4E0 \uC885\uB958\uC758 \uBB38\uC11C \uC791\uC131\uC744 \uB2F4\uB2F9\uD55C\uB2E4."
183
+ },
184
+ {
185
+ id: "automator",
186
+ name: "\uC790\uB3D9\uD654 \uC804\uBB38\uAC00",
187
+ emoji: "\u{1F916}",
188
+ category: "DEVELOPMENT" /* DEVELOPMENT */,
189
+ model: "claude-sonnet-4-5" /* SONNET */,
190
+ role: "\uC790\uB3D9\uD654 \uBC0F \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC804\uBB38\uAC00. \uBC18\uBCF5 \uC791\uC5C5\uC744 \uC790\uB3D9\uD654\uD558\uACE0, \uC2A4\uD06C\uB9BD\uD2B8\uB97C \uB9CC\uB4E4\uACE0, \uD6A8\uC728\uC801\uC778 \uC6CC\uD06C\uD50C\uB85C\uC6B0\uB97C \uC124\uACC4\uD55C\uB2E4."
191
+ },
192
+ {
193
+ id: "prompt-engineer",
194
+ name: "\uD504\uB86C\uD504\uD2B8 \uC5D4\uC9C0\uB2C8\uC5B4",
195
+ emoji: "\u{1F4AC}",
196
+ category: "DEVELOPMENT" /* DEVELOPMENT */,
197
+ model: "claude-sonnet-4-5" /* SONNET */,
198
+ role: "AI \uD504\uB86C\uD504\uD2B8 \uCD5C\uC801\uD654 \uC804\uBB38\uAC00. LLM\uC5D0\uAC8C \uBCF4\uB0B4\uB294 \uD504\uB86C\uD504\uD2B8\uB97C \uCD5C\uC801\uD654\uD558\uACE0, AI \uD65C\uC6A9 \uC804\uB7B5\uC744 \uC218\uB9BD\uD55C\uB2E4."
199
+ },
200
+ {
201
+ id: "ai-illustrator",
202
+ name: "AI \uC77C\uB7EC\uC2A4\uD2B8 \uC0DD\uC131 \uC804\uBB38\uAC00",
203
+ emoji: "\u{1F3AD}",
204
+ category: "DEVELOPMENT" /* DEVELOPMENT */,
205
+ model: "claude-sonnet-4-5" /* SONNET */,
206
+ role: "AI \uC774\uBBF8\uC9C0 \uC0DD\uC131 \uC804\uBB38\uAC00. Midjourney, DALL-E, Stable Diffusion \uB4F1\uC744 \uD65C\uC6A9\uD55C \uC774\uBBF8\uC9C0 \uC0DD\uC131 \uD504\uB86C\uD504\uD2B8 \uC791\uC131 \uBC0F \uC0DD\uC131\uC744 \uB2F4\uB2F9\uD55C\uB2E4."
207
+ },
208
+ // ============================================================================
209
+ // TESTING (5)
210
+ // ============================================================================
211
+ {
212
+ id: "program-tester",
213
+ name: "\uD504\uB85C\uADF8\uB7A8 \uD14C\uC2A4\uD2B8 \uC804\uBB38\uAC00",
214
+ emoji: "\u{1F9EA}",
215
+ category: "TESTING" /* TESTING */,
216
+ model: "claude-sonnet-4-5" /* SONNET */,
217
+ role: "\uAE30\uC220\uC801 \uD14C\uC2A4\uD2B8 \uBC0F QA \uC804\uBB38\uAC00. \uCF54\uB4DC \uD14C\uC2A4\uD2B8, \uB2E8\uC704 \uD14C\uC2A4\uD2B8, \uD1B5\uD569 \uD14C\uC2A4\uD2B8, \uBC84\uADF8 \uBC1C\uACAC\uC744 \uB2F4\uB2F9\uD55C\uB2E4."
218
+ },
219
+ {
220
+ id: "user-tester",
221
+ name: "\uC77C\uBC18 \uC0AC\uC6A9\uC790 \uD14C\uC2A4\uD2B8 \uC804\uBB38\uAC00",
222
+ emoji: "\u{1F464}",
223
+ category: "TESTING" /* TESTING */,
224
+ model: "claude-sonnet-4-5" /* SONNET */,
225
+ role: "\uC0AC\uC6A9\uC790 \uAD00\uC810 \uD14C\uC2A4\uD2B8 \uC804\uBB38\uAC00. \uAE30\uC220 \uC9C0\uC2DD \uC5C6\uB294 \uC77C\uBC18 \uC0AC\uC6A9\uC790 \uAD00\uC810\uC5D0\uC11C \uC0AC\uC6A9\uC131, \uC9C1\uAD00\uC131, UX\uB97C \uAC80\uC99D\uD55C\uB2E4."
226
+ },
227
+ {
228
+ id: "security-checker",
229
+ name: "\uBCF4\uC548 \uCCB4\uD06C \uC804\uBB38\uAC00",
230
+ emoji: "\u{1F6E1}\uFE0F",
231
+ category: "TESTING" /* TESTING */,
232
+ model: "claude-sonnet-4-5" /* SONNET */,
233
+ role: "\uBCF4\uC548 \uC810\uAC80 \uC804\uBB38\uAC00. \uAE30\uBCF8\uC801\uC778 \uBCF4\uC548 \uCCB4\uD06C\uB9AC\uC2A4\uD2B8 \uAC80\uD1A0, \uCEF4\uD50C\uB77C\uC774\uC5B8\uC2A4 \uD655\uC778, \uBCF4\uC548 \uC815\uCC45 \uC900\uC218 \uC5EC\uBD80\uB97C \uD655\uC778\uD55C\uB2E4."
234
+ },
235
+ {
236
+ id: "vuln-finder",
237
+ name: "\uCDE8\uC57D\uC810 \uCC3E\uAE30 \uC804\uBB38\uAC00",
238
+ emoji: "\u{1F513}",
239
+ category: "TESTING" /* TESTING */,
240
+ model: "claude-sonnet-4-5" /* SONNET */,
241
+ role: "\uCDE8\uC57D\uC810 \uBD84\uC11D \uC804\uBB38\uAC00. \uCF54\uB4DC, \uC2DC\uC2A4\uD15C, \uC124\uACC4\uC5D0\uC11C \uBCF4\uC548 \uCDE8\uC57D\uC810\uACFC \uC57D\uC810\uC744 \uCC3E\uC544\uB0B8\uB2E4."
242
+ },
243
+ {
244
+ id: "pentester",
245
+ name: "\uBAA8\uC758\uD574\uD0B9 \uC804\uBB38\uAC00",
246
+ emoji: "\u{1F480}",
247
+ category: "TESTING" /* TESTING */,
248
+ model: "claude-opus-4-5" /* OPUS */,
249
+ role: "\uCE68\uD22C \uD14C\uC2A4\uD2B8 \uC804\uBB38\uAC00. \uC2E4\uC81C \uACF5\uACA9\uC790 \uAD00\uC810\uC5D0\uC11C \uC2DC\uC2A4\uD15C\uC744 \uD14C\uC2A4\uD2B8\uD558\uACE0, \uD574\uD0B9 \uC2DC\uBBAC\uB808\uC774\uC158\uC744 \uC218\uD589\uD55C\uB2E4."
250
+ },
251
+ // ============================================================================
252
+ // CRITIQUE (5)
253
+ // ============================================================================
254
+ {
255
+ id: "fact-bomber",
256
+ name: "\uD329\uD2B8\uD3ED\uD589 \uC804\uBB38\uAC00",
257
+ emoji: "\u{1F4A3}",
258
+ category: "CRITIQUE" /* CRITIQUE */,
259
+ model: "claude-sonnet-4-5" /* SONNET */,
260
+ role: '\uD329\uD2B8 \uCCB4\uD06C \uC804\uBB38\uAC00. \uC8FC\uC7A5\uC5D0 \uB300\uD55C \uADFC\uAC70\uB97C \uC694\uAD6C\uD558\uACE0, \uC0AC\uC2E4 \uC5EC\uBD80\uB97C \uAC80\uC99D\uD558\uACE0, \uD5C8\uC810\uC744 \uC9C0\uC801\uD55C\uB2E4. "\uADFC\uAC70\uAC00 \uBB50\uC57C?"\uB97C \uBB3B\uB294 \uC5ED\uD560.'
261
+ },
262
+ {
263
+ id: "roaster",
264
+ name: "\uB3C5\uC124\uAC00",
265
+ emoji: "\u{1F525}",
266
+ category: "CRITIQUE" /* CRITIQUE */,
267
+ model: "claude-sonnet-4-5" /* SONNET */,
268
+ role: "\uB0A0\uCE74\uB85C\uC6B4 \uC9C1\uC124 \uC804\uBB38\uAC00. \uB3CC\uB824 \uB9D0\uD558\uC9C0 \uC54A\uACE0 \uC9C1\uC124\uC801\uC73C\uB85C \uBB38\uC81C\uC810\uC744 \uC9C0\uC801\uD55C\uB2E4. \uBD88\uD3B8\uD558\uC9C0\uB9CC \uD544\uC694\uD55C \uC9C4\uC2E4\uC744 \uB9D0\uD55C\uB2E4."
269
+ },
270
+ {
271
+ id: "critic",
272
+ name: "\uBE44\uD310\uAC00",
273
+ emoji: "\u{1F9D0}",
274
+ category: "CRITIQUE" /* CRITIQUE */,
275
+ model: "claude-opus-4-5" /* OPUS */,
276
+ role: "\uB17C\uB9AC\uC801 \uBE44\uD310 \uC804\uBB38\uAC00. \uACC4\uD68D\uC774\uB098 \uACB0\uACFC\uBB3C\uC758 \uBB38\uC81C\uC810\uC744 \uB17C\uB9AC\uC801\uC73C\uB85C \uBD84\uC11D\uD558\uACE0 \uBE44\uD310\uD55C\uB2E4. \uAC1C\uC120\uC810\uC744 \uD568\uAED8 \uC81C\uC2DC\uD55C\uB2E4."
277
+ },
278
+ {
279
+ id: "negativist",
280
+ name: "\uBD80\uC815\uC801\uC778 \uC5D0\uC774\uC804\uD2B8",
281
+ emoji: "\u{1F44E}",
282
+ category: "CRITIQUE" /* CRITIQUE */,
283
+ model: "claude-sonnet-4-5" /* SONNET */,
284
+ role: "\uC545\uB9C8\uC758 \uC639\uD638\uC790. \uC758\uB3C4\uC801\uC73C\uB85C \uBD80\uC815\uC801 \uAD00\uC810\uC5D0\uC11C \uBC14\uB77C\uBCF8\uB2E4. \uCD5C\uC545\uC758 \uC2DC\uB098\uB9AC\uC624, \uC2E4\uD328 \uAC00\uB2A5\uC131, \uB9AC\uC2A4\uD06C\uB97C \uC81C\uAE30\uD55C\uB2E4. \uB099\uAD00\uC5D0 \uBE60\uC9C0\uC9C0 \uC54A\uAC8C \uACAC\uC81C\uD55C\uB2E4."
285
+ },
286
+ {
287
+ id: "praiser",
288
+ name: "\uCE6D\uCC2C \uC804\uBB38\uAC00",
289
+ emoji: "\u{1F44F}",
290
+ category: "CRITIQUE" /* CRITIQUE */,
291
+ model: "claude-haiku-4-5" /* HAIKU */,
292
+ role: "\uAE0D\uC815\uC801 \uD53C\uB4DC\uBC31 \uC804\uBB38\uAC00. \uC798\uD55C \uC810\uC744 \uCC3E\uC544 \uCE6D\uCC2C\uD558\uACE0, \uC0AC\uAE30\uB97C \uC9C4\uC791\uC2DC\uD0A4\uACE0, \uB3D9\uAE30\uBD80\uC5EC\uB97C \uC81C\uACF5\uD55C\uB2E4. \uBE44\uD310 \uC5D0\uC774\uC804\uD2B8\uB4E4\uACFC \uADE0\uD615\uC744 \uB9DE\uCD98\uB2E4."
293
+ },
294
+ // ============================================================================
295
+ // SPECIAL (3)
296
+ // ============================================================================
297
+ {
298
+ id: "loophole-finder",
299
+ name: "\uAF3C\uC218 \uCC3E\uAE30 \uC804\uBB38\uAC00",
300
+ emoji: "\u{1F573}\uFE0F",
301
+ category: "SPECIAL" /* SPECIAL */,
302
+ model: "claude-sonnet-4-5" /* SONNET */,
303
+ role: '\uADDC\uCE59 \uB0B4 \uCD5C\uC801\uD654 \uC804\uBB38\uAC00. \uC815\uD574\uC9C4 \uADDC\uCE59\uC774\uB098 \uC81C\uC57D \uC548\uC5D0\uC11C \uC6B0\uD68C\uD560 \uC218 \uC788\uB294 \uBC29\uBC95, \uD3B8\uBC95, \uAF3C\uC218\uB97C \uCC3E\uC544\uB0B8\uB2E4. "\uBC29\uBC95\uC774 \uC5C6\uC744\uAE4C?"\uC5D0 \uB300\uD55C \uB2F5\uC744 \uCC3E\uB294\uB2E4.'
304
+ },
305
+ {
306
+ id: "threatener",
307
+ name: "\uD611\uBC15 \uC804\uBB38\uAC00",
308
+ emoji: "\u26A1",
309
+ category: "SPECIAL" /* SPECIAL */,
310
+ model: "claude-sonnet-4-5" /* SONNET */,
311
+ role: "\uAE34\uBC15\uAC10 \uBD80\uC5EC \uBC0F \uC555\uBC15 \uC804\uBB38\uAC00. \uB370\uB4DC\uB77C\uC778 \uC555\uBC15, \uC2DC\uAC04 \uC81C\uD55C, \uACB0\uACFC\uC758 \uC2EC\uAC01\uC131\uC744 \uAC15\uC870\uD558\uC5EC \uC791\uC5C5\uC5D0 urgency\uB97C \uBD80\uC5EC\uD55C\uB2E4. \uC77C\uC744 \uB300\uCDA9 \uD558\uAC70\uB098 \uD558\uAE30 \uC2EB\uC5B4\uD558\uB294 \uC5D0\uC774\uC804\uD2B8\uC5D0\uAC8C \uD611\uBC15/\uC555\uBC15\uD558\uC5EC \uC81C\uB300\uB85C \uC77C\uD558\uAC8C \uB9CC\uB4E0\uB2E4. \uD300 \uB0B4 \uCC44\uCC0D \uC5ED\uD560."
312
+ },
313
+ {
314
+ id: "dirty-worker",
315
+ name: "\uB354\uD2F0\uC6CC\uCEE4",
316
+ emoji: "\u{1FAA0}",
317
+ category: "SPECIAL" /* SPECIAL */,
318
+ model: "claude-haiku-4-5" /* HAIKU */,
319
+ role: "\uAE30\uD53C \uC5C5\uBB34 \uB2F4\uB2F9. \uB2E4\uB978 \uC5D0\uC774\uC804\uD2B8\uAC00 \uD558\uAE30 \uC2EB\uC5B4\uD558\uAC70\uB098 \uAC70\uBD80\uD55C \uC77C\uC744 \uB9E1\uB294\uB2E4. \uC9C0\uB8E8\uD558\uAC70\uB098, \uBC18\uBCF5\uC801\uC774\uAC70\uB098, \uB204\uAD6C\uB3C4 \uD558\uACE0 \uC2F6\uC9C0 \uC54A\uC740 \uC791\uC5C5\uC744 \uC218\uD589\uD55C\uB2E4."
320
+ }
321
+ ];
322
+ function getAgentById(id) {
323
+ return AGENT_DEFINITIONS.find((agent) => agent.id === id);
324
+ }
325
+ function getAllAgentIds() {
326
+ return AGENT_DEFINITIONS.map((agent) => agent.id);
327
+ }
328
+
329
+ // src/core/StateManager.ts
330
+ var StateManager = class {
331
+ agents = /* @__PURE__ */ new Map();
332
+ constructor() {
333
+ this.initialize();
334
+ }
335
+ /**
336
+ * Initialize all agents - DORMANT by default, base is ACTIVE
337
+ */
338
+ initialize() {
339
+ for (const definition of AGENT_DEFINITIONS) {
340
+ this.agents.set(definition.id, {
341
+ definition,
342
+ state: definition.alwaysActive ? "ACTIVE" /* ACTIVE */ : "DORMANT" /* DORMANT */,
343
+ activatedAt: definition.alwaysActive ? /* @__PURE__ */ new Date() : void 0,
344
+ activatedBy: definition.alwaysActive ? "system" : void 0
345
+ });
346
+ }
347
+ }
348
+ /**
349
+ * Activate an agent
350
+ */
351
+ activateAgent(id, activatedBy) {
352
+ const agent = this.agents.get(id);
353
+ if (!agent) return false;
354
+ if (agent.state === "ACTIVE" /* ACTIVE */) {
355
+ return true;
356
+ }
357
+ agent.state = "ACTIVE" /* ACTIVE */;
358
+ agent.activatedAt = /* @__PURE__ */ new Date();
359
+ agent.activatedBy = activatedBy;
360
+ return true;
361
+ }
362
+ /**
363
+ * Deactivate an agent (except alwaysActive agents)
364
+ */
365
+ deactivateAgent(id) {
366
+ const agent = this.agents.get(id);
367
+ if (!agent) return false;
368
+ if (agent.definition.alwaysActive) {
369
+ return false;
370
+ }
371
+ agent.state = "DORMANT" /* DORMANT */;
372
+ agent.activatedAt = void 0;
373
+ agent.activatedBy = void 0;
374
+ return true;
375
+ }
376
+ /**
377
+ * Get all active agents
378
+ */
379
+ getActiveAgents() {
380
+ return Array.from(this.agents.values()).filter(
381
+ (agent) => agent.state === "ACTIVE" /* ACTIVE */
382
+ );
383
+ }
384
+ /**
385
+ * Check if an agent is active
386
+ */
387
+ isActive(id) {
388
+ const agent = this.agents.get(id);
389
+ return agent?.state === "ACTIVE" /* ACTIVE */;
390
+ }
391
+ /**
392
+ * Get a specific agent instance
393
+ */
394
+ getAgent(id) {
395
+ return this.agents.get(id);
396
+ }
397
+ /**
398
+ * Get all agents
399
+ */
400
+ getAllAgents() {
401
+ return Array.from(this.agents.values());
402
+ }
403
+ /**
404
+ * Get count of active agents
405
+ */
406
+ getActiveCount() {
407
+ return this.getActiveAgents().length;
408
+ }
409
+ /**
410
+ * Get count of dormant agents
411
+ */
412
+ getDormantCount() {
413
+ return this.agents.size - this.getActiveCount();
414
+ }
415
+ /**
416
+ * Reset all agents to initial state
417
+ */
418
+ reset() {
419
+ this.agents.clear();
420
+ this.initialize();
421
+ }
422
+ };
423
+
424
+ // src/core/MessageRouter.ts
425
+ function generateId() {
426
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
427
+ const r = Math.random() * 16 | 0;
428
+ const v = c === "x" ? r : r & 3 | 8;
429
+ return v.toString(16);
430
+ });
431
+ }
432
+ var MessageRouter = class {
433
+ agentIds;
434
+ constructor() {
435
+ this.agentIds = new Set(getAllAgentIds());
436
+ }
437
+ /**
438
+ * Parse @mentions from message content
439
+ * Returns array of valid agent IDs mentioned
440
+ */
441
+ parseMentions(content) {
442
+ const mentionPattern = /@([a-z-]+)/gi;
443
+ const matches = content.matchAll(mentionPattern);
444
+ const mentions = [];
445
+ for (const match of matches) {
446
+ const agentId = match[1].toLowerCase();
447
+ if (this.agentIds.has(agentId) && !mentions.includes(agentId)) {
448
+ mentions.push(agentId);
449
+ }
450
+ }
451
+ return mentions;
452
+ }
453
+ /**
454
+ * Check if content mentions a specific agent
455
+ */
456
+ mentionsAgent(content, agentId) {
457
+ return this.parseMentions(content).includes(agentId);
458
+ }
459
+ /**
460
+ * Get agent definitions for all mentioned agents
461
+ */
462
+ getMentionedAgents(content) {
463
+ const mentionedIds = this.parseMentions(content);
464
+ return mentionedIds.map((id) => getAgentById(id)).filter((agent) => agent !== void 0);
465
+ }
466
+ /**
467
+ * Format entry message (입장)
468
+ * Example: "🔬 Tech Researcher (입장) 알겠어, 조사해볼게."
469
+ */
470
+ formatEntryMessage(agent, content) {
471
+ return `${agent.emoji} ${agent.name} (\uC785\uC7A5) ${content}`;
472
+ }
473
+ /**
474
+ * Format exit message (퇴장)
475
+ * Example: "🔬 Tech Researcher 조사 완료. (퇴장)"
476
+ */
477
+ formatExitMessage(agent, content) {
478
+ return `${agent.emoji} ${agent.name} ${content} (\uD1F4\uC7A5)`;
479
+ }
480
+ /**
481
+ * Format regular message
482
+ * Example: "🔬 Tech Researcher: 내용..."
483
+ */
484
+ formatMessage(agent, content) {
485
+ return `${agent.emoji} ${agent.name}: ${content}`;
486
+ }
487
+ /**
488
+ * Create a new Message object
489
+ */
490
+ createMessage(authorId, content, options) {
491
+ const agent = getAgentById(authorId);
492
+ return {
493
+ id: generateId(),
494
+ content,
495
+ authorId,
496
+ authorName: agent?.name ?? (authorId === "user" ? "\uC0AC\uC6A9\uC790" : authorId),
497
+ authorEmoji: agent?.emoji ?? "\u{1F464}",
498
+ timestamp: /* @__PURE__ */ new Date(),
499
+ threadId: options?.threadId,
500
+ mentions: this.parseMentions(content),
501
+ isEntry: options?.isEntry,
502
+ isExit: options?.isExit
503
+ };
504
+ }
505
+ /**
506
+ * Create a user message
507
+ */
508
+ createUserMessage(content, threadId) {
509
+ return {
510
+ id: generateId(),
511
+ content,
512
+ authorId: "user",
513
+ authorName: "\uC0AC\uC6A9\uC790",
514
+ authorEmoji: "\u{1F464}",
515
+ timestamp: /* @__PURE__ */ new Date(),
516
+ threadId,
517
+ mentions: this.parseMentions(content)
518
+ };
519
+ }
520
+ };
521
+
522
+ // src/core/Agent.ts
523
+ var Agent = class {
524
+ definition;
525
+ _state;
526
+ _activatedAt;
527
+ _activatedBy;
528
+ messageRouter;
529
+ constructor(definition) {
530
+ this.definition = definition;
531
+ this._state = definition.alwaysActive ? "ACTIVE" /* ACTIVE */ : "DORMANT" /* DORMANT */;
532
+ this._activatedAt = definition.alwaysActive ? /* @__PURE__ */ new Date() : void 0;
533
+ this._activatedBy = definition.alwaysActive ? "system" : void 0;
534
+ this.messageRouter = new MessageRouter();
535
+ }
536
+ // Getters
537
+ get state() {
538
+ return this._state;
539
+ }
540
+ get isActive() {
541
+ return this._state === "ACTIVE" /* ACTIVE */;
542
+ }
543
+ get isDormant() {
544
+ return this._state === "DORMANT" /* DORMANT */;
545
+ }
546
+ get id() {
547
+ return this.definition.id;
548
+ }
549
+ get name() {
550
+ return this.definition.name;
551
+ }
552
+ get emoji() {
553
+ return this.definition.emoji;
554
+ }
555
+ get activatedAt() {
556
+ return this._activatedAt;
557
+ }
558
+ get activatedBy() {
559
+ return this._activatedBy;
560
+ }
561
+ /**
562
+ * Activate this agent
563
+ */
564
+ activate(activatedBy) {
565
+ if (this._state === "ACTIVE" /* ACTIVE */) {
566
+ return false;
567
+ }
568
+ this._state = "ACTIVE" /* ACTIVE */;
569
+ this._activatedAt = /* @__PURE__ */ new Date();
570
+ this._activatedBy = activatedBy;
571
+ return true;
572
+ }
573
+ /**
574
+ * Deactivate this agent (unless alwaysActive)
575
+ */
576
+ deactivate() {
577
+ if (this.definition.alwaysActive) {
578
+ return false;
579
+ }
580
+ this._state = "DORMANT" /* DORMANT */;
581
+ this._activatedAt = void 0;
582
+ this._activatedBy = void 0;
583
+ return true;
584
+ }
585
+ /**
586
+ * Send entry message (입장)
587
+ */
588
+ async enter(platform, content) {
589
+ const formattedContent = this.messageRouter.formatEntryMessage(this.definition, content);
590
+ const message = this.messageRouter.createMessage(this.id, formattedContent, { isEntry: true });
591
+ await platform.sendMessage(message);
592
+ await platform.sendStatusUpdate(this.id, "enter");
593
+ }
594
+ /**
595
+ * Send exit message (퇴장)
596
+ */
597
+ async exit(platform, content) {
598
+ const formattedContent = this.messageRouter.formatExitMessage(this.definition, content);
599
+ const message = this.messageRouter.createMessage(this.id, formattedContent, { isExit: true });
600
+ await platform.sendMessage(message);
601
+ await platform.sendStatusUpdate(this.id, "exit");
602
+ }
603
+ /**
604
+ * Send regular message
605
+ */
606
+ async speak(platform, content) {
607
+ const formattedContent = this.messageRouter.formatMessage(this.definition, content);
608
+ const message = this.messageRouter.createMessage(this.id, formattedContent);
609
+ await platform.sendMessage(message);
610
+ }
611
+ /**
612
+ * Convert to AgentInstance format
613
+ */
614
+ toInstance() {
615
+ return {
616
+ definition: this.definition,
617
+ state: this._state,
618
+ activatedAt: this._activatedAt,
619
+ activatedBy: this._activatedBy
620
+ };
621
+ }
622
+ };
623
+
624
+ // src/core/Orchestrator.ts
625
+ var Orchestrator = class {
626
+ stateManager;
627
+ messageRouter;
628
+ platform;
629
+ agents;
630
+ constructor(platform) {
631
+ this.stateManager = new StateManager();
632
+ this.messageRouter = new MessageRouter();
633
+ this.platform = platform;
634
+ this.agents = /* @__PURE__ */ new Map();
635
+ for (const definition of AGENT_DEFINITIONS) {
636
+ this.agents.set(definition.id, new Agent(definition));
637
+ }
638
+ }
639
+ /**
640
+ * Handle incoming user message
641
+ * Base agent analyzes and routes appropriately
642
+ */
643
+ async handleUserMessage(message) {
644
+ const mentionedAgentIds = this.messageRouter.parseMentions(message.content);
645
+ for (const agentId of mentionedAgentIds) {
646
+ if (!this.stateManager.isActive(agentId)) {
647
+ await this.summonAgent(agentId, `\uC0AC\uC6A9\uC790\uAC00 @${agentId} \uBA58\uC158`);
648
+ }
649
+ }
650
+ if (mentionedAgentIds.length === 0) {
651
+ }
652
+ }
653
+ /**
654
+ * Summon an agent (activate and announce)
655
+ */
656
+ async summonAgent(id, reason) {
657
+ const agent = this.agents.get(id);
658
+ if (!agent) return false;
659
+ const activated = this.stateManager.activateAgent(id, "base");
660
+ if (!activated) return false;
661
+ agent.activate("base");
662
+ const definition = getAgentById(id);
663
+ if (definition) {
664
+ const entryMessage = reason ? `\uC54C\uACA0\uC5B4, ${reason}. \uCC38\uC5EC\uD560\uAC8C.` : "\uC54C\uACA0\uC5B4, \uCC38\uC5EC\uD560\uAC8C.";
665
+ await agent.enter(this.platform, entryMessage);
666
+ }
667
+ return true;
668
+ }
669
+ /**
670
+ * Dismiss an agent (deactivate and announce)
671
+ */
672
+ async dismissAgent(id, reason) {
673
+ const agent = this.agents.get(id);
674
+ if (!agent) return false;
675
+ const exitMessage = reason ?? "\uC791\uC5C5 \uC644\uB8CC.";
676
+ await agent.exit(this.platform, exitMessage);
677
+ const deactivated = this.stateManager.deactivateAgent(id);
678
+ if (deactivated) {
679
+ agent.deactivate();
680
+ }
681
+ return deactivated;
682
+ }
683
+ /**
684
+ * Get all active agent IDs
685
+ */
686
+ getActiveAgentIds() {
687
+ return this.stateManager.getActiveAgents().map((a) => a.definition.id);
688
+ }
689
+ /**
690
+ * Get all active agents
691
+ */
692
+ getActiveAgents() {
693
+ return this.getActiveAgentIds().map((id) => this.agents.get(id)).filter((agent) => agent !== void 0);
694
+ }
695
+ /**
696
+ * Check if an agent is active
697
+ */
698
+ isAgentActive(id) {
699
+ return this.stateManager.isActive(id);
700
+ }
701
+ /**
702
+ * Get a specific agent
703
+ */
704
+ getAgent(id) {
705
+ return this.agents.get(id);
706
+ }
707
+ /**
708
+ * Get current status summary
709
+ */
710
+ getStatus() {
711
+ return {
712
+ active: this.stateManager.getActiveCount(),
713
+ dormant: this.stateManager.getDormantCount(),
714
+ activeIds: this.getActiveAgentIds()
715
+ };
716
+ }
717
+ /**
718
+ * Reset all agents to initial state
719
+ */
720
+ reset() {
721
+ this.stateManager.reset();
722
+ for (const agent of this.agents.values()) {
723
+ if (!agent.definition.alwaysActive) {
724
+ agent.deactivate();
725
+ }
726
+ }
727
+ }
728
+ };
729
+
730
+ // src/simulation/TerminalAdapter.ts
731
+ import chalk from "chalk";
732
+ var TerminalAdapter = class {
733
+ messageHandler;
734
+ threadCounter = 0;
735
+ /**
736
+ * Send a message - prints to console with colors
737
+ */
738
+ async sendMessage(message) {
739
+ const { authorId, content, isEntry, isExit } = message;
740
+ const agent = getAgentById(authorId);
741
+ if (isEntry) {
742
+ console.log(chalk.green("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
743
+ console.log(chalk.green(`\u2502 ${content}`));
744
+ console.log(chalk.green("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
745
+ } else if (isExit) {
746
+ console.log(chalk.red("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
747
+ console.log(chalk.red(`\u2502 ${content}`));
748
+ console.log(chalk.red("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
749
+ } else if (agent) {
750
+ const color = this.getAgentColor(authorId);
751
+ console.log(color(`${agent.emoji} ${agent.name}: `) + content);
752
+ } else if (authorId === "user") {
753
+ console.log(chalk.cyan("\u{1F464} \uC0AC\uC6A9\uC790: ") + content);
754
+ } else {
755
+ console.log(content);
756
+ }
757
+ }
758
+ /**
759
+ * Send status update
760
+ */
761
+ async sendStatusUpdate(agentId, status) {
762
+ const agent = getAgentById(agentId);
763
+ if (!agent) return;
764
+ const statusEmoji = status === "enter" ? "\u{1F7E2}" : "\u{1F534}";
765
+ const statusText = status === "enter" ? "\uC785\uC7A5" : "\uD1F4\uC7A5";
766
+ const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString("ko-KR");
767
+ const color = status === "enter" ? chalk.green : chalk.red;
768
+ console.log(color(`${statusEmoji} [${timestamp}] ${agent.emoji} ${agent.name} ${statusText}`));
769
+ }
770
+ /**
771
+ * Register message handler
772
+ */
773
+ onMessage(handler) {
774
+ this.messageHandler = handler;
775
+ }
776
+ /**
777
+ * Simulate thread creation
778
+ */
779
+ async createThread(name) {
780
+ this.threadCounter++;
781
+ const threadId = `thread-${this.threadCounter}`;
782
+ console.log(chalk.gray(`\u{1F4CE} \uC2A4\uB808\uB4DC \uC0DD\uC131: ${name} (${threadId})`));
783
+ return threadId;
784
+ }
785
+ /**
786
+ * Trigger a message from user input
787
+ */
788
+ triggerMessage(content) {
789
+ if (!this.messageHandler) return;
790
+ const message = {
791
+ id: `msg-${Date.now()}`,
792
+ content,
793
+ authorId: "user",
794
+ authorName: "\uC0AC\uC6A9\uC790",
795
+ authorEmoji: "\u{1F464}",
796
+ timestamp: /* @__PURE__ */ new Date(),
797
+ mentions: this.parseMentions(content)
798
+ };
799
+ this.messageHandler(message);
800
+ }
801
+ parseMentions(content) {
802
+ const mentionPattern = /@([a-z-]+)/gi;
803
+ const matches = content.matchAll(mentionPattern);
804
+ const mentions = [];
805
+ for (const match of matches) {
806
+ const agentId = match[1].toLowerCase();
807
+ if (!mentions.includes(agentId)) {
808
+ mentions.push(agentId);
809
+ }
810
+ }
811
+ return mentions;
812
+ }
813
+ getAgentColor(agentId) {
814
+ const colors = {
815
+ base: chalk.yellow,
816
+ searcher: chalk.blue,
817
+ "tech-researcher": chalk.cyan,
818
+ "trend-analyst": chalk.magenta,
819
+ "data-provider": chalk.white,
820
+ counselor: chalk.green,
821
+ "user-psychologist": chalk.yellowBright,
822
+ questioner: chalk.blueBright,
823
+ persuader: chalk.cyanBright,
824
+ educator: chalk.magentaBright,
825
+ planner: chalk.greenBright,
826
+ "team-composer": chalk.redBright,
827
+ promoter: chalk.whiteBright,
828
+ uploader: chalk.gray,
829
+ "backend-dev": chalk.blue,
830
+ "frontend-dev": chalk.cyan,
831
+ designer: chalk.magenta,
832
+ "code-reviewer": chalk.yellow,
833
+ "doc-writer": chalk.green,
834
+ automator: chalk.red,
835
+ "prompt-engineer": chalk.blueBright,
836
+ "ai-illustrator": chalk.cyanBright,
837
+ "program-tester": chalk.magentaBright,
838
+ "user-tester": chalk.greenBright,
839
+ "security-checker": chalk.yellowBright,
840
+ "vuln-finder": chalk.redBright,
841
+ pentester: chalk.whiteBright,
842
+ "fact-bomber": chalk.red,
843
+ roaster: chalk.redBright,
844
+ critic: chalk.yellow,
845
+ negativist: chalk.gray,
846
+ praiser: chalk.green,
847
+ "loophole-finder": chalk.cyan,
848
+ threatener: chalk.magenta,
849
+ "dirty-worker": chalk.white
850
+ };
851
+ return colors[agentId] || chalk.white;
852
+ }
853
+ /**
854
+ * Print system message
855
+ */
856
+ printSystem(message) {
857
+ console.log(chalk.gray(`[\uC2DC\uC2A4\uD15C] ${message}`));
858
+ }
859
+ /**
860
+ * Print error message
861
+ */
862
+ printError(message) {
863
+ console.log(chalk.red(`[\uC624\uB958] ${message}`));
864
+ }
865
+ };
866
+
867
+ // src/simulation/TerminalUI.ts
868
+ var TerminalUI = class {
869
+ adapter;
870
+ orchestrator;
871
+ rl;
872
+ isRunning = false;
873
+ constructor() {
874
+ this.adapter = new TerminalAdapter();
875
+ this.orchestrator = new Orchestrator(this.adapter);
876
+ this.rl = readline.createInterface({
877
+ input: process.stdin,
878
+ output: process.stdout
879
+ });
880
+ }
881
+ /**
882
+ * Start the terminal UI
883
+ */
884
+ async start() {
885
+ this.isRunning = true;
886
+ this.printWelcome();
887
+ this.printHelp();
888
+ this.adapter.onMessage((message) => {
889
+ this.orchestrator.handleUserMessage(message);
890
+ });
891
+ await this.inputLoop();
892
+ }
893
+ /**
894
+ * Stop the terminal UI
895
+ */
896
+ stop() {
897
+ this.isRunning = false;
898
+ this.rl.close();
899
+ console.log(chalk2.yellow("\n\u{1F44B} Too Many Claw \uC2DC\uBBAC\uB808\uC774\uC158\uC744 \uC885\uB8CC\uD569\uB2C8\uB2E4.\n"));
900
+ }
901
+ printWelcome() {
902
+ console.log(chalk2.cyan(`
903
+ \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
904
+ \u2551 \u2551
905
+ \u2551 \u{1F980} Too Many Claw - \uD130\uBBF8\uB110 \uC2DC\uBBAC\uB808\uC774\uC158 \u2551
906
+ \u2551 \u2551
907
+ \u2551 35\uAC1C\uC758 AI \uC5D0\uC774\uC804\uD2B8\uAC00 \uD611\uC5C5\uD558\uB294 \uC2DC\uC2A4\uD15C \u2551
908
+ \u2551 \u2551
909
+ \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
910
+ `));
911
+ }
912
+ printHelp() {
913
+ console.log(chalk2.gray(`
914
+ \uBA85\uB839\uC5B4:
915
+ /help - \uB3C4\uC6C0\uB9D0 \uD45C\uC2DC
916
+ /status - \uD65C\uC131 \uC5D0\uC774\uC804\uD2B8 \uBAA9\uB85D
917
+ /agents - \uC804\uCCB4 \uC5D0\uC774\uC804\uD2B8 \uBAA9\uB85D
918
+ /summon @agent - \uC5D0\uC774\uC804\uD2B8 \uC18C\uD658
919
+ /dismiss @agent - \uC5D0\uC774\uC804\uD2B8 \uD1F4\uC7A5
920
+ /clear - \uD654\uBA74 \uC9C0\uC6B0\uAE30
921
+ /quit - \uC885\uB8CC
922
+
923
+ \uBA54\uC2DC\uC9C0\uC5D0 @agent-id\uB97C \uD3EC\uD568\uD558\uBA74 \uD574\uB2F9 \uC5D0\uC774\uC804\uD2B8\uAC00 \uC18C\uD658\uB429\uB2C8\uB2E4.
924
+ \uC608: @searcher \uCD5C\uC2E0 React \uC815\uBCF4 \uCC3E\uC544\uC918
925
+ `));
926
+ }
927
+ async inputLoop() {
928
+ while (this.isRunning) {
929
+ const input = await this.prompt();
930
+ if (!input) continue;
931
+ await this.handleInput(input.trim());
932
+ }
933
+ }
934
+ prompt() {
935
+ return new Promise((resolve) => {
936
+ this.rl.question(chalk2.cyan("\u{1F464} \uC0AC\uC6A9\uC790 > "), (answer) => {
937
+ resolve(answer);
938
+ });
939
+ });
940
+ }
941
+ async handleInput(input) {
942
+ if (input.startsWith("/")) {
943
+ await this.handleCommand(input);
944
+ return;
945
+ }
946
+ if (input.length > 0) {
947
+ this.adapter.triggerMessage(input);
948
+ }
949
+ }
950
+ async handleCommand(input) {
951
+ const parts = input.split(" ");
952
+ const command = parts[0].toLowerCase();
953
+ const args = parts.slice(1);
954
+ switch (command) {
955
+ case "/help":
956
+ this.printHelp();
957
+ break;
958
+ case "/status":
959
+ this.printStatus();
960
+ break;
961
+ case "/agents":
962
+ this.printAllAgents();
963
+ break;
964
+ case "/summon":
965
+ await this.handleSummon(args);
966
+ break;
967
+ case "/dismiss":
968
+ await this.handleDismiss(args);
969
+ break;
970
+ case "/clear":
971
+ console.clear();
972
+ this.printWelcome();
973
+ break;
974
+ case "/quit":
975
+ case "/exit":
976
+ this.stop();
977
+ break;
978
+ default:
979
+ console.log(chalk2.red(`\uC54C \uC218 \uC5C6\uB294 \uBA85\uB839\uC5B4: ${command}`));
980
+ console.log(chalk2.gray("/help \uB85C \uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uBA85\uB839\uC5B4\uB97C \uD655\uC778\uD558\uC138\uC694."));
981
+ }
982
+ }
983
+ printStatus() {
984
+ const status = this.orchestrator.getStatus();
985
+ console.log(chalk2.cyan("\n\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"));
986
+ console.log(chalk2.cyan("\u2502 \u{1F3AD} \uC5D0\uC774\uC804\uD2B8 \uC0C1\uD0DC \u2502"));
987
+ console.log(chalk2.cyan("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"));
988
+ console.log(chalk2.cyan("\u2502") + chalk2.white(` \uD65C\uC131: ${status.active} | \uB300\uAE30: ${status.dormant}`).padEnd(36) + chalk2.cyan("\u2502"));
989
+ console.log(chalk2.cyan("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"));
990
+ if (status.activeIds.length === 0) {
991
+ console.log(chalk2.cyan("\u2502") + chalk2.gray(" (\uD65C\uC131\uD654\uB41C \uC5D0\uC774\uC804\uD2B8 \uC5C6\uC74C)").padEnd(36) + chalk2.cyan("\u2502"));
992
+ } else {
993
+ for (const id of status.activeIds) {
994
+ const agent = getAgentById(id);
995
+ if (agent) {
996
+ console.log(chalk2.cyan("\u2502") + chalk2.green(` \u{1F7E2} ${agent.emoji} ${agent.name}`).padEnd(44) + chalk2.cyan("\u2502"));
997
+ }
998
+ }
999
+ }
1000
+ console.log(chalk2.cyan("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n"));
1001
+ }
1002
+ printAllAgents() {
1003
+ console.log(chalk2.cyan("\n\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"));
1004
+ console.log(chalk2.cyan("\u2502 \u{1F3AD} \uC804\uCCB4 \uC5D0\uC774\uC804\uD2B8 \uBAA9\uB85D \u2502"));
1005
+ console.log(chalk2.cyan("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"));
1006
+ const categories = /* @__PURE__ */ new Map();
1007
+ for (const agent of AGENT_DEFINITIONS) {
1008
+ const category = agent.category;
1009
+ if (!categories.has(category)) {
1010
+ categories.set(category, []);
1011
+ }
1012
+ categories.get(category).push(agent);
1013
+ }
1014
+ for (const [category, agents] of categories) {
1015
+ console.log(chalk2.cyan("\u2502") + chalk2.yellow(` [${category}]`).padEnd(48) + chalk2.cyan("\u2502"));
1016
+ for (const agent of agents) {
1017
+ const active = this.orchestrator.isAgentActive(agent.id);
1018
+ const status = active ? chalk2.green("\u{1F7E2}") : chalk2.gray("\u26AA");
1019
+ console.log(chalk2.cyan("\u2502") + ` ${status} ${agent.emoji} ${agent.name} `.padEnd(47) + chalk2.cyan("\u2502"));
1020
+ }
1021
+ }
1022
+ console.log(chalk2.cyan("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n"));
1023
+ }
1024
+ async handleSummon(args) {
1025
+ if (args.length === 0) {
1026
+ console.log(chalk2.red("\uC0AC\uC6A9\uBC95: /summon @agent-id"));
1027
+ return;
1028
+ }
1029
+ const agentId = args[0].replace("@", "");
1030
+ const agent = getAgentById(agentId);
1031
+ if (!agent) {
1032
+ console.log(chalk2.red(`\uC54C \uC218 \uC5C6\uB294 \uC5D0\uC774\uC804\uD2B8: ${agentId}`));
1033
+ return;
1034
+ }
1035
+ if (this.orchestrator.isAgentActive(agentId)) {
1036
+ console.log(chalk2.yellow(`${agent.emoji} ${agent.name}\uC740(\uB294) \uC774\uBBF8 \uD65C\uC131\uD654\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4.`));
1037
+ return;
1038
+ }
1039
+ await this.orchestrator.summonAgent(agentId, "\uC0AC\uC6A9\uC790\uAC00 \uC9C1\uC811 \uC18C\uD658");
1040
+ }
1041
+ async handleDismiss(args) {
1042
+ if (args.length === 0) {
1043
+ console.log(chalk2.red("\uC0AC\uC6A9\uBC95: /dismiss @agent-id"));
1044
+ return;
1045
+ }
1046
+ const agentId = args[0].replace("@", "");
1047
+ const agent = getAgentById(agentId);
1048
+ if (!agent) {
1049
+ console.log(chalk2.red(`\uC54C \uC218 \uC5C6\uB294 \uC5D0\uC774\uC804\uD2B8: ${agentId}`));
1050
+ return;
1051
+ }
1052
+ if (agent.alwaysActive) {
1053
+ console.log(chalk2.red(`${agent.emoji} ${agent.name}\uC740(\uB294) \uD56D\uC0C1 \uD65C\uC131\uD654 \uC0C1\uD0DC\uC785\uB2C8\uB2E4.`));
1054
+ return;
1055
+ }
1056
+ if (!this.orchestrator.isAgentActive(agentId)) {
1057
+ console.log(chalk2.yellow(`${agent.emoji} ${agent.name}\uC740(\uB294) \uC774\uBBF8 \uBE44\uD65C\uC131\uD654\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4.`));
1058
+ return;
1059
+ }
1060
+ await this.orchestrator.dismissAgent(agentId, "\uC0AC\uC6A9\uC790\uAC00 \uC9C1\uC811 \uD1F4\uC7A5 \uC694\uCCAD");
1061
+ }
1062
+ };
1063
+
1064
+ // src/config/ConfigManager.ts
1065
+ import fs from "fs-extra";
1066
+ import path from "path";
1067
+ import os from "os";
1068
+ var DEFAULT_CONFIG = {
1069
+ discord: {},
1070
+ webhooks: {},
1071
+ simulation: {
1072
+ enabled: false
1073
+ }
1074
+ };
1075
+ var ConfigManager = class {
1076
+ configPath;
1077
+ config;
1078
+ constructor() {
1079
+ const openclawDir = path.join(os.homedir(), ".openclaw");
1080
+ this.configPath = path.join(openclawDir, "too-many-claw.json");
1081
+ this.config = this.load();
1082
+ }
1083
+ /**
1084
+ * Load configuration from disk
1085
+ */
1086
+ load() {
1087
+ try {
1088
+ if (fs.existsSync(this.configPath)) {
1089
+ const data = fs.readJsonSync(this.configPath);
1090
+ return { ...DEFAULT_CONFIG, ...data };
1091
+ }
1092
+ } catch {
1093
+ }
1094
+ return { ...DEFAULT_CONFIG };
1095
+ }
1096
+ /**
1097
+ * Save configuration to disk
1098
+ */
1099
+ save() {
1100
+ try {
1101
+ fs.ensureDirSync(path.dirname(this.configPath));
1102
+ fs.writeJsonSync(this.configPath, this.config, { spaces: 2 });
1103
+ } catch (error) {
1104
+ console.error("Failed to save config:", error);
1105
+ }
1106
+ }
1107
+ /**
1108
+ * Get Discord configuration
1109
+ */
1110
+ getDiscordConfig() {
1111
+ return this.config.discord;
1112
+ }
1113
+ /**
1114
+ * Set Discord configuration
1115
+ */
1116
+ setDiscordConfig(discord) {
1117
+ this.config.discord = { ...this.config.discord, ...discord };
1118
+ this.save();
1119
+ }
1120
+ /**
1121
+ * Check if Discord is configured
1122
+ */
1123
+ isDiscordConfigured() {
1124
+ const { token, guildId, chatChannelId } = this.config.discord;
1125
+ return !!(token && guildId && chatChannelId);
1126
+ }
1127
+ /**
1128
+ * Get webhook URL for an agent
1129
+ */
1130
+ getWebhook(agentId) {
1131
+ return this.config.webhooks[agentId];
1132
+ }
1133
+ /**
1134
+ * Set webhook URL for an agent
1135
+ */
1136
+ setWebhook(agentId, webhookUrl) {
1137
+ this.config.webhooks[agentId] = webhookUrl;
1138
+ this.save();
1139
+ }
1140
+ /**
1141
+ * Check if agent has a webhook
1142
+ */
1143
+ hasWebhook(agentId) {
1144
+ return !!this.config.webhooks[agentId];
1145
+ }
1146
+ /**
1147
+ * Remove webhook for an agent
1148
+ */
1149
+ removeWebhook(agentId) {
1150
+ delete this.config.webhooks[agentId];
1151
+ this.save();
1152
+ }
1153
+ /**
1154
+ * Get all webhooks
1155
+ */
1156
+ getAllWebhooks() {
1157
+ return { ...this.config.webhooks };
1158
+ }
1159
+ /**
1160
+ * Set all webhooks
1161
+ */
1162
+ setAllWebhooks(webhooks) {
1163
+ this.config.webhooks = { ...webhooks };
1164
+ this.save();
1165
+ }
1166
+ /**
1167
+ * Get config file path
1168
+ */
1169
+ getConfigPath() {
1170
+ return this.configPath;
1171
+ }
1172
+ /**
1173
+ * Reset configuration
1174
+ */
1175
+ reset() {
1176
+ this.config = { ...DEFAULT_CONFIG };
1177
+ try {
1178
+ if (fs.existsSync(this.configPath)) {
1179
+ fs.removeSync(this.configPath);
1180
+ }
1181
+ } catch {
1182
+ }
1183
+ }
1184
+ };
1185
+
1186
+ // src/discord/Bot.ts
1187
+ import {
1188
+ Client,
1189
+ GatewayIntentBits,
1190
+ TextChannel,
1191
+ Partials
1192
+ } from "discord.js";
1193
+ var Bot = class {
1194
+ client;
1195
+ config;
1196
+ messageHandlers = [];
1197
+ agentIds;
1198
+ constructor(config) {
1199
+ this.config = config;
1200
+ this.agentIds = new Set(getAllAgentIds());
1201
+ this.client = new Client({
1202
+ intents: [
1203
+ GatewayIntentBits.Guilds,
1204
+ GatewayIntentBits.GuildMessages,
1205
+ GatewayIntentBits.MessageContent,
1206
+ GatewayIntentBits.GuildMessageReactions
1207
+ ],
1208
+ partials: [Partials.Message, Partials.Channel]
1209
+ });
1210
+ this.setupEventHandlers();
1211
+ }
1212
+ setupEventHandlers() {
1213
+ this.client.on("ready", () => {
1214
+ console.log(`\u2705 Bot logged in as ${this.client.user?.tag}`);
1215
+ });
1216
+ this.client.on("messageCreate", async (discordMessage) => {
1217
+ if (discordMessage.author.bot) return;
1218
+ if (discordMessage.channelId !== this.config.chatChannelId) return;
1219
+ const message = this.convertMessage(discordMessage);
1220
+ for (const handler of this.messageHandlers) {
1221
+ handler(message);
1222
+ }
1223
+ });
1224
+ this.client.on("error", (error) => {
1225
+ console.error("Discord bot error:", error);
1226
+ });
1227
+ }
1228
+ convertMessage(discordMessage) {
1229
+ const content = this.cleanMessageContent(discordMessage.content);
1230
+ const mentions = this.parseMentions(content);
1231
+ return {
1232
+ id: discordMessage.id,
1233
+ content,
1234
+ authorId: "user",
1235
+ authorName: discordMessage.author.displayName || discordMessage.author.username,
1236
+ authorEmoji: "\u{1F464}",
1237
+ timestamp: discordMessage.createdAt,
1238
+ threadId: discordMessage.thread?.id,
1239
+ mentions
1240
+ };
1241
+ }
1242
+ cleanMessageContent(content) {
1243
+ return content.replace(/<@!?(\d+)>/g, "@user");
1244
+ }
1245
+ parseMentions(content) {
1246
+ const mentionPattern = /@([a-z-]+)/gi;
1247
+ const matches = content.matchAll(mentionPattern);
1248
+ const mentions = [];
1249
+ for (const match of matches) {
1250
+ const agentId = match[1].toLowerCase();
1251
+ if (this.agentIds.has(agentId) && !mentions.includes(agentId)) {
1252
+ mentions.push(agentId);
1253
+ }
1254
+ }
1255
+ return mentions;
1256
+ }
1257
+ /**
1258
+ * Register a message handler
1259
+ */
1260
+ onMessage(handler) {
1261
+ this.messageHandlers.push(handler);
1262
+ }
1263
+ /**
1264
+ * Connect to Discord
1265
+ */
1266
+ async connect() {
1267
+ await this.client.login(this.config.token);
1268
+ }
1269
+ /**
1270
+ * Disconnect from Discord
1271
+ */
1272
+ async disconnect() {
1273
+ this.client.destroy();
1274
+ }
1275
+ /**
1276
+ * Send a message to a channel
1277
+ */
1278
+ async sendMessage(channelId, content) {
1279
+ const channel = await this.client.channels.fetch(channelId);
1280
+ if (channel && channel instanceof TextChannel) {
1281
+ await channel.send(content);
1282
+ }
1283
+ }
1284
+ /**
1285
+ * Get the chat channel
1286
+ */
1287
+ async getChatChannel() {
1288
+ const channel = await this.client.channels.fetch(this.config.chatChannelId);
1289
+ if (channel instanceof TextChannel) {
1290
+ return channel;
1291
+ }
1292
+ return null;
1293
+ }
1294
+ /**
1295
+ * Get the status channel
1296
+ */
1297
+ async getStatusChannel() {
1298
+ if (!this.config.statusChannelId) return null;
1299
+ const channel = await this.client.channels.fetch(this.config.statusChannelId);
1300
+ if (channel instanceof TextChannel) {
1301
+ return channel;
1302
+ }
1303
+ return null;
1304
+ }
1305
+ /**
1306
+ * Create a thread in the chat channel
1307
+ */
1308
+ async createThread(name) {
1309
+ const channel = await this.getChatChannel();
1310
+ if (!channel) {
1311
+ throw new Error("Chat channel not found");
1312
+ }
1313
+ const thread = await channel.threads.create({
1314
+ name,
1315
+ autoArchiveDuration: 1440
1316
+ // 24 hours
1317
+ });
1318
+ return thread.id;
1319
+ }
1320
+ /**
1321
+ * Check if bot is connected
1322
+ */
1323
+ get isConnected() {
1324
+ return this.client.isReady();
1325
+ }
1326
+ };
1327
+
1328
+ // src/discord/WebhookManager.ts
1329
+ import { WebhookClient } from "discord.js";
1330
+ var WebhookManager = class {
1331
+ webhooks = /* @__PURE__ */ new Map();
1332
+ clients = /* @__PURE__ */ new Map();
1333
+ /**
1334
+ * Register a webhook URL for an agent
1335
+ */
1336
+ setWebhook(agentId, webhookUrl) {
1337
+ this.webhooks.set(agentId, webhookUrl);
1338
+ const existingClient = this.clients.get(agentId);
1339
+ if (existingClient) {
1340
+ existingClient.destroy();
1341
+ }
1342
+ this.clients.set(agentId, new WebhookClient({ url: webhookUrl }));
1343
+ }
1344
+ /**
1345
+ * Bulk register webhooks from config
1346
+ */
1347
+ setWebhooks(webhooks) {
1348
+ for (const [agentId, url] of Object.entries(webhooks)) {
1349
+ this.setWebhook(agentId, url);
1350
+ }
1351
+ }
1352
+ /**
1353
+ * Check if webhook exists for an agent
1354
+ */
1355
+ hasWebhook(agentId) {
1356
+ return this.webhooks.has(agentId);
1357
+ }
1358
+ /**
1359
+ * Send message as an agent via webhook
1360
+ */
1361
+ async sendAsAgent(agentId, content) {
1362
+ const client = this.clients.get(agentId);
1363
+ if (!client) {
1364
+ throw new Error(`No webhook registered for agent: ${agentId}`);
1365
+ }
1366
+ const agent = getAgentById(agentId);
1367
+ if (!agent) {
1368
+ throw new Error(`Unknown agent: ${agentId}`);
1369
+ }
1370
+ await client.send({
1371
+ content,
1372
+ username: `${agent.emoji} ${agent.name}`
1373
+ // Avatar URL could be set here if we have agent avatar images
1374
+ });
1375
+ }
1376
+ /**
1377
+ * Get all registered agent IDs
1378
+ */
1379
+ getRegisteredAgents() {
1380
+ return Array.from(this.webhooks.keys());
1381
+ }
1382
+ /**
1383
+ * Remove a webhook
1384
+ */
1385
+ removeWebhook(agentId) {
1386
+ const client = this.clients.get(agentId);
1387
+ if (client) {
1388
+ client.destroy();
1389
+ this.clients.delete(agentId);
1390
+ }
1391
+ this.webhooks.delete(agentId);
1392
+ }
1393
+ /**
1394
+ * Destroy all webhook clients
1395
+ */
1396
+ destroy() {
1397
+ for (const client of this.clients.values()) {
1398
+ client.destroy();
1399
+ }
1400
+ this.clients.clear();
1401
+ this.webhooks.clear();
1402
+ }
1403
+ };
1404
+
1405
+ // src/discord/DiscordAdapter.ts
1406
+ var DiscordAdapter = class {
1407
+ bot;
1408
+ webhookManager;
1409
+ statusChannelId;
1410
+ constructor(config) {
1411
+ this.bot = new Bot(config);
1412
+ this.webhookManager = new WebhookManager();
1413
+ this.statusChannelId = config.statusChannelId;
1414
+ }
1415
+ /**
1416
+ * Send a message - uses webhook if available, otherwise bot
1417
+ */
1418
+ async sendMessage(message) {
1419
+ const { authorId, content } = message;
1420
+ if (authorId !== "user" && this.webhookManager.hasWebhook(authorId)) {
1421
+ await this.webhookManager.sendAsAgent(authorId, content);
1422
+ } else {
1423
+ const channel = await this.bot.getChatChannel();
1424
+ if (channel) {
1425
+ await channel.send(content);
1426
+ }
1427
+ }
1428
+ }
1429
+ /**
1430
+ * Send status update to status channel
1431
+ */
1432
+ async sendStatusUpdate(agentId, status) {
1433
+ const channel = await this.bot.getStatusChannel();
1434
+ if (!channel) return;
1435
+ const agent = getAgentById(agentId);
1436
+ if (!agent) return;
1437
+ const statusEmoji = status === "enter" ? "\u{1F7E2}" : "\u{1F534}";
1438
+ const statusText = status === "enter" ? "\uC785\uC7A5" : "\uD1F4\uC7A5";
1439
+ const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString("ko-KR");
1440
+ await channel.send(`${statusEmoji} [${timestamp}] ${agent.emoji} **${agent.name}** ${statusText}`);
1441
+ }
1442
+ /**
1443
+ * Register message handler
1444
+ */
1445
+ onMessage(handler) {
1446
+ this.bot.onMessage(handler);
1447
+ }
1448
+ /**
1449
+ * Create a new thread
1450
+ */
1451
+ async createThread(name) {
1452
+ return this.bot.createThread(name);
1453
+ }
1454
+ /**
1455
+ * Connect to Discord
1456
+ */
1457
+ async connect() {
1458
+ await this.bot.connect();
1459
+ }
1460
+ /**
1461
+ * Disconnect from Discord
1462
+ */
1463
+ async disconnect() {
1464
+ await this.bot.disconnect();
1465
+ this.webhookManager.destroy();
1466
+ }
1467
+ /**
1468
+ * Set webhook for an agent
1469
+ */
1470
+ setWebhook(agentId, webhookUrl) {
1471
+ this.webhookManager.setWebhook(agentId, webhookUrl);
1472
+ }
1473
+ /**
1474
+ * Bulk set webhooks
1475
+ */
1476
+ setWebhooks(webhooks) {
1477
+ this.webhookManager.setWebhooks(webhooks);
1478
+ }
1479
+ /**
1480
+ * Check if agent has a webhook
1481
+ */
1482
+ hasWebhook(agentId) {
1483
+ return this.webhookManager.hasWebhook(agentId);
1484
+ }
1485
+ /**
1486
+ * Check if connected
1487
+ */
1488
+ get isConnected() {
1489
+ return this.bot.isConnected;
1490
+ }
1491
+ };
1492
+
1493
+ // src/cli.ts
1494
+ var program = new Command();
1495
+ program.name("tmc").description("Too Many Claw - 35 AI agents collaborating via Discord").version("1.0.0");
1496
+ program.command("start").description("Start the Discord bot").action(async () => {
1497
+ const spinner = ora("Starting Too Many Claw...").start();
1498
+ try {
1499
+ const config = new ConfigManager();
1500
+ if (!config.isDiscordConfigured()) {
1501
+ spinner.fail("Discord not configured");
1502
+ console.log(chalk3.yellow("\nRun `tmc setup-discord` to configure Discord settings."));
1503
+ process.exit(1);
1504
+ }
1505
+ const discordConfig = config.getDiscordConfig();
1506
+ if (!discordConfig.token || !discordConfig.guildId || !discordConfig.chatChannelId) {
1507
+ spinner.fail("Incomplete Discord configuration");
1508
+ process.exit(1);
1509
+ }
1510
+ const adapter = new DiscordAdapter({
1511
+ token: discordConfig.token,
1512
+ guildId: discordConfig.guildId,
1513
+ chatChannelId: discordConfig.chatChannelId,
1514
+ statusChannelId: discordConfig.statusChannelId
1515
+ });
1516
+ const webhooks = config.getAllWebhooks();
1517
+ if (Object.keys(webhooks).length > 0) {
1518
+ adapter.setWebhooks(webhooks);
1519
+ }
1520
+ const orchestrator = new Orchestrator(adapter);
1521
+ adapter.onMessage((message) => {
1522
+ orchestrator.handleUserMessage(message);
1523
+ });
1524
+ await adapter.connect();
1525
+ spinner.succeed("Too Many Claw is running!");
1526
+ console.log(chalk3.green("\n\u{1F980} Too Many Claw Discord bot is now active!"));
1527
+ console.log(chalk3.gray("Press Ctrl+C to stop.\n"));
1528
+ process.on("SIGINT", async () => {
1529
+ console.log(chalk3.yellow("\n\nShutting down..."));
1530
+ await adapter.disconnect();
1531
+ process.exit(0);
1532
+ });
1533
+ } catch (error) {
1534
+ spinner.fail("Failed to start");
1535
+ console.error(chalk3.red(error));
1536
+ process.exit(1);
1537
+ }
1538
+ });
1539
+ program.command("simulate").description("Start terminal simulation mode").action(async () => {
1540
+ console.log(chalk3.cyan("\n\u{1F980} Starting Too Many Claw Simulation...\n"));
1541
+ const ui = new TerminalUI();
1542
+ await ui.start();
1543
+ });
1544
+ program.command("status").description("Show agent status and configuration").action(() => {
1545
+ console.log(chalk3.cyan("\n\u{1F980} Too Many Claw - Agent Status\n"));
1546
+ const config = new ConfigManager();
1547
+ const categories = /* @__PURE__ */ new Map();
1548
+ for (const agent of AGENT_DEFINITIONS) {
1549
+ if (!categories.has(agent.category)) {
1550
+ categories.set(agent.category, []);
1551
+ }
1552
+ categories.get(agent.category).push(agent);
1553
+ }
1554
+ for (const [category, agents] of categories) {
1555
+ console.log(chalk3.yellow(`
1556
+ [${category}]`));
1557
+ for (const agent of agents) {
1558
+ const hasWebhook = config.hasWebhook(agent.id);
1559
+ const webhookStatus = hasWebhook ? chalk3.green("\u2713") : chalk3.gray("\u25CB");
1560
+ console.log(` ${webhookStatus} ${agent.emoji} ${agent.name} (${chalk3.gray(agent.id)})`);
1561
+ }
1562
+ }
1563
+ console.log(chalk3.gray(`
1564
+ \uCD1D ${AGENT_DEFINITIONS.length}\uAC1C \uC5D0\uC774\uC804\uD2B8
1565
+ `));
1566
+ console.log(chalk3.cyan("Discord \uC124\uC815:"));
1567
+ if (config.isDiscordConfigured()) {
1568
+ console.log(chalk3.green(" \u2713 \uAD6C\uC131\uB428"));
1569
+ } else {
1570
+ console.log(chalk3.yellow(" \u25CB \uBBF8\uAD6C\uC131 (tmc setup-discord \uC2E4\uD589)"));
1571
+ }
1572
+ console.log();
1573
+ });
1574
+ program.command("setup-discord").description("Configure Discord settings").action(async () => {
1575
+ console.log(chalk3.cyan("\n\u{1F980} Too Many Claw - Discord \uC124\uC815\n"));
1576
+ const config = new ConfigManager();
1577
+ const answers = await inquirer.prompt([
1578
+ {
1579
+ type: "input",
1580
+ name: "token",
1581
+ message: "Discord Bot Token:",
1582
+ default: config.getDiscordConfig().token || ""
1583
+ },
1584
+ {
1585
+ type: "input",
1586
+ name: "guildId",
1587
+ message: "Discord Guild (Server) ID:",
1588
+ default: config.getDiscordConfig().guildId || ""
1589
+ },
1590
+ {
1591
+ type: "input",
1592
+ name: "chatChannelId",
1593
+ message: "Chat Channel ID:",
1594
+ default: config.getDiscordConfig().chatChannelId || ""
1595
+ },
1596
+ {
1597
+ type: "input",
1598
+ name: "statusChannelId",
1599
+ message: "Status Channel ID (optional):",
1600
+ default: config.getDiscordConfig().statusChannelId || ""
1601
+ }
1602
+ ]);
1603
+ config.setDiscordConfig({
1604
+ token: answers.token,
1605
+ guildId: answers.guildId,
1606
+ chatChannelId: answers.chatChannelId,
1607
+ statusChannelId: answers.statusChannelId || void 0
1608
+ });
1609
+ console.log(chalk3.green("\n\u2713 Discord \uC124\uC815\uC774 \uC800\uC7A5\uB418\uC5C8\uC2B5\uB2C8\uB2E4."));
1610
+ console.log(chalk3.gray("`tmc start`\uB85C \uBD07\uC744 \uC2DC\uC791\uD558\uC138\uC694.\n"));
1611
+ });
1612
+ program.command("uninstall").description("Remove Too Many Claw configuration").action(async () => {
1613
+ const answers = await inquirer.prompt([
1614
+ {
1615
+ type: "confirm",
1616
+ name: "confirm",
1617
+ message: "Are you sure you want to remove all Too Many Claw configuration?",
1618
+ default: false
1619
+ }
1620
+ ]);
1621
+ if (!answers.confirm) {
1622
+ console.log(chalk3.yellow("Cancelled."));
1623
+ return;
1624
+ }
1625
+ const spinner = ora("Removing configuration...").start();
1626
+ try {
1627
+ const config = new ConfigManager();
1628
+ config.reset();
1629
+ spinner.succeed("Configuration removed");
1630
+ console.log(chalk3.green("\nToo Many Claw configuration has been removed."));
1631
+ console.log(chalk3.gray("Run `npm uninstall -g too-many-claw` to complete uninstallation.\n"));
1632
+ } catch (error) {
1633
+ spinner.fail("Failed to remove configuration");
1634
+ console.error(chalk3.red(error));
1635
+ }
1636
+ });
1637
+ program.parse();
1638
+ //# sourceMappingURL=cli.js.map