@poolzin/pool-bot 2026.3.21 → 2026.3.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/dist/acp/bindings-store.js +209 -0
  3. package/dist/acp/control-plane/runtime-cache.js +54 -0
  4. package/dist/acp/control-plane/runtime-options.js +215 -0
  5. package/dist/acp/control-plane/session-actor-queue.js +36 -0
  6. package/dist/acp/runtime/errors.js +47 -0
  7. package/dist/acp/runtime/registry.js +86 -0
  8. package/dist/acp/runtime/types.js +1 -0
  9. package/dist/acp/translator.js +97 -0
  10. package/dist/agents/failover-error.js +145 -47
  11. package/dist/browser/browser-profile-manager.js +319 -0
  12. package/dist/browser/cdp-proxy-bypass.js +129 -0
  13. package/dist/browser/cdp-timeouts.js +41 -0
  14. package/dist/browser/chrome-extension-validator.js +406 -0
  15. package/dist/browser/chrome-mcp-snapshot.js +222 -0
  16. package/dist/browser/chrome-mcp.js +421 -0
  17. package/dist/browser/chrome-mcp.snapshot.js +133 -0
  18. package/dist/browser/errors.js +67 -0
  19. package/dist/browser/form-fields.js +22 -0
  20. package/dist/browser/output-atomic.js +44 -0
  21. package/dist/browser/profile-capabilities.js +47 -0
  22. package/dist/browser/safe-filename.js +25 -0
  23. package/dist/browser/snapshot-roles.js +60 -0
  24. package/dist/build-info.json +3 -3
  25. package/dist/commands/security-owner-only.js +86 -0
  26. package/dist/control-ui/assets/{index-Dvkl4Xlx.js → index-D7shnQwQ.js} +404 -388
  27. package/dist/control-ui/assets/index-D7shnQwQ.js.map +1 -0
  28. package/dist/control-ui/index.html +1 -1
  29. package/dist/cron/cron-filters.js +150 -0
  30. package/dist/gateway/device-pairing-security.js +197 -0
  31. package/dist/gateway/event-deduplication.js +167 -0
  32. package/dist/gateway/run-tracker.js +253 -0
  33. package/dist/gateway/server-methods/nodes.js +14 -0
  34. package/dist/gateway/websocket-preauth-security.js +188 -0
  35. package/dist/infra/errors.js +53 -13
  36. package/dist/infra/exec-approvals-security.js +217 -0
  37. package/dist/infra/security/command-analyzer.js +257 -0
  38. package/dist/plugins/loader.js +16 -8
  39. package/dist/security/external-content.js +51 -1
  40. package/dist/sessions/session-costs.js +228 -0
  41. package/dist/shared/param-key.js +16 -0
  42. package/dist/shared/poll-params.js +58 -0
  43. package/dist/shared/polls.js +55 -0
  44. package/docs/DASHBOARD-GAP-ANALYSIS-AND-PLAN.md +430 -0
  45. package/docs/FEATURES.md +523 -0
  46. package/docs/FINAL-IMPLEMENTATION-REVIEW.md +274 -0
  47. package/docs/FINAL-IMPLEMENTATION-SUMMARY.md +356 -0
  48. package/docs/FINAL-PROFESSIONAL-EVALUATION.md +312 -0
  49. package/docs/IMPLEMENTATION-PRIORITY-EVALUATION.md +298 -0
  50. package/docs/IMPLEMENTATION-PROGRESS.md +237 -0
  51. package/docs/IMPLEMENTATION-REVIEW-PHASE1-2.md +381 -0
  52. package/docs/IMPLEMENTATION-REVIEW-PHASE4.md +389 -0
  53. package/docs/IMPLEMENTATION-REVIEW-PHASE5.md +420 -0
  54. package/docs/IMPLEMENTATION-REVIEW-PHASE6.md +422 -0
  55. package/docs/IMPLEMENTATION-REVIEW-PHASE7-FINAL.md +184 -0
  56. package/docs/MIKRODASH-ANALYSIS.md +412 -0
  57. package/docs/OPENCLAW-GAP-ANALYSIS-FINAL.md +431 -0
  58. package/docs/OPENCLAW-VS-POOLBOT-ANALYSIS.md +351 -0
  59. package/docs/PHASE-7-SUMMARY.md +144 -0
  60. package/docs/POOLBOT-OFFICE-PLAN.md +697 -0
  61. package/docs/PROJECT-FINAL-STATUS.md +237 -0
  62. package/docs/README.md +116 -0
  63. package/docs/REAL-IMPROVEMENTS-EVALUATION.md +477 -0
  64. package/docs/SECURITY-HARDENING-IMPLEMENTATION.md +161 -0
  65. package/docs/channels/googlechat.md +235 -206
  66. package/docs/channels/irc.md +332 -0
  67. package/docs/channels/nostr.md +255 -168
  68. package/docs/components/command-palette.md +166 -0
  69. package/docs/components/login-gate.md +219 -0
  70. package/docs/getting-started/installation.md +191 -0
  71. package/docs/getting-started/introduction.md +120 -0
  72. package/docs/improvements/USAGE-GUIDE.md +359 -0
  73. package/docs/plans/2026-03-15-openclaw-features-implementation.md +1632 -0
  74. package/docs/reference/deadcode-detection.md +72 -0
  75. package/extensions/acpx/node_modules/.bin/acpx +21 -0
  76. package/extensions/agency-agents/node_modules/.bin/vite +4 -4
  77. package/extensions/agency-agents/node_modules/.bin/vitest +2 -2
  78. package/extensions/googlechat/node_modules/.bin/tsc +21 -0
  79. package/extensions/googlechat/node_modules/.bin/tsserver +21 -0
  80. package/extensions/googlechat/node_modules/.bin/vitest +21 -0
  81. package/extensions/googlechat/package.json +11 -28
  82. package/extensions/googlechat/src/googlechat-channel.test.ts +60 -0
  83. package/extensions/googlechat/src/googlechat-channel.ts +120 -0
  84. package/extensions/googlechat/src/index.ts +14 -0
  85. package/extensions/irc/node_modules/.bin/tsc +21 -0
  86. package/extensions/irc/node_modules/.bin/tsserver +21 -0
  87. package/extensions/irc/node_modules/.bin/vitest +21 -0
  88. package/extensions/irc/package.json +16 -8
  89. package/extensions/irc/src/index.ts +14 -0
  90. package/extensions/irc/src/irc-channel.test.ts +43 -0
  91. package/extensions/irc/src/irc-channel.ts +191 -0
  92. package/extensions/keyed-async-queue/node_modules/.bin/tsc +21 -0
  93. package/extensions/keyed-async-queue/node_modules/.bin/tsserver +21 -0
  94. package/extensions/keyed-async-queue/node_modules/.bin/vitest +21 -0
  95. package/extensions/keyed-async-queue/package.json +20 -0
  96. package/extensions/keyed-async-queue/src/index.ts +14 -0
  97. package/extensions/keyed-async-queue/src/queue.test.ts +135 -0
  98. package/extensions/keyed-async-queue/src/queue.ts +200 -0
  99. package/extensions/memory-core/node_modules/.bin/tsc +21 -0
  100. package/extensions/memory-core/node_modules/.bin/tsserver +21 -0
  101. package/extensions/memory-core/node_modules/.bin/vitest +21 -0
  102. package/extensions/memory-core/package.json +11 -8
  103. package/extensions/memory-core/src/index.ts +14 -0
  104. package/extensions/memory-core/src/memory-manager.test.ts +124 -0
  105. package/extensions/memory-core/src/memory-manager.ts +186 -0
  106. package/extensions/nostr/node_modules/.bin/tsc +2 -2
  107. package/extensions/nostr/node_modules/.bin/tsserver +2 -2
  108. package/extensions/nostr/node_modules/.bin/vitest +21 -0
  109. package/extensions/nostr/package.json +15 -24
  110. package/extensions/nostr/src/index.ts +14 -0
  111. package/extensions/nostr/src/nostr-channel.test.ts +55 -0
  112. package/extensions/nostr/src/nostr-channel.ts +228 -0
  113. package/extensions/page-agent/node_modules/.bin/vitest +2 -2
  114. package/extensions/test-utils/node_modules/.bin/jiti +21 -0
  115. package/extensions/test-utils/node_modules/.bin/playwright +21 -0
  116. package/extensions/test-utils/node_modules/.bin/tsx +21 -0
  117. package/extensions/test-utils/node_modules/.bin/vite +21 -0
  118. package/extensions/test-utils/node_modules/.bin/vitest +21 -0
  119. package/extensions/test-utils/node_modules/.bin/yaml +21 -0
  120. package/extensions/xyops/node_modules/.bin/vitest +2 -2
  121. package/package.json +2 -1
  122. package/dist/control-ui/assets/index-Dvkl4Xlx.js.map +0 -1
  123. package/extensions/googlechat/node_modules/.bin/poolbot +0 -21
  124. package/extensions/memory-core/node_modules/.bin/poolbot +0 -21
