@kadi.build/deploy-ability 0.0.7 → 0.0.9

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.
Files changed (38) hide show
  1. package/.env-example +72 -0
  2. package/README.md +240 -0
  3. package/dist/targets/akash/deployer.d.ts +64 -3
  4. package/dist/targets/akash/deployer.d.ts.map +1 -1
  5. package/dist/targets/akash/deployer.js +170 -4
  6. package/dist/targets/akash/deployer.js.map +1 -1
  7. package/dist/targets/akash/index.d.ts +86 -2
  8. package/dist/targets/akash/index.d.ts.map +1 -1
  9. package/dist/targets/akash/index.js +49 -2
  10. package/dist/targets/akash/index.js.map +1 -1
  11. package/dist/targets/akash/secrets-provider.d.ts +189 -0
  12. package/dist/targets/akash/secrets-provider.d.ts.map +1 -0
  13. package/dist/targets/akash/secrets-provider.js +249 -0
  14. package/dist/targets/akash/secrets-provider.js.map +1 -0
  15. package/dist/targets/akash/types.d.ts +96 -0
  16. package/dist/targets/akash/types.d.ts.map +1 -1
  17. package/dist/targets/akash/wallet-manager.d.ts +21 -3
  18. package/dist/targets/akash/wallet-manager.d.ts.map +1 -1
  19. package/dist/targets/akash/wallet-manager.js +137 -8
  20. package/dist/targets/akash/wallet-manager.js.map +1 -1
  21. package/dist/types/index.d.ts +1 -1
  22. package/dist/types/index.d.ts.map +1 -1
  23. package/dist/types/index.js.map +1 -1
  24. package/dist/types/options.d.ts +74 -0
  25. package/dist/types/options.d.ts.map +1 -1
  26. package/dist/utils/registry/manager.d.ts +10 -9
  27. package/dist/utils/registry/manager.d.ts.map +1 -1
  28. package/dist/utils/registry/manager.js +28 -18
  29. package/dist/utils/registry/manager.js.map +1 -1
  30. package/dist/utils/registry/setup.d.ts +2 -2
  31. package/dist/utils/registry/setup.d.ts.map +1 -1
  32. package/dist/utils/registry/setup.js +7 -5
  33. package/dist/utils/registry/setup.js.map +1 -1
  34. package/dist/utils/registry/transformer.d.ts +1 -1
  35. package/dist/utils/registry/transformer.js +1 -1
  36. package/dist/utils/registry/types.d.ts +36 -12
  37. package/dist/utils/registry/types.d.ts.map +1 -1
  38. package/package.json +3 -2
