pacs-core 0.1.0
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/LICENSE +21 -0
- package/README.md +602 -0
- package/bin/pacs-cli.js +7 -0
- package/package.json +31 -0
- package/phase2-test.mjs +53 -0
- package/src/agent-creator.js +178 -0
- package/src/agent-registry.js +165 -0
- package/src/bootstrap.js +245 -0
- package/src/cli.js +384 -0
- package/src/crypto.js +118 -0
- package/src/index.js +74 -0
- package/src/inter-agent-bus.js +187 -0
- package/src/learn-mode.js +97 -0
- package/src/learning-loop.js +254 -0
- package/src/memory-store.js +226 -0
- package/src/openclaw-bridge.cjs +214 -0
- package/src/openclaw-bridge.js +304 -0
- package/src/routing-engine.js +221 -0
- package/src/test.js +298 -0
- package/src/trigger-parser.js +187 -0
- package/src/triggers.json +122 -0
package/src/cli.js
ADDED
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PACS Core — CLI Tool
|
|
3
|
+
* Command-line interface for PACS operations
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* node src/cli.js <command> [args]
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const { readFileSync } = require('fs');
|
|
10
|
+
|
|
11
|
+
// --- Argument parsing (no external libs) ---
|
|
12
|
+
|
|
13
|
+
const argv = process.argv.slice(2);
|
|
14
|
+
|
|
15
|
+
function flag(name) {
|
|
16
|
+
const idx = argv.findIndex((a) => a === `--${name}` || a === `-${name[0]}`);
|
|
17
|
+
if (idx === -1) return null;
|
|
18
|
+
return argv[idx + 1] !== undefined && !argv[idx + 1].startsWith('-')
|
|
19
|
+
? argv.splice(idx + 1, 1)[0]
|
|
20
|
+
: true;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function boolFlag(name) {
|
|
24
|
+
return argv.includes(`--${name}`) || argv.includes(`-${name[0]}`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function positional(index) {
|
|
28
|
+
return argv[index];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function cmd(first, second) {
|
|
32
|
+
return argv[0] === first && (second === undefined || argv[1] === second);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// --- Output helpers ---
|
|
36
|
+
|
|
37
|
+
function info(msg) {
|
|
38
|
+
console.log(msg);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function error(msg) {
|
|
42
|
+
console.error(`[ERROR] ${msg}`);
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function success(msg) {
|
|
47
|
+
console.log(msg);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// --- Lazy-loaded modules (CJS) ---
|
|
51
|
+
|
|
52
|
+
function getAgentRegistry() {
|
|
53
|
+
return require('./agent-registry.js').default;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function getMemoryStore() {
|
|
57
|
+
return require('./memory-store.js');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function getLearnMode() {
|
|
61
|
+
return require('./learn-mode.js').default;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function getBridgeStatus() {
|
|
65
|
+
try {
|
|
66
|
+
return require('./openclaw-bridge.cjs').status;
|
|
67
|
+
} catch {
|
|
68
|
+
return () => ({ initialized: false, mode: 'unknown', enabled: false, openClawConnected: false });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// --- Commands ---
|
|
73
|
+
|
|
74
|
+
function showHelp() {
|
|
75
|
+
console.log(`
|
|
76
|
+
PACS — Personal AI Control System
|
|
77
|
+
==================================
|
|
78
|
+
|
|
79
|
+
Usage: pacs <command> [options]
|
|
80
|
+
|
|
81
|
+
Commands:
|
|
82
|
+
pacs --help
|
|
83
|
+
Show this help text.
|
|
84
|
+
|
|
85
|
+
pacs init
|
|
86
|
+
Initialize PACS storage directory.
|
|
87
|
+
|
|
88
|
+
pacs status
|
|
89
|
+
Show PACS status (bridge, mode, agents count, memory facts).
|
|
90
|
+
|
|
91
|
+
pacs agents list
|
|
92
|
+
List all registered agents.
|
|
93
|
+
|
|
94
|
+
pacs agents add <name> [--text "..."] [--md ./file.md]
|
|
95
|
+
Register a new agent. Use --text or --md for description.
|
|
96
|
+
|
|
97
|
+
pacs agents remove <name>
|
|
98
|
+
Remove an agent by name.
|
|
99
|
+
|
|
100
|
+
pacs agents get <name>
|
|
101
|
+
Show details for a specific agent.
|
|
102
|
+
|
|
103
|
+
pacs memory list
|
|
104
|
+
List all memory facts.
|
|
105
|
+
|
|
106
|
+
pacs memory search <query>
|
|
107
|
+
Search memory facts for a query string.
|
|
108
|
+
|
|
109
|
+
pacs memory add "<fact>"
|
|
110
|
+
Add a new memory fact.
|
|
111
|
+
|
|
112
|
+
pacs memory forget "<fact>"
|
|
113
|
+
Remove a memory fact by content match.
|
|
114
|
+
|
|
115
|
+
pacs learn-mode get
|
|
116
|
+
Show the current learn mode (safe | explicit | auto).
|
|
117
|
+
|
|
118
|
+
pacs learn-mode set <mode>
|
|
119
|
+
Set learn mode to safe, explicit, or auto.
|
|
120
|
+
|
|
121
|
+
pacs messages <agent>
|
|
122
|
+
Show message history for an agent.
|
|
123
|
+
|
|
124
|
+
Examples:
|
|
125
|
+
pacs agents add finbot --text "Finance agent"
|
|
126
|
+
pacs memory add "Lech prefers German in the morning"
|
|
127
|
+
pacs memory search "preferences"
|
|
128
|
+
pacs learn-mode set explicit
|
|
129
|
+
`);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// -- init --
|
|
133
|
+
|
|
134
|
+
function handleInit() {
|
|
135
|
+
const ms = getMemoryStore();
|
|
136
|
+
ms.ensureStorageDir();
|
|
137
|
+
info('PACS initialisiert. Storage: ~/.openclaw/pacs/');
|
|
138
|
+
info('Hinweis: PACS_ENCRYPTION_KEY muss in der Umgebung gesetzt sein.');
|
|
139
|
+
success('✓ Init abgeschlossen.');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// -- status --
|
|
143
|
+
|
|
144
|
+
function handleStatus() {
|
|
145
|
+
const bridge = getBridgeStatus()();
|
|
146
|
+
let agentCount = '?';
|
|
147
|
+
let factCount = '?';
|
|
148
|
+
|
|
149
|
+
try {
|
|
150
|
+
const registry = getAgentRegistry();
|
|
151
|
+
agentCount = registry.listAgents().length;
|
|
152
|
+
} catch {
|
|
153
|
+
agentCount = 'Fehler (falscher Key?)';
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
try {
|
|
157
|
+
const ms = getMemoryStore();
|
|
158
|
+
const memory = ms.readMemory() || {};
|
|
159
|
+
factCount = memory.facts ? memory.facts.length : 0;
|
|
160
|
+
} catch {
|
|
161
|
+
factCount = 'Fehler (falscher Key?)';
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
info('=== PACS Status ===');
|
|
165
|
+
info(`Bridge initialisiert : ${bridge.initialized ? 'ja' : 'nein'}`);
|
|
166
|
+
info(`Bridge Mode : ${bridge.mode}`);
|
|
167
|
+
info(`Bridge aktiviert : ${bridge.enabled ? 'ja' : 'nein'}`);
|
|
168
|
+
info(`OpenClaw verbunden : ${bridge.openClawConnected ? 'ja' : 'nein'}`);
|
|
169
|
+
info(`Agenten registriert : ${agentCount}`);
|
|
170
|
+
info(`Memory Facts : ${factCount}`);
|
|
171
|
+
success('✓ Status abgerufen.');
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// -- agents --
|
|
175
|
+
|
|
176
|
+
function handleAgents() {
|
|
177
|
+
const registry = getAgentRegistry();
|
|
178
|
+
const sub = positional(1);
|
|
179
|
+
|
|
180
|
+
if (cmd('list') || sub === 'list') {
|
|
181
|
+
const agents = registry.listAgents();
|
|
182
|
+
if (agents.length === 0) {
|
|
183
|
+
info('Keine Agenten registriert.');
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
info(`=== Agenten (${agents.length}) ===`);
|
|
187
|
+
for (const a of agents) {
|
|
188
|
+
info(` ${String(a.name).padEnd(20)} ${String(a.domain).padEnd(15)} ${a.status}`);
|
|
189
|
+
}
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (sub === 'add') {
|
|
194
|
+
const name = positional(2);
|
|
195
|
+
if (!name) error('Usage: pacs agents add <name> [--text "..."] [--md ./file.md]');
|
|
196
|
+
|
|
197
|
+
let description = flag('text') || '';
|
|
198
|
+
const mdFile = flag('md');
|
|
199
|
+
if (mdFile) {
|
|
200
|
+
try {
|
|
201
|
+
description = readFileSync(mdFile, 'utf8').slice(0, 500);
|
|
202
|
+
} catch {
|
|
203
|
+
error(`Datei nicht gefunden: ${mdFile}`);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const agent = registry.registerAgent(name, { description });
|
|
208
|
+
success(`✓ Agent "${agent.name}" registriert (ID: ${agent.id})`);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (sub === 'remove') {
|
|
213
|
+
const name = positional(2);
|
|
214
|
+
if (!name) error('Usage: pacs agents remove <name>');
|
|
215
|
+
const removed = registry.removeAgent(name);
|
|
216
|
+
if (removed) {
|
|
217
|
+
success(`✓ Agent "${name}" entfernt.`);
|
|
218
|
+
} else {
|
|
219
|
+
error(`Agent "${name}" nicht gefunden.`);
|
|
220
|
+
}
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (sub === 'get') {
|
|
225
|
+
const name = positional(2);
|
|
226
|
+
if (!name) error('Usage: pacs agents get <name>');
|
|
227
|
+
const agent = registry.getAgent(name);
|
|
228
|
+
if (!agent) error(`Agent "${name}" nicht gefunden.`);
|
|
229
|
+
info(`=== Agent: ${agent.name} ===`);
|
|
230
|
+
info(` ID : ${agent.id}`);
|
|
231
|
+
info(` Domain : ${agent.domain}`);
|
|
232
|
+
info(` Status : ${agent.status}`);
|
|
233
|
+
info(` Capabilities: ${(agent.capabilities || []).join(', ') || '(none)'}`);
|
|
234
|
+
info(` Created : ${agent.createdAt}`);
|
|
235
|
+
info(` Last Active : ${agent.lastActive}`);
|
|
236
|
+
info(` Description : ${agent.description}`);
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
error(`Unknown agents subcommand: ${sub}. Use: list, add, remove, get`);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// -- memory --
|
|
244
|
+
|
|
245
|
+
function handleMemory() {
|
|
246
|
+
const ms = getMemoryStore();
|
|
247
|
+
const sub = positional(1);
|
|
248
|
+
|
|
249
|
+
if (sub === 'list') {
|
|
250
|
+
const mem = ms.readMemory() || { facts: [] };
|
|
251
|
+
const facts = mem.facts || [];
|
|
252
|
+
if (facts.length === 0) {
|
|
253
|
+
info('Keine Memory Facts gespeichert.');
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
info(`=== Memory (${facts.length}) ===`);
|
|
257
|
+
for (const fact of facts) {
|
|
258
|
+
info(` • ${fact}`);
|
|
259
|
+
}
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (sub === 'search') {
|
|
264
|
+
const query = argv.slice(2).join(' ').replace(/^(search|list)\s*/i, '');
|
|
265
|
+
if (!query) error('Usage: pacs memory search <query>');
|
|
266
|
+
const results = ms.searchFacts(query);
|
|
267
|
+
if (results.length === 0) {
|
|
268
|
+
info(`Keine Ergebnisse für "${query}".`);
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
info(`=== Suchergebnisse für "${query}" (${results.length}) ===`);
|
|
272
|
+
for (const r of results) info(` • ${r}`);
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (sub === 'add') {
|
|
277
|
+
const fact = argv.slice(2).join(' ').replace(/^(add)\s*/i, '');
|
|
278
|
+
if (!fact) error('Usage: pacs memory add "<fact>"');
|
|
279
|
+
ms.addFact(fact);
|
|
280
|
+
success(`✓ Fact gespeichert: "${fact}"`);
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (sub === 'forget') {
|
|
285
|
+
const fact = argv.slice(2).join(' ').replace(/^(forget)\s*/i, '');
|
|
286
|
+
if (!fact) error('Usage: pacs memory forget "<fact>"');
|
|
287
|
+
ms.removeFact(fact);
|
|
288
|
+
success(`✓ Fact entfernt.`);
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
error(`Unknown memory subcommand: ${sub}. Use: list, search, add, forget`);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// -- learn-mode --
|
|
296
|
+
|
|
297
|
+
function handleLearnMode() {
|
|
298
|
+
const lm = getLearnMode();
|
|
299
|
+
const sub = positional(1);
|
|
300
|
+
|
|
301
|
+
if (sub === 'get' || !sub) {
|
|
302
|
+
success(`Learn-Mode: ${lm.getMode()}`);
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (sub === 'set') {
|
|
307
|
+
const newMode = positional(2);
|
|
308
|
+
if (!newMode) error('Usage: pacs learn-mode set <safe|explicit|auto>');
|
|
309
|
+
const valid = ['safe', 'explicit', 'auto'];
|
|
310
|
+
if (!valid.includes(newMode.toLowerCase())) {
|
|
311
|
+
error(`Ungültiger Modus: ${newMode}. Gültig: ${valid.join(', ')}`);
|
|
312
|
+
}
|
|
313
|
+
lm.setMode(newMode.toLowerCase());
|
|
314
|
+
success(`✓ Learn-Mode gesetzt auf: ${newMode.toLowerCase()}`);
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
error(`Unknown learn-mode subcommand: ${sub}. Use: get, set`);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// -- messages --
|
|
322
|
+
|
|
323
|
+
function handleMessages() {
|
|
324
|
+
const registry = getAgentRegistry();
|
|
325
|
+
const agentName = positional(1);
|
|
326
|
+
if (!agentName) error('Usage: pacs messages <agent>');
|
|
327
|
+
const agent = registry.getAgent(agentName);
|
|
328
|
+
if (!agent) error(`Agent "${agentName}" nicht gefunden.`);
|
|
329
|
+
|
|
330
|
+
const messages = agent.metadata && agent.metadata.messages ? agent.metadata.messages : [];
|
|
331
|
+
if (messages.length === 0) {
|
|
332
|
+
info(`Keine Nachrichten für Agent "${agentName}".`);
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
info(`=== Nachrichten für ${agentName} (${messages.length}) ===`);
|
|
336
|
+
for (const m of messages) {
|
|
337
|
+
info(` [${m.role}] ${m.text}`);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// --- Main router ---
|
|
342
|
+
|
|
343
|
+
function main() {
|
|
344
|
+
const first = argv[0];
|
|
345
|
+
|
|
346
|
+
if (!first || first === '--help' || first === '-h' || first === 'help') {
|
|
347
|
+
showHelp();
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if (cmd('init')) {
|
|
352
|
+
handleInit();
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
if (cmd('status')) {
|
|
357
|
+
handleStatus();
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
if (cmd('agents')) {
|
|
362
|
+
handleAgents();
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
if (cmd('memory')) {
|
|
367
|
+
handleMemory();
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
if (cmd('learn-mode')) {
|
|
372
|
+
handleLearnMode();
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if (cmd('messages')) {
|
|
377
|
+
handleMessages();
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
error(`Unknown command: ${first}. Run "pacs --help" for usage.`);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
main();
|
package/src/crypto.js
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PACS Core — Cryptography Module
|
|
3
|
+
* AES-256-GCM encryption/decryption using Node.js built-in crypto
|
|
4
|
+
* Key is read from PACS_ENCRYPTION_KEY environment variable only.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const crypto = require('crypto');
|
|
8
|
+
|
|
9
|
+
const ALGORITHM = 'aes-256-gcm';
|
|
10
|
+
const IV_LENGTH = 16;
|
|
11
|
+
const AUTH_TAG_LENGTH = 16;
|
|
12
|
+
const SALT_LENGTH = 32;
|
|
13
|
+
const KEY_LENGTH = 32;
|
|
14
|
+
const PBKDF2_ITERATIONS = 100000;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Get encryption key from environment variable.
|
|
18
|
+
* Derives a proper 256-bit key from the env value using PBKDF2.
|
|
19
|
+
* @param {string} [password] - Optional password override (for testing)
|
|
20
|
+
* @returns {Buffer} 32-byte encryption key
|
|
21
|
+
*/
|
|
22
|
+
function getKey(password) {
|
|
23
|
+
const envKey = password || process.env.PACS_ENCRYPTION_KEY;
|
|
24
|
+
|
|
25
|
+
if (!envKey) {
|
|
26
|
+
throw new Error(
|
|
27
|
+
'PACS_ENCRYPTION_KEY environment variable is not set. ' +
|
|
28
|
+
'Please set it before using encrypted storage.\n' +
|
|
29
|
+
'Example: export PACS_ENCRYPTION_KEY="your-secure-random-key-here"'
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Use PBKDF2 to derive a proper 256-bit key from the env value
|
|
34
|
+
// Salt is fixed for deterministic derivation (salt is stored with ciphertext)
|
|
35
|
+
const salt = Buffer.from('pacs-core-salt-v1', 'utf8');
|
|
36
|
+
return crypto.pbkdf2Sync(envKey, salt, PBKDF2_ITERATIONS, KEY_LENGTH, 'sha512');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Encrypt plaintext using AES-256-GCM.
|
|
41
|
+
* @param {string} plaintext - The text to encrypt
|
|
42
|
+
* @param {string} [password] - Optional password override
|
|
43
|
+
* @returns {string} Base64-encoded string: iv:authTag:ciphertext
|
|
44
|
+
*/
|
|
45
|
+
function encrypt(plaintext, password) {
|
|
46
|
+
if (!plaintext) {
|
|
47
|
+
throw new Error('Plaintext is required for encryption');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const key = getKey(password);
|
|
51
|
+
const iv = crypto.randomBytes(IV_LENGTH);
|
|
52
|
+
|
|
53
|
+
const cipher = crypto.createCipheriv(ALGORITHM, key, iv, {
|
|
54
|
+
authTagLength: AUTH_TAG_LENGTH,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
let ciphertext = cipher.update(plaintext, 'utf8', 'base64');
|
|
58
|
+
ciphertext += cipher.final('base64');
|
|
59
|
+
|
|
60
|
+
const authTag = cipher.getAuthTag();
|
|
61
|
+
|
|
62
|
+
// Format: iv:authTag:ciphertext (all base64)
|
|
63
|
+
return [
|
|
64
|
+
iv.toString('base64'),
|
|
65
|
+
authTag.toString('base64'),
|
|
66
|
+
ciphertext,
|
|
67
|
+
].join(':');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Decrypt ciphertext using AES-256-GCM.
|
|
72
|
+
* @param {string} encryptedData - Base64-encoded string: iv:authTag:ciphertext
|
|
73
|
+
* @param {string} [password] - Optional password override
|
|
74
|
+
* @returns {string} Decrypted plaintext
|
|
75
|
+
*/
|
|
76
|
+
function decrypt(encryptedData, password) {
|
|
77
|
+
if (!encryptedData) {
|
|
78
|
+
throw new Error('Encrypted data is required for decryption');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const parts = encryptedData.split(':');
|
|
82
|
+
if (parts.length !== 3) {
|
|
83
|
+
throw new Error('Invalid encrypted data format. Expected iv:authTag:ciphertext');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const [ivBase64, authTagBase64, ciphertext] = parts;
|
|
87
|
+
const key = getKey(password);
|
|
88
|
+
|
|
89
|
+
const iv = Buffer.from(ivBase64, 'base64');
|
|
90
|
+
const authTag = Buffer.from(authTagBase64, 'base64');
|
|
91
|
+
|
|
92
|
+
const decipher = crypto.createDecipheriv(ALGORITHM, key, iv, {
|
|
93
|
+
authTagLength: AUTH_TAG_LENGTH,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
decipher.setAuthTag(authTag);
|
|
97
|
+
|
|
98
|
+
let plaintext = decipher.update(ciphertext, 'base64', 'utf8');
|
|
99
|
+
plaintext += decipher.final('utf8');
|
|
100
|
+
|
|
101
|
+
return plaintext;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Generate a secure random key suitable for PACS_ENCRYPTION_KEY.
|
|
106
|
+
* @returns {string} 64-character hex string (256 bits)
|
|
107
|
+
*/
|
|
108
|
+
function generateKey() {
|
|
109
|
+
return crypto.randomBytes(32).toString('hex');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
module.exports = {
|
|
113
|
+
encrypt,
|
|
114
|
+
decrypt,
|
|
115
|
+
generateKey,
|
|
116
|
+
getKey,
|
|
117
|
+
ALGORITHM,
|
|
118
|
+
};
|
package/src/index.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PACS Core — Main Entry Point
|
|
3
|
+
* Personal AI Control System
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const crypto = require('./crypto');
|
|
7
|
+
const memoryStore = require('./memory-store');
|
|
8
|
+
const triggerParser = require('./trigger-parser');
|
|
9
|
+
|
|
10
|
+
// Default export object
|
|
11
|
+
const pacs = {
|
|
12
|
+
// Crypto utilities
|
|
13
|
+
crypto: {
|
|
14
|
+
encrypt: crypto.encrypt,
|
|
15
|
+
decrypt: crypto.decrypt,
|
|
16
|
+
generateKey: crypto.generateKey,
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
// Memory store
|
|
20
|
+
memory: {
|
|
21
|
+
read: memoryStore.readMemory,
|
|
22
|
+
write: memoryStore.writeMemory,
|
|
23
|
+
addFact: memoryStore.addFact,
|
|
24
|
+
removeFact: memoryStore.removeFact,
|
|
25
|
+
search: memoryStore.searchFacts,
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
// Routing store
|
|
29
|
+
routing: {
|
|
30
|
+
read: memoryStore.readRouting,
|
|
31
|
+
write: memoryStore.writeRouting,
|
|
32
|
+
addHint: memoryStore.addRoutingHint,
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
// Core rules
|
|
36
|
+
rules: {
|
|
37
|
+
read: memoryStore.readCoreRules,
|
|
38
|
+
write: memoryStore.writeCoreRules,
|
|
39
|
+
addRule: memoryStore.addRule,
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
// Trigger parsing
|
|
43
|
+
triggers: {
|
|
44
|
+
parse: triggerParser.parse,
|
|
45
|
+
find: triggerParser.findTrigger,
|
|
46
|
+
contains: triggerParser.containsTrigger,
|
|
47
|
+
detectLearnMode: triggerParser.detectLearnMode,
|
|
48
|
+
getHelp: triggerParser.getHelpText,
|
|
49
|
+
getAll: triggerParser.getAllTriggers,
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
// Storage info
|
|
53
|
+
getStorageDir: memoryStore.getStorageDir,
|
|
54
|
+
FILES: memoryStore.FILES,
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
module.exports = pacs;
|
|
58
|
+
module.exports.AgentRegistry = require('./agent-registry.js').default;
|
|
59
|
+
module.exports.InterAgentBus = require('./inter-agent-bus.js').default;
|
|
60
|
+
module.exports.AgentCreator = require('./agent-creator.js').default;
|
|
61
|
+
module.exports.RoutingEngine = require('./routing-engine.js').default;
|
|
62
|
+
module.exports.LearningLoop = require('./learning-loop.js').default;
|
|
63
|
+
module.exports.LearnMode = require('./learn-mode.js').default;
|
|
64
|
+
|
|
65
|
+
// ES Module re-exports (for ESM consumers)
|
|
66
|
+
module.exports.AgentRegistryESM = () => import('./agent-registry.js');
|
|
67
|
+
module.exports.InterAgentBusESM = () => import('./inter-agent-bus.js');
|
|
68
|
+
module.exports.AgentCreatorESM = () => import('./agent-creator.js');
|
|
69
|
+
module.exports.RoutingEngineESM = () => import('./routing-engine.js');
|
|
70
|
+
module.exports.LearningLoopESM = () => import('./learning-loop.js');
|
|
71
|
+
module.exports.LearnModeESM = () => import('./learn-mode.js');
|
|
72
|
+
|
|
73
|
+
// OpenClaw Bridge
|
|
74
|
+
module.exports.OpenClawBridge = require('./openclaw-bridge.cjs');
|