@@ -0,0 +1,228 @@
1
+ /**
2
+ * Session Cost Tracking
3
+ * Track token costs, time costs, and generate cost reports
4
+ */
5
+ /**
6
+ * Calculate total cost from cost units
7
+ */
8
+ export function calculateTotalCost(costs, rates) {
9
+ const defaultRates = {
10
+ tokens: 0.00002, // $0.00002 per token
11
+ time: 0.001, // $0.001 per second
12
+ api_calls: 0.001, // $0.001 per API call
13
+ custom: 0,
14
+ };
15
+ const effectiveRates = { ...defaultRates, ...rates };
16
+ return costs.reduce((total, cost) => {
17
+ const rate = effectiveRates[cost.type] || 0;
18
+ return total + cost.amount * rate;
19
+ }, 0);
20
+ }
21
+ /**
22
+ * Track session costs
23
+ */
24
+ export class SessionCostTracker {
25
+ sessions = new Map();
26
+ rates = {};
27
+ constructor(rates) {
28
+ if (rates) {
29
+ this.rates = rates;
30
+ }
31
+ }
32
+ /**
33
+ * Start tracking a session
34
+ */
35
+ startSession(sessionId, agentId, channelId) {
36
+ this.sessions.set(sessionId, {
37
+ sessionId,
38
+ agentId,
39
+ channelId,
40
+ costs: [],
41
+ startTime: Date.now(),
42
+ metadata: {},
43
+ });
44
+ }
45
+ /**
46
+ * Add cost to a session
47
+ */
48
+ addCost(sessionId, cost) {
49
+ const session = this.sessions.get(sessionId);
50
+ if (!session) {
51
+ throw new Error(`Session ${sessionId} not found`);
52
+ }
53
+ session.costs.push(cost);
54
+ session.totalCost = calculateTotalCost(session.costs, this.rates);
55
+ }
56
+ /**
57
+ * Add token cost
58
+ */
59
+ addTokenCost(sessionId, tokens, metadata) {
60
+ this.addCost(sessionId, {
61
+ type: "tokens",
62
+ amount: tokens,
63
+ metadata,
64
+ });
65
+ }
66
+ /**
67
+ * Add time cost
68
+ */
69
+ addTimeCost(sessionId, seconds, metadata) {
70
+ this.addCost(sessionId, {
71
+ type: "time",
72
+ amount: seconds,
73
+ metadata,
74
+ });
75
+ }
76
+ /**
77
+ * Add API call cost
78
+ */
79
+ addApiCallCost(sessionId, count = 1, metadata) {
80
+ this.addCost(sessionId, {
81
+ type: "api_calls",
82
+ amount: count,
83
+ metadata,
84
+ });
85
+ }
86
+ /**
87
+ * End session tracking
88
+ */
89
+ endSession(sessionId) {
90
+ const session = this.sessions.get(sessionId);
91
+ if (!session) {
92
+ return undefined;
93
+ }
94
+ session.endTime = Date.now();
95
+ // Add final time cost
96
+ const durationSeconds = (session.endTime - session.startTime) / 1000;
97
+ this.addTimeCost(sessionId, durationSeconds, { type: "session_duration" });
98
+ return session;
99
+ }
100
+ /**
101
+ * Get session cost
102
+ */
103
+ getSessionCost(sessionId) {
104
+ return this.sessions.get(sessionId);
105
+ }
106
+ /**
107
+ * Get cost breakdown
108
+ */
109
+ getCostBreakdown(sessionIds) {
110
+ const sessions = sessionIds
111
+ ? sessionIds.map((id) => this.sessions.get(id)).filter((s) => !!s)
112
+ : Array.from(this.sessions.values());
113
+ const breakdown = {
114
+ byType: {},
115
+ byAgent: {},
116
+ byChannel: {},
117
+ bySession: {},
118
+ total: 0,
119
+ };
120
+ for (const session of sessions) {
121
+ const sessionTotal = calculateTotalCost(session.costs, this.rates);
122
+ // By type
123
+ for (const cost of session.costs) {
124
+ breakdown.byType[cost.type] =
125
+ (breakdown.byType[cost.type] || 0) + cost.amount * (this.rates[cost.type] || 0);
126
+ }
127
+ // By agent
128
+ if (session.agentId) {
129
+ breakdown.byAgent[session.agentId] =
130
+ (breakdown.byAgent[session.agentId] || 0) + sessionTotal;
131
+ }
132
+ // By channel
133
+ if (session.channelId) {
134
+ breakdown.byChannel[session.channelId] =
135
+ (breakdown.byChannel[session.channelId] || 0) + sessionTotal;
136
+ }
137
+ // By session
138
+ breakdown.bySession[session.sessionId] = sessionTotal;
139
+ // Total
140
+ breakdown.total += sessionTotal;
141
+ }
142
+ return breakdown;
143
+ }
144
+ /**
145
+ * Export costs to different formats
146
+ */
147
+ exportCosts(format, sessionIds) {
148
+ const sessions = sessionIds
149
+ ? sessionIds.map((id) => this.getSessionCost(id)).filter((s) => !!s)
150
+ : Array.from(this.sessions.values());
151
+ switch (format) {
152
+ case "csv":
153
+ return this.exportToCSV(sessions);
154
+ case "json":
155
+ return JSON.stringify(sessions, null, 2);
156
+ case "markdown":
157
+ return this.exportToMarkdown(sessions);
158
+ default:
159
+ throw new Error(`Unknown format: ${format}`);
160
+ }
161
+ }
162
+ exportToCSV(sessions) {
163
+ const lines = [
164
+ "Session ID,Agent ID,Channel ID,Start Time,End Time,Total Cost,Token Cost,Time Cost,API Calls",
165
+ ];
166
+ for (const session of sessions) {
167
+ const tokenCost = session.costs
168
+ .filter((c) => c.type === "tokens")
169
+ .reduce((sum, c) => sum + c.amount, 0);
170
+ const timeCost = session.costs
171
+ .filter((c) => c.type === "time")
172
+ .reduce((sum, c) => sum + c.amount, 0);
173
+ const apiCalls = session.costs
174
+ .filter((c) => c.type === "api_calls")
175
+ .reduce((sum, c) => sum + c.amount, 0);
176
+ lines.push(`${session.sessionId},${session.agentId || ""},${session.channelId || ""},${session.startTime},${session.endTime || ""},${session.totalCost || 0},${tokenCost},${timeCost},${apiCalls}`);
177
+ }
178
+ return lines.join("\n");
179
+ }
180
+ exportToMarkdown(sessions) {
181
+ const lines = ["# Session Cost Report", ""];
182
+ const breakdown = this.getCostBreakdown(sessions.map((s) => s.sessionId));
183
+ lines.push("## Summary", "");
184
+ lines.push(`- **Total Cost**: $${breakdown.total.toFixed(4)}`);
185
+ lines.push(`- **Sessions**: ${sessions.length}`);
186
+ lines.push("");
187
+ lines.push("## By Type", "");
188
+ lines.push("| Type | Cost |");
189
+ lines.push("|------|------|");
190
+ for (const [type, cost] of Object.entries(breakdown.byType)) {
191
+ lines.push(`| ${type} | $${cost.toFixed(4)} |`);
192
+ }
193
+ lines.push("");
194
+ lines.push("## Sessions", "");
195
+ lines.push("| Session | Agent | Channel | Total Cost |");
196
+ lines.push("|---------|-------|---------|------------|");
197
+ for (const session of sessions) {
198
+ lines.push(`| ${session.sessionId} | ${session.agentId || "N/A"} | ${session.channelId || "N/A"} | $${(session.totalCost || 0).toFixed(4)} |`);
199
+ }
200
+ return lines.join("\n");
201
+ }
202
+ /**
203
+ * Clear all sessions
204
+ */
205
+ clear() {
206
+ this.sessions.clear();
207
+ }
208
+ /**
209
+ * Get statistics
210
+ */
211
+ getStats() {
212
+ const sessions = Array.from(this.sessions.values());
213
+ const _activeSessions = sessions.filter((s) => !s.endTime).length;
214
+ const _totalCost = sessions.reduce((sum, s) => sum + (s.totalCost || 0), 0);
215
+ return {
216
+ totalSessions: sessions.length,
217
+ activeSessions: _activeSessions,
218
+ totalCost: _totalCost,
219
+ avgCostPerSession: sessions.length > 0 ? _totalCost / sessions.length : 0,
220
+ };
221
+ }
222
+ }
223
+ /**
224
+ * Create default cost tracker
225
+ */
226
+ export function createSessionCostTracker(rates) {
227
+ return new SessionCostTracker(rates);
228
+ }
@@ -0,0 +1,16 @@
1
+ export function toSnakeCaseKey(key) {
2
+ return key
3
+ .replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2")
4
+ .replace(/([a-z0-9])([A-Z])/g, "$1_$2")
5
+ .toLowerCase();
6
+ }
7
+ export function readSnakeCaseParamRaw(params, key) {
8
+ if (Object.hasOwn(params, key)) {
9
+ return params[key];
10
+ }
11
+ const snakeKey = toSnakeCaseKey(key);
12
+ if (snakeKey !== key && Object.hasOwn(params, snakeKey)) {
13
+ return params[snakeKey];
14
+ }
15
+ return undefined;
16
+ }
@@ -0,0 +1,58 @@
1
+ import { readSnakeCaseParamRaw } from "./param-key.js";
2
+ export const POLL_CREATION_PARAM_DEFS = {
3
+ pollQuestion: { kind: "string" },
4
+ pollOption: { kind: "stringArray" },
5
+ pollDurationHours: { kind: "number" },
6
+ pollMulti: { kind: "boolean" },
7
+ pollDurationSeconds: { kind: "number", telegramOnly: true },
8
+ pollAnonymous: { kind: "boolean", telegramOnly: true },
9
+ pollPublic: { kind: "boolean", telegramOnly: true },
10
+ };
11
+ export const POLL_CREATION_PARAM_NAMES = Object.keys(POLL_CREATION_PARAM_DEFS);
12
+ function readPollParamRaw(params, key) {
13
+ return readSnakeCaseParamRaw(params, key);
14
+ }
15
+ export function resolveTelegramPollVisibility(params) {
16
+ if (params.pollAnonymous && params.pollPublic) {
17
+ throw new Error("pollAnonymous and pollPublic are mutually exclusive");
18
+ }
19
+ return params.pollAnonymous ? true : params.pollPublic ? false : undefined;
20
+ }
21
+ export function hasPollCreationParams(params) {
22
+ for (const key of POLL_CREATION_PARAM_NAMES) {
23
+ const def = POLL_CREATION_PARAM_DEFS[key];
24
+ const value = readPollParamRaw(params, key);
25
+ if (def.kind === "string" && typeof value === "string" && value.trim().length > 0) {
26
+ return true;
27
+ }
28
+ if (def.kind === "stringArray") {
29
+ if (Array.isArray(value) &&
30
+ value.some((entry) => typeof entry === "string" && entry.trim())) {
31
+ return true;
32
+ }
33
+ if (typeof value === "string" && value.trim().length > 0) {
34
+ return true;
35
+ }
36
+ }
37
+ if (def.kind === "number") {
38
+ if (typeof value === "number" && Number.isFinite(value)) {
39
+ return true;
40
+ }
41
+ if (typeof value === "string") {
42
+ const trimmed = value.trim();
43
+ if (trimmed.length > 0 && Number.isFinite(Number(trimmed))) {
44
+ return true;
45
+ }
46
+ }
47
+ }
48
+ if (def.kind === "boolean") {
49
+ if (value === true) {
50
+ return true;
51
+ }
52
+ if (typeof value === "string" && value.trim().toLowerCase() === "true") {
53
+ return true;
54
+ }
55
+ }
56
+ }
57
+ return false;
58
+ }
@@ -0,0 +1,55 @@
1
+ export function resolvePollMaxSelections(optionCount, allowMultiselect) {
2
+ return allowMultiselect ? Math.max(2, optionCount) : 1;
3
+ }
4
+ export function normalizePollInput(input, options = {}) {
5
+ const question = input.question.trim();
6
+ if (!question) {
7
+ throw new Error("Poll question is required");
8
+ }
9
+ const pollOptions = (input.options ?? []).map((option) => option.trim());
10
+ const cleaned = pollOptions.filter(Boolean);
11
+ if (cleaned.length < 2) {
12
+ throw new Error("Poll requires at least 2 options");
13
+ }
14
+ if (options.maxOptions !== undefined && cleaned.length > options.maxOptions) {
15
+ throw new Error(`Poll supports at most ${options.maxOptions} options`);
16
+ }
17
+ const maxSelectionsRaw = input.maxSelections;
18
+ const maxSelections = typeof maxSelectionsRaw === "number" && Number.isFinite(maxSelectionsRaw)
19
+ ? Math.floor(maxSelectionsRaw)
20
+ : 1;
21
+ if (maxSelections < 1) {
22
+ throw new Error("maxSelections must be at least 1");
23
+ }
24
+ if (maxSelections > cleaned.length) {
25
+ throw new Error("maxSelections cannot exceed option count");
26
+ }
27
+ const durationSecondsRaw = input.durationSeconds;
28
+ const durationSeconds = typeof durationSecondsRaw === "number" && Number.isFinite(durationSecondsRaw)
29
+ ? Math.floor(durationSecondsRaw)
30
+ : undefined;
31
+ if (durationSeconds !== undefined && durationSeconds < 1) {
32
+ throw new Error("durationSeconds must be at least 1");
33
+ }
34
+ const durationRaw = input.durationHours;
35
+ const durationHours = typeof durationRaw === "number" && Number.isFinite(durationRaw)
36
+ ? Math.floor(durationRaw)
37
+ : undefined;
38
+ if (durationHours !== undefined && durationHours < 1) {
39
+ throw new Error("durationHours must be at least 1");
40
+ }
41
+ if (durationSeconds !== undefined && durationHours !== undefined) {
42
+ throw new Error("durationSeconds and durationHours are mutually exclusive");
43
+ }
44
+ return {
45
+ question,
46
+ options: cleaned,
47
+ maxSelections,
48
+ durationSeconds,
49
+ durationHours,
50
+ };
51
+ }
52
+ export function normalizePollDurationHours(value, options) {
53
+ const base = typeof value === "number" && Number.isFinite(value) ? Math.floor(value) : options.defaultHours;
54
+ return Math.min(Math.max(base, 1), options.maxHours);
55
+ }