dank-ai 1.0.33 → 1.0.35

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/lib/agent.js CHANGED
@@ -64,7 +64,7 @@ class DankAgent {
64
64
  }
65
65
 
66
66
  /**
67
- * Set instance type (small, medium, large, xlarge)
67
+ * Set instance type (any string value - validated by backend)
68
68
  * @param {string} instanceType - Instance type string
69
69
  */
70
70
  setInstanceType(instanceType) {
@@ -72,49 +72,17 @@ class DankAgent {
72
72
  throw new Error('Instance type must be a non-empty string');
73
73
  }
74
74
 
75
- const normalizedType = instanceType.toLowerCase().trim();
76
-
77
- if (!INSTANCE_TYPES[normalizedType]) {
78
- const validTypes = Object.keys(INSTANCE_TYPES).join(', ');
79
- throw new Error(`Invalid instance type: "${instanceType}". Valid types are: ${validTypes}`);
80
- }
81
-
82
- this.config.instanceType = normalizedType;
75
+ // Store the instance type as-is (no validation - backend handles valid types)
76
+ this.config.instanceType = instanceType.trim();
83
77
  return this;
84
78
  }
85
79
 
86
80
  /**
87
- * @deprecated Use setInstanceType() instead. This method is kept for backward compatibility.
88
- * Set resource limits for the container
81
+ * @deprecated DISABLED - Use setInstanceType() instead.
82
+ * This method has been disabled. Please use setInstanceType('small'|'medium'|'large'|'xlarge') instead.
89
83
  */
90
84
  setResources(resources) {
91
- // Map old resources format to instance type
92
- if (resources && typeof resources === 'object') {
93
- const memory = resources.memory || '512m';
94
- const cpu = resources.cpu || 1;
95
-
96
- // Try to map to an instance type
97
- let instanceType = 'small'; // default
98
-
99
- if (memory === '512m' && cpu === 1) {
100
- instanceType = 'small';
101
- } else if (memory === '1g' && cpu === 2) {
102
- instanceType = 'medium';
103
- } else if (memory === '2g' && cpu === 2) {
104
- instanceType = 'large';
105
- } else if (memory === '4g' && cpu === 4) {
106
- instanceType = 'xlarge';
107
- } else {
108
- // For custom configurations, default to small and log a warning
109
- console.warn(`⚠️ setResources() is deprecated. Using 'small' instance type. Please use setInstanceType('small'|'medium'|'large'|'xlarge') instead.`);
110
- instanceType = 'small';
111
- }
112
-
113
- return this.setInstanceType(instanceType);
114
- }
115
-
116
- // If no resources provided, default to small
117
- return this.setInstanceType('small');
85
+ throw new Error('setResources() has been disabled. Please use setInstanceType() instead. Example: .setInstanceType("small")');
118
86
  }
119
87
 
