@nexagent-cli/cli 0.2.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 (188) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/LICENSE +21 -0
  3. package/README.md +40 -0
  4. package/dist/agent/loop.d.ts +45 -0
  5. package/dist/agent/loop.d.ts.map +1 -0
  6. package/dist/agent/loop.js +270 -0
  7. package/dist/agent/loop.js.map +1 -0
  8. package/dist/agent/prompt.d.ts +3 -0
  9. package/dist/agent/prompt.d.ts.map +1 -0
  10. package/dist/agent/prompt.js +43 -0
  11. package/dist/agent/prompt.js.map +1 -0
  12. package/dist/commands/agent.d.ts +21 -0
  13. package/dist/commands/agent.d.ts.map +1 -0
  14. package/dist/commands/agent.js +111 -0
  15. package/dist/commands/agent.js.map +1 -0
  16. package/dist/commands/chat.d.ts +18 -0
  17. package/dist/commands/chat.d.ts.map +1 -0
  18. package/dist/commands/chat.js +115 -0
  19. package/dist/commands/chat.js.map +1 -0
  20. package/dist/commands/config.d.ts +10 -0
  21. package/dist/commands/config.d.ts.map +1 -0
  22. package/dist/commands/config.js +96 -0
  23. package/dist/commands/config.js.map +1 -0
  24. package/dist/commands/doctor.d.ts +8 -0
  25. package/dist/commands/doctor.d.ts.map +1 -0
  26. package/dist/commands/doctor.js +201 -0
  27. package/dist/commands/doctor.js.map +1 -0
  28. package/dist/commands/memory.d.ts +13 -0
  29. package/dist/commands/memory.d.ts.map +1 -0
  30. package/dist/commands/memory.js +97 -0
  31. package/dist/commands/memory.js.map +1 -0
  32. package/dist/commands/models.d.ts +2 -0
  33. package/dist/commands/models.d.ts.map +1 -0
  34. package/dist/commands/models.js +5 -0
  35. package/dist/commands/models.js.map +1 -0
  36. package/dist/commands/run.d.ts +13 -0
  37. package/dist/commands/run.d.ts.map +1 -0
  38. package/dist/commands/run.js +74 -0
  39. package/dist/commands/run.js.map +1 -0
  40. package/dist/commands/server.d.ts +8 -0
  41. package/dist/commands/server.d.ts.map +1 -0
  42. package/dist/commands/server.js +73 -0
  43. package/dist/commands/server.js.map +1 -0
  44. package/dist/commands/session.d.ts +11 -0
  45. package/dist/commands/session.d.ts.map +1 -0
  46. package/dist/commands/session.js +77 -0
  47. package/dist/commands/session.js.map +1 -0
  48. package/dist/commands/update.d.ts +17 -0
  49. package/dist/commands/update.d.ts.map +1 -0
  50. package/dist/commands/update.js +320 -0
  51. package/dist/commands/update.js.map +1 -0
  52. package/dist/config/loader.d.ts +4 -0
  53. package/dist/config/loader.d.ts.map +1 -0
  54. package/dist/config/loader.js +83 -0
  55. package/dist/config/loader.js.map +1 -0
  56. package/dist/config/wizard.d.ts +4 -0
  57. package/dist/config/wizard.d.ts.map +1 -0
  58. package/dist/config/wizard.js +131 -0
  59. package/dist/config/wizard.js.map +1 -0
  60. package/dist/db/database.d.ts +4 -0
  61. package/dist/db/database.d.ts.map +1 -0
  62. package/dist/db/database.js +130 -0
  63. package/dist/db/database.js.map +1 -0
  64. package/dist/db/session-store.d.ts +17 -0
  65. package/dist/db/session-store.d.ts.map +1 -0
  66. package/dist/db/session-store.js +117 -0
  67. package/dist/db/session-store.js.map +1 -0
  68. package/dist/index.d.ts +3 -0
  69. package/dist/index.d.ts.map +1 -0
  70. package/dist/index.js +207 -0
  71. package/dist/index.js.map +1 -0
  72. package/dist/llm/providers/anthropic.d.ts +21 -0
  73. package/dist/llm/providers/anthropic.d.ts.map +1 -0
  74. package/dist/llm/providers/anthropic.js +186 -0
  75. package/dist/llm/providers/anthropic.js.map +1 -0
  76. package/dist/llm/providers/google.d.ts +13 -0
  77. package/dist/llm/providers/google.d.ts.map +1 -0
  78. package/dist/llm/providers/google.js +83 -0
  79. package/dist/llm/providers/google.js.map +1 -0
  80. package/dist/llm/providers/ollama.d.ts +12 -0
  81. package/dist/llm/providers/ollama.d.ts.map +1 -0
  82. package/dist/llm/providers/ollama.js +110 -0
  83. package/dist/llm/providers/ollama.js.map +1 -0
  84. package/dist/llm/providers/openai.d.ts +15 -0
  85. package/dist/llm/providers/openai.d.ts.map +1 -0
  86. package/dist/llm/providers/openai.js +180 -0
  87. package/dist/llm/providers/openai.js.map +1 -0
  88. package/dist/llm/router.d.ts +20 -0
  89. package/dist/llm/router.d.ts.map +1 -0
  90. package/dist/llm/router.js +52 -0
  91. package/dist/llm/router.js.map +1 -0
  92. package/dist/memory/manager.d.ts +16 -0
  93. package/dist/memory/manager.d.ts.map +1 -0
  94. package/dist/memory/manager.js +114 -0
  95. package/dist/memory/manager.js.map +1 -0
  96. package/dist/safety/gate.d.ts +14 -0
  97. package/dist/safety/gate.d.ts.map +1 -0
  98. package/dist/safety/gate.js +102 -0
  99. package/dist/safety/gate.js.map +1 -0
  100. package/dist/subagents/orchestrator.d.ts +20 -0
  101. package/dist/subagents/orchestrator.d.ts.map +1 -0
  102. package/dist/subagents/orchestrator.js +151 -0
  103. package/dist/subagents/orchestrator.js.map +1 -0
  104. package/dist/tools/file-delete.d.ts +15 -0
  105. package/dist/tools/file-delete.d.ts.map +1 -0
  106. package/dist/tools/file-delete.js +94 -0
  107. package/dist/tools/file-delete.js.map +1 -0
  108. package/dist/tools/file-edit.d.ts +19 -0
  109. package/dist/tools/file-edit.d.ts.map +1 -0
  110. package/dist/tools/file-edit.js +182 -0
  111. package/dist/tools/file-edit.js.map +1 -0
  112. package/dist/tools/file-list.d.ts +13 -0
  113. package/dist/tools/file-list.d.ts.map +1 -0
  114. package/dist/tools/file-list.js +92 -0
  115. package/dist/tools/file-list.js.map +1 -0
  116. package/dist/tools/file-read.d.ts +13 -0
  117. package/dist/tools/file-read.d.ts.map +1 -0
  118. package/dist/tools/file-read.js +68 -0
  119. package/dist/tools/file-read.js.map +1 -0
  120. package/dist/tools/file-search.d.ts +14 -0
  121. package/dist/tools/file-search.d.ts.map +1 -0
  122. package/dist/tools/file-search.js +133 -0
  123. package/dist/tools/file-search.js.map +1 -0
  124. package/dist/tools/file-write.d.ts +14 -0
  125. package/dist/tools/file-write.d.ts.map +1 -0
  126. package/dist/tools/file-write.js +80 -0
  127. package/dist/tools/file-write.js.map +1 -0
  128. package/dist/tools/memory-read.d.ts +22 -0
  129. package/dist/tools/memory-read.d.ts.map +1 -0
  130. package/dist/tools/memory-read.js +114 -0
  131. package/dist/tools/memory-read.js.map +1 -0
  132. package/dist/tools/memory-write.d.ts +2 -0
  133. package/dist/tools/memory-write.d.ts.map +1 -0
  134. package/dist/tools/memory-write.js +5 -0
  135. package/dist/tools/memory-write.js.map +1 -0
  136. package/dist/tools/registry.d.ts +12 -0
  137. package/dist/tools/registry.d.ts.map +1 -0
  138. package/dist/tools/registry.js +66 -0
  139. package/dist/tools/registry.js.map +1 -0
  140. package/dist/tools/shell-exec.d.ts +14 -0
  141. package/dist/tools/shell-exec.d.ts.map +1 -0
  142. package/dist/tools/shell-exec.js +112 -0
  143. package/dist/tools/shell-exec.js.map +1 -0
  144. package/dist/tools/web-fetch.d.ts +12 -0
  145. package/dist/tools/web-fetch.d.ts.map +1 -0
  146. package/dist/tools/web-fetch.js +91 -0
  147. package/dist/tools/web-fetch.js.map +1 -0
  148. package/dist/tools/web-search.d.ts +12 -0
  149. package/dist/tools/web-search.d.ts.map +1 -0
  150. package/dist/tools/web-search.js +88 -0
  151. package/dist/tools/web-search.js.map +1 -0
  152. package/dist/ui/ChatApp.d.ts +22 -0
  153. package/dist/ui/ChatApp.d.ts.map +1 -0
  154. package/dist/ui/ChatApp.js +94 -0
  155. package/dist/ui/ChatApp.js.map +1 -0
  156. package/dist/ui/ConfirmDialog.d.ts +20 -0
  157. package/dist/ui/ConfirmDialog.d.ts.map +1 -0
  158. package/dist/ui/ConfirmDialog.js +23 -0
  159. package/dist/ui/ConfirmDialog.js.map +1 -0
  160. package/dist/ui/InputBar.d.ts +15 -0
  161. package/dist/ui/InputBar.d.ts.map +1 -0
  162. package/dist/ui/InputBar.js +49 -0
  163. package/dist/ui/InputBar.js.map +1 -0
  164. package/dist/ui/MessageList.d.ts +21 -0
  165. package/dist/ui/MessageList.d.ts.map +1 -0
  166. package/dist/ui/MessageList.js +29 -0
  167. package/dist/ui/MessageList.js.map +1 -0
  168. package/dist/ui/Spinner.d.ts +8 -0
  169. package/dist/ui/Spinner.d.ts.map +1 -0
  170. package/dist/ui/Spinner.js +16 -0
  171. package/dist/ui/Spinner.js.map +1 -0
  172. package/dist/ui/StatusBar.d.ts +32 -0
  173. package/dist/ui/StatusBar.d.ts.map +1 -0
  174. package/dist/ui/StatusBar.js +42 -0
  175. package/dist/ui/StatusBar.js.map +1 -0
  176. package/dist/ui/ToolPanel.d.ts +2 -0
  177. package/dist/ui/ToolPanel.d.ts.map +1 -0
  178. package/dist/ui/ToolPanel.js +5 -0
  179. package/dist/ui/ToolPanel.js.map +1 -0
  180. package/dist/utils/changelog.d.ts +19 -0
  181. package/dist/utils/changelog.d.ts.map +1 -0
  182. package/dist/utils/changelog.js +111 -0
  183. package/dist/utils/changelog.js.map +1 -0
  184. package/dist/utils/env.d.ts +9 -0
  185. package/dist/utils/env.d.ts.map +1 -0
  186. package/dist/utils/env.js +37 -0
  187. package/dist/utils/env.js.map +1 -0
  188. package/package.json +72 -0
