Skip to content

Commit 4f6a99d

Browse files
authored
Publish agent (Part 2) (#226)
1 parent 0ce0524 commit 4f6a99d

File tree

10 files changed

+1135
-41
lines changed

10 files changed

+1135
-41
lines changed

common/src/types/publisher.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,43 @@ export const PublisherSchema = z.object({
1818
})
1919

2020
export type PublisherInput = z.infer<typeof PublisherSchema>
21+
22+
export interface Publisher {
23+
id: string
24+
user_id: string
25+
name: string
26+
email: string | null
27+
verified: boolean
28+
bio: string | null
29+
avatar_url: string | null
30+
created_at: Date
31+
updated_at: Date
32+
}
33+
34+
export interface CreatePublisherRequest {
35+
id: string
36+
name: string
37+
email?: string
38+
bio?: string
39+
avatar_url?: string
40+
}
41+
42+
export interface UpdatePublisherRequest {
43+
name?: string
44+
email?: string
45+
bio?: string
46+
avatar_url?: string
47+
}
48+
49+
export interface PublisherProfileResponse {
50+
id: string
51+
user_id: string
52+
name: string
53+
email: string | null
54+
verified: boolean
55+
bio: string | null
56+
avatar_url: string | null
57+
created_at: Date
58+
updated_at: Date
59+
agentCount?: number
60+
}

npm-app/src/cli-handlers/publish.ts

Lines changed: 58 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import { DynamicAgentTemplate } from '@codebuff/common/types/dynamic-agent-template'
22
import * as fs from 'fs'
3-
import { green, red, yellow, cyan } from 'picocolors'
4-
import { websiteUrl } from '../config'
5-
import { logger } from '../utils/logger'
6-
import { loadLocalAgents } from '../agents/load-agents'
3+
import { cyan, green, red, yellow } from 'picocolors'
74
import { getAgentsDirectory } from '../agents/agent-utils'
5+
import { loadLocalAgents } from '../agents/load-agents'
6+
import { websiteUrl } from '../config'
87
import { getUserCredentials } from '../credentials'
98

109
interface PublishResponse {
@@ -13,6 +12,12 @@ interface PublishResponse {
1312
version?: string
1413
message?: string
1514
error?: string
15+
details?: string
16+
validationErrors?: Array<{
17+
code: string
18+
message: string
19+
path: (string | number)[]
20+
}>
1621
}
1722

1823
/**
@@ -106,34 +111,25 @@ interface PublishResponse {
106111
`❌ Error publishing ${template.displayName}: ${error instanceof Error ? error.message : String(error)}`
107112
)
108113
)
109-
logger.error(
110-
{
111-
error: error instanceof Error ? error.message : String(error),
112-
agentId: template.id,
113-
},
114-
'Error publishing agent template'
115-
)
114+
// Avoid logger.error here as it can cause sonic boom errors that mask the real error
115+
// The error is already displayed to the user via console.log above
116116
}
117117
} catch (error) {
118118
console.log(
119119
red(
120-
`Error during publish: ${error instanceof Error ? error.message : String(error)}`
120+
`Error during publish: ${error instanceof Error ? error.message + '\n' + error.stack : String(error)}`
121121
)
122122
)
123-
logger.error(
124-
{
125-
error: error instanceof Error ? error.message : String(error),
126-
},
127-
'Error during publish command'
128-
)
123+
// Avoid logger.error here as it can cause sonic boom errors that mask the real error
124+
// The error is already displayed to the user via console.log above
129125
}
130126
}
131127

132128
/**
133129
* Publish an agent template to the backend
134130
*/
135131
async function publishAgentTemplate(
136-
template: DynamicAgentTemplate,
132+
data: DynamicAgentTemplate,
137133
authToken: string
138134
): Promise<PublishResponse> {
139135
try {
@@ -144,17 +140,47 @@ async function publishAgentTemplate(
144140
Cookie: `next-auth.session-token=${authToken}`,
145141
},
146142
body: JSON.stringify({
147-
template,
143+
data,
148144
}),
149145
})
150146

151-
const result = await response.json()
147+
let result: any
148+
try {
149+
result = await response.json()
150+
} catch (jsonError) {
151+
return {
152+
success: false,
153+
error: `Failed to parse server response: ${response.status} ${response.statusText}`,
154+
}
155+
}
152156

153157
if (!response.ok) {
158+
// Extract detailed error information from the response
159+
let errorMessage =
160+
result.error || `HTTP ${response.status}: ${response.statusText}`
161+
162+
// If there are validation details, include them
163+
if (result.details) {
164+
errorMessage += `\n\nDetails: ${result.details}`
165+
}
166+
167+
// If there are specific validation errors, format them nicely
168+
if (result.validationErrors && Array.isArray(result.validationErrors)) {
169+
const formattedErrors = result.validationErrors
170+
.map((err: any) => {
171+
const path =
172+
err.path && err.path.length > 0 ? `${err.path.join('.')}: ` : ''
173+
return ` • ${path}${err.message}`
174+
})
175+
.join('\n')
176+
errorMessage += `\n\nValidation errors:\n${formattedErrors}`
177+
}
178+
154179
return {
155180
success: false,
156-
error:
157-
result.error || `HTTP ${response.status}: ${response.statusText}`,
181+
error: errorMessage,
182+
details: result.details,
183+
validationErrors: result.validationErrors,
158184
}
159185
}
160186

@@ -165,9 +191,17 @@ async function publishAgentTemplate(
165191
message: result.message,
166192
}
167193
} catch (error) {
194+
// Handle network errors, timeouts, etc.
195+
if (error instanceof TypeError && error.message.includes('fetch')) {
196+
return {
197+
success: false,
198+
error: `Network error: Unable to connect to ${websiteUrl}. Please check your internet connection and try again.`,
199+
}
200+
}
201+
168202
return {
169203
success: false,
170-
error: error instanceof Error ? error.message : String(error),
204+
error: `Unexpected error: ${error instanceof Error ? error.message : String(error)}`,
171205
}
172206
}
173207
}

