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.
Files changed (102) hide show
  1. package/README.md +326 -326
  2. package/dist/agent/llm.d.ts +4 -0
  3. package/dist/agent/llm.d.ts.map +1 -1
  4. package/dist/agent/prompt-builder.d.ts.map +1 -1
  5. package/dist/agent/prompt-builder.js +13 -9
  6. package/dist/agent/prompt-builder.js.map +1 -1
  7. package/dist/agent/providers/google.d.ts.map +1 -1
  8. package/dist/agent/providers/google.js.map +1 -1
  9. package/dist/agent/providers/openai.d.ts.map +1 -1
  10. package/dist/agent/providers/openai.js +43 -3
  11. package/dist/agent/providers/openai.js.map +1 -1
  12. package/dist/agent/session.d.ts +4 -0
  13. package/dist/agent/session.d.ts.map +1 -1
  14. package/dist/agent/session.js +45 -7
  15. package/dist/agent/session.js.map +1 -1
  16. package/dist/config/index.d.ts.map +1 -1
  17. package/dist/config/index.js +7 -1
  18. package/dist/config/index.js.map +1 -1
  19. package/dist/tools/__tests__/bash.test.js +1 -1
  20. package/dist/tools/__tests__/bash.test.js.map +1 -1
  21. package/dist/tools/__tests__/edit.test.js +875 -371
  22. package/dist/tools/__tests__/edit.test.js.map +1 -1
  23. package/dist/tools/__tests__/grep.test.js +32 -0
  24. package/dist/tools/__tests__/grep.test.js.map +1 -1
  25. package/dist/tools/__tests__/sed.test.d.ts +2 -0
  26. package/dist/tools/__tests__/sed.test.d.ts.map +1 -0
  27. package/dist/tools/__tests__/sed.test.js +228 -0
  28. package/dist/tools/__tests__/sed.test.js.map +1 -0
  29. package/dist/tools/bash.d.ts.map +1 -1
  30. package/dist/tools/bash.js +83 -10
  31. package/dist/tools/bash.js.map +1 -1
  32. package/dist/tools/edit.d.ts +50 -9
  33. package/dist/tools/edit.d.ts.map +1 -1
  34. package/dist/tools/edit.js +328 -158
  35. package/dist/tools/edit.js.map +1 -1
  36. package/dist/tools/grep.d.ts.map +1 -1
  37. package/dist/tools/grep.js +54 -30
  38. package/dist/tools/grep.js.map +1 -1
  39. package/dist/tools/registry.d.ts +0 -6
  40. package/dist/tools/registry.d.ts.map +1 -1
  41. package/dist/tools/registry.js +2 -29
  42. package/dist/tools/registry.js.map +1 -1
  43. package/dist/tools/sed.d.ts +4 -0
  44. package/dist/tools/sed.d.ts.map +1 -0
  45. package/dist/tools/sed.js +121 -0
  46. package/dist/tools/sed.js.map +1 -0
  47. package/dist/web/index.d.ts.map +1 -1
  48. package/dist/web/index.js +26 -3
  49. package/dist/web/index.js.map +1 -1
  50. package/dist/web/public/app.js +5 -855
  51. package/dist/web/public/confirm.js +70 -0
  52. package/dist/web/public/index.html +121 -120
  53. package/dist/web/public/input.js +107 -0
  54. package/dist/web/public/messages.js +395 -0
  55. package/dist/web/public/sidebar.js +82 -0
  56. package/dist/web/public/state.js +72 -0
  57. package/dist/web/public/style.css +996 -949
  58. package/dist/web/public/utils.js +37 -0
  59. package/dist/web/public/websocket.js +267 -0
  60. package/dist/web/public/ws.js +19 -0
  61. package/dist/web/session-bridge.d.ts.map +1 -1
  62. package/dist/web/session-bridge.js +3 -7
  63. package/dist/web/session-bridge.js.map +1 -1
  64. package/package.json +55 -54
  65. package/scripts/copy-native.mjs +24 -0
  66. package/scripts/copy-web.mjs +15 -0
  67. package/src/agent/index.ts +25 -25
  68. package/src/agent/llm.ts +4 -0
  69. package/src/agent/prompt-builder.ts +13 -9
  70. package/src/agent/providers/anthropic.ts +179 -179
  71. package/src/agent/providers/google.ts +210 -211
  72. package/src/agent/providers/ollama.ts +186 -186
  73. package/src/agent/providers/openai.ts +61 -5
  74. package/src/agent/session.ts +59 -3
  75. package/src/config/index.ts +342 -335
  76. package/src/tools/__tests__/bash.test.ts +1 -1
  77. package/src/tools/__tests__/edit.test.ts +981 -385
  78. package/src/tools/__tests__/grep.test.ts +35 -0
  79. package/src/tools/bash.ts +97 -11
  80. package/src/tools/edit.ts +362 -169
  81. package/src/tools/git.ts +76 -76
  82. package/src/tools/grep.ts +57 -30
  83. package/src/tools/registry.ts +2 -31
  84. package/src/tui/index.ts +786 -786
  85. package/src/web/index.ts +25 -3
  86. package/src/web/public/app.js +5 -855
  87. package/src/web/public/confirm.js +70 -0
  88. package/src/web/public/index.html +121 -120
  89. package/src/web/public/input.js +107 -0
  90. package/src/web/public/messages.js +395 -0
  91. package/src/web/public/sidebar.js +82 -0
  92. package/src/web/public/state.js +72 -0
  93. package/src/web/public/style.css +996 -949
  94. package/src/web/public/utils.js +37 -0
  95. package/src/web/public/websocket.js +267 -0
  96. package/src/web/public/ws.js +19 -0
  97. package/src/web/session-bridge.ts +193 -194
  98. package/.claude/settings.local.json +0 -14
  99. package/.kilo/plans/1780064105789-mighty-pixel.md +0 -171
  100. package/.kilo/plans/1780293725888-quick-wizard.md +0 -62
  101. package/.lonny/plan-web-cwd-status.md +0 -38
  102. package/src/tools/exec.ts +0 -348
