agent-window 1.3.8 → 1.4.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/hooks/settings.json +67 -0
- package/install-bmad-automated.exp +91 -0
- package/install-bmad-interactive.sh +22 -0
- package/install-bmad.js +148 -0
- package/package.json +6 -20
- package/src/api/routes/instances.js +58 -15
- package/src/api/routes/operations.js +40 -10
- package/src/bmad/experts.js +165 -0
- package/src/bmad/formatter.js +238 -0
- package/src/bmad/index.js +10 -0
- package/src/bmad/nlp.js +189 -0
- package/src/bmad/participants.js +148 -0
- package/src/bot.js +252 -15
- package/src/core/config.js +18 -2
- package/src/core/instance/manager.js +59 -1
- package/src/core/mcp-sync.js +114 -0
- package/src/core/perf-monitor.js +1 -1
- package/src/core/platform/pm2-bridge.js +50 -24
- package/src/module-help.csv +4 -0
- package/src/module.yaml +46 -0
- package/web/dist/assets/{Dashboard-323Iwz70.css → Dashboard-Db69RRgS.css} +1 -1
- package/web/dist/assets/Dashboard-jlJe-uLN.js +1 -0
- package/web/dist/assets/{InstanceDetail-d8jMzT8_.js → InstanceDetail-BwYesO8h.js} +1 -1
- package/web/dist/assets/{Instances-B9UMgfY_.js → Instances-eF1JJARO.js} +1 -1
- package/web/dist/assets/{Settings-CxVYMUOR.js → Settings-BFnkGSaK.js} +1 -1
- package/web/dist/assets/{main-dB-FsGdD.js → main-D6Y4CFNn.js} +2 -2
- package/web/dist/index.html +1 -1
- package/web/dist/assets/Dashboard-CkSgP5p6.js +0 -1
package/hooks/settings.json
CHANGED
|
@@ -11,5 +11,72 @@
|
|
|
11
11
|
]
|
|
12
12
|
}
|
|
13
13
|
]
|
|
14
|
+
},
|
|
15
|
+
"permissions": {
|
|
16
|
+
"allow": [
|
|
17
|
+
"WebSearch",
|
|
18
|
+
"Bash(npm install)",
|
|
19
|
+
"Bash(pm2 list:*)",
|
|
20
|
+
"Bash(pm2 start:*)",
|
|
21
|
+
"Bash(pm2 logs:*)",
|
|
22
|
+
"WebFetch(domain:github.com)",
|
|
23
|
+
"Bash(docker stop:*)",
|
|
24
|
+
"Bash(docker rm:*)",
|
|
25
|
+
"Bash(pm2 restart:*)",
|
|
26
|
+
"Bash(docker exec:*)",
|
|
27
|
+
"Bash(docker logs:*)",
|
|
28
|
+
"Bash(pm2 flush:*)",
|
|
29
|
+
"Bash(chmod:*)",
|
|
30
|
+
"Bash(node bin/cli.js:*)",
|
|
31
|
+
"Bash(node /Users/cyrus/Documents/project/discord-cli-bot/bin/cli.js:*)",
|
|
32
|
+
"Bash(pm2 stop:*)",
|
|
33
|
+
"Bash(pm2 delete:*)",
|
|
34
|
+
"Bash(git checkout:*)",
|
|
35
|
+
"Skill(bmad:bmm:workflows:quick-spec)",
|
|
36
|
+
"Skill(bmad:bmb:workflows:module)",
|
|
37
|
+
"Skill(bmad:bmb:workflows:quick-dev)",
|
|
38
|
+
"Bash(git rev-parse:*)",
|
|
39
|
+
"Bash(node --check:*)",
|
|
40
|
+
"Bash(npm init -y)",
|
|
41
|
+
"Bash(node:*)",
|
|
42
|
+
"Bash(git add:*)",
|
|
43
|
+
"Bash(git commit:*)",
|
|
44
|
+
"Bash(python3:*)",
|
|
45
|
+
"WebFetch(domain:www.vibesparking.com)",
|
|
46
|
+
"WebFetch(domain:docs.z.ai)",
|
|
47
|
+
"Bash(claude mcp search:*)",
|
|
48
|
+
"Bash(npm search:*)",
|
|
49
|
+
"Bash(npm view:*)",
|
|
50
|
+
"WebFetch(domain:docs.bigmodel.cn)",
|
|
51
|
+
"mcp__web-search-prime__webSearchPrime",
|
|
52
|
+
"mcp__web-reader__webReader",
|
|
53
|
+
"Bash(docker stats:*)",
|
|
54
|
+
"Bash(git stash:*)",
|
|
55
|
+
"Bash(git -C /Users/cyrus/Documents/project/corp-office/finance-department log:*)",
|
|
56
|
+
"Bash(git -C /Users/cyrus/Documents/project/corp-office/finance-department status)",
|
|
57
|
+
"Bash(lsof:*)",
|
|
58
|
+
"Bash(pwdx:*)",
|
|
59
|
+
"Bash(docker:*)",
|
|
60
|
+
"Bash(kill:*)",
|
|
61
|
+
"Bash(pkill:*)",
|
|
62
|
+
"Bash(env:*)",
|
|
63
|
+
"Bash(compgen:*)",
|
|
64
|
+
"Bash(claude:*)",
|
|
65
|
+
"Bash(for:*)",
|
|
66
|
+
"Bash(do echo:*)",
|
|
67
|
+
"Bash(done:*)",
|
|
68
|
+
"mcp__zai-mcp-server__analyze_image",
|
|
69
|
+
"mcp__zread__search_doc",
|
|
70
|
+
"mcp__zread__get_repo_structure",
|
|
71
|
+
"mcp__zread__read_file",
|
|
72
|
+
"mcp__zai-mcp-server__extract_text_from_screenshot",
|
|
73
|
+
"mcp__zai-mcp-server__ui_to_artifact",
|
|
74
|
+
"mcp__zai-mcp-server__understand_technical_diagram",
|
|
75
|
+
"mcp__zai-mcp-server__diagnose_error_screenshot",
|
|
76
|
+
"mcp__zai-mcp-server__analyze_data_visualization",
|
|
77
|
+
"mcp__zai-mcp-server__analyze_video",
|
|
78
|
+
"Skill(bmad:core:workflows:party-mode)",
|
|
79
|
+
"Skill(bmad:core:agents:bmad-master)"
|
|
80
|
+
]
|
|
14
81
|
}
|
|
15
82
|
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#!/usr/bin/expect -f
|
|
2
|
+
|
|
3
|
+
# BMAD Framework Automated Installation Script
|
|
4
|
+
# This script automates the BMAD framework installation
|
|
5
|
+
|
|
6
|
+
set timeout 120
|
|
7
|
+
|
|
8
|
+
# Check if expect is installed
|
|
9
|
+
if {catch {exec expect << EOC
|
|
10
|
+
package require Expect
|
|
11
|
+
EOC
|
|
12
|
+
}} {
|
|
13
|
+
puts "Error: expect is not installed"
|
|
14
|
+
puts "Install with: brew install expect"
|
|
15
|
+
exit 1
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
puts "\n🔧 BMAD Framework Automated Installer"
|
|
19
|
+
puts "==================================\n"
|
|
20
|
+
|
|
21
|
+
# Change to project directory
|
|
22
|
+
cd /Users/cyrus/Documents/project/agent-window-main
|
|
23
|
+
|
|
24
|
+
puts "📍 Current directory: [exec pwd]"
|
|
25
|
+
puts "🚀 Starting: npx observer-ggboy-bmad-method install\n"
|
|
26
|
+
|
|
27
|
+
# Spawn the installer
|
|
28
|
+
spawn npx observer-gyboy-bmad-method install
|
|
29
|
+
|
|
30
|
+
# Wait for installer to load
|
|
31
|
+
expect {
|
|
32
|
+
-timeout 30
|
|
33
|
+
"Installation directory:"
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
puts "\n✓ Installer loaded"
|
|
37
|
+
puts "\n⚠️ IMPORTANT: Please make selections manually:"
|
|
38
|
+
puts " 1. Use ↑↓ arrows to navigate"
|
|
39
|
+
puts " 2. Press SPACE to select/deselect modules"
|
|
40
|
+
puts " 3. SKIP 'agent-window' module (your project)"
|
|
41
|
+
puts " 4. Install official BMAD modules:"
|
|
42
|
+
puts " - bmad-builder"
|
|
43
|
+
puts " - bmad-creative-intelligence-suite"
|
|
44
|
+
puts " - bmad-game-dev-studio"
|
|
45
|
+
puts " 5. Press ENTER to start installation"
|
|
46
|
+
puts "\n📝 Press ENTER when ready to see selections...\n"
|
|
47
|
+
|
|
48
|
+
# Wait for user to press Enter
|
|
49
|
+
expect {
|
|
50
|
+
"\n"
|
|
51
|
+
puts "\n✓ Ready. Proceeding with installation..."
|
|
52
|
+
exp_continue
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
# Wait for installation to complete
|
|
56
|
+
expect {
|
|
57
|
+
timeout 300
|
|
58
|
+
eof
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
puts "\n✅ Installation completed!"
|
|
62
|
+
puts "\n🔍 Verifying installation..."
|
|
63
|
+
|
|
64
|
+
# Check if BMAD files were installed
|
|
65
|
+
after 3 {
|
|
66
|
+
if {[file exists "_bmad/core/agents"]} {
|
|
67
|
+
puts "✓ BMAD core files installed"
|
|
68
|
+
} else {
|
|
69
|
+
puts "⚠️ BMAD core files not found"
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if {[file exists "_bmad/bmm/agents"]} {
|
|
73
|
+
puts "✓ BMM module installed"
|
|
74
|
+
} else {
|
|
75
|
+
puts "⚠️ BMM module not found"
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if {[file exists "_bmad/bmb/agents"]} {
|
|
79
|
+
puts "✓ BMB module installed"
|
|
80
|
+
} else {
|
|
81
|
+
puts "⚠️ BMB module not found"
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
puts "\n📚 Next steps:"
|
|
86
|
+
puts "1. Check _bmad/ directory structure"
|
|
87
|
+
puts "2. Test BMAD commands in Claude Code by typing /"
|
|
88
|
+
puts "3. Read BMAD-INSTALL-GUIDE.md for detailed information\n"
|
|
89
|
+
|
|
90
|
+
puts "Press ENTER to exit..."
|
|
91
|
+
expect user "\n"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# BMAD Framework Installation Script
|
|
4
|
+
# Interactive installation that preserves existing files
|
|
5
|
+
|
|
6
|
+
echo "🔧 BMAD Framework Installer"
|
|
7
|
+
echo ""
|
|
8
|
+
echo "Starting: npx observer-ggboy-bmad-method install"
|
|
9
|
+
echo ""
|
|
10
|
+
|
|
11
|
+
# Run installer in background with input stream
|
|
12
|
+
{
|
|
13
|
+
# Wait a bit for installer to start
|
|
14
|
+
sleep 3
|
|
15
|
+
|
|
16
|
+
# Check if it's asking about modules
|
|
17
|
+
echo "Skipping AgentWindow module installation..."
|
|
18
|
+
|
|
19
|
+
} | npx observer-ggboy-bmad-method install
|
|
20
|
+
|
|
21
|
+
echo ""
|
|
22
|
+
echo "✅ Installation complete!"
|
package/install-bmad.js
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* BMAD Framework Installation Script
|
|
5
|
+
* Interactive installer that preserves existing files
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { spawn } = require('child_process');
|
|
9
|
+
const readline = require('readline');
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
|
|
13
|
+
class BMADInstaller {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.bmadDir = path.join(process.cwd(), '_bmad');
|
|
16
|
+
this.installer = null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
log(message) {
|
|
20
|
+
console.log(`[BMAD Installer] ${message}`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async checkExistingFiles() {
|
|
24
|
+
this.log('Checking existing BMAD files...');
|
|
25
|
+
|
|
26
|
+
const existing = [];
|
|
27
|
+
|
|
28
|
+
// Check core directories
|
|
29
|
+
const coreDirs = ['agents', 'tasks', 'workflows', 'resources'];
|
|
30
|
+
const corePath = path.join(this.bmadDir, 'core');
|
|
31
|
+
|
|
32
|
+
if (fs.existsSync(corePath)) {
|
|
33
|
+
for (const dir of coreDirs) {
|
|
34
|
+
const dirPath = path.join(corePath, dir);
|
|
35
|
+
if (fs.existsSync(dirPath)) {
|
|
36
|
+
const files = fs.readdirSync(dirPath);
|
|
37
|
+
if (files.length > 0) {
|
|
38
|
+
existing.push(`core/${dir}/ (${files.length} files)`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Check modules
|
|
45
|
+
const modules = ['bmm', 'bmb'];
|
|
46
|
+
for (const mod of modules) {
|
|
47
|
+
const modPath = path.join(this.bmadDir, mod);
|
|
48
|
+
if (fs.existsSync(modPath)) {
|
|
49
|
+
const files = fs.readdirSync(modPath, { recursive: true });
|
|
50
|
+
existing.push(`${mod}/ (${files.length} files)`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (existing.length > 0) {
|
|
55
|
+
this.log(`Found existing files:\n - ${existing.join('\n - ')}`);
|
|
56
|
+
} else {
|
|
57
|
+
this.log('No existing BMAD framework files found');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return existing;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async runInteractive(input) {
|
|
64
|
+
return new Promise((resolve, reject) => {
|
|
65
|
+
this.log('Starting BMAD framework installer...');
|
|
66
|
+
this.log('Command: npx observer-ggboy-bmad-method install');
|
|
67
|
+
|
|
68
|
+
this.installer = spawn('npm', ['exec', 'observer-ggboy-bmad-method', 'install'], {
|
|
69
|
+
cwd: process.cwd(),
|
|
70
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
let output = '';
|
|
74
|
+
let prompt = '';
|
|
75
|
+
|
|
76
|
+
this.installer.stdout.on('data', (data) => {
|
|
77
|
+
const text = data.toString();
|
|
78
|
+
output += text;
|
|
79
|
+
process.stdout.write(text);
|
|
80
|
+
|
|
81
|
+
// Check if installer is waiting for input
|
|
82
|
+
if (text.includes('?') || text.includes('Select')) {
|
|
83
|
+
prompt = text;
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
this.installer.stderr.on('data', (data) => {
|
|
88
|
+
process.stderr.write(data);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
this.installer.on('close', (code) => {
|
|
92
|
+
if (code === 0) {
|
|
93
|
+
this.log('✅ Installation completed');
|
|
94
|
+
resolve(output);
|
|
95
|
+
} else {
|
|
96
|
+
this.log(`Installer exited with code ${code}`);
|
|
97
|
+
resolve(output);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// Send input if provided
|
|
102
|
+
if (input) {
|
|
103
|
+
setTimeout(() => {
|
|
104
|
+
this.installer.stdin.write(input + '\n');
|
|
105
|
+
}, 1000);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async installWithDefaults() {
|
|
111
|
+
this.log('Installing with default options (skip AgentWindow module)...');
|
|
112
|
+
|
|
113
|
+
// The installer will ask which modules to install
|
|
114
|
+
// We'll provide default answers
|
|
115
|
+
const responses = [
|
|
116
|
+
// Skip AgentWindow module (we want official modules only)
|
|
117
|
+
'\n', // Press Enter to skip AgentWindow
|
|
118
|
+
];
|
|
119
|
+
|
|
120
|
+
for (const response of responses) {
|
|
121
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
122
|
+
this.installer.stdin.write(response);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Main installation
|
|
128
|
+
async function main() {
|
|
129
|
+
const installer = new BMADInstaller();
|
|
130
|
+
|
|
131
|
+
console.log('\n🔧 BMAD Framework Interactive Installer\n');
|
|
132
|
+
console.log('This will install the BMAD framework without overwriting existing files.\n');
|
|
133
|
+
|
|
134
|
+
await installer.checkExistingFiles();
|
|
135
|
+
|
|
136
|
+
console.log('\nStarting interactive installer...');
|
|
137
|
+
console.log('Note: When prompted, SKIP the AgentWindow module installation.');
|
|
138
|
+
console.log('Only install official BMAD modules (core, bmm, bmb).\n');
|
|
139
|
+
|
|
140
|
+
await installer.runInteractive();
|
|
141
|
+
|
|
142
|
+
console.log('\n✅ Installation complete!\n');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
main().catch(err => {
|
|
146
|
+
console.error('Error:', err);
|
|
147
|
+
process.exit(1);
|
|
148
|
+
});
|
package/package.json
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-window",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "A window to interact with AI agents through chat interfaces. Simplified interaction, powerful backend capabilities.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/bot.js",
|
|
7
|
-
"bin": {
|
|
8
|
-
"agent-window": "./bin/cli.js"
|
|
9
|
-
},
|
|
10
7
|
"scripts": {
|
|
11
8
|
"start": "node src/bot.js",
|
|
12
9
|
"dev": "node --watch src/bot.js",
|
|
@@ -15,23 +12,16 @@
|
|
|
15
12
|
"ui:dev": "cd web && npm run dev",
|
|
16
13
|
"ui:build": "cd web && npm run build",
|
|
17
14
|
"pm2:start": "pm2 start ecosystem.config.cjs",
|
|
18
|
-
"pm2:stop": "pm2 stop
|
|
19
|
-
"pm2:restart": "pm2 restart
|
|
20
|
-
"pm2:logs": "pm2 logs
|
|
15
|
+
"pm2:stop": "pm2 stop bot-corp",
|
|
16
|
+
"pm2:restart": "pm2 restart bot-corp",
|
|
17
|
+
"pm2:logs": "pm2 logs bot-corp"
|
|
21
18
|
},
|
|
22
19
|
"keywords": [
|
|
23
|
-
"agent",
|
|
24
|
-
"window",
|
|
25
20
|
"discord",
|
|
26
|
-
"slack",
|
|
27
21
|
"bot",
|
|
22
|
+
"bmad",
|
|
28
23
|
"claude",
|
|
29
|
-
"ai"
|
|
30
|
-
"cli",
|
|
31
|
-
"docker",
|
|
32
|
-
"sandbox",
|
|
33
|
-
"chat",
|
|
34
|
-
"interface"
|
|
24
|
+
"ai"
|
|
35
25
|
],
|
|
36
26
|
"author": "",
|
|
37
27
|
"license": "MIT",
|
|
@@ -49,9 +39,5 @@
|
|
|
49
39
|
},
|
|
50
40
|
"overrides": {
|
|
51
41
|
"undici": "^7.19.0"
|
|
52
|
-
},
|
|
53
|
-
"repository": {
|
|
54
|
-
"type": "git",
|
|
55
|
-
"url": "https://github.com/Observer-GGboy/AgentWindow"
|
|
56
42
|
}
|
|
57
43
|
}
|
|
@@ -24,7 +24,9 @@ import {
|
|
|
24
24
|
getLogs
|
|
25
25
|
} from '../../core/instance/pm2-bridge.js';
|
|
26
26
|
import { readConfig, writeConfig } from '../../core/instance/config-reader.js';
|
|
27
|
+
import { paths } from '../../core/platform/index.js';
|
|
27
28
|
import { existsSync } from 'fs';
|
|
29
|
+
import { promises as fs } from 'fs';
|
|
28
30
|
import path from 'path';
|
|
29
31
|
|
|
30
32
|
/**
|
|
@@ -113,27 +115,68 @@ export async function registerInstanceRoutes(fastify) {
|
|
|
113
115
|
try {
|
|
114
116
|
const { name, projectPath, displayName, tags, configPath, config, createConfig, instanceType } = request.body;
|
|
115
117
|
|
|
116
|
-
// If creating config file, ensure
|
|
118
|
+
// If creating config file, ensure directories exist
|
|
117
119
|
if (createConfig) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
+
// For simple-config instances, config goes in botsDir/{name}/config.json
|
|
121
|
+
// For bmad-plugin instances, config goes in project directory
|
|
122
|
+
let configFilePath;
|
|
123
|
+
const effectiveInstanceType = instanceType || 'simple-config';
|
|
124
|
+
|
|
125
|
+
if (effectiveInstanceType === 'simple-config') {
|
|
126
|
+
// Simple-config: use botsDir/{name}/config.json
|
|
127
|
+
const botsDir = paths.getBotsDir();
|
|
128
|
+
configFilePath = configPath || path.join(botsDir, name, 'config.json');
|
|
129
|
+
|
|
130
|
+
// Ensure bots directory exists
|
|
131
|
+
if (!existsSync(botsDir)) {
|
|
132
|
+
try {
|
|
133
|
+
await fs.mkdir(botsDir, { recursive: true });
|
|
134
|
+
} catch (err) {
|
|
135
|
+
return reply.code(400).send({
|
|
136
|
+
error: 'Failed to create bots directory',
|
|
137
|
+
message: err.message
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
120
141
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
142
|
+
// Create instance directory (botsDir/{name})
|
|
143
|
+
const instanceDir = path.dirname(configFilePath);
|
|
144
|
+
if (!existsSync(instanceDir)) {
|
|
145
|
+
try {
|
|
146
|
+
await fs.mkdir(instanceDir, { recursive: true });
|
|
147
|
+
} catch (err) {
|
|
148
|
+
return reply.code(400).send({
|
|
149
|
+
error: 'Failed to create instance directory',
|
|
150
|
+
message: err.message
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
} else {
|
|
155
|
+
// BMAD plugin: use projectPath/config.json
|
|
156
|
+
configFilePath = configPath || path.join(projectPath, 'config.json');
|
|
157
|
+
|
|
158
|
+
// Create project directory if it doesn't exist
|
|
159
|
+
if (!existsSync(projectPath)) {
|
|
160
|
+
try {
|
|
161
|
+
await fs.mkdir(projectPath, { recursive: true });
|
|
162
|
+
} catch (err) {
|
|
163
|
+
return reply.code(400).send({
|
|
164
|
+
error: 'Failed to create project directory',
|
|
165
|
+
message: err.message
|
|
166
|
+
});
|
|
167
|
+
}
|
|
130
168
|
}
|
|
131
169
|
}
|
|
132
170
|
|
|
133
171
|
// Write config file
|
|
134
|
-
const configFilePath = configPath || path.join(projectPath, 'config.json');
|
|
135
172
|
try {
|
|
136
|
-
|
|
173
|
+
// Ensure dockerImage uses local claude-sandbox if workspace specified but no dockerImage
|
|
174
|
+
const finalConfig = { ...config };
|
|
175
|
+
if (finalConfig.workspace && finalConfig.workspace.containerName && !finalConfig.workspace.dockerImage) {
|
|
176
|
+
finalConfig.workspace.dockerImage = 'claude-sandbox';
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
await fs.writeFile(configFilePath, JSON.stringify(finalConfig, null, 2), 'utf-8');
|
|
137
180
|
} catch (err) {
|
|
138
181
|
return reply.code(400).send({
|
|
139
182
|
error: 'Failed to write config file',
|
|
@@ -148,7 +191,7 @@ export async function registerInstanceRoutes(fastify) {
|
|
|
148
191
|
tags,
|
|
149
192
|
configPath: finalConfigPath,
|
|
150
193
|
createConfig: true,
|
|
151
|
-
instanceType:
|
|
194
|
+
instanceType: effectiveInstanceType
|
|
152
195
|
});
|
|
153
196
|
|
|
154
197
|
if (!result.success) {
|
|
@@ -108,19 +108,20 @@ export async function registerOperationRoutes(fastify) {
|
|
|
108
108
|
};
|
|
109
109
|
|
|
110
110
|
// Check if process already exists in PM2
|
|
111
|
-
const { getProcess } = await import('../../core/instance/pm2-bridge.js');
|
|
111
|
+
const { getProcess, deleteProcess } = await import('../../core/instance/pm2-bridge.js');
|
|
112
112
|
const existingProc = await getProcess(botName);
|
|
113
113
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
// Process doesn't exist or is stopped - start it
|
|
121
|
-
result = await startProcess(scriptPath, botName, options);
|
|
114
|
+
// Always delete existing process before starting to ensure:
|
|
115
|
+
// 1. Fresh configuration (environment variables)
|
|
116
|
+
// 2. No duplicate instances
|
|
117
|
+
// 3. Clean state (no stale resurrected processes)
|
|
118
|
+
if (existingProc) {
|
|
119
|
+
await deleteProcess(botName);
|
|
122
120
|
}
|
|
123
121
|
|
|
122
|
+
// Start with fresh configuration
|
|
123
|
+
const result = await startProcess(scriptPath, botName, options);
|
|
124
|
+
|
|
124
125
|
if (!result.success) {
|
|
125
126
|
return reply.code(400).send({
|
|
126
127
|
error: result.error,
|
|
@@ -202,8 +203,37 @@ export async function registerOperationRoutes(fastify) {
|
|
|
202
203
|
});
|
|
203
204
|
}
|
|
204
205
|
|
|
206
|
+
// Normalize instance type
|
|
207
|
+
const normalizedType = normalizeInstanceType(instance.instanceType);
|
|
208
|
+
|
|
209
|
+
// Determine script path
|
|
210
|
+
let scriptPath;
|
|
211
|
+
const cwd = instance.projectPath;
|
|
212
|
+
|
|
213
|
+
switch (normalizedType) {
|
|
214
|
+
case 'bmad-plugin':
|
|
215
|
+
scriptPath = path.join(instance.projectPath, '_agent-bridge', 'src', 'bot.js');
|
|
216
|
+
break;
|
|
217
|
+
case 'simple-config':
|
|
218
|
+
default:
|
|
219
|
+
scriptPath = path.join(PACKAGE_ROOT, 'src', 'bot.js');
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
|
|
205
223
|
const botName = instance.botName || `bot-${name}`;
|
|
206
|
-
|
|
224
|
+
|
|
225
|
+
// For restart, delete and start fresh to update env vars
|
|
226
|
+
const { deleteProcess, startProcess } = await import('../../core/instance/pm2-bridge.js');
|
|
227
|
+
await deleteProcess(botName);
|
|
228
|
+
|
|
229
|
+
const options = {
|
|
230
|
+
cwd,
|
|
231
|
+
env: {
|
|
232
|
+
CONFIG_PATH: instance.configPath
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
const result = await startProcess(scriptPath, botName, options);
|
|
207
237
|
|
|
208
238
|
if (!result.success) {
|
|
209
239
|
return reply.code(400).send({
|