dank-ai 1.0.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/README.md +1331 -0
- package/bin/dank +118 -0
- package/docker/Dockerfile +57 -0
- package/docker/entrypoint.js +1227 -0
- package/docker/package.json +19 -0
- package/lib/agent.js +644 -0
- package/lib/cli/build.js +43 -0
- package/lib/cli/clean.js +30 -0
- package/lib/cli/init.js +38 -0
- package/lib/cli/logs.js +122 -0
- package/lib/cli/run.js +176 -0
- package/lib/cli/status.js +125 -0
- package/lib/cli/stop.js +87 -0
- package/lib/config.js +180 -0
- package/lib/constants.js +58 -0
- package/lib/docker/manager.js +968 -0
- package/lib/index.js +26 -0
- package/lib/project.js +280 -0
- package/lib/tools/builtin.js +445 -0
- package/lib/tools/index.js +335 -0
- package/package.json +52 -0
package/lib/cli/clean.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Clean Command - Clean up Docker resources
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const chalk = require('chalk');
|
|
6
|
+
const { DockerManager } = require('../docker/manager');
|
|
7
|
+
|
|
8
|
+
async function cleanCommand(options) {
|
|
9
|
+
console.log(chalk.yellow('๐งน Cleaning up Docker resources...\\n'));
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
const dockerManager = new DockerManager();
|
|
13
|
+
await dockerManager.initialize();
|
|
14
|
+
|
|
15
|
+
await dockerManager.cleanup({
|
|
16
|
+
all: options.all,
|
|
17
|
+
containers: options.containers || options.all,
|
|
18
|
+
images: options.images || options.all,
|
|
19
|
+
buildContexts: options.buildContexts || options.all
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
console.log(chalk.green('\\nโ
Cleanup completed successfully!'));
|
|
23
|
+
|
|
24
|
+
} catch (error) {
|
|
25
|
+
console.error(chalk.red('โ Cleanup failed:'), error.message);
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
module.exports = { cleanCommand };
|
package/lib/cli/init.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Init Command - Initialize new Dank project
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const fs = require('fs-extra');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const chalk = require('chalk');
|
|
8
|
+
const { DankProject } = require('../project');
|
|
9
|
+
|
|
10
|
+
async function initCommand(projectName, options) {
|
|
11
|
+
const name = projectName || path.basename(process.cwd());
|
|
12
|
+
|
|
13
|
+
console.log(chalk.yellow(`๐ Initializing Dank project: ${name}\\n`));
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
// Create project instance
|
|
17
|
+
const project = new DankProject(name, {
|
|
18
|
+
template: options.template,
|
|
19
|
+
force: options.force
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// Initialize project structure
|
|
23
|
+
await project.init();
|
|
24
|
+
|
|
25
|
+
console.log(chalk.green('\\nโ
Project initialized successfully!'));
|
|
26
|
+
console.log(chalk.cyan('\\nNext steps:'));
|
|
27
|
+
console.log(chalk.gray(' 1. Set your API keys in environment variables'));
|
|
28
|
+
console.log(chalk.gray(' 2. Edit dank.config.js to configure your agents'));
|
|
29
|
+
console.log(chalk.gray(' 3. Run "dank run" to start your agents'));
|
|
30
|
+
console.log(chalk.gray('\\nFor more information, visit: https://github.com/your-org/dank'));
|
|
31
|
+
|
|
32
|
+
} catch (error) {
|
|
33
|
+
console.error(chalk.red('โ Initialization failed:'), error.message);
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
module.exports = { initCommand };
|
package/lib/cli/logs.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Logs Command - View agent logs
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const chalk = require('chalk');
|
|
6
|
+
const { DockerManager } = require('../docker/manager');
|
|
7
|
+
|
|
8
|
+
async function logsCommand(agentName, options) {
|
|
9
|
+
try {
|
|
10
|
+
const dockerManager = new DockerManager();
|
|
11
|
+
await dockerManager.initialize();
|
|
12
|
+
|
|
13
|
+
if (agentName) {
|
|
14
|
+
await showAgentLogs(dockerManager, agentName, options);
|
|
15
|
+
} else {
|
|
16
|
+
await showAllLogs(dockerManager, options);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
} catch (error) {
|
|
20
|
+
console.error(chalk.red('โ Logs failed:'), error.message);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function showAgentLogs(dockerManager, agentName, options) {
|
|
26
|
+
console.log(chalk.yellow(`๐ Logs for agent: ${agentName}\\n`));
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const logStream = await dockerManager.getAgentLogs(agentName, {
|
|
30
|
+
follow: options.follow,
|
|
31
|
+
tail: parseInt(options.tail) || 100,
|
|
32
|
+
since: options.since
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
logStream.on('data', (chunk) => {
|
|
36
|
+
// Docker log format includes 8-byte header, remove it
|
|
37
|
+
const logLine = chunk.toString('utf8').substring(8);
|
|
38
|
+
|
|
39
|
+
// Color code log levels
|
|
40
|
+
const coloredLine = logLine
|
|
41
|
+
.replace(/\\[ERROR\\]/g, chalk.red('[ERROR]'))
|
|
42
|
+
.replace(/\\[WARN\\]/g, chalk.yellow('[WARN]'))
|
|
43
|
+
.replace(/\\[INFO\\]/g, chalk.blue('[INFO]'))
|
|
44
|
+
.replace(/\\[DEBUG\\]/g, chalk.gray('[DEBUG]'));
|
|
45
|
+
|
|
46
|
+
process.stdout.write(coloredLine);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
logStream.on('end', () => {
|
|
50
|
+
if (!options.follow) {
|
|
51
|
+
console.log(chalk.gray('\\n--- End of logs ---'));
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
if (options.follow) {
|
|
56
|
+
console.log(chalk.gray('Following logs (Ctrl+C to stop)...'));
|
|
57
|
+
|
|
58
|
+
process.on('SIGINT', () => {
|
|
59
|
+
console.log(chalk.yellow('\\n๐ Stopped following logs'));
|
|
60
|
+
process.exit(0);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
} catch (error) {
|
|
65
|
+
throw new Error(`Failed to get logs for ${agentName}: ${error.message}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function showAllLogs(dockerManager, options) {
|
|
70
|
+
console.log(chalk.yellow('๐ Logs from all agents\\n'));
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
const containers = await dockerManager.docker.listContainers({
|
|
74
|
+
all: true,
|
|
75
|
+
filters: { name: ['dank-'] }
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
if (containers.length === 0) {
|
|
79
|
+
console.log(chalk.gray('No agents found.'));
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
for (const containerInfo of containers) {
|
|
84
|
+
const agentName = containerInfo.Names[0].replace('/dank-', '').split('-')[0];
|
|
85
|
+
|
|
86
|
+
console.log(chalk.cyan(`\\n=== ${agentName} ===`));
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
const logStream = await dockerManager.getAgentLogs(agentName, {
|
|
90
|
+
follow: false,
|
|
91
|
+
tail: parseInt(options.tail) || 50
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
logStream.on('data', (chunk) => {
|
|
95
|
+
const logLine = chunk.toString('utf8').substring(8);
|
|
96
|
+
const coloredLine = logLine
|
|
97
|
+
.replace(/\\[ERROR\\]/g, chalk.red('[ERROR]'))
|
|
98
|
+
.replace(/\\[WARN\\]/g, chalk.yellow('[WARN]'))
|
|
99
|
+
.replace(/\\[INFO\\]/g, chalk.blue('[INFO]'))
|
|
100
|
+
.replace(/\\[DEBUG\\]/g, chalk.gray('[DEBUG]'));
|
|
101
|
+
|
|
102
|
+
process.stdout.write(`[${agentName}] ${coloredLine}`);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// Wait for logs to finish
|
|
106
|
+
await new Promise((resolve) => {
|
|
107
|
+
logStream.on('end', resolve);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
} catch (error) {
|
|
111
|
+
console.log(chalk.red(`Failed to get logs for ${agentName}: ${error.message}`));
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
console.log(chalk.gray('\\n--- End of all logs ---'));
|
|
116
|
+
|
|
117
|
+
} catch (error) {
|
|
118
|
+
throw new Error(`Failed to get all logs: ${error.message}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
module.exports = { logsCommand };
|
package/lib/cli/run.js
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Run Command - Start all defined agents
|
|
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
|
+
const { DankProject } = require('../project');
|
|
10
|
+
|
|
11
|
+
async function runCommand(options) {
|
|
12
|
+
console.log(chalk.yellow('๐ Starting Dank agents...\\n'));
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
// Load configuration
|
|
16
|
+
const configPath = path.resolve(options.config);
|
|
17
|
+
if (!(await fs.pathExists(configPath))) {
|
|
18
|
+
throw new Error(`Configuration file not found: ${configPath}`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
console.log(chalk.blue('๐ Loading configuration...'));
|
|
22
|
+
|
|
23
|
+
// Clear require cache to get fresh config
|
|
24
|
+
delete require.cache[require.resolve(configPath)];
|
|
25
|
+
const config = require(configPath);
|
|
26
|
+
|
|
27
|
+
if (!config.agents || !Array.isArray(config.agents)) {
|
|
28
|
+
throw new Error('No agents defined in configuration');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
console.log(chalk.green(`โ
Found ${config.agents.length} agents`));
|
|
32
|
+
|
|
33
|
+
// Initialize Docker manager
|
|
34
|
+
console.log(chalk.blue('๐ณ Initializing Docker...'));
|
|
35
|
+
const dockerManager = new DockerManager();
|
|
36
|
+
await dockerManager.initialize();
|
|
37
|
+
|
|
38
|
+
// Clean up existing containers from previous runs
|
|
39
|
+
console.log(chalk.blue('๐งน Cleaning up existing containers...'));
|
|
40
|
+
await dockerManager.cleanupExistingContainers(config.agents);
|
|
41
|
+
|
|
42
|
+
// Pull base image if needed
|
|
43
|
+
if (options.pull) {
|
|
44
|
+
console.log(chalk.blue('๐ฅ Pulling base image...'));
|
|
45
|
+
await dockerManager.pullBaseImage();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Start agents
|
|
49
|
+
console.log(chalk.blue('\\n๐ฏ Starting agents...'));
|
|
50
|
+
|
|
51
|
+
const parallel = parseInt(options.parallel) || 3;
|
|
52
|
+
const agentBatches = chunkArray(config.agents, parallel);
|
|
53
|
+
|
|
54
|
+
const results = [];
|
|
55
|
+
|
|
56
|
+
for (const batch of agentBatches) {
|
|
57
|
+
const batchPromises = batch.map(async (agent) => {
|
|
58
|
+
try {
|
|
59
|
+
console.log(chalk.gray(` Starting ${agent.name}...`));
|
|
60
|
+
|
|
61
|
+
const container = await dockerManager.startAgent(agent, {
|
|
62
|
+
rebuild: !options.noBuild // Rebuild by default unless --no-build is specified
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
console.log(chalk.green(` โ
${agent.name} started (${container.id.substring(0, 12)})`));
|
|
66
|
+
|
|
67
|
+
return { agent: agent.name, status: 'started', containerId: container.id };
|
|
68
|
+
|
|
69
|
+
} catch (error) {
|
|
70
|
+
console.log(chalk.red(` โ ${agent.name} failed: ${error.message}`));
|
|
71
|
+
return { agent: agent.name, status: 'failed', error: error.message };
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const batchResults = await Promise.allSettled(batchPromises);
|
|
76
|
+
results.push(...batchResults.map(r => r.value || r.reason));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Summary
|
|
80
|
+
console.log(chalk.yellow('\\n๐ Summary:'));
|
|
81
|
+
const started = results.filter(r => r.status === 'started').length;
|
|
82
|
+
const failed = results.filter(r => r.status === 'failed').length;
|
|
83
|
+
|
|
84
|
+
console.log(chalk.green(` โ
Started: ${started}`));
|
|
85
|
+
if (failed > 0) {
|
|
86
|
+
console.log(chalk.red(` โ Failed: ${failed}`));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (options.detached) {
|
|
90
|
+
console.log(chalk.cyan('\\n๐ง Agents running in detached mode'));
|
|
91
|
+
console.log(chalk.gray('Use "dank status" to check agent status'));
|
|
92
|
+
console.log(chalk.gray('Use "dank logs <agent>" to view logs'));
|
|
93
|
+
} else {
|
|
94
|
+
console.log(chalk.cyan('\\n๐ Monitoring agents (Ctrl+C to stop)...'));
|
|
95
|
+
|
|
96
|
+
// Monitor agents
|
|
97
|
+
await monitorAgents(dockerManager, config.agents);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
} catch (error) {
|
|
101
|
+
console.error(chalk.red('โ Run failed:'), error.message);
|
|
102
|
+
process.exit(1);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Monitor running agents
|
|
108
|
+
*/
|
|
109
|
+
async function monitorAgents(dockerManager, agents) {
|
|
110
|
+
const monitorInterval = setInterval(async () => {
|
|
111
|
+
try {
|
|
112
|
+
console.log(chalk.gray('\\n--- Agent Status ---'));
|
|
113
|
+
|
|
114
|
+
for (const agent of agents) {
|
|
115
|
+
const status = await dockerManager.getAgentStatus(agent.name);
|
|
116
|
+
|
|
117
|
+
const statusColor = status.status === 'running' ? chalk.green :
|
|
118
|
+
status.status === 'stopped' ? chalk.yellow : chalk.red;
|
|
119
|
+
|
|
120
|
+
const uptime = status.uptime ? formatUptime(status.uptime) : 'N/A';
|
|
121
|
+
|
|
122
|
+
console.log(`${statusColor('โ')} ${agent.name}: ${status.status} (${uptime})`);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
} catch (error) {
|
|
126
|
+
console.error(chalk.red('Monitor error:'), error.message);
|
|
127
|
+
}
|
|
128
|
+
}, 10000); // Check every 10 seconds
|
|
129
|
+
|
|
130
|
+
// Handle Ctrl+C
|
|
131
|
+
process.on('SIGINT', async () => {
|
|
132
|
+
console.log(chalk.yellow('\\n๐ Stopping agents...'));
|
|
133
|
+
clearInterval(monitorInterval);
|
|
134
|
+
|
|
135
|
+
try {
|
|
136
|
+
for (const agent of agents) {
|
|
137
|
+
await dockerManager.stopAgent(agent.name);
|
|
138
|
+
}
|
|
139
|
+
console.log(chalk.green('โ
All agents stopped'));
|
|
140
|
+
} catch (error) {
|
|
141
|
+
console.error(chalk.red('โ Error stopping agents:'), error.message);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
process.exit(0);
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Chunk array into smaller arrays
|
|
150
|
+
*/
|
|
151
|
+
function chunkArray(array, chunkSize) {
|
|
152
|
+
const chunks = [];
|
|
153
|
+
for (let i = 0; i < array.length; i += chunkSize) {
|
|
154
|
+
chunks.push(array.slice(i, i + chunkSize));
|
|
155
|
+
}
|
|
156
|
+
return chunks;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Format uptime in human readable format
|
|
161
|
+
*/
|
|
162
|
+
function formatUptime(ms) {
|
|
163
|
+
const seconds = Math.floor(ms / 1000);
|
|
164
|
+
const minutes = Math.floor(seconds / 60);
|
|
165
|
+
const hours = Math.floor(minutes / 60);
|
|
166
|
+
|
|
167
|
+
if (hours > 0) {
|
|
168
|
+
return `${hours}h ${minutes % 60}m`;
|
|
169
|
+
} else if (minutes > 0) {
|
|
170
|
+
return `${minutes}m ${seconds % 60}s`;
|
|
171
|
+
} else {
|
|
172
|
+
return `${seconds}s`;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
module.exports = { runCommand };
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Status Command - Show agent status
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const chalk = require('chalk');
|
|
6
|
+
const { DockerManager } = require('../docker/manager');
|
|
7
|
+
|
|
8
|
+
async function statusCommand(options) {
|
|
9
|
+
try {
|
|
10
|
+
const dockerManager = new DockerManager();
|
|
11
|
+
await dockerManager.initialize();
|
|
12
|
+
|
|
13
|
+
if (options.watch) {
|
|
14
|
+
await watchStatus(dockerManager, options);
|
|
15
|
+
} else {
|
|
16
|
+
await showStatus(dockerManager, options);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
} catch (error) {
|
|
20
|
+
console.error(chalk.red('โ Status check failed:'), error.message);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function showStatus(dockerManager, options) {
|
|
26
|
+
console.log(chalk.yellow('๐ Agent Status\\n'));
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
// Get all Dank containers
|
|
30
|
+
const containers = await dockerManager.docker.listContainers({
|
|
31
|
+
all: true,
|
|
32
|
+
filters: { name: ['dank-'] }
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
if (containers.length === 0) {
|
|
36
|
+
console.log(chalk.gray('No agents found. Run "dank run" to start agents.'));
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const statuses = [];
|
|
41
|
+
|
|
42
|
+
for (const containerInfo of containers) {
|
|
43
|
+
const container = dockerManager.docker.getContainer(containerInfo.Id);
|
|
44
|
+
const data = await container.inspect();
|
|
45
|
+
|
|
46
|
+
const agentName = containerInfo.Names[0].replace('/dank-', '').split('-')[0];
|
|
47
|
+
const status = {
|
|
48
|
+
name: agentName,
|
|
49
|
+
id: containerInfo.Id.substring(0, 12),
|
|
50
|
+
status: data.State.Running ? 'running' : 'stopped',
|
|
51
|
+
uptime: data.State.Running ? Date.now() - new Date(data.State.StartedAt).getTime() : 0,
|
|
52
|
+
restarts: data.RestartCount,
|
|
53
|
+
health: data.State.Health?.Status || 'unknown',
|
|
54
|
+
memory: data.HostConfig.Memory,
|
|
55
|
+
cpu: data.HostConfig.CpuQuota / 1000
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
statuses.push(status);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (options.json) {
|
|
62
|
+
console.log(JSON.stringify(statuses, null, 2));
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Display status table
|
|
67
|
+
console.log(chalk.bold('NAME\\t\\tSTATUS\\t\\tUPTIME\\t\\tRESTARTS\\tHEALTH'));
|
|
68
|
+
console.log('โ'.repeat(70));
|
|
69
|
+
|
|
70
|
+
for (const status of statuses) {
|
|
71
|
+
const statusColor = status.status === 'running' ? chalk.green : chalk.red;
|
|
72
|
+
const healthColor = status.health === 'healthy' ? chalk.green :
|
|
73
|
+
status.health === 'unhealthy' ? chalk.red : chalk.yellow;
|
|
74
|
+
|
|
75
|
+
const uptime = status.uptime > 0 ? formatUptime(status.uptime) : 'N/A';
|
|
76
|
+
|
|
77
|
+
console.log(
|
|
78
|
+
`${status.name.padEnd(12)}\\t${statusColor(status.status.padEnd(8))}\\t${uptime.padEnd(8)}\\t${status.restarts}\\t\\t${healthColor(status.health)}`
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
console.log('\\n' + chalk.gray(`Total agents: ${statuses.length}`));
|
|
83
|
+
|
|
84
|
+
} catch (error) {
|
|
85
|
+
throw new Error(`Failed to get status: ${error.message}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async function watchStatus(dockerManager, options) {
|
|
90
|
+
console.log(chalk.yellow('๐ Watching agent status (Ctrl+C to stop)...\\n'));
|
|
91
|
+
|
|
92
|
+
const interval = setInterval(async () => {
|
|
93
|
+
// Clear screen
|
|
94
|
+
process.stdout.write('\\x1Bc');
|
|
95
|
+
|
|
96
|
+
console.log(chalk.yellow('๐ Agent Status (Live)\\n'));
|
|
97
|
+
console.log(chalk.gray(`Last updated: ${new Date().toLocaleTimeString()}\\n`));
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
await showStatus(dockerManager, { ...options, json: false });
|
|
101
|
+
} catch (error) {
|
|
102
|
+
console.error(chalk.red('Status update failed:'), error.message);
|
|
103
|
+
}
|
|
104
|
+
}, 2000);
|
|
105
|
+
|
|
106
|
+
process.on('SIGINT', () => {
|
|
107
|
+
clearInterval(interval);
|
|
108
|
+
console.log(chalk.yellow('\\n๐ Status monitoring stopped'));
|
|
109
|
+
process.exit(0);
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function formatUptime(ms) {
|
|
114
|
+
const seconds = Math.floor(ms / 1000);
|
|
115
|
+
const minutes = Math.floor(seconds / 60);
|
|
116
|
+
const hours = Math.floor(minutes / 60);
|
|
117
|
+
const days = Math.floor(hours / 24);
|
|
118
|
+
|
|
119
|
+
if (days > 0) return `${days}d ${hours % 24}h`;
|
|
120
|
+
if (hours > 0) return `${hours}h ${minutes % 60}m`;
|
|
121
|
+
if (minutes > 0) return `${minutes}m`;
|
|
122
|
+
return `${seconds}s`;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
module.exports = { statusCommand };
|
package/lib/cli/stop.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Stop Command - Stop running agents
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const chalk = require('chalk');
|
|
6
|
+
const { DockerManager } = require('../docker/manager');
|
|
7
|
+
|
|
8
|
+
async function stopCommand(agents, options) {
|
|
9
|
+
try {
|
|
10
|
+
const dockerManager = new DockerManager();
|
|
11
|
+
await dockerManager.initialize();
|
|
12
|
+
|
|
13
|
+
if (options.all) {
|
|
14
|
+
await stopAllAgents(dockerManager, options);
|
|
15
|
+
} else if (agents.length > 0) {
|
|
16
|
+
await stopSpecificAgents(dockerManager, agents, options);
|
|
17
|
+
} else {
|
|
18
|
+
console.log(chalk.yellow('No agents specified. Use --all to stop all agents or specify agent names.'));
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.error(chalk.red('โ Stop failed:'), error.message);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function stopAllAgents(dockerManager, options) {
|
|
29
|
+
console.log(chalk.yellow('๐ Stopping all agents...\\n'));
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
const containers = await dockerManager.docker.listContainers({
|
|
33
|
+
all: true,
|
|
34
|
+
filters: { name: ['dank-'] }
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
if (containers.length === 0) {
|
|
38
|
+
console.log(chalk.gray('No running agents found.'));
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
for (const containerInfo of containers) {
|
|
43
|
+
const agentName = containerInfo.Names[0].replace('/dank-', '').split('-')[0];
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
await dockerManager.stopAgent(agentName, options);
|
|
47
|
+
console.log(chalk.green(`โ
Stopped: ${agentName}`));
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.log(chalk.red(`โ Failed to stop ${agentName}: ${error.message}`));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
console.log(chalk.green('\\nโ
All agents stopped'));
|
|
54
|
+
|
|
55
|
+
} catch (error) {
|
|
56
|
+
throw new Error(`Failed to stop all agents: ${error.message}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function stopSpecificAgents(dockerManager, agentNames, options) {
|
|
61
|
+
console.log(chalk.yellow(`๐ Stopping agents: ${agentNames.join(', ')}\\n`));
|
|
62
|
+
|
|
63
|
+
const results = [];
|
|
64
|
+
|
|
65
|
+
for (const agentName of agentNames) {
|
|
66
|
+
try {
|
|
67
|
+
await dockerManager.stopAgent(agentName, options);
|
|
68
|
+
console.log(chalk.green(`โ
Stopped: ${agentName}`));
|
|
69
|
+
results.push({ agent: agentName, status: 'stopped' });
|
|
70
|
+
} catch (error) {
|
|
71
|
+
console.log(chalk.red(`โ Failed to stop ${agentName}: ${error.message}`));
|
|
72
|
+
results.push({ agent: agentName, status: 'failed', error: error.message });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Summary
|
|
77
|
+
const stopped = results.filter(r => r.status === 'stopped').length;
|
|
78
|
+
const failed = results.filter(r => r.status === 'failed').length;
|
|
79
|
+
|
|
80
|
+
console.log(chalk.yellow('\\n๐ Summary:'));
|
|
81
|
+
console.log(chalk.green(` โ
Stopped: ${stopped}`));
|
|
82
|
+
if (failed > 0) {
|
|
83
|
+
console.log(chalk.red(` โ Failed: ${failed}`));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
module.exports = { stopCommand };
|