commanderclaw 1.1.3
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 +57 -0
- package/bin/commanderclaw.cjs +77 -0
- package/binaries/darwin-arm64/coordination-server +0 -0
- package/dist/cli/config.js +116 -0
- package/dist/cli/gateway.js +250 -0
- package/dist/cli/index.js +53 -0
- package/dist/cli/plugin.js +400 -0
- package/dist/cli/utils.js +121 -0
- package/dist/plugin/client.d.ts +76 -0
- package/dist/plugin/client.d.ts.map +1 -0
- package/dist/plugin/config.d.ts +25 -0
- package/dist/plugin/config.d.ts.map +1 -0
- package/dist/plugin/index.cjs +4538 -0
- package/dist/plugin/index.cjs.map +1 -0
- package/dist/plugin/index.d.ts +15 -0
- package/dist/plugin/index.d.ts.map +1 -0
- package/dist/plugin/index.mjs +4536 -0
- package/dist/plugin/index.mjs.map +1 -0
- package/dist/plugin/skills/commanderclaw/SKILL.md +177 -0
- package/dist/plugin/tools/command.d.ts +7 -0
- package/dist/plugin/tools/command.d.ts.map +1 -0
- package/dist/plugin/tools/command.ts +136 -0
- package/dist/plugin/tools/nodes.d.ts +7 -0
- package/dist/plugin/tools/nodes.d.ts.map +1 -0
- package/dist/plugin/tools/nodes.ts +71 -0
- package/dist/plugin/tools/status.d.ts +7 -0
- package/dist/plugin/tools/status.d.ts.map +1 -0
- package/dist/plugin/tools/status.ts +59 -0
- package/dist/plugin/tools/task.d.ts +7 -0
- package/dist/plugin/tools/task.d.ts.map +1 -0
- package/dist/plugin/tools/task.ts +254 -0
- package/dist/plugin/types.d.ts +133 -0
- package/dist/plugin/types.d.ts.map +1 -0
- package/openclaw.plugin.json +51 -0
- package/package.json +86 -0
package/README.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# CommanderClaw
|
|
2
|
+
|
|
3
|
+
Multi-device Agent Coordination Framework - CLI and OpenClaw/QClaw Plugin.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g commanderclaw
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
### CLI Commands
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Start gateway (server + web console)
|
|
17
|
+
commanderclaw gateway start
|
|
18
|
+
|
|
19
|
+
# Check gateway status
|
|
20
|
+
commanderclaw gateway status
|
|
21
|
+
|
|
22
|
+
# Stop gateway
|
|
23
|
+
commanderclaw gateway stop
|
|
24
|
+
|
|
25
|
+
# Install plugin to QClaw
|
|
26
|
+
commanderclaw plugin install qclaw
|
|
27
|
+
|
|
28
|
+
# Install plugin to OpenClaw
|
|
29
|
+
commanderclaw plugin install openclaw
|
|
30
|
+
|
|
31
|
+
# Check plugin status
|
|
32
|
+
commanderclaw plugin status
|
|
33
|
+
|
|
34
|
+
# Configure server URL and token
|
|
35
|
+
commanderclaw config
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Gateway Ports
|
|
39
|
+
|
|
40
|
+
| Service | Port |
|
|
41
|
+
|---------|------|
|
|
42
|
+
| Server | 19739 |
|
|
43
|
+
| WebSocket | ws://127.0.0.1:19739/ws |
|
|
44
|
+
| Web Console | 19730 |
|
|
45
|
+
|
|
46
|
+
## Supported Platforms
|
|
47
|
+
|
|
48
|
+
| Platform | Architecture |
|
|
49
|
+
|----------|--------------|
|
|
50
|
+
| macOS | x64 (Intel) |
|
|
51
|
+
| macOS | arm64 (Apple Silicon) |
|
|
52
|
+
| Linux | x64 |
|
|
53
|
+
| Windows | x64 |
|
|
54
|
+
|
|
55
|
+
## License
|
|
56
|
+
|
|
57
|
+
MIT
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const { spawn } = require('child_process');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
|
|
8
|
+
const command = process.argv[2];
|
|
9
|
+
|
|
10
|
+
// Helper to get platform identifier
|
|
11
|
+
function getPlatformId() {
|
|
12
|
+
const platform = os.platform();
|
|
13
|
+
const arch = os.arch();
|
|
14
|
+
|
|
15
|
+
// Normalize architecture
|
|
16
|
+
let normalizedArch = arch;
|
|
17
|
+
if (arch === 'x64' || arch === 'amd64') {
|
|
18
|
+
normalizedArch = 'x64';
|
|
19
|
+
} else if (arch === 'arm64' || arch === 'aarch64') {
|
|
20
|
+
normalizedArch = 'arm64';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return `${platform}-${normalizedArch}`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Gateway start uses pre-compiled binary
|
|
27
|
+
// Other gateway commands use TypeScript implementation
|
|
28
|
+
if (command === 'gateway' && process.argv[3] === 'start') {
|
|
29
|
+
const platformId = getPlatformId();
|
|
30
|
+
const ext = os.platform() === 'win32' ? '.exe' : '';
|
|
31
|
+
const binaryPath = path.join(
|
|
32
|
+
__dirname,
|
|
33
|
+
'..',
|
|
34
|
+
'binaries',
|
|
35
|
+
platformId,
|
|
36
|
+
`coordination-server${ext}`
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
if (!fs.existsSync(binaryPath)) {
|
|
40
|
+
console.error(`Error: Unsupported platform: ${platformId}`);
|
|
41
|
+
console.error('');
|
|
42
|
+
console.error('Supported platforms:');
|
|
43
|
+
console.error(' - darwin-x64 (macOS Intel)');
|
|
44
|
+
console.error(' - darwin-arm64 (macOS Apple Silicon)');
|
|
45
|
+
console.error(' - linux-x64 (Linux)');
|
|
46
|
+
console.error(' - win32-x64 (Windows)');
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const args = process.argv.slice(4);
|
|
51
|
+
const child = spawn(binaryPath, args, {
|
|
52
|
+
stdio: 'inherit',
|
|
53
|
+
env: { ...process.env },
|
|
54
|
+
shell: os.platform() === 'win32'
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
child.on('error', (err) => {
|
|
58
|
+
console.error('Failed to start server:', err.message);
|
|
59
|
+
process.exit(1);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
child.on('exit', (code) => {
|
|
63
|
+
process.exit(code || 0);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Other commands use TypeScript implementation
|
|
68
|
+
else {
|
|
69
|
+
const cliPath = path.join(__dirname, '..', 'dist', 'cli', 'index.js');
|
|
70
|
+
|
|
71
|
+
if (!fs.existsSync(cliPath)) {
|
|
72
|
+
console.error('Error: CLI not built. Run: npm run build');
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
require(cliPath);
|
|
77
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as os from 'os';
|
|
4
|
+
import { rl, rlWithDefault, maskToken, DEFAULT_SERVER_URL, DEFAULT_DEVICE_NAME } from './utils.js';
|
|
5
|
+
export function handleConfig() {
|
|
6
|
+
console.log('🦞 CommanderClaw Configuration');
|
|
7
|
+
console.log();
|
|
8
|
+
const homeDir = os.homedir();
|
|
9
|
+
let configPath;
|
|
10
|
+
if (fs.existsSync('/Applications/QClaw.app')) {
|
|
11
|
+
configPath = path.join(homeDir, '.qclaw', 'openclaw.json');
|
|
12
|
+
console.log('Detected QClaw installation.');
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
configPath = path.join(homeDir, '.openclaw', 'openclaw.json');
|
|
16
|
+
}
|
|
17
|
+
const existingConfig = loadExistingConfig(configPath);
|
|
18
|
+
console.log('Current configuration:');
|
|
19
|
+
console.log(` Server URL: ${existingConfig.serverUrl}`);
|
|
20
|
+
if (existingConfig.token) {
|
|
21
|
+
console.log(` Token: ${maskToken(existingConfig.token)}`);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
console.log(' Token: (not set)');
|
|
25
|
+
}
|
|
26
|
+
console.log(` Device Name: ${existingConfig.deviceName}`);
|
|
27
|
+
console.log();
|
|
28
|
+
// Collect new config
|
|
29
|
+
collectConfigWithDefaults(existingConfig).then(config => {
|
|
30
|
+
updateConfigFile(configPath, config);
|
|
31
|
+
console.log();
|
|
32
|
+
console.log('✅ Configuration updated!');
|
|
33
|
+
console.log();
|
|
34
|
+
console.log('New configuration:');
|
|
35
|
+
console.log(` Server URL: ${config.serverUrl}`);
|
|
36
|
+
console.log(` Device Name: ${config.deviceName}`);
|
|
37
|
+
if (config.token) {
|
|
38
|
+
console.log(` Token: ${maskToken(config.token)}`);
|
|
39
|
+
}
|
|
40
|
+
console.log();
|
|
41
|
+
console.log('Restart your OpenClaw/QClaw to apply changes.');
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
function loadExistingConfig(configPath) {
|
|
45
|
+
const config = {
|
|
46
|
+
serverUrl: DEFAULT_SERVER_URL,
|
|
47
|
+
token: '',
|
|
48
|
+
deviceName: DEFAULT_DEVICE_NAME,
|
|
49
|
+
};
|
|
50
|
+
if (!fs.existsSync(configPath)) {
|
|
51
|
+
return config;
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
const data = fs.readFileSync(configPath, 'utf-8');
|
|
55
|
+
const cfg = JSON.parse(data);
|
|
56
|
+
const cc = cfg.channels?.commanderclaw || cfg.plugins?.entries?.commanderclaw?.config || {};
|
|
57
|
+
return {
|
|
58
|
+
serverUrl: cc.serverUrl || config.serverUrl,
|
|
59
|
+
token: cc.token || config.token,
|
|
60
|
+
deviceName: cc.deviceName || config.deviceName,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return config;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
async function collectConfigWithDefaults(defaults) {
|
|
68
|
+
const serverUrl = await rlWithDefault('CommanderClaw server URL', defaults.serverUrl);
|
|
69
|
+
const token = await rl('Authentication token (press Enter to skip): ');
|
|
70
|
+
const deviceName = await rlWithDefault('Device name', defaults.deviceName);
|
|
71
|
+
return {
|
|
72
|
+
serverUrl,
|
|
73
|
+
token: token || defaults.token,
|
|
74
|
+
deviceName,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function updateConfigFile(configPath, config) {
|
|
78
|
+
let cfg = {};
|
|
79
|
+
if (fs.existsSync(configPath)) {
|
|
80
|
+
try {
|
|
81
|
+
cfg = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
82
|
+
}
|
|
83
|
+
catch { }
|
|
84
|
+
}
|
|
85
|
+
// Update channels
|
|
86
|
+
if (!cfg.channels)
|
|
87
|
+
cfg.channels = {};
|
|
88
|
+
cfg.channels.commanderclaw = {
|
|
89
|
+
enabled: true,
|
|
90
|
+
serverUrl: config.serverUrl,
|
|
91
|
+
token: config.token,
|
|
92
|
+
deviceName: config.deviceName,
|
|
93
|
+
autoConnect: true,
|
|
94
|
+
};
|
|
95
|
+
// Update plugins
|
|
96
|
+
if (!cfg.plugins)
|
|
97
|
+
cfg.plugins = {};
|
|
98
|
+
if (!cfg.plugins.entries)
|
|
99
|
+
cfg.plugins.entries = {};
|
|
100
|
+
cfg.plugins.entries.commanderclaw = {
|
|
101
|
+
enabled: true,
|
|
102
|
+
config: {
|
|
103
|
+
serverUrl: config.serverUrl,
|
|
104
|
+
token: config.token,
|
|
105
|
+
deviceName: config.deviceName,
|
|
106
|
+
autoConnect: true,
|
|
107
|
+
reconnect: {
|
|
108
|
+
enabled: true,
|
|
109
|
+
maxAttempts: 10,
|
|
110
|
+
delayMs: 5000,
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
115
|
+
fs.writeFileSync(configPath, JSON.stringify(cfg, null, 2));
|
|
116
|
+
}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import * as os from 'os';
|
|
4
|
+
import { spawn, execSync } from 'child_process';
|
|
5
|
+
import { getProjectRoot } from './utils.js';
|
|
6
|
+
const SERVER_PORT = 19739;
|
|
7
|
+
const WEB_PORT = 19730;
|
|
8
|
+
const SERVER_PID_FILE = '/tmp/commanderclaw-server.pid';
|
|
9
|
+
const WEB_PID_FILE = '/tmp/commanderclaw-web.pid';
|
|
10
|
+
const SERVER_LOG_FILE = '/tmp/commanderclaw-server.log';
|
|
11
|
+
const WEB_LOG_FILE = '/tmp/commanderclaw-web.log';
|
|
12
|
+
export function handleGateway(args) {
|
|
13
|
+
if (args.length === 0) {
|
|
14
|
+
printGatewayUsage();
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
const action = args[0];
|
|
18
|
+
switch (action) {
|
|
19
|
+
case 'start':
|
|
20
|
+
gatewayStart();
|
|
21
|
+
break;
|
|
22
|
+
case 'stop':
|
|
23
|
+
gatewayStop();
|
|
24
|
+
break;
|
|
25
|
+
case 'restart':
|
|
26
|
+
gatewayRestart();
|
|
27
|
+
break;
|
|
28
|
+
case 'status':
|
|
29
|
+
gatewayStatus();
|
|
30
|
+
break;
|
|
31
|
+
default:
|
|
32
|
+
console.log(`Unknown gateway action: ${action}`);
|
|
33
|
+
printGatewayUsage();
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function printGatewayUsage() {
|
|
38
|
+
console.log('Gateway management commands:');
|
|
39
|
+
console.log();
|
|
40
|
+
console.log('Usage:');
|
|
41
|
+
console.log(' commanderclaw gateway <action>');
|
|
42
|
+
console.log();
|
|
43
|
+
console.log('Actions:');
|
|
44
|
+
console.log(' start Start server (port 19739) and web console (port 19730)');
|
|
45
|
+
console.log(' stop Stop server and web console');
|
|
46
|
+
console.log(' restart Restart server and web console');
|
|
47
|
+
console.log(' status Show status of server and web console');
|
|
48
|
+
}
|
|
49
|
+
function getBinaryPath() {
|
|
50
|
+
const platform = os.platform();
|
|
51
|
+
const arch = os.arch();
|
|
52
|
+
let platformId = `${platform}-${arch === 'x64' ? 'x64' : arch}`;
|
|
53
|
+
// Find binary in package binaries directory
|
|
54
|
+
const packageDir = path.dirname(path.dirname(__dirname));
|
|
55
|
+
const binaryDir = path.join(packageDir, 'binaries', platformId);
|
|
56
|
+
const ext = platform === 'win32' ? '.exe' : '';
|
|
57
|
+
const binaryPath = path.join(binaryDir, `coordination-server${ext}`);
|
|
58
|
+
if (fs.existsSync(binaryPath)) {
|
|
59
|
+
return binaryPath;
|
|
60
|
+
}
|
|
61
|
+
// Fallback to project root bin directory (development mode)
|
|
62
|
+
const projectRoot = getProjectRoot();
|
|
63
|
+
const devBinaryPath = path.join(projectRoot, 'bin', 'coordination-server');
|
|
64
|
+
if (fs.existsSync(devBinaryPath)) {
|
|
65
|
+
return devBinaryPath;
|
|
66
|
+
}
|
|
67
|
+
// Need to build
|
|
68
|
+
console.log('(building server first)...');
|
|
69
|
+
execSync('go build -o bin/coordination-server ./cmd/coordination-server', {
|
|
70
|
+
cwd: projectRoot,
|
|
71
|
+
stdio: 'inherit',
|
|
72
|
+
});
|
|
73
|
+
return devBinaryPath;
|
|
74
|
+
}
|
|
75
|
+
function isProcessRunning(pidFile) {
|
|
76
|
+
if (!fs.existsSync(pidFile)) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
const pid = parseInt(fs.readFileSync(pidFile, 'utf-8').trim(), 10);
|
|
80
|
+
if (isNaN(pid)) {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
process.kill(pid, 0);
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function stopProcess(pidFile) {
|
|
92
|
+
if (!fs.existsSync(pidFile)) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const pid = parseInt(fs.readFileSync(pidFile, 'utf-8').trim(), 10);
|
|
96
|
+
if (isNaN(pid)) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
try {
|
|
100
|
+
process.kill(pid, 'SIGTERM');
|
|
101
|
+
setTimeout(() => {
|
|
102
|
+
try {
|
|
103
|
+
process.kill(pid, 'SIGKILL');
|
|
104
|
+
}
|
|
105
|
+
catch { }
|
|
106
|
+
}, 500);
|
|
107
|
+
}
|
|
108
|
+
catch { }
|
|
109
|
+
fs.unlinkSync(pidFile);
|
|
110
|
+
}
|
|
111
|
+
function gatewayStart() {
|
|
112
|
+
const serverRunning = isProcessRunning(SERVER_PID_FILE);
|
|
113
|
+
const webRunning = isProcessRunning(WEB_PID_FILE);
|
|
114
|
+
if (serverRunning && webRunning) {
|
|
115
|
+
console.log('Gateway is already running');
|
|
116
|
+
console.log(` Server: http://127.0.0.1:${SERVER_PORT}`);
|
|
117
|
+
console.log(` Web Console: http://127.0.0.1:${WEB_PORT}`);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (!serverRunning) {
|
|
121
|
+
process.stdout.write(`Starting server on port ${SERVER_PORT}... `);
|
|
122
|
+
if (startServer()) {
|
|
123
|
+
console.log('OK');
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
console.log('Failed');
|
|
127
|
+
process.exit(1);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (!webRunning) {
|
|
131
|
+
process.stdout.write(`Starting web console on port ${WEB_PORT}... `);
|
|
132
|
+
if (startWeb()) {
|
|
133
|
+
console.log('OK');
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
console.log('Failed');
|
|
137
|
+
process.exit(1);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
console.log();
|
|
141
|
+
console.log('Gateway started successfully!');
|
|
142
|
+
console.log(` Server: http://127.0.0.1:${SERVER_PORT}`);
|
|
143
|
+
console.log(` WebSocket: ws://127.0.0.1:${SERVER_PORT}/ws`);
|
|
144
|
+
console.log(` Web Console: http://127.0.0.1:${WEB_PORT}`);
|
|
145
|
+
console.log();
|
|
146
|
+
console.log('Logs:');
|
|
147
|
+
console.log(` Server: ${SERVER_LOG_FILE}`);
|
|
148
|
+
console.log(` Web: ${WEB_LOG_FILE}`);
|
|
149
|
+
}
|
|
150
|
+
function startServer() {
|
|
151
|
+
try {
|
|
152
|
+
const binaryPath = getBinaryPath();
|
|
153
|
+
const logFile = fs.openSync(SERVER_LOG_FILE, 'a');
|
|
154
|
+
const child = spawn(binaryPath, ['-port', String(SERVER_PORT)], {
|
|
155
|
+
detached: true,
|
|
156
|
+
stdio: ['ignore', logFile, logFile],
|
|
157
|
+
});
|
|
158
|
+
child.unref();
|
|
159
|
+
fs.writeFileSync(SERVER_PID_FILE, String(child.pid));
|
|
160
|
+
// Wait a bit to verify it started
|
|
161
|
+
setTimeout(() => {
|
|
162
|
+
if (!isProcessRunning(SERVER_PID_FILE)) {
|
|
163
|
+
console.log('\nServer process exited immediately. Check logs at ' + SERVER_LOG_FILE);
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
166
|
+
}, 500);
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
catch (e) {
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
function startWeb() {
|
|
174
|
+
try {
|
|
175
|
+
const projectRoot = getProjectRoot();
|
|
176
|
+
const webDir = path.join(projectRoot, 'web');
|
|
177
|
+
if (!fs.existsSync(webDir)) {
|
|
178
|
+
console.log('(web directory not found, skipping)');
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
const logFile = fs.openSync(WEB_LOG_FILE, 'a');
|
|
182
|
+
const child = spawn('npm', ['run', 'dev', '--', '--port', String(WEB_PORT)], {
|
|
183
|
+
cwd: webDir,
|
|
184
|
+
detached: true,
|
|
185
|
+
stdio: ['ignore', logFile, logFile],
|
|
186
|
+
env: { ...process.env, PORT: String(WEB_PORT) },
|
|
187
|
+
});
|
|
188
|
+
child.unref();
|
|
189
|
+
fs.writeFileSync(WEB_PID_FILE, String(child.pid));
|
|
190
|
+
return true;
|
|
191
|
+
}
|
|
192
|
+
catch (e) {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
function gatewayStop() {
|
|
197
|
+
process.stdout.write('Stopping web console... ');
|
|
198
|
+
if (isProcessRunning(WEB_PID_FILE)) {
|
|
199
|
+
stopProcess(WEB_PID_FILE);
|
|
200
|
+
console.log('OK');
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
console.log('(not running)');
|
|
204
|
+
}
|
|
205
|
+
process.stdout.write('Stopping server... ');
|
|
206
|
+
if (isProcessRunning(SERVER_PID_FILE)) {
|
|
207
|
+
stopProcess(SERVER_PID_FILE);
|
|
208
|
+
console.log('OK');
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
console.log('(not running)');
|
|
212
|
+
}
|
|
213
|
+
console.log('Gateway stopped');
|
|
214
|
+
}
|
|
215
|
+
function gatewayRestart() {
|
|
216
|
+
console.log('Restarting gateway...');
|
|
217
|
+
gatewayStop();
|
|
218
|
+
setTimeout(() => {
|
|
219
|
+
console.log();
|
|
220
|
+
gatewayStart();
|
|
221
|
+
}, 500);
|
|
222
|
+
}
|
|
223
|
+
function gatewayStatus() {
|
|
224
|
+
console.log('CommanderClaw Gateway Status');
|
|
225
|
+
console.log('-'.repeat(40));
|
|
226
|
+
const serverRunning = isProcessRunning(SERVER_PID_FILE);
|
|
227
|
+
const webRunning = isProcessRunning(WEB_PID_FILE);
|
|
228
|
+
let serverStatus = 'stopped';
|
|
229
|
+
let serverPid = '';
|
|
230
|
+
if (serverRunning) {
|
|
231
|
+
serverStatus = 'running';
|
|
232
|
+
serverPid = fs.readFileSync(SERVER_PID_FILE, 'utf-8').trim();
|
|
233
|
+
}
|
|
234
|
+
let webStatus = 'stopped';
|
|
235
|
+
let webPid = '';
|
|
236
|
+
if (webRunning) {
|
|
237
|
+
webStatus = 'running';
|
|
238
|
+
webPid = fs.readFileSync(WEB_PID_FILE, 'utf-8').trim();
|
|
239
|
+
}
|
|
240
|
+
console.log(`Server (port ${SERVER_PORT}): ${serverStatus}${serverPid ? ` (PID: ${serverPid})` : ''}`);
|
|
241
|
+
console.log(`Web (port ${WEB_PORT}): ${webStatus}${webPid ? ` (PID: ${webPid})` : ''}`);
|
|
242
|
+
if (serverRunning) {
|
|
243
|
+
console.log();
|
|
244
|
+
console.log(`Server URL: http://127.0.0.1:${SERVER_PORT}`);
|
|
245
|
+
console.log(`WebSocket: ws://127.0.0.1:${SERVER_PORT}/ws`);
|
|
246
|
+
}
|
|
247
|
+
if (webRunning) {
|
|
248
|
+
console.log(`Web Console: http://127.0.0.1:${WEB_PORT}`);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { handleGateway } from './gateway.js';
|
|
2
|
+
import { handlePlugin } from './plugin.js';
|
|
3
|
+
import { handleConfig } from './config.js';
|
|
4
|
+
const VERSION = '1.1.3';
|
|
5
|
+
function printUsage() {
|
|
6
|
+
console.log('CommanderClaw - Multi-device Agent Coordination Framework');
|
|
7
|
+
console.log();
|
|
8
|
+
console.log('Usage:');
|
|
9
|
+
console.log(' commanderclaw <command> [arguments]');
|
|
10
|
+
console.log();
|
|
11
|
+
console.log('Commands:');
|
|
12
|
+
console.log(' gateway Manage gateway services (server + web)');
|
|
13
|
+
console.log(' plugin Install/update plugin to OpenClaw/QClaw');
|
|
14
|
+
console.log(' config Configure server URL and token');
|
|
15
|
+
console.log(' help Show this help message');
|
|
16
|
+
console.log();
|
|
17
|
+
console.log('Run \'commanderclaw gateway\' for gateway commands.');
|
|
18
|
+
console.log('Run \'commanderclaw plugin\' for plugin commands.');
|
|
19
|
+
}
|
|
20
|
+
function main() {
|
|
21
|
+
const args = process.argv.slice(2);
|
|
22
|
+
if (args.length === 0) {
|
|
23
|
+
printUsage();
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
const command = args[0];
|
|
27
|
+
const subArgs = args.slice(1);
|
|
28
|
+
switch (command) {
|
|
29
|
+
case 'gateway':
|
|
30
|
+
handleGateway(subArgs);
|
|
31
|
+
break;
|
|
32
|
+
case 'plugin':
|
|
33
|
+
handlePlugin(subArgs);
|
|
34
|
+
break;
|
|
35
|
+
case 'config':
|
|
36
|
+
handleConfig();
|
|
37
|
+
break;
|
|
38
|
+
case 'help':
|
|
39
|
+
case '-h':
|
|
40
|
+
case '--help':
|
|
41
|
+
printUsage();
|
|
42
|
+
break;
|
|
43
|
+
case '-v':
|
|
44
|
+
case '--version':
|
|
45
|
+
console.log(`commanderclaw v${VERSION}`);
|
|
46
|
+
break;
|
|
47
|
+
default:
|
|
48
|
+
console.log(`Unknown command: ${command}`);
|
|
49
|
+
printUsage();
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
main();
|