lonny-agent 0.2.4 → 0.2.6
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/README.md +326 -326
- package/dist/agent/llm.d.ts +4 -0
- package/dist/agent/llm.d.ts.map +1 -1
- package/dist/agent/prompt-builder.d.ts.map +1 -1
- package/dist/agent/prompt-builder.js +13 -9
- package/dist/agent/prompt-builder.js.map +1 -1
- package/dist/agent/providers/google.d.ts.map +1 -1
- package/dist/agent/providers/google.js.map +1 -1
- package/dist/agent/providers/openai.d.ts.map +1 -1
- package/dist/agent/providers/openai.js +43 -3
- package/dist/agent/providers/openai.js.map +1 -1
- package/dist/agent/session.d.ts +4 -0
- package/dist/agent/session.d.ts.map +1 -1
- package/dist/agent/session.js +45 -7
- package/dist/agent/session.js.map +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +7 -1
- package/dist/config/index.js.map +1 -1
- package/dist/tools/__tests__/bash.test.js +1 -1
- package/dist/tools/__tests__/bash.test.js.map +1 -1
- package/dist/tools/__tests__/edit.test.js +875 -371
- package/dist/tools/__tests__/edit.test.js.map +1 -1
- package/dist/tools/__tests__/grep.test.js +32 -0
- package/dist/tools/__tests__/grep.test.js.map +1 -1
- package/dist/tools/__tests__/sed.test.d.ts +2 -0
- package/dist/tools/__tests__/sed.test.d.ts.map +1 -0
- package/dist/tools/__tests__/sed.test.js +228 -0
- package/dist/tools/__tests__/sed.test.js.map +1 -0
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +83 -10
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/edit.d.ts +50 -9
- package/dist/tools/edit.d.ts.map +1 -1
- package/dist/tools/edit.js +328 -158
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/grep.d.ts.map +1 -1
- package/dist/tools/grep.js +54 -30
- package/dist/tools/grep.js.map +1 -1
- package/dist/tools/registry.d.ts +0 -6
- package/dist/tools/registry.d.ts.map +1 -1
- package/dist/tools/registry.js +2 -29
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/sed.d.ts +4 -0
- package/dist/tools/sed.d.ts.map +1 -0
- package/dist/tools/sed.js +121 -0
- package/dist/tools/sed.js.map +1 -0
- package/dist/web/index.d.ts.map +1 -1
- package/dist/web/index.js +26 -3
- package/dist/web/index.js.map +1 -1
- package/dist/web/public/app.js +5 -855
- package/dist/web/public/confirm.js +70 -0
- package/dist/web/public/index.html +121 -120
- package/dist/web/public/input.js +107 -0
- package/dist/web/public/messages.js +395 -0
- package/dist/web/public/sidebar.js +82 -0
- package/dist/web/public/state.js +72 -0
- package/dist/web/public/style.css +996 -949
- package/dist/web/public/utils.js +37 -0
- package/dist/web/public/websocket.js +267 -0
- package/dist/web/public/ws.js +19 -0
- package/dist/web/session-bridge.d.ts.map +1 -1
- package/dist/web/session-bridge.js +3 -7
- package/dist/web/session-bridge.js.map +1 -1
- package/package.json +55 -54
- package/scripts/copy-native.mjs +24 -0
- package/scripts/copy-web.mjs +15 -0
- package/src/agent/index.ts +25 -25
- package/src/agent/llm.ts +4 -0
- package/src/agent/prompt-builder.ts +13 -9
- package/src/agent/providers/anthropic.ts +179 -179
- package/src/agent/providers/google.ts +210 -211
- package/src/agent/providers/ollama.ts +186 -186
- package/src/agent/providers/openai.ts +61 -5
- package/src/agent/session.ts +59 -3
- package/src/config/index.ts +342 -335
- package/src/tools/__tests__/bash.test.ts +1 -1
- package/src/tools/__tests__/edit.test.ts +981 -385
- package/src/tools/__tests__/grep.test.ts +35 -0
- package/src/tools/bash.ts +97 -11
- package/src/tools/edit.ts +362 -169
- package/src/tools/git.ts +76 -76
- package/src/tools/grep.ts +57 -30
- package/src/tools/registry.ts +2 -31
- package/src/tui/index.ts +786 -786
- package/src/web/index.ts +25 -3
- package/src/web/public/app.js +5 -855
- package/src/web/public/confirm.js +70 -0
- package/src/web/public/index.html +121 -120
- package/src/web/public/input.js +107 -0
- package/src/web/public/messages.js +395 -0
- package/src/web/public/sidebar.js +82 -0
- package/src/web/public/state.js +72 -0
- package/src/web/public/style.css +996 -949
- package/src/web/public/utils.js +37 -0
- package/src/web/public/websocket.js +267 -0
- package/src/web/public/ws.js +19 -0
- package/src/web/session-bridge.ts +193 -194
- package/.claude/settings.local.json +0 -14
- package/.kilo/plans/1780064105789-mighty-pixel.md +0 -171
- package/.kilo/plans/1780293725888-quick-wizard.md +0 -62
- package/.lonny/plan-web-cwd-status.md +0 -38
- package/src/tools/exec.ts +0 -348
|
@@ -16,6 +16,12 @@ describe('grep tool', () => {
|
|
|
16
16
|
fs.writeFileSync(path.join(tmpDir, 'world.js'), 'const y = 2\nconsole.log("world")\n')
|
|
17
17
|
fs.mkdirSync(path.join(tmpDir, 'sub'))
|
|
18
18
|
fs.writeFileSync(path.join(tmpDir, 'sub', 'deep.ts'), 'const z = 3\n// TODO: implement\n')
|
|
19
|
+
// Additional files for include glob and path parameter tests
|
|
20
|
+
fs.mkdirSync(path.join(tmpDir, 'lib'))
|
|
21
|
+
fs.writeFileSync(path.join(tmpDir, 'lib', 'index.ts'), 'export const version = 1\n')
|
|
22
|
+
fs.writeFileSync(path.join(tmpDir, 'lib', 'helper.tsx'), 'export function helper() {}\n')
|
|
23
|
+
fs.writeFileSync(path.join(tmpDir, 'lib', 'config.tsx'), 'export const config = {}\n')
|
|
24
|
+
fs.writeFileSync(path.join(tmpDir, 'lib', 'readme.md'), '# no code here\n')
|
|
19
25
|
})
|
|
20
26
|
|
|
21
27
|
afterAll(() => {
|
|
@@ -44,6 +50,28 @@ describe('grep tool', () => {
|
|
|
44
50
|
expect(result.output).not.toContain('world.js')
|
|
45
51
|
})
|
|
46
52
|
|
|
53
|
+
it('filters by brace-enclosed glob pattern', async () => {
|
|
54
|
+
const result = await tool().execute({ pattern: 'export', include: '*.{ts,tsx}' })
|
|
55
|
+
expect(result.success).toBe(true)
|
|
56
|
+
expect(result.output).toContain('lib/index.ts')
|
|
57
|
+
expect(result.output).toContain('lib/helper.tsx')
|
|
58
|
+
expect(result.output).toContain('lib/config.tsx')
|
|
59
|
+
// Should NOT match hello.ts (it matches 'export' but is in root, not filtered out)
|
|
60
|
+
// All .ts and .tsx files should be included, including hello.ts which has 'export'
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('filters by include with path parameter', async () => {
|
|
64
|
+
const result = await tool().execute({
|
|
65
|
+
pattern: 'export',
|
|
66
|
+
include: '*.ts',
|
|
67
|
+
path: tmpDir + '/lib',
|
|
68
|
+
})
|
|
69
|
+
expect(result.success).toBe(true)
|
|
70
|
+
expect(result.output).toContain('lib/index.ts')
|
|
71
|
+
// helper.tsx and config.tsx are .tsx, not .ts, so should not appear
|
|
72
|
+
expect(result.output).not.toContain('lib/helper.tsx')
|
|
73
|
+
})
|
|
74
|
+
|
|
47
75
|
it('rejects missing pattern argument', async () => {
|
|
48
76
|
const result = await tool().execute({})
|
|
49
77
|
expect(result.success).toBe(false)
|
|
@@ -55,4 +83,11 @@ describe('grep tool', () => {
|
|
|
55
83
|
expect(result.success).toBe(true)
|
|
56
84
|
expect(result.output).toContain('deep.ts')
|
|
57
85
|
})
|
|
86
|
+
|
|
87
|
+
it('handles pattern with alternation', async () => {
|
|
88
|
+
const result = await tool().execute({ pattern: 'TODO|hello' })
|
|
89
|
+
expect(result.success).toBe(true)
|
|
90
|
+
expect(result.output).toContain('deep.ts')
|
|
91
|
+
expect(result.output).toContain('hello.ts')
|
|
92
|
+
})
|
|
58
93
|
})
|
package/src/tools/bash.ts
CHANGED
|
@@ -1,15 +1,89 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
const execAsync = promisify(exec)
|
|
1
|
+
import { spawn } from 'node:child_process'
|
|
2
|
+
import * as os from 'node:os'
|
|
5
3
|
|
|
6
4
|
import { fmtErr } from './errors.js'
|
|
7
5
|
import type { Tool, ToolResult } from './types.js'
|
|
8
6
|
|
|
7
|
+
function detectEnv(): { osInfo: string; shell: string } {
|
|
8
|
+
const platform = os.platform()
|
|
9
|
+
const release = os.release()
|
|
10
|
+
const arch = os.arch()
|
|
11
|
+
|
|
12
|
+
if (platform === 'win32') {
|
|
13
|
+
return {
|
|
14
|
+
osInfo: `Windows ${release} (${arch})`,
|
|
15
|
+
shell: 'powershell.exe',
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const osName = platform === 'darwin' ? 'macOS' : platform === 'linux' ? 'Linux' : platform
|
|
20
|
+
return {
|
|
21
|
+
osInfo: `${osName} ${release} (${arch})`,
|
|
22
|
+
shell: process.env.SHELL || '/bin/sh',
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const env = detectEnv()
|
|
27
|
+
|
|
28
|
+
function execCommand(
|
|
29
|
+
command: string,
|
|
30
|
+
timeout: number,
|
|
31
|
+
): Promise<{ stdout: string; stderr: string; exitCode: number }> {
|
|
32
|
+
return new Promise(resolve => {
|
|
33
|
+
const isWindows = os.platform() === 'win32'
|
|
34
|
+
const shellExe = isWindows ? 'powershell.exe' : process.env.SHELL || '/bin/sh'
|
|
35
|
+
const shellArgs = isWindows
|
|
36
|
+
? ['-NoProfile', '-NonInteractive', '-Command', command]
|
|
37
|
+
: ['-c', command]
|
|
38
|
+
|
|
39
|
+
const child = spawn(shellExe, shellArgs, {
|
|
40
|
+
cwd: process.cwd(),
|
|
41
|
+
env: { ...process.env, FORCE_COLOR: '0', NO_COLOR: '1' },
|
|
42
|
+
windowsHide: true,
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
let stdout = ''
|
|
46
|
+
let stderr = ''
|
|
47
|
+
const timer = setTimeout(() => {
|
|
48
|
+
child.kill('SIGTERM')
|
|
49
|
+
setTimeout(() => {
|
|
50
|
+
try {
|
|
51
|
+
child.kill('SIGKILL')
|
|
52
|
+
} catch {
|
|
53
|
+
/* already exited */
|
|
54
|
+
}
|
|
55
|
+
}, 5000)
|
|
56
|
+
}, timeout)
|
|
57
|
+
|
|
58
|
+
child.stdout?.on('data', (data: Buffer) => {
|
|
59
|
+
stdout += data.toString('utf-8')
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
child.stderr?.on('data', (data: Buffer) => {
|
|
63
|
+
stderr += data.toString('utf-8')
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
child.on('close', code => {
|
|
67
|
+
clearTimeout(timer)
|
|
68
|
+
resolve({ stdout, stderr, exitCode: code ?? 0 })
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
child.on('error', err => {
|
|
72
|
+
clearTimeout(timer)
|
|
73
|
+
resolve({ stdout, stderr: stderr + fmtErr(err), exitCode: 1 })
|
|
74
|
+
})
|
|
75
|
+
})
|
|
76
|
+
}
|
|
77
|
+
|
|
9
78
|
export const bashTool: Tool = {
|
|
10
79
|
definition: {
|
|
11
80
|
name: 'bash',
|
|
12
|
-
description:
|
|
81
|
+
description: `Execute a shell command. Returns stdout and stderr.
|
|
82
|
+
|
|
83
|
+
Environment: ${env.osInfo}
|
|
84
|
+
Shell: ${env.shell}
|
|
85
|
+
|
|
86
|
+
⚠️ IMPORTANT: Do NOT use this tool to create or modify files. Use the 'edit' tool for file modifications instead.`,
|
|
13
87
|
parameters: {
|
|
14
88
|
command: { type: 'string', description: 'Shell command to execute', required: true },
|
|
15
89
|
description: { type: 'string', description: 'Brief description of what the command does' },
|
|
@@ -25,12 +99,24 @@ export const bashTool: Tool = {
|
|
|
25
99
|
const timeout = (input.timeout as number) || 120_000
|
|
26
100
|
|
|
27
101
|
try {
|
|
28
|
-
const { stdout } = await
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
102
|
+
const { stdout, stderr, exitCode } = await execCommand(command, timeout)
|
|
103
|
+
|
|
104
|
+
let output = ''
|
|
105
|
+
if (stdout.trim()) output += stdout.trim()
|
|
106
|
+
if (stderr.trim()) {
|
|
107
|
+
output += output ? '\n' + stderr.trim() : stderr.trim()
|
|
108
|
+
}
|
|
109
|
+
if (!output) output = '(no output)'
|
|
110
|
+
|
|
111
|
+
if (exitCode !== 0) {
|
|
112
|
+
return {
|
|
113
|
+
success: false,
|
|
114
|
+
output,
|
|
115
|
+
error: `Command exited with code ${exitCode}`,
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return { success: true, output }
|
|
34
120
|
} catch (err) {
|
|
35
121
|
const msg = fmtErr(err)
|
|
36
122
|
return { success: false, output: '', error: `Command failed: ${msg}` }
|