@sunilp-org/jam-cli 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.
- package/LICENSE +21 -0
- package/README.md +625 -0
- package/dist/commands/ask.d.ts +9 -0
- package/dist/commands/ask.d.ts.map +1 -0
- package/dist/commands/ask.js +84 -0
- package/dist/commands/ask.js.map +1 -0
- package/dist/commands/auth.d.ts +4 -0
- package/dist/commands/auth.d.ts.map +1 -0
- package/dist/commands/auth.js +44 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/chat.d.ts +10 -0
- package/dist/commands/chat.d.ts.map +1 -0
- package/dist/commands/chat.js +57 -0
- package/dist/commands/chat.js.map +1 -0
- package/dist/commands/completion.d.ts +4 -0
- package/dist/commands/completion.d.ts.map +1 -0
- package/dist/commands/completion.js +156 -0
- package/dist/commands/completion.js.map +1 -0
- package/dist/commands/config.d.ts +6 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +59 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/diff.d.ts +9 -0
- package/dist/commands/diff.d.ts.map +1 -0
- package/dist/commands/diff.js +69 -0
- package/dist/commands/diff.js.map +1 -0
- package/dist/commands/doctor.d.ts +3 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +86 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/explain.d.ts +7 -0
- package/dist/commands/explain.d.ts.map +1 -0
- package/dist/commands/explain.js +72 -0
- package/dist/commands/explain.js.map +1 -0
- package/dist/commands/history.d.ts +3 -0
- package/dist/commands/history.d.ts.map +1 -0
- package/dist/commands/history.js +99 -0
- package/dist/commands/history.js.map +1 -0
- package/dist/commands/models.d.ts +3 -0
- package/dist/commands/models.d.ts.map +1 -0
- package/dist/commands/models.js +39 -0
- package/dist/commands/models.js.map +1 -0
- package/dist/commands/patch.d.ts +8 -0
- package/dist/commands/patch.d.ts.map +1 -0
- package/dist/commands/patch.js +158 -0
- package/dist/commands/patch.js.map +1 -0
- package/dist/commands/run.d.ts +6 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +241 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/search.d.ts +9 -0
- package/dist/commands/search.d.ts.map +1 -0
- package/dist/commands/search.js +128 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/config/defaults.d.ts +3 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +16 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/loader.d.ts +4 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +103 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +104 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +21 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +249 -0
- package/dist/index.js.map +1 -0
- package/dist/providers/base.d.ts +32 -0
- package/dist/providers/base.d.ts.map +1 -0
- package/dist/providers/base.js +2 -0
- package/dist/providers/base.js.map +1 -0
- package/dist/providers/factory.d.ts +4 -0
- package/dist/providers/factory.d.ts.map +1 -0
- package/dist/providers/factory.js +13 -0
- package/dist/providers/factory.js.map +1 -0
- package/dist/providers/ollama.d.ts +14 -0
- package/dist/providers/ollama.d.ts.map +1 -0
- package/dist/providers/ollama.js +152 -0
- package/dist/providers/ollama.js.map +1 -0
- package/dist/storage/history.d.ts +21 -0
- package/dist/storage/history.d.ts.map +1 -0
- package/dist/storage/history.js +103 -0
- package/dist/storage/history.js.map +1 -0
- package/dist/tools/apply_patch.d.ts +3 -0
- package/dist/tools/apply_patch.d.ts.map +1 -0
- package/dist/tools/apply_patch.js +86 -0
- package/dist/tools/apply_patch.js.map +1 -0
- package/dist/tools/git_diff.d.ts +3 -0
- package/dist/tools/git_diff.d.ts.map +1 -0
- package/dist/tools/git_diff.js +49 -0
- package/dist/tools/git_diff.js.map +1 -0
- package/dist/tools/git_status.d.ts +3 -0
- package/dist/tools/git_status.d.ts.map +1 -0
- package/dist/tools/git_status.js +26 -0
- package/dist/tools/git_status.js.map +1 -0
- package/dist/tools/index.d.ts +10 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +10 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/list_dir.d.ts +3 -0
- package/dist/tools/list_dir.d.ts.map +1 -0
- package/dist/tools/list_dir.js +61 -0
- package/dist/tools/list_dir.js.map +1 -0
- package/dist/tools/read_file.d.ts +3 -0
- package/dist/tools/read_file.d.ts.map +1 -0
- package/dist/tools/read_file.js +83 -0
- package/dist/tools/read_file.js.map +1 -0
- package/dist/tools/registry.d.ts +12 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +76 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/run_command.d.ts +6 -0
- package/dist/tools/run_command.d.ts.map +1 -0
- package/dist/tools/run_command.js +37 -0
- package/dist/tools/run_command.js.map +1 -0
- package/dist/tools/search_text.d.ts +3 -0
- package/dist/tools/search_text.d.ts.map +1 -0
- package/dist/tools/search_text.js +171 -0
- package/dist/tools/search_text.js.map +1 -0
- package/dist/tools/types.d.ts +25 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +2 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/tools/write_file.d.ts +3 -0
- package/dist/tools/write_file.d.ts.map +1 -0
- package/dist/tools/write_file.js +61 -0
- package/dist/tools/write_file.js.map +1 -0
- package/dist/ui/chat.d.ts +10 -0
- package/dist/ui/chat.d.ts.map +1 -0
- package/dist/ui/chat.js +173 -0
- package/dist/ui/chat.js.map +1 -0
- package/dist/ui/logo.d.ts +14 -0
- package/dist/ui/logo.d.ts.map +1 -0
- package/dist/ui/logo.js +76 -0
- package/dist/ui/logo.js.map +1 -0
- package/dist/ui/renderer.d.ts +15 -0
- package/dist/ui/renderer.d.ts.map +1 -0
- package/dist/ui/renderer.js +61 -0
- package/dist/ui/renderer.js.map +1 -0
- package/dist/utils/errors.d.ts +14 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +26 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/logger.d.ts +17 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +50 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/secrets.d.ts +4 -0
- package/dist/utils/secrets.d.ts.map +1 -0
- package/dist/utils/secrets.js +39 -0
- package/dist/utils/secrets.js.map +1 -0
- package/dist/utils/stream.d.ts +12 -0
- package/dist/utils/stream.d.ts.map +1 -0
- package/dist/utils/stream.js +54 -0
- package/dist/utils/stream.js.map +1 -0
- package/dist/utils/workspace.d.ts +14 -0
- package/dist/utils/workspace.d.ts.map +1 -0
- package/dist/utils/workspace.js +39 -0
- package/dist/utils/workspace.js.map +1 -0
- package/package.json +84 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import * as readline from 'node:readline/promises';
|
|
2
|
+
import { stdin, stdout } from 'node:process';
|
|
3
|
+
import { JamError } from '../utils/errors.js';
|
|
4
|
+
import { readFileTool } from './read_file.js';
|
|
5
|
+
import { listDirTool } from './list_dir.js';
|
|
6
|
+
import { searchTextTool } from './search_text.js';
|
|
7
|
+
import { gitDiffTool } from './git_diff.js';
|
|
8
|
+
import { gitStatusTool } from './git_status.js';
|
|
9
|
+
import { applyPatchTool } from './apply_patch.js';
|
|
10
|
+
import { writeFileTool } from './write_file.js';
|
|
11
|
+
export class ToolRegistry {
|
|
12
|
+
tools = new Map();
|
|
13
|
+
register(tool) {
|
|
14
|
+
this.tools.set(tool.name, tool);
|
|
15
|
+
}
|
|
16
|
+
get(name) {
|
|
17
|
+
return this.tools.get(name);
|
|
18
|
+
}
|
|
19
|
+
list() {
|
|
20
|
+
return Array.from(this.tools.values());
|
|
21
|
+
}
|
|
22
|
+
async execute(name, args, ctx, policy) {
|
|
23
|
+
const tool = this.tools.get(name);
|
|
24
|
+
if (tool === undefined) {
|
|
25
|
+
throw new JamError(`Tool not found: "${name}"`, 'TOOL_NOT_FOUND');
|
|
26
|
+
}
|
|
27
|
+
if (!tool.readonly) {
|
|
28
|
+
// Write tool — enforce policy
|
|
29
|
+
if (policy === 'never') {
|
|
30
|
+
throw new JamError(`Tool execution denied by policy: "${name}" is a write tool and policy is "never".`, 'TOOL_DENIED');
|
|
31
|
+
}
|
|
32
|
+
if (policy === 'ask_every_time') {
|
|
33
|
+
const confirmed = await this.confirmExecution(tool, args);
|
|
34
|
+
if (!confirmed) {
|
|
35
|
+
throw new JamError(`Tool execution denied by user: "${name}"`, 'TOOL_DENIED');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// policy === 'allowlist' falls through to execution below
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
return await tool.execute(args, ctx);
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
if (JamError.isJamError(err))
|
|
45
|
+
throw err;
|
|
46
|
+
throw new JamError(`Tool "${name}" threw an unexpected error.`, 'TOOL_EXEC_ERROR', { cause: err });
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async confirmExecution(tool, args) {
|
|
50
|
+
const rl = readline.createInterface({ input: stdin, output: stdout });
|
|
51
|
+
try {
|
|
52
|
+
const argsJson = JSON.stringify(args, null, 2);
|
|
53
|
+
const prompt = `\nTool: ${tool.name}\n` +
|
|
54
|
+
`Description: ${tool.description}\n` +
|
|
55
|
+
`Args:\n${argsJson}\n` +
|
|
56
|
+
`\nThis is a write operation. Proceed? [y/N] `;
|
|
57
|
+
const answer = await rl.question(prompt);
|
|
58
|
+
return answer.trim().toLowerCase() === 'y';
|
|
59
|
+
}
|
|
60
|
+
finally {
|
|
61
|
+
rl.close();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
export function createDefaultRegistry() {
|
|
66
|
+
const registry = new ToolRegistry();
|
|
67
|
+
registry.register(readFileTool);
|
|
68
|
+
registry.register(listDirTool);
|
|
69
|
+
registry.register(searchTextTool);
|
|
70
|
+
registry.register(gitDiffTool);
|
|
71
|
+
registry.register(gitStatusTool);
|
|
72
|
+
registry.register(applyPatchTool);
|
|
73
|
+
registry.register(writeFileTool);
|
|
74
|
+
return registry;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/tools/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spawns a child process and returns stdout as a string.
|
|
3
|
+
* Rejects with an Error containing stderr if the process exits with a non-zero code.
|
|
4
|
+
*/
|
|
5
|
+
export declare function runCommand(command: string, args: string[], cwd: string, timeoutMs?: number): Promise<string>;
|
|
6
|
+
//# sourceMappingURL=run_command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run_command.d.ts","sourceRoot":"","sources":["../../src/tools/run_command.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,UAAU,CACxB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,EACX,SAAS,SAAS,GACjB,OAAO,CAAC,MAAM,CAAC,CAuCjB"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
/**
|
|
3
|
+
* Spawns a child process and returns stdout as a string.
|
|
4
|
+
* Rejects with an Error containing stderr if the process exits with a non-zero code.
|
|
5
|
+
*/
|
|
6
|
+
export function runCommand(command, args, cwd, timeoutMs = 30_000) {
|
|
7
|
+
return new Promise((resolve, reject) => {
|
|
8
|
+
const child = spawn(command, args, { cwd, stdio: ['ignore', 'pipe', 'pipe'] });
|
|
9
|
+
let stdout = '';
|
|
10
|
+
let stderr = '';
|
|
11
|
+
child.stdout.on('data', (chunk) => {
|
|
12
|
+
stdout += chunk.toString('utf8');
|
|
13
|
+
});
|
|
14
|
+
child.stderr.on('data', (chunk) => {
|
|
15
|
+
stderr += chunk.toString('utf8');
|
|
16
|
+
});
|
|
17
|
+
const timer = setTimeout(() => {
|
|
18
|
+
child.kill('SIGTERM');
|
|
19
|
+
reject(new Error(`Command timed out after ${timeoutMs}ms: ${command} ${args.join(' ')}`));
|
|
20
|
+
}, timeoutMs);
|
|
21
|
+
child.on('close', (code) => {
|
|
22
|
+
clearTimeout(timer);
|
|
23
|
+
if (code === 0) {
|
|
24
|
+
resolve(stdout);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
const detail = stderr.trim() || stdout.trim();
|
|
28
|
+
reject(new Error(`Command "${command} ${args.join(' ')}" exited with code ${code}${detail ? `: ${detail}` : ''}`));
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
child.on('error', (err) => {
|
|
32
|
+
clearTimeout(timer);
|
|
33
|
+
reject(err);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=run_command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run_command.js","sourceRoot":"","sources":["../../src/tools/run_command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C;;;GAGG;AACH,MAAM,UAAU,UAAU,CACxB,OAAe,EACf,IAAc,EACd,GAAW,EACX,SAAS,GAAG,MAAM;IAElB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;QAE/E,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,IAAI,MAAM,GAAG,EAAE,CAAC;QAEhB,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YACxC,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QAEH,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YACxC,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QAEH,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACtB,MAAM,CAAC,IAAI,KAAK,CAAC,2BAA2B,SAAS,OAAO,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QAC5F,CAAC,EAAE,SAAS,CAAC,CAAC;QAEd,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YACzB,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;gBACf,OAAO,CAAC,MAAM,CAAC,CAAC;YAClB,CAAC;iBAAM,CAAC;gBACN,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,EAAE,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;gBAC9C,MAAM,CACJ,IAAI,KAAK,CACP,YAAY,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,sBAAsB,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAChG,CACF,CAAC;YACJ,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACxB,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,MAAM,CAAC,GAAG,CAAC,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search_text.d.ts","sourceRoot":"","sources":["../../src/tools/search_text.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,YAAY,CAAC;AAuI1E,eAAO,MAAM,cAAc,EAAE,cAkE5B,CAAC"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { readdir, readFile } from 'node:fs/promises';
|
|
3
|
+
import { resolve, join, relative } from 'node:path';
|
|
4
|
+
import { JamError } from '../utils/errors.js';
|
|
5
|
+
const SEARCH_TIMEOUT_MS = 10_000;
|
|
6
|
+
const DEFAULT_MAX_RESULTS = 20;
|
|
7
|
+
function runRipgrep(query, cwd, glob, maxResults) {
|
|
8
|
+
return new Promise((resolve, reject) => {
|
|
9
|
+
const args = [
|
|
10
|
+
'--line-number',
|
|
11
|
+
'--no-heading',
|
|
12
|
+
'--color=never',
|
|
13
|
+
`--max-count=${maxResults}`,
|
|
14
|
+
];
|
|
15
|
+
if (glob !== undefined) {
|
|
16
|
+
args.push('--glob', glob);
|
|
17
|
+
}
|
|
18
|
+
args.push(query, '.');
|
|
19
|
+
const child = spawn('rg', args, { cwd, stdio: ['ignore', 'pipe', 'pipe'] });
|
|
20
|
+
let stdout = '';
|
|
21
|
+
let stderr = '';
|
|
22
|
+
child.stdout.on('data', (chunk) => {
|
|
23
|
+
stdout += chunk.toString('utf8');
|
|
24
|
+
});
|
|
25
|
+
child.stderr.on('data', (chunk) => {
|
|
26
|
+
stderr += chunk.toString('utf8');
|
|
27
|
+
});
|
|
28
|
+
const timer = setTimeout(() => {
|
|
29
|
+
child.kill('SIGTERM');
|
|
30
|
+
reject(new Error('ripgrep timed out'));
|
|
31
|
+
}, SEARCH_TIMEOUT_MS);
|
|
32
|
+
child.on('close', (code) => {
|
|
33
|
+
clearTimeout(timer);
|
|
34
|
+
if (code === 0 || code === 1) {
|
|
35
|
+
// code 1 = no matches, which is fine
|
|
36
|
+
resolve(stdout.trim() === '' ? [] : stdout.trim().split('\n'));
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
reject(new Error(`rg exited with code ${code}: ${stderr}`));
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
child.on('error', (err) => {
|
|
43
|
+
clearTimeout(timer);
|
|
44
|
+
reject(err);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
async function collectFiles(dir, globPattern) {
|
|
49
|
+
const results = [];
|
|
50
|
+
async function walk(current) {
|
|
51
|
+
let entries;
|
|
52
|
+
try {
|
|
53
|
+
entries = await readdir(current, { withFileTypes: true });
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
for (const entry of entries) {
|
|
59
|
+
const name = String(entry.name);
|
|
60
|
+
// Skip hidden directories (like .git) and node_modules
|
|
61
|
+
if (name.startsWith('.') || name === 'node_modules') {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
const fullPath = join(current, name);
|
|
65
|
+
if (entry.isDirectory()) {
|
|
66
|
+
await walk(fullPath);
|
|
67
|
+
}
|
|
68
|
+
else if (entry.isFile()) {
|
|
69
|
+
if (globPattern !== undefined) {
|
|
70
|
+
// Simple glob: support *.ext and **/*.ext patterns
|
|
71
|
+
const dotIdx = globPattern.lastIndexOf('.');
|
|
72
|
+
if (dotIdx !== -1) {
|
|
73
|
+
const ext = globPattern.slice(dotIdx);
|
|
74
|
+
if (!name.endsWith(ext)) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
results.push(fullPath);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
await walk(dir);
|
|
84
|
+
return results;
|
|
85
|
+
}
|
|
86
|
+
async function nodeFallbackSearch(query, workspaceRoot, glob, maxResults) {
|
|
87
|
+
const files = await collectFiles(workspaceRoot, glob);
|
|
88
|
+
const matchLines = [];
|
|
89
|
+
const lowerQuery = query.toLowerCase();
|
|
90
|
+
outer: for (const file of files) {
|
|
91
|
+
let content;
|
|
92
|
+
try {
|
|
93
|
+
content = await readFile(file, 'utf8');
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
const lines = content.split('\n');
|
|
99
|
+
for (let i = 0; i < lines.length; i++) {
|
|
100
|
+
const line = lines[i] ?? '';
|
|
101
|
+
if (line.toLowerCase().includes(lowerQuery)) {
|
|
102
|
+
const relPath = relative(workspaceRoot, file);
|
|
103
|
+
matchLines.push(`${relPath}:${i + 1}: ${line}`);
|
|
104
|
+
if (matchLines.length >= maxResults) {
|
|
105
|
+
break outer;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return matchLines;
|
|
111
|
+
}
|
|
112
|
+
export const searchTextTool = {
|
|
113
|
+
name: 'search_text',
|
|
114
|
+
description: 'Search for text across files in the workspace. Uses ripgrep if available, otherwise falls back to a Node.js implementation.',
|
|
115
|
+
readonly: true,
|
|
116
|
+
parameters: {
|
|
117
|
+
type: 'object',
|
|
118
|
+
properties: {
|
|
119
|
+
query: { type: 'string', description: 'The text or regex pattern to search for.' },
|
|
120
|
+
glob: {
|
|
121
|
+
type: 'string',
|
|
122
|
+
description: 'Optional glob pattern to restrict the search (e.g. "**/*.ts").',
|
|
123
|
+
optional: true,
|
|
124
|
+
},
|
|
125
|
+
maxResults: {
|
|
126
|
+
type: 'number',
|
|
127
|
+
description: `Maximum number of results to return. Defaults to ${DEFAULT_MAX_RESULTS}.`,
|
|
128
|
+
optional: true,
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
required: ['query'],
|
|
132
|
+
},
|
|
133
|
+
async execute(args, ctx) {
|
|
134
|
+
const query = args['query'];
|
|
135
|
+
if (typeof query !== 'string' || query.trim() === '') {
|
|
136
|
+
throw new JamError('Argument "query" must be a non-empty string.', 'INPUT_MISSING');
|
|
137
|
+
}
|
|
138
|
+
const glob = typeof args['glob'] === 'string' ? args['glob'] : undefined;
|
|
139
|
+
const maxResults = typeof args['maxResults'] === 'number' && args['maxResults'] > 0
|
|
140
|
+
? args['maxResults']
|
|
141
|
+
: DEFAULT_MAX_RESULTS;
|
|
142
|
+
const absoluteRoot = resolve(ctx.workspaceRoot);
|
|
143
|
+
let matchLines;
|
|
144
|
+
let usedFallback = false;
|
|
145
|
+
try {
|
|
146
|
+
matchLines = await runRipgrep(query, absoluteRoot, glob, maxResults);
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
// rg not available or failed — fall back to Node.js search
|
|
150
|
+
usedFallback = true;
|
|
151
|
+
try {
|
|
152
|
+
matchLines = await nodeFallbackSearch(query, absoluteRoot, glob, maxResults);
|
|
153
|
+
}
|
|
154
|
+
catch (err) {
|
|
155
|
+
throw new JamError('Search failed.', 'TOOL_EXEC_ERROR', { cause: err });
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (matchLines.length === 0) {
|
|
159
|
+
return {
|
|
160
|
+
output: 'No matches found.',
|
|
161
|
+
metadata: { query, usedFallback, matchCount: 0 },
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
const output = matchLines.join('\n');
|
|
165
|
+
return {
|
|
166
|
+
output,
|
|
167
|
+
metadata: { query, usedFallback, matchCount: matchLines.length },
|
|
168
|
+
};
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
//# sourceMappingURL=search_text.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search_text.js","sourceRoot":"","sources":["../../src/tools/search_text.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAErD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAG9C,MAAM,iBAAiB,GAAG,MAAM,CAAC;AACjC,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAE/B,SAAS,UAAU,CACjB,KAAa,EACb,GAAW,EACX,IAAwB,EACxB,UAAkB;IAElB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,IAAI,GAAG;YACX,eAAe;YACf,cAAc;YACd,eAAe;YACf,eAAe,UAAU,EAAE;SAC5B,CAAC;QAEF,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAC5B,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAEtB,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;QAE5E,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,IAAI,MAAM,GAAG,EAAE,CAAC;QAEhB,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YACxC,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QAEH,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YACxC,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QAEH,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACtB,MAAM,CAAC,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC,CAAC;QACzC,CAAC,EAAE,iBAAiB,CAAC,CAAC;QAEtB,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YACzB,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,IAAI,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;gBAC7B,qCAAqC;gBACrC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;YACjE,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,IAAI,KAAK,CAAC,uBAAuB,IAAI,KAAK,MAAM,EAAE,CAAC,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACxB,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,MAAM,CAAC,GAAG,CAAC,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,GAAW,EAAE,WAA+B;IACtE,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,KAAK,UAAU,IAAI,CAAC,OAAe;QACjC,IAAI,OAAiB,CAAC;QACtB,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5D,CAAC;QAAC,MAAM,CAAC;YACP,OAAO;QACT,CAAC;QAED,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAChC,uDAAuD;YACvD,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,KAAK,cAAc,EAAE,CAAC;gBACpD,SAAS;YACX,CAAC;YAED,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YACrC,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC;YACvB,CAAC;iBAAM,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;gBAC1B,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;oBAC9B,mDAAmD;oBACnD,MAAM,MAAM,GAAG,WAAW,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;oBAC5C,IAAI,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC;wBAClB,MAAM,GAAG,GAAG,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;wBACtC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;4BACxB,SAAS;wBACX,CAAC;oBACH,CAAC;gBACH,CAAC;gBACD,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC;IAChB,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,KAAK,UAAU,kBAAkB,CAC/B,KAAa,EACb,aAAqB,EACrB,IAAwB,EACxB,UAAkB;IAElB,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;IACtD,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;IAEvC,KAAK,EAAE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QAChC,IAAI,OAAe,CAAC;QACpB,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACzC,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QAED,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAC5B,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC5C,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;gBAC9C,UAAU,CAAC,IAAI,CAAC,GAAG,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;gBAChD,IAAI,UAAU,CAAC,MAAM,IAAI,UAAU,EAAE,CAAC;oBACpC,MAAM,KAAK,CAAC;gBACd,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAmB;IAC5C,IAAI,EAAE,aAAa;IACnB,WAAW,EACT,6HAA6H;IAC/H,QAAQ,EAAE,IAAI;IACd,UAAU,EAAE;QACV,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,0CAA0C,EAAE;YAClF,IAAI,EAAE;gBACJ,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,gEAAgE;gBAC7E,QAAQ,EAAE,IAAI;aACf;YACD,UAAU,EAAE;gBACV,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,oDAAoD,mBAAmB,GAAG;gBACvF,QAAQ,EAAE,IAAI;aACf;SACF;QACD,QAAQ,EAAE,CAAC,OAAO,CAAC;KACpB;IAED,KAAK,CAAC,OAAO,CAAC,IAA6B,EAAE,GAAgB;QAC3D,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;QAC5B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACrD,MAAM,IAAI,QAAQ,CAAC,8CAA8C,EAAE,eAAe,CAAC,CAAC;QACtF,CAAC;QAED,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACzE,MAAM,UAAU,GACd,OAAO,IAAI,CAAC,YAAY,CAAC,KAAK,QAAQ,IAAI,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC;YAC9D,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC;YACpB,CAAC,CAAC,mBAAmB,CAAC;QAE1B,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QAEhD,IAAI,UAAoB,CAAC;QACzB,IAAI,YAAY,GAAG,KAAK,CAAC;QAEzB,IAAI,CAAC;YACH,UAAU,GAAG,MAAM,UAAU,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;QACvE,CAAC;QAAC,MAAM,CAAC;YACP,2DAA2D;YAC3D,YAAY,GAAG,IAAI,CAAC;YACpB,IAAI,CAAC;gBACH,UAAU,GAAG,MAAM,kBAAkB,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;YAC/E,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,IAAI,QAAQ,CAAC,gBAAgB,EAAE,iBAAiB,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;YAC1E,CAAC;QACH,CAAC;QAED,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5B,OAAO;gBACL,MAAM,EAAE,mBAAmB;gBAC3B,QAAQ,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC,EAAE;aACjD,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAErC,OAAO;YACL,MAAM;YACN,QAAQ,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,CAAC,MAAM,EAAE;SACjE,CAAC;IACJ,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface ToolContext {
|
|
2
|
+
workspaceRoot: string;
|
|
3
|
+
cwd: string;
|
|
4
|
+
}
|
|
5
|
+
export interface ToolResult {
|
|
6
|
+
output: string;
|
|
7
|
+
error?: string;
|
|
8
|
+
metadata?: Record<string, unknown>;
|
|
9
|
+
}
|
|
10
|
+
export interface ToolDefinition {
|
|
11
|
+
name: string;
|
|
12
|
+
description: string;
|
|
13
|
+
readonly: boolean;
|
|
14
|
+
parameters: {
|
|
15
|
+
type: 'object';
|
|
16
|
+
properties: Record<string, {
|
|
17
|
+
type: string;
|
|
18
|
+
description: string;
|
|
19
|
+
optional?: boolean;
|
|
20
|
+
}>;
|
|
21
|
+
required: string[];
|
|
22
|
+
};
|
|
23
|
+
execute(args: Record<string, unknown>, ctx: ToolContext): Promise<ToolResult>;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/tools/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE;QACV,IAAI,EAAE,QAAQ,CAAC;QACf,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,WAAW,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;SAAE,CAAC,CAAC;QACtF,QAAQ,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;IACF,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CAC/E"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/tools/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write_file.d.ts","sourceRoot":"","sources":["../../src/tools/write_file.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,YAAY,CAAC;AAE1E,eAAO,MAAM,aAAa,EAAE,cAqE3B,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { writeFile, appendFile, mkdir } from 'node:fs/promises';
|
|
2
|
+
import { resolve, dirname } from 'node:path';
|
|
3
|
+
import { JamError } from '../utils/errors.js';
|
|
4
|
+
export const writeFileTool = {
|
|
5
|
+
name: 'write_file',
|
|
6
|
+
description: 'Write or append content to a file. Creates parent directories if they do not exist.',
|
|
7
|
+
readonly: false,
|
|
8
|
+
parameters: {
|
|
9
|
+
type: 'object',
|
|
10
|
+
properties: {
|
|
11
|
+
path: { type: 'string', description: 'Path to the file, relative to workspace root.' },
|
|
12
|
+
content: { type: 'string', description: 'Content to write to the file.' },
|
|
13
|
+
mode: {
|
|
14
|
+
type: 'string',
|
|
15
|
+
description: '"overwrite" (default) replaces the file; "append" adds to the end.',
|
|
16
|
+
optional: true,
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
required: ['path', 'content'],
|
|
20
|
+
},
|
|
21
|
+
async execute(args, ctx) {
|
|
22
|
+
const filePath = args['path'];
|
|
23
|
+
if (typeof filePath !== 'string' || filePath.trim() === '') {
|
|
24
|
+
throw new JamError('Argument "path" must be a non-empty string.', 'INPUT_MISSING');
|
|
25
|
+
}
|
|
26
|
+
const content = args['content'];
|
|
27
|
+
if (typeof content !== 'string') {
|
|
28
|
+
throw new JamError('Argument "content" must be a string.', 'INPUT_MISSING');
|
|
29
|
+
}
|
|
30
|
+
const mode = args['mode'] === 'append' ? 'append' : 'overwrite';
|
|
31
|
+
const absolutePath = resolve(ctx.workspaceRoot, filePath);
|
|
32
|
+
const parentDir = dirname(absolutePath);
|
|
33
|
+
try {
|
|
34
|
+
await mkdir(parentDir, { recursive: true });
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
throw new JamError(`Failed to create parent directories for: ${filePath}`, 'TOOL_EXEC_ERROR', { cause: err });
|
|
38
|
+
}
|
|
39
|
+
const byteLength = Buffer.byteLength(content, 'utf8');
|
|
40
|
+
try {
|
|
41
|
+
if (mode === 'append') {
|
|
42
|
+
await appendFile(absolutePath, content, 'utf8');
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
await writeFile(absolutePath, content, 'utf8');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
throw new JamError(`Failed to write file: ${filePath}`, 'TOOL_EXEC_ERROR', { cause: err });
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
output: `Written ${byteLength} bytes to ${filePath}`,
|
|
53
|
+
metadata: {
|
|
54
|
+
path: absolutePath,
|
|
55
|
+
mode,
|
|
56
|
+
bytes: byteLength,
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
//# sourceMappingURL=write_file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write_file.js","sourceRoot":"","sources":["../../src/tools/write_file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAG9C,MAAM,CAAC,MAAM,aAAa,GAAmB;IAC3C,IAAI,EAAE,YAAY;IAClB,WAAW,EACT,qFAAqF;IACvF,QAAQ,EAAE,KAAK;IACf,UAAU,EAAE;QACV,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,+CAA+C,EAAE;YACtF,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,+BAA+B,EAAE;YACzE,IAAI,EAAE;gBACJ,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,oEAAoE;gBACjF,QAAQ,EAAE,IAAI;aACf;SACF;QACD,QAAQ,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC;KAC9B;IAED,KAAK,CAAC,OAAO,CAAC,IAA6B,EAAE,GAAgB;QAC3D,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;QAC9B,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YAC3D,MAAM,IAAI,QAAQ,CAAC,6CAA6C,EAAE,eAAe,CAAC,CAAC;QACrF,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;QAChC,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;YAChC,MAAM,IAAI,QAAQ,CAAC,sCAAsC,EAAE,eAAe,CAAC,CAAC;QAC9E,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC;QAChE,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;QAC1D,MAAM,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;QAExC,IAAI,CAAC;YACH,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,QAAQ,CAChB,4CAA4C,QAAQ,EAAE,EACtD,iBAAiB,EACjB,EAAE,KAAK,EAAE,GAAG,EAAE,CACf,CAAC;QACJ,CAAC;QAED,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAEtD,IAAI,CAAC;YACH,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACtB,MAAM,UAAU,CAAC,YAAY,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;YAClD,CAAC;iBAAM,CAAC;gBACN,MAAM,SAAS,CAAC,YAAY,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;YACjD,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,QAAQ,CAChB,yBAAyB,QAAQ,EAAE,EACnC,iBAAiB,EACjB,EAAE,KAAK,EAAE,GAAG,EAAE,CACf,CAAC;QACJ,CAAC;QAED,OAAO;YACL,MAAM,EAAE,WAAW,UAAU,aAAa,QAAQ,EAAE;YACpD,QAAQ,EAAE;gBACR,IAAI,EAAE,YAAY;gBAClB,IAAI;gBACJ,KAAK,EAAE,UAAU;aAClB;SACF,CAAC;IACJ,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ProviderAdapter, Message } from '../providers/base.js';
|
|
2
|
+
import type { JamConfig } from '../config/schema.js';
|
|
3
|
+
export interface ChatOptions {
|
|
4
|
+
provider: ProviderAdapter;
|
|
5
|
+
config: JamConfig;
|
|
6
|
+
sessionId: string;
|
|
7
|
+
initialMessages: Message[];
|
|
8
|
+
}
|
|
9
|
+
export declare function startChat(options: ChatOptions): Promise<void>;
|
|
10
|
+
//# sourceMappingURL=chat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/ui/chat.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGrD,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,eAAe,CAAC;IAC1B,MAAM,EAAE,SAAS,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,OAAO,EAAE,CAAC;CAC5B;AAkRD,wBAAsB,SAAS,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAWnE"}
|
package/dist/ui/chat.js
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect, useCallback, useRef } from 'react';
|
|
3
|
+
import { render, Box, Text, useApp, useInput, Static } from 'ink';
|
|
4
|
+
import TextInput from 'ink-text-input';
|
|
5
|
+
import { appendMessage } from '../storage/history.js';
|
|
6
|
+
function formatRole(role) {
|
|
7
|
+
switch (role) {
|
|
8
|
+
case 'user':
|
|
9
|
+
return 'You';
|
|
10
|
+
case 'assistant':
|
|
11
|
+
return 'Jam';
|
|
12
|
+
case 'system':
|
|
13
|
+
return 'System';
|
|
14
|
+
default:
|
|
15
|
+
return role;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function MessageItem({ message }) {
|
|
19
|
+
const roleColor = message.role === 'user' ? 'blue' : message.role === 'assistant' ? 'green' : 'gray';
|
|
20
|
+
return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { color: roleColor, bold: true, children: formatRole(message.role) }), _jsx(Text, { children: message.content })] }));
|
|
21
|
+
}
|
|
22
|
+
function ChatApp({ provider, config, sessionId, initialMessages, }) {
|
|
23
|
+
const { exit } = useApp();
|
|
24
|
+
// Messages that have been fully committed (shown via Static)
|
|
25
|
+
const [committedMessages, setCommittedMessages] = useState(() => initialMessages
|
|
26
|
+
.filter((m) => m.role !== 'system')
|
|
27
|
+
.map((m) => ({
|
|
28
|
+
role: m.role,
|
|
29
|
+
content: m.content,
|
|
30
|
+
timestamp: new Date().toISOString(),
|
|
31
|
+
})));
|
|
32
|
+
// Current in-progress assistant streaming text
|
|
33
|
+
const [streamingText, setStreamingText] = useState('');
|
|
34
|
+
// Whether we are currently streaming
|
|
35
|
+
const [isStreaming, setIsStreaming] = useState(false);
|
|
36
|
+
// Whether we are waiting for the first chunk (show spinner)
|
|
37
|
+
const [isThinking, setIsThinking] = useState(false);
|
|
38
|
+
// Error message to display
|
|
39
|
+
const [errorMessage, setErrorMessage] = useState(null);
|
|
40
|
+
// User's current input
|
|
41
|
+
const [inputValue, setInputValue] = useState('');
|
|
42
|
+
// Whether input is disabled (during streaming)
|
|
43
|
+
const [inputDisabled, setInputDisabled] = useState(false);
|
|
44
|
+
// Abort controller ref for cancelling generation
|
|
45
|
+
const abortRef = useRef(null);
|
|
46
|
+
// Track ctrl-c timing for double-press exit
|
|
47
|
+
const lastCtrlCRef = useRef(0);
|
|
48
|
+
// Conversation history for the provider (includes all roles)
|
|
49
|
+
const conversationRef = useRef(initialMessages);
|
|
50
|
+
useInput((_input, key) => {
|
|
51
|
+
if (key.ctrl && _input === 'c') {
|
|
52
|
+
const now = Date.now();
|
|
53
|
+
if (isStreaming) {
|
|
54
|
+
// First Ctrl-C during streaming: abort current generation
|
|
55
|
+
if (abortRef.current) {
|
|
56
|
+
abortRef.current.abort();
|
|
57
|
+
}
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
// Double Ctrl-C within 1 second: exit
|
|
61
|
+
if (now - lastCtrlCRef.current < 1000) {
|
|
62
|
+
exit();
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
lastCtrlCRef.current = now;
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
const handleSubmit = useCallback(async (value) => {
|
|
69
|
+
const trimmed = value.trim();
|
|
70
|
+
if (!trimmed || inputDisabled)
|
|
71
|
+
return;
|
|
72
|
+
setInputValue('');
|
|
73
|
+
setErrorMessage(null);
|
|
74
|
+
const userMessage = { role: 'user', content: trimmed };
|
|
75
|
+
const userDisplay = {
|
|
76
|
+
role: 'user',
|
|
77
|
+
content: trimmed,
|
|
78
|
+
timestamp: new Date().toISOString(),
|
|
79
|
+
};
|
|
80
|
+
// Persist user message
|
|
81
|
+
try {
|
|
82
|
+
await appendMessage(sessionId, userMessage);
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// Non-fatal; continue
|
|
86
|
+
}
|
|
87
|
+
// Add to committed messages display
|
|
88
|
+
setCommittedMessages((prev) => [...prev, userDisplay]);
|
|
89
|
+
// Update conversation history
|
|
90
|
+
conversationRef.current = [...conversationRef.current, userMessage];
|
|
91
|
+
// Start streaming
|
|
92
|
+
setIsThinking(true);
|
|
93
|
+
setIsStreaming(true);
|
|
94
|
+
setInputDisabled(true);
|
|
95
|
+
const profile = config.profiles[config.defaultProfile];
|
|
96
|
+
const abortController = new AbortController();
|
|
97
|
+
abortRef.current = abortController;
|
|
98
|
+
let fullResponse = '';
|
|
99
|
+
let interrupted = false;
|
|
100
|
+
try {
|
|
101
|
+
const stream = provider.streamCompletion({
|
|
102
|
+
messages: conversationRef.current,
|
|
103
|
+
model: profile?.model,
|
|
104
|
+
temperature: profile?.temperature,
|
|
105
|
+
maxTokens: profile?.maxTokens,
|
|
106
|
+
systemPrompt: profile?.systemPrompt,
|
|
107
|
+
});
|
|
108
|
+
for await (const chunk of stream) {
|
|
109
|
+
if (abortController.signal.aborted) {
|
|
110
|
+
interrupted = true;
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
if (!chunk.done) {
|
|
114
|
+
fullResponse += chunk.delta;
|
|
115
|
+
setIsThinking(false);
|
|
116
|
+
setStreamingText(fullResponse);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
if (!abortController.signal.aborted) {
|
|
122
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
123
|
+
setErrorMessage(`Error: ${message}`);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
interrupted = true;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// Finalize the streamed message
|
|
130
|
+
const finalContent = interrupted
|
|
131
|
+
? fullResponse + (fullResponse ? '\n[Generation interrupted]' : '[Generation interrupted]')
|
|
132
|
+
: fullResponse;
|
|
133
|
+
setStreamingText('');
|
|
134
|
+
setIsThinking(false);
|
|
135
|
+
setIsStreaming(false);
|
|
136
|
+
setInputDisabled(false);
|
|
137
|
+
abortRef.current = null;
|
|
138
|
+
if (finalContent) {
|
|
139
|
+
const assistantMessage = { role: 'assistant', content: finalContent };
|
|
140
|
+
const assistantDisplay = {
|
|
141
|
+
role: 'assistant',
|
|
142
|
+
content: finalContent,
|
|
143
|
+
timestamp: new Date().toISOString(),
|
|
144
|
+
};
|
|
145
|
+
// Persist assistant message
|
|
146
|
+
try {
|
|
147
|
+
await appendMessage(sessionId, assistantMessage);
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
// Non-fatal; continue
|
|
151
|
+
}
|
|
152
|
+
conversationRef.current = [...conversationRef.current, assistantMessage];
|
|
153
|
+
setCommittedMessages((prev) => [...prev, assistantDisplay]);
|
|
154
|
+
}
|
|
155
|
+
}, [inputDisabled, sessionId, config, provider]);
|
|
156
|
+
// Spinner frames for "Thinking..."
|
|
157
|
+
const [spinnerFrame, setSpinnerFrame] = useState(0);
|
|
158
|
+
const spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
159
|
+
useEffect(() => {
|
|
160
|
+
if (!isThinking)
|
|
161
|
+
return;
|
|
162
|
+
const timer = setInterval(() => {
|
|
163
|
+
setSpinnerFrame((f) => (f + 1) % spinnerFrames.length);
|
|
164
|
+
}, 80);
|
|
165
|
+
return () => clearInterval(timer);
|
|
166
|
+
}, [isThinking, spinnerFrames.length]);
|
|
167
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Static, { items: committedMessages, children: (message, index) => _jsx(MessageItem, { message: message }, index) }), isThinking && (_jsx(Box, { marginBottom: 1, children: _jsxs(Text, { color: "yellow", children: [spinnerFrames[spinnerFrame] ?? '⠋', " Thinking..."] }) })), streamingText !== '' && (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { color: "green", bold: true, children: "Jam" }), _jsx(Text, { children: streamingText })] })), errorMessage !== null && (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "red", children: errorMessage }) })), _jsxs(Box, { children: [_jsx(Text, { color: "blue", bold: true, children: '> ' }), _jsx(TextInput, { value: inputValue, onChange: setInputValue, onSubmit: (val) => { void handleSubmit(val); }, placeholder: inputDisabled ? 'Generating...' : 'Ask something... (Ctrl-C twice to exit)', focus: !inputDisabled })] })] }));
|
|
168
|
+
}
|
|
169
|
+
export async function startChat(options) {
|
|
170
|
+
const { waitUntilExit } = render(_jsx(ChatApp, { provider: options.provider, config: options.config, sessionId: options.sessionId, initialMessages: options.initialMessages }));
|
|
171
|
+
await waitUntilExit();
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=chat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat.js","sourceRoot":"","sources":["../../src/ui/chat.tsx"],"names":[],"mappings":"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"}
|