@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,94 @@
1
+ // ============================================================
2
+ // Tool: file_delete — Delete a file (CRITICAL risk, requires confirm)
3
+ // ============================================================
4
+ import { unlink, rmdir, readdir, stat } from 'node:fs/promises';
5
+ import { resolve, relative } from 'node:path';
6
+ import { generateId } from '@nexagent-cli/shared';
7
+ export class FileDeleteTool {
8
+ name = 'file_delete';
9
+ version = '1.0.0';
10
+ description = 'Delete a file from the workspace. This operation requires explicit user confirmation and CANNOT be undone automatically. Use with extreme care.';
11
+ enabled = true;
12
+ riskLevel = 'critical';
13
+ permissions = ['fs:delete'];
14
+ parameters = {
15
+ type: 'object',
16
+ properties: {
17
+ path: {
18
+ type: 'string',
19
+ description: 'Path of the file to delete, relative to workspace directory',
20
+ },
21
+ recursive: {
22
+ type: 'boolean',
23
+ description: 'Delete a directory and all its contents (default: false, requires explicit opt-in)',
24
+ },
25
+ },
26
+ required: ['path'],
27
+ };
28
+ async execute(args, ctx) {
29
+ const { path, recursive = false } = args;
30
+ const executionId = generateId();
31
+ const absPath = this.resolveSafe(path, ctx.workspaceDir);
32
+ if (ctx.dryRun) {
33
+ return {
34
+ success: true,
35
+ output: `[DRY RUN] Would delete ${path}${recursive ? ' (recursive)' : ''}`,
36
+ data: { dryRun: true, path },
37
+ executionId,
38
+ durationMs: 0,
39
+ };
40
+ }
41
+ try {
42
+ const s = await stat(absPath);
43
+ if (s.isDirectory()) {
44
+ if (!recursive) {
45
+ throw new Error(`${path} is a directory. Pass recursive=true to delete directories.`);
46
+ }
47
+ await this.rmRecursive(absPath);
48
+ }
49
+ else {
50
+ await unlink(absPath);
51
+ }
52
+ return {
53
+ success: true,
54
+ output: `Deleted ${path}`,
55
+ data: { path, wasDirectory: s.isDirectory() },
56
+ executionId,
57
+ durationMs: 0,
58
+ };
59
+ }
60
+ catch (e) {
61
+ const msg = e instanceof Error ? e.message : String(e);
62
+ throw new Error(`Failed to delete "${path}": ${msg}`);
63
+ }
64
+ }
65
+ async dryRun(args, _ctx) {
66
+ const { path } = args;
67
+ return `Would permanently delete "${path}" — this CANNOT be undone`;
68
+ }
69
+ async rmRecursive(dir) {
70
+ const items = await readdir(dir);
71
+ for (const item of items) {
72
+ const { join } = await import('node:path');
73
+ const full = join(dir, item);
74
+ const s = await stat(full);
75
+ if (s.isDirectory()) {
76
+ await this.rmRecursive(full);
77
+ await rmdir(full);
78
+ }
79
+ else {
80
+ await unlink(full);
81
+ }
82
+ }
83
+ await rmdir(dir);
84
+ }
85
+ resolveSafe(filePath, workspaceDir) {
86
+ const abs = resolve(workspaceDir, filePath);
87
+ const rel = relative(workspaceDir, abs);
88
+ if (rel.startsWith('..') || require('node:path').isAbsolute(rel)) {
89
+ throw new Error(`Path traversal denied: "${filePath}" is outside the workspace`);
90
+ }
91
+ return abs;
92
+ }
93
+ }
94
+ //# sourceMappingURL=file-delete.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-delete.js","sourceRoot":"","sources":["../../../../src/tools/file-delete.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { Tool, ToolContext, ToolResult, JSONSchemaObject } from '@nexagent-cli/shared';
2
+ export declare class FileEditTool implements Tool {
3
+ name: string;
4
+ version: string;
5
+ description: string;
6
+ enabled: boolean;
7
+ riskLevel: "medium";
8
+ permissions: readonly ["fs:read", "fs:write"];
9
+ parameters: JSONSchemaObject;
10
+ execute(args: unknown, ctx: ToolContext): Promise<ToolResult>;
11
+ undo(executionId: string, ctx: ToolContext): Promise<void>;
12
+ dryRun(args: unknown, _ctx: ToolContext): Promise<string>;
13
+ private saveUndo;
14
+ private getUndo;
15
+ private deleteUndo;
16
+ private dryRunResult;
17
+ private resolveSafe;
18
+ }
19
+ //# sourceMappingURL=file-edit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-edit.d.ts","sourceRoot":"","sources":["../../../../src/tools/file-edit.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAG5F,qBAAa,YAAa,YAAW,IAAI;IACvC,IAAI,SAAsB;IAC1B,OAAO,SAAe;IACtB,WAAW,SAME;IACb,OAAO,UAAY;IACnB,SAAS,EAAK,QAAQ,CAAU;IAChC,WAAW,mCAAoC;IAE/C,UAAU,EAAE,gBAAgB,CA8B1B;IAEI,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IAmE7D,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAc1D,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC;IAO/D,OAAO,CAAC,QAAQ;IAgBhB,OAAO,CAAC,OAAO;IAgBf,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,YAAY;IAapB,OAAO,CAAC,WAAW;CAQpB"}
@@ -0,0 +1,182 @@
1
+ // ============================================================
2
+ // Tool: file_edit — Apply a unified diff patch to a file
3
+ // Supports both unified diff patches and exact string replacements.
4
+ // Full undo support via SQLite-backed undo stack.
5
+ // ============================================================
6
+ import { readFile, writeFile, mkdir } from 'node:fs/promises';
7
+ import { resolve, relative, dirname } from 'node:path';
8
+ import { applyPatch } from 'diff';
9
+ import { generateId } from '@nexagent-cli/shared';
10
+ export class FileEditTool {
11
+ name = 'file_edit';
12
+ version = '2.0.0';
13
+ description = [
14
+ 'Edit a file using one of two strategies:',
15
+ ' 1. "diff" mode: Apply a unified diff patch (preferred for large edits)',
16
+ ' 2. "replace" mode: Replace exact string occurrences in the file',
17
+ 'Always read the file first to ensure accuracy.',
18
+ 'Returns the resulting file content.',
19
+ ].join('\n');
20
+ enabled = true;
21
+ riskLevel = 'medium';
22
+ permissions = ['fs:read', 'fs:write'];
23
+ parameters = {
24
+ type: 'object',
25
+ properties: {
26
+ path: {
27
+ type: 'string',
28
+ description: 'File path, relative to workspace directory',
29
+ },
30
+ mode: {
31
+ type: 'string',
32
+ description: '"diff" to apply a unified diff, "replace" for exact string replacement',
33
+ enum: ['diff', 'replace'],
34
+ },
35
+ patch: {
36
+ type: 'string',
37
+ description: '[mode=diff] Unified diff patch string (output of diff -u)',
38
+ },
39
+ old_string: {
40
+ type: 'string',
41
+ description: '[mode=replace] Exact string to find in the file',
42
+ },
43
+ new_string: {
44
+ type: 'string',
45
+ description: '[mode=replace] Replacement string',
46
+ },
47
+ replace_all: {
48
+ type: 'boolean',
49
+ description: '[mode=replace] Replace all occurrences (default false)',
50
+ },
51
+ },
52
+ required: ['path', 'mode'],
53
+ };
54
+ async execute(args, ctx) {
55
+ const { path, mode, patch, old_string, new_string, replace_all = false } = args;
56
+ const executionId = generateId();
57
+ const absPath = this.resolveSafe(path, ctx.workspaceDir);
58
+ // Read original content
59
+ let original;
60
+ try {
61
+ original = await readFile(absPath, 'utf-8');
62
+ }
63
+ catch {
64
+ original = ''; // New file — diff will still work
65
+ }
66
+ if (ctx.dryRun) {
67
+ return this.dryRunResult(mode, path, original, { patch, old_string, new_string, replace_all }, executionId);
68
+ }
69
+ let edited;
70
+ if (mode === 'diff') {
71
+ if (!patch)
72
+ throw new Error('patch is required for mode=diff');
73
+ const result = applyPatch(original, patch);
74
+ if (result === false) {
75
+ throw new Error('Patch does not apply cleanly. Read the current file content and regenerate the patch.');
76
+ }
77
+ edited = result;
78
+ }
79
+ else {
80
+ if (old_string === undefined)
81
+ throw new Error('old_string is required for mode=replace');
82
+ if (new_string === undefined)
83
+ throw new Error('new_string is required for mode=replace');
84
+ if (!original.includes(old_string)) {
85
+ throw new Error(`old_string not found in ${path}. Read the file first to get the exact current content.`);
86
+ }
87
+ edited = replace_all
88
+ ? original.split(old_string).join(new_string)
89
+ : original.replace(old_string, new_string);
90
+ }
91
+ // Persist undo to SQLite (fallback to in-memory if db unavailable)
92
+ this.saveUndo(ctx, executionId, ctx.sessionId, path, original);
93
+ ctx.emit('undo:available', { undoId: executionId, description: `Edit ${path}` });
94
+ // Atomic write
95
+ await mkdir(dirname(absPath), { recursive: true });
96
+ await writeFile(absPath, edited, 'utf-8');
97
+ const linesBefore = original.split('\n').length;
98
+ const linesAfter = edited.split('\n').length;
99
+ const delta = linesAfter - linesBefore;
100
+ const sign = delta >= 0 ? '+' : '';
101
+ return {
102
+ success: true,
103
+ output: `Edited ${path} (${sign}${delta} lines, ${edited.length} chars total)`,
104
+ data: { path, linesBefore, linesAfter, charsDelta: edited.length - original.length },
105
+ executionId,
106
+ durationMs: 0,
107
+ };
108
+ }
109
+ async undo(executionId, ctx) {
110
+ const entry = this.getUndo(ctx, executionId);
111
+ if (!entry) {
112
+ throw new Error(`No undo data found for executionId: ${executionId}`);
113
+ }
114
+ const absPath = this.resolveSafe(entry.path, ctx.workspaceDir);
115
+ await writeFile(absPath, entry.originalContent, 'utf-8');
116
+ // Remove from undo store
117
+ this.deleteUndo(ctx, executionId);
118
+ ctx.emit('status:change', { status: 'idle', message: `Undo applied: restored ${entry.path}` });
119
+ }
120
+ async dryRun(args, _ctx) {
121
+ const { path, mode } = args;
122
+ return `Would edit "${path}" using ${mode} strategy`;
123
+ }
124
+ // ── Undo persistence helpers ─────────────────────────────────
125
+ saveUndo(ctx, executionId, sessionId, path, originalContent) {
126
+ if (ctx.db) {
127
+ try {
128
+ ctx.db.prepare(`
129
+ INSERT INTO undo_stack (id, session_id, tool_name, operation, file_path, original_content, created_at)
130
+ VALUES (?, ?, ?, ?, ?, ?, ?)
131
+ `).run(executionId, sessionId, 'file_edit', `edit ${path}`, path, originalContent, Date.now());
132
+ return;
133
+ }
134
+ catch {
135
+ // Fallback to in-memory if DB insert fails
136
+ }
137
+ }
138
+ // In-memory fallback (stored on ToolContext via emit for simplicity, or we just note it)
139
+ ctx.emit('undo:cached', { executionId, path, originalContent });
140
+ }
141
+ getUndo(ctx, executionId) {
142
+ if (ctx.db) {
143
+ try {
144
+ const row = ctx.db.prepare('SELECT file_path, original_content FROM undo_stack WHERE id = ?').get(executionId);
145
+ if (row) {
146
+ return { path: row.file_path, originalContent: row.original_content };
147
+ }
148
+ }
149
+ catch {
150
+ // Fallback
151
+ }
152
+ }
153
+ return undefined;
154
+ }
155
+ deleteUndo(ctx, executionId) {
156
+ if (ctx.db) {
157
+ try {
158
+ ctx.db.prepare('DELETE FROM undo_stack WHERE id = ?').run(executionId);
159
+ }
160
+ catch {
161
+ // ignore
162
+ }
163
+ }
164
+ }
165
+ dryRunResult(mode, path, original, opts, executionId) {
166
+ let preview = `[DRY RUN] Would edit ${path} using ${mode} mode`;
167
+ if (mode === 'replace' && opts.old_string) {
168
+ const count = original.split(opts.old_string).length - 1;
169
+ preview += ` — found ${count} occurrence(s) of the target string`;
170
+ }
171
+ return { success: true, output: preview, data: { dryRun: true }, executionId, durationMs: 0 };
172
+ }
173
+ resolveSafe(filePath, workspaceDir) {
174
+ const abs = resolve(workspaceDir, filePath);
175
+ const rel = relative(workspaceDir, abs);
176
+ if (rel.startsWith('..') || require('node:path').isAbsolute(rel)) {
177
+ throw new Error(`Path traversal denied: "${filePath}" is outside the workspace`);
178
+ }
179
+ return abs;
180
+ }
181
+ }
182
+ //# sourceMappingURL=file-edit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-edit.js","sourceRoot":"","sources":["../../../../src/tools/file-edit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { Tool, ToolContext, ToolResult, JSONSchemaObject } from '@nexagent-cli/shared';
2
+ export declare class FileListTool implements Tool {
3
+ name: string;
4
+ version: string;
5
+ description: string;
6
+ enabled: boolean;
7
+ riskLevel: "low";
8
+ permissions: readonly ["fs:read"];
9
+ parameters: JSONSchemaObject;
10
+ execute(args: unknown, ctx: ToolContext): Promise<ToolResult>;
11
+ private walk;
12
+ }
13
+ //# sourceMappingURL=file-list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-list.d.ts","sourceRoot":"","sources":["../../../../src/tools/file-list.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAU5F,qBAAa,YAAa,YAAW,IAAI;IACvC,IAAI,SAAsB;IAC1B,OAAO,SAAe;IACtB,WAAW,SAAqF;IAChG,OAAO,UAAY;IACnB,SAAS,EAAK,KAAK,CAAU;IAC7B,WAAW,uBAAwB;IAEnC,UAAU,EAAE,gBAAgB,CAyB1B;IAEI,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;YAgCrD,IAAI;CAiCnB"}
@@ -0,0 +1,92 @@
1
+ // ============================================================
2
+ // Tool: file_list — List files in a directory
3
+ // ============================================================
4
+ import { readdir, stat } from 'node:fs/promises';
5
+ import { join, resolve, relative } from 'node:path';
6
+ import { generateId } from '@nexagent-cli/shared';
7
+ export class FileListTool {
8
+ name = 'file_list';
9
+ version = '1.0.0';
10
+ description = 'List files and directories in a workspace path. Respects .gitignore by default.';
11
+ enabled = true;
12
+ riskLevel = 'low';
13
+ permissions = ['fs:read'];
14
+ parameters = {
15
+ type: 'object',
16
+ properties: {
17
+ path: {
18
+ type: 'string',
19
+ description: 'Directory path relative to workspace (default: workspace root)',
20
+ },
21
+ recursive: {
22
+ type: 'boolean',
23
+ description: 'Recursively list subdirectories (default: false)',
24
+ },
25
+ include_hidden: {
26
+ type: 'boolean',
27
+ description: 'Include dot files/directories (default: false)',
28
+ },
29
+ pattern: {
30
+ type: 'string',
31
+ description: 'Glob pattern to filter results (e.g. "*.ts")',
32
+ },
33
+ max_depth: {
34
+ type: 'number',
35
+ description: 'Max recursion depth (default: 5)',
36
+ },
37
+ },
38
+ required: [],
39
+ };
40
+ async execute(args, ctx) {
41
+ const { path: relPath = '.', recursive = false, include_hidden = false, max_depth = 5, } = args;
42
+ const absDir = resolve(ctx.workspaceDir, relPath);
43
+ const entries = [];
44
+ await this.walk(absDir, ctx.workspaceDir, entries, {
45
+ recursive, include_hidden, maxDepth: max_depth, depth: 0,
46
+ });
47
+ const summary = entries
48
+ .slice(0, 200) // cap output
49
+ .map(e => `${e.type === 'directory' ? 'd' : 'f'} ${e.path}${e.sizeBytes !== undefined ? ` (${e.sizeBytes}B)` : ''}`)
50
+ .join('\n');
51
+ return {
52
+ success: true,
53
+ output: `Found ${entries.length} entries in ${relPath}\n${summary}`,
54
+ data: { path: relPath, entries: entries.slice(0, 200), total: entries.length },
55
+ executionId: generateId(),
56
+ durationMs: 0,
57
+ };
58
+ }
59
+ async walk(dir, workspace, results, opts) {
60
+ if (opts.depth > opts.maxDepth)
61
+ return;
62
+ let items;
63
+ try {
64
+ items = await readdir(dir);
65
+ }
66
+ catch {
67
+ return;
68
+ }
69
+ for (const item of items) {
70
+ if (!opts.include_hidden && item.startsWith('.'))
71
+ continue;
72
+ const full = join(dir, item);
73
+ const rel = relative(workspace, full);
74
+ try {
75
+ const s = await stat(full);
76
+ if (s.isDirectory()) {
77
+ results.push({ path: rel, type: 'directory' });
78
+ if (opts.recursive) {
79
+ await this.walk(full, workspace, results, { ...opts, depth: opts.depth + 1 });
80
+ }
81
+ }
82
+ else {
83
+ results.push({ path: rel, type: 'file', sizeBytes: s.size, modifiedAt: s.mtime.toISOString() });
84
+ }
85
+ }
86
+ catch {
87
+ // skip inaccessible entries
88
+ }
89
+ }
90
+ }
91
+ }
92
+ //# sourceMappingURL=file-list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-list.js","sourceRoot":"","sources":["../../../../src/tools/file-list.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { Tool, ToolContext, ToolResult, JSONSchemaObject } from '@nexagent-cli/shared';
2
+ export declare class FileReadTool implements Tool {
3
+ name: string;
4
+ version: string;
5
+ description: string;
6
+ enabled: boolean;
7
+ riskLevel: "low";
8
+ permissions: readonly ["fs:read"];
9
+ parameters: JSONSchemaObject;
10
+ execute(args: unknown, ctx: ToolContext): Promise<ToolResult>;
11
+ private resolveSafe;
12
+ }
13
+ //# sourceMappingURL=file-read.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-read.d.ts","sourceRoot":"","sources":["../../../../src/tools/file-read.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAG5F,qBAAa,YAAa,YAAW,IAAI;IACvC,IAAI,SAAsB;IAC1B,OAAO,SAAe;IACtB,WAAW,SAA8F;IACzG,OAAO,UAAY;IACnB,SAAS,EAAK,KAAK,CAAU;IAC7B,WAAW,uBAAwB;IAEnC,UAAU,EAAE,gBAAgB,CAsB1B;IAEI,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IA6BnE,OAAO,CAAC,WAAW;CAQpB"}
@@ -0,0 +1,68 @@
1
+ // ============================================================
2
+ // Tool: file_read — Read file contents from the workspace
3
+ // ============================================================
4
+ import { readFile } from 'node:fs/promises';
5
+ import { resolve, relative } from 'node:path';
6
+ import { generateId } from '@nexagent-cli/shared';
7
+ export class FileReadTool {
8
+ name = 'file_read';
9
+ version = '1.0.0';
10
+ description = 'Read the full contents of a file. Supports text files only. Returns content as a string.';
11
+ enabled = true;
12
+ riskLevel = 'low';
13
+ permissions = ['fs:read'];
14
+ parameters = {
15
+ type: 'object',
16
+ properties: {
17
+ path: {
18
+ type: 'string',
19
+ description: 'Path to the file, relative to the workspace directory',
20
+ },
21
+ encoding: {
22
+ type: 'string',
23
+ description: 'File encoding (default: utf-8)',
24
+ enum: ['utf-8', 'base64'],
25
+ },
26
+ start_line: {
27
+ type: 'number',
28
+ description: 'First line to read (1-indexed, optional)',
29
+ },
30
+ end_line: {
31
+ type: 'number',
32
+ description: 'Last line to read (inclusive, optional)',
33
+ },
34
+ },
35
+ required: ['path'],
36
+ };
37
+ async execute(args, ctx) {
38
+ const { path, encoding = 'utf-8', start_line, end_line } = args;
39
+ const absPath = this.resolveSafe(path, ctx.workspaceDir);
40
+ const raw = await readFile(absPath, { encoding: (encoding === 'base64' ? 'base64' : 'utf-8') });
41
+ let content = raw;
42
+ let lineInfo = '';
43
+ if ((start_line !== undefined || end_line !== undefined) && encoding !== 'base64') {
44
+ const lines = raw.split('\n');
45
+ const start = (start_line ?? 1) - 1;
46
+ const end = end_line ?? lines.length;
47
+ content = lines.slice(start, end).join('\n');
48
+ lineInfo = ` (lines ${start + 1}–${end})`;
49
+ }
50
+ return {
51
+ success: true,
52
+ output: `Read ${path}${lineInfo} — ${content.length} chars`,
53
+ data: { path, content, encoding },
54
+ executionId: generateId(),
55
+ durationMs: 0,
56
+ bytesRead: content.length,
57
+ };
58
+ }
59
+ resolveSafe(filePath, workspaceDir) {
60
+ const abs = resolve(workspaceDir, filePath);
61
+ const rel = relative(workspaceDir, abs);
62
+ if (rel.startsWith('..') || require('node:path').isAbsolute(rel)) {
63
+ throw new Error(`Path traversal denied: "${filePath}" is outside the workspace`);
64
+ }
65
+ return abs;
66
+ }
67
+ }
68
+ //# sourceMappingURL=file-read.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-read.js","sourceRoot":"","sources":["../../../../src/tools/file-read.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 FileSearchTool implements Tool {
3
+ name: string;
4
+ version: string;
5
+ description: string;
6
+ enabled: boolean;
7
+ riskLevel: "low";
8
+ permissions: readonly ["fs:read"];
9
+ parameters: JSONSchemaObject;
10
+ execute(args: unknown, ctx: ToolContext): Promise<ToolResult>;
11
+ private collectFiles;
12
+ private matchPattern;
13
+ }
14
+ //# sourceMappingURL=file-search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-search.d.ts","sourceRoot":"","sources":["../../../../src/tools/file-search.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAG5F,qBAAa,cAAe,YAAW,IAAI;IACzC,IAAI,SAAwB;IAC5B,OAAO,SAAe;IACtB,WAAW,SAA4H;IACvI,OAAO,UAAY;IACnB,SAAS,EAAK,KAAK,CAAU;IAC7B,WAAW,uBAAwB;IAEnC,UAAU,EAAE,gBAAgB,CAiC1B;IAEI,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;YA8DrD,YAAY;IA4B1B,OAAO,CAAC,YAAY;CAIrB"}