kadi-deploy 0.19.0
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/.env.example +6 -0
- package/.prettierrc +6 -0
- package/README.md +589 -0
- package/agent.json +23 -0
- package/index.js +11 -0
- package/package.json +42 -0
- package/quick-command.txt +92 -0
- package/scripts/preflight.js +458 -0
- package/scripts/preflight.sh +300 -0
- package/src/cli/bid-selector.ts +222 -0
- package/src/cli/colors.ts +216 -0
- package/src/cli/index.ts +11 -0
- package/src/cli/prompts.ts +190 -0
- package/src/cli/spinners.ts +165 -0
- package/src/commands/deploy-local.ts +475 -0
- package/src/commands/deploy.ts +1342 -0
- package/src/commands/down.ts +679 -0
- package/src/commands/index.ts +10 -0
- package/src/commands/lock.ts +571 -0
- package/src/config/agent-loader.ts +177 -0
- package/src/config/index.ts +9 -0
- package/src/display/deployment-info.ts +220 -0
- package/src/display/pricing.ts +137 -0
- package/src/display/resources.ts +234 -0
- package/src/enhanced-registry-manager.ts +892 -0
- package/src/index.ts +307 -0
- package/src/infrastructure/registry.ts +269 -0
- package/src/schemas/profiles.ts +529 -0
- package/src/secrets/broker-urls.ts +109 -0
- package/src/secrets/handshake.ts +407 -0
- package/src/secrets/index.ts +69 -0
- package/src/secrets/inject-env.ts +171 -0
- package/src/secrets/nonce.ts +31 -0
- package/src/secrets/normalize.ts +204 -0
- package/src/secrets/prepare.ts +152 -0
- package/src/secrets/validate.ts +243 -0
- package/src/secrets/vault.ts +80 -0
- package/src/types/akash.ts +116 -0
- package/src/types/container-registry-ability.d.ts +158 -0
- package/src/types/external.ts +49 -0
- package/src/types.ts +211 -0
- package/src/utils/akt-price.ts +74 -0
- package/tests/agent-loader.test.ts +239 -0
- package/tests/autonomous.test.ts +244 -0
- package/tests/down.test.ts +1143 -0
- package/tests/lock.test.ts +1148 -0
- package/tests/nonce.test.ts +34 -0
- package/tests/normalize.test.ts +270 -0
- package/tests/secrets-schema.test.ts +301 -0
- package/tests/types.test.ts +198 -0
- package/tsconfig.json +18 -0
- package/vitest.config.ts +9 -0
package/.env.example
ADDED
package/.prettierrc
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,589 @@
|
|
|
1
|
+
# kadi-deploy
|
|
2
|
+
|
|
3
|
+
Deploy KADI agents to local Docker/Podman or Akash Network using profiles defined in `agent.json`.
|
|
4
|
+
|
|
5
|
+
This is a **CLI plugin** that provides the `deploy` command. See [kadi-by-example](https://gitlab.com/humin-game-lab/kadi/kadi-by-example) for tutorials.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
kadi install kadi-deploy
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Quick Reference
|
|
18
|
+
|
|
19
|
+
| Command | Purpose |
|
|
20
|
+
|---------|---------|
|
|
21
|
+
| `kadi deploy` | Deploy using first available profile |
|
|
22
|
+
| `kadi deploy --profile production` | Deploy using a specific profile |
|
|
23
|
+
| `kadi deploy --autonomous` | Fully autonomous deployment (no human interaction) |
|
|
24
|
+
| `kadi deploy --dry-run` | Preview deployment without executing || `kadi deploy down` | Tear down an active deployment |
|
|
25
|
+
| `kadi deploy down --profile <name>` | Tear down a specific profile's deployment |
|
|
26
|
+
| `kadi deploy down --autonomous` | Tear down Akash deployment without human interaction |
|
|
27
|
+
| `kadi deploy down --yes` | Tear down without confirmation prompt |
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Quick Start
|
|
31
|
+
|
|
32
|
+
### 1. Add a deploy profile to `agent.json`
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"name": "my-agent",
|
|
37
|
+
"version": "1.0.0",
|
|
38
|
+
"deploy": {
|
|
39
|
+
"local": {
|
|
40
|
+
"target": "local",
|
|
41
|
+
"engine": "docker",
|
|
42
|
+
"services": {
|
|
43
|
+
"app": {
|
|
44
|
+
"image": "my-agent:latest",
|
|
45
|
+
"expose": [{ "port": 3000, "as": 3000 }]
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 2. Deploy
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
kadi deploy --profile local
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
That's it. For Akash Network deployment, see [Deploying to Akash](#deploying-to-akash).
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Deploying Locally
|
|
64
|
+
|
|
65
|
+
Local deployment uses Docker or Podman to run your services via docker-compose.
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"deploy": {
|
|
70
|
+
"local": {
|
|
71
|
+
"target": "local",
|
|
72
|
+
"engine": "docker",
|
|
73
|
+
"services": {
|
|
74
|
+
"web": {
|
|
75
|
+
"image": "nginx:alpine",
|
|
76
|
+
"expose": [{ "port": 80, "as": 8080 }]
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
kadi deploy --profile local
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**Local profile options:**
|
|
89
|
+
|
|
90
|
+
| Field | Description |
|
|
91
|
+
|-------|-------------|
|
|
92
|
+
| `target` | Must be `"local"` |
|
|
93
|
+
| `engine` | `"docker"` or `"podman"` |
|
|
94
|
+
| `network` | Docker network name (optional) |
|
|
95
|
+
| `services` | Service definitions (see below) |
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Deploying to Akash
|
|
100
|
+
|
|
101
|
+
Akash Network is a decentralized cloud platform. Deploying to Akash requires:
|
|
102
|
+
1. A Keplr wallet with AKT tokens
|
|
103
|
+
2. Scanning a QR code to connect your wallet
|
|
104
|
+
3. Selecting a provider from the bid list
|
|
105
|
+
|
|
106
|
+
```json
|
|
107
|
+
{
|
|
108
|
+
"deploy": {
|
|
109
|
+
"production": {
|
|
110
|
+
"target": "akash",
|
|
111
|
+
"network": "mainnet",
|
|
112
|
+
"services": {
|
|
113
|
+
"web": {
|
|
114
|
+
"image": "nginx:alpine",
|
|
115
|
+
"expose": [{ "port": 80, "as": 80, "to": [{ "global": true }] }],
|
|
116
|
+
"resources": {
|
|
117
|
+
"cpu": 0.5,
|
|
118
|
+
"memory": "512Mi",
|
|
119
|
+
"ephemeralStorage": "1Gi"
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
kadi deploy --profile production
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
The CLI will:
|
|
133
|
+
1. Generate a QR code - scan with Keplr mobile
|
|
134
|
+
2. Create/load your deployment certificate
|
|
135
|
+
3. Submit to Akash and collect bids
|
|
136
|
+
4. Let you select a provider interactively
|
|
137
|
+
5. Deploy and show your service endpoints
|
|
138
|
+
|
|
139
|
+
**Akash profile options:**
|
|
140
|
+
|
|
141
|
+
| Field | Description |
|
|
142
|
+
|-------|-------------|
|
|
143
|
+
| `target` | Must be `"akash"` |
|
|
144
|
+
| `network` | `"mainnet"` or `"testnet"` |
|
|
145
|
+
| `services` | Service definitions (see below) |
|
|
146
|
+
| `blacklist` | Provider addresses to exclude |
|
|
147
|
+
| `deposit` | Escrow deposit in AKT (default: 5) |
|
|
148
|
+
| `cert` | Path to saved certificate file |
|
|
149
|
+
| `useRemoteRegistry` | Skip local tunnel, assume images are in a public registry |
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Autonomous Deployment (Agent-Controlled)
|
|
154
|
+
|
|
155
|
+
The `--autonomous` flag enables fully autonomous deployment with **zero human interaction**. This is designed for AI agents and automation pipelines that need to deploy without prompts, QR codes, or manual bid selection.
|
|
156
|
+
|
|
157
|
+
### Prerequisites
|
|
158
|
+
|
|
159
|
+
Store your Akash wallet mnemonic in the KADI secrets vault:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
kadi secret set AKASH_WALLET "your twelve or twenty four word mnemonic phrase here" -v global
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
The mnemonic is encrypted at rest using age (ChaCha20-Poly1305) with your OS keychain protecting the master key.
|
|
166
|
+
|
|
167
|
+
### Usage
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
# Basic autonomous deployment (cheapest bid)
|
|
171
|
+
kadi deploy --profile production --autonomous
|
|
172
|
+
|
|
173
|
+
# Use a specific bid strategy
|
|
174
|
+
kadi deploy --autonomous --bid-strategy balanced
|
|
175
|
+
|
|
176
|
+
# Set a maximum price and require audited providers
|
|
177
|
+
kadi deploy --autonomous --bid-max-price 500 --require-audited
|
|
178
|
+
|
|
179
|
+
# Use a custom secrets vault
|
|
180
|
+
kadi deploy --autonomous --secrets-vault my-vault --bid-strategy balanced
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### What Happens
|
|
184
|
+
|
|
185
|
+
When `--autonomous` is set, the CLI:
|
|
186
|
+
|
|
187
|
+
1. **Reads wallet mnemonic** from the secrets vault (no QR code / Keplr)
|
|
188
|
+
2. **Creates or loads** the deployment certificate automatically
|
|
189
|
+
3. **Submits the deployment** to Akash Network
|
|
190
|
+
4. **Selects a provider** algorithmically based on `--bid-strategy`
|
|
191
|
+
5. **Shares secrets** with the deployment automatically (no approval prompt)
|
|
192
|
+
6. **Reports results** including endpoints and lease info
|
|
193
|
+
|
|
194
|
+
### Autonomous Flags
|
|
195
|
+
|
|
196
|
+
| Flag | Description | Default |
|
|
197
|
+
|------|-------------|---------|
|
|
198
|
+
| `--autonomous` | Enable autonomous mode | `false` |
|
|
199
|
+
| `--bid-strategy <strategy>` | `cheapest`, `most-reliable`, or `balanced` | `cheapest` |
|
|
200
|
+
| `--bid-max-price <uakt>` | Max price per block in uAKT | No limit |
|
|
201
|
+
| `--require-audited` | Only accept bids from audited providers | `false` |
|
|
202
|
+
| `--secrets-vault <vault>` | Vault for wallet mnemonic (does NOT affect deployment secrets) | `global` |
|
|
203
|
+
| `--auto-approve-secrets` | Auto-approve secret sharing (also works in interactive mode) | `false` |
|
|
204
|
+
| `--secret-timeout <ms>` | How long to wait for the agent to request secrets | `300000` |
|
|
205
|
+
|
|
206
|
+
### Bid Strategies
|
|
207
|
+
|
|
208
|
+
| Strategy | Behavior |
|
|
209
|
+
|----------|----------|
|
|
210
|
+
| `cheapest` | Selects the lowest-price bid. Best for cost-sensitive workloads. |
|
|
211
|
+
| `most-reliable` | Selects the provider with the highest uptime. Best for production. |
|
|
212
|
+
| `balanced` | Weighs price and reliability together. Good default for most cases. |
|
|
213
|
+
|
|
214
|
+
### Example: Agent Workflow
|
|
215
|
+
|
|
216
|
+
An AI agent can deploy with a single command:
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
kadi deploy \
|
|
220
|
+
--profile production \
|
|
221
|
+
--autonomous \
|
|
222
|
+
--bid-strategy balanced \
|
|
223
|
+
--bid-max-price 1000 \
|
|
224
|
+
--require-audited
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
The entire flow completes without any human interaction.
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## Tearing Down Deployments
|
|
232
|
+
|
|
233
|
+
The `kadi deploy down` command tears down an active deployment launched by `kadi deploy`. It works for both local (Docker/Podman) and Akash deployments.
|
|
234
|
+
|
|
235
|
+
After a successful deployment, kadi-deploy writes a `.kadi-deploy.lock` file to the project root that records everything needed to tear it down. The lock file supports **multiple simultaneous deployments** — you can have a local dev deployment and an Akash production deployment active at the same time.
|
|
236
|
+
|
|
237
|
+
### Multi-Profile Support
|
|
238
|
+
|
|
239
|
+
When multiple deployments are active:
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
# Specify which profile to tear down
|
|
243
|
+
kadi deploy down --profile dev
|
|
244
|
+
kadi deploy down --profile production
|
|
245
|
+
|
|
246
|
+
# If only one deployment is active, it's auto-selected
|
|
247
|
+
kadi deploy down
|
|
248
|
+
|
|
249
|
+
# If multiple are active and no --profile, you'll be prompted to choose
|
|
250
|
+
kadi deploy down --yes
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Local Teardown
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
# Tear down local containers
|
|
257
|
+
kadi deploy down
|
|
258
|
+
|
|
259
|
+
# Skip confirmation
|
|
260
|
+
kadi deploy down --yes
|
|
261
|
+
|
|
262
|
+
# Override container engine
|
|
263
|
+
kadi deploy down --engine podman
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
This runs `docker compose down --remove-orphans` (or `podman compose`) against the compose file recorded in the lock.
|
|
267
|
+
|
|
268
|
+
### Akash Teardown (Interactive)
|
|
269
|
+
|
|
270
|
+
```bash
|
|
271
|
+
# Close Akash deployment via WalletConnect QR
|
|
272
|
+
kadi deploy down
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
The CLI will:
|
|
276
|
+
1. Display the active deployment details (DSEQ, provider, network)
|
|
277
|
+
2. Ask for confirmation
|
|
278
|
+
3. Show a QR code — scan with Keplr mobile
|
|
279
|
+
4. Call `closeDeployment` on the blockchain
|
|
280
|
+
5. Display the transaction hash and refund info
|
|
281
|
+
6. Delete the lock file
|
|
282
|
+
|
|
283
|
+
### Akash Teardown (Autonomous)
|
|
284
|
+
|
|
285
|
+
For fully automated teardown without human interaction:
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
# Autonomous teardown using vault mnemonic
|
|
289
|
+
kadi deploy down --autonomous
|
|
290
|
+
|
|
291
|
+
# With custom vault
|
|
292
|
+
kadi deploy down --autonomous --secrets-vault my-wallet-vault
|
|
293
|
+
|
|
294
|
+
# Tear down a specific profile (required when multiple deployments are active)
|
|
295
|
+
kadi deploy down --autonomous --profile production
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
The autonomous path skips all interactive prompts (confirmation and profile selection), reads the wallet mnemonic from the secrets vault (same as `kadi deploy --autonomous`), signs the close transaction directly, and refunds the remaining escrow to your wallet.
|
|
299
|
+
|
|
300
|
+
> **Note:** If multiple deployments are active, `--autonomous` requires `--profile` to specify which one to tear down (it cannot prompt for selection).
|
|
301
|
+
|
|
302
|
+
### Down Flags
|
|
303
|
+
|
|
304
|
+
| Flag | Description | Default |
|
|
305
|
+
|------|-------------|----------|
|
|
306
|
+
| `-p, --project <path>` | Path to project with `.kadi-deploy.lock` | Current directory |
|
|
307
|
+
| `--profile <profile>` | Profile name to tear down (prompts if multiple; **required** in autonomous mode with multiple deployments) | Auto-select |
|
|
308
|
+
| `--engine <engine>` | Override container engine (`docker`/`podman`) | From lock file |
|
|
309
|
+
| `--network <network>` | Override Akash network (`mainnet`/`testnet`) | From lock file |
|
|
310
|
+
| `--autonomous` | No human interaction — skips confirmation, uses vault mnemonic for Akash | `false` |
|
|
311
|
+
| `--secrets-vault <vault>` | Vault for wallet mnemonic (autonomous mode) | `global` |
|
|
312
|
+
| `-y, --yes` | Skip confirmation prompt (implied by `--autonomous`) | `false` |
|
|
313
|
+
| `--verbose` | Detailed output | `false` |
|
|
314
|
+
|
|
315
|
+
### The Lock File
|
|
316
|
+
|
|
317
|
+
The `.kadi-deploy.lock` file is written to the project root after every successful deployment. It uses a v2 format that supports multiple simultaneous deployments keyed by profile name:
|
|
318
|
+
|
|
319
|
+
```json
|
|
320
|
+
{
|
|
321
|
+
"version": 2,
|
|
322
|
+
"deployments": {
|
|
323
|
+
"dev": {
|
|
324
|
+
"target": "local",
|
|
325
|
+
"profile": "dev",
|
|
326
|
+
"deployedAt": "2026-02-25T12:00:00.000Z",
|
|
327
|
+
"local": { "composePath": "...", "engine": "docker", ... }
|
|
328
|
+
},
|
|
329
|
+
"production": {
|
|
330
|
+
"target": "akash",
|
|
331
|
+
"profile": "production",
|
|
332
|
+
"deployedAt": "2026-02-25T14:00:00.000Z",
|
|
333
|
+
"akash": { "dseq": 12345678, "owner": "akash1...", ... }
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
Each entry contains:
|
|
340
|
+
|
|
341
|
+
- **Local deployments**: compose file path, engine, network, service names, container IDs
|
|
342
|
+
- **Akash deployments**: DSEQ, owner address, provider, network, gseq/oseq
|
|
343
|
+
|
|
344
|
+
When you tear down a profile, only that entry is removed. The file is deleted entirely when the last deployment is removed. Existing v1 lock files (single deployment) are transparently migrated on read.
|
|
345
|
+
|
|
346
|
+
It is safe to add `.kadi-deploy.lock` to `.gitignore`.
|
|
347
|
+
|
|
348
|
+
If the lock file is missing or was manually deleted, you can still tear down containers directly:
|
|
349
|
+
|
|
350
|
+
```bash
|
|
351
|
+
# Local: run compose down manually
|
|
352
|
+
docker compose down --remove-orphans
|
|
353
|
+
|
|
354
|
+
# Akash: close via Akash Console or CLI
|
|
355
|
+
# You'll need the DSEQ from the original deployment output
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
---
|
|
359
|
+
|
|
360
|
+
## Deployment Secrets
|
|
361
|
+
|
|
362
|
+
Declare secrets your deployed agent needs in the `secrets` block of a deploy profile. Before deployment, `kadi deploy` validates that every required secret exists in the vault and shares them with the container.
|
|
363
|
+
|
|
364
|
+
### Single Vault (Legacy)
|
|
365
|
+
|
|
366
|
+
```json
|
|
367
|
+
{
|
|
368
|
+
"deploy": {
|
|
369
|
+
"production": {
|
|
370
|
+
"target": "akash",
|
|
371
|
+
"network": "mainnet",
|
|
372
|
+
"services": { "..." : "..." },
|
|
373
|
+
"secrets": {
|
|
374
|
+
"vault": "my-agent",
|
|
375
|
+
"required": ["API_KEY", "DB_URL"],
|
|
376
|
+
"optional": ["DEBUG_KEY"],
|
|
377
|
+
"delivery": "broker"
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### Multi-Vault
|
|
385
|
+
|
|
386
|
+
When your agent needs secrets from more than one vault, use the `vaults` array:
|
|
387
|
+
|
|
388
|
+
```json
|
|
389
|
+
{
|
|
390
|
+
"deploy": {
|
|
391
|
+
"production": {
|
|
392
|
+
"target": "akash",
|
|
393
|
+
"network": "mainnet",
|
|
394
|
+
"services": { "..." : "..." },
|
|
395
|
+
"secrets": {
|
|
396
|
+
"vaults": [
|
|
397
|
+
{ "vault": "my-agent", "required": ["API_KEY", "API_URL"] },
|
|
398
|
+
{ "vault": "infra", "required": ["TUNNEL_TOKEN"], "optional": ["OBSERVABILITY_KEY"] }
|
|
399
|
+
],
|
|
400
|
+
"delivery": "broker"
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
Each vault entry specifies which secrets to pull from that vault. All vaults are created inside the container and each secret is stored in its designated vault.
|
|
408
|
+
|
|
409
|
+
### Secrets Fields
|
|
410
|
+
|
|
411
|
+
| Field | Description |
|
|
412
|
+
|-------|-------------|
|
|
413
|
+
| `vault` | (Legacy) Single vault name |
|
|
414
|
+
| `vaults` | (Multi-vault) Array of `{ vault, required?, optional? }` entries |
|
|
415
|
+
| `required` | Secret names that **must** exist before deployment (deploy fails if missing) |
|
|
416
|
+
| `optional` | Secret names shared if available (no error if missing) |
|
|
417
|
+
| `delivery` | `"env"` (default) — injected as plain env vars. `"broker"` — E2E encrypted handshake via broker |
|
|
418
|
+
|
|
419
|
+
Both formats are fully backwards compatible. Existing single-vault configs continue to work unchanged.
|
|
420
|
+
|
|
421
|
+
---
|
|
422
|
+
|
|
423
|
+
## Service Configuration
|
|
424
|
+
|
|
425
|
+
Services are defined the same way for both local and Akash deployments:
|
|
426
|
+
|
|
427
|
+
```json
|
|
428
|
+
{
|
|
429
|
+
"services": {
|
|
430
|
+
"api": {
|
|
431
|
+
"image": "myapp:latest",
|
|
432
|
+
"command": ["node", "server.js"],
|
|
433
|
+
"env": ["PORT=3000", "NODE_ENV=production"],
|
|
434
|
+
"expose": [{ "port": 3000, "as": 80, "to": [{ "global": true }] }],
|
|
435
|
+
"resources": {
|
|
436
|
+
"cpu": 0.5,
|
|
437
|
+
"memory": "512Mi",
|
|
438
|
+
"ephemeralStorage": "1Gi"
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
**Service fields:**
|
|
446
|
+
|
|
447
|
+
| Field | Description |
|
|
448
|
+
|-------|-------------|
|
|
449
|
+
| `image` | Container image |
|
|
450
|
+
| `command` | Override container command (array) |
|
|
451
|
+
| `env` | Environment variables (array of `KEY=value`) |
|
|
452
|
+
| `expose` | Port mappings |
|
|
453
|
+
| `resources` | CPU, memory, storage (Akash only) |
|
|
454
|
+
| `credentials` | Registry credentials for private images |
|
|
455
|
+
|
|
456
|
+
### Private Registry
|
|
457
|
+
|
|
458
|
+
For private images, add credentials:
|
|
459
|
+
|
|
460
|
+
```json
|
|
461
|
+
{
|
|
462
|
+
"services": {
|
|
463
|
+
"app": {
|
|
464
|
+
"image": "ghcr.io/myorg/private-app:main",
|
|
465
|
+
"credentials": {
|
|
466
|
+
"host": "ghcr.io",
|
|
467
|
+
"username": "github-username",
|
|
468
|
+
"password": "github-token"
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
### Multi-Service
|
|
476
|
+
|
|
477
|
+
Services can communicate with each other:
|
|
478
|
+
|
|
479
|
+
```json
|
|
480
|
+
{
|
|
481
|
+
"services": {
|
|
482
|
+
"frontend": {
|
|
483
|
+
"image": "nginx:alpine",
|
|
484
|
+
"expose": [{ "port": 80, "as": 80, "to": [{ "global": true }] }]
|
|
485
|
+
},
|
|
486
|
+
"backend": {
|
|
487
|
+
"image": "node:20-alpine",
|
|
488
|
+
"expose": [{ "port": 3000, "to": [{ "service": "frontend" }] }]
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
---
|
|
495
|
+
|
|
496
|
+
## Local Images on Akash
|
|
497
|
+
|
|
498
|
+
When deploying local images to Akash, kadi-deploy automatically:
|
|
499
|
+
|
|
500
|
+
1. Starts a temporary container registry
|
|
501
|
+
2. Pushes your local images to it
|
|
502
|
+
3. Exposes the registry via tunnel (kadi, ngrok, serveo, or localtunnel)
|
|
503
|
+
4. Rewrites image URLs in the deployment manifest
|
|
504
|
+
5. Waits for the provider to pull images
|
|
505
|
+
6. Shuts down the registry once containers are running
|
|
506
|
+
|
|
507
|
+
This happens automatically - no configuration needed for local images.
|
|
508
|
+
|
|
509
|
+
---
|
|
510
|
+
|
|
511
|
+
## CLI Options
|
|
512
|
+
|
|
513
|
+
```bash
|
|
514
|
+
kadi deploy # Use first available profile
|
|
515
|
+
kadi deploy --profile production # Use specific profile
|
|
516
|
+
kadi deploy --project /path/to/app # Specify project directory
|
|
517
|
+
kadi deploy --dry-run # Preview without deploying
|
|
518
|
+
kadi deploy --verbose # Detailed output
|
|
519
|
+
kadi deploy --yes # Skip confirmation prompts
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
**Override profile settings:**
|
|
523
|
+
|
|
524
|
+
```bash
|
|
525
|
+
kadi deploy --network testnet # Override Akash network
|
|
526
|
+
kadi deploy --engine podman # Override container engine
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
**Autonomous deployment:**
|
|
530
|
+
|
|
531
|
+
```bash
|
|
532
|
+
kadi deploy --autonomous # No human interaction
|
|
533
|
+
kadi deploy --autonomous --bid-strategy balanced # Pick balanced provider
|
|
534
|
+
kadi deploy --autonomous --bid-max-price 500 # Cap bid price
|
|
535
|
+
kadi deploy --autonomous --require-audited # Audited providers only
|
|
536
|
+
kadi deploy --autonomous --secrets-vault myvault # Custom vault
|
|
537
|
+
kadi deploy --auto-approve-secrets # Works in interactive mode too
|
|
538
|
+
kadi deploy --secret-timeout 120000 # 2 min timeout for secret handshake
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
**Tear down deployments:**
|
|
542
|
+
|
|
543
|
+
```bash
|
|
544
|
+
kadi deploy down # Tear down active deployment
|
|
545
|
+
kadi deploy down --yes # Skip confirmation (interactive)
|
|
546
|
+
kadi deploy down --autonomous # Fully non-interactive (skips confirmation + QR)
|
|
547
|
+
kadi deploy down --autonomous --profile prod # Required when multiple deployments active
|
|
548
|
+
kadi deploy down --autonomous --secrets-vault v # Akash: custom vault
|
|
549
|
+
kadi deploy down --engine podman # Override container engine
|
|
550
|
+
kadi deploy down --verbose # Detailed output
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
---
|
|
554
|
+
|
|
555
|
+
## Troubleshooting
|
|
556
|
+
|
|
557
|
+
### Local Deployment
|
|
558
|
+
|
|
559
|
+
```bash
|
|
560
|
+
# Check container engine
|
|
561
|
+
docker --version
|
|
562
|
+
podman --version
|
|
563
|
+
|
|
564
|
+
# Start Podman machine (macOS)
|
|
565
|
+
podman machine start
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
### Akash Deployment
|
|
569
|
+
|
|
570
|
+
**Certificate issues:** If deployment fails with a certificate error, add the cert path to your profile:
|
|
571
|
+
```json
|
|
572
|
+
{
|
|
573
|
+
"deploy": {
|
|
574
|
+
"production": {
|
|
575
|
+
"cert": "~/.kadi/certificate.json"
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
**Preview before deploying:**
|
|
582
|
+
```bash
|
|
583
|
+
kadi deploy --profile production --dry-run
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
**Verbose output for debugging:**
|
|
587
|
+
```bash
|
|
588
|
+
kadi deploy --profile production --verbose
|
|
589
|
+
```
|
package/agent.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "kadi-deploy",
|
|
3
|
+
"version": "0.19.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"type": "plugin",
|
|
6
|
+
"entrypoint": "dist/index.js",
|
|
7
|
+
"commands": ["deploy"],
|
|
8
|
+
"description": "CLI plugin that converts an agent's deploy spec into platform-specific artifacts (Akash SDL, Docker Compose, etc.) and orchestrates the deployment process.",
|
|
9
|
+
"repo": "https://gitlab.com/humin-game-lab/kadi/kadi-deploy.git",
|
|
10
|
+
"lib": "https://gitlab.com/humin-game-lab/kadi/kadi-deploy/-/archive/v0.19.0/kadi-deploy-v0.19.0.zip",
|
|
11
|
+
"api": "http://127.0.0.1:8000",
|
|
12
|
+
"brokers": {
|
|
13
|
+
"local": "ws://127.0.0.1:8080",
|
|
14
|
+
"remote": "wss://broker.kadi.build"
|
|
15
|
+
},
|
|
16
|
+
"abilities": {
|
|
17
|
+
"secret-ability": "^0.9.1"
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"preflight": "node scripts/preflight.js",
|
|
21
|
+
"setup": "npm install && npm run build"
|
|
22
|
+
}
|
|
23
|
+
}
|
package/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KADI Deploy Plugin Entry Point
|
|
3
|
+
*
|
|
4
|
+
* This file imports and re-exports the TypeScript implementation
|
|
5
|
+
* of the deploy plugin.
|
|
6
|
+
* The TypeScript version provides profile-based configuration while
|
|
7
|
+
* maintaining full backward compatibility with the existing CLI flags.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// Import the compiled TypeScript implementation
|
|
11
|
+
export { default } from './dist/index.js';
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "kadi-deploy",
|
|
3
|
+
"version": "0.19.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "tsc",
|
|
8
|
+
"setup": "npm install && npm run build",
|
|
9
|
+
"format": "prettier --write .",
|
|
10
|
+
"test": "vitest run"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [],
|
|
13
|
+
"author": "",
|
|
14
|
+
"license": "ISC",
|
|
15
|
+
"description": "",
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@kadi.build/container-registry-ability": "^0.0.7",
|
|
18
|
+
"@kadi.build/core": "^0.11.0",
|
|
19
|
+
"@kadi.build/deploy-ability": "^0.0.13",
|
|
20
|
+
"chalk": "^5",
|
|
21
|
+
"commander": "^14.0.0",
|
|
22
|
+
"debug": "^4.3.7",
|
|
23
|
+
"ed2curve": "^0.3.0",
|
|
24
|
+
"enquirer": "^2",
|
|
25
|
+
"node-localstorage": "^3.0.5",
|
|
26
|
+
"ora": "^7",
|
|
27
|
+
"qrcode-terminal": "^0.12.0",
|
|
28
|
+
"tweetnacl": "^1.0.3",
|
|
29
|
+
"tweetnacl-sealedbox-js": "^1.2.0",
|
|
30
|
+
"tweetnacl-util": "^0.15.1",
|
|
31
|
+
"zod": "^4.1.12"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/debug": "^4.1.12",
|
|
35
|
+
"@types/node": "^24.3.0",
|
|
36
|
+
"@types/node-localstorage": "^1.3.3",
|
|
37
|
+
"@types/qrcode-terminal": "^0.12.2",
|
|
38
|
+
"prettier": "^3.6.2",
|
|
39
|
+
"typescript": "^5.9.2",
|
|
40
|
+
"vitest": "^3.2.4"
|
|
41
|
+
}
|
|
42
|
+
}
|