@yemi33/squad 0.1.0 → 0.1.1
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/LICENSE +21 -21
- package/TODO.md +10 -10
- package/bin/squad.js +164 -164
- package/dashboard.js +901 -886
- package/engine/ado-mcp-wrapper.js +49 -49
- package/engine.js +194 -14
- package/package.json +46 -46
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 yemi33
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 yemi33
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/TODO.md
CHANGED
|
@@ -6,21 +6,21 @@ Ordered by difficulty: quick wins first, larger efforts later.
|
|
|
6
6
|
|
|
7
7
|
## Quick Wins (< 1 hour each)
|
|
8
8
|
|
|
9
|
-
- [
|
|
10
|
-
- [
|
|
11
|
-
- [
|
|
12
|
-
- [
|
|
13
|
-
- [
|
|
14
|
-
- [
|
|
15
|
-
- [
|
|
16
|
-
- [
|
|
17
|
-
- [
|
|
9
|
+
- [x] **Output.log append, not overwrite** — per-dispatch archive at `output-{id}.log` + latest copy at `output.log`
|
|
10
|
+
- [x] **Persistent cooldowns** — saved to `engine/cooldowns.json`, loaded at startup, 24hr auto-prune
|
|
11
|
+
- [x] **Worktree cleanup on merge/close** — `handlePostMerge` removes worktrees when PR merges or is abandoned
|
|
12
|
+
- [x] **Discovery skip logging** — PRD and work item discovery log skip counts by reason at debug level
|
|
13
|
+
- [x] **Idle threshold alert** — warns when all agents idle >15min (configurable via `engine.idleAlertMinutes`)
|
|
14
|
+
- [x] **Config validation at startup** — checks agents, project paths, playbooks, routing.md. Fatal errors exit(1).
|
|
15
|
+
- [x] **macOS/Linux browser launch** — already platform-aware (was done previously)
|
|
16
|
+
- [x] **Health check endpoint** — `GET /api/health` returning engine state, agents, project reachability, uptime
|
|
17
|
+
- [x] **Fan-out per-agent timeout** — fan-out items carry `meta.deadline`, configurable via `engine.fanOutTimeout`
|
|
18
18
|
|
|
19
19
|
## Small Effort (1–3 hours each)
|
|
20
20
|
|
|
21
21
|
- [ ] **Auto-retry with backoff** — when an agent errors, auto-retry with exponential backoff (5min, 15min, cap at 3 attempts) instead of requiring manual dashboard retry.
|
|
22
22
|
- [ ] **Auto-escalation** — if an agent errors 3 times in a row, pause their dispatch and alert via dashboard/Teams
|
|
23
|
-
- [
|
|
23
|
+
- [x] **Post-merge hooks** — `handlePostMerge`: worktree cleanup, PRD status → implemented, prsMerged metric, Teams notification
|
|
24
24
|
- [ ] **Pending dispatch explanation** — show in dashboard why each pending item hasn't been dispatched (no idle agent? cooldown? max concurrency?)
|
|
25
25
|
- [ ] **Work item editing** — edit title, description, type, priority, agent assignment from the dashboard UI (currently requires editing JSON)
|
|
26
26
|
- [ ] **Bulk operations** — retry/delete/reassign multiple work items at once
|
package/bin/squad.js
CHANGED
|
@@ -1,164 +1,164 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Squad CLI — Central AI dev team manager
|
|
4
|
-
*
|
|
5
|
-
* Usage:
|
|
6
|
-
* squad init Bootstrap ~/.squad/ with default config and agents
|
|
7
|
-
* squad add <project-dir> Link a project (interactive)
|
|
8
|
-
* squad remove <project-dir> Unlink a project
|
|
9
|
-
* squad list List linked projects
|
|
10
|
-
* squad start Start the engine
|
|
11
|
-
* squad stop Stop the engine
|
|
12
|
-
* squad status Show engine status
|
|
13
|
-
* squad pause / resume Pause/resume dispatching
|
|
14
|
-
* squad dash Start the dashboard
|
|
15
|
-
* squad work <title> [opts-json] Add a work item
|
|
16
|
-
* squad spawn <agent> <prompt> Manually spawn an agent
|
|
17
|
-
* squad dispatch Force a dispatch cycle
|
|
18
|
-
* squad discover Dry-run work discovery
|
|
19
|
-
* squad cleanup Run cleanup manually
|
|
20
|
-
* squad plan <file|text> [proj] Run a plan
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
const fs = require('fs');
|
|
24
|
-
const path = require('path');
|
|
25
|
-
const { spawn, execSync } = require('child_process');
|
|
26
|
-
|
|
27
|
-
const SQUAD_HOME = path.join(require('os').homedir(), '.squad');
|
|
28
|
-
const PKG_ROOT = path.resolve(__dirname, '..');
|
|
29
|
-
|
|
30
|
-
const [cmd, ...rest] = process.argv.slice(2);
|
|
31
|
-
|
|
32
|
-
// ─── Init: bootstrap ~/.squad/ from package templates ───────────────────────
|
|
33
|
-
|
|
34
|
-
function init() {
|
|
35
|
-
if (fs.existsSync(path.join(SQUAD_HOME, 'engine.js'))) {
|
|
36
|
-
console.log(`\n Squad already installed at ${SQUAD_HOME}`);
|
|
37
|
-
console.log(' To reinitialize config: squad init --force\n');
|
|
38
|
-
if (!rest.includes('--force')) return;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
console.log(`\n Bootstrapping Squad to ${SQUAD_HOME}...\n`);
|
|
42
|
-
fs.mkdirSync(SQUAD_HOME, { recursive: true });
|
|
43
|
-
|
|
44
|
-
// Copy all package files to ~/.squad/
|
|
45
|
-
const exclude = new Set([
|
|
46
|
-
'bin', 'node_modules', '.git', '.claude', 'package.json',
|
|
47
|
-
'package-lock.json', 'LICENSE', '.npmignore', '.gitignore',
|
|
48
|
-
]);
|
|
49
|
-
|
|
50
|
-
copyDir(PKG_ROOT, SQUAD_HOME, exclude);
|
|
51
|
-
|
|
52
|
-
// Create config from template if it doesn't exist
|
|
53
|
-
const configPath = path.join(SQUAD_HOME, 'config.json');
|
|
54
|
-
if (!fs.existsSync(configPath)) {
|
|
55
|
-
const tmpl = path.join(SQUAD_HOME, 'config.template.json');
|
|
56
|
-
if (fs.existsSync(tmpl)) {
|
|
57
|
-
fs.copyFileSync(tmpl, configPath);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Ensure runtime directories exist
|
|
62
|
-
const dirs = [
|
|
63
|
-
'engine', 'notes/inbox', 'notes/archive',
|
|
64
|
-
'identity', 'plans',
|
|
65
|
-
];
|
|
66
|
-
for (const d of dirs) {
|
|
67
|
-
fs.mkdirSync(path.join(SQUAD_HOME, d), { recursive: true });
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Run squad.js init to populate config with defaults
|
|
71
|
-
execSync(`node "${path.join(SQUAD_HOME, 'squad.js')}" init`, { stdio: 'inherit' });
|
|
72
|
-
|
|
73
|
-
console.log('\n Next steps:');
|
|
74
|
-
console.log(' squad add ~/my-project Link your first project');
|
|
75
|
-
console.log(' squad start Start the engine');
|
|
76
|
-
console.log(' squad dash Open the dashboard\n');
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function copyDir(src, dest, exclude) {
|
|
80
|
-
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
81
|
-
for (const entry of entries) {
|
|
82
|
-
if (exclude.has(entry.name)) continue;
|
|
83
|
-
const srcPath = path.join(src, entry.name);
|
|
84
|
-
const destPath = path.join(dest, entry.name);
|
|
85
|
-
if (entry.isDirectory()) {
|
|
86
|
-
fs.mkdirSync(destPath, { recursive: true });
|
|
87
|
-
copyDir(srcPath, destPath, new Set()); // only exclude at top level
|
|
88
|
-
} else {
|
|
89
|
-
// Don't overwrite user-modified files (except on --force)
|
|
90
|
-
if (fs.existsSync(destPath) && !rest.includes('--force')) {
|
|
91
|
-
// Always update engine code files
|
|
92
|
-
if (!entry.name.endsWith('.js') && !entry.name.endsWith('.html')) continue;
|
|
93
|
-
}
|
|
94
|
-
fs.copyFileSync(srcPath, destPath);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// ─── Delegate: run commands against installed ~/.squad/ ─────────────────────
|
|
100
|
-
|
|
101
|
-
function ensureInstalled() {
|
|
102
|
-
if (!fs.existsSync(path.join(SQUAD_HOME, 'engine.js'))) {
|
|
103
|
-
console.log('\n Squad is not installed. Run: squad init\n');
|
|
104
|
-
process.exit(1);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function delegate(script, args) {
|
|
109
|
-
ensureInstalled();
|
|
110
|
-
const child = spawn(process.execPath, [path.join(SQUAD_HOME, script), ...args], {
|
|
111
|
-
stdio: 'inherit',
|
|
112
|
-
cwd: SQUAD_HOME,
|
|
113
|
-
});
|
|
114
|
-
child.on('exit', code => process.exit(code || 0));
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// ─── Command routing ────────────────────────────────────────────────────────
|
|
118
|
-
|
|
119
|
-
const engineCmds = new Set([
|
|
120
|
-
'start', 'stop', 'status', 'pause', 'resume',
|
|
121
|
-
'queue', 'sources', 'discover', 'dispatch',
|
|
122
|
-
'spawn', 'work', 'cleanup', 'mcp-sync', 'plan',
|
|
123
|
-
]);
|
|
124
|
-
|
|
125
|
-
if (!cmd || cmd === 'help' || cmd === '--help' || cmd === '-h') {
|
|
126
|
-
console.log(`
|
|
127
|
-
Squad — Central AI dev team manager
|
|
128
|
-
|
|
129
|
-
Setup:
|
|
130
|
-
squad init Bootstrap ~/.squad/ (first time)
|
|
131
|
-
squad add <project-dir> Link a project (interactive)
|
|
132
|
-
squad remove <project-dir> Unlink a project
|
|
133
|
-
squad list List linked projects
|
|
134
|
-
|
|
135
|
-
Engine:
|
|
136
|
-
squad start Start engine daemon
|
|
137
|
-
squad stop Stop the engine
|
|
138
|
-
squad status Show agents, projects, queue
|
|
139
|
-
squad pause / resume Pause/resume dispatching
|
|
140
|
-
squad dispatch Force a dispatch cycle
|
|
141
|
-
squad discover Dry-run work discovery
|
|
142
|
-
squad work <title> [opts] Add a work item
|
|
143
|
-
squad spawn <agent> <prompt> Manually spawn an agent
|
|
144
|
-
squad plan <file|text> [proj] Run a plan
|
|
145
|
-
squad cleanup Clean temp files, worktrees, zombies
|
|
146
|
-
|
|
147
|
-
Dashboard:
|
|
148
|
-
squad dash Start web dashboard (default :7331)
|
|
149
|
-
|
|
150
|
-
Home: ${SQUAD_HOME}
|
|
151
|
-
`);
|
|
152
|
-
} else if (cmd === 'init') {
|
|
153
|
-
init();
|
|
154
|
-
} else if (cmd === 'add' || cmd === 'remove' || cmd === 'list') {
|
|
155
|
-
delegate('squad.js', [cmd, ...rest]);
|
|
156
|
-
} else if (cmd === 'dash' || cmd === 'dashboard') {
|
|
157
|
-
delegate('dashboard.js', rest);
|
|
158
|
-
} else if (engineCmds.has(cmd)) {
|
|
159
|
-
delegate('engine.js', [cmd, ...rest]);
|
|
160
|
-
} else {
|
|
161
|
-
console.log(` Unknown command: ${cmd}`);
|
|
162
|
-
console.log(' Run "squad help" for usage.\n');
|
|
163
|
-
process.exit(1);
|
|
164
|
-
}
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Squad CLI — Central AI dev team manager
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* squad init Bootstrap ~/.squad/ with default config and agents
|
|
7
|
+
* squad add <project-dir> Link a project (interactive)
|
|
8
|
+
* squad remove <project-dir> Unlink a project
|
|
9
|
+
* squad list List linked projects
|
|
10
|
+
* squad start Start the engine
|
|
11
|
+
* squad stop Stop the engine
|
|
12
|
+
* squad status Show engine status
|
|
13
|
+
* squad pause / resume Pause/resume dispatching
|
|
14
|
+
* squad dash Start the dashboard
|
|
15
|
+
* squad work <title> [opts-json] Add a work item
|
|
16
|
+
* squad spawn <agent> <prompt> Manually spawn an agent
|
|
17
|
+
* squad dispatch Force a dispatch cycle
|
|
18
|
+
* squad discover Dry-run work discovery
|
|
19
|
+
* squad cleanup Run cleanup manually
|
|
20
|
+
* squad plan <file|text> [proj] Run a plan
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
const fs = require('fs');
|
|
24
|
+
const path = require('path');
|
|
25
|
+
const { spawn, execSync } = require('child_process');
|
|
26
|
+
|
|
27
|
+
const SQUAD_HOME = path.join(require('os').homedir(), '.squad');
|
|
28
|
+
const PKG_ROOT = path.resolve(__dirname, '..');
|
|
29
|
+
|
|
30
|
+
const [cmd, ...rest] = process.argv.slice(2);
|
|
31
|
+
|
|
32
|
+
// ─── Init: bootstrap ~/.squad/ from package templates ───────────────────────
|
|
33
|
+
|
|
34
|
+
function init() {
|
|
35
|
+
if (fs.existsSync(path.join(SQUAD_HOME, 'engine.js'))) {
|
|
36
|
+
console.log(`\n Squad already installed at ${SQUAD_HOME}`);
|
|
37
|
+
console.log(' To reinitialize config: squad init --force\n');
|
|
38
|
+
if (!rest.includes('--force')) return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
console.log(`\n Bootstrapping Squad to ${SQUAD_HOME}...\n`);
|
|
42
|
+
fs.mkdirSync(SQUAD_HOME, { recursive: true });
|
|
43
|
+
|
|
44
|
+
// Copy all package files to ~/.squad/
|
|
45
|
+
const exclude = new Set([
|
|
46
|
+
'bin', 'node_modules', '.git', '.claude', 'package.json',
|
|
47
|
+
'package-lock.json', 'LICENSE', '.npmignore', '.gitignore',
|
|
48
|
+
]);
|
|
49
|
+
|
|
50
|
+
copyDir(PKG_ROOT, SQUAD_HOME, exclude);
|
|
51
|
+
|
|
52
|
+
// Create config from template if it doesn't exist
|
|
53
|
+
const configPath = path.join(SQUAD_HOME, 'config.json');
|
|
54
|
+
if (!fs.existsSync(configPath)) {
|
|
55
|
+
const tmpl = path.join(SQUAD_HOME, 'config.template.json');
|
|
56
|
+
if (fs.existsSync(tmpl)) {
|
|
57
|
+
fs.copyFileSync(tmpl, configPath);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Ensure runtime directories exist
|
|
62
|
+
const dirs = [
|
|
63
|
+
'engine', 'notes/inbox', 'notes/archive',
|
|
64
|
+
'identity', 'plans',
|
|
65
|
+
];
|
|
66
|
+
for (const d of dirs) {
|
|
67
|
+
fs.mkdirSync(path.join(SQUAD_HOME, d), { recursive: true });
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Run squad.js init to populate config with defaults
|
|
71
|
+
execSync(`node "${path.join(SQUAD_HOME, 'squad.js')}" init`, { stdio: 'inherit' });
|
|
72
|
+
|
|
73
|
+
console.log('\n Next steps:');
|
|
74
|
+
console.log(' squad add ~/my-project Link your first project');
|
|
75
|
+
console.log(' squad start Start the engine');
|
|
76
|
+
console.log(' squad dash Open the dashboard\n');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function copyDir(src, dest, exclude) {
|
|
80
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
81
|
+
for (const entry of entries) {
|
|
82
|
+
if (exclude.has(entry.name)) continue;
|
|
83
|
+
const srcPath = path.join(src, entry.name);
|
|
84
|
+
const destPath = path.join(dest, entry.name);
|
|
85
|
+
if (entry.isDirectory()) {
|
|
86
|
+
fs.mkdirSync(destPath, { recursive: true });
|
|
87
|
+
copyDir(srcPath, destPath, new Set()); // only exclude at top level
|
|
88
|
+
} else {
|
|
89
|
+
// Don't overwrite user-modified files (except on --force)
|
|
90
|
+
if (fs.existsSync(destPath) && !rest.includes('--force')) {
|
|
91
|
+
// Always update engine code files
|
|
92
|
+
if (!entry.name.endsWith('.js') && !entry.name.endsWith('.html')) continue;
|
|
93
|
+
}
|
|
94
|
+
fs.copyFileSync(srcPath, destPath);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ─── Delegate: run commands against installed ~/.squad/ ─────────────────────
|
|
100
|
+
|
|
101
|
+
function ensureInstalled() {
|
|
102
|
+
if (!fs.existsSync(path.join(SQUAD_HOME, 'engine.js'))) {
|
|
103
|
+
console.log('\n Squad is not installed. Run: squad init\n');
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function delegate(script, args) {
|
|
109
|
+
ensureInstalled();
|
|
110
|
+
const child = spawn(process.execPath, [path.join(SQUAD_HOME, script), ...args], {
|
|
111
|
+
stdio: 'inherit',
|
|
112
|
+
cwd: SQUAD_HOME,
|
|
113
|
+
});
|
|
114
|
+
child.on('exit', code => process.exit(code || 0));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// ─── Command routing ────────────────────────────────────────────────────────
|
|
118
|
+
|
|
119
|
+
const engineCmds = new Set([
|
|
120
|
+
'start', 'stop', 'status', 'pause', 'resume',
|
|
121
|
+
'queue', 'sources', 'discover', 'dispatch',
|
|
122
|
+
'spawn', 'work', 'cleanup', 'mcp-sync', 'plan',
|
|
123
|
+
]);
|
|
124
|
+
|
|
125
|
+
if (!cmd || cmd === 'help' || cmd === '--help' || cmd === '-h') {
|
|
126
|
+
console.log(`
|
|
127
|
+
Squad — Central AI dev team manager
|
|
128
|
+
|
|
129
|
+
Setup:
|
|
130
|
+
squad init Bootstrap ~/.squad/ (first time)
|
|
131
|
+
squad add <project-dir> Link a project (interactive)
|
|
132
|
+
squad remove <project-dir> Unlink a project
|
|
133
|
+
squad list List linked projects
|
|
134
|
+
|
|
135
|
+
Engine:
|
|
136
|
+
squad start Start engine daemon
|
|
137
|
+
squad stop Stop the engine
|
|
138
|
+
squad status Show agents, projects, queue
|
|
139
|
+
squad pause / resume Pause/resume dispatching
|
|
140
|
+
squad dispatch Force a dispatch cycle
|
|
141
|
+
squad discover Dry-run work discovery
|
|
142
|
+
squad work <title> [opts] Add a work item
|
|
143
|
+
squad spawn <agent> <prompt> Manually spawn an agent
|
|
144
|
+
squad plan <file|text> [proj] Run a plan
|
|
145
|
+
squad cleanup Clean temp files, worktrees, zombies
|
|
146
|
+
|
|
147
|
+
Dashboard:
|
|
148
|
+
squad dash Start web dashboard (default :7331)
|
|
149
|
+
|
|
150
|
+
Home: ${SQUAD_HOME}
|
|
151
|
+
`);
|
|
152
|
+
} else if (cmd === 'init') {
|
|
153
|
+
init();
|
|
154
|
+
} else if (cmd === 'add' || cmd === 'remove' || cmd === 'list') {
|
|
155
|
+
delegate('squad.js', [cmd, ...rest]);
|
|
156
|
+
} else if (cmd === 'dash' || cmd === 'dashboard') {
|
|
157
|
+
delegate('dashboard.js', rest);
|
|
158
|
+
} else if (engineCmds.has(cmd)) {
|
|
159
|
+
delegate('engine.js', [cmd, ...rest]);
|
|
160
|
+
} else {
|
|
161
|
+
console.log(` Unknown command: ${cmd}`);
|
|
162
|
+
console.log(' Run "squad help" for usage.\n');
|
|
163
|
+
process.exit(1);
|
|
164
|
+
}
|