Skip to content

Commit e6dfd14

Browse files
authored
Shims: save any agent to your path as a command (#306)
1 parent 70a2bfb commit e6dfd14

File tree

5 files changed

+1124
-2
lines changed

5 files changed

+1124
-2
lines changed

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/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
]

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

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
import { red } from 'picocolors'
2+
3+
import {
4+
installShims,
5+
uninstallShims,
6+
listShims,
7+
updateShims,
8+
doctorShims,
9+
upgradeShims,
10+
} from '../shell-dispatcher'
11+
import { logger } from '../utils/logger'
12+
13+
/**
14+
* Handle the 'shims install' command
15+
*/
16+
export async function handleShimsInstall(
17+
agentSpecs: string[],
18+
options: { force?: boolean } = {},
19+
): Promise<void> {
20+
try {
21+
if (!agentSpecs || agentSpecs.length === 0) {
22+
console.error(red('Error: No agent IDs specified to install as shims.'))
23+
console.log(
24+
'Usage: codebuff shims install <publisher/agent-id@version> [publisher/agent-id@version:custom-command] ...',
25+
)
26+
process.exit(1)
27+
}
28+
installShims(agentSpecs, options)
29+
} catch (error) {
30+
logger.error(
31+
{
32+
errorMessage: error instanceof Error ? error.message : String(error),
33+
errorStack: error instanceof Error ? error.stack : undefined,
34+
agentSpecs,
35+
options,
36+
},
37+
'Error installing shims',
38+
)
39+
console.error(red(`Error installing shims: ${error}`))
40+
process.exit(1)
41+
}
42+
}
43+
44+
/**
45+
* Handle the 'shims uninstall' command
46+
*/
47+
export async function handleShimsUninstall(
48+
commandNames?: string[],
49+
): Promise<void> {
50+
try {
51+
uninstallShims(commandNames)
52+
} catch (error) {
53+
logger.error(
54+
{
55+
errorMessage: error instanceof Error ? error.message : String(error),
56+
errorStack: error instanceof Error ? error.stack : undefined,
57+
commandNames,
58+
},
59+
'Error uninstalling shims',
60+
)
61+
console.error(red(`Error uninstalling shims: ${error}`))
62+
process.exit(1)
63+
}
64+
}
65+
66+
/**
67+
* Handle the 'shims list' command
68+
*/
69+
export async function handleShimsList(): Promise<void> {
70+
try {
71+
listShims()
72+
} catch (error) {
73+
logger.error(
74+
{
75+
errorMessage: error instanceof Error ? error.message : String(error),
76+
errorStack: error instanceof Error ? error.stack : undefined,
77+
},
78+
'Error listing shims',
79+
)
80+
console.error(red(`Error listing shims: ${error}`))
81+
process.exit(1)
82+
}
83+
}
84+
85+
/**
86+
* Handle the 'shims update' command
87+
*/
88+
export async function handleShimsUpdate(
89+
commandNames?: string[],
90+
): Promise<void> {
91+
try {
92+
updateShims(commandNames)
93+
} catch (error) {
94+
logger.error(
95+
{
96+
errorMessage: error instanceof Error ? error.message : String(error),
97+
errorStack: error instanceof Error ? error.stack : undefined,
98+
commandNames,
99+
},
100+
'Error updating shims',
101+
)
102+
console.error(red(`Error updating shims: ${error}`))
103+
process.exit(1)
104+
}
105+
}
106+
107+
/**
108+
* Handle the 'shims doctor' command
109+
*/
110+
export async function handleShimsDoctor(): Promise<void> {
111+
try {
112+
doctorShims()
113+
} catch (error) {
114+
logger.error(
115+
{
116+
errorMessage: error instanceof Error ? error.message : String(error),
117+
errorStack: error instanceof Error ? error.stack : undefined,
118+
},
119+
'Error running shims doctor',
120+
)
121+
console.error(red(`Error running shims doctor: ${error}`))
122+
process.exit(1)
123+
}
124+
}
125+
126+
/**
127+
* Handle the 'shims upgrade' command
128+
*/
129+
export async function handleShimsUpgrade(): Promise<void> {
130+
try {
131+
await upgradeShims()
132+
} catch (error) {
133+
logger.error(
134+
{
135+
errorMessage: error instanceof Error ? error.message : String(error),
136+
errorStack: error instanceof Error ? error.stack : undefined,
137+
},
138+
'Error upgrading shims',
139+
)
140+
console.error(red(`Error upgrading shims: ${error}`))
141+
process.exit(1)
142+
}
143+
}

