chainlesschain 0.37.12 → 0.40.1
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/package.json +3 -2
- package/src/commands/agent.js +7 -1
- package/src/commands/ask.js +24 -9
- package/src/commands/chat.js +7 -1
- package/src/commands/cli-anything.js +266 -0
- package/src/commands/compliance.js +216 -0
- package/src/commands/dao.js +312 -0
- package/src/commands/dlp.js +278 -0
- package/src/commands/evomap.js +558 -0
- package/src/commands/hardening.js +230 -0
- package/src/commands/matrix.js +168 -0
- package/src/commands/nostr.js +185 -0
- package/src/commands/pqc.js +162 -0
- package/src/commands/scim.js +218 -0
- package/src/commands/serve.js +109 -0
- package/src/commands/siem.js +156 -0
- package/src/commands/social.js +480 -0
- package/src/commands/terraform.js +148 -0
- package/src/constants.js +1 -0
- package/src/index.js +60 -0
- package/src/lib/autonomous-agent.js +487 -0
- package/src/lib/cli-anything-bridge.js +379 -0
- package/src/lib/cli-context-engineering.js +472 -0
- package/src/lib/compliance-manager.js +290 -0
- package/src/lib/content-recommender.js +205 -0
- package/src/lib/dao-governance.js +296 -0
- package/src/lib/dlp-engine.js +304 -0
- package/src/lib/evomap-client.js +135 -0
- package/src/lib/evomap-federation.js +240 -0
- package/src/lib/evomap-governance.js +250 -0
- package/src/lib/evomap-manager.js +227 -0
- package/src/lib/git-integration.js +1 -1
- package/src/lib/hardening-manager.js +275 -0
- package/src/lib/llm-providers.js +14 -1
- package/src/lib/matrix-bridge.js +196 -0
- package/src/lib/nostr-bridge.js +195 -0
- package/src/lib/permanent-memory.js +370 -0
- package/src/lib/plan-mode.js +211 -0
- package/src/lib/pqc-manager.js +196 -0
- package/src/lib/scim-manager.js +212 -0
- package/src/lib/session-manager.js +38 -0
- package/src/lib/siem-exporter.js +137 -0
- package/src/lib/social-manager.js +283 -0
- package/src/lib/task-model-selector.js +232 -0
- package/src/lib/terraform-manager.js +201 -0
- package/src/lib/ws-server.js +474 -0
- package/src/repl/agent-repl.js +796 -41
- package/src/repl/chat-repl.js +14 -6
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Matrix Bridge — login, room management, messaging,
|
|
3
|
+
* and E2EE support for the Matrix protocol.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import crypto from "crypto";
|
|
7
|
+
|
|
8
|
+
/* ── In-memory stores ──────────────────────────────────────── */
|
|
9
|
+
const _rooms = new Map();
|
|
10
|
+
const _messages = new Map();
|
|
11
|
+
let _loginState = {
|
|
12
|
+
state: "logged_out",
|
|
13
|
+
userId: null,
|
|
14
|
+
homeserver: null,
|
|
15
|
+
accessToken: null,
|
|
16
|
+
e2eeEnabled: true,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const LOGIN_STATE = {
|
|
20
|
+
LOGGED_OUT: "logged_out",
|
|
21
|
+
LOGGING_IN: "logging_in",
|
|
22
|
+
LOGGED_IN: "logged_in",
|
|
23
|
+
ERROR: "error",
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/* ── Schema ────────────────────────────────────────────────── */
|
|
27
|
+
|
|
28
|
+
export function ensureMatrixTables(db) {
|
|
29
|
+
db.exec(`
|
|
30
|
+
CREATE TABLE IF NOT EXISTS matrix_rooms (
|
|
31
|
+
id TEXT PRIMARY KEY,
|
|
32
|
+
room_id TEXT,
|
|
33
|
+
name TEXT,
|
|
34
|
+
topic TEXT,
|
|
35
|
+
is_encrypted INTEGER DEFAULT 1,
|
|
36
|
+
member_count INTEGER DEFAULT 0,
|
|
37
|
+
last_event_at TEXT,
|
|
38
|
+
joined_at TEXT,
|
|
39
|
+
status TEXT DEFAULT 'joined',
|
|
40
|
+
created_at TEXT DEFAULT (datetime('now'))
|
|
41
|
+
)
|
|
42
|
+
`);
|
|
43
|
+
db.exec(`
|
|
44
|
+
CREATE TABLE IF NOT EXISTS matrix_events (
|
|
45
|
+
id TEXT PRIMARY KEY,
|
|
46
|
+
event_id TEXT,
|
|
47
|
+
room_id TEXT,
|
|
48
|
+
sender TEXT,
|
|
49
|
+
event_type TEXT,
|
|
50
|
+
content TEXT,
|
|
51
|
+
origin_server_ts TEXT,
|
|
52
|
+
is_encrypted INTEGER DEFAULT 0,
|
|
53
|
+
decrypted_content TEXT,
|
|
54
|
+
created_at TEXT DEFAULT (datetime('now'))
|
|
55
|
+
)
|
|
56
|
+
`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/* ── Login ─────────────────────────────────────────────────── */
|
|
60
|
+
|
|
61
|
+
export function login(db, homeserver, userId, password) {
|
|
62
|
+
if (!userId) throw new Error("User ID is required");
|
|
63
|
+
if (!password) throw new Error("Password is required");
|
|
64
|
+
|
|
65
|
+
const hs = homeserver || "https://matrix.org";
|
|
66
|
+
const token = crypto.randomBytes(32).toString("hex");
|
|
67
|
+
|
|
68
|
+
_loginState = {
|
|
69
|
+
state: LOGIN_STATE.LOGGED_IN,
|
|
70
|
+
userId,
|
|
71
|
+
homeserver: hs,
|
|
72
|
+
accessToken: token,
|
|
73
|
+
e2eeEnabled: true,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
success: true,
|
|
78
|
+
userId,
|
|
79
|
+
homeserver: hs,
|
|
80
|
+
accessToken: token.slice(0, 8) + "...",
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function getLoginState() {
|
|
85
|
+
return {
|
|
86
|
+
state: _loginState.state,
|
|
87
|
+
userId: _loginState.userId,
|
|
88
|
+
homeserver: _loginState.homeserver,
|
|
89
|
+
e2eeEnabled: _loginState.e2eeEnabled,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/* ── Room Management ──────────────────────────────────────── */
|
|
94
|
+
|
|
95
|
+
export function listRooms() {
|
|
96
|
+
return [..._rooms.values()].filter((r) => r.status === "joined");
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function joinRoom(db, roomIdOrAlias) {
|
|
100
|
+
if (!roomIdOrAlias) throw new Error("Room ID or alias is required");
|
|
101
|
+
|
|
102
|
+
// Check if already joined
|
|
103
|
+
for (const room of _rooms.values()) {
|
|
104
|
+
if (room.roomId === roomIdOrAlias) return { success: true, room };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const id = crypto.randomUUID();
|
|
108
|
+
const now = new Date().toISOString();
|
|
109
|
+
|
|
110
|
+
const room = {
|
|
111
|
+
id,
|
|
112
|
+
roomId: roomIdOrAlias,
|
|
113
|
+
name: roomIdOrAlias,
|
|
114
|
+
topic: null,
|
|
115
|
+
isEncrypted: true,
|
|
116
|
+
memberCount: 1,
|
|
117
|
+
lastEventAt: now,
|
|
118
|
+
joinedAt: now,
|
|
119
|
+
status: "joined",
|
|
120
|
+
createdAt: now,
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
_rooms.set(id, room);
|
|
124
|
+
|
|
125
|
+
db.prepare(
|
|
126
|
+
`INSERT INTO matrix_rooms (id, room_id, name, topic, is_encrypted, member_count, last_event_at, joined_at, status, created_at)
|
|
127
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
128
|
+
).run(id, room.roomId, room.name, null, 1, 1, now, now, "joined", now);
|
|
129
|
+
|
|
130
|
+
return { success: true, room };
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/* ── Messaging ─────────────────────────────────────────────── */
|
|
134
|
+
|
|
135
|
+
export function sendMessage(db, roomId, body, msgtype) {
|
|
136
|
+
if (!roomId) throw new Error("Room ID is required");
|
|
137
|
+
if (!body) throw new Error("Message body is required");
|
|
138
|
+
|
|
139
|
+
const id = crypto.randomUUID();
|
|
140
|
+
const eventId = `$${crypto.randomBytes(16).toString("hex")}`;
|
|
141
|
+
const now = new Date().toISOString();
|
|
142
|
+
|
|
143
|
+
const message = {
|
|
144
|
+
id,
|
|
145
|
+
eventId,
|
|
146
|
+
roomId,
|
|
147
|
+
sender: _loginState.userId || "cli-user",
|
|
148
|
+
eventType: "m.room.message",
|
|
149
|
+
content: { body, msgtype: msgtype || "m.text" },
|
|
150
|
+
originServerTs: now,
|
|
151
|
+
isEncrypted: _loginState.e2eeEnabled,
|
|
152
|
+
createdAt: now,
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
_messages.set(id, message);
|
|
156
|
+
|
|
157
|
+
db.prepare(
|
|
158
|
+
`INSERT INTO matrix_events (id, event_id, room_id, sender, event_type, content, origin_server_ts, is_encrypted, decrypted_content, created_at)
|
|
159
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
160
|
+
).run(
|
|
161
|
+
id,
|
|
162
|
+
eventId,
|
|
163
|
+
roomId,
|
|
164
|
+
message.sender,
|
|
165
|
+
"m.room.message",
|
|
166
|
+
JSON.stringify(message.content),
|
|
167
|
+
now,
|
|
168
|
+
message.isEncrypted ? 1 : 0,
|
|
169
|
+
body,
|
|
170
|
+
now,
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
return { success: true, event: message };
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export function getMessages(roomId, filter = {}) {
|
|
177
|
+
if (!roomId) throw new Error("Room ID is required");
|
|
178
|
+
|
|
179
|
+
let messages = [..._messages.values()].filter((m) => m.roomId === roomId);
|
|
180
|
+
const limit = filter.limit || 50;
|
|
181
|
+
return messages.slice(0, limit);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/* ── Reset (for testing) ───────────────────────────────────── */
|
|
185
|
+
|
|
186
|
+
export function _resetState() {
|
|
187
|
+
_rooms.clear();
|
|
188
|
+
_messages.clear();
|
|
189
|
+
_loginState = {
|
|
190
|
+
state: "logged_out",
|
|
191
|
+
userId: null,
|
|
192
|
+
homeserver: null,
|
|
193
|
+
accessToken: null,
|
|
194
|
+
e2eeEnabled: true,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nostr Bridge — relay management, event publishing,
|
|
3
|
+
* keypair generation, and DID mapping for Nostr protocol.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import crypto from "crypto";
|
|
7
|
+
|
|
8
|
+
/* ── In-memory stores ──────────────────────────────────────── */
|
|
9
|
+
const _relays = new Map();
|
|
10
|
+
const _events = new Map();
|
|
11
|
+
const _keypairs = new Map();
|
|
12
|
+
const _didMappings = new Map();
|
|
13
|
+
|
|
14
|
+
const EVENT_KINDS = {
|
|
15
|
+
SET_METADATA: 0,
|
|
16
|
+
TEXT_NOTE: 1,
|
|
17
|
+
RECOMMEND_RELAY: 2,
|
|
18
|
+
CONTACTS: 3,
|
|
19
|
+
ENCRYPTED_DM: 4,
|
|
20
|
+
DELETE: 5,
|
|
21
|
+
REPOST: 6,
|
|
22
|
+
REACTION: 7,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/* ── Schema ────────────────────────────────────────────────── */
|
|
26
|
+
|
|
27
|
+
export function ensureNostrTables(db) {
|
|
28
|
+
db.exec(`
|
|
29
|
+
CREATE TABLE IF NOT EXISTS nostr_relays (
|
|
30
|
+
id TEXT PRIMARY KEY,
|
|
31
|
+
url TEXT NOT NULL,
|
|
32
|
+
status TEXT DEFAULT 'disconnected',
|
|
33
|
+
last_connected TEXT,
|
|
34
|
+
event_count INTEGER DEFAULT 0,
|
|
35
|
+
read_enabled INTEGER DEFAULT 1,
|
|
36
|
+
write_enabled INTEGER DEFAULT 1
|
|
37
|
+
)
|
|
38
|
+
`);
|
|
39
|
+
db.exec(`
|
|
40
|
+
CREATE TABLE IF NOT EXISTS nostr_events (
|
|
41
|
+
id TEXT PRIMARY KEY,
|
|
42
|
+
pubkey TEXT,
|
|
43
|
+
kind INTEGER,
|
|
44
|
+
content TEXT,
|
|
45
|
+
tags TEXT,
|
|
46
|
+
sig TEXT,
|
|
47
|
+
created_at TEXT,
|
|
48
|
+
relay_url TEXT,
|
|
49
|
+
imported INTEGER DEFAULT 0
|
|
50
|
+
)
|
|
51
|
+
`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* ── Relay Management ─────────────────────────────────────── */
|
|
55
|
+
|
|
56
|
+
export function listRelays() {
|
|
57
|
+
return [..._relays.values()];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function addRelay(db, url) {
|
|
61
|
+
if (!url) throw new Error("Relay URL is required");
|
|
62
|
+
|
|
63
|
+
// Check if already exists
|
|
64
|
+
for (const relay of _relays.values()) {
|
|
65
|
+
if (relay.url === url) return relay;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const id = crypto.randomUUID();
|
|
69
|
+
const relay = {
|
|
70
|
+
id,
|
|
71
|
+
url,
|
|
72
|
+
status: "disconnected",
|
|
73
|
+
lastConnected: null,
|
|
74
|
+
eventCount: 0,
|
|
75
|
+
readEnabled: true,
|
|
76
|
+
writeEnabled: true,
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
_relays.set(id, relay);
|
|
80
|
+
|
|
81
|
+
db.prepare(
|
|
82
|
+
`INSERT INTO nostr_relays (id, url, status, last_connected, event_count, read_enabled, write_enabled)
|
|
83
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
|
84
|
+
).run(id, url, "disconnected", null, 0, 1, 1);
|
|
85
|
+
|
|
86
|
+
return relay;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* ── Event Publishing ─────────────────────────────────────── */
|
|
90
|
+
|
|
91
|
+
export function publishEvent(db, kind, content, pubkey, tags) {
|
|
92
|
+
if (content === undefined || content === null)
|
|
93
|
+
throw new Error("Content is required");
|
|
94
|
+
|
|
95
|
+
const now = new Date().toISOString();
|
|
96
|
+
const serialized = JSON.stringify([
|
|
97
|
+
0,
|
|
98
|
+
pubkey || "anonymous",
|
|
99
|
+
now,
|
|
100
|
+
kind || 1,
|
|
101
|
+
tags || [],
|
|
102
|
+
content,
|
|
103
|
+
]);
|
|
104
|
+
const id = crypto.createHash("sha256").update(serialized).digest("hex");
|
|
105
|
+
const sig = crypto.randomBytes(64).toString("hex");
|
|
106
|
+
|
|
107
|
+
const event = {
|
|
108
|
+
id,
|
|
109
|
+
pubkey: pubkey || "anonymous",
|
|
110
|
+
kind: kind || EVENT_KINDS.TEXT_NOTE,
|
|
111
|
+
content,
|
|
112
|
+
tags: tags || [],
|
|
113
|
+
sig,
|
|
114
|
+
createdAt: now,
|
|
115
|
+
relayUrl: null,
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
_events.set(id, event);
|
|
119
|
+
|
|
120
|
+
// Count relays that received the event
|
|
121
|
+
const writeRelays = [..._relays.values()].filter((r) => r.writeEnabled);
|
|
122
|
+
let sentCount = 0;
|
|
123
|
+
for (const relay of writeRelays) {
|
|
124
|
+
relay.eventCount++;
|
|
125
|
+
sentCount++;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
db.prepare(
|
|
129
|
+
`INSERT INTO nostr_events (id, pubkey, kind, content, tags, sig, created_at, relay_url, imported)
|
|
130
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
131
|
+
).run(
|
|
132
|
+
id,
|
|
133
|
+
event.pubkey,
|
|
134
|
+
event.kind,
|
|
135
|
+
content,
|
|
136
|
+
JSON.stringify(tags || []),
|
|
137
|
+
sig,
|
|
138
|
+
now,
|
|
139
|
+
null,
|
|
140
|
+
0,
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
return { success: true, event, sentCount };
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/* ── Event Retrieval ──────────────────────────────────────── */
|
|
147
|
+
|
|
148
|
+
export function getEvents(filter = {}) {
|
|
149
|
+
let events = [..._events.values()];
|
|
150
|
+
if (filter.kinds) {
|
|
151
|
+
events = events.filter((e) => filter.kinds.includes(e.kind));
|
|
152
|
+
}
|
|
153
|
+
const limit = filter.limit || 50;
|
|
154
|
+
return events.slice(0, limit);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/* ── Keypair Generation ───────────────────────────────────── */
|
|
158
|
+
|
|
159
|
+
export function generateKeypair() {
|
|
160
|
+
const privateKey = crypto.randomBytes(32).toString("hex");
|
|
161
|
+
const publicKey = crypto
|
|
162
|
+
.createHash("sha256")
|
|
163
|
+
.update(privateKey)
|
|
164
|
+
.digest("hex");
|
|
165
|
+
const id = crypto.randomUUID();
|
|
166
|
+
|
|
167
|
+
const keypair = {
|
|
168
|
+
id,
|
|
169
|
+
publicKey,
|
|
170
|
+
privateKey,
|
|
171
|
+
createdAt: new Date().toISOString(),
|
|
172
|
+
};
|
|
173
|
+
_keypairs.set(id, keypair);
|
|
174
|
+
|
|
175
|
+
return keypair;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/* ── DID Mapping ──────────────────────────────────────────── */
|
|
179
|
+
|
|
180
|
+
export function mapDid(did, nostrPubkey) {
|
|
181
|
+
if (!did) throw new Error("DID is required");
|
|
182
|
+
if (!nostrPubkey) throw new Error("Nostr pubkey is required");
|
|
183
|
+
|
|
184
|
+
_didMappings.set(did, nostrPubkey);
|
|
185
|
+
return { did, nostrPubkey, mapped: true };
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/* ── Reset (for testing) ───────────────────────────────────── */
|
|
189
|
+
|
|
190
|
+
export function _resetState() {
|
|
191
|
+
_relays.clear();
|
|
192
|
+
_events.clear();
|
|
193
|
+
_keypairs.clear();
|
|
194
|
+
_didMappings.clear();
|
|
195
|
+
}
|