@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,21 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*|*MINGW*|*MSYS*)
6
+ if command -v cygpath > /dev/null 2>&1; then
7
+ basedir=`cygpath -w "$basedir"`
8
+ fi
9
+ ;;
10
+ esac
11
+
12
+ if [ -z "$NODE_PATH" ]; then
13
+ export NODE_PATH="/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/vitest@1.6.1_@types+node@20.19.30_@vitest+browser@4.0.18_vite@7.3.1_@types+node@25.2.3__a102e25684722dd7e16c8e55a5848dc8/node_modules/vitest/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/vitest@1.6.1_@types+node@20.19.30_@vitest+browser@4.0.18_vite@7.3.1_@types+node@25.2.3__a102e25684722dd7e16c8e55a5848dc8/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/node_modules"
14
+ else
15
+ export NODE_PATH="/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/vitest@1.6.1_@types+node@20.19.30_@vitest+browser@4.0.18_vite@7.3.1_@types+node@25.2.3__a102e25684722dd7e16c8e55a5848dc8/node_modules/vitest/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/vitest@1.6.1_@types+node@20.19.30_@vitest+browser@4.0.18_vite@7.3.1_@types+node@25.2.3__a102e25684722dd7e16c8e55a5848dc8/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/node_modules:$NODE_PATH"
16
+ fi
17
+ if [ -x "$basedir/node" ]; then
18
+ exec "$basedir/node" "$basedir/../vitest/vitest.mjs" "$@"
19
+ else
20
+ exec node "$basedir/../vitest/vitest.mjs" "$@"
21
+ fi
@@ -1,17 +1,20 @@
1
1
  {
2
2
  "name": "@poolbot/memory-core",
3
- "version": "2026.3.11",
3
+ "version": "1.0.0",
4
+ "description": "Core memory management for Pool Bot agents",
4
5
  "type": "module",
5
- "description": "Poolbot core memory search plugin",
6
- "poolbot": {
7
- "extensions": [
8
- "./index.ts"
9
- ]
6
+ "main": "src/index.js",
7
+ "scripts": {
8
+ "test": "vitest run",
9
+ "build": "tsc"
10
10
  },
11
+ "dependencies": {},
11
12
  "devDependencies": {
12
- "@poolzin/pool-bot": "workspace:*"
13
+ "@types/node": "^20.0.0",
14
+ "typescript": "^5.0.0",
15
+ "vitest": "^1.0.0"
13
16
  },
14
17
  "peerDependencies": {
15
- "@poolzin/pool-bot": ">=2026.1.26"
18
+ "poolbot": "workspace:*"
16
19
  }
17
20
  }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Memory Core Plugin Entry Point
3
+ */
4
+
5
+ export { MemoryManager, createMemoryManager, type MemoryEntry, type MemoryQuery } from "./memory-manager.js";
6
+
7
+ // Export plugin metadata
8
+ export const pluginInfo = {
9
+ id: "memory-core",
10
+ name: "Memory Core",
11
+ version: "1.0.0",
12
+ description: "Core memory management for Pool Bot agents",
13
+ author: "Pool Bot Team",
14
+ };
@@ -0,0 +1,124 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import { MemoryManager, createMemoryManager } from "./memory-manager";
3
+
4
+ describe("MemoryManager", () => {
5
+ let manager: MemoryManager;
6
+
7
+ beforeEach(() => {
8
+ manager = createMemoryManager();
9
+ });
10
+
11
+ afterEach(() => {
12
+ manager.destroy();
13
+ });
14
+
15
+ it("sets and gets memory", () => {
16
+ manager.set("test-key", "test-value");
17
+ const value = manager.get("test-key");
18
+ expect(value).toBe("test-value");
19
+ });
20
+
21
+ it("returns undefined for non-existent key", () => {
22
+ const value = manager.get("non-existent");
23
+ expect(value).toBeUndefined();
24
+ });
25
+
26
+ it("respects TTL", async () => {
27
+ manager.set("expiring-key", "value", { ttl: 100 });
28
+ expect(manager.get("expiring-key")).toBe("value");
29
+
30
+ await new Promise((resolve) => setTimeout(resolve, 150));
31
+ expect(manager.get("expiring-key")).toBeUndefined();
32
+ });
33
+
34
+ it("deletes by ID", () => {
35
+ const entry = manager.set("test-key", "value");
36
+ const deleted = manager.delete(entry.id);
37
+ expect(deleted).toBe(true);
38
+ expect(manager.get("test-key")).toBeUndefined();
39
+ });
40
+
41
+ it("deletes by key", () => {
42
+ manager.set("test-key", "value1");
43
+ manager.set("test-key", "value2");
44
+ const deleted = manager.delete("test-key");
45
+ expect(deleted).toBe(true);
46
+ expect(manager.get("test-key")).toBeUndefined();
47
+ });
48
+
49
+ it("queries by key", () => {
50
+ manager.set("key1", "value1");
51
+ manager.set("key2", "value2");
52
+ manager.set("key1", "value3");
53
+
54
+ const results = manager.query({ key: "key1" });
55
+ expect(results).toHaveLength(2);
56
+ });
57
+
58
+ it("queries by key prefix", () => {
59
+ manager.set("user:1:name", "Alice");
60
+ manager.set("user:1:age", "30");
61
+ manager.set("user:2:name", "Bob");
62
+
63
+ const results = manager.query({ keyPrefix: "user:1:" });
64
+ expect(results).toHaveLength(2);
65
+ });
66
+
67
+ it("queries by tags", () => {
68
+ manager.set("key1", "value1", { tags: ["important"] });
69
+ manager.set("key2", "value2", { tags: ["temporary"] });
70
+ manager.set("key3", "value3", { tags: ["important", "temporary"] });
71
+
72
+ const results = manager.query({ tags: ["important"] });
73
+ expect(results).toHaveLength(2);
74
+ });
75
+
76
+ it("excludes expired by default", async () => {
77
+ manager.set("expiring", "value", { ttl: 50 });
78
+ await new Promise((resolve) => setTimeout(resolve, 100));
79
+
80
+ const results = manager.query({ excludeExpired: true });
81
+ expect(results).toHaveLength(0);
82
+ });
83
+
84
+ it("clears all memories", () => {
85
+ manager.set("key1", "value1");
86
+ manager.set("key2", "value2");
87
+ manager.clear();
88
+
89
+ const stats = manager.getStats();
90
+ expect(stats.total).toBe(0);
91
+ });
92
+
93
+ it("cleans up expired memories", async () => {
94
+ manager.set("expiring1", "value1", { ttl: 50 });
95
+ manager.set("expiring2", "value2", { ttl: 50 });
96
+ manager.set("permanent", "value3");
97
+
98
+ await new Promise((resolve) => setTimeout(resolve, 100));
99
+ const cleared = manager.cleanupExpired();
100
+
101
+ expect(cleared).toBe(2);
102
+ expect(manager.get("permanent")).toBe("value3");
103
+ });
104
+
105
+ it("gets statistics", () => {
106
+ manager.set("key1", "value1");
107
+ manager.set("key1", "value2");
108
+ manager.set("key2", "value3", { ttl: 1000 });
109
+
110
+ const stats = manager.getStats();
111
+ expect(stats.total).toBe(3);
112
+ expect(stats.byKey.key1).toBe(2);
113
+ expect(stats.byKey.key2).toBe(1);
114
+ expect(stats.withTTL).toBe(1);
115
+ });
116
+
117
+ it("returns most recent value for duplicate keys", () => {
118
+ manager.set("test-key", "old-value");
119
+ manager.set("test-key", "new-value");
120
+
121
+ const value = manager.get("test-key");
122
+ expect(value).toBe("new-value");
123
+ });
124
+ });
@@ -0,0 +1,186 @@
1
+ /**
2
+ * Memory Manager Plugin
3
+ * Core memory management for Pool Bot agents
4
+ */
5
+
6
+ export type MemoryEntry = {
7
+ id: string;
8
+ key: string;
9
+ value: unknown;
10
+ ttl?: number; // Time to live in ms
11
+ createdAt: number;
12
+ expiresAt?: number;
13
+ tags?: string[];
14
+ };
15
+
16
+ export type MemoryQuery = {
17
+ key?: string;
18
+ keyPrefix?: string;
19
+ tags?: string[];
20
+ excludeExpired?: boolean;
21
+ };
22
+
23
+ export class MemoryManager {
24
+ private memories: Map<string, MemoryEntry> = new Map();
25
+ private cleanupInterval?: NodeJS.Timeout;
26
+
27
+ constructor(cleanupIntervalMs = 60000) {
28
+ // Start cleanup interval
29
+ this.cleanupInterval = setInterval(() => this.cleanupExpired(), cleanupIntervalMs);
30
+ }
31
+
32
+ /**
33
+ * Set a memory entry
34
+ */
35
+ set(key: string, value: unknown, options?: { ttl?: number; tags?: string[] }): MemoryEntry {
36
+ const id = `mem_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
37
+ const createdAt = Date.now();
38
+ const expiresAt = options?.ttl ? createdAt + options.ttl : undefined;
39
+
40
+ const entry: MemoryEntry = {
41
+ id,
42
+ key,
43
+ value,
44
+ ttl: options?.ttl,
45
+ createdAt,
46
+ expiresAt,
47
+ tags: options?.tags,
48
+ };
49
+
50
+ this.memories.set(id, entry);
51
+ return entry;
52
+ }
53
+
54
+ /**
55
+ * Get a memory entry by key
56
+ */
57
+ get<T = unknown>(key: string): T | undefined {
58
+ const entries = Array.from(this.memories.values()).filter((e) => e.key === key);
59
+ if (entries.length === 0) {
60
+ return undefined;
61
+ }
62
+
63
+ // Return most recent
64
+ const latest = entries.sort((a, b) => b.createdAt - a.createdAt)[0];
65
+
66
+ // Check expiration
67
+ if (latest.expiresAt && latest.expiresAt < Date.now()) {
68
+ this.delete(latest.id);
69
+ return undefined;
70
+ }
71
+
72
+ return latest.value as T;
73
+ }
74
+
75
+ /**
76
+ * Delete a memory entry
77
+ */
78
+ delete(idOrKey: string): boolean {
79
+ // Try by ID first
80
+ if (this.memories.has(idOrKey)) {
81
+ return this.memories.delete(idOrKey);
82
+ }
83
+
84
+ // Try by key
85
+ const entries = Array.from(this.memories.values()).filter((e) => e.key === idOrKey);
86
+ for (const entry of entries) {
87
+ this.memories.delete(entry.id);
88
+ }
89
+
90
+ return entries.length > 0;
91
+ }
92
+
93
+ /**
94
+ * Query memories
95
+ */
96
+ query(query: MemoryQuery): MemoryEntry[] {
97
+ let results = Array.from(this.memories.values());
98
+
99
+ // Filter by key
100
+ if (query.key) {
101
+ results = results.filter((e) => e.key === query.key);
102
+ }
103
+
104
+ // Filter by key prefix
105
+ if (query.keyPrefix) {
106
+ results = results.filter((e) => e.key.startsWith(query.keyPrefix));
107
+ }
108
+
109
+ // Filter by tags
110
+ if (query.tags && query.tags.length > 0) {
111
+ results = results.filter((e) => e.tags?.some((t) => query.tags?.includes(t)));
112
+ }
113
+
114
+ // Exclude expired
115
+ if (query.excludeExpired !== false) {
116
+ const now = Date.now();
117
+ results = results.filter((e) => !e.expiresAt || e.expiresAt > now);
118
+ }
119
+
120
+ return results;
121
+ }
122
+
123
+ /**
124
+ * Clear all memories
125
+ */
126
+ clear(): void {
127
+ this.memories.clear();
128
+ }
129
+
130
+ /**
131
+ * Cleanup expired memories
132
+ */
133
+ cleanupExpired(): number {
134
+ const now = Date.now();
135
+ let cleared = 0;
136
+
137
+ for (const [id, entry] of this.memories.entries()) {
138
+ if (entry.expiresAt && entry.expiresAt < now) {
139
+ this.memories.delete(id);
140
+ cleared++;
141
+ }
142
+ }
143
+
144
+ return cleared;
145
+ }
146
+
147
+ /**
148
+ * Get statistics
149
+ */
150
+ getStats(): {
151
+ total: number;
152
+ byKey: Record<string, number>;
153
+ expired: number;
154
+ withTTL: number;
155
+ } {
156
+ const entries = Array.from(this.memories.values());
157
+ const now = Date.now();
158
+
159
+ return {
160
+ total: entries.length,
161
+ byKey: entries.reduce((acc, e) => {
162
+ acc[e.key] = (acc[e.key] || 0) + 1;
163
+ return acc;
164
+ }, {} as Record<string, number>),
165
+ expired: entries.filter((e) => e.expiresAt && e.expiresAt < now).length,
166
+ withTTL: entries.filter((e) => e.ttl).length,
167
+ };
168
+ }
169
+
170
+ /**
171
+ * Destroy the memory manager
172
+ */
173
+ destroy(): void {
174
+ if (this.cleanupInterval) {
175
+ clearInterval(this.cleanupInterval);
176
+ }
177
+ this.clear();
178
+ }
179
+ }
180
+
181
+ /**
182
+ * Create memory manager instance
183
+ */
184
+ export function createMemoryManager(cleanupIntervalMs?: number): MemoryManager {
185
+ return new MemoryManager(cleanupIntervalMs);
186
+ }
@@ -15,7 +15,7 @@ else
15
15
  export NODE_PATH="/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/typescript@5.9.3/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/node_modules:$NODE_PATH"
16
16
  fi
17
17
  if [ -x "$basedir/node" ]; then
18
- exec "$basedir/node" "$basedir/../../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/tsc" "$@"
18
+ exec "$basedir/node" "$basedir/../typescript/bin/tsc" "$@"
19
19
  else
20
- exec node "$basedir/../../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/tsc" "$@"
20
+ exec node "$basedir/../typescript/bin/tsc" "$@"
21
21
  fi
@@ -15,7 +15,7 @@ else
15
15
  export NODE_PATH="/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/typescript@5.9.3/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/node_modules:$NODE_PATH"
16
16
  fi
17
17
  if [ -x "$basedir/node" ]; then
18
- exec "$basedir/node" "$basedir/../../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/tsserver" "$@"
18
+ exec "$basedir/node" "$basedir/../typescript/bin/tsserver" "$@"
19
19
  else
20
- exec node "$basedir/../../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/tsserver" "$@"
20
+ exec node "$basedir/../typescript/bin/tsserver" "$@"
21
21
  fi
@@ -0,0 +1,21 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*|*MINGW*|*MSYS*)
6
+ if command -v cygpath > /dev/null 2>&1; then
7
+ basedir=`cygpath -w "$basedir"`
8
+ fi
9
+ ;;
10
+ esac
11
+
12
+ if [ -z "$NODE_PATH" ]; then
13
+ export NODE_PATH="/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/vitest@1.6.1_@types+node@20.19.30_@vitest+browser@4.0.18_vite@7.3.1_@types+node@25.2.3__a102e25684722dd7e16c8e55a5848dc8/node_modules/vitest/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/vitest@1.6.1_@types+node@20.19.30_@vitest+browser@4.0.18_vite@7.3.1_@types+node@25.2.3__a102e25684722dd7e16c8e55a5848dc8/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/node_modules"
14
+ else
15
+ export NODE_PATH="/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/vitest@1.6.1_@types+node@20.19.30_@vitest+browser@4.0.18_vite@7.3.1_@types+node@25.2.3__a102e25684722dd7e16c8e55a5848dc8/node_modules/vitest/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/vitest@1.6.1_@types+node@20.19.30_@vitest+browser@4.0.18_vite@7.3.1_@types+node@25.2.3__a102e25684722dd7e16c8e55a5848dc8/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/node_modules:$NODE_PATH"
16
+ fi
17
+ if [ -x "$basedir/node" ]; then
18
+ exec "$basedir/node" "$basedir/../vitest/vitest.mjs" "$@"
19
+ else
20
+ exec node "$basedir/../vitest/vitest.mjs" "$@"
21
+ fi
@@ -1,31 +1,22 @@
1
1
  {
2
2
  "name": "@poolbot/nostr",
3
- "version": "2026.3.11",
3
+ "version": "1.0.0",
4
+ "description": "Nostr channel extension for Pool Bot",
4
5
  "type": "module",
5
- "description": "Poolbot Nostr channel plugin for NIP-04 encrypted DMs",
6
- "poolbot": {
7
- "extensions": [
8
- "./index.ts"
9
- ],
10
- "channel": {
11
- "id": "nostr",
12
- "label": "Nostr",
13
- "selectionLabel": "Nostr (NIP-04 DMs)",
14
- "docsPath": "/channels/nostr",
15
- "docsLabel": "nostr",
16
- "blurb": "Decentralized protocol; encrypted DMs via NIP-04.",
17
- "order": 55,
18
- "quickstartAllowFrom": true
19
- },
20
- "install": {
21
- "npmSpec": "@poolbot/nostr",
22
- "localPath": "extensions/nostr",
23
- "defaultChoice": "npm"
24
- }
6
+ "main": "src/index.js",
7
+ "scripts": {
8
+ "test": "vitest run",
9
+ "build": "tsc"
25
10
  },
26
11
  "dependencies": {
27
- "poolbot": "workspace:*",
28
- "nostr-tools": "^2.20.0",
29
- "zod": "^4.3.6"
12
+ "nostr-tools": "^2.0.0"
13
+ },
14
+ "devDependencies": {
15
+ "@types/node": "^20.0.0",
16
+ "typescript": "^5.0.0",
17
+ "vitest": "^1.0.0"
18
+ },
19
+ "peerDependencies": {
20
+ "poolbot": "workspace:*"
30
21
  }
31
22
  }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Nostr Channel Extension Entry Point
3
+ */
4
+
5
+ export { NostrChannel, createNostrChannel, type NostrConfig } from "./nostr-channel.js";
6
+
7
+ // Export channel metadata
8
+ export const channelInfo = {
9
+ id: "nostr",
10
+ name: "Nostr",
11
+ version: "1.0.0",
12
+ description: "Nostr integration for Pool Bot",
13
+ author: "Pool Bot Team",
14
+ };
@@ -0,0 +1,55 @@
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
+ import { NostrChannel, createNostrChannel } from "./nostr-channel";
3
+
4
+ describe("NostrChannel", () => {
5
+ const mockConfig = {
6
+ relays: ["wss://relay.damus.io", "wss://nos.lol"],
7
+ };
8
+
9
+ let channel: NostrChannel;
10
+
11
+ beforeEach(() => {
12
+ channel = createNostrChannel(mockConfig);
13
+ });
14
+
15
+ it("creates channel with correct id", () => {
16
+ expect(channel.id).toBe("nostr");
17
+ expect(channel.name).toBe("Nostr");
18
+ });
19
+
20
+ it("generates keypair if not provided", () => {
21
+ expect(channel.getPublicKey()).toBeDefined();
22
+ expect(channel.getPublicKey().length).toBe(64);
23
+ });
24
+
25
+ it("uses provided public key", () => {
26
+ const configWithKey = {
27
+ ...mockConfig,
28
+ publicKey: "abc123",
29
+ };
30
+ const channel2 = createNostrChannel(configWithKey);
31
+ expect(channel2.getPublicKey()).toBe("abc123");
32
+ });
33
+
34
+ it("starts disconnected", () => {
35
+ expect(channel.getStatus()).toBe("disconnected");
36
+ });
37
+
38
+ it("returns presence with public key", async () => {
39
+ const presences = await channel.getPresences();
40
+ expect(presences.length).toBe(1);
41
+ expect(presences[0].userId).toBe(channel.getPublicKey());
42
+ });
43
+
44
+ it("throws error when sending while disconnected", async () => {
45
+ await expect(
46
+ channel.sendMessage({ text: "test", id: "1" }),
47
+ ).rejects.toThrow("not connected");
48
+ });
49
+
50
+ it("throws error sending DM without private key", async () => {
51
+ await expect(
52
+ channel.sendDirectMessage("recipient", "message"),
53
+ ).rejects.toThrow("without private key");
54
+ });
55
+ });