@@ -0,0 +1,37 @@
1
+ /* ── Utility Functions ── */
2
+
3
+ import { chatContainer } from './state.js'
4
+
5
+ export function getWsUrl() {
6
+ const proto = location.protocol === 'https:' ? 'wss:' : 'ws:'
7
+ return `${proto}//${location.host}`
8
+ }
9
+
10
+ export function scrollToBottom() {
11
+ requestAnimationFrame(() => {
12
+ chatContainer.scrollTop = chatContainer.scrollHeight
13
+ })
14
+ }
15
+
16
+ export function escapeHtml(text) {
17
+ const div = document.createElement('div')
18
+ div.textContent = text
19
+ return div.innerHTML
20
+ }
21
+
22
+ export function formatTimestamp() {
23
+ return new Date().toLocaleTimeString()
24
+ }
25
+
26
+ export function formatTokenCount(n) {
27
+ if (n >= 1000000) return `${(n / 1000000).toFixed(n % 1000000 === 0 ? 0 : 1)}M`
28
+ if (n >= 1000) return `${(n / 1000).toFixed(n % 1000 === 0 ? 0 : 1)}K`
29
+ return String(n)
30
+ }
31
+
32
+ export function renderMarkdown(text) {
33
+ if (typeof marked !== 'undefined' && marked.parse) {
34
+ return marked.parse(text, { breaks: true, gfm: true })
35
+ }
36
+ return `<pre>${escapeHtml(text)}</pre>`
37
+ }
@@ -0,0 +1,267 @@
1
+ /* ── WebSocket Connection & Message Handler ── */
2
+
3
+ import { closeConfirmDialog, showConfirmDialog } from './confirm.js'
4
+ import {
5
+ addErrorMessage,
6
+ addSystemMessage,
7
+ addTokenStats,
8
+ addToolCall,
9
+ addToolResult,
10
+ appendChunk,
11
+ finalizeAssistantMessage,
12
+ hideThinking,
13
+ renderSessionHistory,
14
+ showThinking,
15
+ startAssistantMessage,
16
+ } from './messages.js'
17
+ import { updatePlansAndTodos } from './sidebar.js'
18
+ import {
19
+ balanceDisplay,
20
+ balanceSep,
21
+ connectionOverlay,
22
+ cwdDisplay,
23
+ MAX_RECONNECT_ATTEMPTS,
24
+ messagesEl,
25
+ modeDisplay,
26
+ modelDisplay,
27
+ pendingToolCalls,
28
+ RECONNECT_DELAY,
29
+ setStatus,
30
+ state,
31
+ tokenCache,
32
+ tokenCalls,
33
+ tokenIn,
34
+ tokenOut,
35
+ } from './state.js'
36
+ import { formatTokenCount, getWsUrl, scrollToBottom } from './utils.js'
37
+ import { setWs } from './ws.js'
38
+
39
+ function handleMessage(msg) {
40
+ switch (msg.type) {
41
+ case 'hello':
42
+ state.currentMode = msg.mode || 'code'
43
+ state.currentModel = msg.model || ''
44
+ state.currentProvider = msg.provider || ''
45
+ modeDisplay.textContent = state.currentMode
46
+ modelDisplay.textContent = `${state.currentProvider}/${state.currentModel}`
47
+ if (msg.totalIn !== undefined) {
48
+ tokenIn.textContent = formatTokenCount(msg.totalIn || 0)
49
+ tokenOut.textContent = formatTokenCount(msg.totalOut || 0)
50
+ tokenCalls.textContent = `(${msg.totalApi || 0})`
51
+ const cacheHit = msg.totalCacheHit ?? 0
52
+ const cacheMiss = msg.totalCacheMiss ?? 0
53
+ const cacheTotal = cacheHit + cacheMiss
54
+ if (cacheTotal > 0) {
55
+ const pct = Math.round((cacheHit / cacheTotal) * 100)
56
+ tokenCache.textContent = `| 缓存 ${pct}%`
57
+ tokenCache.classList.remove('hidden')
58
+ }
59
+ }
60
+ if (msg.webBalance) {
61
+ balanceDisplay.textContent = `余额:${msg.webBalance}`
62
+ balanceDisplay.style.display = ''
63
+ balanceSep.style.display = ''
64
+ } else if (msg.balance) {
65
+ balanceDisplay.textContent = `余额:${msg.balance}`
66
+ balanceDisplay.style.display = ''
67
+ balanceSep.style.display = ''
68
+ } else {
69
+ balanceDisplay.style.display = 'none'
70
+ balanceSep.style.display = 'none'
71
+ }
72
+ if (msg.cwd) {
73
+ const maxLen = 35
74
+ cwdDisplay.textContent = msg.cwd.length > maxLen ? `...${msg.cwd.slice(-maxLen)}` : msg.cwd
75
+ }
76
+ break
77
+
78
+ case 'chunk':
79
+ appendChunk(msg.text || '')
80
+ break
81
+
82
+ case 'thinking':
83
+ showThinking(msg.text || '')
84
+ break
85
+
86
+ case 'thinking_end':
87
+ hideThinking()
88
+ break
89
+
90
+ case 'tool_call':
91
+ addToolCall(msg.name, msg.input, msg.id)
92
+ break
93
+
94
+ case 'tool_result':
95
+ if (msg.success) {
96
+ addToolResult(msg.name, true, msg.output || '', msg.id)
97
+ } else {
98
+ addToolResult(msg.name, false, msg.error || 'Unknown error', msg.id)
99
+ }
100
+ break
101
+
102
+ case 'turn_start':
103
+ setStatus(true)
104
+ startAssistantMessage()
105
+ break
106
+
107
+ case 'turn_end':
108
+ hideThinking()
109
+ for (const [, el] of pendingToolCalls) el.classList.remove('executing')
110
+ pendingToolCalls.clear()
111
+ finalizeAssistantMessage()
112
+ break
113
+
114
+ case 'done':
115
+ setStatus(false)
116
+ hideThinking()
117
+ for (const [, el] of pendingToolCalls) el.classList.remove('executing')
118
+ pendingToolCalls.clear()
119
+ finalizeAssistantMessage()
120
+ if (msg.reason === 'error') {
121
+ addErrorMessage('An error occurred during processing.')
122
+ }
123
+ break
124
+
125
+ case 'mode_changed':
126
+ state.currentMode = msg.mode
127
+ modeDisplay.textContent = state.currentMode
128
+ addSystemMessage(`Switched to ${state.currentMode} mode`)
129
+ break
130
+
131
+ case 'model_changed':
132
+ state.currentModel = msg.model
133
+ modelDisplay.textContent = `${state.currentProvider}/${state.currentModel}`
134
+ addSystemMessage(`Model switched to ${state.currentModel}`)
135
+ break
136
+
137
+ case 'session_cleared':
138
+ messagesEl.innerHTML = ''
139
+ addSystemMessage('Session cleared. Starting fresh.')
140
+ break
141
+
142
+ case 'help':
143
+ if (Array.isArray(msg.commands)) {
144
+ addSystemMessage('Available commands:')
145
+ msg.commands.forEach(cmd => addSystemMessage(cmd))
146
+ }
147
+ break
148
+
149
+ case 'compaction':
150
+ addSystemMessage(`📦 Compressed context: ${msg.before} → ${msg.after} messages`)
151
+ break
152
+
153
+ case 'plan_written':
154
+ addSystemMessage(`📝 Plan written: ${msg.display || ''}`)
155
+ break
156
+
157
+ case 'session_history':
158
+ renderSessionHistory(msg.messages)
159
+ setTimeout(scrollToBottom, 50)
160
+ break
161
+
162
+ case 'plan_data':
163
+ state.plans = msg.plans || []
164
+ state.currentPlanName = msg.currentPlanName || ''
165
+ state.todos = msg.todos || []
166
+ updatePlansAndTodos()
167
+ break
168
+
169
+ case 'balance_update':
170
+ if (msg.webBalance) {
171
+ balanceDisplay.textContent = `余额:${msg.webBalance}`
172
+ balanceDisplay.style.display = ''
173
+ balanceSep.style.display = ''
174
+ } else if (msg.balance) {
175
+ balanceDisplay.textContent = `余额:${msg.balance}`
176
+ balanceDisplay.style.display = ''
177
+ balanceSep.style.display = ''
178
+ }
179
+ break
180
+
181
+ case 'token_stats':
182
+ addTokenStats(
183
+ msg.turnIn,
184
+ msg.turnOut,
185
+ msg.totalIn,
186
+ msg.totalOut,
187
+ msg.turnApi,
188
+ msg.totalApi,
189
+ msg.totalCacheHit,
190
+ msg.totalCacheMiss,
191
+ )
192
+ break
193
+
194
+ case 'tool_confirm_request': {
195
+ if (!msg.toolCalls || msg.toolCalls.length === 0) break
196
+ showConfirmDialog(msg.toolCalls)
197
+ break
198
+ }
199
+
200
+ case 'error':
201
+ closeConfirmDialog()
202
+ addErrorMessage(msg.message || 'Unknown error')
203
+ break
204
+
205
+ case 'pong':
206
+ break
207
+
208
+ default:
209
+ console.log('Unknown message type:', msg.type)
210
+ }
211
+ }
212
+
213
+ export function connect() {
214
+ connectionOverlay.classList.remove('hidden')
215
+
216
+ let ws
217
+ try {
218
+ ws = new WebSocket(getWsUrl())
219
+ setWs(ws)
220
+ } catch (err) {
221
+ connectionOverlay.classList.add('hidden')
222
+ addErrorMessage(`Connection failed: ${err.message}`)
223
+ return
224
+ }
225
+
226
+ ws.onopen = () => {
227
+ connectionOverlay.classList.add('hidden')
228
+ state.reconnectAttempts = 0
229
+ addSystemMessage('Connected to Lonny')
230
+ }
231
+
232
+ ws.onmessage = event => {
233
+ try {
234
+ const msg = JSON.parse(event.data)
235
+ handleMessage(msg)
236
+ } catch (err) {
237
+ console.error('Failed to parse message:', err)
238
+ }
239
+ }
240
+
241
+ ws.onclose = () => {
242
+ setStatus(false)
243
+ hideThinking()
244
+ for (const [, el] of pendingToolCalls) el.classList.remove('executing')
245
+ pendingToolCalls.clear()
246
+ if (state.streamingMsgEl) {
247
+ finalizeAssistantMessage()
248
+ }
249
+
250
+ if (state.reconnectAttempts < MAX_RECONNECT_ATTEMPTS) {
251
+ state.reconnectAttempts++
252
+ const delay = RECONNECT_DELAY * Math.min(state.reconnectAttempts, 5)
253
+ connectionOverlay.querySelector('p').textContent =
254
+ `Reconnecting in ${delay / 1000}s... (attempt ${state.reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS})`
255
+ connectionOverlay.classList.remove('hidden')
256
+ setTimeout(connect, delay)
257
+ } else {
258
+ connectionOverlay.querySelector('p').textContent = 'Connection lost. Please refresh the page.'
259
+ connectionOverlay.classList.remove('hidden')
260
+ addErrorMessage('Connection lost. Refresh the page to reconnect.')
261
+ }
262
+ }
263
+
264
+ ws.onerror = () => {
265
+ // onclose will fire after this
266
+ }
267
+ }
@@ -0,0 +1,19 @@
1
+ /* ── WebSocket Reference & Send ── */
2
+
3
+ let ws = null
4
+
5
+ export function getWs() {
6
+ return ws
7
+ }
8
+
9
+ export function setWs(newWs) {
10
+ ws = newWs
11
+ }
12
+
13
+ export function sendWsMsg(data) {
14
+ if (ws && ws.readyState === WebSocket.OPEN) {
15
+ ws.send(JSON.stringify(data))
16
+ return true
17
+ }
18
+ return false
19
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"session-bridge.d.ts","sourceRoot":"","sources":["../../src/web/session-bridge.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAYhD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED,MAAM,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,SAAS,KAAK,IAAI,CAAA;AAI7C,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX;IAAE,KAAK,EAAE,MAAM,IAAI,CAAC;IAAC,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CAsKrE"}
1
+ {"version":3,"file":"session-bridge.d.ts","sourceRoot":"","sources":["../../src/web/session-bridge.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAYhD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED,MAAM,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,SAAS,KAAK,IAAI,CAAA;AAI7C,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX;IAAE,KAAK,EAAE,MAAM,IAAI,CAAC;IAAC,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CAqKrE"}
@@ -20,6 +20,8 @@ export function startSessionBridge(session, config, send) {
20
20
  totalIn: session.totalInputTokens,
21
21
  totalOut: session.totalOutputTokens,
22
22
  totalApi: session.totalApiCalls,
23
+ totalCacheHit: session.totalCacheHitTokens || undefined,
24
+ totalCacheMiss: session.totalCacheMissTokens || undefined,
23
25
  });
24
26
  // ── Subscribe to EventBus ──
25
27
  const unsubTurnStart = bus.on(EventChannels.TURN_START, data => {
@@ -37,7 +39,7 @@ export function startSessionBridge(session, config, send) {
37
39
  name: d.name,
38
40
  id: d.id,
39
41
  success: true,
40
- output: stripAnsi(d.output),
42
+ output: d.name === 'edit' ? d.output : stripAnsi(d.output),
41
43
  });
42
44
  });
