@johpaz/hive 1.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.
Files changed (156) hide show
  1. package/CONTRIBUTING.md +44 -0
  2. package/README.md +310 -0
  3. package/package.json +96 -0
  4. package/packages/cli/package.json +28 -0
  5. package/packages/cli/src/commands/agent-run.ts +168 -0
  6. package/packages/cli/src/commands/agents.ts +398 -0
  7. package/packages/cli/src/commands/chat.ts +142 -0
  8. package/packages/cli/src/commands/config.ts +50 -0
  9. package/packages/cli/src/commands/cron.ts +161 -0
  10. package/packages/cli/src/commands/dev.ts +95 -0
  11. package/packages/cli/src/commands/doctor.ts +133 -0
  12. package/packages/cli/src/commands/gateway.ts +443 -0
  13. package/packages/cli/src/commands/logs.ts +57 -0
  14. package/packages/cli/src/commands/mcp.ts +175 -0
  15. package/packages/cli/src/commands/message.ts +77 -0
  16. package/packages/cli/src/commands/onboard.ts +1868 -0
  17. package/packages/cli/src/commands/security.ts +144 -0
  18. package/packages/cli/src/commands/service.ts +50 -0
  19. package/packages/cli/src/commands/sessions.ts +116 -0
  20. package/packages/cli/src/commands/skills.ts +187 -0
  21. package/packages/cli/src/commands/update.ts +25 -0
  22. package/packages/cli/src/index.ts +185 -0
  23. package/packages/cli/src/utils/token.ts +6 -0
  24. package/packages/code-bridge/README.md +78 -0
  25. package/packages/code-bridge/package.json +18 -0
  26. package/packages/code-bridge/src/index.ts +95 -0
  27. package/packages/code-bridge/src/process-manager.ts +212 -0
  28. package/packages/code-bridge/src/schemas.ts +133 -0
  29. package/packages/core/package.json +46 -0
  30. package/packages/core/src/agent/agent-loop.ts +369 -0
  31. package/packages/core/src/agent/compaction.ts +140 -0
  32. package/packages/core/src/agent/context-compiler.ts +378 -0
  33. package/packages/core/src/agent/context-guard.ts +91 -0
  34. package/packages/core/src/agent/context.ts +138 -0
  35. package/packages/core/src/agent/conversation-store.ts +198 -0
  36. package/packages/core/src/agent/curator.ts +158 -0
  37. package/packages/core/src/agent/hooks.ts +166 -0
  38. package/packages/core/src/agent/index.ts +116 -0
  39. package/packages/core/src/agent/llm-client.ts +503 -0
  40. package/packages/core/src/agent/native-tools.ts +505 -0
  41. package/packages/core/src/agent/prompt-builder.ts +532 -0
  42. package/packages/core/src/agent/providers/index.ts +167 -0
  43. package/packages/core/src/agent/providers.ts +1 -0
  44. package/packages/core/src/agent/reflector.ts +170 -0
  45. package/packages/core/src/agent/service.ts +64 -0
  46. package/packages/core/src/agent/stuck-loop.ts +133 -0
  47. package/packages/core/src/agent/supervisor.ts +39 -0
  48. package/packages/core/src/agent/tracer.ts +102 -0
  49. package/packages/core/src/agent/workspace.ts +110 -0
  50. package/packages/core/src/canvas/canvas-manager.test.ts +161 -0
  51. package/packages/core/src/canvas/canvas-manager.ts +319 -0
  52. package/packages/core/src/canvas/canvas-tools.ts +420 -0
  53. package/packages/core/src/canvas/emitter.ts +115 -0
  54. package/packages/core/src/canvas/index.ts +2 -0
  55. package/packages/core/src/channels/base.ts +138 -0
  56. package/packages/core/src/channels/discord.ts +260 -0
  57. package/packages/core/src/channels/index.ts +7 -0
  58. package/packages/core/src/channels/manager.ts +383 -0
  59. package/packages/core/src/channels/slack.ts +287 -0
  60. package/packages/core/src/channels/telegram.ts +502 -0
  61. package/packages/core/src/channels/webchat.ts +128 -0
  62. package/packages/core/src/channels/whatsapp.ts +375 -0
  63. package/packages/core/src/config/index.ts +12 -0
  64. package/packages/core/src/config/loader.ts +529 -0
  65. package/packages/core/src/events/event-bus.ts +169 -0
  66. package/packages/core/src/gateway/index.ts +5 -0
  67. package/packages/core/src/gateway/initializer.ts +290 -0
  68. package/packages/core/src/gateway/lane-queue.ts +169 -0
  69. package/packages/core/src/gateway/resolver.ts +108 -0
  70. package/packages/core/src/gateway/router.ts +124 -0
  71. package/packages/core/src/gateway/server.ts +3317 -0
  72. package/packages/core/src/gateway/session.ts +95 -0
  73. package/packages/core/src/gateway/slash-commands.ts +192 -0
  74. package/packages/core/src/heartbeat/index.ts +157 -0
  75. package/packages/core/src/index.ts +19 -0
  76. package/packages/core/src/integrations/catalog.ts +286 -0
  77. package/packages/core/src/integrations/env.ts +64 -0
  78. package/packages/core/src/integrations/index.ts +2 -0
  79. package/packages/core/src/memory/index.ts +1 -0
  80. package/packages/core/src/memory/notes.ts +68 -0
  81. package/packages/core/src/plugins/api.ts +128 -0
  82. package/packages/core/src/plugins/index.ts +2 -0
  83. package/packages/core/src/plugins/loader.ts +365 -0
  84. package/packages/core/src/resilience/circuit-breaker.ts +225 -0
  85. package/packages/core/src/security/google-chat.ts +269 -0
  86. package/packages/core/src/security/index.ts +192 -0
  87. package/packages/core/src/security/pairing.ts +250 -0
  88. package/packages/core/src/security/rate-limit.ts +270 -0
  89. package/packages/core/src/security/signal.ts +321 -0
  90. package/packages/core/src/state/store.ts +312 -0
  91. package/packages/core/src/storage/bun-sqlite-store.ts +188 -0
  92. package/packages/core/src/storage/crypto.ts +101 -0
  93. package/packages/core/src/storage/db-context.ts +333 -0
  94. package/packages/core/src/storage/onboarding.ts +1087 -0
  95. package/packages/core/src/storage/schema.ts +541 -0
  96. package/packages/core/src/storage/seed.ts +571 -0
  97. package/packages/core/src/storage/sqlite.ts +387 -0
  98. package/packages/core/src/storage/usage.ts +212 -0
  99. package/packages/core/src/tools/bridge-events.ts +74 -0
  100. package/packages/core/src/tools/browser.ts +275 -0
  101. package/packages/core/src/tools/codebridge.ts +421 -0
  102. package/packages/core/src/tools/coordinator-tools.ts +179 -0
  103. package/packages/core/src/tools/cron.ts +611 -0
  104. package/packages/core/src/tools/exec.ts +140 -0
  105. package/packages/core/src/tools/fs.ts +364 -0
  106. package/packages/core/src/tools/index.ts +12 -0
  107. package/packages/core/src/tools/memory.ts +176 -0
  108. package/packages/core/src/tools/notify.ts +113 -0
  109. package/packages/core/src/tools/project-management.ts +376 -0
  110. package/packages/core/src/tools/project.ts +375 -0
  111. package/packages/core/src/tools/read.ts +158 -0
  112. package/packages/core/src/tools/web.ts +436 -0
  113. package/packages/core/src/tools/workspace.ts +171 -0
  114. package/packages/core/src/utils/benchmark.ts +80 -0
  115. package/packages/core/src/utils/crypto.ts +73 -0
  116. package/packages/core/src/utils/date.ts +42 -0
  117. package/packages/core/src/utils/index.ts +4 -0
  118. package/packages/core/src/utils/logger.ts +388 -0
  119. package/packages/core/src/utils/retry.ts +70 -0
  120. package/packages/core/src/voice/index.ts +583 -0
  121. package/packages/core/tsconfig.json +9 -0
  122. package/packages/mcp/package.json +26 -0
  123. package/packages/mcp/src/config.ts +13 -0
  124. package/packages/mcp/src/index.ts +1 -0
  125. package/packages/mcp/src/logger.ts +42 -0
  126. package/packages/mcp/src/manager.ts +434 -0
  127. package/packages/mcp/src/transports/index.ts +67 -0
  128. package/packages/mcp/src/transports/sse.ts +241 -0
  129. package/packages/mcp/src/transports/websocket.ts +159 -0
  130. package/packages/skills/package.json +21 -0
  131. package/packages/skills/src/bundled/agent_management/SKILL.md +24 -0
  132. package/packages/skills/src/bundled/browser_automation/SKILL.md +30 -0
  133. package/packages/skills/src/bundled/context_compact/SKILL.md +35 -0
  134. package/packages/skills/src/bundled/cron_manager/SKILL.md +52 -0
  135. package/packages/skills/src/bundled/file_manager/SKILL.md +76 -0
  136. package/packages/skills/src/bundled/http_client/SKILL.md +24 -0
  137. package/packages/skills/src/bundled/memory/SKILL.md +42 -0
  138. package/packages/skills/src/bundled/project_management/SKILL.md +26 -0
  139. package/packages/skills/src/bundled/shell/SKILL.md +43 -0
  140. package/packages/skills/src/bundled/system_notify/SKILL.md +52 -0
  141. package/packages/skills/src/bundled/voice/SKILL.md +25 -0
  142. package/packages/skills/src/bundled/web_search/SKILL.md +29 -0
  143. package/packages/skills/src/index.ts +1 -0
  144. package/packages/skills/src/loader.ts +282 -0
  145. package/packages/tools/package.json +43 -0
  146. package/packages/tools/src/browser/browser.test.ts +111 -0
  147. package/packages/tools/src/browser/index.ts +272 -0
  148. package/packages/tools/src/canvas/index.ts +220 -0
  149. package/packages/tools/src/cron/cron.test.ts +164 -0
  150. package/packages/tools/src/cron/index.ts +304 -0
  151. package/packages/tools/src/filesystem/filesystem.test.ts +240 -0
  152. package/packages/tools/src/filesystem/index.ts +379 -0
  153. package/packages/tools/src/git/index.ts +239 -0
  154. package/packages/tools/src/index.ts +4 -0
  155. package/packages/tools/src/shell/detect-env.ts +70 -0
  156. package/packages/tools/tsconfig.json +9 -0
