Skip to content

Commit 65932f5

Browse files
committed
Merge remote-tracking branch 'origin/main' into brandon/upgrade-opentui-2025-10-28
# Conflicts: # cli/src/chat.tsx
2 parents 00a9acd + 29d0165 commit 65932f5

File tree

22 files changed

+219
-193
lines changed

22 files changed

+219
-193
lines changed

bun.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cli/src/chat.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,27 @@ export const App = ({
393393
})
394394
}
395395

396+
blocks.push({
397+
type: 'html',
398+
render: () => (
399+
<text style={{ wrapMode: 'word' }}>
400+
<span fg={baseTextColorValue}>
401+
Codebuff can read and write files in{' '}
402+
<TerminalLink
403+
text={displayPath}
404+
color="#3b82f6"
405+
inline={true}
406+
underlineOnHover={true}
407+
onActivate={() => openFileAtPath(repoRoot)}
408+
/>
409+
, and run terminal commands to help you build.
410+
</span>
411+
</text>
412+
),
413+
})
414+
415+
416+
396417
blocks.push({
397418
type: 'html',
398419
render: () => (

cli/src/project-files.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { mkdirSync } from 'fs'
22
import path from 'path'
33

44
import { findGitRoot } from './utils/git'
5+
import { getConfigDir } from './utils/auth'
56

67
let projectRoot: string | undefined
78
let currentChatId: string | undefined
@@ -34,10 +35,22 @@ export function startNewChat() {
3435
return currentChatId
3536
}
3637

38+
// Get the project-specific data directory
39+
export function getProjectDataDir(): string {
40+
const root = getProjectRoot()
41+
if (!root) {
42+
throw new Error('Project root not set')
43+
}
44+
45+
const baseName = path.basename(root)
46+
const baseDir = path.join(getConfigDir(), 'projects', baseName)
47+
48+
return baseDir
49+
}
50+
3751
export function getCurrentChatDir() {
38-
const root = getProjectRoot() || process.cwd()
3952
const chatId = getCurrentChatId()
40-
const dir = path.join(root, 'debug', 'chats', chatId)
53+
const dir = path.join(getProjectDataDir(), 'chats', chatId)
4154
ensureChatDirectory(dir)
4255
return dir
4356
}

cli/src/utils/logger.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -103,13 +103,7 @@ function sendAnalyticsAndLog(
103103
const logTarget =
104104
env.NEXT_PUBLIC_CB_ENVIRONMENT === 'dev'
105105
? path.join(projectRoot, 'debug', 'cli.log')
106-
: (() => {
107-
try {
108-
return path.join(getCurrentChatDir(), 'log.jsonl')
109-
} catch {
110-
return path.join(projectRoot, 'debug', 'cli.log')
111-
}
112-
})()
106+
: path.join(getCurrentChatDir(), 'log.jsonl')
113107

114108
setLogPath(logTarget)
115109
}

common/src/analytics.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import { env } from '@codebuff/common/env'
21
import { PostHog } from 'posthog-node'
32

3+
import { env } from '@codebuff/common/env'
4+
45
import type { AnalyticsEvent } from './constants/analytics-events'
56
import type { Logger } from '@codebuff/common/types/contracts/logger'
67

@@ -52,11 +53,14 @@ export function trackEvent({
5253
}
5354

5455
if (!client) {
55-
logger.warn(
56-
{ event, userId },
57-
'Analytics client not initialized, skipping event tracking',
58-
)
59-
return
56+
initAnalytics({ logger })
57+
if (!client) {
58+
logger.warn(
59+
{ event, userId },
60+
'Analytics client not initialized, skipping event tracking',
61+
)
62+
return
63+
}
6064
}
6165

6266
try {

common/src/env-schema.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ export const clientEnvSchema = z.object({
77
NEXT_PUBLIC_CODEBUFF_APP_URL: z.url().min(1),
88
NEXT_PUBLIC_CODEBUFF_BACKEND_URL: z.string().min(1),
99
NEXT_PUBLIC_SUPPORT_EMAIL: z.email().min(1),
10-
NEXT_PUBLIC_POSTHOG_API_KEY: z.string().optional().default(''),
11-
NEXT_PUBLIC_POSTHOG_HOST_URL: z.url().optional(),
10+
NEXT_PUBLIC_POSTHOG_API_KEY: z.string().default(''),
11+
NEXT_PUBLIC_POSTHOG_HOST_URL: z.url(),
1212
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: z.string().min(1),
1313
NEXT_PUBLIC_STRIPE_CUSTOMER_PORTAL: z.url().min(1),
1414
NEXT_PUBLIC_LINKEDIN_PARTNER_ID: z.string().optional(),

common/src/types/contracts/logger.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@ export type Logger = {
1010
warn: LoggerFn
1111
error: LoggerFn
1212
}
13+
14+
export type LoggerWithContextFn = (context: Record<string, any>) => Logger

packages/agent-runtime/src/run-programmatic-step.ts

Lines changed: 22 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { getErrorObject } from '@codebuff/common/util/error'
33
import { cloneDeep } from 'lodash'
44

55
import { executeToolCall } from './tools/tool-executor'
6-
import { SandboxManager } from './util/quickjs-sandbox'
76

87
import type { CodebuffToolCall } from '@codebuff/common/tools/list'
98
import type {
@@ -17,34 +16,24 @@ import type {
1716
} from '@codebuff/common/types/contracts/client'
1817
import type { AddAgentStepFn } from '@codebuff/common/types/contracts/database'
1918
import type { Logger } from '@codebuff/common/types/contracts/logger'
20-
import type {
21-
ParamsExcluding,
22-
ParamsOf,
23-
} from '@codebuff/common/types/function-params'
19+
import type { ParamsExcluding } from '@codebuff/common/types/function-params'
2420
import type {
2521
ToolResultOutput,
2622
ToolResultPart,
2723
} from '@codebuff/common/types/messages/content-part'
2824
import type { PrintModeEvent } from '@codebuff/common/types/print-mode'
2925
import type { AgentState } from '@codebuff/common/types/session-state'
3026

31-
// Global sandbox manager for QuickJS contexts
32-
const sandboxManager = new SandboxManager()
33-
3427
// Maintains generator state for all agents. Generator state can't be serialized, so we store it in memory.
3528
const runIdToGenerator: Record<string, StepGenerator | undefined> = {}
3629
export const runIdToStepAll: Set<string> = new Set()
3730

3831
// Function to clear the generator cache for testing purposes
39-
export function clearAgentGeneratorCache(
40-
params: ParamsOf<typeof sandboxManager.dispose>,
41-
) {
32+
export function clearAgentGeneratorCache(params: { logger: Logger }) {
4233
for (const key in runIdToGenerator) {
4334
delete runIdToGenerator[key]
4435
}
4536
runIdToStepAll.clear()
46-
// Clean up QuickJS sandboxes
47-
sandboxManager.dispose(params)
4837
}
4938

5039
// Function to handle programmatic agents
@@ -129,10 +118,9 @@ export async function runProgrammaticStep(
129118

130119
// Run with either a generator or a sandbox.
131120
let generator = runIdToGenerator[agentState.runId]
132-
let sandbox = sandboxManager.getSandbox({ runId: agentState.runId })
133121

134122
// Check if we need to initialize a generator
135-
if (!generator && !sandbox) {
123+
if (!generator) {
136124
const createLogMethod =
137125
(level: 'debug' | 'info' | 'warn' | 'error') =>
138126
(data: any, msg?: string) => {
@@ -153,31 +141,19 @@ export async function runProgrammaticStep(
153141
error: createLogMethod('error'),
154142
}
155143

156-
if (typeof template.handleSteps === 'string') {
157-
// Initialize QuickJS sandbox for string-based generator
158-
sandbox = await sandboxManager.getOrCreateSandbox({
159-
runId: agentState.runId,
160-
generatorCode: template.handleSteps,
161-
initialInput: {
162-
agentState,
163-
prompt,
164-
params: toolCallParams,
165-
logger: streamingLogger,
166-
},
167-
config: undefined, // config
168-
sandboxLogger: streamingLogger, // pass the streaming logger instance for internal use
169-
logger,
170-
})
171-
} else {
172-
// Initialize native generator
173-
generator = template.handleSteps({
174-
agentState,
175-
prompt,
176-
params,
177-
logger: streamingLogger,
178-
})
179-
runIdToGenerator[agentState.runId] = generator
180-
}
144+
const generatorFn =
145+
typeof template.handleSteps === 'string'
146+
? eval(`(${template.handleSteps})`)
147+
: template.handleSteps
148+
149+
// Initialize native generator
150+
generator = generatorFn({
151+
agentState,
152+
prompt,
153+
params: toolCallParams,
154+
logger: streamingLogger,
155+
})
156+
runIdToGenerator[agentState.runId] = generator
181157
}
182158

183159
// Check if we're in STEP_ALL mode
@@ -239,17 +215,11 @@ export async function runProgrammaticStep(
239215
creditsBefore = state.agentState.directCreditsUsed
240216
childrenBefore = state.agentState.childRunIds.length
241217

242-
const result = sandbox
243-
? await sandbox.executeStep({
244-
agentState: getPublicAgentState(state.agentState),
245-
toolResult,
246-
stepsComplete,
247-
})
248-
: generator!.next({
249-
agentState: getPublicAgentState(state.agentState),
250-
toolResult,
251-
stepsComplete,
252-
})
218+
const result = generator!.next({
219+
agentState: getPublicAgentState(state.agentState),
220+
toolResult,
221+
stepsComplete,
222+
})
253223

254224
if (result.done) {
255225
endTurn = true
@@ -263,7 +233,7 @@ export async function runProgrammaticStep(
263233
break
264234
}
265235

266-
if (result.value.type === 'STEP_TEXT') {
236+
if ('type' in result.value && result.value.type === 'STEP_TEXT') {
267237
textOverride = result.value.text
268238
break
269239
}
@@ -464,10 +434,6 @@ export async function runProgrammaticStep(
464434
}
465435
} finally {
466436
if (endTurn) {
467-
if (sandbox) {
468-
// Clean up QuickJS sandbox if execution is complete
469-
sandboxManager.removeSandbox({ runId: agentState.runId, logger })
470-
}
471437
delete runIdToGenerator[agentState.runId]
472438
runIdToStepAll.delete(agentState.runId)
473439
}

sdk/src/client.ts

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import { BACKEND_URL, WEBSITE_URL, WEBSOCKET_URL, IS_DEV, IS_TEST, IS_PROD } from './constants'
1+
import { BACKEND_URL, WEBSITE_URL } from './constants'
22
import { run } from './run'
33
import { API_KEY_ENV_VAR } from '../../common/src/old-constants'
4-
import { env } from '@codebuff/common/env'
54

65
import type { RunOptions, CodebuffClientOptions } from './run'
76
import type { RunState } from './run-state'
@@ -82,29 +81,4 @@ export class CodebuffClient {
8281
return false
8382
}
8483
}
85-
86-
/**
87-
* [TEST] Get environment information from the SDK
88-
*
89-
* @returns Object containing SDK environment variables and computed constants
90-
*/
91-
public getEnvironmentInfo() {
92-
return {
93-
// Raw env vars
94-
rawEnv: {
95-
NEXT_PUBLIC_CB_ENVIRONMENT: env.NEXT_PUBLIC_CB_ENVIRONMENT,
96-
NEXT_PUBLIC_CODEBUFF_APP_URL: env.NEXT_PUBLIC_CODEBUFF_APP_URL,
97-
NEXT_PUBLIC_CODEBUFF_BACKEND_URL: env.NEXT_PUBLIC_CODEBUFF_BACKEND_URL,
98-
},
99-
// Computed constants
100-
computed: {
101-
WEBSITE_URL,
102-
BACKEND_URL,
103-
WEBSOCKET_URL,
104-
IS_DEV,
105-
IS_TEST,
106-
IS_PROD,
107-
},
108-
}
109-
}
11084
}

0 commit comments

Comments
 (0)