npm-app/src/index.ts

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,23 @@ import { AnalyticsEvent } from '@codebuff/common/constants/analytics-events'
1010
import { displayLoadedAgents, loadLocalAgents } from './agents/load-agents'
1111
import { CLI } from './cli'
1212
import { cliArguments, cliOptions } from './cli-definitions'
13+
import { handlePublish } from './cli-handlers/publish'
1314
import { npmAppVersion } from './config'
1415
import { createTemplateProject } from './create-template-project'
15-
import { handlePublish } from './cli-handlers/publish'
1616
import { printModeLog, setPrintMode } from './display/print-mode'
17+
import { loadCodebuffConfig } from './json-config/parser'
1718
import {
18-
getStartingDirectory,
19+
getProjectRoot,
20+
getWorkingDirectory,
21+
initializeProjectRootAndWorkingDir,
1922
initProjectFileContextWithWorker,
20-
setProjectRoot,
21-
setWorkingDirectory,
2223
} from './project-files'
2324
import { rageDetectors } from './rage-detectors'
2425
import { logAndHandleStartup } from './startup-process-handler'
2526
import { recreateShell } from './terminal/run-command'
2627
import { CliOptions } from './types'
2728
import { initAnalytics, trackEvent } from './utils/analytics'
28-
import { findGitRoot } from './utils/git'
2929
import { logger } from './utils/logger'
30-
import { loadCodebuffConfig } from './json-config/parser'
3130

3231
async function codebuff({
3332
initialInput,
@@ -42,15 +41,8 @@ async function codebuff({
4241
trace,
4342
}: CliOptions) {
4443
enableSquashNewlines()
45-
46-
// Initialize starting directory
47-
const { cwd: workingDir, shouldSearch } = getStartingDirectory(cwd)
48-
const gitRoot = shouldSearch
49-
? findGitRoot(workingDir) ?? workingDir
50-
: workingDir
51-
const projectRoot = setProjectRoot(gitRoot)
52-
setWorkingDirectory(workingDir)
53-
44+
const workingDir = getWorkingDirectory()
45+
const projectRoot = getProjectRoot()
5446
await recreateShell(workingDir)
5547

5648
// Kill all processes we failed to kill before
@@ -130,6 +122,10 @@ For all commands and options, run 'codebuff' and then type 'help'.
130122

131123
const options = program.opts()
132124
const args = program.args // Handle template creation
125+
126+
// Initialize project root and working directory
127+
initializeProjectRootAndWorkingDir(options.cwd)
128+
133129
if (options.create) {
134130
const template = options.create
135131
const projectDir = args[0] || '.'

npm-app/src/project-files.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@ import {
2929
codebuffConfigFile,
3030
codebuffConfigFileBackup,
3131
} from '@codebuff/common/json-config/constants'
32-
import { loadCodebuffConfig } from './json-config/parser'
3332
import { loadedAgents, loadLocalAgents } from './agents/load-agents'
3433
import { checkpointManager } from './checkpoints/checkpoint-manager'
3534
import { CONFIG_DIR } from './credentials'
36-
import { gitCommandIsAvailable } from './utils/git'
35+
import { loadCodebuffConfig } from './json-config/parser'
36+
import { findGitRoot, gitCommandIsAvailable } from './utils/git'
3737
import { logger } from './utils/logger'
3838
import { getSystemInfo } from './utils/system-info'
3939
import { getScrapedContentBlocks, parseUrlsFromContent } from './web-scraper'
@@ -156,6 +156,24 @@ export function getStartingDirectory(dir: string | undefined = undefined): {
156156
return { cwd: dirAbsolute, shouldSearch: false }
157157
}
158158

159+
/**
160+
* Initialize project root for standalone commands that don't go through normal CLI setup
161+
* @param cwd Optional working directory override
162+
* @returns Object with projectRoot and workingDir paths
163+
*/
164+
export function initializeProjectRootAndWorkingDir(cwd?: string): {
165+
projectRoot: string
166+
workingDir: string
167+
} {
168+
const { cwd: workingDir, shouldSearch } = getStartingDirectory(cwd)
169+
const gitRoot = shouldSearch
170+
? findGitRoot(workingDir) ?? workingDir
171+
: workingDir
172+
const projectRoot = setProjectRoot(gitRoot)
173+
setWorkingDirectory(workingDir)
174+
return { projectRoot, workingDir }
175+
}
176+
159177
/**
160178
* Transforms a relative filepath into an absolute one, using the project root as the base.
161179
* Handles '..' and '.' in paths correctly. Also handles Windows paths.

web/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,6 @@ sitemap-*.xml
4848
/playwright-report/
4949
/blob-report/
5050
/playwright/.cache/
51+
52+
# uploads
53+
/public/uploads/

0 commit comments

Comments
 (0)