@@ -0,0 +1,140 @@
1
+ import type { Tool } from "../agent/native-tools.ts";
2
+ import type { Config } from "../config/loader.ts";
3
+ import { logger } from "../utils/logger.ts";
4
+
5
+ function getShellCommand(): { cmd: string; args: string[] } {
6
+ const platform = process.platform;
7
+
8
+ if (platform === "win32") {
9
+ return { cmd: "cmd", args: ["/c"] };
10
+ } else if (platform === "darwin") {
11
+ return { cmd: "/bin/sh", args: ["-c"] };
12
+ }
13
+
14
+ // Linux: use full path so posix_spawn can find the binary
15
+ return { cmd: "/bin/sh", args: ["-c"] };
16
+ }
17
+
18
+ function getDefaultShell(): string {
19
+ const platform = process.platform;
20
+
21
+ if (platform === "win32") {
22
+ return "cmd.exe";
23
+ } else if (platform === "darwin") {
24
+ return "/bin/zsh";
25
+ }
26
+
27
+ return "/bin/bash";
28
+ }
29
+
30
+ export function createExecTool(config: Config): Tool | null {
31
+ const execConfig = config.tools?.exec;
32
+
33
+ if (!execConfig?.enabled) {
34
+ return null;
35
+ }
36
+
37
+ const allowlist = execConfig.allowlist ?? [];
38
+ const denylist = execConfig.denylist ?? [
39
+ "rm -rf /",
40
+ "sudo",
41
+ "chmod 777",
42
+ "> /dev/",
43
+ "mkfs",
44
+ "del /f /s /q",
45
+ "format",
46
+ ];
47
+ const timeout = (execConfig.timeoutSeconds ?? 30) * 1000;
48
+ const workDir = execConfig.workDir?.replace(/^~/, process.env.USERPROFILE ?? process.env.HOME ?? "") ?? process.cwd();
49
+
50
+ const log = logger.child("exec");
51
+ const shell = getShellCommand();
52
+
53
+ const isAllowed = (command: string): { allowed: boolean; reason?: string } => {
54
+ if (allowlist.length > 0) {
55
+ const baseCmd = command.split(" ")[0] ?? "";
56
+ if (!allowlist.some((allowed) => baseCmd === allowed || command.startsWith(allowed))) {
57
+ return { allowed: false, reason: `Command not in allowlist: ${baseCmd}` };
58
+ }
59
+ }
60
+
61
+ for (const denied of denylist) {
62
+ if (command.includes(denied)) {
63
+ return { allowed: false, reason: `Command matches denylist pattern: ${denied}` };
64
+ }
65
+ }
66
+
67
+ return { allowed: true };
68
+ };
69
+
70
+ return {
71
+ name: "exec",
72
+ description: "Execute shell commands with allowlist/denylist restrictions. Works on Windows, macOS, and Linux.",
73
+ parameters: {
74
+ type: "object",
75
+ properties: {
76
+ command: {
77
+ type: "string",
78
+ description: "The shell command to execute",
79
+ },
80
+ timeout: {
81
+ type: "number",
82
+ description: "Timeout in seconds (optional, default from config)",
83
+ },
84
+ cwd: {
85
+ type: "string",
86
+ description: "Working directory (optional)",
87
+ },
88
+ },
89
+ required: ["command"],
90
+ },
91
+ execute: async (params: Record<string, unknown>) => {
92
+ const command = params.command as string;
93
+ const cmdTimeout = ((params.timeout as number) ?? timeout / 1000) * 1000;
94
+ const cwd = (params.cwd as string)?.replace(/^~/, process.env.USERPROFILE ?? process.env.HOME ?? "") ?? workDir;
95
+
96
+ const check = isAllowed(command);
97
+ if (!check.allowed) {
98
+ throw new Error(check.reason ?? "Command not allowed");
99
+ }
100
+
101
+ log.debug(`Executing on ${process.platform}: ${command}`);
102
+
103
+ try {
104
+ const shellCmd = getShellCommand();
105
+
106
+ const proc = Bun.spawn([shellCmd.cmd, ...shellCmd.args, command], {
107
+ cwd,
108
+ timeout: cmdTimeout,
109
+ maxBuffer: 10 * 1024 * 1024,
110
+ });
111
+
112
+ const stdout = await new Response(proc.stdout).text();
113
+ const stderr = await new Response(proc.stderr).text();
114
+ const exitCode = await proc.exited;
115
+
116
+ if (exitCode === 0) {
117
+ return {
118
+ stdout: stdout.slice(-10000),
119
+ stderr: stderr.slice(-5000),
120
+ exitCode,
121
+ platform: process.platform,
122
+ shell: getDefaultShell(),
123
+ };
124
+ } else {
125
+ throw new Error(`Command exited with code ${exitCode}: ${stderr.slice(0, 500)}`);
126
+ }
127
+ } catch (error) {
128
+ const err = error as Error;
129
+ if (err.message.includes("exit") || err.message.includes("ENOENT")) {
130
+ const shellInfo = process.platform === "win32"
131
+ ? "Windows requires cmd.exe. Make sure the shell is available."
132
+ : "Make sure sh or bash is available.";
133
+ throw new Error(`Failed to execute command: ${err.message}. ${shellInfo}`);
134
+ }
135
+ log.error(`Exec failed: ${err.message}`);
136
+ throw new Error(`Failed to execute command: ${err.message}`);
137
+ }
138
+ },
139
+ };
140
+ }
@@ -0,0 +1,364 @@
1
+ import type { Tool } from "../agent/native-tools.ts";
2
+ import type { Config } from "../config/loader.ts";
3
+ import { logger } from "../utils/logger.ts";
4
+ import { readdir, stat, mkdir, rm, rmdir, unlink, copyFile, rename } from "fs/promises";
5
+ import * as path from "path";
6
+
7
+ interface FSConfig {
8
+ allowedPaths: string[];
9
+ sandboxed: boolean;
10
+ }
11
+
12
+ function validatePath(targetPath: string, allowedPaths: string[]): void {
13
+ const resolved = path.resolve(targetPath);
14
+ const isAllowed = allowedPaths.some((allowed) => resolved.startsWith(path.resolve(allowed)));
15
+
16
+ if (!isAllowed) {
17
+ throw new Error(`Path ${targetPath} not in allowed paths`);
18
+ }
19
+ }
20
+
21
+ function getFSConfig(config: Config): FSConfig {
22
+ const toolsConfig = config.tools as Record<string, unknown> | undefined;
23
+ const fsConfig = toolsConfig?.fs as Record<string, unknown> | undefined;
24
+
25
+ return {
26
+ allowedPaths: (fsConfig?.allowedPaths as string[]) ?? [process.cwd()],
27
+ sandboxed: (fsConfig?.sandboxed as boolean) ?? true,
28
+ };
29
+ }
30
+
31
+ export function createFSReadTool(config: Config): Tool {
32
+ const log = logger.child("fs-read");
33
+ const fsConfig = getFSConfig(config);
34
+
35
+ return {
36
+ name: "fs_read",
37
+ description: "Read a file from the filesystem",
38
+ parameters: {
39
+ type: "object",
40
+ properties: {
41
+ path: {
42
+ type: "string",
43
+ description: "Path to the file to read",
44
+ },
45
+ encoding: {
46
+ type: "string",
47
+ description: "File encoding (default: utf-8)",
48
+ },
49
+ },
50
+ required: ["path"],
51
+ },
52
+ execute: async (params: Record<string, unknown>) => {
53
+ const filePath = params.path as string;
54
+ const encoding = (params.encoding as BufferEncoding) ?? "utf-8";
55
+
56
+ if (fsConfig.sandboxed) {
57
+ validatePath(filePath, fsConfig.allowedPaths);
58
+ }
59
+
60
+ log.debug(`Reading: ${filePath}`);
61
+
62
+ const content = await Bun.file(filePath).text();
63
+
64
+ return {
65
+ success: true,
66
+ path: filePath,
67
+ content,
68
+ size: content.length,
69
+ };
70
+ },
71
+ };
72
+ }
73
+
74
+ export function createFSWriteTool(config: Config): Tool {
75
+ const log = logger.child("fs-write");
76
+ const fsConfig = getFSConfig(config);
77
+
78
+ return {
79
+ name: "fs_write",
80
+ description: "Write content to a file",
81
+ parameters: {
82
+ type: "object",
83
+ properties: {
84
+ path: {
85
+ type: "string",
86
+ description: "Path to the file to write",
87
+ },
88
+ content: {
89
+ type: "string",
90
+ description: "Content to write",
91
+ },
92
+ encoding: {
93
+ type: "string",
94
+ description: "File encoding (default: utf-8)",
95
+ },
96
+ },
97
+ required: ["path", "content"],
98
+ },
99
+ execute: async (params: Record<string, unknown>) => {
100
+ const filePath = params.path as string;
101
+ const content = params.content as string;
102
+ const encoding = (params.encoding as BufferEncoding) ?? "utf-8";
103
+
104
+ if (fsConfig.sandboxed) {
105
+ validatePath(filePath, fsConfig.allowedPaths);
106
+ }
107
+
108
+ log.debug(`Writing: ${filePath}`);
109
+
110
+ await Bun.write(filePath, content);
111
+
112
+ return {
113
+ success: true,
114
+ path: filePath,
115
+ bytesWritten: content.length,
116
+ };
117
+ },
118
+ };
119
+ }
120
+
121
+ export function createFSListTool(config: Config): Tool {
122
+ const log = logger.child("fs-list");
123
+ const fsConfig = getFSConfig(config);
124
+
125
+ return {
126
+ name: "fs_list",
127
+ description: "List contents of a directory",
128
+ parameters: {
129
+ type: "object",
130
+ properties: {
131
+ path: {
132
+ type: "string",
133
+ description: "Path to the directory",
134
+ },
135
+ recursive: {
136
+ type: "boolean",
137
+ description: "List recursively (default: false)",
138
+ },
139
+ },
140
+ required: ["path"],
141
+ },
142
+ execute: async (params: Record<string, unknown>) => {
143
+ const dirPath = params.path as string;
144
+ const recursive = (params.recursive as boolean) ?? false;
145
+
146
+ if (fsConfig.sandboxed) {
147
+ validatePath(dirPath, fsConfig.allowedPaths);
148
+ }
149
+
150
+ log.debug(`Listing: ${dirPath}`);
151
+
152
+ const entries = await readdir(dirPath, { withFileTypes: true });
153
+
154
+ const results: Array<{
155
+ name: string;
156
+ path: string;
157
+ type: string;
158
+ size: number;
159
+ modified: string;
160
+ }> = [];
161
+
162
+ for (const entry of entries) {
163
+ const fullPath = path.join(dirPath, entry.name);
164
+ const stats = await stat(fullPath);
165
+
166
+ results.push({
167
+ name: entry.name,
168
+ path: fullPath,
169
+ type: entry.isDirectory() ? "directory" : "file",
170
+ size: stats.size,
171
+ modified: stats.mtime.toISOString(),
172
+ });
173
+ }
174
+
175
+ if (recursive) {
176
+ const subdirs = results.filter((r) => r.type === "directory");
177
+ for (const subdir of subdirs) {
178
+ const subParams = { path: subdir.path, recursive: true };
179
+ const subResult = await createFSListTool(config).execute(subParams);
180
+ const subFiles = (subResult as { entries: unknown[] }).entries;
181
+ results.push(...(subFiles as typeof results));
182
+ }
183
+ }
184
+
185
+ return {
186
+ success: true,
187
+ path: dirPath,
188
+ entries: results,
189
+ count: results.length,
190
+ };
191
+ },
192
+ };
193
+ }
194
+
195
+ export function createFSMkdirTool(config: Config): Tool {
196
+ const log = logger.child("fs-mkdir");
197
+ const fsConfig = getFSConfig(config);
198
+
199
+ return {
200
+ name: "fs_mkdir",
201
+ description: "Create a directory",
202
+ parameters: {
203
+ type: "object",
204
+ properties: {
205
+ path: {
206
+ type: "string",
207
+ description: "Path to create",
208
+ },
209
+ },
210
+ required: ["path"],
211
+ },
212
+ execute: async (params: Record<string, unknown>) => {
213
+ const dirPath = params.path as string;
214
+
215
+ if (fsConfig.sandboxed) {
216
+ validatePath(dirPath, fsConfig.allowedPaths);
217
+ }
218
+
219
+ log.debug(`Creating directory: ${dirPath}`);
220
+
221
+ await mkdir(dirPath, { recursive: true });
222
+
223
+ return { success: true, path: dirPath };
224
+ },
225
+ };
226
+ }
227
+
228
+ export function createFSDeleteTool(config: Config): Tool {
229
+ const log = logger.child("fs-delete");
230
+ const fsConfig = getFSConfig(config);
231
+
232
+ return {
233
+ name: "fs_delete",
234
+ description: "Delete a file or directory",
235
+ parameters: {
236
+ type: "object",
237
+ properties: {
238
+ path: {
239
+ type: "string",
240
+ description: "Path to delete",
241
+ },
242
+ recursive: {
243
+ type: "boolean",
244
+ description: "Delete recursively for directories",
245
+ },
246
+ },
247
+ required: ["path"],
248
+ },
249
+ execute: async (params: Record<string, unknown>) => {
250
+ const targetPath = params.path as string;
251
+ const recursive = (params.recursive as boolean) ?? false;
252
+
253
+ if (fsConfig.sandboxed) {
254
+ validatePath(targetPath, fsConfig.allowedPaths);
255
+ }
256
+
257
+ log.debug(`Deleting: ${targetPath}`);
258
+
259
+ const stats = await stat(targetPath);
260
+
261
+ if (stats.isDirectory()) {
262
+ if (recursive) {
263
+ await rm(targetPath, { recursive: true });
264
+ } else {
265
+ await rmdir(targetPath);
266
+ }
267
+ } else {
268
+ await unlink(targetPath);
269
+ }
270
+
271
+ return { success: true, path: targetPath };
272
+ },
273
+ };
274
+ }
275
+
276
+ export function createFSCopyTool(config: Config): Tool {
277
+ const log = logger.child("fs-copy");
278
+ const fsConfig = getFSConfig(config);
279
+
280
+ return {
281
+ name: "fs_copy",
282
+ description: "Copy a file",
283
+ parameters: {
284
+ type: "object",
285
+ properties: {
286
+ source: {
287
+ type: "string",
288
+ description: "Source file path",
289
+ },
290
+ destination: {
291
+ type: "string",
292
+ description: "Destination file path",
293
+ },
294
+ },
295
+ required: ["source", "destination"],
296
+ },
297
+ execute: async (params: Record<string, unknown>) => {
298
+ const source = params.source as string;
299
+ const destination = params.destination as string;
300
+
301
+ if (fsConfig.sandboxed) {
302
+ validatePath(source, fsConfig.allowedPaths);
303
+ validatePath(destination, fsConfig.allowedPaths);
304
+ }
305
+
306
+ log.debug(`Copying: ${source} -> ${destination}`);
307
+
308
+ await copyFile(source, destination);
309
+
310
+ return { success: true, source, destination };
311
+ },
312
+ };
313
+ }
314
+
315
+ export function createFSMoveTool(config: Config): Tool {
316
+ const log = logger.child("fs-move");
317
+ const fsConfig = getFSConfig(config);
318
+
319
+ return {
320
+ name: "fs_move",
321
+ description: "Move/rename a file",
322
+ parameters: {
323
+ type: "object",
324
+ properties: {
325
+ source: {
326
+ type: "string",
327
+ description: "Source file path",
328
+ },
329
+ destination: {
330
+ type: "string",
331
+ description: "Destination file path",
332
+ },
333
+ },
334
+ required: ["source", "destination"],
335
+ },
336
+ execute: async (params: Record<string, unknown>) => {
337
+ const source = params.source as string;
338
+ const destination = params.destination as string;
339
+
340
+ if (fsConfig.sandboxed) {
341
+ validatePath(source, fsConfig.allowedPaths);
342
+ validatePath(destination, fsConfig.allowedPaths);
343
+ }
344
+
345
+ log.debug(`Moving: ${source} -> ${destination}`);
346
+
347
+ await rename(source, destination);
348
+
349
+ return { success: true, source, destination };
350
+ },
351
+ };
352
+ }
353
+
354
+ export function createFSTools(config: Config): Tool[] {
355
+ return [
356
+ createFSReadTool(config),
357
+ createFSWriteTool(config),
358
+ createFSListTool(config),
359
+ createFSMkdirTool(config),
360
+ createFSDeleteTool(config),
361
+ createFSCopyTool(config),
362
+ createFSMoveTool(config),
363
+ ];
364
+ }
@@ -0,0 +1,12 @@
1
+ export * from "./project-management.ts";
2
+ export * from "./read.ts";
3
+ export * from "./exec.ts";
4
+ export * from "./web.ts";
5
+ export * from "./notify.ts";
6
+ export * from "./cron.ts";
7
+ export * from "./fs.ts";
8
+ export * from "./workspace.ts";
9
+ export * from "./project.ts";
10
+ export * from "./browser.ts";
11
+ export * from "./memory.ts";
12
+ export * from "./codebridge.ts";
@@ -0,0 +1,176 @@
1
+ import type { Tool, ToolResult } from "../agent/native-tools.ts";
2
+ import type { MemoryStore, Note } from "../memory/notes.ts";
3
+
4
+ export function memoryWriteTool(memory: MemoryStore): Tool {
5
+ return {
6
+ name: "memory_write",
7
+ description: "Store information in long-term memory. Use this to remember important facts, user preferences, or context for future conversations.",
8
+ parameters: {
9
+ type: "object",
10
+ properties: {
11
+ title: {
12
+ type: "string",
13
+ description: "A descriptive title for this memory entry",
14
+ },
15
+ content: {
16
+ type: "string",
17
+ description: "The content to store in memory",
18
+ },
19
+ },
20
+ required: ["title", "content"],
21
+ },
22
+ execute: async (params: Record<string, unknown>): Promise<ToolResult> => {
23
+ const title = params.title as string;
24
+ const content = params.content as string;
25
+
26
+ if (!title || !content) {
27
+ return { success: false, error: "Title and content are required" };
28
+ }
29
+
30
+ const note = memory.write(title, content);
31
+ return {
32
+ success: true,
33
+ result: {
34
+ title: note.title,
35
+ updatedAt: note.updatedAt.toISOString(),
36
+ },
37
+ };
38
+ },
39
+ };
40
+ }
41
+
42
+ export function memoryReadTool(memory: MemoryStore): Tool {
43
+ return {
44
+ name: "memory_read",
45
+ description: "Retrieve information from long-term memory by title.",
46
+ parameters: {
47
+ type: "object",
48
+ properties: {
49
+ title: {
50
+ type: "string",
51
+ description: "The title of the memory entry to retrieve",
52
+ },
53
+ },
54
+ required: ["title"],
55
+ },
56
+ execute: async (params: Record<string, unknown>): Promise<ToolResult> => {
57
+ const title = params.title as string;
58
+
59
+ if (!title) {
60
+ return { success: false, error: "Title is required" };
61
+ }
62
+
63
+ const note = memory.read(title);
64
+ if (!note) {
65
+ return { success: false, error: `Memory not found: ${title}` };
66
+ }
67
+
68
+ return {
69
+ success: true,
70
+ result: {
71
+ title: note.title,
72
+ content: note.content,
73
+ createdAt: note.createdAt.toISOString(),
74
+ updatedAt: note.updatedAt.toISOString(),
75
+ },
76
+ };
77
+ },
78
+ };
79
+ }
80
+
81
+ export function memoryListTool(memory: MemoryStore): Tool {
82
+ return {
83
+ name: "memory_list",
84
+ description: "List all memory entries.",
85
+ parameters: {
86
+ type: "object",
87
+ properties: {},
88
+ },
89
+ execute: async (_params: Record<string, unknown>): Promise<ToolResult> => {
90
+ const notes = memory.list();
91
+ return {
92
+ success: true,
93
+ result: {
94
+ count: notes.length,
95
+ entries: notes.map((n) => ({ title: n.title })),
96
+ },
97
+ };
98
+ },
99
+ };
100
+ }
101
+
102
+ export function memorySearchTool(memory: MemoryStore): Tool {
103
+ return {
104
+ name: "memory_search",
105
+ description: "Search memory entries by content.",
106
+ parameters: {
107
+ type: "object",
108
+ properties: {
109
+ query: {
110
+ type: "string",
111
+ description: "The search query",
112
+ },
113
+ },
114
+ required: ["query"],
115
+ },
116
+ execute: async (params: Record<string, unknown>): Promise<ToolResult> => {
117
+ const query = params.query as string;
118
+
119
+ if (!query) {
120
+ return { success: false, error: "Query is required" };
121
+ }
122
+
123
+ const results = memory.search(query);
124
+ return {
125
+ success: true,
126
+ result: {
127
+ query,
128
+ count: results.length,
129
+ results: results.map((n: Note) => ({
130
+ title: n.title,
131
+ snippet: n.content.slice(0, 200) + (n.content.length > 200 ? "..." : ""),
132
+ })),
133
+ },
134
+ };
135
+ },
136
+ };
137
+ }
138
+
139
+ export function memoryDeleteTool(memory: MemoryStore): Tool {
140
+ return {
141
+ name: "memory_delete",
142
+ description: "Delete a memory entry by title.",
143
+ parameters: {
144
+ type: "object",
145
+ properties: {
146
+ title: {
147
+ type: "string",
148
+ description: "The title of the memory entry to delete",
149
+ },
150
+ },
151
+ required: ["title"],
152
+ },
153
+ execute: async (params: Record<string, unknown>): Promise<ToolResult> => {
154
+ const title = params.title as string;
155
+
156
+ if (!title) {
157
+ return { success: false, error: "Title is required" };
158
+ }
159
+
160
+ const deleted = memory.delete(title);
161
+ return {
162
+ success: deleted,
163
+ result: deleted ? { message: `Deleted: ${title}` } : { message: `Not found: ${title}` },
164
+ error: deleted ? undefined : `Memory not found: ${title}`,
165
+ };
166
+ },
167
+ };
168
+ }
169
+
170
+ export function registerMemoryTools(registry: { register: (tool: Tool) => void }, memory: MemoryStore): void {
171
+ registry.register(memoryWriteTool(memory));
172
+ registry.register(memoryReadTool(memory));
173
+ registry.register(memoryListTool(memory));
174
+ registry.register(memorySearchTool(memory));
175
+ registry.register(memoryDeleteTool(memory));
176
+ }