120
88
  /**
@@ -159,19 +127,25 @@ class DankAgent {
159
127
  port: Joi.number().min(1000).max(65535).default(3000),
160
128
  authentication: Joi.boolean().default(false),
161
129
  maxConnections: Joi.number().min(1).max(1000).default(50),
162
- timeout: Joi.number().min(1000).default(30000)
130
+ timeout: Joi.number().min(1000).default(30000),
131
+ protocol: Joi.string().valid('http').optional() // Allow but ignore for backward compatibility
163
132
  });
164
133
 
165
- const { error, value } = schema.validate(options);
134
+ const { error, value } = schema.validate(options, {
135
+ stripUnknown: true // Strip unknown fields after validation
136
+ });
166
137
  if (error) {
167
138
  throw new Error(`Invalid prompting server configuration: ${error.message}`);
168
139
  }
140
+
141
+ // Remove protocol from value if present (we always use HTTP now)
142
+ const { protocol, ...cleanValue } = value;
169
143
 
170
144
  // Set the port in docker config
171
- this.config.docker = { ...this.config.docker, port: value.port };
145
+ this.config.docker = { ...this.config.docker, port: cleanValue.port };
172
146
 
173
147
  // Set the communication config (always HTTP, excluding port)
174
- const { port, ...communicationConfig } = value;
148
+ const { port, ...communicationConfig } = cleanValue;
175
149
  this.config.communication = {
176
150
  ...this.config.communication,
177
151
  directPrompting: {
@@ -649,7 +623,7 @@ class DankAgent {
649
623
 
650
624
  prompt: Joi.string().optional(),
651
625
 
652
- instanceType: Joi.string().valid('small', 'medium', 'large', 'xlarge').default('small'),
626
+ instanceType: Joi.string().default('small'), // Any string allowed - backend validates
653
627
 
654
628
  docker: Joi.object({
655
629
  baseImage: Joi.string().default(`${DOCKER_CONFIG.baseImagePrefix}:${DOCKER_CONFIG.defaultTag}`),
package/lib/cli/build.js CHANGED
@@ -20,8 +20,8 @@ async function buildCommand(options) {
20
20
 
21
21
  console.log(chalk.green('\\n✅ Pull completed successfully!'));
22
22
  }
23
-
24
23
 
24
+ process.exit(0);
25
25
  } catch (error) {
26
26
  console.error(chalk.red('❌ Pull failed:'), error.message);
27
27
  process.exit(1);
package/lib/cli/clean.js CHANGED
@@ -21,6 +21,7 @@ async function cleanCommand(options) {
21
21
 
22
22
  console.log(chalk.green('\\n✅ Cleanup completed successfully!'));
23
23
 
24
+ process.exit(0);
24
25
  } catch (error) {
25
26
  console.error(chalk.red('❌ Cleanup failed:'), error.message);
26
27
  process.exit(1);
package/lib/cli/init.js CHANGED
@@ -72,7 +72,7 @@ async function initCommand(projectName, options) {
72
72
  force: options.force
73
73
  });
74
74
 
75
- // Initialize project structure
75
+ // Initialize project structure (creates directory if needed)
76
76
  await project.init();
77
77
 
78
78
  // Create package.json
@@ -95,6 +95,7 @@ async function initCommand(projectName, options) {
95
95
  console.log(chalk.gray(' 4. Run "dank run" to start your agents'));
96
96
  console.log(chalk.gray('\nFor more information, visit: https://github.com/your-org/dank'));
97
97
 
98
+ process.exit(0);
98
99
  } catch (error) {
99
100
  console.error(chalk.red('❌ Initialization failed:'), error.message);
100
101
  process.exit(1);
@@ -131,6 +131,9 @@ async function productionBuildCommand(options) {
131
131
  throw new Error(`Configuration file not found: ${configPath}`);
132
132
  }
133
133
 
134
+ // Get project directory (directory containing the config file)
135
+ const projectDir = path.dirname(configPath);
136
+
134
137
  const config = require(configPath);
135
138
  if (!config.agents || !Array.isArray(config.agents)) {
136
139
  throw new Error('No agents found in configuration');
@@ -157,7 +160,8 @@ async function productionBuildCommand(options) {
157
160
  tagByAgent: Boolean(options.tagByAgent || agentImageConfig.tagByAgent),
158
161
  force: options.force || false,
159
162
  push: options.push || false,
160
- baseImageOverride: options.baseImageOverride || null
163
+ baseImageOverride: options.baseImageOverride || null,
164
+ projectDir: projectDir // Pass project directory so external files can be copied
161
165
  };
162
166
 
163
167
  const result = await dockerManager.buildProductionImage(agent, buildOptions);
package/lib/cli/run.js CHANGED
@@ -23,6 +23,9 @@ async function runCommand(options) {
23
23
  throw new Error(`Configuration file not found: ${configPath}`);
24
24
  }
25
25
 
26
+ // Get project directory (directory containing the config file)
27
+ const projectDir = path.dirname(configPath);
28
+
26
29
  console.log(chalk.blue('📋 Loading configuration...'));
27
30
 
28
31
  // Clear require cache to get fresh config
@@ -67,7 +70,8 @@ async function runCommand(options) {
67
70
  console.log(chalk.gray(` Starting ${agent.name}...`));
68
71
 
69
72
  const container = await dockerManager.startAgent(agent, {
70
- rebuild: !options.noBuild // Rebuild by default unless --no-build is specified
73
+ rebuild: !options.noBuild, // Rebuild by default unless --no-build is specified
74
+ projectDir: projectDir // Pass project directory so external files can be copied
71
75
  });
72
76
 
73
77
  console.log(chalk.green(` ✅ ${agent.name} started (${container.id.substring(0, 12)})`));
@@ -98,6 +102,7 @@ async function runCommand(options) {
98
102
  console.log(chalk.cyan('\\n🔧 Agents running in detached mode'));
99
103
  console.log(chalk.gray('Use "dank status" to check agent status'));
100
104
  console.log(chalk.gray('Use "dank logs <agent>" to view logs'));
105
+ process.exit(0);
101
106
  } else {
102
107
  console.log(chalk.cyan('\\n👀 Monitoring agents (Ctrl+C to stop)...'));
103
108
 
package/lib/cli/stop.js CHANGED
@@ -19,6 +19,7 @@ async function stopCommand(agents, options) {
19
19
  process.exit(1);
20
20
  }
21
21
 
22
+ process.exit(0);
22
23
  } catch (error) {
23
24
  console.error(chalk.red('❌ Stop failed:'), error.message);
24
25
  process.exit(1);
package/lib/config.js CHANGED
@@ -77,15 +77,17 @@ class AgentConfig {
77
77
 
78
78
  /**
79
79
  * Get resources (memory, cpu) from instance type
80
- * @param {string} instanceType - Instance type (small, medium, large, xlarge)
80
+ * @param {string} instanceType - Instance type (any string, defaults to 'small' if not found)
81
81
  * @returns {Object} Resources object with memory and cpu
82
82
  */
