dank-ai 1.0.5 → 1.0.7

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/bin/dank CHANGED
@@ -75,6 +75,21 @@ program
75
75
  await buildCommand(options);
76
76
  });
77
77
 
78
+ // Production build command - build and optionally push production images
79
+ program
80
+ .command('build:prod')
81
+ .description('Build production Docker images with custom naming and tagging')
82
+ .option('-c, --config <file>', 'Configuration file path', 'dank.config.js')
83
+ .option('--push', 'Push images to registry after building')
84
+ .option('--tag <tag>', 'Custom tag for images (default: latest)')
85
+ .option('--registry <registry>', 'Docker registry URL (e.g., docker.io, ghcr.io)')
86
+ .option('--namespace <namespace>', 'Docker namespace/organization')
87
+ .option('--force', 'Force rebuild without cache')
88
+ .action(async (options) => {
89
+ const { productionBuildCommand } = require('../lib/cli/production-build');
90
+ await productionBuildCommand(options);
91
+ });
92
+
78
93
  // Clean command - cleanup Docker resources
79
94
  program
80
95
  .command('clean')
package/lib/agent.js CHANGED
@@ -500,6 +500,27 @@ class DankAgent {
500
500
  return this;
501
501
  }
502
502
 
503
+ /**
504
+ * Set agent image configuration for Docker builds
505
+ */
506
+ setAgentImageConfig(options = {}) {
507
+ const schema = Joi.object({
508
+ registry: Joi.string().optional(),
509
+ namespace: Joi.string().optional(),
510
+ tag: Joi.string().default('latest')
511
+ });
512
+
513
+ const { error, value } = schema.validate(options);
514
+ if (error) {
515
+ throw new Error(`Invalid agent image configuration: ${error.message}`);
516
+ }
517
+
518
+ this.config.agentImage = value;
519
+ return this;
520
+ }
521
+
522
+
523
+
503
524
  /**
504
525
  * Get the complete agent configuration for serialization
505
526
  */