npm-app/src/index.ts

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,16 @@ import { cliArguments, cliOptions } from './cli-definitions'
1111
import { handlePublish } from './cli-handlers/publish'
1212
import { handleInitAgents } from './cli-handlers/init-agents'
1313
import { handleSaveAgent } from './cli-handlers/save-agent'
14-
import { npmAppVersion, backendUrl } from './config'
14+
import {
15+
handleShimsInstall,
16+
handleShimsUninstall,
17+
handleShimsList,
18+
handleShimsUpdate,
19+
handleShimsDoctor,
20+
handleShimsUpgrade,
21+
} from './cli-handlers/shims'
22+
import { generateEvalCommand } from './shell-dispatcher'
23+
import { npmAppVersion } from './config'
1524
import { createTemplateProject } from './create-template-project'
1625
import { printModeLog, setPrintMode } from './display/print-mode'
1726
import { enableSquashNewlines } from './display/squash-newlines'
@@ -128,6 +137,13 @@ Examples:
128137
$ codebuff --agent file-picker "find relevant files for authentication"
129138
$ codebuff --agent reviewer --params '{"focus": "security"}' "review this code"
130139
140+
Direct Commands (via shell shims):
141+
$ codebuff shims install codebuff/base-lite@1.0.0 # One-step setup!
142+
$ eval "$(codebuff shims env)" # Run this for immediate use
143+
$ base-lite "fix the bug" # Direct command (after eval)
144+
$ codebuff shims list # List installed shims
145+
$ codebuff shims upgrade # Upgrade all shims to latest versions
146+
131147
For all commands and options, run 'codebuff' and then type 'help'.
132148
`,
133149
)
@@ -168,6 +184,46 @@ For all commands and options, run 'codebuff' and then type 'help'.
168184
process.exit(0)
169185
}
170186

187+
// Handle shims command
188+
if (args[0] === 'shims') {
189+
const subcommand = args[1]
190+
const subArgs = args.slice(2)
191+
192+
switch (subcommand) {
193+
case 'install':
194+
await handleShimsInstall(subArgs, {
195+
force: options.force,
196+
})
197+
break
198+
case 'uninstall':
199+
case 'remove':
200+
await handleShimsUninstall(subArgs.length > 0 ? subArgs : undefined)
201+
break
202+
case 'list':
203+
await handleShimsList()
204+
break
205+
case 'update':
206+
await handleShimsUpdate(subArgs.length > 0 ? subArgs : undefined)
207+
break
208+
case 'doctor':
209+
await handleShimsDoctor()
210+
break
211+
case 'upgrade':
212+
await handleShimsUpgrade()
213+
break
214+
case 'env':
215+
console.log(generateEvalCommand())
216+
break
217+
default:
218+
console.error(red(`Unknown shims subcommand: ${subcommand}`))
219+
console.log(
220+
'Available subcommands: install, uninstall, list, update, doctor, upgrade, env',
221+
)
222+
process.exit(1)
223+
}
224+
process.exit(0)
225+
}
226+
171227
// Handle deprecated --pro flag
172228
if (options.pro) {
173229
console.error(
@@ -235,7 +291,7 @@ For all commands and options, run 'codebuff' and then type 'help'.
235291
const filteredArgs = args[0]?.startsWith('/$bunfs') ? args.slice(1) : args
236292

237293
// If first arg is a command like 'publish' or 'save-agent', don't treat it as initial input
238-
const isCommand = ['publish', 'init-agents', 'save-agent'].includes(
294+
const isCommand = ['publish', 'init-agents', 'save-agent', 'shims'].includes(
239295
filteredArgs[0],
240296
)
241297
const initialInput = isCommand ? '' : filteredArgs.join(' ')

0 commit comments

Comments
 (0)