opc-agent 3.0.1 → 4.0.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.
Files changed (216) hide show
  1. package/README.md +404 -74
  2. package/README.zh-CN.md +82 -0
  3. package/dist/channels/dingtalk.d.ts +17 -0
  4. package/dist/channels/dingtalk.js +38 -0
  5. package/dist/channels/googlechat.d.ts +14 -0
  6. package/dist/channels/googlechat.js +37 -0
  7. package/dist/channels/imessage.d.ts +13 -0
  8. package/dist/channels/imessage.js +28 -0
  9. package/dist/channels/irc.d.ts +20 -0
  10. package/dist/channels/irc.js +71 -0
  11. package/dist/channels/line.d.ts +14 -0
  12. package/dist/channels/line.js +28 -0
  13. package/dist/channels/matrix.d.ts +15 -0
  14. package/dist/channels/matrix.js +28 -0
  15. package/dist/channels/mattermost.d.ts +18 -0
  16. package/dist/channels/mattermost.js +49 -0
  17. package/dist/channels/msteams.d.ts +14 -0
  18. package/dist/channels/msteams.js +28 -0
  19. package/dist/channels/nostr.d.ts +14 -0
  20. package/dist/channels/nostr.js +28 -0
  21. package/dist/channels/qq.d.ts +15 -0
  22. package/dist/channels/qq.js +28 -0
  23. package/dist/channels/signal.d.ts +14 -0
  24. package/dist/channels/signal.js +28 -0
  25. package/dist/channels/sms.d.ts +15 -0
  26. package/dist/channels/sms.js +28 -0
  27. package/dist/channels/twitch.d.ts +17 -0
  28. package/dist/channels/twitch.js +59 -0
  29. package/dist/channels/voice-call.d.ts +27 -0
  30. package/dist/channels/voice-call.js +82 -0
  31. package/dist/channels/whatsapp.d.ts +14 -0
  32. package/dist/channels/whatsapp.js +28 -0
  33. package/dist/cli/chat.d.ts +2 -0
  34. package/dist/cli/chat.js +134 -0
  35. package/dist/cli/setup.d.ts +4 -0
  36. package/dist/cli/setup.js +303 -0
  37. package/dist/cli.js +142 -6
  38. package/dist/core/api-server.d.ts +25 -0
  39. package/dist/core/api-server.js +286 -0
  40. package/dist/core/audio.d.ts +50 -0
  41. package/dist/core/audio.js +68 -0
  42. package/dist/core/context-discovery.d.ts +16 -0
  43. package/dist/core/context-discovery.js +107 -0
  44. package/dist/core/context-refs.d.ts +29 -0
  45. package/dist/core/context-refs.js +162 -0
  46. package/dist/core/gateway.d.ts +53 -0
  47. package/dist/core/gateway.js +80 -0
  48. package/dist/core/heartbeat.d.ts +19 -0
  49. package/dist/core/heartbeat.js +50 -0
  50. package/dist/core/hooks.d.ts +28 -0
  51. package/dist/core/hooks.js +82 -0
  52. package/dist/core/ide-bridge.d.ts +53 -0
  53. package/dist/core/ide-bridge.js +97 -0
  54. package/dist/core/node-network.d.ts +23 -0
  55. package/dist/core/node-network.js +77 -0
  56. package/dist/core/profiles.d.ts +27 -0
  57. package/dist/core/profiles.js +131 -0
  58. package/dist/core/sandbox.d.ts +25 -0
  59. package/dist/core/sandbox.js +84 -1
  60. package/dist/core/session-manager.d.ts +33 -0
  61. package/dist/core/session-manager.js +157 -0
  62. package/dist/core/vision.d.ts +45 -0
  63. package/dist/core/vision.js +177 -0
  64. package/dist/hub/brain-seed.d.ts +14 -0
  65. package/dist/hub/brain-seed.js +77 -0
  66. package/dist/hub/client.d.ts +25 -0
  67. package/dist/hub/client.js +44 -0
  68. package/dist/index.d.ts +66 -1
  69. package/dist/index.js +95 -3
  70. package/dist/memory/context-compressor.d.ts +43 -0
  71. package/dist/memory/context-compressor.js +167 -0
  72. package/dist/memory/index.d.ts +4 -0
  73. package/dist/memory/index.js +5 -1
  74. package/dist/memory/user-profiler.d.ts +50 -0
  75. package/dist/memory/user-profiler.js +201 -0
  76. package/dist/providers/index.d.ts +1 -1
  77. package/dist/providers/index.js +54 -1
  78. package/dist/scheduler/cron-engine.d.ts +41 -0
  79. package/dist/scheduler/cron-engine.js +200 -0
  80. package/dist/scheduler/index.d.ts +3 -0
  81. package/dist/scheduler/index.js +7 -0
  82. package/dist/schema/oad.d.ts +12 -12
  83. package/dist/security/approvals.d.ts +53 -0
  84. package/dist/security/approvals.js +115 -0
  85. package/dist/security/elevated.d.ts +41 -0
  86. package/dist/security/elevated.js +89 -0
  87. package/dist/security/index.d.ts +6 -0
  88. package/dist/security/index.js +7 -1
  89. package/dist/security/secrets.d.ts +34 -0
  90. package/dist/security/secrets.js +115 -0
  91. package/dist/skills/builtin/index.d.ts +6 -0
  92. package/dist/skills/builtin/index.js +402 -0
  93. package/dist/skills/marketplace.d.ts +30 -0
  94. package/dist/skills/marketplace.js +142 -0
  95. package/dist/skills/types.d.ts +34 -0
  96. package/dist/skills/types.js +16 -0
  97. package/dist/studio/server.d.ts +25 -0
  98. package/dist/studio/server.js +780 -0
  99. package/dist/studio/templates-data.d.ts +21 -0
  100. package/dist/studio/templates-data.js +148 -0
  101. package/dist/studio-ui/index.html +2502 -1073
  102. package/dist/tools/builtin/browser.d.ts +47 -0
  103. package/dist/tools/builtin/browser.js +284 -0
  104. package/dist/tools/builtin/home-assistant.d.ts +12 -0
  105. package/dist/tools/builtin/home-assistant.js +126 -0
  106. package/dist/tools/builtin/index.d.ts +7 -1
  107. package/dist/tools/builtin/index.js +23 -2
  108. package/dist/tools/builtin/rl-tools.d.ts +13 -0
  109. package/dist/tools/builtin/rl-tools.js +228 -0
  110. package/dist/tools/builtin/vision.d.ts +6 -0
  111. package/dist/tools/builtin/vision.js +61 -0
  112. package/dist/tools/builtin/web-search.d.ts +9 -0
  113. package/dist/tools/builtin/web-search.js +150 -0
  114. package/dist/tools/document-processor.d.ts +39 -0
  115. package/dist/tools/document-processor.js +188 -0
  116. package/dist/tools/image-generator.d.ts +42 -0
  117. package/dist/tools/image-generator.js +136 -0
  118. package/dist/tools/web-scraper.d.ts +20 -0
  119. package/dist/tools/web-scraper.js +148 -0
  120. package/dist/tools/web-search.d.ts +51 -0
  121. package/dist/tools/web-search.js +152 -0
  122. package/install.ps1 +154 -0
  123. package/install.sh +164 -0
  124. package/package.json +63 -52
  125. package/src/channels/dingtalk.ts +46 -0
  126. package/src/channels/googlechat.ts +42 -0
  127. package/src/channels/imessage.ts +32 -0
  128. package/src/channels/irc.ts +82 -0
  129. package/src/channels/line.ts +33 -0
  130. package/src/channels/matrix.ts +34 -0
  131. package/src/channels/mattermost.ts +57 -0
  132. package/src/channels/msteams.ts +33 -0
  133. package/src/channels/nostr.ts +33 -0
  134. package/src/channels/qq.ts +34 -0
  135. package/src/channels/signal.ts +33 -0
  136. package/src/channels/sms.ts +34 -0
  137. package/src/channels/twitch.ts +65 -0
  138. package/src/channels/voice-call.ts +100 -0
  139. package/src/channels/whatsapp.ts +33 -0
  140. package/src/cli/chat.ts +99 -0
  141. package/src/cli/setup.ts +314 -0
  142. package/src/cli.ts +148 -6
  143. package/src/core/api-server.ts +277 -0
  144. package/src/core/audio.ts +98 -0
  145. package/src/core/context-discovery.ts +85 -0
  146. package/src/core/context-refs.ts +140 -0
  147. package/src/core/gateway.ts +106 -0
  148. package/src/core/heartbeat.ts +51 -0
  149. package/src/core/hooks.ts +105 -0
  150. package/src/core/ide-bridge.ts +133 -0
  151. package/src/core/node-network.ts +86 -0
  152. package/src/core/profiles.ts +122 -0
  153. package/src/core/sandbox.ts +100 -0
  154. package/src/core/session-manager.ts +137 -0
  155. package/src/core/vision.ts +180 -0
  156. package/src/hub/brain-seed.ts +54 -0
  157. package/src/hub/client.ts +60 -0
  158. package/src/index.ts +86 -1
  159. package/src/memory/context-compressor.ts +189 -0
  160. package/src/memory/index.ts +4 -0
  161. package/src/memory/user-profiler.ts +215 -0
  162. package/src/providers/index.ts +64 -1
  163. package/src/scheduler/cron-engine.ts +191 -0
  164. package/src/scheduler/index.ts +2 -0
  165. package/src/security/approvals.ts +143 -0
  166. package/src/security/elevated.ts +105 -0
  167. package/src/security/index.ts +6 -0
  168. package/src/security/secrets.ts +129 -0
  169. package/src/skills/builtin/index.ts +408 -0
  170. package/src/skills/marketplace.ts +113 -0
  171. package/src/skills/types.ts +42 -0
  172. package/src/studio/server.ts +1591 -791
  173. package/src/studio/templates-data.ts +178 -0
  174. package/src/studio-ui/index.html +2502 -1073
  175. package/src/tools/builtin/browser.ts +299 -0
  176. package/src/tools/builtin/home-assistant.ts +116 -0
  177. package/src/tools/builtin/index.ts +37 -28
  178. package/src/tools/builtin/rl-tools.ts +243 -0
  179. package/src/tools/builtin/vision.ts +64 -0
  180. package/src/tools/builtin/web-search.ts +126 -0
  181. package/src/tools/document-processor.ts +213 -0
  182. package/src/tools/image-generator.ts +150 -0
  183. package/src/tools/web-scraper.ts +179 -0
  184. package/src/tools/web-search.ts +180 -0
  185. package/tests/api-server.test.ts +148 -0
  186. package/tests/approvals.test.ts +89 -0
  187. package/tests/audio.test.ts +40 -0
  188. package/tests/browser.test.ts +179 -0
  189. package/tests/builtin-tools.test.ts +83 -83
  190. package/tests/channels-extra.test.ts +45 -0
  191. package/tests/context-compressor.test.ts +172 -0
  192. package/tests/context-refs.test.ts +121 -0
  193. package/tests/cron-engine.test.ts +101 -0
  194. package/tests/document-processor.test.ts +69 -0
  195. package/tests/e2e-nocode.test.ts +442 -0
  196. package/tests/elevated.test.ts +69 -0
  197. package/tests/gateway.test.ts +63 -71
  198. package/tests/home-assistant.test.ts +40 -0
  199. package/tests/hooks.test.ts +79 -0
  200. package/tests/ide-bridge.test.ts +38 -0
  201. package/tests/image-generator.test.ts +84 -0
  202. package/tests/node-network.test.ts +74 -0
  203. package/tests/profiles.test.ts +61 -0
  204. package/tests/rl-tools.test.ts +93 -0
  205. package/tests/sandbox-manager.test.ts +46 -0
  206. package/tests/secrets.test.ts +107 -0
  207. package/tests/settings-api.test.ts +148 -0
  208. package/tests/setup.test.ts +73 -0
  209. package/tests/studio.test.ts +402 -229
  210. package/tests/tools/builtin-extended.test.ts +138 -138
  211. package/tests/user-profiler.test.ts +169 -0
  212. package/tests/v090-features.test.ts +254 -0
  213. package/tests/vision.test.ts +61 -0
  214. package/tests/voice-call.test.ts +47 -0
  215. package/tests/voice-interaction.test.ts +38 -0
  216. package/tests/web-search.test.ts +155 -0
