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/README.md +221 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +1638 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +650 -0
- package/dist/index.js +2628 -0
- package/dist/index.js.map +1 -0
- package/dist/scripts/postinstall.d.ts +1 -0
- package/dist/scripts/postinstall.js +1547 -0
- package/dist/scripts/postinstall.js.map +1 -0
- package/package.json +57 -0
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
|