83
83
  static getResourcesFromInstanceType(instanceType) {
84
84
  const normalizedType = (instanceType || 'small').toLowerCase().trim();
85
85
  const instanceConfig = INSTANCE_TYPES[normalizedType];
86
86
 
87
+ // If instance type not found in mapping, default to 'small'
88
+ // Backend will handle the actual resource allocation
87
89
  if (!instanceConfig) {
88
- throw new Error(`Invalid instance type: "${instanceType}". Valid types are: ${Object.keys(INSTANCE_TYPES).join(', ')}`);
90
+ return INSTANCE_TYPES.small; // Default to small resources
89
91
  }
90
92
 
91
93
  return {
@@ -1170,7 +1170,9 @@ class DockerManager {
1170
1170
  agent.finalize();
1171
1171
 
1172
1172
  try {
1173
- const buildContext = await this.createAgentBuildContext(agent);
1173
+ const buildContext = await this.createAgentBuildContext(agent, {
1174
+ projectDir: options.projectDir
1175
+ });
1174
1176
  const dockerCmd = await this.resolveDockerCommand();
1175
1177
 
1176
1178
  const buildCommand = [
@@ -1221,6 +1223,7 @@ class DockerManager {
1221
1223
  force = false,
1222
1224
  push = false,
1223
1225
  baseImageOverride = null, // Production-only: override base image for all agents
1226
+ projectDir = null, // Project directory to copy files from
1224
1227
  } = options;
1225
1228
 
1226
1229
  // Normalize all components
@@ -1259,7 +1262,8 @@ class DockerManager {
1259
1262
  try {
1260
1263
  const buildContext = await this.createAgentBuildContext(agent, {
1261
1264
  isProductionBuild: true,
1262
- baseImageOverride: baseImageOverride
1265
+ baseImageOverride: baseImageOverride,
1266
+ projectDir: projectDir
1263
1267
  });
1264
1268
  const dockerCmd = await this.resolveDockerCommand();
1265
1269
 
@@ -1417,7 +1421,9 @@ class DockerManager {
1417
1421
  // Check if agent image exists, build if necessary
1418
1422
  const hasImage = await this.hasImage(imageName);
1419
1423
  if (!hasImage || options.rebuild) {
1420
- await this.buildAgentImage(agent, options);
1424
+ await this.buildAgentImage(agent, {
1425
+ projectDir: options.projectDir
1426
+ });
1421
1427
  }
1422
1428
 
1423
1429
  // Prepare container configuration
@@ -1617,6 +1623,66 @@ class DockerManager {
1617
1623
  return tarPath;
1618
1624
  }
1619
1625
 
1626
+ /**
1627
+ * Copy project files to build context (excluding common ignore patterns)
1628
+ */
1629
+ async copyProjectFiles(projectDir, contextDir) {
1630
+ const agentCodeDir = path.join(contextDir, "agent-code");
1631
+ await fs.ensureDir(agentCodeDir);
1632
+
1633
+ // Patterns to exclude when copying project files
1634
+ const ignorePatterns = [
1635
+ 'node_modules',
1636
+ '.git',
1637
+ '.build-context-*',
1638
+ '.env',
1639
+ '.env.*',
1640
+ '*.log',
1641
+ '.DS_Store',
1642
+ 'dist',
1643
+ 'build',
1644
+ '.dank',
1645
+ 'coverage',
1646
+ '.nyc_output'
1647
+ ];
1648
+
1649
+ try {
1650
+ // Copy all files from project directory, filtering out ignored patterns
1651
+ const items = await fs.readdir(projectDir);
1652
+
1653
+ for (const item of items) {
1654
+ const sourcePath = path.join(projectDir, item);
1655
+ const destPath = path.join(agentCodeDir, item);
1656
+ const stat = await fs.stat(sourcePath);
1657
+
1658
+ // Skip if matches ignore pattern
1659
+ const shouldIgnore = ignorePatterns.some(pattern => {
1660
+ if (pattern.includes('*')) {
1661
+ const regex = new RegExp('^' + pattern.replace(/\*/g, '.*') + '$');
1662
+ return regex.test(item);
1663
+ }
1664
+ return item === pattern;
1665
+ });
1666
+
1667
+ if (shouldIgnore) {
1668
+ continue;
1669
+ }
1670
+
1671
+ // Copy file or directory
1672
+ if (stat.isDirectory()) {
1673
+ await fs.copy(sourcePath, destPath);
1674
+ } else if (stat.isFile()) {
1675
+ await fs.copy(sourcePath, destPath);
1676
+ }
1677
+ }
1678
+
1679
+ this.logger.info(`📁 Copied project files from ${projectDir} to build context`);
1680
+ } catch (error) {
1681
+ this.logger.warn(`⚠️ Failed to copy project files: ${error.message}`);
1682
+ // Don't fail the build if copying project files fails
1683
+ }
1684
+ }
1685
+
1620
1686
  /**
1621
1687
  * Create build context for agent
1622
1688
  */
@@ -1626,6 +1692,12 @@ class DockerManager {
1626
1692
  `../../.build-context-${agent.name}`
1627
1693
  );
1628
1694
  await fs.ensureDir(contextDir);
1695
+
1696
+ // Copy project files if project directory is provided
1697
+ // This allows handlers to reference functions from other files
1698
+ if (options.projectDir) {
1699
+ await this.copyProjectFiles(options.projectDir, contextDir);
1700
+ }
1629
1701
 
1630
1702
  // Get the base image for this agent
1631
1703
  // Production builds can override the base image via baseImageOverride option
@@ -1680,10 +1752,20 @@ USER dankuser
1680
1752
  const handlersCode = this.generateHandlersCode(agent);
1681
1753
  const routesCode = this.generateRoutesCode(agent);
1682
1754
 
1755
+ // Check if project files were copied (indicated by presence of files other than index.js)
1756
+ const hasProjectFiles = options.projectDir ? true : false;
1757
+ const projectFilesNote = hasProjectFiles
1758
+ ? `// Note: Project files from your project directory have been copied here.
1759
+ // You can require them in your handlers using relative paths.
1760
+ // Example: const { myFunction } = require('./utils');`
1761
+ : '';
1762
+
1683
1763
  const agentCode = `
1684
1764
  // Agent: ${agent.name}
1685
1765
  // Generated by Dank Agent Service
1686
1766
 
1767
+ ${projectFilesNote}
1768
+
1687
1769
  module.exports = {
1688
1770
  async main(context) {
1689
1771
  const { llmClient, handlers, tools, config } = context;
@@ -1693,7 +1775,7 @@ module.exports = {
1693
1775
  // Basic agent loop
1694
1776
  setInterval(async () => {
1695
1777
  try {
1696
- // Trigger heartbeat
1778
+ // Trigger heartbeat handlers (no logging)
1697
1779
  const heartbeatHandlers = handlers.get('heartbeat') || [];
1698
1780
  heartbeatHandlers.forEach(handler => {
1699
1781
  try {
@@ -1703,9 +1785,6 @@ module.exports = {
1703
1785
  }
1704
1786
  });
1705
1787
 
1706
- // Custom agent logic would go here
1707
- console.log('Agent ${agent.name} heartbeat - uptime:', Math.floor(process.uptime()), 'seconds');
1708
-
1709
1788
  } catch (error) {
1710
1789
  console.error('Agent loop error:', error);
1711
1790
  const errorHandlers = handlers.get('error') || [];
package/lib/project.js CHANGED
@@ -24,8 +24,8 @@ class DankProject {
24
24
  async init() {
25
25
  const projectDir = this.projectPath;
26
26
 
27
- // Create directory structure (if needed)
28
- // await fs.ensureDir(path.join(projectDir, this.options.outputDir));
27
+ // Create project directory if it doesn't exist
28
+ await fs.ensureDir(projectDir);
29
29
 
30
30
  // Create example config file
31
31
  const exampleConfig = this._generateExampleConfig();
@@ -82,7 +82,6 @@ module.exports = {
82
82
  .setPrompt('You are a helpful AI assistant. Be concise and friendly in your responses.')
83
83
  .setBaseImage('nodejs-20')
84
84
  .setPromptingServer({
85
- protocol: 'http',
86
85
  port: 3000
87
86
  })
88
87
  .setInstanceType('small')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dank-ai",
3
- "version": "1.0.33",
3
+ "version": "1.0.35",
4
4
  "description": "Dank Agent Service - Docker-based AI agent orchestration platform",
5
5
  "main": "lib/index.js",
6
6
  "exports": {