@@ -0,0 +1,133 @@
1
+ // ============================================================
2
+ // Tool: file_search — Search file contents with regex or literal
3
+ // ============================================================
4
+ import { readFile, readdir, stat } from 'node:fs/promises';
5
+ import { join, resolve, relative } from 'node:path';
6
+ import { generateId } from '@nexagent-cli/shared';
7
+ export class FileSearchTool {
8
+ name = 'file_search';
9
+ version = '1.0.0';
10
+ description = 'Search for a pattern in file contents across the workspace. Returns matching file paths with line numbers and context.';
11
+ enabled = true;
12
+ riskLevel = 'low';
13
+ permissions = ['fs:read'];
14
+ parameters = {
15
+ type: 'object',
16
+ properties: {
17
+ pattern: {
18
+ type: 'string',
19
+ description: 'Search pattern (regex or literal string)',
20
+ },
21
+ regex: {
22
+ type: 'boolean',
23
+ description: 'Treat pattern as regex (default: false)',
24
+ },
25
+ case_sensitive: {
26
+ type: 'boolean',
27
+ description: 'Case-sensitive search (default: false)',
28
+ },
29
+ file_pattern: {
30
+ type: 'string',
31
+ description: 'Glob-style file extension filter (e.g. "*.ts")',
32
+ },
33
+ path: {
34
+ type: 'string',
35
+ description: 'Directory to search in (default: workspace root)',
36
+ },
37
+ max_results: {
38
+ type: 'number',
39
+ description: 'Maximum number of results to return (default: 50)',
40
+ },
41
+ context_lines: {
42
+ type: 'number',
43
+ description: 'Number of context lines around each match (default: 2)',
44
+ },
45
+ },
46
+ required: ['pattern'],
47
+ };
48
+ async execute(args, ctx) {
49
+ const { pattern, regex = false, case_sensitive = false, file_pattern, path: searchPath = '.', max_results = 50, context_lines = 2, } = args;
50
+ const flags = case_sensitive ? 'g' : 'gi';
51
+ const re = regex
52
+ ? new RegExp(pattern, flags)
53
+ : new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), flags);
54
+ const absDir = resolve(ctx.workspaceDir, searchPath);
55
+ const files = await this.collectFiles(absDir, file_pattern);
56
+ const results = [];
57
+ for (const file of files) {
58
+ if (results.length >= max_results)
59
+ break;
60
+ try {
61
+ const content = await readFile(file, 'utf-8');
62
+ const lines = content.split('\n');
63
+ for (let i = 0; i < lines.length; i++) {
64
+ re.lastIndex = 0;
65
+ if (re.test(lines[i])) {
66
+ const start = Math.max(0, i - context_lines);
67
+ const end = Math.min(lines.length - 1, i + context_lines);
68
+ const context = lines.slice(start, end + 1);
69
+ results.push({
70
+ file: relative(ctx.workspaceDir, file),
71
+ line: i + 1,
72
+ content: lines[i],
73
+ context,
74
+ });
75
+ if (results.length >= max_results)
76
+ break;
77
+ }
78
+ }
79
+ }
80
+ catch {
81
+ // skip unreadable files
82
+ }
83
+ }
84
+ const summary = results
85
+ .map(r => `${r.file}:${r.line}: ${r.content.trim()}`)
86
+ .join('\n');
87
+ return {
88
+ success: true,
89
+ output: `Found ${results.length} match(es) for "${pattern}"\n${summary}`,
90
+ data: { pattern, results, total: results.length },
91
+ executionId: generateId(),
92
+ durationMs: 0,
93
+ };
94
+ }
95
+ async collectFiles(dir, filePattern) {
96
+ const files = [];
97
+ const SKIP_DIRS = new Set(['node_modules', '.git', 'dist', '.nexagent', '__pycache__', 'venv']);
98
+ const walk = async (d) => {
99
+ let items;
100
+ try {
101
+ items = await readdir(d);
102
+ }
103
+ catch {
104
+ return;
105
+ }
106
+ for (const item of items) {
107
+ if (item.startsWith('.') && item !== '.')
108
+ continue;
109
+ const full = join(d, item);
110
+ try {
111
+ const s = await stat(full);
112
+ if (s.isDirectory()) {
113
+ if (!SKIP_DIRS.has(item))
114
+ await walk(full);
115
+ }
116
+ else {
117
+ if (!filePattern || this.matchPattern(item, filePattern)) {
118
+ files.push(full);
119
+ }
120
+ }
121
+ }
122
+ catch { /* skip */ }
123
+ }
124
+ };
125
+ await walk(dir);
126
+ return files;
127
+ }
128
+ matchPattern(filename, pattern) {
129
+ const regex = new RegExp('^' + pattern.replace(/\./g, '\\.').replace(/\*/g, '.*') + '$');
130
+ return regex.test(filename);
131
+ }
132
+ }
133
+ //# sourceMappingURL=file-search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-search.js","sourceRoot":"","sources":["../../../../src/tools/file-search.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { Tool, ToolContext, ToolResult, JSONSchemaObject } from '@nexagent-cli/shared';
2
+ export declare class FileWriteTool implements Tool {
3
+ name: string;
4
+ version: string;
5
+ description: string;
6
+ enabled: boolean;
7
+ riskLevel: "medium";
8
+ permissions: readonly ["fs:write"];
9
+ parameters: JSONSchemaObject;
10
+ execute(args: unknown, ctx: ToolContext): Promise<ToolResult>;
11
+ dryRun(args: unknown, _ctx: ToolContext): Promise<string>;
12
+ private resolveSafe;
13
+ }
14
+ //# sourceMappingURL=file-write.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-write.d.ts","sourceRoot":"","sources":["../../../../src/tools/file-write.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAG5F,qBAAa,aAAc,YAAW,IAAI;IACxC,IAAI,SAAuB;IAC3B,OAAO,SAAe;IACtB,WAAW,SAA0G;IACrH,OAAO,UAAY;IACnB,SAAS,EAAK,QAAQ,CAAU;IAChC,WAAW,wBAAyB;IAEpC,UAAU,EAAE,gBAAgB,CAkB1B;IAEI,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IAwC7D,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC;IAK/D,OAAO,CAAC,WAAW;CAQpB"}
@@ -0,0 +1,80 @@
1
+ // ============================================================
2
+ // Tool: file_write — Atomically write file content
3
+ // Uses temp-file → rename to prevent partial writes
4
+ // ============================================================
5
+ import { writeFile, mkdir, rename } from 'node:fs/promises';
6
+ import { resolve, relative, dirname } from 'node:path';
7
+ import { tmpdir } from 'node:os';
8
+ import { join } from 'node:path';
9
+ import { generateId } from '@nexagent-cli/shared';
10
+ export class FileWriteTool {
11
+ name = 'file_write';
12
+ version = '1.0.0';
13
+ description = 'Write content to a file atomically. Creates parent directories as needed. Overwrites existing files.';
14
+ enabled = true;
15
+ riskLevel = 'medium';
16
+ permissions = ['fs:write'];
17
+ parameters = {
18
+ type: 'object',
19
+ properties: {
20
+ path: {
21
+ type: 'string',
22
+ description: 'Path to write, relative to workspace directory',
23
+ },
24
+ content: {
25
+ type: 'string',
26
+ description: 'Full file content to write',
27
+ },
28
+ encoding: {
29
+ type: 'string',
30
+ description: 'Encoding: utf-8 or base64',
31
+ enum: ['utf-8', 'base64'],
32
+ },
33
+ },
34
+ required: ['path', 'content'],
35
+ };
36
+ async execute(args, ctx) {
37
+ const { path, content, encoding = 'utf-8' } = args;
38
+ const executionId = generateId();
39
+ const absPath = this.resolveSafe(path, ctx.workspaceDir);
40
+ if (ctx.dryRun) {
41
+ return {
42
+ success: true,
43
+ output: `[DRY RUN] Would write ${content.length} chars to ${path}`,
44
+ data: { path, bytes: content.length, dryRun: true },
45
+ executionId,
46
+ durationMs: 0,
47
+ };
48
+ }
49
+ // Create parent directories
50
+ await mkdir(dirname(absPath), { recursive: true });
51
+ // Atomic write: temp file → rename
52
+ const tmpPath = join(tmpdir(), `nexagent-${executionId}`);
53
+ const buf = encoding === 'base64'
54
+ ? Buffer.from(content, 'base64')
55
+ : content;
56
+ await writeFile(tmpPath, buf, { encoding: encoding === 'base64' ? undefined : 'utf-8' });
57
+ await rename(tmpPath, absPath);
58
+ return {
59
+ success: true,
60
+ output: `Wrote ${content.length} chars to ${path}`,
61
+ data: { path, bytes: content.length },
62
+ executionId,
63
+ durationMs: 0,
64
+ bytesWritten: content.length,
65
+ };
66
+ }
67
+ async dryRun(args, _ctx) {
68
+ const { path, content } = args;
69
+ return `Would write ${content.length} chars to "${path}"`;
70
+ }
71
+ resolveSafe(filePath, workspaceDir) {
72
+ const abs = resolve(workspaceDir, filePath);
73
+ const rel = relative(workspaceDir, abs);
74
+ if (rel.startsWith('..') || require('node:path').isAbsolute(rel)) {
75
+ throw new Error(`Path traversal denied: "${filePath}" is outside the workspace`);
76
+ }
77
+ return abs;
78
+ }
79
+ }
80
+ //# sourceMappingURL=file-write.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-write.js","sourceRoot":"","sources":["../../../../src/tools/file-write.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,mDAAmD;AACnD,oDAAoD;AACpD,+DAA+D;AAE/D,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAQ,WAAW,CAAC;AAEnC,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAElD,MAAM,OAAO,aAAa;IACxB,IAAI,GAAU,YAAY,CAAC;IAC3B,OAAO,GAAO,OAAO,CAAC;IACtB,WAAW,GAAG,sGAAsG,CAAC;IACrH,OAAO,GAAO,IAAI,CAAC;IACnB,SAAS,GAAK,QAAiB,CAAC;IAChC,WAAW,GAAG,CAAC,UAAU,CAAU,CAAC;IAEpC,UAAU,GAAqB;QAC7B,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,IAAI,EAAE;gBACJ,IAAI,EAAS,QAAQ;gBACrB,WAAW,EAAE,gDAAgD;aAC9D;YACD,OAAO,EAAE;gBACP,IAAI,EAAS,QAAQ;gBACrB,WAAW,EAAE,4BAA4B;aAC1C;YACD,QAAQ,EAAE;gBACR,IAAI,EAAS,QAAQ;gBACrB,WAAW,EAAE,2BAA2B;gBACxC,IAAI,EAAS,CAAC,OAAO,EAAE,QAAQ,CAAC;aACjC;SACF;QACD,QAAQ,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC;KAC9B,CAAC;IAEF,KAAK,CAAC,OAAO,CAAC,IAAa,EAAE,GAAgB;QAC3C,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,GAAG,OAAO,EAAE,GAAG,IAE7C,CAAC;QACF,MAAM,WAAW,GAAG,UAAU,EAAE,CAAC;QAEjC,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC,CAAC;QAEzD,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;YACf,OAAO;gBACL,OAAO,EAAM,IAAI;gBACjB,MAAM,EAAO,yBAAyB,OAAO,CAAC,MAAM,aAAa,IAAI,EAAE;gBACvE,IAAI,EAAS,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE;gBAC1D,WAAW;gBACX,UAAU,EAAG,CAAC;aACf,CAAC;QACJ,CAAC;QAED,4BAA4B;QAC5B,MAAM,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAEnD,mCAAmC;QACnC,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,YAAY,WAAW,EAAE,CAAC,CAAC;QAC1D,MAAM,GAAG,GAAO,QAAQ,KAAK,QAAQ;YACnC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC;YAChC,CAAC,CAAC,OAAO,CAAC;QAEZ,MAAM,SAAS,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE,QAAQ,EAAE,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;QACzF,MAAM,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAE/B,OAAO;YACL,OAAO,EAAQ,IAAI;YACnB,MAAM,EAAS,SAAS,OAAO,CAAC,MAAM,aAAa,IAAI,EAAE;YACzD,IAAI,EAAW,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE;YAC9C,WAAW;YACX,UAAU,EAAK,CAAC;YAChB,YAAY,EAAG,OAAO,CAAC,MAAM;SAC9B,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAa,EAAE,IAAiB;QAC3C,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,IAAyC,CAAC;QACpE,OAAO,eAAe,OAAO,CAAC,MAAM,cAAc,IAAI,GAAG,CAAC;IAC5D,CAAC;IAEO,WAAW,CAAC,QAAgB,EAAE,YAAoB;QACxD,MAAM,GAAG,GAAG,OAAO,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;QAC5C,MAAM,GAAG,GAAG,QAAQ,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;QACxC,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACjE,MAAM,IAAI,KAAK,CAAC,2BAA2B,QAAQ,4BAA4B,CAAC,CAAC;QACnF,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;CACF"}
@@ -0,0 +1,22 @@
1
+ import type { Tool, ToolContext, ToolResult, JSONSchemaObject } from '@nexagent-cli/shared';
2
+ export declare class MemoryReadTool implements Tool {
3
+ name: string;
4
+ version: string;
5
+ description: string;
6
+ enabled: boolean;
7
+ riskLevel: "low";
8
+ permissions: readonly ["memory:read"];
9
+ parameters: JSONSchemaObject;
10
+ execute(args: unknown, ctx: ToolContext): Promise<ToolResult>;
11
+ }
12
+ export declare class MemoryWriteTool implements Tool {
13
+ name: string;
14
+ version: string;
15
+ description: string;
16
+ enabled: boolean;
17
+ riskLevel: "medium";
18
+ permissions: readonly ["memory:write"];
19
+ parameters: JSONSchemaObject;
20
+ execute(args: unknown, ctx: ToolContext): Promise<ToolResult>;
21
+ }
22
+ //# sourceMappingURL=memory-read.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-read.d.ts","sourceRoot":"","sources":["../../../../src/tools/memory-read.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,gBAAgB,EAAqB,MAAM,sBAAsB,CAAC;AAG/G,qBAAa,cAAe,YAAW,IAAI;IACzC,IAAI,SAAwB;IAC5B,OAAO,SAAe;IACtB,WAAW,SAAmJ;IAC9J,OAAO,UAAY;IACnB,SAAS,EAAK,KAAK,CAAU;IAC7B,WAAW,2BAA4B;IAEvC,UAAU,EAAE,gBAAgB,CAkB1B;IAEI,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;CAmDpE;AAMD,qBAAa,eAAgB,YAAW,IAAI;IAC1C,IAAI,SAAyB;IAC7B,OAAO,SAAe;IACtB,WAAW,SAA2J;IACtK,OAAO,UAAY;IACnB,SAAS,EAAK,QAAQ,CAAU;IAChC,WAAW,4BAA6B;IAExC,UAAU,EAAE,gBAAgB,CAkB1B;IAEI,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;CAepE"}
@@ -0,0 +1,114 @@
1
+ // ============================================================
2
+ // Tool: memory_read — Read blocks from agent memory
3
+ // Wired directly into MemoryManager when available in context.
4
+ // ============================================================
5
+ import { generateId } from '@nexagent-cli/shared';
6
+ export class MemoryReadTool {
7
+ name = 'memory_read';
8
+ version = '1.1.0';
9
+ description = 'Read one or more memory blocks from the agent\'s persistent memory. Use to recall facts about the user, learned preferences, or past context.';
10
+ enabled = true;
11
+ riskLevel = 'low';
12
+ permissions = ['memory:read'];
13
+ parameters = {
14
+ type: 'object',
15
+ properties: {
16
+ block_type: {
17
+ type: 'string',
18
+ description: 'Filter by block type: persona, user_profile, task_context, learned_facts, skill_preferences, conversation_summary, custom',
19
+ enum: ['persona', 'user_profile', 'task_context', 'learned_facts', 'skill_preferences', 'conversation_summary', 'custom'],
20
+ },
21
+ query: {
22
+ type: 'string',
23
+ description: 'Semantic search query to find relevant memory blocks',
24
+ },
25
+ limit: {
26
+ type: 'number',
27
+ description: 'Max blocks to return (default: 5)',
28
+ },
29
+ },
30
+ required: [],
31
+ };
32
+ async execute(args, ctx) {
33
+ const { block_type, query, limit = 5 } = args;
34
+ // If MemoryManager is available via context, query it directly
35
+ if (ctx.memory) {
36
+ const opts = {
37
+ semanticQuery: query,
38
+ includeArchived: false,
39
+ limit,
40
+ pinFirst: true,
41
+ };
42
+ const blocks = await ctx.memory.read(opts);
43
+ // Filter by block_type if requested
44
+ const filtered = block_type
45
+ ? blocks.filter((b) => b.blockType === block_type)
46
+ : blocks;
47
+ const output = filtered.length === 0
48
+ ? `No memory blocks found (type: ${block_type ?? 'all'}, query: "${query ?? 'none'}").`
49
+ : `Found ${filtered.length} memory block(s):\n` + filtered.map((b, i) => `${i + 1}. [${b.blockType}] ${b.content.slice(0, 120)}${b.content.length > 120 ? '...' : ''}`).join('\n');
50
+ ctx.emit('memory:read', {
51
+ blockIds: filtered.map((b) => b.id),
52
+ tokenCount: filtered.reduce((s, b) => s + (b.tokenEstimate ?? 0), 0),
53
+ });
54
+ return {
55
+ success: true,
56
+ output,
57
+ data: { blocks: filtered.map((b) => ({ id: b.id, type: b.blockType, content: b.content })) },
58
+ executionId: generateId(),
59
+ durationMs: 0,
60
+ };
61
+ }
62
+ // Fallback when MemoryManager is not injected
63
+ ctx.emit('memory:read', { blockIds: [], tokenCount: 0 });
64
+ return {
65
+ success: true,
66
+ output: `Memory read requested (type: ${block_type ?? 'all'}, query: "${query ?? 'none'}", limit: ${limit}) — MemoryManager not available in this context.`,
67
+ data: { note: 'MemoryManager not injected. Memory is still assembled at context-build time.' },
68
+ executionId: generateId(),
69
+ durationMs: 0,
70
+ };
71
+ }
72
+ }
73
+ // ============================================================
74
+ // Tool: memory_write — Propose a memory block update
75
+ // ============================================================
76
+ export class MemoryWriteTool {
77
+ name = 'memory_write';
78
+ version = '1.0.0';
79
+ description = 'Propose an update to a memory block. The agent will record this for the user to review. Use to save important facts, user preferences, or task notes.';
80
+ enabled = true;
81
+ riskLevel = 'medium';
82
+ permissions = ['memory:write'];
83
+ parameters = {
84
+ type: 'object',
85
+ properties: {
86
+ block_type: {
87
+ type: 'string',
88
+ description: 'Type of memory block to write',
89
+ enum: ['persona', 'user_profile', 'task_context', 'learned_facts', 'skill_preferences', 'conversation_summary', 'custom'],
90
+ },
91
+ content: {
92
+ type: 'string',
93
+ description: 'The content to store in this memory block',
94
+ },
95
+ rationale: {
96
+ type: 'string',
97
+ description: 'Why you are saving this information',
98
+ },
99
+ },
100
+ required: ['block_type', 'content', 'rationale'],
101
+ };
102
+ async execute(args, ctx) {
103
+ const { block_type, content, rationale } = args;
104
+ ctx.emit('memory:write', { blockId: generateId(), blockType: block_type });
105
+ return {
106
+ success: true,
107
+ output: `Memory write proposal queued: [${block_type}] "${content.slice(0, 80)}..."`,
108
+ data: { block_type, content, rationale },
109
+ executionId: generateId(),
110
+ durationMs: 0,
111
+ };
112
+ }
113
+ }
114
+ //# sourceMappingURL=memory-read.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-read.js","sourceRoot":"","sources":["../../../../src/tools/memory-read.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export { MemoryWriteTool } from './memory-read.js';
2
+ //# sourceMappingURL=memory-write.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-write.d.ts","sourceRoot":"","sources":["../../../../src/tools/memory-write.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,5 @@
1
+ // ============================================================
2
+ // Tool: memory_write — re-exported from memory-read.ts for clean barrel
3
+ // ============================================================
4
+ export { MemoryWriteTool } from './memory-read.js';
5
+ //# sourceMappingURL=memory-write.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-write.js","sourceRoot":"","sources":["../../../../src/tools/memory-write.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,wEAAwE;AACxE,+DAA+D;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { Tool, LLMToolDefinition } from '@nexagent-cli/shared';
2
+ export declare class ToolRegistry {
3
+ private tools;
4
+ register(tool: Tool): void;
5
+ get(name: string): Tool | undefined;
6
+ list(): Tool[];
7
+ /** Convert registered tools to LLM function-call format */
8
+ toToolDefinitions(allowList: string[], blockList: string[]): LLMToolDefinition[];
9
+ }
10
+ /** Create a pre-loaded registry with all default tools */
11
+ export declare function createDefaultRegistry(): Promise<ToolRegistry>;
12
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../../src/tools/registry.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAEpE,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAA2B;IAExC,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAI1B,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS;IAInC,IAAI,IAAI,IAAI,EAAE;IAId,2DAA2D;IAC3D,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,iBAAiB,EAAE;CAiBjF;AAED,0DAA0D;AAC1D,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,YAAY,CAAC,CAyCnE"}
@@ -0,0 +1,66 @@
1
+ // ============================================================
2
+ // Tool Registry — central registration and lookup
3
+ // ============================================================
4
+ export class ToolRegistry {
5
+ tools = new Map();
6
+ register(tool) {
7
+ this.tools.set(tool.name, tool);
8
+ }
9
+ get(name) {
10
+ return this.tools.get(name);
11
+ }
12
+ list() {
13
+ return [...this.tools.values()];
14
+ }
15
+ /** Convert registered tools to LLM function-call format */
16
+ toToolDefinitions(allowList, blockList) {
17
+ return this.list()
18
+ .filter(t => {
19
+ if (!t.enabled)
20
+ return false;
21
+ if (blockList.includes(t.name))
22
+ return false;
23
+ if (allowList.length > 0 && !allowList.includes(t.name))
24
+ return false;
25
+ return true;
26
+ })
27
+ .map(t => ({
28
+ type: 'function',
29
+ function: {
30
+ name: t.name,
31
+ description: t.description,
32
+ parameters: t.parameters,
33
+ },
34
+ }));
35
+ }
36
+ }
37
+ /** Create a pre-loaded registry with all default tools */
38
+ export async function createDefaultRegistry() {
39
+ const registry = new ToolRegistry();
40
+ const [{ FileReadTool }, { FileWriteTool }, { FileEditTool }, { FileListTool }, { FileSearchTool }, { FileDeleteTool }, { ShellExecTool }, { WebFetchTool }, { WebSearchTool }, { MemoryReadTool }, { MemoryWriteTool },] = await Promise.all([
41
+ import('./file-read.js'),
42
+ import('./file-write.js'),
43
+ import('./file-edit.js'),
44
+ import('./file-list.js'),
45
+ import('./file-search.js'),
46
+ import('./file-delete.js'),
47
+ import('./shell-exec.js'),
48
+ import('./web-fetch.js'),
49
+ import('./web-search.js'),
50
+ import('./memory-read.js'),
51
+ import('./memory-write.js'),
52
+ ]);
53
+ registry.register(new FileReadTool());
54
+ registry.register(new FileWriteTool());
55
+ registry.register(new FileEditTool());
56
+ registry.register(new FileListTool());
57
+ registry.register(new FileSearchTool());
58
+ registry.register(new FileDeleteTool());
59
+ registry.register(new ShellExecTool());
60
+ registry.register(new WebFetchTool());
61
+ registry.register(new WebSearchTool());
62
+ registry.register(new MemoryReadTool());
63
+ registry.register(new MemoryWriteTool());
64
+ return registry;
65
+ }
66
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../../src/tools/registry.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,kDAAkD;AAClD,+DAA+D;AAI/D,MAAM,OAAO,YAAY;IACf,KAAK,GAAG,IAAI,GAAG,EAAgB,CAAC;IAExC,QAAQ,CAAC,IAAU;QACjB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAClC,CAAC;IAED,GAAG,CAAC,IAAY;QACd,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC;IAED,IAAI;QACF,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IAClC,CAAC;IAED,2DAA2D;IAC3D,iBAAiB,CAAC,SAAmB,EAAE,SAAmB;QACxD,OAAO,IAAI,CAAC,IAAI,EAAE;aACf,MAAM,CAAC,CAAC,CAAC,EAAE;YACV,IAAI,CAAC,CAAC,CAAC,OAAO;gBAAE,OAAO,KAAK,CAAC;YAC7B,IAAI,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;gBAAE,OAAO,KAAK,CAAC;YAC7C,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;gBAAE,OAAO,KAAK,CAAC;YACtE,OAAO,IAAI,CAAC;QACd,CAAC,CAAC;aACD,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACT,IAAI,EAAE,UAAmB;YACzB,QAAQ,EAAE;gBACR,IAAI,EAAS,CAAC,CAAC,IAAI;gBACnB,WAAW,EAAE,CAAC,CAAC,WAAW;gBAC1B,UAAU,EAAG,CAAC,CAAC,UAAgD;aAChE;SACF,CAAC,CAAC,CAAC;IACR,CAAC;CACF;AAED,0DAA0D;AAC1D,MAAM,CAAC,KAAK,UAAU,qBAAqB;IACzC,MAAM,QAAQ,GAAG,IAAI,YAAY,EAAE,CAAC;IACpC,MAAM,CACJ,EAAE,YAAY,EAAE,EAChB,EAAE,aAAa,EAAE,EACjB,EAAE,YAAY,EAAE,EAChB,EAAE,YAAY,EAAE,EAChB,EAAE,cAAc,EAAE,EAClB,EAAE,cAAc,EAAE,EAClB,EAAE,aAAa,EAAE,EACjB,EAAE,YAAY,EAAE,EAChB,EAAE,aAAa,EAAE,EACjB,EAAE,cAAc,EAAE,EAClB,EAAE,eAAe,EAAE,EACpB,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACpB,MAAM,CAAC,gBAAgB,CAAC;QACxB,MAAM,CAAC,iBAAiB,CAAC;QACzB,MAAM,CAAC,gBAAgB,CAAC;QACxB,MAAM,CAAC,gBAAgB,CAAC;QACxB,MAAM,CAAC,kBAAkB,CAAC;QAC1B,MAAM,CAAC,kBAAkB,CAAC;QAC1B,MAAM,CAAC,iBAAiB,CAAC;QACzB,MAAM,CAAC,gBAAgB,CAAC;QACxB,MAAM,CAAC,iBAAiB,CAAC;QACzB,MAAM,CAAC,kBAAkB,CAAC;QAC1B,MAAM,CAAC,mBAAmB,CAAC;KAC5B,CAAC,CAAC;IAEH,QAAQ,CAAC,QAAQ,CAAC,IAAI,YAAY,EAAE,CAAC,CAAC;IACtC,QAAQ,CAAC,QAAQ,CAAC,IAAI,aAAa,EAAE,CAAC,CAAC;IACvC,QAAQ,CAAC,QAAQ,CAAC,IAAI,YAAY,EAAE,CAAC,CAAC;IACtC,QAAQ,CAAC,QAAQ,CAAC,IAAI,YAAY,EAAE,CAAC,CAAC;IACtC,QAAQ,CAAC,QAAQ,CAAC,IAAI,cAAc,EAAE,CAAC,CAAC;IACxC,QAAQ,CAAC,QAAQ,CAAC,IAAI,cAAc,EAAE,CAAC,CAAC;IACxC,QAAQ,CAAC,QAAQ,CAAC,IAAI,aAAa,EAAE,CAAC,CAAC;IACvC,QAAQ,CAAC,QAAQ,CAAC,IAAI,YAAY,EAAE,CAAC,CAAC;IACtC,QAAQ,CAAC,QAAQ,CAAC,IAAI,aAAa,EAAE,CAAC,CAAC;IACvC,QAAQ,CAAC,QAAQ,CAAC,IAAI,cAAc,EAAE,CAAC,CAAC;IACxC,QAAQ,CAAC,QAAQ,CAAC,IAAI,eAAe,EAAE,CAAC,CAAC;IAEzC,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { Tool, ToolContext, ToolResult, JSONSchemaObject } from '@nexagent-cli/shared';
2
+ export declare class ShellExecTool implements Tool {
3
+ name: string;
4
+ version: string;
5
+ description: string;
6
+ enabled: boolean;
7
+ riskLevel: "high";
8
+ permissions: readonly ["shell:exec"];
9
+ parameters: JSONSchemaObject;
10
+ execute(args: unknown, ctx: ToolContext): Promise<ToolResult>;
11
+ dryRun(args: unknown, _ctx: ToolContext): Promise<string>;
12
+ private detectShell;
13
+ }
14
+ //# sourceMappingURL=shell-exec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell-exec.d.ts","sourceRoot":"","sources":["../../../../src/tools/shell-exec.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAG5F,qBAAa,aAAc,YAAW,IAAI;IACxC,IAAI,SAAuB;IAC3B,OAAO,SAAe;IACtB,WAAW,SAA4L;IACvM,OAAO,UAAY;IACnB,SAAS,EAAK,MAAM,CAAU;IAC9B,WAAW,0BAA2B;IAEtC,UAAU,EAAE,gBAAgB,CAqB1B;IAEI,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IAiF7D,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC;IAK/D,OAAO,CAAC,WAAW;CASpB"}
@@ -0,0 +1,112 @@
1
+ // ============================================================
2
+ // Tool: shell_exec — Execute shell commands in the workspace
3
+ // Windows-safe: auto-detects cmd/PowerShell/bash
4
+ // ============================================================
5
+ import { spawn } from 'node:child_process';
6
+ import { resolve } from 'node:path';
7
+ import { generateId, GLOBAL_SHELL_BLOCKLIST } from '@nexagent-cli/shared';
8
+ export class ShellExecTool {
9
+ name = 'shell_exec';
10
+ version = '1.0.0';
11
+ description = 'Execute a shell command in the workspace directory. Output is captured and returned. Long-running commands time out after timeout_ms. Dangerous commands are blocked by safety checks.';
12
+ enabled = true;
13
+ riskLevel = 'high';
14
+ permissions = ['shell:exec'];
15
+ parameters = {
16
+ type: 'object',
17
+ properties: {
18
+ command: {
19
+ type: 'string',
20
+ description: 'The shell command to execute',
21
+ },
22
+ cwd: {
23
+ type: 'string',
24
+ description: 'Working directory for the command (relative to workspace, default: workspace root)',
25
+ },
26
+ timeout_ms: {
27
+ type: 'number',
28
+ description: 'Timeout in milliseconds (default: 30000, max: 120000)',
29
+ },
30
+ env: {
31
+ type: 'object',
32
+ description: 'Additional environment variables as key-value pairs',
33
+ },
34
+ },
35
+ required: ['command'],
36
+ };
37
+ async execute(args, ctx) {
38
+ const { command, cwd: relCwd = '.', timeout_ms: timeout = 30_000, env: extraEnv = {}, } = args;
39
+ // Blocklist check (belt-and-suspenders on top of safety gate)
40
+ for (const blocked of GLOBAL_SHELL_BLOCKLIST) {
41
+ if (command.toLowerCase().includes(blocked.toLowerCase())) {
42
+ throw new Error(`Command blocked by global blocklist: "${blocked}"`);
43
+ }
44
+ }
45
+ if (ctx.dryRun) {
46
+ return {
47
+ success: true,
48
+ output: `[DRY RUN] Would execute: ${command}`,
49
+ data: { dryRun: true, command },
50
+ executionId: generateId(),
51
+ durationMs: 0,
52
+ };
53
+ }
54
+ const absCwd = resolve(ctx.workspaceDir, relCwd);
55
+ const executionId = generateId();
56
+ const start = Date.now();
57
+ const effectiveTout = Math.min(timeout, 120_000);
58
+ const { shell, shellFlag } = this.detectShell();
59
+ return new Promise((resolve_p, reject) => {
60
+ const proc = spawn(shell, [shellFlag, command], {
61
+ cwd: absCwd,
62
+ env: { ...process.env, ...extraEnv },
63
+ stdio: 'pipe',
64
+ });
65
+ let stdout = '';
66
+ let stderr = '';
67
+ proc.stdout?.on('data', (d) => { stdout += d.toString(); });
68
+ proc.stderr?.on('data', (d) => { stderr += d.toString(); });
69
+ const timer = setTimeout(() => {
70
+ proc.kill('SIGTERM');
71
+ reject(new Error(`Command timed out after ${effectiveTout}ms: ${command}`));
72
+ }, effectiveTout);
73
+ proc.on('close', (code) => {
74
+ clearTimeout(timer);
75
+ const durationMs = Date.now() - start;
76
+ const combined = [stdout, stderr].filter(Boolean).join('\n--- stderr ---\n');
77
+ const truncated = combined.length > 20_000
78
+ ? combined.slice(0, 20_000) + '\n[...output truncated at 20k chars...]'
79
+ : combined;
80
+ if (code !== 0 && !stderr) {
81
+ reject(new Error(`Command exited with code ${code}: ${truncated}`));
82
+ return;
83
+ }
84
+ resolve_p({
85
+ success: code === 0,
86
+ output: truncated || `(no output, exit code ${code})`,
87
+ data: { exitCode: code, stdout, stderr, command, durationMs },
88
+ executionId,
89
+ durationMs,
90
+ });
91
+ });
92
+ proc.on('error', (err) => {
93
+ clearTimeout(timer);
94
+ reject(new Error(`Failed to spawn process: ${err.message}`));
95
+ });
96
+ });
97
+ }
98
+ async dryRun(args, _ctx) {
99
+ const { command } = args;
100
+ return `Would execute shell command: "${command}"`;
101
+ }
102
+ detectShell() {
103
+ if (process.platform === 'win32') {
104
+ // Prefer PowerShell 7, fall back to cmd
105
+ return process.env['PSModulePath']
106
+ ? { shell: 'pwsh.exe', shellFlag: '-Command' }
107
+ : { shell: 'cmd.exe', shellFlag: '/c' };
108
+ }
109
+ return { shell: process.env['SHELL'] ?? '/bin/sh', shellFlag: '-c' };
110
+ }
111
+ }
112
+ //# sourceMappingURL=shell-exec.js.map