@@ -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
@@ -0,0 +1,157 @@
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.SessionManager = void 0;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const crypto = __importStar(require("crypto"));
40
+ class SessionManager {
41
+ sessions = new Map();
42
+ storageDir;
43
+ constructor(storageDir) {
44
+ this.storageDir = storageDir || path.join(process.env.HOME || process.env.USERPROFILE || '~', '.opc', 'sessions');
45
+ }
46
+ create(agentId, channel, parentId) {
47
+ const session = {
48
+ id: crypto.randomUUID(),
49
+ agentId,
50
+ channel,
51
+ messages: [],
52
+ metadata: {},
53
+ createdAt: Date.now(),
54
+ lastActivity: Date.now(),
55
+ parentId,
56
+ };
57
+ this.sessions.set(session.id, session);
58
+ return session;
59
+ }
60
+ get(id) {
61
+ return this.sessions.get(id) || null;
62
+ }
63
+ list(filter) {
64
+ let result = Array.from(this.sessions.values());
65
+ if (filter?.agentId)
66
+ result = result.filter(s => s.agentId === filter.agentId);
67
+ if (filter?.channel)
68
+ result = result.filter(s => s.channel === filter.channel);
69
+ if (filter?.active !== undefined) {
70
+ const cutoff = Date.now() - 30 * 60 * 1000; // 30 min
71
+ result = result.filter(s => filter.active ? s.lastActivity > cutoff : s.lastActivity <= cutoff);
72
+ }
73
+ return result;
74
+ }
75
+ addMessage(sessionId, message) {
76
+ const session = this.sessions.get(sessionId);
77
+ if (!session)
78
+ throw new Error(`Session ${sessionId} not found`);
79
+ session.messages.push(message);
80
+ session.lastActivity = Date.now();
81
+ }
82
+ async compact(sessionId, brain) {
83
+ const session = this.sessions.get(sessionId);
84
+ if (!session)
85
+ throw new Error(`Session ${sessionId} not found`);
86
+ if (brain && typeof brain.compress === 'function') {
87
+ const compressed = await brain.compress(session.messages);
88
+ session.messages = [{ id: 'compacted', role: 'system', content: compressed, timestamp: Date.now() }];
89
+ }
90
+ else {
91
+ // Simple: keep first and last 5 messages
92
+ if (session.messages.length > 10) {
93
+ const first = session.messages.slice(0, 2);
94
+ const last = session.messages.slice(-5);
95
+ session.messages = [...first, { id: 'compacted', role: 'system', content: `[${session.messages.length - 7} messages compacted]`, timestamp: Date.now() }, ...last];
96
+ }
97
+ }
98
+ session.compactedAt = Date.now();
99
+ }
100
+ prune(maxAge) {
101
+ const cutoff = Date.now() - maxAge;
102
+ let pruned = 0;
103
+ for (const [id, session] of this.sessions) {
104
+ if (session.lastActivity < cutoff) {
105
+ this.sessions.delete(id);
106
+ pruned++;
107
+ }
108
+ }
109
+ return pruned;
110
+ }
111
+ getLineage(sessionId) {
112
+ const lineage = [];
113
+ let current = this.sessions.get(sessionId);
114
+ while (current) {
115
+ lineage.unshift(current);
116
+ current = current.parentId ? this.sessions.get(current.parentId) || undefined : undefined;
117
+ }
118
+ return lineage;
119
+ }
120
+ fork(sessionId) {
121
+ const parent = this.sessions.get(sessionId);
122
+ if (!parent)
123
+ throw new Error(`Session ${sessionId} not found`);
124
+ return this.create(parent.agentId, parent.channel, parent.id);
125
+ }
126
+ export(sessionId) {
127
+ const session = this.sessions.get(sessionId);
128
+ if (!session)
129
+ throw new Error(`Session ${sessionId} not found`);
130
+ const lines = [`# Session ${session.id}`, `Agent: ${session.agentId} | Channel: ${session.channel}`, `Created: ${new Date(session.createdAt).toISOString()}`, ''];
131
+ for (const msg of session.messages) {
132
+ lines.push(`**${msg.role}** (${new Date(msg.timestamp).toISOString()}):`);
133
+ lines.push(msg.content);
134
+ lines.push('');
135
+ }
136
+ return lines.join('\n');
137
+ }
138
+ save() {
139
+ if (!fs.existsSync(this.storageDir)) {
140
+ fs.mkdirSync(this.storageDir, { recursive: true });
141
+ }
142
+ for (const [id, session] of this.sessions) {
143
+ fs.writeFileSync(path.join(this.storageDir, `${id}.json`), JSON.stringify(session, null, 2));
144
+ }
145
+ }
146
+ load() {
147
+ if (!fs.existsSync(this.storageDir))
148
+ return;
149
+ const files = fs.readdirSync(this.storageDir).filter(f => f.endsWith('.json'));
150
+ for (const file of files) {
151
+ const data = JSON.parse(fs.readFileSync(path.join(this.storageDir, file), 'utf-8'));
152
+ this.sessions.set(data.id, data);
153
+ }
154
+ }
155
+ }
156
+ exports.SessionManager = SessionManager;
157
+ //# sourceMappingURL=session-manager.js.map
@@ -0,0 +1,45 @@
1
+ export interface ImageInput {
2
+ type: 'base64' | 'url' | 'file';
3
+ data: string;
4
+ mimeType?: string;
5
+ }
6
+ export interface VisionResult {
7
+ description: string;
8
+ text_content?: string;
9
+ objects?: string[];
10
+ }
11
+ export declare function detectMimeType(buffer: Buffer): string;
12
+ export interface VisionManagerConfig {
13
+ model?: string;
14
+ apiKey?: string;
15
+ baseURL?: string;
16
+ maxImageSize?: number;
17
+ }
18
+ export declare class VisionManager {
19
+ private config;
20
+ constructor(config?: VisionManagerConfig);
21
+ /**
22
+ * Load image data as base64, detecting MIME type.
23
+ */
24
+ loadImage(input: ImageInput): Promise<{
25
+ base64: string;
26
+ mimeType: string;
27
+ }>;
28
+ /**
29
+ * Prepare messages in OpenAI multimodal format.
30
+ */
31
+ prepareMessage(images: ImageInput[], text: string): Array<Record<string, unknown>>;
32
+ /**
33
+ * Analyze an image with optional prompt.
34
+ */
35
+ analyze(image: ImageInput, prompt?: string): Promise<VisionResult>;
36
+ /**
37
+ * Extract text (OCR) from an image.
38
+ */
39
+ extractText(image: ImageInput): Promise<string>;
40
+ /**
41
+ * Compare multiple images.
42
+ */
43
+ compareImages(images: ImageInput[], prompt?: string): Promise<string>;
44
+ }
45
+ //# sourceMappingURL=vision.d.ts.map