Skip to content

Commit 3aba28e

Browse files
authored
Merge branch 'CodebuffAI:main' into main
2 parents ff60949 + d6671e2 commit 3aba28e

File tree

10 files changed

+1196
-19
lines changed

10 files changed

+1196
-19
lines changed

backend/src/__tests__/run-programmatic-step.test.ts

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import {
2424
import { mockFileContext, MockWebSocket } from './test-utils'
2525
import * as toolExecutor from '../tools/tool-executor'
2626
import * as requestContext from '../websockets/request-context'
27+
import * as agentRun from '../agent-run'
28+
import * as websocketAction from '../websockets/websocket-action'
2729

2830
import type { AgentTemplate, StepGenerator } from '../templates/types'
2931
import type { PublicAgentState } from '@codebuff/common/types/agent-template'
@@ -40,6 +42,8 @@ describe('runProgrammaticStep', () => {
4042
let mockParams: any
4143
let executeToolCallSpy: any
4244
let getRequestContextSpy: any
45+
let addAgentStepSpy: any
46+
let sendActionSpy: any
4347

4448
beforeAll(() => {
4549
// Mock logger
@@ -74,6 +78,17 @@ describe('runProgrammaticStep', () => {
7478
processedRepoId: 'test-repo-id',
7579
}))
7680

81+
// Mock addAgentStep
82+
addAgentStepSpy = spyOn(agentRun, 'addAgentStep').mockImplementation(
83+
async () => 'test-step-id',
84+
)
85+
86+
// Mock sendAction
87+
sendActionSpy = spyOn(
88+
websocketAction,
89+
'sendAction',
90+
).mockImplementation(() => {})
91+
7792
// Mock crypto.randomUUID
7893
spyOn(crypto, 'randomUUID').mockImplementation(
7994
() =>
@@ -103,11 +118,14 @@ describe('runProgrammaticStep', () => {
103118
mockAgentState = {
104119
...sessionState.mainAgentState,
105120
agentId: 'test-agent-id',
121+
runId: 'test-run-id' as `${string}-${string}-${string}-${string}-${string}`,
106122
messageHistory: [
107123
{ role: 'user', content: 'Initial message' },
108124
{ role: 'assistant', content: 'Initial response' },
109125
],
110126
output: undefined,
127+
directCreditsUsed: 0,
128+
childRunIds: [],
111129
}
112130

113131
// Create mock params
@@ -124,6 +142,9 @@ describe('runProgrammaticStep', () => {
124142
assistantMessage: undefined,
125143
assistantPrefix: undefined,
126144
ws: new MockWebSocket() as unknown as WebSocket,
145+
localAgentTemplates: {},
146+
stepsComplete: false,
147+
stepNumber: 1,
127148
}
128149
})
129150

@@ -184,9 +205,10 @@ describe('runProgrammaticStep', () => {
184205
expect(result1.endTurn).toBe(false)
185206

186207
// Second call should return early due to STEP_ALL state
187-
const result2 = await runProgrammaticStep(mockAgentState, mockParams)
208+
// Use the same agent state with the same runId
209+
const result2 = await runProgrammaticStep(result1.agentState, mockParams)
188210
expect(result2.endTurn).toBe(false)
189-
expect(result2.agentState).toEqual(mockAgentState)
211+
expect(result2.agentState.agentId).toEqual(result1.agentState.agentId)
190212
})
191213

192214
it('should throw error when template has no handleStep', async () => {
@@ -215,12 +237,7 @@ describe('runProgrammaticStep', () => {
215237

216238
// Track chunks sent via sendSubagentChunk
217239
const sentChunks: string[] = []
218-
const originalSendAction =
219-
require('../websockets/websocket-action').sendAction
220-
const sendActionSpy = spyOn(
221-
require('../websockets/websocket-action'),
222-
'sendAction',
223-
).mockImplementation((ws: any, action: any) => {
240+
sendActionSpy.mockImplementation((ws: any, action: any) => {
224241
if (action.type === 'subagent-response-chunk') {
225242
sentChunks.push(action.chunk)
226243
}
@@ -619,7 +636,7 @@ describe('runProgrammaticStep', () => {
619636
// Verify STEP_ALL behavior
620637
expect(executeToolCallSpy).not.toHaveBeenCalled() // No tools should execute
621638
expect(result2.endTurn).toBe(false) // Should still not end turn
622-
expect(result2.agentState).toEqual(result1.agentState) // State should be unchanged
639+
expect(result2.agentState.agentId).toEqual(result1.agentState.agentId) // State should be similar
623640
expect(stepCount).toBe(1) // Generator should not have run again
624641

625642
// Third call - verify STEP_ALL state persists
@@ -629,7 +646,7 @@ describe('runProgrammaticStep', () => {
629646

630647
expect(executeToolCallSpy).not.toHaveBeenCalled()
631648
expect(result3.endTurn).toBe(false)
632-
expect(result3.agentState).toEqual(result1.agentState)
649+
expect(result3.agentState.agentId).toEqual(result1.agentState.agentId)
633650
expect(stepCount).toBe(1) // Generator should still not have run again
634651
})
635652

@@ -1120,7 +1137,7 @@ describe('runProgrammaticStep', () => {
11201137
expect(generatorCallCount).toBe(1)
11211138

11221139
// Second call with stepsComplete=false should return early due to STEP_ALL
1123-
const result2 = await runProgrammaticStep(mockAgentState, {
1140+
const result2 = await runProgrammaticStep(result1.agentState, {
11241141
...mockParams,
11251142
stepsComplete: false,
11261143
})
@@ -1134,7 +1151,7 @@ describe('runProgrammaticStep', () => {
11341151
}
11351152
})
11361153

1137-
const result3 = await runProgrammaticStep(mockAgentState, {
1154+
const result3 = await runProgrammaticStep(result2.agentState, {
11381155
...mockParams,
11391156
stepsComplete: true,
11401157
})

backend/src/__tests__/sandbox-generator.test.ts

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,20 @@ import {
22
getInitialAgentState,
33
type AgentState,
44
} from '@codebuff/common/types/session-state'
5-
import { afterEach, beforeEach, describe, expect, test } from 'bun:test'
5+
import { afterEach, beforeEach, describe, expect, test, spyOn } from 'bun:test'
6+
import {
7+
clearMockedModules,
8+
mockModule,
9+
} from '@codebuff/common/testing/mock-modules'
610

711
import {
812
clearAgentGeneratorCache,
913
runProgrammaticStep,
1014
} from '../run-programmatic-step'
1115
import { mockFileContext, MockWebSocket } from './test-utils'
16+
import * as agentRun from '../agent-run'
17+
import * as requestContext from '../websockets/request-context'
18+
import * as websocketAction from '../websockets/websocket-action'
1219

1320
import type { AgentTemplate } from '../templates/types'
1421
import type { WebSocket } from 'ws'
@@ -21,11 +28,39 @@ describe('QuickJS Sandbox Generator', () => {
2128
beforeEach(() => {
2229
clearAgentGeneratorCache()
2330

31+
// Mock dependencies
32+
spyOn(agentRun, 'addAgentStep').mockImplementation(
33+
async () => 'test-step-id',
34+
)
35+
spyOn(requestContext, 'getRequestContext').mockImplementation(() => ({
36+
processedRepoId: 'test-repo-id',
37+
}))
38+
spyOn(websocketAction, 'sendAction').mockImplementation(() => {})
39+
spyOn(crypto, 'randomUUID').mockImplementation(
40+
() =>
41+
'mock-uuid-0000-0000-0000-000000000000' as `${string}-${string}-${string}-${string}-${string}`,
42+
)
43+
44+
// Mock logger
45+
mockModule('@codebuff/backend/util/logger', () => ({
46+
logger: {
47+
debug: () => {},
48+
error: () => {},
49+
info: () => {},
50+
warn: () => {},
51+
},
52+
withLoggerContext: async (context: any, fn: () => Promise<any>) => fn(),
53+
}))
54+
2455
// Reuse common test data structure
2556
mockAgentState = {
2657
...getInitialAgentState(),
2758
agentId: 'test-agent-123',
2859
agentType: 'test-vm-agent',
60+
runId:
61+
'test-run-id' as `${string}-${string}-${string}-${string}-${string}`,
62+
directCreditsUsed: 0,
63+
childRunIds: [],
2964
}
3065

3166
// Base template structure - will be customized per test
@@ -62,11 +97,14 @@ describe('QuickJS Sandbox Generator', () => {
6297
assistantPrefix: undefined,
6398
ws: new MockWebSocket() as unknown as WebSocket,
6499
localAgentTemplates: {},
100+
stepsComplete: false,
101+
stepNumber: 1,
65102
}
66103
})
67104

68105
afterEach(() => {
69106
clearAgentGeneratorCache()
107+
clearMockedModules()
70108
})
71109

72110
test('should execute string-based generator in QuickJS sandbox', async () => {

backend/src/run-programmatic-step.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ export async function runProgrammaticStep(
188188
break
189189
}
190190
if (result.value === 'STEP_ALL') {
191-
runIdToStepAll.add(state.agentState.agentId)
191+
runIdToStepAll.add(state.agentState.runId)
192192
break
193193
}
194194

knowledge.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,25 @@ Codebuff is a tool for editing codebases via natural language instruction to Buf
5555
- ESC key to toggle menu or stop AI response
5656
- CTRL+C to exit the application
5757

58+
### Shell Shims (Direct Commands)
59+
60+
Codebuff supports shell shims for direct command invocation without the `codebuff` prefix.
61+
62+
- **Cross-platform**: Works on Windows (CMD/PowerShell), macOS, and Linux (bash/zsh/fish)
63+
- **Store integration**: Uses fully qualified agent IDs from the agent store
64+
- **Easy management**: Install, update, list, and uninstall shims via CLI commands### Quick Start (Recommended)
65+
66+
```bash
67+
# One-step setup: install and add to PATH automatically
68+
codebuff shims install codebuff/base-lite@1.0.0
69+
70+
# Use immediately in current session (follow the printed instruction)
71+
eval "$(codebuff shims env)"
72+
73+
# Now use direct commands!
74+
base-lite "fix this bug" # Works right away!
75+
```
76+
5877
## Package Management
5978

6079
- Use Bun for all package management operations
@@ -326,11 +345,13 @@ Templates are maintained in the codebuff community repo. Each directory correspo
326345
**Important**: When adding database indexes or schema changes, modify the schema file directly (`common/src/db/schema.ts`) using Drizzle's index syntax, then run the migration generation script to create the actual migration files.
327346

328347
**Do NOT** write migration SQL files directly. The proper workflow is:
348+
329349
1. Update `common/src/db/schema.ts` with new indexes using Drizzle syntax
330350
2. Run the migration generation script to create the SQL migration files
331351
3. Apply the migrations using the deployment process
332352

333353
Example of adding performance indexes:
354+
334355
```typescript
335356
index('idx_table_optimized')
336357
.on(table.column1, table.column2)

npm-app/release/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "codebuff",
3-
"version": "1.0.491",
3+
"version": "1.0.492",
44
"description": "AI coding agent",
55
"license": "MIT",
66
"bin": {

npm-app/src/cli-definitions.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,9 @@ export const cliOptions: CliParam[] = [
9393
menuDescription: 'Log subagent messages to trace files',
9494
hidden: false,
9595
},
96+
{
97+
flags: '--force',
98+
description: 'Force overwrite existing shims',
99+
hidden: true,
100+
},
96101
]

0 commit comments

Comments
 (0)