opc-agent 3.0.0 → 4.0.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.
Files changed (151) hide show
  1. package/README.md +30 -24
  2. package/dist/channels/dingtalk.d.ts +17 -0
  3. package/dist/channels/dingtalk.js +38 -0
  4. package/dist/channels/googlechat.d.ts +14 -0
  5. package/dist/channels/googlechat.js +37 -0
  6. package/dist/channels/imessage.d.ts +13 -0
  7. package/dist/channels/imessage.js +28 -0
  8. package/dist/channels/irc.d.ts +20 -0
  9. package/dist/channels/irc.js +71 -0
  10. package/dist/channels/line.d.ts +14 -0
  11. package/dist/channels/line.js +28 -0
  12. package/dist/channels/matrix.d.ts +15 -0
  13. package/dist/channels/matrix.js +28 -0
  14. package/dist/channels/mattermost.d.ts +18 -0
  15. package/dist/channels/mattermost.js +49 -0
  16. package/dist/channels/msteams.d.ts +14 -0
  17. package/dist/channels/msteams.js +28 -0
  18. package/dist/channels/nostr.d.ts +14 -0
  19. package/dist/channels/nostr.js +28 -0
  20. package/dist/channels/qq.d.ts +15 -0
  21. package/dist/channels/qq.js +28 -0
  22. package/dist/channels/signal.d.ts +14 -0
  23. package/dist/channels/signal.js +28 -0
  24. package/dist/channels/sms.d.ts +15 -0
  25. package/dist/channels/sms.js +28 -0
  26. package/dist/channels/twitch.d.ts +17 -0
  27. package/dist/channels/twitch.js +59 -0
  28. package/dist/channels/voice-call.d.ts +27 -0
  29. package/dist/channels/voice-call.js +82 -0
  30. package/dist/channels/whatsapp.d.ts +14 -0
  31. package/dist/channels/whatsapp.js +28 -0
  32. package/dist/cli.js +36 -0
  33. package/dist/core/api-server.d.ts +25 -0
  34. package/dist/core/api-server.js +286 -0
  35. package/dist/core/audio.d.ts +50 -0
  36. package/dist/core/audio.js +68 -0
  37. package/dist/core/context-discovery.d.ts +16 -0
  38. package/dist/core/context-discovery.js +107 -0
  39. package/dist/core/context-refs.d.ts +29 -0
  40. package/dist/core/context-refs.js +162 -0
  41. package/dist/core/gateway.d.ts +53 -0
  42. package/dist/core/gateway.js +80 -0
  43. package/dist/core/heartbeat.d.ts +19 -0
  44. package/dist/core/heartbeat.js +50 -0
  45. package/dist/core/hooks.d.ts +28 -0
  46. package/dist/core/hooks.js +82 -0
  47. package/dist/core/ide-bridge.d.ts +53 -0
  48. package/dist/core/ide-bridge.js +97 -0
  49. package/dist/core/node-network.d.ts +23 -0
  50. package/dist/core/node-network.js +77 -0
  51. package/dist/core/profiles.d.ts +27 -0
  52. package/dist/core/profiles.js +131 -0
  53. package/dist/core/sandbox.d.ts +25 -0
  54. package/dist/core/sandbox.js +84 -1
  55. package/dist/core/session-manager.d.ts +33 -0
  56. package/dist/core/session-manager.js +157 -0
  57. package/dist/core/vision.d.ts +45 -0
  58. package/dist/core/vision.js +177 -0
  59. package/dist/index.d.ts +64 -1
  60. package/dist/index.js +86 -3
  61. package/dist/memory/context-compressor.d.ts +43 -0
  62. package/dist/memory/context-compressor.js +167 -0
  63. package/dist/memory/index.d.ts +4 -0
  64. package/dist/memory/index.js +5 -1
  65. package/dist/memory/user-profiler.d.ts +50 -0
  66. package/dist/memory/user-profiler.js +201 -0
  67. package/dist/schema/oad.d.ts +12 -12
  68. package/dist/security/approvals.d.ts +53 -0
  69. package/dist/security/approvals.js +115 -0
  70. package/dist/security/elevated.d.ts +41 -0
  71. package/dist/security/elevated.js +89 -0
  72. package/dist/security/index.d.ts +6 -0
  73. package/dist/security/index.js +7 -1
  74. package/dist/security/secrets.d.ts +34 -0
  75. package/dist/security/secrets.js +115 -0
  76. package/dist/tools/builtin/browser.d.ts +47 -0
  77. package/dist/tools/builtin/browser.js +284 -0
  78. package/dist/tools/builtin/home-assistant.d.ts +12 -0
  79. package/dist/tools/builtin/home-assistant.js +126 -0
  80. package/dist/tools/builtin/index.d.ts +6 -1
  81. package/dist/tools/builtin/index.js +18 -2
  82. package/dist/tools/builtin/rl-tools.d.ts +13 -0
  83. package/dist/tools/builtin/rl-tools.js +228 -0
  84. package/dist/tools/builtin/vision.d.ts +6 -0
  85. package/dist/tools/builtin/vision.js +61 -0
  86. package/package.json +3 -3
  87. package/src/channels/dingtalk.ts +46 -0
  88. package/src/channels/googlechat.ts +42 -0
  89. package/src/channels/imessage.ts +32 -0
  90. package/src/channels/irc.ts +82 -0
  91. package/src/channels/line.ts +33 -0
  92. package/src/channels/matrix.ts +34 -0
  93. package/src/channels/mattermost.ts +57 -0
  94. package/src/channels/msteams.ts +33 -0
  95. package/src/channels/nostr.ts +33 -0
  96. package/src/channels/qq.ts +34 -0
  97. package/src/channels/signal.ts +33 -0
  98. package/src/channels/sms.ts +34 -0
  99. package/src/channels/twitch.ts +65 -0
  100. package/src/channels/voice-call.ts +100 -0
  101. package/src/channels/whatsapp.ts +33 -0
  102. package/src/cli.ts +40 -0
  103. package/src/core/api-server.ts +277 -0
  104. package/src/core/audio.ts +98 -0
  105. package/src/core/context-discovery.ts +85 -0
  106. package/src/core/context-refs.ts +140 -0
  107. package/src/core/gateway.ts +106 -0
  108. package/src/core/heartbeat.ts +51 -0
  109. package/src/core/hooks.ts +105 -0
  110. package/src/core/ide-bridge.ts +133 -0
  111. package/src/core/node-network.ts +86 -0
  112. package/src/core/profiles.ts +122 -0
  113. package/src/core/sandbox.ts +100 -0
  114. package/src/core/session-manager.ts +137 -0
  115. package/src/core/vision.ts +180 -0
  116. package/src/index.ts +84 -1
  117. package/src/memory/context-compressor.ts +189 -0
  118. package/src/memory/index.ts +4 -0
  119. package/src/memory/user-profiler.ts +215 -0
  120. package/src/security/approvals.ts +143 -0
  121. package/src/security/elevated.ts +105 -0
  122. package/src/security/index.ts +6 -0
  123. package/src/security/secrets.ts +129 -0
  124. package/src/tools/builtin/browser.ts +299 -0
  125. package/src/tools/builtin/home-assistant.ts +116 -0
  126. package/src/tools/builtin/index.ts +9 -2
  127. package/src/tools/builtin/rl-tools.ts +243 -0
  128. package/src/tools/builtin/vision.ts +64 -0
  129. package/tests/api-server.test.ts +148 -0
  130. package/tests/approvals.test.ts +89 -0
  131. package/tests/audio.test.ts +40 -0
  132. package/tests/browser.test.ts +179 -0
  133. package/tests/builtin-tools.test.ts +83 -83
  134. package/tests/channels-extra.test.ts +45 -0
  135. package/tests/context-compressor.test.ts +172 -0
  136. package/tests/context-refs.test.ts +121 -0
  137. package/tests/elevated.test.ts +69 -0
  138. package/tests/gateway.test.ts +63 -71
  139. package/tests/home-assistant.test.ts +40 -0
  140. package/tests/hooks.test.ts +79 -0
  141. package/tests/ide-bridge.test.ts +38 -0
  142. package/tests/node-network.test.ts +74 -0
  143. package/tests/profiles.test.ts +61 -0
  144. package/tests/rl-tools.test.ts +93 -0
  145. package/tests/sandbox-manager.test.ts +46 -0
  146. package/tests/secrets.test.ts +107 -0
  147. package/tests/tools/builtin-extended.test.ts +138 -138
  148. package/tests/user-profiler.test.ts +169 -0
  149. package/tests/v090-features.test.ts +254 -0
  150. package/tests/vision.test.ts +61 -0
  151. package/tests/voice-call.test.ts +47 -0
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ /**
3
+ * Hooks Module - v1.0.0
4
+ * Event hook system with priority ordering and context modification.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.HookManager = exports.ALL_HOOK_EVENTS = void 0;
8
+ exports.ALL_HOOK_EVENTS = [
9
+ 'before:message', 'after:message',
10
+ 'before:tool', 'after:tool',
11
+ 'before:llm', 'after:llm',
12
+ 'before:send', 'after:send',
13
+ 'before:learn', 'after:learn',
14
+ 'before:recall', 'after:recall',
15
+ 'on:error', 'on:start', 'on:stop',
16
+ ];
17
+ let hookIdCounter = 0;
18
+ class HookManager {
19
+ hooks = new Map();
20
+ register(event, handler, options) {
21
+ const id = `hook_${++hookIdCounter}`;
22
+ const entry = {
23
+ id,
24
+ event,
25
+ handler,
26
+ priority: options?.priority ?? 100,
27
+ name: options?.name,
28
+ };
29
+ if (!this.hooks.has(event))
30
+ this.hooks.set(event, []);
31
+ const list = this.hooks.get(event);
32
+ list.push(entry);
33
+ list.sort((a, b) => a.priority - b.priority);
34
+ return id;
35
+ }
36
+ unregister(id) {
37
+ for (const [event, list] of this.hooks) {
38
+ const idx = list.findIndex(h => h.id === id);
39
+ if (idx !== -1) {
40
+ list.splice(idx, 1);
41
+ return true;
42
+ }
43
+ }
44
+ return false;
45
+ }
46
+ async run(event, ctx = {}) {
47
+ const list = this.hooks.get(event);
48
+ if (!list || list.length === 0)
49
+ return ctx;
50
+ let current = { ...ctx };
51
+ for (const hook of list) {
52
+ const result = await hook.handler(current);
53
+ if (result)
54
+ current = { ...current, ...result };
55
+ }
56
+ return current;
57
+ }
58
+ getRegistered(event) {
59
+ const results = [];
60
+ const events = event ? [event] : exports.ALL_HOOK_EVENTS;
61
+ for (const e of events) {
62
+ const list = this.hooks.get(e) ?? [];
63
+ for (const h of list) {
64
+ results.push({ id: h.id, event: h.event, priority: h.priority, name: h.name });
65
+ }
66
+ }
67
+ return results;
68
+ }
69
+ clear(event) {
70
+ if (event) {
71
+ this.hooks.delete(event);
72
+ }
73
+ else {
74
+ this.hooks.clear();
75
+ }
76
+ }
77
+ hasHooks(event) {
78
+ return (this.hooks.get(event)?.length ?? 0) > 0;
79
+ }
80
+ }
81
+ exports.HookManager = HookManager;
82
+ //# sourceMappingURL=hooks.js.map
@@ -0,0 +1,53 @@
1
+ export interface IDEConfig {
2
+ editor: 'vscode' | 'jetbrains' | 'zed' | 'cursor';
3
+ workspacePath?: string;
4
+ }
5
+ export interface Diagnostic {
6
+ path: string;
7
+ line: number;
8
+ column: number;
9
+ severity: 'error' | 'warning' | 'info';
10
+ message: string;
11
+ }
12
+ export interface TextEdit {
13
+ range: Range;
14
+ newText: string;
15
+ }
16
+ export interface Range {
17
+ startLine: number;
18
+ startColumn: number;
19
+ endLine: number;
20
+ endColumn: number;
21
+ }
22
+ export interface SearchOptions {
23
+ caseSensitive?: boolean;
24
+ regex?: boolean;
25
+ include?: string;
26
+ exclude?: string;
27
+ maxResults?: number;
28
+ }
29
+ export interface SearchResult {
30
+ path: string;
31
+ line: number;
32
+ column: number;
33
+ text: string;
34
+ }
35
+ export declare class IDEBridge {
36
+ private config;
37
+ constructor(config: IDEConfig);
38
+ private getCliCommand;
39
+ private exec;
40
+ openFile(path: string, line?: number): Promise<void>;
41
+ getDiagnostics(path?: string): Promise<Diagnostic[]>;
42
+ runCommand(command: string): Promise<string>;
43
+ getOpenFiles(): Promise<string[]>;
44
+ applyEdit(path: string, edits: TextEdit[]): Promise<void>;
45
+ search(query: string, options?: SearchOptions): Promise<SearchResult[]>;
46
+ getSelection(): Promise<{
47
+ path: string;
48
+ text: string;
49
+ range: Range;
50
+ } | null>;
51
+ installExtension(extensionId: string): Promise<void>;
52
+ }
53
+ //# sourceMappingURL=ide-bridge.d.ts.map
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.IDEBridge = void 0;
4
+ const child_process_1 = require("child_process");
5
+ class IDEBridge {
6
+ config;
7
+ constructor(config) {
8
+ this.config = config;
9
+ }
10
+ getCliCommand() {
11
+ switch (this.config.editor) {
12
+ case 'vscode':
13
+ case 'cursor': return this.config.editor === 'cursor' ? 'cursor' : 'code';
14
+ case 'jetbrains': return 'idea';
15
+ case 'zed': return 'zed';
16
+ }
17
+ }
18
+ exec(cmd) {
19
+ try {
20
+ return (0, child_process_1.execSync)(cmd, { encoding: 'utf-8', timeout: 10000, cwd: this.config.workspacePath }).trim();
21
+ }
22
+ catch (e) {
23
+ throw new Error(`IDE command failed: ${e.message}`);
24
+ }
25
+ }
26
+ async openFile(path, line) {
27
+ const cli = this.getCliCommand();
28
+ const target = line ? `${path}:${line}` : path;
29
+ if (this.config.editor === 'vscode' || this.config.editor === 'cursor') {
30
+ this.exec(`${cli} --goto "${target}"`);
31
+ }
32
+ else if (this.config.editor === 'zed') {
33
+ this.exec(`zed "${target}"`);
34
+ }
35
+ else {
36
+ this.exec(`${cli} --line ${line || 1} "${path}"`);
37
+ }
38
+ }
39
+ async getDiagnostics(path) {
40
+ // VS Code doesn't expose diagnostics via CLI; return empty as stub
41
+ return [];
42
+ }
43
+ async runCommand(command) {
44
+ const cli = this.getCliCommand();
45
+ if (this.config.editor === 'vscode' || this.config.editor === 'cursor') {
46
+ return this.exec(`${cli} --command "${command}"`);
47
+ }
48
+ throw new Error(`runCommand not supported for ${this.config.editor}`);
49
+ }
50
+ async getOpenFiles() {
51
+ // Stub — no standard CLI to get open files
52
+ return [];
53
+ }
54
+ async applyEdit(path, edits) {
55
+ // Stub — would use editor's API/extension
56
+ if (edits.length === 0)
57
+ return;
58
+ throw new Error('applyEdit requires an IDE extension to be installed. Use file system edits as fallback.');
59
+ }
60
+ async search(query, options) {
61
+ const cli = this.getCliCommand();
62
+ if (this.config.editor === 'vscode' || this.config.editor === 'cursor') {
63
+ try {
64
+ const args = [`--search "${query}"`];
65
+ if (options?.include)
66
+ args.push(`--include "${options.include}"`);
67
+ const output = this.exec(`${cli} ${args.join(' ')}`);
68
+ // Parse output lines
69
+ return output.split('\n').filter(Boolean).map(line => {
70
+ const match = line.match(/^(.+):(\d+):(\d+):(.*)$/);
71
+ if (!match)
72
+ return { path: '', line: 0, column: 0, text: line };
73
+ return { path: match[1], line: parseInt(match[2]), column: parseInt(match[3]), text: match[4] };
74
+ });
75
+ }
76
+ catch {
77
+ return [];
78
+ }
79
+ }
80
+ return [];
81
+ }
82
+ async getSelection() {
83
+ // Stub — requires editor extension
84
+ return null;
85
+ }
86
+ async installExtension(extensionId) {
87
+ const cli = this.getCliCommand();
88
+ if (this.config.editor === 'vscode' || this.config.editor === 'cursor') {
89
+ this.exec(`${cli} --install-extension ${extensionId}`);
90
+ }
91
+ else {
92
+ throw new Error(`installExtension not supported for ${this.config.editor}`);
93
+ }
94
+ }
95
+ }
96
+ exports.IDEBridge = IDEBridge;
97
+ //# sourceMappingURL=ide-bridge.js.map
@@ -0,0 +1,23 @@
1
+ import { EventEmitter } from 'events';
2
+ export interface RemoteNode {
3
+ id: string;
4
+ name: string;
5
+ host: string;
6
+ port: number;
7
+ type: 'vps' | 'pi' | 'phone' | 'desktop';
8
+ status: 'online' | 'offline' | 'pairing';
9
+ capabilities: string[];
10
+ lastSeen: number;
11
+ }
12
+ export declare class NodeNetwork extends EventEmitter {
13
+ private nodes;
14
+ addNode(config: Partial<RemoteNode>): RemoteNode;
15
+ removeNode(id: string): void;
16
+ listNodes(): RemoteNode[];
17
+ getNode(id: string): RemoteNode | null;
18
+ pair(nodeId: string, pairingCode: string): Promise<boolean>;
19
+ sendCommand(nodeId: string, command: string): Promise<any>;
20
+ broadcast(command: string): Promise<Map<string, any>>;
21
+ healthCheck(): Promise<Map<string, boolean>>;
22
+ }
23
+ //# sourceMappingURL=node-network.d.ts.map
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NodeNetwork = void 0;
4
+ const crypto_1 = require("crypto");
5
+ const events_1 = require("events");
6
+ class NodeNetwork extends events_1.EventEmitter {
7
+ nodes = new Map();
8
+ addNode(config) {
9
+ const node = {
10
+ id: config.id || (0, crypto_1.randomUUID)(),
11
+ name: config.name || 'unnamed',
12
+ host: config.host || 'localhost',
13
+ port: config.port || 8080,
14
+ type: config.type || 'desktop',
15
+ status: config.status || 'offline',
16
+ capabilities: config.capabilities || [],
17
+ lastSeen: Date.now(),
18
+ };
19
+ this.nodes.set(node.id, node);
20
+ return node;
21
+ }
22
+ removeNode(id) {
23
+ if (!this.nodes.has(id))
24
+ throw new Error(`Node ${id} not found`);
25
+ this.nodes.delete(id);
26
+ }
27
+ listNodes() {
28
+ return Array.from(this.nodes.values());
29
+ }
30
+ getNode(id) {
31
+ return this.nodes.get(id) || null;
32
+ }
33
+ async pair(nodeId, pairingCode) {
34
+ const node = this.nodes.get(nodeId);
35
+ if (!node)
36
+ throw new Error(`Node ${nodeId} not found`);
37
+ if (!pairingCode || pairingCode.length < 4)
38
+ return false;
39
+ node.status = 'online';
40
+ node.lastSeen = Date.now();
41
+ return true;
42
+ }
43
+ async sendCommand(nodeId, command) {
44
+ const node = this.nodes.get(nodeId);
45
+ if (!node)
46
+ throw new Error(`Node ${nodeId} not found`);
47
+ if (node.status !== 'online')
48
+ throw new Error(`Node ${nodeId} is ${node.status}`);
49
+ node.lastSeen = Date.now();
50
+ // Stub: return command echo
51
+ return { nodeId, command, status: 'sent', timestamp: Date.now() };
52
+ }
53
+ async broadcast(command) {
54
+ const results = new Map();
55
+ for (const [id, node] of this.nodes) {
56
+ if (node.status === 'online') {
57
+ try {
58
+ results.set(id, await this.sendCommand(id, command));
59
+ }
60
+ catch (e) {
61
+ results.set(id, { error: e.message });
62
+ }
63
+ }
64
+ }
65
+ return results;
66
+ }
67
+ async healthCheck() {
68
+ const results = new Map();
69
+ for (const [id, node] of this.nodes) {
70
+ results.set(id, node.status === 'online');
71
+ node.lastSeen = Date.now();
72
+ }
73
+ return results;
74
+ }
75
+ }
76
+ exports.NodeNetwork = NodeNetwork;
77
+ //# sourceMappingURL=node-network.js.map
@@ -0,0 +1,27 @@
1
+ export interface ProfileConfig {
2
+ model?: string;
3
+ systemPrompt?: string;
4
+ temperature?: number;
5
+ [key: string]: unknown;
6
+ }
7
+ export interface Profile {
8
+ name: string;
9
+ config: ProfileConfig;
10
+ createdAt: number;
11
+ lastUsed: number;
12
+ }
13
+ export declare class ProfileManager {
14
+ private profilesDir;
15
+ private currentName;
16
+ constructor(baseDir?: string);
17
+ private ensureDir;
18
+ private profileDir;
19
+ private profileFile;
20
+ create(name: string, config?: ProfileConfig): Profile;
21
+ switch(name: string): void;
22
+ list(): Profile[];
23
+ get(name: string): Profile;
24
+ delete(name: string): void;
25
+ current(): Profile;
26
+ }
27
+ //# sourceMappingURL=profiles.d.ts.map
@@ -0,0 +1,131 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.ProfileManager = void 0;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const os = __importStar(require("os"));
40
+ // ─── ProfileManager ─────────────────────────────────────────
41
+ class ProfileManager {
42
+ profilesDir;
43
+ currentName = 'default';
44
+ constructor(baseDir) {
45
+ this.profilesDir = baseDir ?? path.join(os.homedir(), '.opc', 'profiles');
46
+ this.ensureDir(this.profilesDir);
47
+ // Load current profile pointer
48
+ const pointerFile = path.join(this.profilesDir, '.current');
49
+ if (fs.existsSync(pointerFile)) {
50
+ this.currentName = fs.readFileSync(pointerFile, 'utf-8').trim();
51
+ }
52
+ }
53
+ ensureDir(dir) {
54
+ if (!fs.existsSync(dir)) {
55
+ fs.mkdirSync(dir, { recursive: true });
56
+ }
57
+ }
58
+ profileDir(name) {
59
+ return path.join(this.profilesDir, name);
60
+ }
61
+ profileFile(name) {
62
+ return path.join(this.profileDir(name), 'profile.json');
63
+ }
64
+ create(name, config = {}) {
65
+ const dir = this.profileDir(name);
66
+ if (fs.existsSync(dir)) {
67
+ throw new Error(`Profile '${name}' already exists`);
68
+ }
69
+ this.ensureDir(dir);
70
+ // Also create memory and sessions dirs
71
+ this.ensureDir(path.join(dir, 'memory'));
72
+ this.ensureDir(path.join(dir, 'sessions'));
73
+ const profile = {
74
+ name,
75
+ config,
76
+ createdAt: Date.now(),
77
+ lastUsed: Date.now(),
78
+ };
79
+ fs.writeFileSync(this.profileFile(name), JSON.stringify(profile, null, 2));
80
+ return profile;
81
+ }
82
+ switch(name) {
83
+ if (!fs.existsSync(this.profileDir(name))) {
84
+ throw new Error(`Profile '${name}' does not exist`);
85
+ }
86
+ this.currentName = name;
87
+ fs.writeFileSync(path.join(this.profilesDir, '.current'), name);
88
+ // Update lastUsed
89
+ const profile = this.get(name);
90
+ profile.lastUsed = Date.now();
91
+ fs.writeFileSync(this.profileFile(name), JSON.stringify(profile, null, 2));
92
+ }
93
+ list() {
94
+ if (!fs.existsSync(this.profilesDir))
95
+ return [];
96
+ return fs.readdirSync(this.profilesDir)
97
+ .filter(f => {
98
+ const full = path.join(this.profilesDir, f);
99
+ return fs.statSync(full).isDirectory() && fs.existsSync(path.join(full, 'profile.json'));
100
+ })
101
+ .map(f => this.get(f));
102
+ }
103
+ get(name) {
104
+ const file = this.profileFile(name);
105
+ if (!fs.existsSync(file)) {
106
+ throw new Error(`Profile '${name}' not found`);
107
+ }
108
+ return JSON.parse(fs.readFileSync(file, 'utf-8'));
109
+ }
110
+ delete(name) {
111
+ if (name === this.currentName) {
112
+ throw new Error(`Cannot delete the current active profile '${name}'`);
113
+ }
114
+ const dir = this.profileDir(name);
115
+ if (!fs.existsSync(dir)) {
116
+ throw new Error(`Profile '${name}' does not exist`);
117
+ }
118
+ fs.rmSync(dir, { recursive: true, force: true });
119
+ }
120
+ current() {
121
+ try {
122
+ return this.get(this.currentName);
123
+ }
124
+ catch {
125
+ // Auto-create default
126
+ return this.create(this.currentName);
127
+ }
128
+ }
129
+ }
130
+ exports.ProfileManager = ProfileManager;
131
+ //# sourceMappingURL=profiles.js.map
@@ -51,4 +51,29 @@ export declare class Sandbox {
51
51
  getMaxFileSize(): number;
52
52
  getMaxFiles(): number;
53
53
  }
54
+ export interface RemoteSandboxConfig {
55
+ backend: 'local' | 'docker' | 'ssh';
56
+ docker?: {
57
+ image: string;
58
+ volumes?: string[];
59
+ };
60
+ ssh?: {
61
+ host: string;
62
+ user: string;
63
+ keyPath?: string;
64
+ };
65
+ timeout?: number;
66
+ }
67
+ export interface ExecResult {
68
+ stdout: string;
69
+ stderr: string;
70
+ exitCode: number;
71
+ }
72
+ export declare class SandboxManager {
73
+ private defaultConfig;
74
+ constructor(config?: Partial<RemoteSandboxConfig>);
75
+ exec(command: string, config?: Partial<RemoteSandboxConfig>): Promise<ExecResult>;
76
+ upload(localPath: string, remotePath: string, config?: Partial<RemoteSandboxConfig>): Promise<void>;
77
+ download(remotePath: string, localPath: string, config?: Partial<RemoteSandboxConfig>): Promise<void>;
78
+ }
54
79
  //# sourceMappingURL=sandbox.d.ts.map
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.Sandbox = void 0;
36
+ exports.SandboxManager = exports.Sandbox = void 0;
37
37
  const path = __importStar(require("path"));
38
38
  const fs = __importStar(require("fs"));
39
39
  const TRUST_RESTRICTIONS = {
@@ -232,4 +232,87 @@ class Sandbox {
232
232
  }
233
233
  }
234
234
  exports.Sandbox = Sandbox;
235
+ class SandboxManager {
236
+ defaultConfig;
237
+ constructor(config) {
238
+ this.defaultConfig = {
239
+ backend: config?.backend ?? 'local',
240
+ docker: config?.docker,
241
+ ssh: config?.ssh,
242
+ timeout: config?.timeout ?? 30000,
243
+ };
244
+ }
245
+ async exec(command, config) {
246
+ const cfg = { ...this.defaultConfig, ...config };
247
+ const { execSync } = await Promise.resolve().then(() => __importStar(require('child_process')));
248
+ switch (cfg.backend) {
249
+ case 'local': {
250
+ try {
251
+ const stdout = execSync(command, {
252
+ timeout: cfg.timeout,
253
+ encoding: 'utf-8',
254
+ stdio: ['pipe', 'pipe', 'pipe'],
255
+ });
256
+ return { stdout: stdout ?? '', stderr: '', exitCode: 0 };
257
+ }
258
+ catch (err) {
259
+ return {
260
+ stdout: err.stdout ?? '',
261
+ stderr: err.stderr ?? '',
262
+ exitCode: err.status ?? 1,
263
+ };
264
+ }
265
+ }
266
+ case 'docker': {
267
+ if (!cfg.docker?.image)
268
+ throw new Error('Docker image is required');
269
+ const volumes = (cfg.docker.volumes ?? []).map(v => `-v ${v}`).join(' ');
270
+ const dockerCmd = `docker run --rm ${volumes} ${cfg.docker.image} sh -c "${command.replace(/"/g, '\\"')}"`;
271
+ return this.exec(dockerCmd, { backend: 'local', timeout: cfg.timeout });
272
+ }
273
+ case 'ssh': {
274
+ if (!cfg.ssh?.host || !cfg.ssh?.user)
275
+ throw new Error('SSH host and user are required');
276
+ const keyArg = cfg.ssh.keyPath ? `-i ${cfg.ssh.keyPath}` : '';
277
+ const sshCmd = `ssh ${keyArg} ${cfg.ssh.user}@${cfg.ssh.host} "${command.replace(/"/g, '\\"')}"`;
278
+ return this.exec(sshCmd, { backend: 'local', timeout: cfg.timeout });
279
+ }
280
+ default:
281
+ throw new Error(`Unknown sandbox backend: ${cfg.backend}`);
282
+ }
283
+ }
284
+ async upload(localPath, remotePath, config) {
285
+ const cfg = { ...this.defaultConfig, ...config };
286
+ if (cfg.backend === 'local') {
287
+ const fsp = await Promise.resolve().then(() => __importStar(require('fs')));
288
+ fsp.copyFileSync(localPath, remotePath);
289
+ return;
290
+ }
291
+ if (cfg.backend === 'ssh') {
292
+ const keyArg = cfg.ssh?.keyPath ? `-i ${cfg.ssh.keyPath}` : '';
293
+ await this.exec(`scp ${keyArg} "${localPath}" ${cfg.ssh.user}@${cfg.ssh.host}:"${remotePath}"`, { backend: 'local' });
294
+ return;
295
+ }
296
+ if (cfg.backend === 'docker') {
297
+ throw new Error('Upload to docker not yet supported. Use volumes instead.');
298
+ }
299
+ }
300
+ async download(remotePath, localPath, config) {
301
+ const cfg = { ...this.defaultConfig, ...config };
302
+ if (cfg.backend === 'local') {
303
+ const fsp = await Promise.resolve().then(() => __importStar(require('fs')));
304
+ fsp.copyFileSync(remotePath, localPath);
305
+ return;
306
+ }
307
+ if (cfg.backend === 'ssh') {
308
+ const keyArg = cfg.ssh?.keyPath ? `-i ${cfg.ssh.keyPath}` : '';
309
+ await this.exec(`scp ${keyArg} ${cfg.ssh.user}@${cfg.ssh.host}:"${remotePath}" "${localPath}"`, { backend: 'local' });
310
+ return;
311
+ }
312
+ if (cfg.backend === 'docker') {
313
+ throw new Error('Download from docker not yet supported. Use volumes instead.');
314
+ }
315
+ }
316
+ }
317
+ exports.SandboxManager = SandboxManager;
235
318
  //# sourceMappingURL=sandbox.js.map
@@ -0,0 +1,33 @@
1
+ import type { Message } from './types';
2
+ export interface Session {
3
+ id: string;
4
+ agentId: string;
5
+ channel: string;
6
+ messages: Message[];
7
+ metadata: Record<string, any>;
8
+ createdAt: number;
9
+ lastActivity: number;
10
+ parentId?: string;
11
+ compactedAt?: number;
12
+ }
13
+ export declare class SessionManager {
14
+ private sessions;
15
+ private storageDir;
16
+ constructor(storageDir?: string);
17
+ create(agentId: string, channel: string, parentId?: string): Session;
18
+ get(id: string): Session | null;
19
+ list(filter?: {
20
+ agentId?: string;
21
+ channel?: string;
22
+ active?: boolean;
23
+ }): Session[];
24
+ addMessage(sessionId: string, message: Message): void;
25
+ compact(sessionId: string, brain?: any): Promise<void>;
26
+ prune(maxAge: number): number;
27
+ getLineage(sessionId: string): Session[];
28
+ fork(sessionId: string): Session;
29
+ export(sessionId: string): string;
30
+ save(): void;
31
+ load(): void;
32
+ }
33
+ //# sourceMappingURL=session-manager.d.ts.map