Skip to content

Commit 721d24d

Browse files
committed
Merge remote-tracking branch 'origin/main' into brandon/cli-input-fixes
# Conflicts: # cli/src/state/chat-store.ts
2 parents 4dfdf8f + 01d7aa0 commit 721d24d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1857
-1020
lines changed

.agents/__tests__/context-pruner.test.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -140,20 +140,20 @@ describe('context-pruner handleSteps', () => {
140140
const firstTerminalMessage = resultMessages.find(
141141
(m: any) =>
142142
m.role === 'tool' &&
143-
m.content?.toolName === 'run_terminal_command' &&
144-
m.content?.output?.[0]?.value?.command === 'command-1',
143+
m.toolName === 'run_terminal_command' &&
144+
m.content?.[0]?.value?.command === 'command-1',
145145
)
146146
expect(
147-
firstTerminalMessage?.content?.output?.[0]?.value?.stdoutOmittedForLength,
147+
firstTerminalMessage?.content?.[0]?.value?.stdoutOmittedForLength,
148148
).toBe(true)
149149

150150
// Check that recent terminal commands are preserved (but may be processed by large tool result pass)
151151
const recentTerminalMessage = resultMessages.find(
152152
(m: any) =>
153153
m.role === 'tool' &&
154-
m.content?.toolName === 'run_terminal_command' &&
155-
(m.content?.output?.[0]?.value?.command === 'command-7' ||
156-
m.content?.output?.[0]?.value?.message ===
154+
m.toolName === 'run_terminal_command' &&
155+
(m.content?.[0]?.value?.command === 'command-7' ||
156+
m.content?.[0]?.value?.message ===
157157
'[LARGE_TOOL_RESULT_OMITTED]'),
158158
)
159159
expect(recentTerminalMessage).toBeDefined()
@@ -181,17 +181,17 @@ describe('context-pruner handleSteps', () => {
181181

182182
// Large tool result should be simplified
183183
const largeResultMessage = resultMessages.find(
184-
(m: any) => m.role === 'tool' && m.content?.toolName === 'read_files',
184+
(m: any) => m.role === 'tool' && m.toolName === 'read_files',
185185
)
186-
expect(largeResultMessage?.content?.output?.[0]?.value?.message).toBe(
186+
expect(largeResultMessage?.content?.[0]?.value?.message).toBe(
187187
'[LARGE_TOOL_RESULT_OMITTED]',
188188
)
189189

190190
// Small tool result should be preserved
191191
const smallResultMessage = resultMessages.find(
192-
(m: any) => m.role === 'tool' && m.content?.toolName === 'code_search',
192+
(m: any) => m.role === 'tool' && m.toolName === 'code_search',
193193
)
194-
expect(smallResultMessage?.content?.output?.[0]?.value?.data).toBe(
194+
expect(smallResultMessage?.content?.[0]?.value?.data).toBe(
195195
'Small result',
196196
)
197197
})
@@ -367,7 +367,7 @@ describe('context-pruner edge cases', () => {
367367
// Valid terminal command should be processed correctly
368368
const validCommand = resultMessages.find(
369369
(m: any) =>
370-
m.role === 'tool' && m.content?.toolName === 'run_terminal_command',
370+
m.role === 'tool' && m.toolName === 'run_terminal_command',
371371
)
372372
expect(validCommand).toBeDefined()
373373
})
@@ -481,7 +481,7 @@ describe('context-pruner edge cases', () => {
481481
const hasLargeToolResultReplacement = resultMessages.some(
482482
(m: any) =>
483483
m.role === 'tool' &&
484-
m.content?.output?.[0]?.value?.message ===
484+
m.content?.[0]?.value?.message ===
485485
'[LARGE_TOOL_RESULT_OMITTED]',
486486
)
487487
expect(hasLargeToolResultReplacement).toBe(true)

.agents/base2/base2.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ function buildImplementationStepPrompt({
404404
!isFast &&
405405
`You must spawn the ${useGeminiEditor ? 'editor-implementor-gemini' : isMax ? 'editor-best-of-n-gpt-5' : 'editor-best-of-n'} agent to implement code changes, since it will generate the best code changes.`,
406406
isMax && 'Spawn the thinker-best-of-n-gpt-5 to solve complex problems.',
407-
`After completing the user request, summarize your changes in a sentence${isFast ? '' : ' or a few short bullet points'}.${isSonnet ? " Don't create any summary markdown files or example documentation files, unless asked by the user." : ''}. Don't repeat yourself -- especially if you already summarized your changes then just end your turn.`,
407+
`After completing the user request, summarize your changes in a sentence${isFast ? '' : ' or a few short bullet points'}.${isSonnet ? " Don't create any summary markdown files or example documentation files, unless asked by the user." : ''}.`,
408408
).join('\n')
409409
}
410410

.agents/file-explorer/file-picker.ts

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ToolCall } from 'types/agent-definition'
1+
import { StepText, ToolCall } from 'types/agent-definition'
22
import { publisher } from '../constants'
33

44
import {
@@ -50,7 +50,7 @@ In your report, please give a very concise analysis that includes the full paths
5050
Do not use any further tools or spawn any further agents.
5151
`.trim(),
5252

53-
handleSteps: function* ({ prompt, params }) {
53+
handleSteps: function* ({ prompt, params, logger }) {
5454
const { toolResult: fileListerResults } = yield {
5555
toolName: 'spawn_agents',
5656
input: {
@@ -64,21 +64,46 @@ Do not use any further tools or spawn any further agents.
6464
},
6565
} satisfies ToolCall
6666

67-
const fileListerResult = fileListerResults?.[0]
68-
const filesStr =
69-
fileListerResult && fileListerResult.type === 'json'
70-
? ((fileListerResult.value as any)?.[0]?.value?.value as string)
71-
: ''
72-
const files = filesStr.split('\n').filter(Boolean)
67+
const filesResult =
68+
extractSpawnResults<{ text: string }[]>(fileListerResults)[0]
69+
if (!Array.isArray(filesResult)) {
70+
yield {
71+
type: 'STEP_TEXT',
72+
text: filesResult.errorMessage,
73+
} satisfies StepText
74+
return
75+
}
76+
77+
const paths = filesResult[0].text.split('\n').filter(Boolean)
7378

7479
yield {
7580
toolName: 'read_files',
7681
input: {
77-
paths: files,
82+
paths,
7883
},
7984
}
8085

8186
yield 'STEP'
87+
88+
function extractSpawnResults<T>(
89+
results: any[] | undefined,
90+
): (T | { errorMessage: string })[] {
91+
if (!results) return []
92+
const spawnedResults = results
93+
.filter((result) => result.type === 'json')
94+
.map((result) => result.value)
95+
.flat() as {
96+
agentType: string
97+
value: { value?: T; errorMessage?: string }
98+
}[]
99+
return spawnedResults.map(
100+
(result) =>
101+
result.value.value ?? {
102+
errorMessage:
103+
result.value.errorMessage ?? 'Error extracting spawn results',
104+
},
105+
)
106+
}
82107
},
83108
}
84109

cli/package.json

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,13 @@
1515
}
1616
},
1717
"scripts": {
18-
"dev": "./scripts/dev.sh",
19-
"prebuild": "bun run build:sdk",
20-
"build": "bun build src/index.tsx --outdir dist --target bun --format esm",
18+
"dev": "bun run src/index.tsx",
2119
"build:sdk": "cd ../sdk && bun run build",
22-
"build:sdk-types": "cd ../sdk && bun run build:types",
2320
"build:binary": "bun ./scripts/build-binary.ts codebuff $npm_package_version",
2421
"release": "bun run scripts/release.ts",
2522
"start": "bun run dist/index.js",
2623
"test": "bun test",
2724
"test:tmux-poc": "bun run src/__tests__/tmux-poc.ts",
28-
"pretypecheck": "bun run build:sdk-types",
2925
"typecheck": "tsc --noEmit -p ."
3026
},
3127
"sideEffects": false,

cli/release/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
{
22
"name": "codebuff",
3-
"version": "1.0.522",
3+
"version": "1.0.523",
44
"description": "AI coding agent",
55
"license": "MIT",
66
"bin": {
77
"codebuff": "index.js",
88
"cb": "index.js"
99
},
1010
"scripts": {
11-
"postinstall": "node -e \"const fs = require('fs'); const path = require('path'); const os = require('os'); const binaryPath = path.join(os.homedir(), '.config', 'manicode', process.platform === 'win32' ? 'codebuff.exe' : 'codebuff'); try { fs.unlinkSync(binaryPath) } catch (e) { /* ignore if file doesn't exist */ }\"",
11+
"postinstall": "node postinstall.js",
1212
"preuninstall": "node -e \"const fs = require('fs'); const path = require('path'); const os = require('os'); const binaryPath = path.join(os.homedir(), '.config', 'manicode', process.platform === 'win32' ? 'codebuff.exe' : 'codebuff'); try { fs.unlinkSync(binaryPath) } catch (e) { /* ignore if file doesn't exist */ }\""
1313
},
1414
"files": [
1515
"index.js",
16+
"postinstall.js",
1617
"README.md"
1718
],
1819
"os": [

cli/release/postinstall.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#!/usr/bin/env node
2+
3+
const fs = require('fs');
4+
const path = require('path');
5+
const os = require('os');
6+
7+
// Clean up old binary
8+
const binaryPath = path.join(
9+
os.homedir(),
10+
'.config',
11+
'manicode',
12+
process.platform === 'win32' ? 'codebuff.exe' : 'codebuff'
13+
);
14+
15+
try {
16+
fs.unlinkSync(binaryPath);
17+
} catch (e) {
18+
/* ignore if file doesn't exist */
19+
}
20+
21+
// Print welcome message
22+
console.log('\n');
23+
console.log('🎉 Welcome to Codebuff!');
24+
console.log('\n');
25+
console.log('To get started:');
26+
console.log(' 1. cd to your project directory');
27+
console.log(' 2. Run: codebuff');
28+
console.log('\n');
29+
console.log('Example:');
30+
console.log(' $ cd ~/my-project');
31+
console.log(' $ codebuff');
32+
console.log('\n');
33+
console.log('For more information, visit: https://codebuff.com/docs');
34+
console.log('\n');

cli/scripts/dev.sh

Lines changed: 0 additions & 9 deletions
This file was deleted.

cli/src/__tests__/integration/api-integration.test.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,23 @@ describe('API Integration', () => {
151151
// 401s are now logged as auth failures
152152
expect(testLogger.error.mock.calls.length).toBeGreaterThan(0)
153153
})
154+
155+
test('should treat 404 from /api/v1/me as invalid credentials (AuthenticationError)', async () => {
156+
setFetchMock(async () => {
157+
return new Response(null, { status: 404 })
158+
})
159+
const testLogger = createLoggerMocks()
160+
161+
await expect(
162+
getUserInfoFromApiKey({
163+
apiKey: 'not-found-token',
164+
fields: ['id'],
165+
logger: testLogger,
166+
}),
167+
).rejects.toBeInstanceOf(AuthenticationError)
168+
169+
expect(testLogger.error.mock.calls.length).toBeGreaterThan(0)
170+
})
154171
})
155172

156173
describe('P1: Error Response Handling', () => {

0 commit comments

Comments
 (0)