43
45
  const unsubToolError = bus.on(EventChannels.TOOL_ERROR, data => {
@@ -86,12 +88,6 @@ export function startSessionBridge(session, config, send) {
86
88
  send({ type: 'model_changed', model: arg });
87
89
  return;
88
90
  }
89
- if (cmd === 'new') {
90
- const { Session } = await import('../agent/session.js');
91
- Session.clearSavedSession(config.cwd);
92
- send({ type: 'session_cleared' });
93
- return;
94
- }
95
91
  if (cmd === 'help') {
96
92
  send({
97
93
  type: 'help',
@@ -1 +1 @@
1
- {"version":3,"file":"session-bridge.js","sourceRoot":"","sources":["../../src/web/session-bridge.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session-bridge.js","sourceRoot":"","sources":["../../src/web/session-bridge.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,54 +1,55 @@
1
- {
2
- "name": "lonny-agent",
3
- "version": "0.2.4",
4
- "license": "MIT",
5
- "repository": "github:as3long/lonny-agent",
6
- "description": "AI coding agent that does more with fewer API calls, optimized for Coding Plan (5h 1200-call bundle)",
7
- "type": "module",
8
- "bin": {
9
- "lonny": "./dist/index.js"
10
- },
11
- "scripts": {
12
- "build": "tsc && npm run copy:web && npm run copy:native",
13
- "copy:web": "node -e \"const fs=require('fs'),p=require('path');const src=p.join('src','web','public');const dst=p.join('dist','web','public');if(fs.existsSync(src)){if(!fs.existsSync(dst))fs.mkdirSync(dst,{recursive:true});for(const f of fs.readdirSync(src)){fs.copyFileSync(p.join(src,f),p.join(dst,f))}}\"",
14
- "copy:native": "node -e \"const fs=require('fs'),p=require('path');function cpDir(s,d){fs.mkdirSync(d,{recursive:true});for(const e of fs.readdirSync(s)){const sp=p.join(s,e),dp=p.join(d,e);fs.statSync(sp).isDirectory()?cpDir(sp,dp):fs.copyFileSync(sp,dp)}}const src=p.join('src','pi-tui','native');const dst=p.join('dist','pi-tui','native');if(fs.existsSync(src))cpDir(src,dst)\"",
15
- "dev": "tsx src/index.ts",
16
- "start": "node dist/index.js",
17
- "test": "vitest run",
18
- "test:watch": "vitest",
19
- "lint": "biome lint .",
20
- "lint:fix": "biome lint --fix .",
21
- "format": "biome format --write .",
22
- "check": "biome check .",
23
- "check:fix": "biome check --fix .",
24
- "prepare": "husky"
25
- },
26
- "lint-staged": {
27
- "*.{ts,js,mjs}": [
28
- "biome check --fix --no-errors-on-unmatched"
29
- ],
30
- "*.{json,jsonc}": [
31
- "biome format --write --no-errors-on-unmatched"
32
- ]
33
- },
34
- "dependencies": {
35
- "@anthropic-ai/sdk": "^0.30.0",
36
- "adm-zip": "^0.5.17",
37
- "get-east-asian-width": "1.6.0",
38
- "marked": "15.0.12",
39
- "commander": "^12.0.0",
40
- "openai": "^4.0.0",
41
- "ws": "^8.21.0",
42
- "zod": "^3.23.0"
43
- },
44
- "devDependencies": {
45
- "@biomejs/biome": "^2.4.15",
46
- "@types/node": "^22.19.19",
47
- "@types/ws": "^8.18.1",
48
- "husky": "^9.1.7",
49
- "lint-staged": "^17.0.5",
50
- "tsx": "^4.19.0",
51
- "typescript": "^5.6.0",
52
- "vitest": "^2.1.0"
53
- }
54
- }
1
+ {
2
+ "name": "lonny-agent",
3
+ "version": "0.2.6",
4
+ "license": "MIT",
5
+ "repository": "github:as3long/lonny-agent",
6
+ "description": "AI coding agent that does more with fewer API calls, optimized for Coding Plan (5h 1200-call bundle)",
7
+ "type": "module",
8
+ "bin": {
9
+ "lonny": "./dist/index.js"
10
+ },
11
+ "scripts": {
12
+ "build": "tsc && npm run copy:web && npm run copy:native",
13
+ "copy:web": "node scripts/copy-web.mjs",
14
+ "copy:native": "node scripts/copy-native.mjs",
15
+ "dev": "tsx src/index.ts",
16
+ "start": "node dist/index.js",
17
+ "test": "vitest run",
18
+ "test:watch": "vitest",
19
+ "lint": "biome lint .",
20
+ "lint:fix": "biome lint --fix .",
21
+ "format": "biome format --write .",
22
+ "check": "biome check .",
23
+ "check:fix": "biome check --fix .",
24
+ "prepare": "husky"
25
+ },
26
+ "lint-staged": {
27
+ "*.{ts,js,mjs}": [
28
+ "biome check --fix --no-errors-on-unmatched"
29
+ ],
30
+ "*.{json,jsonc}": [
31
+ "biome format --write --no-errors-on-unmatched"
32
+ ]
33
+ },
34
+ "dependencies": {
35
+ "@anthropic-ai/sdk": "^0.30.0",
36
+ "adm-zip": "^0.5.17",
37
+ "commander": "^12.0.0",
38
+ "get-east-asian-width": "1.6.0",
39
+ "jest-diff": "^30.4.1",
40
+ "marked": "15.0.12",
41
+ "openai": "^4.0.0",
42
+ "ws": "^8.21.0",
43
+ "zod": "^3.23.0"
44
+ },
45
+ "devDependencies": {
46
+ "@biomejs/biome": "^2.4.15",
47
+ "@types/node": "^22.19.19",
48
+ "@types/ws": "^8.18.1",
49
+ "husky": "^9.1.7",
50
+ "lint-staged": "^17.0.5",
51
+ "tsx": "^4.19.0",
52
+ "typescript": "^5.6.0",
53
+ "vitest": "^2.1.0"
54
+ }
55
+ }
@@ -0,0 +1,24 @@
1
+ // copy:native — recursively copies src/pi-tui/native/ to dist/pi-tui/native/
2
+ import { copyFileSync, existsSync, mkdirSync, readdirSync, statSync } from 'fs'
3
+ import { join } from 'path'
4
+ import { fileURLToPath } from 'url'
5
+
6
+ const __dirname = fileURLToPath(new URL('..', import.meta.url))
7
+
8
+ function cpDir(s, d) {
9
+ mkdirSync(d, { recursive: true })
10
+ for (const e of readdirSync(s)) {
11
+ const sp = join(s, e)
12
+ const dp = join(d, e)
13
+ if (statSync(sp).isDirectory()) {
14
+ cpDir(sp, dp)
15
+ } else {
16
+ copyFileSync(sp, dp)
17
+ }
18
+ }
19
+ }
20
+
21
+ const src = join(__dirname, 'src', 'pi-tui', 'native')
22
+ const dst = join(__dirname, 'dist', 'pi-tui', 'native')
23
+
24
+ if (existsSync(src)) cpDir(src, dst)
@@ -0,0 +1,15 @@
1
+ // copy:web — copies src/web/public/ to dist/web/public/
2
+ import { copyFileSync, existsSync, mkdirSync, readdirSync } from 'fs'
3
+ import { join } from 'path'
4
+ import { fileURLToPath } from 'url'
5
+
6
+ const __dirname = fileURLToPath(new URL('..', import.meta.url))
7
+ const src = join(__dirname, 'src', 'web', 'public')
8
+ const dst = join(__dirname, 'dist', 'web', 'public')
9
+
10
+ if (existsSync(src)) {
11
+ if (!existsSync(dst)) mkdirSync(dst, { recursive: true })
12
+ for (const f of readdirSync(src)) {
13
+ copyFileSync(join(src, f), join(dst, f))
14
+ }
15
+ }
@@ -1,25 +1,25 @@
1
- import * as readline from 'node:readline'
2
- import type { Config } from '../config/index.js'
3
- import { Session, type SessionOutput } from './session.js'
4
-
5
- export async function runAgent(prompt: string, config: Config): Promise<void> {
6
- const output: SessionOutput = {
7
- write: text => process.stdout.write(text),
8
- confirmTool: async toolCalls => {
9
- console.log('\nAllow these tool calls?')
10
- for (const tc of toolCalls) {
11
- const input = JSON.stringify(tc.input)
12
- console.log(` \u2022 ${tc.name}: ${input.slice(0, 120)}`)
13
- }
14
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout })
15
- return new Promise(resolve => {
16
- rl.question(' (y/N) ', answer => {
17
- rl.close()
18
- resolve(answer.trim().toLowerCase() === 'y')
19
- })
20
- })
21
- },
22
- }
23
- const session = (await Session.load(config, output)) || new Session(config, output)
24
- await session.chat(prompt)
25
- }
1
+ import * as readline from 'node:readline'
2
+ import type { Config } from '../config/index.js'
3
+ import { Session, type SessionOutput } from './session.js'
4
+
5
+ export async function runAgent(prompt: string, config: Config): Promise<void> {
6
+ const output: SessionOutput = {
7
+ write: text => process.stdout.write(text),
8
+ confirmTool: async toolCalls => {
9
+ console.log('\nAllow these tool calls?')
10
+ for (const tc of toolCalls) {
11
+ const input = JSON.stringify(tc.input)
12
+ console.log(` \u2022 ${tc.name}: ${input.slice(0, 120)}`)
13
+ }
14
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout })
15
+ return new Promise(resolve => {
16
+ rl.question(' (y/N) ', answer => {
17
+ rl.close()
18
+ resolve(answer.trim().toLowerCase() === 'y')
19
+ })
20
+ })
21
+ },
22
+ }
23
+ const session = (await Session.load(config, output)) || new Session(config, output)
24
+ await session.chat(prompt)
25
+ }
package/src/agent/llm.ts CHANGED
@@ -20,6 +20,10 @@ export interface LLMProvider {
20
20
  export interface TokenUsage {
21
21
  input_tokens: number
22
22
  output_tokens: number
23
+ /** DeepSeek-specific: tokens read from cache */
24
+ prompt_cache_hit_tokens?: number
25
+ /** DeepSeek-specific: tokens not in cache */
26
+ prompt_cache_miss_tokens?: number
23
27
  }
24
28
 
25
29
  export interface LLMChunk {
@@ -49,13 +49,12 @@ export async function buildSystemPrompt(config: Config): Promise<string> {
49
49
  - \`glob\`: Find files by glob pattern (pattern: string)
50
50
  - \`grep\`: Search file content by regex (pattern: string, include?: string, path?: string)
51
51
  - \`ls\`: List directory (path?: string)
52
- - \`bash\`: Execute a shell command
53
- - \`edit\`: Replace text in files call with {edits: [{file_path: string, old_string: string, new_string: string}]} (array required)
52
+ - \`bash\`: Execute a shell command — for running commands (NOT for creating or modifying files — use \`edit\` for that)
53
+ - \`edit\`: Replace text in files using markdown code block format. Use: \`edit({ content: "\`\`\`edit\\nfile: path\\nold: |\\ntext\\nnew: |\\ntext\\n\`\`\`" })\`
54
54
  - \`install_skill\`: Install an npm package as a skill — fetches package info from npm, runs npm install, and creates a .lonny/skills/ file with usage instructions for the AI
55
55
  - \`find\`: Find files by name pattern (pattern: string, path?: string, maxResults?: number)
56
56
  - \`git\`: Run read-only git commands (command: string)
57
57
  - \`search\`: Search the web using Tavily (query: string, search_depth?: string, include_answer?: boolean, max_results?: number, topic?: string, days?: number)
58
- - \`exec\`: Run JavaScript in a sandbox to orchestrate multiple tool calls — all tools are available as \`await tools.xxx(args)\` inside exec (code mode only)
59
58
  `
60
59
  }
61
60
 
@@ -64,8 +63,7 @@ export async function buildSystemPrompt(config: Config): Promise<string> {
64
63
  RULES:
65
64
  1. Read first: Use read/grep/glob tools to gather all context you need before making any edits.
66
65
  2. Be thorough: Explore the relevant parts of the codebase.
67
- 3. COST OPTIMIZATION (CRITICAL): Each API call costs money. You MUST maximize work per call. Use \`read(paths: [...])\` to read multiple files at once. Use \`edit({edits: [...]})\` to edit multiple files at once. Do NOT do sequential single-file reads or single-edit calls.
68
- 4. When using \`edit\`, the \`edits\` value MUST be an array — even for a single change. Do NOT pass empty objects.
66
+ 3. COST OPTIMIZATION (CRITICAL): Each API call costs money. You MUST maximize work per call. Use \`read(paths: [...])\` to read multiple files at once. Use \`edit({ content: "..." })\` with multiple \`\`\`edit blocks to edit multiple files at once.
69
67
 
70
68
  ${getToolListForMode(config.mode)}`
71
69
 
@@ -74,7 +72,7 @@ ${getToolListForMode(config.mode)}`
74
72
  config.mode === 'plan'
75
73
  ? `You are a planning agent. Your ONLY job is to investigate the codebase and produce an actionable implementation plan with a todo list.
76
74
 
77
- You CANNOT edit files. You do NOT have access to edit, bash (write mode), exec, or install_skill.
75
+ You CANNOT edit files. You do NOT have access to edit, bash (write mode), or install_skill.
78
76
  Any attempt to call these tools will FAIL — they are simply unavailable in this mode.
79
77
 
80
78
  RULES (plan-specific):
@@ -116,9 +114,15 @@ RULES (ask-specific):
116
114
 
117
115
  RULES (code-specific):
118
116
  1. Read first: Use read/grep/glob tools to gather all context you need BEFORE making any edits. The \`read\` output prefixes each line with "<lineNumber>: " for easy reference. Do NOT include the "N: " prefix when copying text into \`edit\`.
119
- 2. edit CALL FORMAT — you MUST call edit with exactly this JSON shape:
120
- { "edits": [{ "file_path": "src/file.ts", "old_string": "text to replace", "new_string": "replacement text" }] }
121
- The "edits" value is ALWAYS an array, even for a single edit. Do NOT pass file_path/old_string/new_string as top-level keys. Do NOT pass an empty object {}.
117
+ 2. edit CALL FORMAT — use markdown code block format:
118
+ \`\`\`edit
119
+ file: src/file.ts
120
+ old: |
121
+ text to replace
122
+ new: |
123
+ replacement text
124
+ \`\`\`
125
+ Use separate \`\`\`edit blocks for multiple files.
122
126
  3. After making edits to a file, if you need to make ANOTHER edit to the SAME file, you MUST re-read it first to get the updated content.
123
127
  4. If \`edit\` reports \`old_string not found\`, do NOT retry with the same old_string — re-read the file immediately to see its actual current content, then retry with correctly-copied text.
124
128
  5. When copying old_string from \`read\` output, include 2-3 lines of context BEFORE and AFTER the target change to make the string unique in the file.