too-many-claw 1.0.7 → 1.0.9

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 CHANGED
@@ -20,7 +20,7 @@ var AGENT_DEFINITIONS = [
20
20
  name: "Base",
21
21
  emoji: "\u{1F3E0}",
22
22
  category: "CORE" /* CORE */,
23
- model: "claude-opus-4-5" /* OPUS */,
23
+ model: "anthropic/claude-opus-4-5" /* OPUS */,
24
24
  role: "Team Coordinator. Always active. Receives and analyzes user requests, then summons appropriate agents. Orchestrates team conversations and synthesizes results for the user upon task completion. Can dismiss agents when necessary.",
25
25
  alwaysActive: true
26
26
  },
@@ -32,7 +32,7 @@ var AGENT_DEFINITIONS = [
32
32
  name: "Search Specialist",
33
33
  emoji: "\u{1F50D}",
34
34
  category: "RESEARCH" /* RESEARCH */,
35
- model: "claude-sonnet-4-5" /* SONNET */,
35
+ model: "anthropic/claude-sonnet-4-5" /* SONNET */,
36
36
  role: "Information search and resource collection specialist. Finds necessary information through web searches, document searches, and database queries. Organizes and shares search results with the team."
37
37
  },
38
38
  {
@@ -40,7 +40,7 @@ var AGENT_DEFINITIONS = [
40
40
  name: "Technology Research Specialist",
41
41
  emoji: "\u{1F52C}",
42
42
  category: "RESEARCH" /* RESEARCH */,
43
- model: "claude-sonnet-4-5" /* SONNET */,
43
+ model: "anthropic/claude-sonnet-4-5" /* SONNET */,
44
44
  role: "Latest technology trends research specialist. Investigates new technologies, frameworks, libraries, and industry trends. Provides comparative analysis of pros and cons for technology selection."
45
45
  },
46
46
  {
@@ -48,7 +48,7 @@ var AGENT_DEFINITIONS = [
48
48
  name: "Trend Analysis Specialist",
49
49
  emoji: "\u{1F4C8}",
50
50
  category: "RESEARCH" /* RESEARCH */,
51
- model: "claude-sonnet-4-5" /* SONNET */,
51
+ model: "anthropic/claude-sonnet-4-5" /* SONNET */,
52
52
  role: "Market and trend analyst. Analyzes current trends, popular topics, and market dynamics. Provides insights on timing and strategic direction."
53
53
  },
54
54
  {
@@ -56,7 +56,7 @@ var AGENT_DEFINITIONS = [
56
56
  name: "Data Preparation Specialist",
57
57
  emoji: "\u{1F4CA}",
58
58
  category: "RESEARCH" /* RESEARCH */,
59
- model: "claude-sonnet-4-5" /* SONNET */,
59
+ model: "anthropic/claude-sonnet-4-5" /* SONNET */,
60
60
  role: "Data collection and refinement specialist. Collects, cleanses, and processes data into usable formats. Handles statistics, metrics, and data preparation."
61
61
  },
62
62
  // ============================================================================
@@ -67,7 +67,7 @@ var AGENT_DEFINITIONS = [
67
67
  name: "Psychological Counselor",
68
68
  emoji: "\u{1F49A}",
69
69
  category: "PSYCHOLOGY" /* PSYCHOLOGY */,
70
- model: "claude-sonnet-4-5" /* SONNET */,
70
+ model: "anthropic/claude-sonnet-4-5" /* SONNET */,
71
71
  role: "Emotional support and counseling specialist. Provides emotional support when users or team members are struggling or stressed. Offers comfort, empathy, and psychological stability."
72
72
  },
73
73
  {
@@ -75,7 +75,7 @@ var AGENT_DEFINITIONS = [
75
75
  name: "User Psychology Analyst",
76
76
  emoji: "\u{1F9E0}",
77
77
  category: "PSYCHOLOGY" /* PSYCHOLOGY */,
78
- model: "claude-opus-4-5" /* OPUS */,
78
+ model: "anthropic/claude-opus-4-5" /* OPUS */,
79
79
  role: "User intent and psychology analysis specialist. Analyzes what users truly want and the hidden intentions behind their words. Identifies underlying needs beyond stated requirements."
80
80
  },
81
81
  {
@@ -83,7 +83,7 @@ var AGENT_DEFINITIONS = [
83
83
  name: "Questioning Specialist",
84
84
  emoji: "\u2753",
85
85
  category: "PSYCHOLOGY" /* PSYCHOLOGY */,
86
- model: "claude-sonnet-4-5" /* SONNET */,
86
+ model: "anthropic/claude-sonnet-4-5" /* SONNET */,
87
87
  role: "Core questioning and clarification specialist. Asks questions to clarify ambiguous requirements. Identifies missing information and unclear aspects to seek clarification."
88
88
  },
89
89
  {
@@ -91,7 +91,7 @@ var AGENT_DEFINITIONS = [
91
91
  name: "Rational Persuasion Specialist",
92
92
  emoji: "\u{1F3AF}",
93
93
  category: "PSYCHOLOGY" /* PSYCHOLOGY */,
94
- model: "claude-sonnet-4-5" /* SONNET */,
94
+ model: "anthropic/claude-sonnet-4-5" /* SONNET */,
95
95
  role: "Logical persuasion and perspective-shifting specialist. Changes or persuades others' views through rational arguments and logic. Also mediates in conflict situations."
96
96
  },
97
97
  {
@@ -99,7 +99,7 @@ var AGENT_DEFINITIONS = [
99
99
  name: "Education Specialist",
100
100
  emoji: "\u{1F4DA}",
101
101
  category: "PSYCHOLOGY" /* PSYCHOLOGY */,
102
- model: "claude-sonnet-4-5" /* SONNET */,
102
+ model: "anthropic/claude-sonnet-4-5" /* SONNET */,
103
103
  role: "Explanation and education specialist. Explains complex concepts in simple terms. Teaches and educates users or team members on topics they don't understand."
104
104
  },
105
105
  // ============================================================================
@@ -110,7 +110,7 @@ var AGENT_DEFINITIONS = [
110
110
  name: "Professional Planning Specialist",
111
111
  emoji: "\u{1F4CB}",
112
112
  category: "PLANNING" /* PLANNING */,
113
- model: "claude-opus-4-5" /* OPUS */,
113
+ model: "anthropic/claude-opus-4-5" /* OPUS */,
114
114
  role: "Planning and roadmap specialist. Breaks down tasks into steps, establishes schedules, and sets priorities. Presents systematic plans and roadmaps."
115
115
  },
116
116
  {
@@ -118,7 +118,7 @@ var AGENT_DEFINITIONS = [
118
118
  name: "Agent Team Composition Specialist",
119
119
  emoji: "\u{1F465}",
120
120
  category: "PLANNING" /* PLANNING */,
121
- model: "claude-sonnet-4-5" /* SONNET */,
121
+ model: "anthropic/claude-sonnet-4-5" /* SONNET */,
122
122
  role: "Optimal team composition recommendation specialist. Analyzes and recommends which agents are needed for a given task. Optimizes team composition efficiency."
123
123
  },
124
124
  {
@@ -126,7 +126,7 @@ var AGENT_DEFINITIONS = [
126
126
  name: "Promotion Specialist",
127
127
  emoji: "\u{1F4E2}",
128
128
  category: "PLANNING" /* PLANNING */,
129
- model: "claude-sonnet-4-5" /* SONNET */,
129
+ model: "anthropic/claude-sonnet-4-5" /* SONNET */,
130
130
  role: "Marketing and promotion specialist. Handles how to publicize deliverables, branding, and marketing strategies. Refines messaging and positioning."
131
131
  },
132
132
  {
@@ -134,7 +134,7 @@ var AGENT_DEFINITIONS = [
134
134
  name: "Uploader",
135
135
  emoji: "\u2B06\uFE0F",
136
136
  category: "PLANNING" /* PLANNING */,
137
- model: "claude-haiku-4-5" /* HAIKU */,
137
+ model: "anthropic/claude-haiku-3-5" /* HAIKU */,
138
138
  role: "Deployment and upload specialist. Deploys and uploads completed deliverables. Handles launches, releases, and publishing."
139
139
  },
140
140
  // ============================================================================
@@ -145,7 +145,7 @@ var AGENT_DEFINITIONS = [
145
145
  name: "Backend Developer",
146
146
  emoji: "\u2699\uFE0F",
147
147
  category: "DEVELOPMENT" /* DEVELOPMENT */,
148
- model: "claude-sonnet-4-5" /* SONNET */,
148
+ model: "anthropic/claude-sonnet-4-5" /* SONNET */,
149
149
  role: "Server and backend development specialist. Handles server logic, APIs, databases, and infrastructure-related development."
150
150
  },
151
151
  {
@@ -153,7 +153,7 @@ var AGENT_DEFINITIONS = [
153
153
  name: "Frontend Developer",
154
154
  emoji: "\u{1F3A8}",
155
155
  category: "DEVELOPMENT" /* DEVELOPMENT */,
156
- model: "claude-sonnet-4-5" /* SONNET */,
156
+ model: "anthropic/claude-sonnet-4-5" /* SONNET */,
157
157
  role: "Frontend and UI development specialist. Handles web/app user interface, screen, and interaction development."
158
158
  },
159
159
  {
@@ -161,7 +161,7 @@ var AGENT_DEFINITIONS = [
161
161
  name: "Professional Designer",
162
162
  emoji: "\u{1F58C}\uFE0F",
163
163
  category: "DEVELOPMENT" /* DEVELOPMENT */,
164
- model: "claude-sonnet-4-5" /* SONNET */,
164
+ model: "anthropic/claude-sonnet-4-5" /* SONNET */,
165
165
  role: "Design and visual specialist. Handles UI/UX design, visual design, layout, color, and typography."
166
166
  },
167
167
  {
@@ -169,7 +169,7 @@ var AGENT_DEFINITIONS = [
169
169
  name: "Code Reviewer",
170
170
  emoji: "\u{1F440}",
171
171
  category: "DEVELOPMENT" /* DEVELOPMENT */,
172
- model: "claude-sonnet-4-5" /* SONNET */,
172
+ model: "anthropic/claude-sonnet-4-5" /* SONNET */,
173
173
  role: "Code quality review specialist. Reviews written code, suggests improvements, and identifies bugs or issues."
174
174
  },
175
175
  {
@@ -177,7 +177,7 @@ var AGENT_DEFINITIONS = [
177
177
  name: "Documentation Specialist",
178
178
  emoji: "\u{1F4DD}",
179
179
  category: "DEVELOPMENT" /* DEVELOPMENT */,
180
- model: "claude-sonnet-4-5" /* SONNET */,
180
+ model: "anthropic/claude-sonnet-4-5" /* SONNET */,
181
181
  role: "Documentation specialist. Handles writing all types of documentation including README, guides, API documentation, and user manuals."
182
182
  },
183
183
  {
@@ -185,7 +185,7 @@ var AGENT_DEFINITIONS = [
185
185
  name: "Automation Specialist",
186
186
  emoji: "\u{1F916}",
187
187
  category: "DEVELOPMENT" /* DEVELOPMENT */,
188
- model: "claude-sonnet-4-5" /* SONNET */,
188
+ model: "anthropic/claude-sonnet-4-5" /* SONNET */,
189
189
  role: "Automation and workflow specialist. Automates repetitive tasks, creates scripts, and designs efficient workflows."
190
190
  },
191
191
  {
@@ -193,7 +193,7 @@ var AGENT_DEFINITIONS = [
193
193
  name: "Prompt Engineer",
194
194
  emoji: "\u{1F4AC}",
195
195
  category: "DEVELOPMENT" /* DEVELOPMENT */,
196
- model: "claude-sonnet-4-5" /* SONNET */,
196
+ model: "anthropic/claude-sonnet-4-5" /* SONNET */,
197
197
  role: "AI prompt optimization specialist. Optimizes prompts sent to LLMs and develops AI utilization strategies."
198
198
  },
199
199
  {
@@ -201,7 +201,7 @@ var AGENT_DEFINITIONS = [
201
201
  name: "AI Illustration Generation Specialist",
202
202
  emoji: "\u{1F3AD}",
203
203
  category: "DEVELOPMENT" /* DEVELOPMENT */,
204
- model: "claude-sonnet-4-5" /* SONNET */,
204
+ model: "anthropic/claude-sonnet-4-5" /* SONNET */,
205
205
  role: "AI image generation specialist. Handles image generation prompt writing and creation using Midjourney, DALL-E, Stable Diffusion, and similar tools."
206
206
  },
207
207
  // ============================================================================
@@ -212,7 +212,7 @@ var AGENT_DEFINITIONS = [
212
212
  name: "Program Testing Specialist",
213
213
  emoji: "\u{1F9EA}",
214
214
  category: "TESTING" /* TESTING */,
215
- model: "claude-sonnet-4-5" /* SONNET */,
215
+ model: "anthropic/claude-sonnet-4-5" /* SONNET */,
216
216
  role: "Technical testing and QA specialist. Handles code testing, unit testing, integration testing, and bug discovery."
217
217
  },
218
218
  {
@@ -220,7 +220,7 @@ var AGENT_DEFINITIONS = [
220
220
  name: "General User Testing Specialist",
221
221
  emoji: "\u{1F464}",
222
222
  category: "TESTING" /* TESTING */,
223
- model: "claude-sonnet-4-5" /* SONNET */,
223
+ model: "anthropic/claude-sonnet-4-5" /* SONNET */,
224
224
  role: "User perspective testing specialist. Validates usability, intuitiveness, and UX from the perspective of a general user without technical knowledge."
225
225
  },
226
226
  {
@@ -228,7 +228,7 @@ var AGENT_DEFINITIONS = [
228
228
  name: "Security Check Specialist",
229
229
  emoji: "\u{1F6E1}\uFE0F",
230
230
  category: "TESTING" /* TESTING */,
231
- model: "claude-sonnet-4-5" /* SONNET */,
231
+ model: "anthropic/claude-sonnet-4-5" /* SONNET */,
232
232
  role: "Security audit specialist. Reviews basic security checklists, confirms compliance, and verifies adherence to security policies."
233
233
  },
234
234
  {
@@ -236,7 +236,7 @@ var AGENT_DEFINITIONS = [
236
236
  name: "Vulnerability Discovery Specialist",
237
237
  emoji: "\u{1F513}",
238
238
  category: "TESTING" /* TESTING */,
239
- model: "claude-sonnet-4-5" /* SONNET */,
239
+ model: "anthropic/claude-sonnet-4-5" /* SONNET */,
240
240
  role: "Vulnerability analysis specialist. Identifies security vulnerabilities and weaknesses in code, systems, and designs."
241
241
  },
242
242
  {
@@ -244,7 +244,7 @@ var AGENT_DEFINITIONS = [
244
244
  name: "Penetration Testing Specialist",
245
245
  emoji: "\u{1F480}",
246
246
  category: "TESTING" /* TESTING */,
247
- model: "claude-opus-4-5" /* OPUS */,
247
+ model: "anthropic/claude-opus-4-5" /* OPUS */,
248
248
  role: "Penetration testing specialist. Tests systems from an actual attacker's perspective and performs hacking simulations."
249
249
  },
250
250
  // ============================================================================
@@ -255,7 +255,7 @@ var AGENT_DEFINITIONS = [
255
255
  name: "Fact Check Specialist",
256
256
  emoji: "\u{1F4A3}",
257
257
  category: "CRITIQUE" /* CRITIQUE */,
258
- model: "claude-sonnet-4-5" /* SONNET */,
258
+ model: "anthropic/claude-sonnet-4-5" /* SONNET */,
259
259
  role: `Fact-checking specialist. Demands evidence for claims, verifies factual accuracy, and points out flaws. The one who asks "What's your evidence?"`
260
260
  },
261
261
  {
@@ -263,7 +263,7 @@ var AGENT_DEFINITIONS = [
263
263
  name: "Blunt Critic",
264
264
  emoji: "\u{1F525}",
265
265
  category: "CRITIQUE" /* CRITIQUE */,
266
- model: "claude-sonnet-4-5" /* SONNET */,
266
+ model: "anthropic/claude-sonnet-4-5" /* SONNET */,
267
267
  role: "Sharp direct feedback specialist. Points out problems directly without beating around the bush. Speaks uncomfortable but necessary truths."
268
268
  },
269
269
  {
@@ -271,7 +271,7 @@ var AGENT_DEFINITIONS = [
271
271
  name: "Critic",
272
272
  emoji: "\u{1F9D0}",
273
273
  category: "CRITIQUE" /* CRITIQUE */,
274
- model: "claude-opus-4-5" /* OPUS */,
274
+ model: "anthropic/claude-opus-4-5" /* OPUS */,
275
275
  role: "Logical criticism specialist. Logically analyzes and critiques problems in plans or deliverables. Provides improvement suggestions alongside criticism."
276
276
  },
277
277
  {
@@ -279,7 +279,7 @@ var AGENT_DEFINITIONS = [
279
279
  name: "Negative Agent",
280
280
  emoji: "\u{1F44E}",
281
281
  category: "CRITIQUE" /* CRITIQUE */,
282
- model: "claude-sonnet-4-5" /* SONNET */,
282
+ model: "anthropic/claude-sonnet-4-5" /* SONNET */,
283
283
  role: "Devil's advocate. Intentionally views things from a negative perspective. Raises worst-case scenarios, failure possibilities, and risks. Prevents the team from falling into blind optimism."
284
284
  },
285
285
  {
@@ -287,7 +287,7 @@ var AGENT_DEFINITIONS = [
287
287
  name: "Praise Specialist",
288
288
  emoji: "\u{1F44F}",
289
289
  category: "CRITIQUE" /* CRITIQUE */,
290
- model: "claude-haiku-4-5" /* HAIKU */,
290
+ model: "anthropic/claude-haiku-3-5" /* HAIKU */,
291
291
  role: "Positive feedback specialist. Finds and praises what was done well, boosts morale, and provides motivation. Balances against critical agents."
292
292
  },
293
293
  // ============================================================================
@@ -298,7 +298,7 @@ var AGENT_DEFINITIONS = [
298
298
  name: "Loophole Discovery Specialist",
299
299
  emoji: "\u{1F573}\uFE0F",
300
300
  category: "SPECIAL" /* SPECIAL */,
301
- model: "claude-sonnet-4-5" /* SONNET */,
301
+ model: "anthropic/claude-sonnet-4-5" /* SONNET */,
302
302
  role: 'Within-rules optimization specialist. Finds workarounds, shortcuts, and clever solutions within established rules or constraints. Answers the question "Is there a way?"'
303
303
  },
304
304
  {
@@ -306,7 +306,7 @@ var AGENT_DEFINITIONS = [
306
306
  name: "Pressure Specialist",
307
307
  emoji: "\u26A1",
308
308
  category: "SPECIAL" /* SPECIAL */,
309
- model: "claude-sonnet-4-5" /* SONNET */,
309
+ model: "anthropic/claude-sonnet-4-5" /* SONNET */,
310
310
  role: "Urgency and pressure specialist. Creates urgency by emphasizing deadline pressure, time limits, and severity of consequences. Pressures agents who are slacking or reluctant to work properly. The team's whip."
311
311
  },
312
312
  {
@@ -314,7 +314,7 @@ var AGENT_DEFINITIONS = [
314
314
  name: "Dirty Worker",
315
315
  emoji: "\u{1FAA0}",
316
316
  category: "SPECIAL" /* SPECIAL */,
317
- model: "claude-haiku-4-5" /* HAIKU */,
317
+ model: "anthropic/claude-haiku-3-5" /* HAIKU */,
318
318
  role: "Undesirable tasks handler. Takes on work that other agents dislike or refuse. Performs boring, repetitive, or tasks nobody wants to do."
319
319
  }
320
320
  ];
@@ -1925,6 +1925,811 @@ var DiscordAdapter = class {
1925
1925
  }
1926
1926
  };
1927
1927
 
1928
+ // src/daemon/OpenClawDaemon.ts
1929
+ import { EventEmitter as EventEmitter2 } from "events";
1930
+ import { execSync } from "child_process";
1931
+
1932
+ // src/openclaw/GatewayClient.ts
1933
+ import WebSocket from "ws";
1934
+ import { EventEmitter } from "events";
1935
+ var DEFAULT_CONFIG2 = {
1936
+ url: "ws://127.0.0.1:18789",
1937
+ reconnect: {
1938
+ enabled: true,
1939
+ maxAttempts: 10,
1940
+ baseDelay: 1e3,
1941
+ maxDelay: 3e4
1942
+ },
1943
+ heartbeatInterval: 3e4,
1944
+ connectionTimeout: 1e4
1945
+ };
1946
+ var GatewayClient = class extends EventEmitter {
1947
+ ws = null;
1948
+ config;
1949
+ state = "disconnected" /* DISCONNECTED */;
1950
+ reconnectAttempts = 0;
1951
+ reconnectTimer = null;
1952
+ heartbeatTimer = null;
1953
+ connectionTimeoutTimer = null;
1954
+ intentionalClose = false;
1955
+ lastPongTime = 0;
1956
+ constructor(config = {}) {
1957
+ super();
1958
+ this.config = {
1959
+ ...DEFAULT_CONFIG2,
1960
+ ...config,
1961
+ reconnect: {
1962
+ ...DEFAULT_CONFIG2.reconnect,
1963
+ ...config.reconnect
1964
+ }
1965
+ };
1966
+ }
1967
+ /**
1968
+ * Get current connection state
1969
+ */
1970
+ get connectionState() {
1971
+ return this.state;
1972
+ }
1973
+ /**
1974
+ * Check if connected to gateway
1975
+ */
1976
+ get isConnected() {
1977
+ return this.state === "connected" /* CONNECTED */ && this.ws?.readyState === WebSocket.OPEN;
1978
+ }
1979
+ /**
1980
+ * Connect to the OpenClaw Gateway
1981
+ */
1982
+ async connect() {
1983
+ if (this.state === "connected" /* CONNECTED */ || this.state === "connecting" /* CONNECTING */) {
1984
+ return;
1985
+ }
1986
+ this.intentionalClose = false;
1987
+ await this.doConnect();
1988
+ }
1989
+ /**
1990
+ * Disconnect from the gateway
1991
+ */
1992
+ async disconnect() {
1993
+ this.intentionalClose = true;
1994
+ this.clearTimers();
1995
+ this.setState("closed" /* CLOSED */);
1996
+ if (this.ws) {
1997
+ this.ws.close(1e3, "Client disconnect");
1998
+ this.ws = null;
1999
+ }
2000
+ }
2001
+ /**
2002
+ * Send a message to the gateway
2003
+ */
2004
+ send(message) {
2005
+ if (!this.isConnected || !this.ws) {
2006
+ return false;
2007
+ }
2008
+ try {
2009
+ this.ws.send(JSON.stringify(message));
2010
+ return true;
2011
+ } catch {
2012
+ return false;
2013
+ }
2014
+ }
2015
+ /**
2016
+ * Send a ping to the gateway
2017
+ */
2018
+ ping() {
2019
+ return this.send({ type: "ping", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
2020
+ }
2021
+ /**
2022
+ * Request gateway status
2023
+ */
2024
+ requestStatus() {
2025
+ return this.send({ type: "status" });
2026
+ }
2027
+ /**
2028
+ * Request gateway health
2029
+ */
2030
+ requestHealth() {
2031
+ return this.send({ type: "health" });
2032
+ }
2033
+ // ============================================
2034
+ // Private Methods
2035
+ // ============================================
2036
+ async doConnect() {
2037
+ return new Promise((resolve, reject) => {
2038
+ this.setState("connecting" /* CONNECTING */);
2039
+ try {
2040
+ this.ws = new WebSocket(this.config.url);
2041
+ } catch (error) {
2042
+ this.setState("disconnected" /* DISCONNECTED */);
2043
+ reject(error);
2044
+ return;
2045
+ }
2046
+ this.connectionTimeoutTimer = setTimeout(() => {
2047
+ if (this.state === "connecting" /* CONNECTING */) {
2048
+ this.ws?.close();
2049
+ this.ws = null;
2050
+ this.setState("disconnected" /* DISCONNECTED */);
2051
+ reject(new Error(`Connection timeout after ${this.config.connectionTimeout}ms`));
2052
+ }
2053
+ }, this.config.connectionTimeout);
2054
+ this.ws.on("open", () => {
2055
+ this.clearConnectionTimeout();
2056
+ this.reconnectAttempts = 0;
2057
+ this.lastPongTime = Date.now();
2058
+ this.setState("connected" /* CONNECTED */);
2059
+ this.startHeartbeat();
2060
+ this.emit("connect");
2061
+ resolve();
2062
+ });
2063
+ this.ws.on("message", (data) => {
2064
+ this.handleMessage(data);
2065
+ });
2066
+ this.ws.on("close", (code, reason) => {
2067
+ this.clearTimers();
2068
+ const reasonStr = reason.toString() || "Unknown reason";
2069
+ this.emit("disconnect", code, reasonStr);
2070
+ if (!this.intentionalClose && this.config.reconnect.enabled) {
2071
+ this.scheduleReconnect();
2072
+ } else {
2073
+ this.setState("disconnected" /* DISCONNECTED */);
2074
+ }
2075
+ });
2076
+ this.ws.on("error", (error) => {
2077
+ this.emit("error", error);
2078
+ });
2079
+ this.ws.on("pong", () => {
2080
+ this.lastPongTime = Date.now();
2081
+ });
2082
+ });
2083
+ }
2084
+ handleMessage(data) {
2085
+ let message;
2086
+ try {
2087
+ const str = data.toString();
2088
+ message = JSON.parse(str);
2089
+ } catch {
2090
+ return;
2091
+ }
2092
+ this.emit("message", message);
2093
+ switch (message.type) {
2094
+ case "shutdown" /* SHUTDOWN */:
2095
+ this.emit("shutdown");
2096
+ break;
2097
+ case "pong" /* PONG */:
2098
+ this.lastPongTime = Date.now();
2099
+ break;
2100
+ case "agent_response" /* AGENT_RESPONSE */:
2101
+ case "assistant":
2102
+ this.emit("agent_response", message);
2103
+ break;
2104
+ case "agent_delta" /* AGENT_DELTA */:
2105
+ case "delta":
2106
+ this.emit("agent_delta", message);
2107
+ break;
2108
+ case "agent_start" /* AGENT_START */:
2109
+ case "start":
2110
+ this.emit("agent_start", message);
2111
+ break;
2112
+ case "agent_end" /* AGENT_END */:
2113
+ case "end":
2114
+ case "complete":
2115
+ this.emit("agent_end", message);
2116
+ break;
2117
+ case "message" /* MESSAGE */:
2118
+ case "channel_message" /* CHANNEL_MESSAGE */:
2119
+ case "discord":
2120
+ this.emit("channel_message", message);
2121
+ break;
2122
+ case "error" /* ERROR */:
2123
+ this.emit("error", new Error(message.error || "Unknown gateway error"));
2124
+ break;
2125
+ default:
2126
+ break;
2127
+ }
2128
+ }
2129
+ scheduleReconnect() {
2130
+ const { maxAttempts = 10, baseDelay = 1e3, maxDelay = 3e4 } = this.config.reconnect;
2131
+ if (maxAttempts !== -1 && this.reconnectAttempts >= maxAttempts) {
2132
+ this.setState("disconnected" /* DISCONNECTED */);
2133
+ this.emit("reconnect_failed");
2134
+ return;
2135
+ }
2136
+ this.setState("reconnecting" /* RECONNECTING */);
2137
+ this.reconnectAttempts++;
2138
+ const delay = Math.min(
2139
+ baseDelay * Math.pow(2, this.reconnectAttempts - 1),
2140
+ maxDelay
2141
+ );
2142
+ this.emit("reconnecting", this.reconnectAttempts, maxAttempts);
2143
+ this.reconnectTimer = setTimeout(async () => {
2144
+ try {
2145
+ await this.doConnect();
2146
+ } catch {
2147
+ }
2148
+ }, delay);
2149
+ }
2150
+ startHeartbeat() {
2151
+ if (this.config.heartbeatInterval <= 0) {
2152
+ return;
2153
+ }
2154
+ this.heartbeatTimer = setInterval(() => {
2155
+ if (!this.isConnected) {
2156
+ return;
2157
+ }
2158
+ const timeSinceLastPong = Date.now() - this.lastPongTime;
2159
+ if (timeSinceLastPong > this.config.heartbeatInterval * 2) {
2160
+ this.ws?.close(4e3, "Heartbeat timeout");
2161
+ return;
2162
+ }
2163
+ try {
2164
+ this.ws?.ping();
2165
+ } catch {
2166
+ }
2167
+ }, this.config.heartbeatInterval);
2168
+ }
2169
+ setState(state) {
2170
+ if (this.state !== state) {
2171
+ this.state = state;
2172
+ this.emit("state_change", state);
2173
+ }
2174
+ }
2175
+ clearTimers() {
2176
+ this.clearConnectionTimeout();
2177
+ this.clearReconnectTimer();
2178
+ this.clearHeartbeat();
2179
+ }
2180
+ clearConnectionTimeout() {
2181
+ if (this.connectionTimeoutTimer) {
2182
+ clearTimeout(this.connectionTimeoutTimer);
2183
+ this.connectionTimeoutTimer = null;
2184
+ }
2185
+ }
2186
+ clearReconnectTimer() {
2187
+ if (this.reconnectTimer) {
2188
+ clearTimeout(this.reconnectTimer);
2189
+ this.reconnectTimer = null;
2190
+ }
2191
+ }
2192
+ clearHeartbeat() {
2193
+ if (this.heartbeatTimer) {
2194
+ clearInterval(this.heartbeatTimer);
2195
+ this.heartbeatTimer = null;
2196
+ }
2197
+ }
2198
+ };
2199
+
2200
+ // src/daemon/AgentMapper.ts
2201
+ var AgentMapper = class {
2202
+ idMap = /* @__PURE__ */ new Map();
2203
+ nameMap = /* @__PURE__ */ new Map();
2204
+ aliasMap = /* @__PURE__ */ new Map();
2205
+ constructor() {
2206
+ this.buildMaps();
2207
+ }
2208
+ /**
2209
+ * Build lookup maps for efficient agent resolution
2210
+ */
2211
+ buildMaps() {
2212
+ for (const agent of AGENT_DEFINITIONS) {
2213
+ this.idMap.set(agent.id, agent);
2214
+ this.idMap.set(agent.id.toLowerCase(), agent);
2215
+ const normalizedName = this.normalizeName(agent.name);
2216
+ this.nameMap.set(normalizedName, agent);
2217
+ this.buildAliases(agent);
2218
+ }
2219
+ }
2220
+ /**
2221
+ * Build common aliases for an agent
2222
+ */
2223
+ buildAliases(agent) {
2224
+ const { id, name } = agent;
2225
+ this.aliasMap.set(id.replace(/-/g, "_"), agent);
2226
+ const camelCase = id.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
2227
+ this.aliasMap.set(camelCase, agent);
2228
+ this.aliasMap.set(camelCase.toLowerCase(), agent);
2229
+ this.aliasMap.set(name.replace(/\s+/g, "").toLowerCase(), agent);
2230
+ this.aliasMap.set(name.replace(/\s+/g, "_").toLowerCase(), agent);
2231
+ const specialAliases = {
2232
+ "base": ["coordinator", "main", "primary", "default", "openclaw"],
2233
+ "backend-dev": ["backend", "server", "api"],
2234
+ "frontend-dev": ["frontend", "ui", "web"],
2235
+ "code-reviewer": ["reviewer", "review"],
2236
+ "program-tester": ["tester", "qa", "testing"],
2237
+ "security-checker": ["security", "securitycheck"],
2238
+ "vuln-finder": ["vulnerability", "vulnscanner"],
2239
+ "tech-researcher": ["researcher", "research"],
2240
+ "doc-writer": ["documentation", "docs", "writer"],
2241
+ "prompt-engineer": ["prompter", "prompt"],
2242
+ "ai-illustrator": ["illustrator", "artist", "image"],
2243
+ "user-psychologist": ["psychologist", "psychology"],
2244
+ "fact-bomber": ["factcheck", "factchecker"],
2245
+ "dirty-worker": ["worker", "grunt"]
2246
+ };
2247
+ if (specialAliases[id]) {
2248
+ for (const alias of specialAliases[id]) {
2249
+ this.aliasMap.set(alias, agent);
2250
+ }
2251
+ }
2252
+ }
2253
+ /**
2254
+ * Normalize a name for comparison
2255
+ */
2256
+ normalizeName(name) {
2257
+ return name.toLowerCase().replace(/[^a-z0-9]/g, "").trim();
2258
+ }
2259
+ /**
2260
+ * Resolve an OpenClaw agent identifier to a TMC agent
2261
+ * Tries multiple matching strategies
2262
+ */
2263
+ resolve(identifier) {
2264
+ if (!identifier) {
2265
+ return this.getDefaultAgent();
2266
+ }
2267
+ const normalized = identifier.toLowerCase().trim();
2268
+ const byId = this.idMap.get(normalized);
2269
+ if (byId) return byId;
2270
+ const byName = this.nameMap.get(this.normalizeName(identifier));
2271
+ if (byName) return byName;
2272
+ const byAlias = this.aliasMap.get(normalized);
2273
+ if (byAlias) return byAlias;
2274
+ const partial = this.partialMatch(normalized);
2275
+ if (partial) return partial;
2276
+ return this.getDefaultAgent();
2277
+ }
2278
+ /**
2279
+ * Try partial/fuzzy matching
2280
+ */
2281
+ partialMatch(query) {
2282
+ for (const agent of AGENT_DEFINITIONS) {
2283
+ if (agent.id.includes(query) || query.includes(agent.id)) {
2284
+ return agent;
2285
+ }
2286
+ }
2287
+ const normalizedQuery = this.normalizeName(query);
2288
+ for (const agent of AGENT_DEFINITIONS) {
2289
+ const normalizedAgentName = this.normalizeName(agent.name);
2290
+ if (normalizedAgentName.includes(normalizedQuery) || normalizedQuery.includes(normalizedAgentName)) {
2291
+ return agent;
2292
+ }
2293
+ }
2294
+ return null;
2295
+ }
2296
+ /**
2297
+ * Get the default agent (base/coordinator)
2298
+ */
2299
+ getDefaultAgent() {
2300
+ return getAgentById("base") || AGENT_DEFINITIONS[0];
2301
+ }
2302
+ /**
2303
+ * Check if an identifier maps to a known agent
2304
+ */
2305
+ isKnownAgent(identifier) {
2306
+ return this.resolve(identifier) !== null;
2307
+ }
2308
+ /**
2309
+ * Get all registered agent IDs
2310
+ */
2311
+ getAllAgentIds() {
2312
+ return AGENT_DEFINITIONS.map((a) => a.id);
2313
+ }
2314
+ };
2315
+
2316
+ // src/daemon/OpenClawDaemon.ts
2317
+ var DEFAULT_CONFIG3 = {
2318
+ gatewayUrl: "ws://127.0.0.1:18789",
2319
+ autoStart: true,
2320
+ processCheckInterval: 5e3,
2321
+ verbose: false
2322
+ };
2323
+ var OpenClawDaemon = class extends EventEmitter2 {
2324
+ config;
2325
+ gatewayClient;
2326
+ webhookManager;
2327
+ configManager;
2328
+ agentMapper;
2329
+ running = false;
2330
+ startTime = null;
2331
+ processCheckTimer = null;
2332
+ openclawDetected = false;
2333
+ // Stats
2334
+ messagesProcessed = 0;
2335
+ messagesForwarded = 0;
2336
+ webhookErrors = 0;
2337
+ lastMessageAt = null;
2338
+ reconnectAttempts = 0;
2339
+ // Track active agents in conversation
2340
+ activeAgents = /* @__PURE__ */ new Set();
2341
+ // Buffer for accumulating streaming responses
2342
+ responseBuffers = /* @__PURE__ */ new Map();
2343
+ bufferCleanupTimer = null;
2344
+ // Buffer stale threshold in ms (60 seconds)
2345
+ BUFFER_STALE_THRESHOLD = 6e4;
2346
+ constructor(config = {}) {
2347
+ super();
2348
+ this.config = { ...DEFAULT_CONFIG3, ...config };
2349
+ this.configManager = new ConfigManager();
2350
+ this.webhookManager = new WebhookManager();
2351
+ this.agentMapper = new AgentMapper();
2352
+ this.gatewayClient = new GatewayClient({
2353
+ url: this.config.gatewayUrl,
2354
+ reconnect: {
2355
+ enabled: true,
2356
+ maxAttempts: -1,
2357
+ // Infinite reconnection
2358
+ baseDelay: 1e3,
2359
+ maxDelay: 3e4
2360
+ }
2361
+ });
2362
+ this.setupEventHandlers();
2363
+ this.loadWebhooks();
2364
+ }
2365
+ /**
2366
+ * Start the daemon
2367
+ */
2368
+ async start() {
2369
+ if (this.running) {
2370
+ return;
2371
+ }
2372
+ this.running = true;
2373
+ this.startTime = /* @__PURE__ */ new Date();
2374
+ this.emit("start");
2375
+ this.forceLog("Daemon starting...");
2376
+ this.startBufferCleanup();
2377
+ if (this.config.autoStart) {
2378
+ this.startProcessDetection();
2379
+ }
2380
+ await this.connect();
2381
+ }
2382
+ /**
2383
+ * Stop the daemon
2384
+ */
2385
+ async stop() {
2386
+ if (!this.running) {
2387
+ return;
2388
+ }
2389
+ this.running = false;
2390
+ this.forceLog("Daemon stopping...");
2391
+ this.stopProcessDetection();
2392
+ this.stopBufferCleanup();
2393
+ await this.gatewayClient.disconnect();
2394
+ this.webhookManager.destroy();
2395
+ this.emit("stop");
2396
+ }
2397
+ /**
2398
+ * Connect to OpenClaw Gateway
2399
+ */
2400
+ async connect() {
2401
+ try {
2402
+ await this.gatewayClient.connect();
2403
+ return true;
2404
+ } catch (error) {
2405
+ this.log(`Connection failed: ${error instanceof Error ? error.message : "Unknown error"}`);
2406
+ return false;
2407
+ }
2408
+ }
2409
+ /**
2410
+ * Get daemon statistics
2411
+ */
2412
+ getStats() {
2413
+ return {
2414
+ connected: this.gatewayClient.isConnected,
2415
+ connectionState: this.gatewayClient.connectionState,
2416
+ messagesProcessed: this.messagesProcessed,
2417
+ messagesForwarded: this.messagesForwarded,
2418
+ webhookErrors: this.webhookErrors,
2419
+ lastMessageAt: this.lastMessageAt,
2420
+ uptimeMs: this.startTime ? Date.now() - this.startTime.getTime() : 0,
2421
+ reconnectAttempts: this.reconnectAttempts
2422
+ };
2423
+ }
2424
+ /**
2425
+ * Check if daemon is running
2426
+ */
2427
+ get isRunning() {
2428
+ return this.running;
2429
+ }
2430
+ /**
2431
+ * Check if connected to OpenClaw
2432
+ */
2433
+ get isConnected() {
2434
+ return this.gatewayClient.isConnected;
2435
+ }
2436
+ /**
2437
+ * Get list of active agents
2438
+ */
2439
+ getActiveAgents() {
2440
+ return Array.from(this.activeAgents);
2441
+ }
2442
+ // ============================================
2443
+ // Private Methods
2444
+ // ============================================
2445
+ /**
2446
+ * Set up event handlers for the gateway client
2447
+ */
2448
+ setupEventHandlers() {
2449
+ this.gatewayClient.on("connect", () => {
2450
+ this.forceLog("Connected to OpenClaw Gateway");
2451
+ this.openclawDetected = true;
2452
+ this.emit("connected");
2453
+ this.emit("openclaw_detected");
2454
+ });
2455
+ this.gatewayClient.on("disconnect", (code, reason) => {
2456
+ this.forceLog(`Disconnected from Gateway: ${code} - ${reason}`);
2457
+ this.emit("disconnected", reason);
2458
+ });
2459
+ this.gatewayClient.on("reconnecting", (attempt) => {
2460
+ this.reconnectAttempts = attempt;
2461
+ this.forceLog(`Reconnecting... (attempt ${attempt})`);
2462
+ this.emit("reconnecting", attempt);
2463
+ });
2464
+ this.gatewayClient.on("reconnect_failed", () => {
2465
+ this.forceLog("Reconnection failed - max attempts reached");
2466
+ if (this.openclawDetected) {
2467
+ this.openclawDetected = false;
2468
+ this.emit("openclaw_lost");
2469
+ }
2470
+ });
2471
+ this.gatewayClient.on("error", (error) => {
2472
+ this.forceLog(`Gateway error: ${error.message}`);
2473
+ this.emit("error", error);
2474
+ });
2475
+ this.gatewayClient.on("shutdown", () => {
2476
+ this.forceLog("Gateway shutdown signal received");
2477
+ this.openclawDetected = false;
2478
+ this.emit("openclaw_lost");
2479
+ });
2480
+ this.gatewayClient.on("message", (message) => {
2481
+ this.handleRawMessage(message);
2482
+ });
2483
+ this.gatewayClient.on("agent_response", (message) => {
2484
+ this.handleAgentResponse(message);
2485
+ });
2486
+ this.gatewayClient.on("agent_delta", (message) => {
2487
+ this.handleAgentDelta(message);
2488
+ });
2489
+ this.gatewayClient.on("agent_start", (message) => {
2490
+ this.handleAgentStart(message);
2491
+ });
2492
+ this.gatewayClient.on("agent_end", (message) => {
2493
+ this.handleAgentEnd(message);
2494
+ });
2495
+ this.gatewayClient.on("channel_message", (message) => {
2496
+ this.handleChannelMessage(message);
2497
+ });
2498
+ }
2499
+ /**
2500
+ * Load webhooks from configuration
2501
+ */
2502
+ loadWebhooks() {
2503
+ const webhooks = this.configManager.getAllWebhooks();
2504
+ if (Object.keys(webhooks).length > 0) {
2505
+ this.webhookManager.setWebhooks(webhooks);
2506
+ this.log(`Loaded ${Object.keys(webhooks).length} webhooks`);
2507
+ } else {
2508
+ this.log("No webhooks configured - messages will not be forwarded to Discord");
2509
+ }
2510
+ }
2511
+ /**
2512
+ * Handle raw message from gateway (for debugging/logging)
2513
+ */
2514
+ handleRawMessage(message) {
2515
+ this.messagesProcessed++;
2516
+ this.lastMessageAt = /* @__PURE__ */ new Date();
2517
+ if (this.config.verbose) {
2518
+ this.log(`Raw message: ${JSON.stringify(message).substring(0, 200)}...`);
2519
+ }
2520
+ }
2521
+ /**
2522
+ * Handle agent response (complete response)
2523
+ */
2524
+ async handleAgentResponse(message) {
2525
+ const agentIdentifier = message.agentId || message.agentName || message.agent;
2526
+ const content = message.content || message.text || message.message;
2527
+ if (!content) {
2528
+ return;
2529
+ }
2530
+ const agent = this.agentMapper.resolve(agentIdentifier);
2531
+ if (!agent) {
2532
+ this.log(`Unknown agent: ${agentIdentifier}`);
2533
+ return;
2534
+ }
2535
+ this.emit("message_received", agent.id, content);
2536
+ await this.forwardToWebhook(agent, content);
2537
+ }
2538
+ /**
2539
+ * Handle streaming delta (partial response)
2540
+ */
2541
+ handleAgentDelta(message) {
2542
+ const agentIdentifier = message.agentId || message.agentName || message.agent;
2543
+ const delta = message.delta || message.content || message.text;
2544
+ const messageId = message.id || agentIdentifier || "default";
2545
+ if (!delta) {
2546
+ return;
2547
+ }
2548
+ const existing = this.responseBuffers.get(messageId);
2549
+ if (existing) {
2550
+ existing.content += delta;
2551
+ existing.lastUpdate = Date.now();
2552
+ } else {
2553
+ const agent = this.agentMapper.resolve(agentIdentifier);
2554
+ this.responseBuffers.set(messageId, {
2555
+ agentId: agent?.id || "base",
2556
+ content: delta,
2557
+ lastUpdate: Date.now()
2558
+ });
2559
+ }
2560
+ }
2561
+ /**
2562
+ * Handle agent start event
2563
+ */
2564
+ handleAgentStart(message) {
2565
+ const agentIdentifier = message.agentId || message.agentName || message.agent;
2566
+ const agent = this.agentMapper.resolve(agentIdentifier);
2567
+ if (agent && !this.activeAgents.has(agent.id)) {
2568
+ this.activeAgents.add(agent.id);
2569
+ this.emit("agent_enter", agent);
2570
+ this.log(`Agent entered: ${agent.emoji} ${agent.name}`);
2571
+ }
2572
+ }
2573
+ /**
2574
+ * Handle agent end event (flush buffer and send)
2575
+ */
2576
+ async handleAgentEnd(message) {
2577
+ const messageId = message.id || message.agentId || message.agentName || "default";
2578
+ const agentIdentifier = message.agentId || message.agentName || message.agent;
2579
+ const buffered = this.responseBuffers.get(messageId);
2580
+ if (buffered && buffered.content) {
2581
+ const agent2 = this.agentMapper.resolve(buffered.agentId) || this.agentMapper.getDefaultAgent();
2582
+ this.emit("message_received", agent2.id, buffered.content);
2583
+ await this.forwardToWebhook(agent2, buffered.content);
2584
+ this.responseBuffers.delete(messageId);
2585
+ }
2586
+ const content = message.content || message.text;
2587
+ if (content) {
2588
+ const agent2 = this.agentMapper.resolve(agentIdentifier);
2589
+ if (agent2) {
2590
+ this.emit("message_received", agent2.id, content);
2591
+ await this.forwardToWebhook(agent2, content);
2592
+ }
2593
+ }
2594
+ const agent = this.agentMapper.resolve(agentIdentifier);
2595
+ if (agent && message.complete !== false) {
2596
+ }
2597
+ }
2598
+ /**
2599
+ * Handle channel message (user messages from Discord)
2600
+ */
2601
+ handleChannelMessage(message) {
2602
+ if (this.config.verbose) {
2603
+ this.log(`Channel message from ${message.author?.name || "unknown"}: ${message.content?.substring(0, 50)}...`);
2604
+ }
2605
+ }
2606
+ /**
2607
+ * Forward a message to Discord via webhook
2608
+ */
2609
+ async forwardToWebhook(agent, content) {
2610
+ let webhookAgentId = agent.id;
2611
+ if (!this.webhookManager.hasWebhook(agent.id)) {
2612
+ if (!this.webhookManager.hasWebhook("base")) {
2613
+ this.log(`No webhook available for agent: ${agent.id}`);
2614
+ return;
2615
+ }
2616
+ webhookAgentId = "base";
2617
+ this.log(`Using base webhook for agent: ${agent.id}`);
2618
+ }
2619
+ try {
2620
+ await this.webhookManager.sendAsAgent(webhookAgentId, content);
2621
+ this.messagesForwarded++;
2622
+ this.emit("message_forwarded", agent.id, content);
2623
+ this.log(`Forwarded message from ${agent.emoji} ${agent.name}`);
2624
+ } catch (error) {
2625
+ this.webhookErrors++;
2626
+ this.log(`Failed to forward message: ${error instanceof Error ? error.message : "Unknown error"}`);
2627
+ this.emit("error", error instanceof Error ? error : new Error("Webhook send failed"));
2628
+ }
2629
+ }
2630
+ /**
2631
+ * Start process detection loop
2632
+ */
2633
+ startProcessDetection() {
2634
+ if (this.processCheckTimer) {
2635
+ return;
2636
+ }
2637
+ this.processCheckTimer = setInterval(() => {
2638
+ this.checkOpenClawProcess();
2639
+ }, this.config.processCheckInterval);
2640
+ }
2641
+ /**
2642
+ * Stop process detection loop
2643
+ */
2644
+ stopProcessDetection() {
2645
+ if (this.processCheckTimer) {
2646
+ clearInterval(this.processCheckTimer);
2647
+ this.processCheckTimer = null;
2648
+ }
2649
+ }
2650
+ /**
2651
+ * Check if OpenClaw process is running
2652
+ */
2653
+ checkOpenClawProcess() {
2654
+ const isRunning = this.isOpenClawRunning();
2655
+ if (isRunning && !this.gatewayClient.isConnected) {
2656
+ this.log("OpenClaw process detected, attempting to connect...");
2657
+ this.connect();
2658
+ } else if (!isRunning && this.openclawDetected) {
2659
+ this.openclawDetected = false;
2660
+ this.emit("openclaw_lost");
2661
+ }
2662
+ }
2663
+ /**
2664
+ * Start periodic cleanup of stale response buffers
2665
+ */
2666
+ startBufferCleanup() {
2667
+ if (this.bufferCleanupTimer) {
2668
+ return;
2669
+ }
2670
+ this.bufferCleanupTimer = setInterval(() => {
2671
+ const now = Date.now();
2672
+ let cleanedCount = 0;
2673
+ for (const [id, buffer] of this.responseBuffers) {
2674
+ if (now - buffer.lastUpdate > this.BUFFER_STALE_THRESHOLD) {
2675
+ if (buffer.content.trim()) {
2676
+ const agent = this.agentMapper.resolve(buffer.agentId) || this.agentMapper.getDefaultAgent();
2677
+ this.forwardToWebhook(agent, buffer.content).catch(() => {
2678
+ });
2679
+ }
2680
+ this.responseBuffers.delete(id);
2681
+ cleanedCount++;
2682
+ }
2683
+ }
2684
+ if (cleanedCount > 0 && this.config.verbose) {
2685
+ this.log(`Cleaned ${cleanedCount} stale response buffer(s)`);
2686
+ }
2687
+ }, 3e4);
2688
+ }
2689
+ /**
2690
+ * Stop buffer cleanup interval
2691
+ */
2692
+ stopBufferCleanup() {
2693
+ if (this.bufferCleanupTimer) {
2694
+ clearInterval(this.bufferCleanupTimer);
2695
+ this.bufferCleanupTimer = null;
2696
+ }
2697
+ }
2698
+ /**
2699
+ * Check if OpenClaw process is running on the system
2700
+ */
2701
+ isOpenClawRunning() {
2702
+ try {
2703
+ const platform = process.platform;
2704
+ if (platform === "win32") {
2705
+ const result = execSync('tasklist /FI "IMAGENAME eq node.exe" /FO CSV', { encoding: "utf8", timeout: 5e3 });
2706
+ return result.toLowerCase().includes("openclaw");
2707
+ } else {
2708
+ const result = execSync("ps aux", { encoding: "utf8", timeout: 5e3 });
2709
+ return result.toLowerCase().includes("openclaw");
2710
+ }
2711
+ } catch {
2712
+ return true;
2713
+ }
2714
+ }
2715
+ /**
2716
+ * Log a message (if verbose mode or important)
2717
+ */
2718
+ log(message) {
2719
+ if (this.config.verbose) {
2720
+ const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString();
2721
+ console.log(`[${timestamp}] [TMC Daemon] ${message}`);
2722
+ }
2723
+ }
2724
+ /**
2725
+ * Force log regardless of verbose setting
2726
+ */
2727
+ forceLog(message) {
2728
+ const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString();
2729
+ console.log(`[${timestamp}] [TMC Daemon] ${message}`);
2730
+ }
2731
+ };
2732
+
1928
2733
  // src/cli.ts
1929
2734
  var program = new Command();
1930
2735
  program.name("tmc").description("Too Many Claw - 35 AI agents collaborating via Discord").version("1.0.4");
@@ -2666,6 +3471,131 @@ program.command("debug").description("Debug OpenClaw configuration detection").o
2666
3471
  console.log(chalk3.gray(" Check the paths above to see where Discord settings are stored.\n"));
2667
3472
  }
2668
3473
  });
3474
+ program.command("daemon").description("Run daemon mode to auto-connect to OpenClaw and forward agent messages via webhooks").option("-v, --verbose", "Enable verbose logging").option("--url <url>", "OpenClaw Gateway URL", "ws://127.0.0.1:18789").action(async (options) => {
3475
+ console.log(chalk3.cyan(`
3476
+ \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
3477
+ \u2551 \u2551
3478
+ \u2551 \u{1F980} Too Many Claw - Daemon Mode \u2551
3479
+ \u2551 \u2551
3480
+ \u2551 Auto-connects to OpenClaw and forwards agent messages \u2551
3481
+ \u2551 through Discord webhooks \u2551
3482
+ \u2551 \u2551
3483
+ \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
3484
+ `));
3485
+ const config = new ConfigManager();
3486
+ const webhooks = config.getAllWebhooks();
3487
+ if (Object.keys(webhooks).length === 0) {
3488
+ console.log(chalk3.yellow("\u26A0 No webhooks configured."));
3489
+ console.log(chalk3.gray(" Agent messages will not be forwarded to Discord."));
3490
+ console.log(chalk3.gray(" Run `tmc setup` to configure webhooks.\n"));
3491
+ } else {
3492
+ console.log(chalk3.green(`\u2713 ${Object.keys(webhooks).length} webhooks loaded
3493
+ `));
3494
+ }
3495
+ const daemon = new OpenClawDaemon({
3496
+ gatewayUrl: options.url,
3497
+ verbose: options.verbose || false,
3498
+ autoStart: true
3499
+ });
3500
+ let statusSpinner = ora("Connecting to OpenClaw Gateway...").start();
3501
+ let statsInterval = null;
3502
+ let isShuttingDown = false;
3503
+ daemon.on("connected", () => {
3504
+ statusSpinner.succeed("Connected to OpenClaw Gateway");
3505
+ console.log(chalk3.green("\n\u{1F99E} Daemon is now running!"));
3506
+ console.log(chalk3.gray(" Listening for agent responses..."));
3507
+ console.log(chalk3.gray(" Press Ctrl+C to stop.\n"));
3508
+ statsInterval = setInterval(() => {
3509
+ const stats = daemon.getStats();
3510
+ if (stats.messagesProcessed > 0 || options.verbose) {
3511
+ const uptime = formatUptime(stats.uptimeMs);
3512
+ console.log(chalk3.gray(
3513
+ `[Stats] Uptime: ${uptime} | Messages: ${stats.messagesProcessed} processed, ${stats.messagesForwarded} forwarded | Errors: ${stats.webhookErrors}`
3514
+ ));
3515
+ }
3516
+ }, 3e4);
3517
+ });
3518
+ daemon.on("disconnected", (reason) => {
3519
+ if (!isShuttingDown) {
3520
+ console.log(chalk3.yellow(`
3521
+ \u26A0 Disconnected: ${reason}`));
3522
+ statusSpinner = ora("Waiting for OpenClaw Gateway...").start();
3523
+ }
3524
+ });
3525
+ daemon.on("reconnecting", (attempt) => {
3526
+ statusSpinner.text = `Reconnecting to OpenClaw Gateway... (attempt ${attempt})`;
3527
+ });
3528
+ daemon.on("openclaw_detected", () => {
3529
+ if (options.verbose) {
3530
+ console.log(chalk3.green("\n\u2713 OpenClaw process detected"));
3531
+ }
3532
+ });
3533
+ daemon.on("openclaw_lost", () => {
3534
+ console.log(chalk3.yellow("\n\u26A0 OpenClaw process no longer detected"));
3535
+ console.log(chalk3.gray(" Daemon will auto-reconnect when OpenClaw starts.\n"));
3536
+ statusSpinner = ora("Waiting for OpenClaw...").start();
3537
+ });
3538
+ daemon.on("message_forwarded", (agentId, content) => {
3539
+ if (options.verbose) {
3540
+ const preview = content.length > 50 ? content.substring(0, 50) + "..." : content;
3541
+ console.log(chalk3.blue(` \u2192 Forwarded from ${agentId}: ${preview}`));
3542
+ }
3543
+ });
3544
+ daemon.on("error", (error) => {
3545
+ if (options.verbose) {
3546
+ console.log(chalk3.red(` \u2717 Error: ${error.message}`));
3547
+ }
3548
+ });
3549
+ const shutdown = async () => {
3550
+ if (isShuttingDown) return;
3551
+ isShuttingDown = true;
3552
+ statusSpinner.stop();
3553
+ console.log(chalk3.yellow("\n\nShutting down daemon..."));
3554
+ if (statsInterval) {
3555
+ clearInterval(statsInterval);
3556
+ }
3557
+ const stats = daemon.getStats();
3558
+ console.log(chalk3.cyan("\n\u2501\u2501\u2501 Final Statistics \u2501\u2501\u2501"));
3559
+ console.log(chalk3.white(` Uptime: ${formatUptime(stats.uptimeMs)}`));
3560
+ console.log(chalk3.white(` Messages processed: ${stats.messagesProcessed}`));
3561
+ console.log(chalk3.white(` Messages forwarded: ${stats.messagesForwarded}`));
3562
+ console.log(chalk3.white(` Webhook errors: ${stats.webhookErrors}`));
3563
+ console.log(chalk3.cyan("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n"));
3564
+ await daemon.stop();
3565
+ console.log(chalk3.green("Daemon stopped. Goodbye! \u{1F44B}\n"));
3566
+ process.exit(0);
3567
+ };
3568
+ process.on("SIGINT", shutdown);
3569
+ process.on("SIGTERM", shutdown);
3570
+ try {
3571
+ await daemon.start();
3572
+ if (!daemon.isConnected) {
3573
+ statusSpinner.warn("OpenClaw Gateway not found");
3574
+ console.log(chalk3.yellow("\n\u26A0 Could not connect to OpenClaw Gateway."));
3575
+ console.log(chalk3.gray("\nMake sure OpenClaw is running:"));
3576
+ console.log(chalk3.white(" $ openclaw gateway run\n"));
3577
+ console.log(chalk3.gray("The daemon will keep trying to connect..."));
3578
+ statusSpinner = ora("Waiting for OpenClaw Gateway...").start();
3579
+ }
3580
+ } catch (error) {
3581
+ statusSpinner.fail("Failed to start daemon");
3582
+ console.error(chalk3.red(`
3583
+ Error: ${error instanceof Error ? error.message : "Unknown error"}`));
3584
+ process.exit(1);
3585
+ }
3586
+ });
3587
+ function formatUptime(ms) {
3588
+ const seconds = Math.floor(ms / 1e3);
3589
+ const minutes = Math.floor(seconds / 60);
3590
+ const hours = Math.floor(minutes / 60);
3591
+ if (hours > 0) {
3592
+ return `${hours}h ${minutes % 60}m ${seconds % 60}s`;
3593
+ } else if (minutes > 0) {
3594
+ return `${minutes}m ${seconds % 60}s`;
3595
+ } else {
3596
+ return `${seconds}s`;
3597
+ }
3598
+ }
2669
3599
  program.command("agents").description("List all available agents").option("-c, --category <category>", "Filter by category").action((options) => {
2670
3600
  console.log(chalk3.cyan("\n\u{1F980} Too Many Claw - Agent Directory\n"));
2671
3601
  let agents = AGENT_DEFINITIONS;