@@ -589,6 +610,12 @@ class DankAgent {
589
610
 
590
611
  environment: Joi.object().pattern(Joi.string(), Joi.string()).default({}),
591
612
 
613
+ agentImage: Joi.object({
614
+ registry: Joi.string().optional(),
615
+ namespace: Joi.string().optional(),
616
+ tag: Joi.string().default('latest')
617
+ }).optional(),
618
+
592
619
  custom: Joi.object().default({}),
593
620
 
594
621
  tools: Joi.object({
@@ -0,0 +1,110 @@
1
+ /**
2
+ * CLI Production Build Command - Build and optionally push production Docker images
3
+ */
4
+
5
+ const fs = require('fs-extra');
6
+ const path = require('path');
7
+ const chalk = require('chalk');
8
+ const { DockerManager } = require('../docker/manager');
9
+
10
+ async function productionBuildCommand(options) {
11
+ try {
12
+ console.log(chalk.yellow('šŸ—ļø Building production Docker images...\n'));
13
+
14
+ // Load configuration
15
+ const configPath = path.resolve(options.config);
16
+ if (!await fs.pathExists(configPath)) {
17
+ throw new Error(`Configuration file not found: ${configPath}`);
18
+ }
19
+
20
+ const config = require(configPath);
21
+ if (!config.agents || !Array.isArray(config.agents)) {
22
+ throw new Error('No agents found in configuration');
23
+ }
24
+
25
+ // Initialize Docker manager
26
+ const dockerManager = new DockerManager();
27
+ await dockerManager.initialize();
28
+
29
+ // Build production images for each agent
30
+ const buildResults = [];
31
+ for (const agent of config.agents) {
32
+ try {
33
+ console.log(chalk.blue(`šŸ“¦ Building production image for agent: ${agent.name}`));
34
+
35
+ // Use agent's image config if available, otherwise use CLI options
36
+ const agentImageConfig = agent.config?.agentImage || {};
37
+ const buildOptions = {
38
+ tag: options.tag || agentImageConfig.tag || 'latest',
39
+ registry: options.registry || agentImageConfig.registry,
40
+ namespace: options.namespace || agentImageConfig.namespace,
41
+ force: options.force || false,
42
+ push: options.push || false
43
+ };
44
+
45
+ const result = await dockerManager.buildProductionImage(agent, buildOptions);
46
+
47
+ buildResults.push({
48
+ agent: agent.name,
49
+ imageName: result.imageName,
50
+ success: true,
51
+ pushed: result.pushed || false
52
+ });
53
+
54
+ console.log(chalk.green(`āœ… Successfully built: ${result.imageName}`));
55
+ if (result.pushed) {
56
+ console.log(chalk.green(`šŸš€ Successfully pushed: ${result.imageName}`));
57
+ }
58
+
59
+ } catch (error) {
60
+ console.error(chalk.red(`āŒ Failed to build agent ${agent.name}:`), error.message);
61
+ buildResults.push({
62
+ agent: agent.name,
63
+ success: false,
64
+ error: error.message
65
+ });
66
+ }
67
+ }
68
+
69
+ // Print summary
70
+ console.log(chalk.yellow('\nšŸ“Š Build Summary:'));
71
+ console.log(chalk.gray('================'));
72
+
73
+ const successful = buildResults.filter(r => r.success);
74
+ const failed = buildResults.filter(r => !r.success);
75
+ const pushed = buildResults.filter(r => r.pushed);
76
+
77
+ console.log(chalk.green(`āœ… Successful builds: ${successful.length}`));
78
+ if (pushed.length > 0) {
79
+ console.log(chalk.blue(`šŸš€ Pushed to registry: ${pushed.length}`));
80
+ }
81
+ if (failed.length > 0) {
82
+ console.log(chalk.red(`āŒ Failed builds: ${failed.length}`));
83
+ }
84
+
85
+ // List built images
86
+ if (successful.length > 0) {
87
+ console.log(chalk.cyan('\nšŸ“¦ Built Images:'));
88
+ successful.forEach(result => {
89
+ console.log(chalk.gray(` - ${result.imageName}`));
90
+ });
91
+ }
92
+
93
+ // List failed builds
94
+ if (failed.length > 0) {
95
+ console.log(chalk.red('\nāŒ Failed Builds:'));
96
+ failed.forEach(result => {
97
+ console.log(chalk.gray(` - ${result.agent}: ${result.error}`));
98
+ });
99
+ process.exit(1);
100
+ }
101
+
102
+ console.log(chalk.green('\nšŸŽ‰ Production build completed successfully!'));
103
+
104
+ } catch (error) {
105
+ console.error(chalk.red('āŒ Production build failed:'), error.message);
106
+ process.exit(1);
107
+ }
108
+ }
109
+
110
+ module.exports = { productionBuildCommand };
@@ -413,6 +413,78 @@ class DockerManager {
413
413
  }
414
414
  }
415
415
 
416
+ /**
417
+ * Build production image with custom naming and tagging
418
+ */
419
+ async buildProductionImage(agent, options = {}) {
420
+ const {
421
+ tag = 'latest',
422
+ registry,
423
+ namespace,
424
+ force = false,
425
+ push = false
426
+ } = options;
427
+
428
+ // Construct production image name
429
+ let imageName = agent.name.toLowerCase();
430
+
431
+ // Add namespace if provided
432
+ if (namespace) {
433
+ imageName = `${namespace}/${imageName}`;
434
+ }
435
+
436
+ // Add registry if provided
437
+ if (registry) {
438
+ imageName = `${registry}/${imageName}`;
439
+ }
440
+
441
+ // Add tag
442
+ imageName = `${imageName}:${tag}`;
443
+
444
+ this.logger.info(`Building production image for agent: ${agent.name} -> ${imageName}`);
445
+
446
+ try {
447
+ const buildContext = await this.createAgentBuildContext(agent);
448
+
449
+ const stream = await this.docker.buildImage(buildContext, {
450
+ t: imageName,
451
+ dockerfile: 'Dockerfile',
452
+ nocache: force
453
+ });
454
+
455
+ await this.followBuildProgress(stream, `Production build for ${agent.name}`);
456
+
457
+ this.logger.info(`Production image '${imageName}' built successfully`);
458
+
459
+ // Clean up build context
460
+ await fs.remove(buildContext);
461
+
462
+ let pushed = false;
463
+
464
+ // Push to registry if requested
465
+ if (push) {
466
+ try {
467
+ this.logger.info(`Pushing image to registry: ${imageName}`);
468
+ const pushStream = await this.docker.getImage(imageName).push();
469
+ await this.followBuildProgress(pushStream, `Push ${imageName}`);
470
+ this.logger.info(`Successfully pushed image: ${imageName}`);
471
+ pushed = true;
472
+ } catch (pushError) {
473
+ this.logger.warn(`Failed to push image ${imageName}: ${pushError.message}`);
474
+ // Don't fail the build if push fails
475
+ }
476
+ }
477
+
478
+ return {
479
+ imageName,
480
+ pushed
481
+ };
482
+
483
+ } catch (error) {
484
+ throw new Error(`Failed to build production image: ${error.message}`);
485
+ }
486
+ }
487
+
416
488
  /**
417
489
  * Generate handlers code from agent configuration
418
490
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dank-ai",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "Dank Agent Service - Docker-based AI agent orchestration platform",
5
5
  "main": "lib/index.js",
6
6
  "exports": {