package/.env-example ADDED
@@ -0,0 +1,72 @@
1
+ # Local & Remote File Manager Configuration
2
+ # Copy this file to .env and customize the values
3
+
4
+ # =============================================================================
5
+ # LOCAL FILE SYSTEM CONFIGURATION
6
+ # =============================================================================
7
+
8
+ # Directory Paths (customize these for your setup)
9
+ DEFAULT_LOCAL_ROOT=/Users/yourname/Documents
10
+ DEFAULT_UPLOAD_DIRECTORY=./uploads
11
+ DEFAULT_DOWNLOAD_DIRECTORY=./downloads
12
+ DEFAULT_TEMP_DIRECTORY=./temp
13
+
14
+ # File Operation Limits
15
+ MAX_FILE_SIZE=1073741824
16
+ CHUNK_SIZE=8388608
17
+ MAX_RETRY_ATTEMPTS=3
18
+ TIMEOUT_MS=30000
19
+
20
+ # Performance Settings
21
+ MAX_CONCURRENT_OPERATIONS=5
22
+ ENABLE_PROGRESS_TRACKING=true
23
+ ENABLE_CHECKSUM_VERIFICATION=true
24
+
25
+ # Security Settings
26
+ ALLOW_SYMLINKS=false
27
+ RESTRICT_TO_BASE_PATH=true
28
+ MAX_PATH_LENGTH=255
29
+
30
+ # =============================================================================
31
+ # FEATURE CONFIGURATION (Future Buckets)
32
+ # =============================================================================
33
+
34
+ # File Watching (Bucket 2)
35
+ WATCH_ENABLED=true
36
+ WATCH_RECURSIVE=true
37
+ WATCH_IGNORE_DOTFILES=true
38
+ WATCH_DEBOUNCE_MS=100
39
+
40
+ # Compression (Bucket 3)
41
+ COMPRESSION_ENABLED=true
42
+ COMPRESSION_LEVEL=6
43
+ COMPRESSION_FORMAT=zip
44
+
45
+ # Tunneling (Bucket 4) - Multi-Service Configuration
46
+ TUNNEL_SERVICE=kadi
47
+ TUNNEL_FALLBACK_SERVICES=ngrok,serveo,localtunnel
48
+ TUNNEL_AUTH_TOKEN=
49
+ TUNNEL_SUBDOMAIN=
50
+ TUNNEL_REGION=us
51
+ TUNNEL_AUTO_FALLBACK=true
52
+
53
+ # Ngrok-specific configuration
54
+ NGROK_AUTH_TOKEN=your-ngrok-auth-token
55
+ NGROK_REGION=us
56
+ NGROK_PROTOCOL=http
57
+
58
+ # KĀDI Tunnel Configuration
59
+ KADI_TUNNEL_SERVER=broker.kadi.build
60
+ KADI_TUNNEL_SSH_PORT=2200
61
+ KADI_TUNNEL_TOKEN=your-kadi-tunnel-token
62
+ KADI_TUNNEL_DOMAIN=tunnel.kadi.build
63
+ KADI_TUNNEL_MODE=frpc
64
+ KADI_TUNNEL_TRANSPORT=wss
65
+ KADI_TUNNEL_WSS_HOST=tunnel-control.kadi.build
66
+ KADI_AGENT_ID=kadi
67
+
68
+
69
+ # Logging
70
+ LOG_LEVEL=info
71
+ ENABLE_FILE_LOGGING=false
72
+ LOG_FILE_PATH=./logs/application.log
package/README.md CHANGED
@@ -16,6 +16,7 @@
16
16
  **Type-Safe** - Complete TypeScript support with zero `any` types
17
17
  **Delightful API** - Simple for common tasks, powerful for advanced use cases
18
18
  **Flexible Wallet Support** - Human approval (WalletConnect) or autonomous signing (agents)
19
+ **Autonomous Mode** - Fully automated deployments with secure secrets integration
19
20
  **Well-Documented** - Comprehensive JSDoc with IntelliSense
20
21
  **Production-Ready** - Handles Akash Network complexity elegantly
21
22
 
@@ -167,6 +168,30 @@ if (result.success) {
167
168
  }
168
169
  ```
169
170
 
171
+ ### Autonomous Deployment (Agent-Controlled)
172
+
173
+ For fully automated deployments with secrets integration:
174
+
175
+ ```typescript
176
+ import { createSecretsProvider, deployToAkash } from 'deploy-ability';
177
+
178
+ // In a KADI agent:
179
+ const secrets = createSecretsProvider(this.secrets);
180
+
181
+ const result = await deployToAkash({
182
+ autonomous: { secrets, bidStrategy: 'cheapest' },
183
+ projectRoot: process.cwd(),
184
+ profile: 'production',
185
+ network: 'mainnet',
186
+ });
187
+
188
+ if (result.success) {
189
+ console.log(`Deployed! DSEQ: ${result.data.dseq}`);
190
+ }
191
+ ```
192
+
193
+ See [Autonomous Deployment with Secrets Integration](#autonomous-deployment-with-secrets-integration) for full details.
194
+
170
195
  ### Deploy to Local Docker
171
196
 
172
197
  ```typescript
