@poolzin/pool-bot 2026.3.22 → 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.
- package/CHANGELOG.md +54 -0
- package/dist/acp/bindings-store.js +209 -0
- package/dist/acp/control-plane/runtime-cache.js +54 -0
- package/dist/acp/control-plane/runtime-options.js +215 -0
- package/dist/acp/control-plane/session-actor-queue.js +36 -0
- package/dist/acp/runtime/errors.js +47 -0
- package/dist/acp/runtime/registry.js +86 -0
- package/dist/acp/runtime/types.js +1 -0
- package/dist/acp/translator.js +97 -0
- package/dist/agents/failover-error.js +145 -47
- package/dist/browser/browser-profile-manager.js +319 -0
- package/dist/browser/cdp-proxy-bypass.js +129 -0
- package/dist/browser/cdp-timeouts.js +41 -0
- package/dist/browser/chrome-extension-validator.js +406 -0
- package/dist/browser/chrome-mcp-snapshot.js +222 -0
- package/dist/browser/chrome-mcp.js +421 -0
- package/dist/browser/chrome-mcp.snapshot.js +133 -0
- package/dist/browser/errors.js +67 -0
- package/dist/browser/form-fields.js +22 -0
- package/dist/browser/output-atomic.js +44 -0
- package/dist/browser/profile-capabilities.js +47 -0
- package/dist/browser/safe-filename.js +25 -0
- package/dist/browser/snapshot-roles.js +60 -0
- package/dist/build-info.json +3 -3
- package/dist/commands/security-owner-only.js +86 -0
- package/dist/control-ui/assets/{index-Dvkl4Xlx.js → index-D7shnQwQ.js} +404 -388
- package/dist/control-ui/assets/index-D7shnQwQ.js.map +1 -0
- package/dist/control-ui/index.html +1 -1
- package/dist/cron/cron-filters.js +150 -0
- package/dist/gateway/device-pairing-security.js +197 -0
- package/dist/gateway/event-deduplication.js +167 -0
- package/dist/gateway/run-tracker.js +253 -0
- package/dist/gateway/server-methods/nodes.js +14 -0
- package/dist/gateway/websocket-preauth-security.js +188 -0
- package/dist/infra/errors.js +53 -13
- package/dist/infra/exec-approvals-security.js +217 -0
- package/dist/infra/security/command-analyzer.js +257 -0
- package/dist/plugins/loader.js +16 -8
- package/dist/security/external-content.js +51 -1
- package/dist/sessions/session-costs.js +228 -0
- package/dist/shared/param-key.js +16 -0
- package/dist/shared/poll-params.js +58 -0
- package/dist/shared/polls.js +55 -0
- package/docs/DASHBOARD-GAP-ANALYSIS-AND-PLAN.md +430 -0
- package/docs/FEATURES.md +523 -0
- package/docs/FINAL-IMPLEMENTATION-REVIEW.md +274 -0
- package/docs/FINAL-IMPLEMENTATION-SUMMARY.md +356 -0
- package/docs/FINAL-PROFESSIONAL-EVALUATION.md +312 -0
- package/docs/IMPLEMENTATION-PRIORITY-EVALUATION.md +298 -0
- package/docs/IMPLEMENTATION-PROGRESS.md +237 -0
- package/docs/IMPLEMENTATION-REVIEW-PHASE1-2.md +381 -0
- package/docs/IMPLEMENTATION-REVIEW-PHASE4.md +389 -0
- package/docs/IMPLEMENTATION-REVIEW-PHASE5.md +420 -0
- package/docs/IMPLEMENTATION-REVIEW-PHASE6.md +422 -0
- package/docs/IMPLEMENTATION-REVIEW-PHASE7-FINAL.md +184 -0
- package/docs/MIKRODASH-ANALYSIS.md +412 -0
- package/docs/OPENCLAW-GAP-ANALYSIS-FINAL.md +431 -0
- package/docs/OPENCLAW-VS-POOLBOT-ANALYSIS.md +351 -0
- package/docs/PHASE-7-SUMMARY.md +144 -0
- package/docs/POOLBOT-OFFICE-PLAN.md +697 -0
- package/docs/PROJECT-FINAL-STATUS.md +237 -0
- package/docs/README.md +116 -0
- package/docs/REAL-IMPROVEMENTS-EVALUATION.md +477 -0
- package/docs/SECURITY-HARDENING-IMPLEMENTATION.md +161 -0
- package/docs/channels/googlechat.md +235 -206
- package/docs/channels/irc.md +332 -0
- package/docs/channels/nostr.md +255 -168
- package/docs/components/command-palette.md +166 -0
- package/docs/components/login-gate.md +219 -0
- package/docs/getting-started/installation.md +191 -0
- package/docs/getting-started/introduction.md +120 -0
- package/docs/improvements/USAGE-GUIDE.md +359 -0
- package/docs/plans/2026-03-15-openclaw-features-implementation.md +1632 -0
- package/docs/reference/deadcode-detection.md +72 -0
- package/extensions/acpx/node_modules/.bin/acpx +21 -0
- package/extensions/agency-agents/node_modules/.bin/vite +4 -4
- package/extensions/agency-agents/node_modules/.bin/vitest +2 -2
- package/extensions/googlechat/node_modules/.bin/tsc +21 -0
- package/extensions/googlechat/node_modules/.bin/tsserver +21 -0
- package/extensions/googlechat/node_modules/.bin/vitest +21 -0
- package/extensions/googlechat/package.json +11 -28
- package/extensions/googlechat/src/googlechat-channel.test.ts +60 -0
- package/extensions/googlechat/src/googlechat-channel.ts +120 -0
- package/extensions/googlechat/src/index.ts +14 -0
- package/extensions/irc/node_modules/.bin/tsc +21 -0
- package/extensions/irc/node_modules/.bin/tsserver +21 -0
- package/extensions/irc/node_modules/.bin/vitest +21 -0
- package/extensions/irc/package.json +16 -8
- package/extensions/irc/src/index.ts +14 -0
- package/extensions/irc/src/irc-channel.test.ts +43 -0
- package/extensions/irc/src/irc-channel.ts +191 -0
- package/extensions/keyed-async-queue/node_modules/.bin/tsc +21 -0
- package/extensions/keyed-async-queue/node_modules/.bin/tsserver +21 -0
- package/extensions/keyed-async-queue/node_modules/.bin/vitest +21 -0
- package/extensions/keyed-async-queue/package.json +20 -0
- package/extensions/keyed-async-queue/src/index.ts +14 -0
- package/extensions/keyed-async-queue/src/queue.test.ts +135 -0
- package/extensions/keyed-async-queue/src/queue.ts +200 -0
- package/extensions/memory-core/node_modules/.bin/tsc +21 -0
- package/extensions/memory-core/node_modules/.bin/tsserver +21 -0
- package/extensions/memory-core/node_modules/.bin/vitest +21 -0
- package/extensions/memory-core/package.json +11 -8
- package/extensions/memory-core/src/index.ts +14 -0
- package/extensions/memory-core/src/memory-manager.test.ts +124 -0
- package/extensions/memory-core/src/memory-manager.ts +186 -0
- package/extensions/nostr/node_modules/.bin/tsc +2 -2
- package/extensions/nostr/node_modules/.bin/tsserver +2 -2
- package/extensions/nostr/node_modules/.bin/vitest +21 -0
- package/extensions/nostr/package.json +15 -24
- package/extensions/nostr/src/index.ts +14 -0
- package/extensions/nostr/src/nostr-channel.test.ts +55 -0
- package/extensions/nostr/src/nostr-channel.ts +228 -0
- package/extensions/page-agent/node_modules/.bin/vitest +2 -2
- package/extensions/test-utils/node_modules/.bin/jiti +21 -0
- package/extensions/test-utils/node_modules/.bin/playwright +21 -0
- package/extensions/test-utils/node_modules/.bin/tsx +21 -0
- package/extensions/test-utils/node_modules/.bin/vite +21 -0
- package/extensions/test-utils/node_modules/.bin/vitest +21 -0
- package/extensions/test-utils/node_modules/.bin/yaml +21 -0
- package/extensions/xyops/node_modules/.bin/vitest +2 -2
- package/package.json +2 -1
- package/dist/control-ui/assets/index-Dvkl4Xlx.js.map +0 -1
- package/extensions/googlechat/node_modules/.bin/poolbot +0 -21
- 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": "
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Core memory management for Pool Bot agents",
|
|
4
5
|
"type": "module",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
|
|
9
|
-
]
|
|
6
|
+
"main": "src/index.js",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"test": "vitest run",
|
|
9
|
+
"build": "tsc"
|
|
10
10
|
},
|
|
11
|
+
"dependencies": {},
|
|
11
12
|
"devDependencies": {
|
|
12
|
-
"@
|
|
13
|
+
"@types/node": "^20.0.0",
|
|
14
|
+
"typescript": "^5.0.0",
|
|
15
|
+
"vitest": "^1.0.0"
|
|
13
16
|
},
|
|
14
17
|
"peerDependencies": {
|
|
15
|
-
"
|
|
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
|
|
18
|
+
exec "$basedir/node" "$basedir/../typescript/bin/tsc" "$@"
|
|
19
19
|
else
|
|
20
|
-
exec node "$basedir
|
|
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
|
|
18
|
+
exec "$basedir/node" "$basedir/../typescript/bin/tsserver" "$@"
|
|
19
19
|
else
|
|
20
|
-
exec node "$basedir
|
|
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": "
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Nostr channel extension for Pool Bot",
|
|
4
5
|
"type": "module",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
|
|
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
|
-
"
|
|
28
|
-
|
|
29
|
-
|
|
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
|
+
});
|