bernard-agent 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.
Files changed (112) hide show
  1. package/.env.example +21 -0
  2. package/LICENSE +21 -0
  3. package/README.md +629 -0
  4. package/dist/agent.d.ts +24 -0
  5. package/dist/agent.js +174 -0
  6. package/dist/agent.js.map +1 -0
  7. package/dist/config.d.ts +44 -0
  8. package/dist/config.js +267 -0
  9. package/dist/config.js.map +1 -0
  10. package/dist/context.d.ts +37 -0
  11. package/dist/context.js +245 -0
  12. package/dist/context.js.map +1 -0
  13. package/dist/cron/client.d.ts +4 -0
  14. package/dist/cron/client.js +113 -0
  15. package/dist/cron/client.js.map +1 -0
  16. package/dist/cron/daemon.d.ts +1 -0
  17. package/dist/cron/daemon.js +132 -0
  18. package/dist/cron/daemon.js.map +1 -0
  19. package/dist/cron/log-store.d.ts +51 -0
  20. package/dist/cron/log-store.js +135 -0
  21. package/dist/cron/log-store.js.map +1 -0
  22. package/dist/cron/notify.d.ts +7 -0
  23. package/dist/cron/notify.js +136 -0
  24. package/dist/cron/notify.js.map +1 -0
  25. package/dist/cron/runner.d.ts +6 -0
  26. package/dist/cron/runner.js +219 -0
  27. package/dist/cron/runner.js.map +1 -0
  28. package/dist/cron/scheduler.d.ts +16 -0
  29. package/dist/cron/scheduler.js +105 -0
  30. package/dist/cron/scheduler.js.map +1 -0
  31. package/dist/cron/store.d.ts +20 -0
  32. package/dist/cron/store.js +170 -0
  33. package/dist/cron/store.js.map +1 -0
  34. package/dist/cron/types.d.ts +21 -0
  35. package/dist/cron/types.js +3 -0
  36. package/dist/cron/types.js.map +1 -0
  37. package/dist/embeddings.d.ts +14 -0
  38. package/dist/embeddings.js +61 -0
  39. package/dist/embeddings.js.map +1 -0
  40. package/dist/history.d.ts +6 -0
  41. package/dist/history.js +71 -0
  42. package/dist/history.js.map +1 -0
  43. package/dist/index.d.ts +2 -0
  44. package/dist/index.js +231 -0
  45. package/dist/index.js.map +1 -0
  46. package/dist/logger.d.ts +1 -0
  47. package/dist/logger.js +24 -0
  48. package/dist/logger.js.map +1 -0
  49. package/dist/mcp.d.ts +43 -0
  50. package/dist/mcp.js +303 -0
  51. package/dist/mcp.js.map +1 -0
  52. package/dist/memory.d.ts +17 -0
  53. package/dist/memory.js +106 -0
  54. package/dist/memory.js.map +1 -0
  55. package/dist/output.d.ts +13 -0
  56. package/dist/output.js +151 -0
  57. package/dist/output.js.map +1 -0
  58. package/dist/providers/index.d.ts +2 -0
  59. package/dist/providers/index.js +19 -0
  60. package/dist/providers/index.js.map +1 -0
  61. package/dist/providers/types.d.ts +5 -0
  62. package/dist/providers/types.js +3 -0
  63. package/dist/providers/types.js.map +1 -0
  64. package/dist/rag-worker.d.ts +10 -0
  65. package/dist/rag-worker.js +84 -0
  66. package/dist/rag-worker.js.map +1 -0
  67. package/dist/rag.d.ts +53 -0
  68. package/dist/rag.js +242 -0
  69. package/dist/rag.js.map +1 -0
  70. package/dist/repl.d.ts +2 -0
  71. package/dist/repl.js +531 -0
  72. package/dist/repl.js.map +1 -0
  73. package/dist/setup.d.ts +1 -0
  74. package/dist/setup.js +104 -0
  75. package/dist/setup.js.map +1 -0
  76. package/dist/tools/cron-logs.d.ts +67 -0
  77. package/dist/tools/cron-logs.js +131 -0
  78. package/dist/tools/cron-logs.js.map +1 -0
  79. package/dist/tools/cron.d.ts +98 -0
  80. package/dist/tools/cron.js +248 -0
  81. package/dist/tools/cron.js.map +1 -0
  82. package/dist/tools/datetime.d.ts +4 -0
  83. package/dist/tools/datetime.js +25 -0
  84. package/dist/tools/datetime.js.map +1 -0
  85. package/dist/tools/index.d.ts +317 -0
  86. package/dist/tools/index.js +28 -0
  87. package/dist/tools/index.js.map +1 -0
  88. package/dist/tools/mcp-url.d.ts +16 -0
  89. package/dist/tools/mcp-url.js +27 -0
  90. package/dist/tools/mcp-url.js.map +1 -0
  91. package/dist/tools/mcp.d.ts +28 -0
  92. package/dist/tools/mcp.js +107 -0
  93. package/dist/tools/mcp.js.map +1 -0
  94. package/dist/tools/memory.d.ts +40 -0
  95. package/dist/tools/memory.js +99 -0
  96. package/dist/tools/memory.js.map +1 -0
  97. package/dist/tools/shell.d.ts +15 -0
  98. package/dist/tools/shell.js +60 -0
  99. package/dist/tools/shell.js.map +1 -0
  100. package/dist/tools/subagent.d.ts +21 -0
  101. package/dist/tools/subagent.js +81 -0
  102. package/dist/tools/subagent.js.map +1 -0
  103. package/dist/tools/time.d.ts +50 -0
  104. package/dist/tools/time.js +61 -0
  105. package/dist/tools/time.js.map +1 -0
  106. package/dist/tools/types.d.ts +8 -0
  107. package/dist/tools/types.js +3 -0
  108. package/dist/tools/types.js.map +1 -0
  109. package/dist/tools/web.d.ts +16 -0
  110. package/dist/tools/web.js +136 -0
  111. package/dist/tools/web.js.map +1 -0
  112. package/package.json +73 -0
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createMemoryTool = createMemoryTool;
4
+ exports.createScratchTool = createScratchTool;
5
+ const ai_1 = require("ai");
6
+ const zod_1 = require("zod");
7
+ function createMemoryTool(memoryStore) {
8
+ return (0, ai_1.tool)({
9
+ description: 'Persistent memory that survives across sessions. Use this to remember user preferences, project knowledge, or anything worth recalling later. Stored as files on disk at ~/.bernard/memory/.',
10
+ parameters: zod_1.z.object({
11
+ action: zod_1.z.enum(['list', 'read', 'write', 'delete']).describe('The action to perform'),
12
+ key: zod_1.z.string().optional().describe('The memory key (required for read/write/delete)'),
13
+ content: zod_1.z.string().optional().describe('The content to write (required for write)'),
14
+ }),
15
+ execute: async ({ action, key, content }) => {
16
+ switch (action) {
17
+ case 'list': {
18
+ const keys = memoryStore.listMemory();
19
+ if (keys.length === 0)
20
+ return 'No persistent memories stored.';
21
+ return `Stored memories:\n${keys.map(k => ` - ${k}`).join('\n')}`;
22
+ }
23
+ case 'read': {
24
+ if (!key)
25
+ return 'Error: key is required for read action.';
26
+ const value = memoryStore.readMemory(key);
27
+ if (value === null)
28
+ return `No memory found for key "${key}".`;
29
+ return value;
30
+ }
31
+ case 'write': {
32
+ if (!key)
33
+ return 'Error: key is required for write action.';
34
+ if (!content)
35
+ return 'Error: content is required for write action.';
36
+ memoryStore.writeMemory(key, content);
37
+ return `Memory "${key}" saved.`;
38
+ }
39
+ case 'delete': {
40
+ if (!key)
41
+ return 'Error: key is required for delete action.';
42
+ const deleted = memoryStore.deleteMemory(key);
43
+ if (!deleted)
44
+ return `No memory found for key "${key}".`;
45
+ return `Memory "${key}" deleted.`;
46
+ }
47
+ default:
48
+ return `Unknown action: ${action}`;
49
+ }
50
+ },
51
+ });
52
+ }
53
+ function createScratchTool(memoryStore) {
54
+ return (0, ai_1.tool)({
55
+ description: 'Session scratch notes for tracking complex task progress, intermediate findings, and working plans. These notes survive context compression but are discarded when the session ends. Use this to keep track of multi-step work within a single session.',
56
+ parameters: zod_1.z.object({
57
+ action: zod_1.z.enum(['list', 'read', 'write', 'delete']).describe('The action to perform'),
58
+ key: zod_1.z.string().optional().describe('The scratch note key (required for read/write/delete)'),
59
+ content: zod_1.z.string().optional().describe('The content to write (required for write)'),
60
+ }),
61
+ execute: async ({ action, key, content }) => {
62
+ switch (action) {
63
+ case 'list': {
64
+ const keys = memoryStore.listScratch();
65
+ if (keys.length === 0)
66
+ return 'No scratch notes in this session.';
67
+ return `Scratch notes:\n${keys.map(k => ` - ${k}`).join('\n')}`;
68
+ }
69
+ case 'read': {
70
+ if (!key)
71
+ return 'Error: key is required for read action.';
72
+ const value = memoryStore.readScratch(key);
73
+ if (value === null)
74
+ return `No scratch note found for key "${key}".`;
75
+ return value;
76
+ }
77
+ case 'write': {
78
+ if (!key)
79
+ return 'Error: key is required for write action.';
80
+ if (!content)
81
+ return 'Error: content is required for write action.';
82
+ memoryStore.writeScratch(key, content);
83
+ return `Scratch note "${key}" saved.`;
84
+ }
85
+ case 'delete': {
86
+ if (!key)
87
+ return 'Error: key is required for delete action.';
88
+ const deleted = memoryStore.deleteScratch(key);
89
+ if (!deleted)
90
+ return `No scratch note found for key "${key}".`;
91
+ return `Scratch note "${key}" deleted.`;
92
+ }
93
+ default:
94
+ return `Unknown action: ${action}`;
95
+ }
96
+ },
97
+ });
98
+ }
99
+ //# sourceMappingURL=memory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/tools/memory.ts"],"names":[],"mappings":";;AAIA,4CAuCC;AAED,8CAuCC;AApFD,2BAA0B;AAC1B,6BAAwB;AAGxB,SAAgB,gBAAgB,CAAC,WAAwB;IACvD,OAAO,IAAA,SAAI,EAAC;QACV,WAAW,EACT,8LAA8L;QAChM,UAAU,EAAE,OAAC,CAAC,MAAM,CAAC;YACnB,MAAM,EAAE,OAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,uBAAuB,CAAC;YACrF,GAAG,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,iDAAiD,CAAC;YACtF,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2CAA2C,CAAC;SACrF,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,EAAmB,EAAE;YAC3D,QAAQ,MAAM,EAAE,CAAC;gBACf,KAAK,MAAM,CAAC,CAAC,CAAC;oBACZ,MAAM,IAAI,GAAG,WAAW,CAAC,UAAU,EAAE,CAAC;oBACtC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;wBAAE,OAAO,gCAAgC,CAAC;oBAC/D,OAAO,qBAAqB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBACrE,CAAC;gBACD,KAAK,MAAM,CAAC,CAAC,CAAC;oBACZ,IAAI,CAAC,GAAG;wBAAE,OAAO,yCAAyC,CAAC;oBAC3D,MAAM,KAAK,GAAG,WAAW,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;oBAC1C,IAAI,KAAK,KAAK,IAAI;wBAAE,OAAO,4BAA4B,GAAG,IAAI,CAAC;oBAC/D,OAAO,KAAK,CAAC;gBACf,CAAC;gBACD,KAAK,OAAO,CAAC,CAAC,CAAC;oBACb,IAAI,CAAC,GAAG;wBAAE,OAAO,0CAA0C,CAAC;oBAC5D,IAAI,CAAC,OAAO;wBAAE,OAAO,8CAA8C,CAAC;oBACpE,WAAW,CAAC,WAAW,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;oBACtC,OAAO,WAAW,GAAG,UAAU,CAAC;gBAClC,CAAC;gBACD,KAAK,QAAQ,CAAC,CAAC,CAAC;oBACd,IAAI,CAAC,GAAG;wBAAE,OAAO,2CAA2C,CAAC;oBAC7D,MAAM,OAAO,GAAG,WAAW,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;oBAC9C,IAAI,CAAC,OAAO;wBAAE,OAAO,4BAA4B,GAAG,IAAI,CAAC;oBACzD,OAAO,WAAW,GAAG,YAAY,CAAC;gBACpC,CAAC;gBACD;oBACE,OAAO,mBAAmB,MAAM,EAAE,CAAC;YACvC,CAAC;QACH,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED,SAAgB,iBAAiB,CAAC,WAAwB;IACxD,OAAO,IAAA,SAAI,EAAC;QACV,WAAW,EACT,yPAAyP;QAC3P,UAAU,EAAE,OAAC,CAAC,MAAM,CAAC;YACnB,MAAM,EAAE,OAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,uBAAuB,CAAC;YACrF,GAAG,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,uDAAuD,CAAC;YAC5F,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2CAA2C,CAAC;SACrF,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,EAAmB,EAAE;YAC3D,QAAQ,MAAM,EAAE,CAAC;gBACf,KAAK,MAAM,CAAC,CAAC,CAAC;oBACZ,MAAM,IAAI,GAAG,WAAW,CAAC,WAAW,EAAE,CAAC;oBACvC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;wBAAE,OAAO,mCAAmC,CAAC;oBAClE,OAAO,mBAAmB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBACnE,CAAC;gBACD,KAAK,MAAM,CAAC,CAAC,CAAC;oBACZ,IAAI,CAAC,GAAG;wBAAE,OAAO,yCAAyC,CAAC;oBAC3D,MAAM,KAAK,GAAG,WAAW,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;oBAC3C,IAAI,KAAK,KAAK,IAAI;wBAAE,OAAO,kCAAkC,GAAG,IAAI,CAAC;oBACrE,OAAO,KAAK,CAAC;gBACf,CAAC;gBACD,KAAK,OAAO,CAAC,CAAC,CAAC;oBACb,IAAI,CAAC,GAAG;wBAAE,OAAO,0CAA0C,CAAC;oBAC5D,IAAI,CAAC,OAAO;wBAAE,OAAO,8CAA8C,CAAC;oBACpE,WAAW,CAAC,YAAY,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;oBACvC,OAAO,iBAAiB,GAAG,UAAU,CAAC;gBACxC,CAAC;gBACD,KAAK,QAAQ,CAAC,CAAC,CAAC;oBACd,IAAI,CAAC,GAAG;wBAAE,OAAO,2CAA2C,CAAC;oBAC7D,MAAM,OAAO,GAAG,WAAW,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;oBAC/C,IAAI,CAAC,OAAO;wBAAE,OAAO,kCAAkC,GAAG,IAAI,CAAC;oBAC/D,OAAO,iBAAiB,GAAG,YAAY,CAAC;gBAC1C,CAAC;gBACD;oBACE,OAAO,mBAAmB,MAAM,EAAE,CAAC;YACvC,CAAC;QACH,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { z } from 'zod';
2
+ import type { ToolOptions, ShellResult } from './types.js';
3
+ /** @internal */
4
+ export declare function isDangerous(command: string): boolean;
5
+ export declare function createShellTool(options: ToolOptions): import("ai").Tool<z.ZodObject<{
6
+ command: z.ZodString;
7
+ }, "strip", z.ZodTypeAny, {
8
+ command: string;
9
+ }, {
10
+ command: string;
11
+ }>, ShellResult> & {
12
+ execute: (args: {
13
+ command: string;
14
+ }, options: import("ai").ToolExecutionOptions) => PromiseLike<ShellResult>;
15
+ };
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isDangerous = isDangerous;
4
+ exports.createShellTool = createShellTool;
5
+ const ai_1 = require("ai");
6
+ const zod_1 = require("zod");
7
+ const node_child_process_1 = require("node:child_process");
8
+ const DANGEROUS_PATTERNS = [
9
+ /\brm\s+(-[^\s]*\s+)*-[^\s]*r/, // rm with -r flag
10
+ /\brm\s+(-[^\s]*\s+)*-[^\s]*f/, // rm with -f flag
11
+ /\bsudo\b/,
12
+ /\bmkfs\b/,
13
+ /\bdd\s+/,
14
+ /\b>\s*\/dev\/sd/,
15
+ /\bchmod\s+777\b/,
16
+ /\bchown\s+-R\b/,
17
+ /\breboot\b/,
18
+ /\bshutdown\b/,
19
+ /\bsystemctl\s+(stop|disable|mask)\b/,
20
+ /\bkill\s+-9\b/,
21
+ /\bpkill\b/,
22
+ /\bkillall\b/,
23
+ ];
24
+ /** @internal */
25
+ function isDangerous(command) {
26
+ return DANGEROUS_PATTERNS.some(pattern => pattern.test(command));
27
+ }
28
+ function createShellTool(options) {
29
+ return (0, ai_1.tool)({
30
+ description: 'Execute a shell command in the current working directory and return its output. Use this for file operations, git commands, running scripts, and any terminal task.',
31
+ parameters: zod_1.z.object({
32
+ command: zod_1.z.string().describe('The shell command to execute'),
33
+ }),
34
+ execute: async ({ command }) => {
35
+ if (isDangerous(command)) {
36
+ const confirmed = await options.confirmDangerous(command);
37
+ if (!confirmed) {
38
+ return { output: 'Command cancelled by user.', is_error: false };
39
+ }
40
+ }
41
+ try {
42
+ const stdout = (0, node_child_process_1.execSync)(command, {
43
+ encoding: 'utf-8',
44
+ timeout: options.shellTimeout,
45
+ maxBuffer: 1024 * 1024 * 10, // 10MB
46
+ stdio: ['pipe', 'pipe', 'pipe'],
47
+ });
48
+ return { output: stdout || '(no output)', is_error: false };
49
+ }
50
+ catch (err) {
51
+ const execError = err;
52
+ const stderr = execError.stderr || '';
53
+ const stdout = execError.stdout || '';
54
+ const output = [stdout, stderr].filter(Boolean).join('\n') || execError.message || 'Command failed';
55
+ return { output, is_error: true };
56
+ }
57
+ },
58
+ });
59
+ }
60
+ //# sourceMappingURL=shell.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell.js","sourceRoot":"","sources":["../../src/tools/shell.ts"],"names":[],"mappings":";;AAuBA,kCAEC;AAED,0CA+BC;AA1DD,2BAA0B;AAC1B,6BAAwB;AACxB,2DAA8C;AAG9C,MAAM,kBAAkB,GAAG;IACzB,8BAA8B,EAAI,kBAAkB;IACpD,8BAA8B,EAAI,kBAAkB;IACpD,UAAU;IACV,UAAU;IACV,SAAS;IACT,iBAAiB;IACjB,iBAAiB;IACjB,gBAAgB;IAChB,YAAY;IACZ,cAAc;IACd,qCAAqC;IACrC,eAAe;IACf,WAAW;IACX,aAAa;CACd,CAAC;AAEF,gBAAgB;AAChB,SAAgB,WAAW,CAAC,OAAe;IACzC,OAAO,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;AACnE,CAAC;AAED,SAAgB,eAAe,CAAC,OAAoB;IAClD,OAAO,IAAA,SAAI,EAAC;QACV,WAAW,EAAE,qKAAqK;QAClL,UAAU,EAAE,OAAC,CAAC,MAAM,CAAC;YACnB,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,8BAA8B,CAAC;SAC7D,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,EAAwB,EAAE;YACnD,IAAI,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC;gBACzB,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;gBAC1D,IAAI,CAAC,SAAS,EAAE,CAAC;oBACf,OAAO,EAAE,MAAM,EAAE,4BAA4B,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;gBACnE,CAAC;YACH,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,IAAA,6BAAQ,EAAC,OAAO,EAAE;oBAC/B,QAAQ,EAAE,OAAO;oBACjB,OAAO,EAAE,OAAO,CAAC,YAAY;oBAC7B,SAAS,EAAE,IAAI,GAAG,IAAI,GAAG,EAAE,EAAE,OAAO;oBACpC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;iBAChC,CAAC,CAAC;gBACH,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;YAC9D,CAAC;YAAC,OAAO,GAAY,EAAE,CAAC;gBACtB,MAAM,SAAS,GAAG,GAA6D,CAAC;gBAChF,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,IAAI,EAAE,CAAC;gBACtC,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,IAAI,EAAE,CAAC;gBACtC,MAAM,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,OAAO,IAAI,gBAAgB,CAAC;gBACpG,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;YACpC,CAAC;QACH,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { z } from 'zod';
2
+ import { type ToolOptions } from './index.js';
3
+ import type { BernardConfig } from '../config.js';
4
+ import type { MemoryStore } from '../memory.js';
5
+ /** Reset module state — for testing only. */
6
+ export declare function _resetSubAgentState(): void;
7
+ export declare function createSubAgentTool(config: BernardConfig, options: ToolOptions, memoryStore: MemoryStore, mcpTools?: Record<string, any>): import("ai").Tool<z.ZodObject<{
8
+ task: z.ZodString;
9
+ context: z.ZodOptional<z.ZodString>;
10
+ }, "strip", z.ZodTypeAny, {
11
+ task: string;
12
+ context?: string | undefined;
13
+ }, {
14
+ task: string;
15
+ context?: string | undefined;
16
+ }>, string> & {
17
+ execute: (args: {
18
+ task: string;
19
+ context?: string | undefined;
20
+ }, options: import("ai").ToolExecutionOptions) => PromiseLike<string>;
21
+ };
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports._resetSubAgentState = _resetSubAgentState;
4
+ exports.createSubAgentTool = createSubAgentTool;
5
+ const ai_1 = require("ai");
6
+ const zod_1 = require("zod");
7
+ const index_js_1 = require("../providers/index.js");
8
+ const index_js_2 = require("./index.js");
9
+ const output_js_1 = require("../output.js");
10
+ const MAX_CONCURRENT_AGENTS = 4;
11
+ let activeAgentCount = 0;
12
+ let nextAgentId = 1;
13
+ const SUB_AGENT_SYSTEM_PROMPT = `You are a focused sub-agent of Bernard, an AI CLI assistant. You have been delegated a specific task. Complete it efficiently and report your findings concisely.
14
+
15
+ Guidelines:
16
+ - Focus only on the assigned task.
17
+ - Use tools as needed to accomplish the task.
18
+ - Be thorough but concise in your final response.
19
+ - If a command fails, try alternatives before giving up.
20
+ - Your response will be returned to the main agent for synthesis.`;
21
+ /** Reset module state — for testing only. */
22
+ function _resetSubAgentState() {
23
+ activeAgentCount = 0;
24
+ nextAgentId = 1;
25
+ }
26
+ function createSubAgentTool(config, options, memoryStore, mcpTools) {
27
+ return (0, ai_1.tool)({
28
+ description: 'Delegate a task to an independent sub-agent that runs in parallel. Each sub-agent gets its own tool set and works independently. Call this tool multiple times in a single response to run tasks in parallel.',
29
+ parameters: zod_1.z.object({
30
+ task: zod_1.z.string().describe('The task for the sub-agent to complete'),
31
+ context: zod_1.z.string().optional().describe('Optional additional context to help the sub-agent'),
32
+ }),
33
+ execute: async ({ task, context }, execOptions) => {
34
+ if (activeAgentCount >= MAX_CONCURRENT_AGENTS) {
35
+ return `Error: Maximum concurrent sub-agents (${MAX_CONCURRENT_AGENTS}) reached. Wait for existing sub-agents to finish.`;
36
+ }
37
+ const id = nextAgentId++;
38
+ activeAgentCount++;
39
+ const prefix = `sub:${id}`;
40
+ (0, output_js_1.printSubAgentStart)(id, task);
41
+ try {
42
+ const baseTools = (0, index_js_2.createTools)(options, memoryStore, mcpTools);
43
+ let userMessage = `Task: ${task}`;
44
+ if (context) {
45
+ userMessage += `\n\nContext: ${context}`;
46
+ }
47
+ const result = await (0, ai_1.generateText)({
48
+ model: (0, index_js_1.getModel)(config.provider, config.model),
49
+ tools: baseTools,
50
+ maxSteps: 10,
51
+ maxTokens: config.maxTokens,
52
+ system: SUB_AGENT_SYSTEM_PROMPT,
53
+ messages: [{ role: 'user', content: userMessage }],
54
+ abortSignal: execOptions.abortSignal,
55
+ onStepFinish: ({ text, toolCalls, toolResults }) => {
56
+ for (const tc of toolCalls) {
57
+ (0, output_js_1.printToolCall)(tc.toolName, tc.args, prefix);
58
+ }
59
+ for (const tr of toolResults) {
60
+ (0, output_js_1.printToolResult)(tr.toolName, tr.result, prefix);
61
+ }
62
+ if (text) {
63
+ (0, output_js_1.printAssistantText)(text, prefix);
64
+ }
65
+ },
66
+ });
67
+ (0, output_js_1.printSubAgentEnd)(id);
68
+ return result.text;
69
+ }
70
+ catch (err) {
71
+ (0, output_js_1.printSubAgentEnd)(id);
72
+ const message = err instanceof Error ? err.message : String(err);
73
+ return `Sub-agent error: ${message}`;
74
+ }
75
+ finally {
76
+ activeAgentCount--;
77
+ }
78
+ },
79
+ });
80
+ }
81
+ //# sourceMappingURL=subagent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subagent.js","sourceRoot":"","sources":["../../src/tools/subagent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ import { z } from 'zod';
2
+ export declare function militaryToMinutes(time: number): number;
3
+ export declare function calcRangeMinutes(start: number, end: number): number;
4
+ export declare function formatHours(totalMinutes: number): string;
5
+ export declare function createTimeTools(): {
6
+ time_range: import("ai").Tool<z.ZodObject<{
7
+ start: z.ZodNumber;
8
+ end: z.ZodNumber;
9
+ }, "strip", z.ZodTypeAny, {
10
+ start: number;
11
+ end: number;
12
+ }, {
13
+ start: number;
14
+ end: number;
15
+ }>, string> & {
16
+ execute: (args: {
17
+ start: number;
18
+ end: number;
19
+ }, options: import("ai").ToolExecutionOptions) => PromiseLike<string>;
20
+ };
21
+ time_range_total: import("ai").Tool<z.ZodObject<{
22
+ ranges: z.ZodArray<z.ZodObject<{
23
+ start: z.ZodNumber;
24
+ end: z.ZodNumber;
25
+ }, "strip", z.ZodTypeAny, {
26
+ start: number;
27
+ end: number;
28
+ }, {
29
+ start: number;
30
+ end: number;
31
+ }>, "many">;
32
+ }, "strip", z.ZodTypeAny, {
33
+ ranges: {
34
+ start: number;
35
+ end: number;
36
+ }[];
37
+ }, {
38
+ ranges: {
39
+ start: number;
40
+ end: number;
41
+ }[];
42
+ }>, string> & {
43
+ execute: (args: {
44
+ ranges: {
45
+ start: number;
46
+ end: number;
47
+ }[];
48
+ }, options: import("ai").ToolExecutionOptions) => PromiseLike<string>;
49
+ };
50
+ };
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.militaryToMinutes = militaryToMinutes;
4
+ exports.calcRangeMinutes = calcRangeMinutes;
5
+ exports.formatHours = formatHours;
6
+ exports.createTimeTools = createTimeTools;
7
+ const ai_1 = require("ai");
8
+ const zod_1 = require("zod");
9
+ function militaryToMinutes(time) {
10
+ const hours = Math.floor(time / 100);
11
+ const minutes = time % 100;
12
+ return hours * 60 + minutes;
13
+ }
14
+ function calcRangeMinutes(start, end) {
15
+ const startMin = militaryToMinutes(start);
16
+ const endMin = militaryToMinutes(end);
17
+ if (endMin >= startMin)
18
+ return endMin - startMin;
19
+ return (24 * 60 - startMin) + endMin;
20
+ }
21
+ function formatHours(totalMinutes) {
22
+ if (totalMinutes === 0)
23
+ return '0 minutes';
24
+ const hours = Math.floor(totalMinutes / 60);
25
+ const minutes = totalMinutes % 60;
26
+ const parts = [];
27
+ if (hours > 0)
28
+ parts.push(`${hours} hour${hours === 1 ? '' : 's'}`);
29
+ if (minutes > 0)
30
+ parts.push(`${minutes} minute${minutes === 1 ? '' : 's'}`);
31
+ return parts.join(' ');
32
+ }
33
+ function createTimeTools() {
34
+ return {
35
+ time_range: (0, ai_1.tool)({
36
+ description: 'Calculate the duration between two military/24-hour times. Handles next-day wrap (e.g. 2300 to 0100 = 2 hours).',
37
+ parameters: zod_1.z.object({
38
+ start: zod_1.z.number().describe('Start time in military format (e.g. 800 for 8:00 AM, 1530 for 3:30 PM)'),
39
+ end: zod_1.z.number().describe('End time in military format'),
40
+ }),
41
+ execute: async ({ start, end }) => {
42
+ const minutes = calcRangeMinutes(start, end);
43
+ return formatHours(minutes);
44
+ },
45
+ }),
46
+ time_range_total: (0, ai_1.tool)({
47
+ description: 'Calculate the total duration across multiple military time ranges.',
48
+ parameters: zod_1.z.object({
49
+ ranges: zod_1.z.array(zod_1.z.object({
50
+ start: zod_1.z.number().describe('Start time in military format'),
51
+ end: zod_1.z.number().describe('End time in military format'),
52
+ })).describe('Array of time ranges'),
53
+ }),
54
+ execute: async ({ ranges }) => {
55
+ const total = ranges.reduce((sum, { start, end }) => sum + calcRangeMinutes(start, end), 0);
56
+ return formatHours(total);
57
+ },
58
+ }),
59
+ };
60
+ }
61
+ //# sourceMappingURL=time.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"time.js","sourceRoot":"","sources":["../../src/tools/time.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export interface ToolOptions {
2
+ shellTimeout: number;
3
+ confirmDangerous: (command: string) => Promise<boolean>;
4
+ }
5
+ export interface ShellResult {
6
+ output: string;
7
+ is_error: boolean;
8
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/tools/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,16 @@
1
+ import { z } from 'zod';
2
+ export declare function createWebReadTool(): import("ai").Tool<z.ZodObject<{
3
+ url: z.ZodString;
4
+ selector: z.ZodOptional<z.ZodString>;
5
+ }, "strip", z.ZodTypeAny, {
6
+ url: string;
7
+ selector?: string | undefined;
8
+ }, {
9
+ url: string;
10
+ selector?: string | undefined;
11
+ }>, string> & {
12
+ execute: (args: {
13
+ url: string;
14
+ selector?: string | undefined;
15
+ }, options: import("ai").ToolExecutionOptions) => PromiseLike<string>;
16
+ };
@@ -0,0 +1,136 @@
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
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.createWebReadTool = createWebReadTool;
40
+ const ai_1 = require("ai");
41
+ const zod_1 = require("zod");
42
+ const cheerio = __importStar(require("cheerio"));
43
+ const turndown_1 = __importDefault(require("turndown"));
44
+ const STRIP_SELECTORS = [
45
+ 'script', 'style', 'nav', 'footer', 'header', 'iframe',
46
+ 'noscript', 'svg', '[role="navigation"]', '[role="banner"]',
47
+ '[aria-hidden="true"]',
48
+ ];
49
+ const MAX_HTML_BYTES = 1_000_000; // 1MB
50
+ const MAX_OUTPUT_CHARS = 20_000;
51
+ const FETCH_TIMEOUT_MS = 15_000;
52
+ const USER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36';
53
+ function createWebReadTool() {
54
+ return (0, ai_1.tool)({
55
+ description: 'Fetch a web page by URL and return its content as markdown. Useful for reading documentation, articles, Stack Overflow answers, GitHub pages, or any URL.',
56
+ parameters: zod_1.z.object({
57
+ url: zod_1.z.string().describe('The URL to fetch (must start with http:// or https://)'),
58
+ selector: zod_1.z.string().optional().describe('Optional CSS selector to extract specific content (e.g., "article", "main", ".post-body")'),
59
+ }),
60
+ execute: async ({ url, selector }) => {
61
+ // Validate URL
62
+ if (!url.startsWith('http://') && !url.startsWith('https://')) {
63
+ return 'Error: URL must start with http:// or https://';
64
+ }
65
+ let response;
66
+ try {
67
+ response = await fetch(url, {
68
+ signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
69
+ headers: {
70
+ 'User-Agent': USER_AGENT,
71
+ 'Accept': 'text/html',
72
+ },
73
+ });
74
+ }
75
+ catch (err) {
76
+ const message = err instanceof Error ? err.message : String(err);
77
+ return `Error: Failed to fetch URL — ${message}`;
78
+ }
79
+ if (!response.ok) {
80
+ return `Error: HTTP ${response.status} ${response.statusText}`;
81
+ }
82
+ const contentType = response.headers.get('content-type') || '';
83
+ if (!contentType.includes('text/html') && !contentType.includes('text/plain') && !contentType.includes('application/xhtml')) {
84
+ return `Error: Non-HTML content type (${contentType}). This tool only reads web pages.`;
85
+ }
86
+ let html;
87
+ try {
88
+ const buffer = await response.arrayBuffer();
89
+ if (buffer.byteLength > MAX_HTML_BYTES) {
90
+ html = new TextDecoder().decode(buffer.slice(0, MAX_HTML_BYTES));
91
+ }
92
+ else {
93
+ html = new TextDecoder().decode(buffer);
94
+ }
95
+ }
96
+ catch (err) {
97
+ const message = err instanceof Error ? err.message : String(err);
98
+ return `Error: Failed to read response body — ${message}`;
99
+ }
100
+ const $ = cheerio.load(html);
101
+ // Strip junk elements
102
+ for (const sel of STRIP_SELECTORS) {
103
+ $(sel).remove();
104
+ }
105
+ // Get page title
106
+ const title = $('title').text().trim();
107
+ // Select content
108
+ let content;
109
+ if (selector) {
110
+ const selected = $(selector);
111
+ content = selected.length > 0 ? selected.html() || '' : $.root().html() || '';
112
+ }
113
+ else {
114
+ // Try common content containers, fall back to body
115
+ const body = $('body');
116
+ content = body.length > 0 ? body.html() || '' : $.root().html() || '';
117
+ }
118
+ // Convert to markdown
119
+ const turndown = new turndown_1.default({
120
+ headingStyle: 'atx',
121
+ codeBlockStyle: 'fenced',
122
+ });
123
+ let markdown = turndown.turndown(content);
124
+ // Prepend title
125
+ if (title) {
126
+ markdown = `# ${title}\n\n${markdown}`;
127
+ }
128
+ // Truncate
129
+ if (markdown.length > MAX_OUTPUT_CHARS) {
130
+ markdown = markdown.slice(0, MAX_OUTPUT_CHARS) + '\n\n… (truncated)';
131
+ }
132
+ return markdown;
133
+ },
134
+ });
135
+ }
136
+ //# sourceMappingURL=web.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/tools/web.ts"],"names":[],"mappings":"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"}