@@ -329,6 +354,221 @@ class SelfDeployingAgent {
329
354
 
330
355
  ---
331
356
 
357
+ ## Autonomous Deployment with Secrets Integration
358
+
359
+ For fully automated deployments, deploy-ability integrates with KADI's `secret-ability` to securely retrieve wallet mnemonics from encrypted vaults. This enables agents to deploy without any user interaction while keeping secrets secure.
360
+
361
+ ### How It Works
362
+
363
+ ```mermaid
364
+ sequenceDiagram
365
+ participant Agent as KADI Agent
366
+ participant Secrets as secret-ability
367
+ participant Keychain as OS Keychain
368
+ participant Deploy as deploy-ability
369
+ participant Akash as Akash Network
370
+
371
+ Agent->>Secrets: Get mnemonic from vault
372
+ Secrets->>Keychain: Get master key
373
+ Keychain-->>Secrets: Master key
374
+ Secrets-->>Agent: Decrypted mnemonic
375
+ Agent->>Deploy: deployToAkash({ autonomous: { secrets } })
376
+ Deploy->>Akash: Create deployment (auto-sign)
377
+ Akash-->>Deploy: Deployment result
378
+ Deploy-->>Agent: Success!
379
+ ```
380
+
381
+ ### Vault Configuration
382
+
383
+ Secrets are stored in a **global vault** at the machine level:
384
+
385
+ | Setting | Value |
386
+ |---------|-------|
387
+ | Config Path | `~/.kadi/secrets/config.toml` |
388
+ | Vault Name | `global` |
389
+ | Vault Type | `age` (ChaCha20-Poly1305 encryption) |
390
+ | Master Key | Stored in OS Keychain (macOS Keychain, GNOME Keyring, etc.) |
391
+
392
+ ### Secret Keys
393
+
394
+ | Key | Description |
395
+ |-----|-------------|
396
+ | `AKASH_WALLET` | BIP39 mnemonic phrase (12 or 24 words) |
397
+ | `akash-tls-certificate` | Cached TLS certificate for provider communication |
398
+ | `akash-wallet-password` | Optional BIP39 passphrase |
399
+
400
+ ### Setup: Store Your Mnemonic
401
+
402
+ Before using autonomous deployment, store your mnemonic in the global vault:
403
+
404
+ ```bash
405
+ # Using KADI CLI
406
+ kadi secrets set --vault global --key AKASH_WALLET --value "your 12 or 24 word mnemonic phrase here"
407
+ ```
408
+
409
+ Or programmatically with secret-ability:
410
+
411
+ ```typescript
412
+ // 1. Create the global vault (one-time)
413
+ await secrets.invoke('config.createVault', {
414
+ configPath: '~/.kadi/secrets/config.toml',
415
+ name: 'global',
416
+ type: 'age'
417
+ });
418
+
419
+ // 2. Store the mnemonic
420
+ await secrets.invoke('set', {
421
+ configPath: '~/.kadi/secrets/config.toml',
422
+ vault: 'global',
423
+ key: 'AKASH_WALLET',
424
+ value: 'your 12 or 24 word mnemonic phrase here'
425
+ });
426
+ ```
427
+
428
+ ### Usage: Autonomous Deployment
429
+
430
+ #### Option 1: Using `createSecretsProvider` (Recommended)
431
+
432
+ Integrates directly with KADI's secret-ability:
433
+
434
+ ```typescript
435
+ import {
436
+ createSecretsProvider,
437
+ deployToAkash
438
+ } from 'deploy-ability';
439
+
440
+ // In a KADI agent context:
441
+ class DeploymentAgent {
442
+ async deploy(profile: string) {
443
+ // Create secrets provider from secret-ability client
444
+ const secrets = createSecretsProvider(this.secrets);
445
+
446
+ // Deploy autonomously - no user interaction needed!
447
+ const result = await deployToAkash({
448
+ autonomous: {
449
+ secrets,
450
+ bidStrategy: 'cheapest', // or 'most-reliable'
451
+ },
452
+ projectRoot: process.cwd(),
453
+ profile,
454
+ network: 'mainnet',
455
+ });
456
+
457
+ if (result.success) {
458
+ console.log(`Deployed! DSEQ: ${result.data.dseq}`);
459
+ console.log(`Provider: ${result.data.providerUri}`);
460
+ }
461
+
462
+ return result;
463
+ }
464
+ }
465
+ ```
466
+
467
+ #### Option 2: Using `createSimpleMnemonicProvider` (Testing)
468
+
469
+ For testing or when secret-ability is not available:
470
+
471
+ ```typescript
472
+ import {
473
+ createSimpleMnemonicProvider,
474
+ deployToAkash
475
+ } from 'deploy-ability';
476
+
477
+ // ⚠️ For testing only - mnemonic stored in memory
478
+ const secrets = createSimpleMnemonicProvider(
479
+ 'test test test test test test test test test test test junk'
480
+ );
481
+
482
+ const result = await deployToAkash({
483
+ autonomous: {
484
+ secrets,
485
+ bidStrategy: 'cheapest',
486
+ },
487
+ projectRoot: './my-app',
488
+ profile: 'production',
489
+ network: 'testnet', // Use testnet for testing!
490
+ });
491
+ ```
492
+
493
+ #### Option 3: Custom SecretsProvider
494
+
495
+ Implement the `SecretsProvider` interface for custom secret backends:
496
+
497
+ ```typescript
498
+ import { deployToAkash, SecretsProvider } from 'deploy-ability';
499
+
500
+ // Custom provider (e.g., AWS Secrets Manager, HashiCorp Vault)
501
+ const customSecrets: SecretsProvider = {
502
+ async getMnemonic() {
503
+ // Fetch from your secret backend
504
+ return await mySecretManager.getSecret('akash-wallet-mnemonic');
505
+ },
506
+
507
+ async getCertificate() {
508
+ // Optional: return cached certificate
509
+ const cert = await mySecretManager.getSecret('akash-certificate');
510
+ return cert ? JSON.parse(cert) : null;
511
+ },
512
+
513
+ async storeCertificate(cert) {
514
+ // Optional: cache the certificate
515
+ await mySecretManager.setSecret('akash-certificate', JSON.stringify(cert));
516
+ },
517
+ };
518
+
519
+ const result = await deployToAkash({
520
+ autonomous: { secrets: customSecrets, bidStrategy: 'cheapest' },
521
+ projectRoot: './my-app',
522
+ profile: 'production',
523
+ network: 'mainnet',
524
+ });
525
+ ```
526
+
527
+ ### Bid Selection Strategies
528
+
529
+ When deploying autonomously, you must specify a bid selection strategy:
530
+
531
+ | Strategy | Description |
532
+ |----------|-------------|
533
+ | `'cheapest'` | Select the lowest price bid |
534
+ | `'most-reliable'` | Select the bid with highest provider uptime |
535
+ | `'balanced'` | Balance between price and provider reliability |
536
+
537
+ You can also add filters:
538
+
539
+ ```typescript
540
+ autonomous: {
541
+ secrets,
542
+ bidStrategy: 'cheapest',
543
+ bidFilter: {
544
+ maxPricePerMonth: { uakt: 5_000_000 }, // Max 5 AKT/month
545
+ requireAudited: true, // Only audited providers
546
+ minUptime: { value: 0.95, period: '7d' }, // 95% uptime over 7 days
547
+ },
548
+ }
549
+ ```
550
+
551
+ ### Exported Constants
552
+
553
+ For programmatic access to configuration:
554
+
555
+ ```typescript
556
+ import {
557
+ AKASH_VAULT_NAME, // 'global'
558
+ GLOBAL_CONFIG_PATH, // '~/.kadi/secrets/config.toml'
559
+ AKASH_SECRET_KEYS, // { WALLET_MNEMONIC: 'AKASH_WALLET', ... }
560
+ } from 'deploy-ability';
561
+ ```
562
+
563
+ ### Security Model
564
+
565
+ 1. **Encrypted at Rest**: Secrets are encrypted with ChaCha20-Poly1305 in `config.toml`
566
+ 2. **Master Key in Keychain**: The encryption key is stored in the OS keychain (never in files)
567
+ 3. **No Plaintext**: Mnemonics are never written to disk in plaintext
568
+ 4. **Per-Machine**: Secrets are tied to the machine's keychain - can't be copied
569
+
570
+ ---
571
+
332
572
  ## Error Handling
333
573
 
334
574
  deploy-ability uses a **Result type pattern** for predictable error handling:
@@ -12,24 +12,29 @@
12
12
  *
13
13
  * @module targets/akash/deployer
14
14
  */
15
- import { type AkashDeploymentOptions, type AkashDeploymentResult } from '../../types/index.js';
15
+ import { type AkashDeploymentOptions, type AkashDeploymentResult, type AutonomousDeploymentConfig } from '../../types/index.js';
16
16
  import type { BidSelector } from './bids.js';
17
17
  import type { AkashProviderTlsCertificate, WalletContext } from './types.js';
18
18
  /**
19
19
  * Additional parameters required to execute a deployment
20
20
  *
21
+ * Supports two modes:
22
+ * 1. **Manual mode**: Provide `wallet`, `certificate`, and `bidSelector` directly
23
+ * 2. **Autonomous mode**: Provide `autonomous` config for fully automated deployment
24
+ *
21
25
  * For dry-run mode, wallet and certificate are optional (only SDL generation needed).
22
- * For actual deployments, wallet, certificate, and bidSelector are all required.
23
26
  */
24
27
  export interface AkashDeploymentExecution extends AkashDeploymentOptions {
25
28
  readonly wallet?: WalletContext;
26
29
  readonly certificate?: AkashProviderTlsCertificate;
27
30
  /**
28
- * Bid selection function
31
+ * Bid selection function (manual mode)
29
32
  *
30
33
  * Called with all available bids after waiting for provider responses.
31
34
  * Must return the selected bid or null if none are acceptable.
32
35
  *
36
+ * Not required when using `autonomous` mode.
37
+ *
33
38
  * @example
34
39
  * ```typescript
35
40
  * import { deployToAkash, selectCheapestBid} from '@kadi.build/deploy-ability/akash';
@@ -49,9 +54,65 @@ export interface AkashDeploymentExecution extends AkashDeploymentOptions {
49
54
  * @default 180000 (3 minutes)
50
55
  */
51
56
  readonly bidTimeout?: number;
57
+ /**
58
+ * Autonomous deployment configuration
59
+ *
60
+ * When provided, enables fully automated deployment without user interaction:
61
+ * - Wallet is created from mnemonic provided by SecretsProvider
62
+ * - Certificate is retrieved from cache or auto-generated
63
+ * - Bids are selected algorithmically based on strategy
64
+ *
65
+ * This is mutually exclusive with `wallet`, `certificate`, and `bidSelector`.
66
+ *
67
+ * @example
68
+ * ```typescript
69
+ * const result = await deployToAkash({
70
+ * projectRoot: './',
71
+ * profile: 'production',
72
+ * autonomous: {
73
+ * secrets: {
74
+ * getMnemonic: () => vault.getSecret('wallet-mnemonic'),
75
+ * getCertificate: () => storage.get('akash-cert'),
76
+ * storeCertificate: (cert) => storage.set('akash-cert', cert),
77
+ * },
78
+ * bidStrategy: 'cheapest',
79
+ * }
80
+ * });
81
+ * ```
82
+ */
83
+ readonly autonomous?: AutonomousDeploymentConfig;
52
84
  }
53
85
  /**
54
86
  * Executes a full Akash deployment.
87
+ *
88
+ * Supports two modes:
89
+ * 1. **Manual mode**: Provide `wallet`, `certificate`, and `bidSelector` directly
90
+ * 2. **Autonomous mode**: Provide `autonomous` config for fully automated deployment
91
+ *
92
+ * @example Manual mode
93
+ * ```typescript
94
+ * const result = await deployToAkash({
95
+ * wallet: myWallet,
96
+ * certificate: myCert,
97
+ * bidSelector: selectCheapestBid,
98
+ * projectRoot: './',
99
+ * profile: 'production',
100
+ * });
101
+ * ```
102
+ *
103
+ * @example Autonomous mode (agent-controlled)
104
+ * ```typescript
105
+ * const result = await deployToAkash({
106
+ * projectRoot: './',
107
+ * profile: 'production',
108
+ * autonomous: {
109
+ * secrets: {
110
+ * getMnemonic: () => vault.getSecret('wallet-mnemonic'),
111
+ * },
112
+ * bidStrategy: 'cheapest',
113
+ * }
114
+ * });
115
+ * ```
55
116
  */
56
117
  export declare function deployToAkash(params: AkashDeploymentExecution): Promise<AkashDeploymentResult>;
57
118
  //# sourceMappingURL=deployer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"deployer.d.ts","sourceRoot":"","sources":["../../../src/targets/akash/deployer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAGL,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAM3B,MAAM,sBAAsB,CAAC;AAQ9B,OAAO,KAAK,EAAe,WAAW,EAAe,MAAM,WAAW,CAAC;AAcvE,OAAO,KAAK,EAAE,2BAA2B,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAuF7E;;;;;GAKG;AACH,MAAM,WAAW,wBAAyB,SAAQ,sBAAsB;IACtE,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;IAChC,QAAQ,CAAC,WAAW,CAAC,EAAE,2BAA2B,CAAC;IAEnD;;;;;;;;;;;;;;;;;;OAkBG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC;IAEnC;;;OAGG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,wBAAwB,GAC/B,OAAO,CAAC,qBAAqB,CAAC,CAwdhC"}
1
+ {"version":3,"file":"deployer.d.ts","sourceRoot":"","sources":["../../../src/targets/akash/deployer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAGL,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAI1B,KAAK,0BAA0B,EAGhC,MAAM,sBAAsB,CAAC;AAQ9B,OAAO,KAAK,EAAe,WAAW,EAAe,MAAM,WAAW,CAAC;AAoBvE,OAAO,KAAK,EAAE,2BAA2B,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAyF7E;;;;;;;;GAQG;AACH,MAAM,WAAW,wBAAyB,SAAQ,sBAAsB;IACtE,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;IAChC,QAAQ,CAAC,WAAW,CAAC,EAAE,2BAA2B,CAAC;IAEnD;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC;IAEnC;;;OAGG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAE7B;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,0BAA0B,CAAC;CAClD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,wBAAwB,GAC/B,OAAO,CAAC,qBAAqB,CAAC,CA+lBhC"}
@@ -16,12 +16,15 @@ import Long from 'long';
16
16
  import { success, failure, createWalletAddress, createDeploymentSequence, } from '../../types/index.js';
17
17
  import { defaultLogger } from '../../utils/logger.js';
18
18
  import { loadProfile } from '../../utils/profile-loader.js';
19
+ import { selectCheapestBid, selectMostReliableBid, selectBalancedBid, filterBids, } from './bids.js';
19
20
  import { sendManifestToProvider, fetchProviderLeaseStatus, } from './provider-manager.js';
20
21
  import { AkashClient } from './client.js';
21
22
  import { waitForContainersRunning } from './lease-monitor.js';
22
23
  import { LeasePrice } from './pricing.js';
23
24
  import { generateAkashSdl, createSdlObject, } from './sdl-generator.js';
24
25
  import { DeploymentError, getErrorMessage } from '../../errors/index.js';
26
+ import { createWalletFromMnemonic } from './wallet-manager.js';
27
+ import { CertificateManager } from './certificate-manager.js';
25
28
  /**
26
29
  * Intelligent blacklist resolution with progressive disclosure
27
30
  *
@@ -85,9 +88,38 @@ function resolveBlacklist(profileBlacklist, optionsBlacklist, logger) {
85
88
  }
86
89
  /**
87
90
  * Executes a full Akash deployment.
91
+ *
92
+ * Supports two modes:
93
+ * 1. **Manual mode**: Provide `wallet`, `certificate`, and `bidSelector` directly
94
+ * 2. **Autonomous mode**: Provide `autonomous` config for fully automated deployment
95
+ *
96
+ * @example Manual mode
97
+ * ```typescript
98
+ * const result = await deployToAkash({
99
+ * wallet: myWallet,
100
+ * certificate: myCert,
101
+ * bidSelector: selectCheapestBid,
102
+ * projectRoot: './',
103
+ * profile: 'production',
104
+ * });
105
+ * ```
106
+ *
107
+ * @example Autonomous mode (agent-controlled)
108
+ * ```typescript
109
+ * const result = await deployToAkash({
110
+ * projectRoot: './',
111
+ * profile: 'production',
112
+ * autonomous: {
113
+ * secrets: {
114
+ * getMnemonic: () => vault.getSecret('wallet-mnemonic'),
115
+ * },
116
+ * bidStrategy: 'cheapest',
117
+ * }
118
+ * });
119
+ * ```
88
120
  */
89
121
  export async function deployToAkash(params) {
90
- const { wallet, certificate, bidSelector, logger: customLogger, dryRun = false, ...options } = params;
122
+ const { wallet: providedWallet, certificate: providedCertificate, bidSelector: providedBidSelector, autonomous, logger: customLogger, dryRun = false, ...options } = params;
91
123
  const logger = customLogger ?? defaultLogger;
92
124
  // ---------------------------------------------------------------------------
93
125
  // Load and validate deployment profile
@@ -133,17 +165,106 @@ export async function deployToAkash(params) {
133
165
  return success(dryRunResult);
134
166
  }
135
167
  // ---------------------------------------------------------------------------
168
+ // Resolve wallet, certificate, and bid selector
169
+ // Either from direct params (manual mode) or autonomous config
170
+ // ---------------------------------------------------------------------------
171
+ let wallet = providedWallet;
172
+ let certificate = providedCertificate;
173
+ let bidSelector = providedBidSelector;
174
+ // Track if we're in autonomous mode for cleanup
175
+ // Note: isAutonomous could be used for future cleanup logic
176
+ const _isAutonomous = !!autonomous;
177
+ void _isAutonomous;
178
+ if (autonomous) {
179
+ logger.log('🤖 Autonomous mode: setting up agent-controlled wallet...');
180
+ // Step 1: Get mnemonic from secrets provider
181
+ let mnemonic;
182
+ try {
183
+ mnemonic = await autonomous.secrets.getMnemonic();
184
+ }
185
+ catch (error) {
186
+ const errMsg = getErrorMessage(error);
187
+ return failure(new DeploymentError(`Failed to retrieve mnemonic from secrets provider: ${errMsg}`, 'SECRETS_ERROR', { error: errMsg }, false, 'Ensure your SecretsProvider.getMnemonic() is working correctly'));
188
+ }
189
+ // Step 2: Create wallet from mnemonic
190
+ const walletResult = await createWalletFromMnemonic(mnemonic, network);
191
+ if (!walletResult.success) {
192
+ return failure(new DeploymentError(`Failed to create wallet from mnemonic: ${walletResult.error.message}`, 'WALLET_CREATION_FAILED', { originalError: walletResult.error }, false, 'Check that the mnemonic is a valid BIP39 phrase (12 or 24 words)'));
193
+ }
194
+ wallet = walletResult.data;
195
+ logger.log(`✓ Wallet ready: ${wallet.address}`);
196
+ // Step 3: Get or create certificate
197
+ // First, try to get existing certificate from secrets provider
198
+ if (autonomous.secrets.getCertificate) {
199
+ try {
200
+ const existingCert = await autonomous.secrets.getCertificate();
201
+ if (existingCert) {
202
+ certificate = existingCert;
203
+ logger.log('✓ Using cached certificate from secrets provider');
204
+ }
205
+ }
206
+ catch (error) {
207
+ // Non-fatal: we'll generate a new certificate
208
+ logger.debug?.(`Could not retrieve cached certificate: ${getErrorMessage(error)}`);
209
+ }
210
+ }
211
+ // If no cached certificate, generate and broadcast a new one
212
+ if (!certificate) {
213
+ logger.log('🔐 Generating new TLS certificate...');
214
+ // Create a temporary client with signing capability for certificate operations
215
+ const tempClient = new AkashClient({
216
+ network,
217
+ signer: wallet.signer,
218
+ });
219
+ const certManager = new CertificateManager(tempClient);
220
+ let certResult = await certManager.getOrCreate(wallet.address);
221
+ // Auto-revoke stale on-chain certificate when deploying from a new machine
222
+ // (cert exists on blockchain but private key is not available locally)
223
+ if (!certResult.success && certResult.error.code === 'CERT_NOT_FOUND') {
224
+ logger.log('\u26A0 Certificate exists on-chain but not available locally \u2014 revoking and creating new...');
225
+ const revokeResult = await certManager.revoke(wallet.address);
226
+ if (!revokeResult.success) {
227
+ return failure(new DeploymentError(`Failed to revoke stale certificate: ${revokeResult.error.message}`, 'CERTIFICATE_CREATION_FAILED', { originalError: revokeResult.error }, false, 'Could not revoke existing on-chain certificate to create a new one'));
228
+ }
229
+ logger.log(`\u2713 Revoked ${revokeResult.data.revokedCount} stale certificate(s)`);
230
+ // Retry - blockchain is now clear for a fresh certificate
231
+ certResult = await certManager.getOrCreate(wallet.address);
232
+ }
233
+ if (!certResult.success) {
234
+ return failure(new DeploymentError(`Failed to create certificate: ${certResult.error.message}`, 'CERTIFICATE_CREATION_FAILED', { originalError: certResult.error }, false, 'Certificate generation or blockchain broadcast failed'));
235
+ }
236
+ certificate = certResult.data;
237
+ logger.log('✓ Certificate generated and broadcast to blockchain');
238
+ // Store the new certificate if the secrets provider supports it
239
+ if (autonomous.secrets.storeCertificate) {
240
+ try {
241
+ await autonomous.secrets.storeCertificate(certificate);
242
+ logger.debug?.('Certificate stored in secrets provider for future use');
243
+ }
244
+ catch (error) {
245
+ // Non-fatal: certificate is already on blockchain
246
+ logger.warn?.(`Could not store certificate: ${getErrorMessage(error)}`);
247
+ }
248
+ }
249
+ }
250
+ // Step 4: Create bid selector from strategy
251
+ const strategy = autonomous.bidStrategy ?? 'cheapest';
252
+ const filter = autonomous.bidFilter;
253
+ bidSelector = createBidSelectorFromStrategy(strategy, filter, logger);
254
+ logger.log(`✓ Bid selection strategy: ${strategy}`);
255
+ }
256
+ // ---------------------------------------------------------------------------
136
257
  // Runtime validation: wallet and certificate required for actual deployment
137
258
  // ---------------------------------------------------------------------------
138
259
  if (!wallet) {
139
- return failure(new DeploymentError('Wallet is required for deployment (not dry-run)', 'WALLET_REQUIRED', {}, false, 'Connect wallet using wallet-manager before deployment'));
260
+ return failure(new DeploymentError('Wallet is required for deployment (not dry-run)', 'WALLET_REQUIRED', {}, false, 'Connect wallet using wallet-manager before deployment, or use autonomous mode'));
140
261
  }
141
262
  if (!certificate) {
142
- return failure(new DeploymentError('TLS certificate is required to communicate with the provider', 'CERTIFICATE_REQUIRED', {}, false, 'Generate or load a certificate using certificate-manager before deployment'));
263
+ return failure(new DeploymentError('TLS certificate is required to communicate with the provider', 'CERTIFICATE_REQUIRED', {}, false, 'Generate or load a certificate using certificate-manager before deployment, or use autonomous mode'));
143
264
  }
144
265
  if (!bidSelector) {
145
266
  return failure(new DeploymentError('Bid selector function is required for deployment', 'BID_SELECTOR_REQUIRED', {}, false, 'Provide a bidSelector function to choose which provider bid to accept. ' +
146
- 'Use pre-built selectors like selectCheapestBid, selectMostReliableBid, or implement custom logic.'));
267
+ 'Use pre-built selectors like selectCheapestBid, selectMostReliableBid, or use autonomous mode.'));
147
268
  }
148
269
  // -----------------------------------------------------------------------
149
270
  // Initialize AkashClient with signing capability
@@ -390,6 +511,51 @@ function determineDeposit(options, profile) {
390
511
  }
391
512
  return 5; // Default deposit in AKT
392
513
  }
