balchemy 0.2.2 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +144 -118
- package/dist/cli-options.d.ts +23 -0
- package/dist/cli-options.d.ts.map +1 -0
- package/dist/cli-options.js +87 -0
- package/dist/cli-options.js.map +1 -0
- package/dist/docker-gen.d.ts +20 -1
- package/dist/docker-gen.d.ts.map +1 -1
- package/dist/docker-gen.js +87 -25
- package/dist/docker-gen.js.map +1 -1
- package/dist/errors.d.ts +29 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +115 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +2 -15
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +720 -270
- package/dist/index.js.map +1 -1
- package/dist/output.d.ts +35 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +80 -0
- package/dist/output.js.map +1 -0
- package/dist/tui/AgentBridge.d.ts +2 -2
- package/dist/tui/AgentBridge.d.ts.map +1 -1
- package/dist/tui/AgentBridge.js +1 -1
- package/dist/tui/App.d.ts.map +1 -1
- package/dist/tui/App.js +47 -19
- package/dist/tui/App.js.map +1 -1
- package/dist/tui/ChatAgent.d.ts +2 -1
- package/dist/tui/ChatAgent.d.ts.map +1 -1
- package/dist/tui/ChatAgent.js +15 -4
- package/dist/tui/ChatAgent.js.map +1 -1
- package/dist/tui/Wizard.d.ts.map +1 -1
- package/dist/tui/Wizard.js +58 -10
- package/dist/tui/Wizard.js.map +1 -1
- package/dist/tui/types.d.ts +9 -0
- package/dist/tui/types.d.ts.map +1 -1
- package/dist/wizard.js +2 -2
- package/dist/wizard.js.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
</h1>
|
|
4
4
|
|
|
5
5
|
<p align="center">
|
|
6
|
-
<strong>
|
|
7
|
-
|
|
6
|
+
<strong>Balchemy CLI</strong><br/>
|
|
7
|
+
Initialize a local trading agent, connect model credentials, set risk rules, and generate deployment files.
|
|
8
8
|
</p>
|
|
9
9
|
|
|
10
10
|
<p align="center">
|
|
@@ -17,20 +17,20 @@
|
|
|
17
17
|
|
|
18
18
|
---
|
|
19
19
|
|
|
20
|
-
## What
|
|
20
|
+
## What Balchemy Does
|
|
21
21
|
|
|
22
|
-
Balchemy
|
|
22
|
+
Balchemy connects an external LLM to on-chain markets through MCP. The outer LLM
|
|
23
|
+
chooses tools and instructions. Balchemy applies scopes, behavior rules, risk
|
|
24
|
+
checks, execution, and records.
|
|
23
25
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
- **Inner LLM** (GPT-5.4-mini, server-side) — infrastructure servant that fetches data, formats responses, and serves the external LLM
|
|
26
|
+
The inner LLM is infrastructure support. It fetches data and formats responses.
|
|
27
|
+
It does not make trading decisions.
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
Inner LLM (data fetching, formatting)
|
|
29
|
+
```text
|
|
30
|
+
Strategy -> external LLM -> Balchemy MCP -> policy -> execution -> record
|
|
31
|
+
|
|
|
32
|
+
v
|
|
33
|
+
inner LLM support
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
## Quick Start
|
|
@@ -39,160 +39,186 @@ You (strategy) → External LLM (decisions) → Balchemy MCP (execution) → Sol
|
|
|
39
39
|
npx balchemy
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
-
The
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
42
|
+
The wizard handles five local steps:
|
|
43
|
+
|
|
44
|
+
1. Choose an LLM provider.
|
|
45
|
+
2. Add the provider API key.
|
|
46
|
+
3. Set wallet and chain preferences.
|
|
47
|
+
4. Define behavior rules in plain language.
|
|
48
|
+
5. Start or export the agent runtime.
|
|
49
|
+
|
|
50
|
+
## Commands
|
|
47
51
|
|
|
48
52
|
```bash
|
|
49
53
|
npx balchemy # Setup wizard or resume cached agent
|
|
50
|
-
npx balchemy init
|
|
51
|
-
npx balchemy start
|
|
52
|
-
npx balchemy list
|
|
53
|
-
npx balchemy docker
|
|
54
|
-
npx balchemy --help
|
|
55
|
-
npx balchemy --version
|
|
56
|
-
npx balchemy --no-color
|
|
54
|
+
npx balchemy init # New setup wizard
|
|
55
|
+
npx balchemy start # Start from agent.config.yaml
|
|
56
|
+
npx balchemy list # List saved agents
|
|
57
|
+
npx balchemy docker # Generate Docker files
|
|
58
|
+
npx balchemy --help # Usage
|
|
59
|
+
npx balchemy --version # Version
|
|
60
|
+
npx balchemy --no-color # Disable color output
|
|
57
61
|
```
|
|
58
62
|
|
|
59
|
-
|
|
63
|
+
`NO_COLOR=1` also disables colored output.
|
|
60
64
|
|
|
61
|
-
|
|
62
|
-
- **Buy/Sell tokens** — `buy 0.1 SOL worth of BONK on Solana`
|
|
63
|
-
- **Limit orders** — set price targets, get filled automatically
|
|
64
|
-
- **DCA (Dollar-Cost Averaging)** — schedule recurring buys
|
|
65
|
-
- **Trailing stops** — lock profits as price moves
|
|
65
|
+
## Files Written
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
- **Token analysis** — market cap, volume, holder distribution, risk scores
|
|
69
|
-
- **Smart money tracking** — follow profitable wallets
|
|
70
|
-
- **Bundle detection** — spot insider token launches
|
|
71
|
-
- **Price queries** — real-time Solana and EVM token prices
|
|
72
|
-
|
|
73
|
-
### Manage
|
|
74
|
-
- **Portfolio view** — see balances, P&L, positions across chains
|
|
75
|
-
- **Behavior rules** — define trading constraints in natural language
|
|
76
|
-
- **Subscriptions** — set up alerts for market events
|
|
77
|
-
- **24/7 autonomous loop** — your LLM monitors and acts even when you're away
|
|
78
|
-
|
|
79
|
-
### Risk Management (Built-In)
|
|
80
|
-
Every trade passes through multi-layer safety checks before execution:
|
|
81
|
-
- **RugCheck integration** — community risk scores
|
|
82
|
-
- **Honeypot detection** — simulated sell before buying
|
|
83
|
-
- **Contract verification** — liquidity locks, ownership renouncing
|
|
84
|
-
- **Behavior rules enforcement** — your constraints are always respected
|
|
85
|
-
|
|
86
|
-
## 100+ MCP Tools
|
|
87
|
-
|
|
88
|
-
Your LLM accesses Balchemy through these primary agent-facing tools:
|
|
89
|
-
|
|
90
|
-
| Tool | What It Does |
|
|
91
|
-
|------|-------------|
|
|
92
|
-
| `trade_command` | Execute buy/sell/swap on Solana or EVM |
|
|
93
|
-
| `ask_bot` | Natural language market queries (inner LLM-powered) |
|
|
94
|
-
| `agent_research` | Deep token research with technical analysis |
|
|
95
|
-
| `agent_portfolio` | Portfolio, positions, P&L overview |
|
|
96
|
-
| `configure_behavior_rules` | Set trading constraints in natural language |
|
|
97
|
-
| `get_behavior_rules` | Read current active rules |
|
|
98
|
-
| `create_subscription` | Set up market event alerts |
|
|
99
|
-
| `setup_agent` | Wallet provisioning and onboarding |
|
|
100
|
-
|
|
101
|
-
Plus 90+ internal tools for research, risk scoring, and execution — your LLM picks the right one from descriptions.
|
|
102
|
-
|
|
103
|
-
## LLM Providers
|
|
104
|
-
|
|
105
|
-
| Provider | Environment Variable | Notes |
|
|
106
|
-
|-----------|---------------------|-------|
|
|
107
|
-
| Anthropic | `ANTHROPIC_API_KEY` | Haiku 4.5, Sonnet 4.6, Opus 4.6+ |
|
|
108
|
-
| OpenAI | `OPENAI_API_KEY` | GPT-4o, GPT-5.4, etc. |
|
|
109
|
-
| Google Gemini | `GEMINI_API_KEY` | Gemini 3.1 Pro, Flash |
|
|
110
|
-
| Google Vertex AI | `GOOGLE_APPLICATION_CREDENTIALS` | Gemini 3.1 Pro via Vertex AI |
|
|
111
|
-
| xAI Grok | `GROK_API_KEY` | Grok-4-1-fast for research |
|
|
112
|
-
| OpenRouter | `OPENROUTER_API_KEY` | Access to 100+ models |
|
|
113
|
-
|
|
114
|
-
## Configuration
|
|
115
|
-
|
|
116
|
-
After setup, `agent.config.yaml` and `.env` are generated in the current directory:
|
|
67
|
+
The CLI writes local runtime files in the current directory.
|
|
117
68
|
|
|
118
69
|
```yaml
|
|
119
70
|
# agent.config.yaml
|
|
120
71
|
llm:
|
|
121
72
|
provider: anthropic
|
|
122
|
-
model:
|
|
73
|
+
model: selected-in-wizard
|
|
123
74
|
|
|
124
75
|
agent:
|
|
125
76
|
name: my-trading-agent
|
|
126
|
-
strategy: Focus on
|
|
77
|
+
strategy: Focus on liquid markets. Keep position size below 5%.
|
|
127
78
|
|
|
128
79
|
wallets:
|
|
129
80
|
solana:
|
|
130
81
|
chain: solana
|
|
131
82
|
evm:
|
|
132
|
-
chainId: 8453
|
|
83
|
+
chainId: 8453
|
|
133
84
|
```
|
|
134
85
|
|
|
135
|
-
|
|
86
|
+
Secrets belong in `.env`. Do not commit that file.
|
|
87
|
+
|
|
88
|
+
## What You Can Do
|
|
89
|
+
|
|
90
|
+
### Trade
|
|
136
91
|
|
|
137
|
-
|
|
92
|
+
- Buy and sell on Solana and EVM chains.
|
|
93
|
+
- Create limit orders.
|
|
94
|
+
- Schedule DCA rules.
|
|
95
|
+
- Use trailing stops.
|
|
138
96
|
|
|
139
|
-
|
|
97
|
+
### Research
|
|
98
|
+
|
|
99
|
+
- Query token price, liquidity, volume, and holder distribution.
|
|
100
|
+
- Check risk signals before a trade.
|
|
101
|
+
- Track wallets and market events.
|
|
102
|
+
- Compare positions across chains.
|
|
103
|
+
|
|
104
|
+
### Manage
|
|
105
|
+
|
|
106
|
+
- View portfolio, balances, positions, and PnL.
|
|
107
|
+
- Define behavior rules in natural language.
|
|
108
|
+
- Subscribe to market events.
|
|
109
|
+
- Rotate scoped MCP keys in Hub.
|
|
110
|
+
|
|
111
|
+
## Risk Model
|
|
112
|
+
|
|
113
|
+
Every trade path is expected to pass risk checks before execution:
|
|
114
|
+
|
|
115
|
+
- RugCheck signals.
|
|
116
|
+
- Honeypot simulation.
|
|
117
|
+
- Contract and liquidity checks.
|
|
118
|
+
- Behavior rule enforcement.
|
|
119
|
+
- Scoped MCP permissions.
|
|
120
|
+
|
|
121
|
+
The wallet remains the authority. Keep private keys and seed phrases out of
|
|
122
|
+
source, logs, screenshots, and prompts.
|
|
123
|
+
|
|
124
|
+
## MCP Tools
|
|
125
|
+
|
|
126
|
+
The CLI connects agents to the curated agent-facing MCP surface.
|
|
127
|
+
|
|
128
|
+
| Tool | Purpose |
|
|
129
|
+
| --- | --- |
|
|
130
|
+
| `trade_command` | Buy, sell, or swap through the approved execution path |
|
|
131
|
+
| `ask_bot` | Natural language market query support |
|
|
132
|
+
| `agent_research` | Token and market research |
|
|
133
|
+
| `agent_portfolio` | Portfolio, positions, and PnL |
|
|
134
|
+
| `configure_behavior_rules` | Trading constraints in natural language |
|
|
135
|
+
| `get_behavior_rules` | Current active rules |
|
|
136
|
+
| `create_subscription` | Market event subscription |
|
|
137
|
+
| `setup_agent` | Onboarding and runtime setup |
|
|
138
|
+
|
|
139
|
+
Granular internal tools stay hidden unless the platform enables them for a bot.
|
|
140
|
+
|
|
141
|
+
## LLM Providers
|
|
142
|
+
|
|
143
|
+
| Provider | Environment variable |
|
|
144
|
+
| --- | --- |
|
|
145
|
+
| Anthropic | `ANTHROPIC_API_KEY` |
|
|
146
|
+
| OpenAI | `OPENAI_API_KEY` |
|
|
147
|
+
| Google Gemini | `GEMINI_API_KEY` |
|
|
148
|
+
| Google Vertex AI | `GOOGLE_APPLICATION_CREDENTIALS` |
|
|
149
|
+
| xAI Grok | `GROK_API_KEY` |
|
|
150
|
+
| OpenRouter | `OPENROUTER_API_KEY` |
|
|
151
|
+
|
|
152
|
+
Pick the model in the wizard or edit `agent.config.yaml`.
|
|
153
|
+
|
|
154
|
+
## Runtime Mode
|
|
155
|
+
|
|
156
|
+
The SDK includes an `AgentLoop` for long-running agents.
|
|
140
157
|
|
|
141
158
|
```ts
|
|
142
|
-
import {
|
|
159
|
+
import { AgentLoop, BalchemyAgentSdk } from "@balchemyai/agent-sdk";
|
|
160
|
+
|
|
161
|
+
const sdk = new BalchemyAgentSdk({
|
|
162
|
+
apiBaseUrl: "https://api.balchemy.ai/api",
|
|
163
|
+
});
|
|
143
164
|
|
|
144
|
-
const
|
|
145
|
-
|
|
165
|
+
const loop = new AgentLoop(sdk, {
|
|
166
|
+
apiKey: "your-mcp-api-key",
|
|
167
|
+
});
|
|
146
168
|
|
|
147
|
-
// Starts SSE event stream + polling cycle
|
|
148
|
-
// Your LLM receives market events and decides whether to act
|
|
149
169
|
await loop.start();
|
|
150
170
|
```
|
|
151
171
|
|
|
152
|
-
|
|
172
|
+
Event flow:
|
|
173
|
+
|
|
174
|
+
```text
|
|
175
|
+
Market event -> SSE -> external LLM evaluates -> MCP tool call -> execution -> confirmation
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Hub
|
|
153
179
|
|
|
154
|
-
|
|
180
|
+
Agents registered through the CLI appear in [Balchemy Hub](https://balchemy.ai/hub).
|
|
155
181
|
|
|
156
|
-
|
|
157
|
-
-
|
|
158
|
-
-
|
|
159
|
-
-
|
|
160
|
-
- **Wallet Management** — link/unlink Solana and EVM wallets
|
|
182
|
+
- Monitor portfolio, trade history, and event logs.
|
|
183
|
+
- Create, rotate, and revoke MCP keys.
|
|
184
|
+
- Keep `read` and `trade` scopes separate.
|
|
185
|
+
- Link Solana and EVM wallets.
|
|
161
186
|
|
|
162
187
|
## Security
|
|
163
188
|
|
|
164
|
-
-
|
|
165
|
-
-
|
|
166
|
-
-
|
|
167
|
-
-
|
|
168
|
-
-
|
|
189
|
+
- Credentials are encrypted at rest.
|
|
190
|
+
- MCP keys are scoped and revocable.
|
|
191
|
+
- Behavior rules constrain execution.
|
|
192
|
+
- Pre-trade checks run before approved execution.
|
|
193
|
+
- Seed phrases should never be stored in source or logs.
|
|
169
194
|
|
|
170
|
-
## TUI
|
|
195
|
+
## TUI Shortcuts
|
|
171
196
|
|
|
172
197
|
| Shortcut | Action |
|
|
173
|
-
|
|
174
|
-
| `^S` | Open settings
|
|
198
|
+
| --- | --- |
|
|
199
|
+
| `^S` | Open settings |
|
|
175
200
|
| `^L` | Clear chat history |
|
|
176
|
-
| `^N` | New agent
|
|
201
|
+
| `^N` | New agent |
|
|
177
202
|
| `^Q` | Quit |
|
|
178
203
|
| `PgUp/PgDn` | Scroll message history |
|
|
179
|
-
| `Esc` | Go back
|
|
204
|
+
| `Esc` | Go back |
|
|
180
205
|
|
|
181
206
|
## Requirements
|
|
182
207
|
|
|
183
208
|
- Node.js 18+
|
|
184
|
-
-
|
|
209
|
+
- One supported LLM provider key
|
|
185
210
|
|
|
186
211
|
## Links
|
|
187
212
|
|
|
188
|
-
-
|
|
189
|
-
-
|
|
190
|
-
-
|
|
191
|
-
-
|
|
192
|
-
-
|
|
193
|
-
-
|
|
194
|
-
-
|
|
213
|
+
- [Platform](https://balchemy.ai)
|
|
214
|
+
- [Documentation](https://balchemy.ai/hub/docs)
|
|
215
|
+
- [Agent Explorer](https://balchemy.ai/explorer)
|
|
216
|
+
- [GitHub](https://github.com/balchemy/balchemy-agent)
|
|
217
|
+
- [npm: balchemy](https://www.npmjs.com/package/balchemy)
|
|
218
|
+
- [npm: @balchemyai/agent-sdk](https://www.npmjs.com/package/@balchemyai/agent-sdk)
|
|
219
|
+
- [X: @balchemyai](https://x.com/balchemyai)
|
|
220
|
+
- [Contact](mailto:burak@balchemy.ai)
|
|
195
221
|
|
|
196
222
|
## License
|
|
197
223
|
|
|
198
|
-
MIT
|
|
224
|
+
MIT
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface CliFlags {
|
|
2
|
+
help: boolean;
|
|
3
|
+
version: boolean;
|
|
4
|
+
noColor: boolean;
|
|
5
|
+
json: boolean;
|
|
6
|
+
quiet: boolean;
|
|
7
|
+
verbose: boolean;
|
|
8
|
+
debug: boolean;
|
|
9
|
+
ci: boolean;
|
|
10
|
+
dryRun: boolean;
|
|
11
|
+
yes: boolean;
|
|
12
|
+
force: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface ParsedCliArgs {
|
|
15
|
+
flags: CliFlags;
|
|
16
|
+
commandPath: string[];
|
|
17
|
+
args: string[];
|
|
18
|
+
unknownFlags: string[];
|
|
19
|
+
}
|
|
20
|
+
export declare function parseCliArgs(rawArgs: string[]): ParsedCliArgs;
|
|
21
|
+
export declare function commandKey(commandPath: string[]): string;
|
|
22
|
+
export declare function isNonInteractive(flags: CliFlags): boolean;
|
|
23
|
+
//# sourceMappingURL=cli-options.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-options.d.ts","sourceRoot":"","sources":["../src/cli-options.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,OAAO,CAAC;IAChB,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,QAAQ,CAAC;IAChB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAqED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,aAAa,CA2B7D;AAED,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,MAAM,CAExD;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAEzD"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
const GLOBAL_FLAG_ALIASES = {
|
|
2
|
+
"--help": "help",
|
|
3
|
+
"-h": "help",
|
|
4
|
+
"--version": "version",
|
|
5
|
+
"-v": "version",
|
|
6
|
+
"--no-color": "noColor",
|
|
7
|
+
"--json": "json",
|
|
8
|
+
"--quiet": "quiet",
|
|
9
|
+
"-q": "quiet",
|
|
10
|
+
"--verbose": "verbose",
|
|
11
|
+
"--debug": "debug",
|
|
12
|
+
"--ci": "ci",
|
|
13
|
+
"--dry-run": "dryRun",
|
|
14
|
+
"--yes": "yes",
|
|
15
|
+
"-y": "yes",
|
|
16
|
+
"--force": "force",
|
|
17
|
+
};
|
|
18
|
+
function defaultFlags() {
|
|
19
|
+
return {
|
|
20
|
+
help: false,
|
|
21
|
+
version: false,
|
|
22
|
+
noColor: false,
|
|
23
|
+
json: false,
|
|
24
|
+
quiet: false,
|
|
25
|
+
verbose: false,
|
|
26
|
+
debug: false,
|
|
27
|
+
ci: false,
|
|
28
|
+
dryRun: false,
|
|
29
|
+
yes: false,
|
|
30
|
+
force: false,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function splitCommandAndArgs(positional) {
|
|
34
|
+
const first = positional[0];
|
|
35
|
+
const second = positional[1];
|
|
36
|
+
if (!first)
|
|
37
|
+
return { commandPath: [], args: [] };
|
|
38
|
+
if (first === "agent" && ["list", "current", "use"].includes(second ?? "")) {
|
|
39
|
+
return { commandPath: [first, second], args: positional.slice(2) };
|
|
40
|
+
}
|
|
41
|
+
if (first === "auth" && ["status", "login", "logout"].includes(second ?? "")) {
|
|
42
|
+
return { commandPath: [first, second], args: positional.slice(2) };
|
|
43
|
+
}
|
|
44
|
+
if (first === "context" && ["current", "status"].includes(second ?? "")) {
|
|
45
|
+
return { commandPath: ["agent", "current"], args: positional.slice(2) };
|
|
46
|
+
}
|
|
47
|
+
if (first === "tui") {
|
|
48
|
+
return { commandPath: ["start"], args: positional.slice(1) };
|
|
49
|
+
}
|
|
50
|
+
if (first === "config" && ["validate", "list"].includes(second ?? "")) {
|
|
51
|
+
return { commandPath: [first, second], args: positional.slice(2) };
|
|
52
|
+
}
|
|
53
|
+
if (first === "docker" && second === "generate") {
|
|
54
|
+
return { commandPath: [first], args: positional.slice(2) };
|
|
55
|
+
}
|
|
56
|
+
return { commandPath: [first], args: positional.slice(1) };
|
|
57
|
+
}
|
|
58
|
+
export function parseCliArgs(rawArgs) {
|
|
59
|
+
const flags = defaultFlags();
|
|
60
|
+
const positional = [];
|
|
61
|
+
const unknownFlags = [];
|
|
62
|
+
for (const arg of rawArgs) {
|
|
63
|
+
if (arg === "--init") {
|
|
64
|
+
positional.push("init");
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
const flagName = GLOBAL_FLAG_ALIASES[arg];
|
|
68
|
+
if (flagName) {
|
|
69
|
+
flags[flagName] = true;
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (arg.startsWith("--")) {
|
|
73
|
+
unknownFlags.push(arg);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
positional.push(arg);
|
|
77
|
+
}
|
|
78
|
+
const { commandPath, args } = splitCommandAndArgs(positional);
|
|
79
|
+
return { flags, commandPath, args, unknownFlags };
|
|
80
|
+
}
|
|
81
|
+
export function commandKey(commandPath) {
|
|
82
|
+
return commandPath.join(" ");
|
|
83
|
+
}
|
|
84
|
+
export function isNonInteractive(flags) {
|
|
85
|
+
return flags.ci || !process.stdin.isTTY || !process.stdout.isTTY;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=cli-options.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-options.js","sourceRoot":"","sources":["../src/cli-options.ts"],"names":[],"mappings":"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"}
|
package/dist/docker-gen.d.ts
CHANGED
|
@@ -2,5 +2,24 @@
|
|
|
2
2
|
* Generates Dockerfile + docker-compose.yml for the agent.
|
|
3
3
|
* Copies static template files and does not mutate them.
|
|
4
4
|
*/
|
|
5
|
-
export
|
|
5
|
+
export type DockerFileAction = "create" | "overwrite" | "skip";
|
|
6
|
+
export interface DockerFilePlan {
|
|
7
|
+
filename: string;
|
|
8
|
+
path: string;
|
|
9
|
+
action: DockerFileAction;
|
|
10
|
+
exists: boolean;
|
|
11
|
+
wouldOverwrite: boolean;
|
|
12
|
+
containsSecret: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface DockerGenerationPlan {
|
|
15
|
+
outDir: string;
|
|
16
|
+
files: DockerFilePlan[];
|
|
17
|
+
hasOverwrites: boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface DockerGenerationOptions {
|
|
20
|
+
dryRun?: boolean;
|
|
21
|
+
force?: boolean;
|
|
22
|
+
}
|
|
23
|
+
export declare function buildDockerPlan(outDir: string): DockerGenerationPlan;
|
|
24
|
+
export declare function generateDocker(outDir: string, options?: DockerGenerationOptions): Promise<DockerGenerationPlan>;
|
|
6
25
|
//# sourceMappingURL=docker-gen.d.ts.map
|
package/dist/docker-gen.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docker-gen.d.ts","sourceRoot":"","sources":["../src/docker-gen.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"docker-gen.d.ts","sourceRoot":"","sources":["../src/docker-gen.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,WAAW,GAAG,MAAM,CAAC;AAE/D,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,gBAAgB,CAAC;IACzB,MAAM,EAAE,OAAO,CAAC;IAChB,cAAc,EAAE,OAAO,CAAC;IACxB,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAgCD,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,oBAAoB,CAqCpE;AAMD,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,oBAAoB,CAAC,CA4B/B"}
|
package/dist/docker-gen.js
CHANGED
|
@@ -2,39 +2,101 @@
|
|
|
2
2
|
* Generates Dockerfile + docker-compose.yml for the agent.
|
|
3
3
|
* Copies static template files and does not mutate them.
|
|
4
4
|
*/
|
|
5
|
-
import * as fs from
|
|
6
|
-
import * as path from
|
|
7
|
-
import { fileURLToPath } from
|
|
5
|
+
import * as fs from "node:fs";
|
|
6
|
+
import * as path from "node:path";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
import { TerminalError } from "./errors.js";
|
|
8
9
|
const __filename_esm = fileURLToPath(import.meta.url);
|
|
9
10
|
const __dirname_esm = path.dirname(__filename_esm);
|
|
10
|
-
const TEMPLATES_DIR = path.join(__dirname_esm,
|
|
11
|
-
function
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
const TEMPLATES_DIR = path.join(__dirname_esm, "..", "templates");
|
|
12
|
+
function templatePath(filename) {
|
|
13
|
+
return path.join(TEMPLATES_DIR, filename);
|
|
14
|
+
}
|
|
15
|
+
function assertTemplateExists(filename) {
|
|
16
|
+
const src = templatePath(filename);
|
|
14
17
|
if (!fs.existsSync(src)) {
|
|
15
|
-
throw new
|
|
18
|
+
throw new TerminalError({
|
|
19
|
+
code: "CONFIG_FILE_MISSING",
|
|
20
|
+
title: "Docker template missing",
|
|
21
|
+
cause: `Template file not found: ${src}`,
|
|
22
|
+
fix: "Reinstall the balchemy CLI package or run from a complete build artifact.",
|
|
23
|
+
exitCode: 2,
|
|
24
|
+
});
|
|
16
25
|
}
|
|
17
|
-
fs.copyFileSync(src, dest);
|
|
18
|
-
process.stdout.write(` wrote ${dest}\n`);
|
|
19
26
|
}
|
|
20
|
-
|
|
27
|
+
function plannedFile(outDir, filename, overwriteAllowed) {
|
|
28
|
+
const dest = path.join(outDir, filename);
|
|
29
|
+
const exists = fs.existsSync(dest);
|
|
30
|
+
return {
|
|
31
|
+
filename,
|
|
32
|
+
path: dest,
|
|
33
|
+
action: exists ? (overwriteAllowed ? "overwrite" : "skip") : "create",
|
|
34
|
+
exists,
|
|
35
|
+
wouldOverwrite: exists && overwriteAllowed,
|
|
36
|
+
containsSecret: false,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export function buildDockerPlan(outDir) {
|
|
21
40
|
if (!fs.existsSync(outDir)) {
|
|
22
|
-
throw new
|
|
41
|
+
throw new TerminalError({
|
|
42
|
+
code: "CONFIG_FILE_MISSING",
|
|
43
|
+
title: "Output directory does not exist",
|
|
44
|
+
cause: `Output directory does not exist: ${outDir}`,
|
|
45
|
+
fix: "Create the directory first or pass an existing output directory.",
|
|
46
|
+
commandSuggestion: "mkdir -p ./deploy && balchemy docker ./deploy --dry-run",
|
|
47
|
+
exitCode: 2,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
if (!fs.statSync(outDir).isDirectory()) {
|
|
51
|
+
throw new TerminalError({
|
|
52
|
+
code: "CONFIG_FILE_MISSING",
|
|
53
|
+
title: "Output path is not a directory",
|
|
54
|
+
cause: `Output path is not a directory: ${outDir}`,
|
|
55
|
+
fix: "Pass a directory path for Docker file generation.",
|
|
56
|
+
exitCode: 2,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
for (const filename of ["Dockerfile", "docker-compose.yml", ".env.example"]) {
|
|
60
|
+
assertTemplateExists(filename);
|
|
61
|
+
}
|
|
62
|
+
const files = [
|
|
63
|
+
plannedFile(outDir, "Dockerfile", true),
|
|
64
|
+
plannedFile(outDir, "docker-compose.yml", true),
|
|
65
|
+
plannedFile(outDir, ".env.example", false),
|
|
66
|
+
];
|
|
67
|
+
return {
|
|
68
|
+
outDir,
|
|
69
|
+
files,
|
|
70
|
+
hasOverwrites: files.some((file) => file.wouldOverwrite),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function copyTemplate(filename, dest) {
|
|
74
|
+
fs.copyFileSync(templatePath(filename), dest);
|
|
75
|
+
}
|
|
76
|
+
export async function generateDocker(outDir, options = {}) {
|
|
77
|
+
const plan = buildDockerPlan(outDir);
|
|
78
|
+
if (options.dryRun) {
|
|
79
|
+
return plan;
|
|
23
80
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
81
|
+
if (plan.hasOverwrites && !options.force) {
|
|
82
|
+
const targets = plan.files
|
|
83
|
+
.filter((file) => file.wouldOverwrite)
|
|
84
|
+
.map((file) => file.path)
|
|
85
|
+
.join(", ");
|
|
86
|
+
throw new TerminalError({
|
|
87
|
+
code: "FILE_OVERWRITE_CONFIRMATION_REQUIRED",
|
|
88
|
+
title: "Overwrite confirmation required",
|
|
89
|
+
cause: `Existing files would be overwritten: ${targets}`,
|
|
90
|
+
fix: "Review the preview and type overwrite, or rerun with --dry-run to inspect without writing.",
|
|
91
|
+
commandSuggestion: `balchemy docker ${outDir} --dry-run`,
|
|
92
|
+
exitCode: 4,
|
|
93
|
+
});
|
|
31
94
|
}
|
|
32
|
-
|
|
33
|
-
|
|
95
|
+
for (const file of plan.files) {
|
|
96
|
+
if (file.action === "skip")
|
|
97
|
+
continue;
|
|
98
|
+
copyTemplate(file.filename, file.path);
|
|
34
99
|
}
|
|
35
|
-
|
|
36
|
-
` 1. Copy .env.example to .env and fill in your credentials\n` +
|
|
37
|
-
` 2. Place your agent.config.yaml in the same directory\n` +
|
|
38
|
-
` 3. Run: docker compose up -d\n`);
|
|
100
|
+
return plan;
|
|
39
101
|
}
|
|
40
102
|
//# sourceMappingURL=docker-gen.js.map
|
package/dist/docker-gen.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docker-gen.js","sourceRoot":"","sources":["../src/docker-gen.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"docker-gen.js","sourceRoot":"","sources":["../src/docker-gen.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,cAAc,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACtD,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;AACnD,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;AAwBlE,SAAS,YAAY,CAAC,QAAgB;IACpC,OAAO,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;AAC5C,CAAC;AAED,SAAS,oBAAoB,CAAC,QAAgB;IAC5C,MAAM,GAAG,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IACnC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,aAAa,CAAC;YACtB,IAAI,EAAE,qBAAqB;YAC3B,KAAK,EAAE,yBAAyB;YAChC,KAAK,EAAE,4BAA4B,GAAG,EAAE;YACxC,GAAG,EAAE,2EAA2E;YAChF,QAAQ,EAAE,CAAC;SACZ,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,MAAc,EAAE,QAAgB,EAAE,gBAAyB;IAC9E,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACzC,MAAM,MAAM,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IACnC,OAAO;QACL,QAAQ;QACR,IAAI,EAAE,IAAI;QACV,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ;QACrE,MAAM;QACN,cAAc,EAAE,MAAM,IAAI,gBAAgB;QAC1C,cAAc,EAAE,KAAK;KACtB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,aAAa,CAAC;YACtB,IAAI,EAAE,qBAAqB;YAC3B,KAAK,EAAE,iCAAiC;YACxC,KAAK,EAAE,oCAAoC,MAAM,EAAE;YACnD,GAAG,EAAE,kEAAkE;YACvE,iBAAiB,EAAE,yDAAyD;YAC5E,QAAQ,EAAE,CAAC;SACZ,CAAC,CAAC;IACL,CAAC;IAED,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;QACvC,MAAM,IAAI,aAAa,CAAC;YACtB,IAAI,EAAE,qBAAqB;YAC3B,KAAK,EAAE,gCAAgC;YACvC,KAAK,EAAE,mCAAmC,MAAM,EAAE;YAClD,GAAG,EAAE,mDAAmD;YACxD,QAAQ,EAAE,CAAC;SACZ,CAAC,CAAC;IACL,CAAC;IAED,KAAK,MAAM,QAAQ,IAAI,CAAC,YAAY,EAAE,oBAAoB,EAAE,cAAc,CAAC,EAAE,CAAC;QAC5E,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IACjC,CAAC;IAED,MAAM,KAAK,GAAG;QACZ,WAAW,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,CAAC;QACvC,WAAW,CAAC,MAAM,EAAE,oBAAoB,EAAE,IAAI,CAAC;QAC/C,WAAW,CAAC,MAAM,EAAE,cAAc,EAAE,KAAK,CAAC;KAC3C,CAAC;IAEF,OAAO;QACL,MAAM;QACN,KAAK;QACL,aAAa,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC;KACzD,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,QAAgB,EAAE,IAAY;IAClD,EAAE,CAAC,YAAY,CAAC,YAAY,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,MAAc,EACd,UAAmC,EAAE;IAErC,MAAM,IAAI,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IAErC,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,IAAI,CAAC,aAAa,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACzC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK;aACvB,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC;aACrC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;aACxB,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,MAAM,IAAI,aAAa,CAAC;YACtB,IAAI,EAAE,sCAAsC;YAC5C,KAAK,EAAE,iCAAiC;YACxC,KAAK,EAAE,wCAAwC,OAAO,EAAE;YACxD,GAAG,EAAE,4FAA4F;YACjG,iBAAiB,EAAE,mBAAmB,MAAM,YAAY;YACxD,QAAQ,EAAE,CAAC;SACZ,CAAC,CAAC;IACL,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC9B,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM;YAAE,SAAS;QACrC,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACzC,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
|