514
+ /**
515
+ * Creates a bid selector function from strategy and filter criteria
516
+ *
517
+ * Used by autonomous mode to convert configuration into a BidSelector function.
518
+ */
519
+ function createBidSelectorFromStrategy(strategy, filter, logger) {
520
+ return async (bids) => {
521
+ let filteredBids = bids;
522
+ // Apply filter criteria if provided
523
+ if (filter) {
524
+ // Convert per-block price to per-month for filterBids
525
+ // Blocks per month: ~431,572 (6.098s per block)
526
+ const BLOCKS_PER_MONTH = 431572;
527
+ const maxPricePerMonth = filter.maxPricePerBlock
528
+ ? { uakt: filter.maxPricePerBlock * BLOCKS_PER_MONTH }
529
+ : undefined;
530
+ filteredBids = filterBids(bids, {
531
+ maxPricePerMonth,
532
+ minUptime: filter.minUptime,
533
+ requireAudited: filter.requireAudited,
534
+ preferredRegions: filter.preferredRegions ? [...filter.preferredRegions] : undefined,
535
+ requireOnline: filter.requireOnline,
536
+ });
537
+ logger.debug?.(`Filtered bids: ${filteredBids.length}/${bids.length} passed criteria`);
538
+ if (filteredBids.length === 0) {
539
+ logger.warn?.('No bids passed filter criteria');
540
+ return null;
541
+ }
542
+ }
543
+ // Apply strategy to select best bid
544
+ switch (strategy) {
545
+ case 'cheapest':
546
+ return selectCheapestBid(filteredBids);
547
+ case 'most-reliable':
548
+ return selectMostReliableBid(filteredBids);
549
+ case 'balanced':
550
+ return selectBalancedBid(filteredBids);
551
+ default: {
552
+ // Fallback for any unknown strategy
553
+ logger.warn?.(`Unknown bid strategy, falling back to cheapest`);
554
+ return selectCheapestBid(filteredBids);
555
+ }
556
+ }
557
+ };
558
+ }
393
559
  /** Normalises deployment data into the published AkashDeploymentData structure */
394
560
  function createDeploymentData(params) {
395
561
  const { deployment, lease, leaseDetails, deploymentDetails, providerUri, profileName, network, certificate, providerStatus, selectedBid, } = params;