@bradygaster/squad-cli 0.8.17-preview → 0.8.18
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/dist/cli/commands/consult.d.ts +16 -0
- package/dist/cli/commands/consult.d.ts.map +1 -0
- package/dist/cli/commands/consult.js +91 -0
- package/dist/cli/commands/consult.js.map +1 -0
- package/dist/cli/commands/extract.d.ts +16 -0
- package/dist/cli/commands/extract.d.ts.map +1 -0
- package/dist/cli/commands/extract.js +267 -0
- package/dist/cli/commands/extract.js.map +1 -0
- package/dist/cli/commands/rc.d.ts.map +1 -1
- package/dist/cli/commands/rc.js +2 -1
- package/dist/cli/commands/rc.js.map +1 -1
- package/dist/cli/commands/start.d.ts.map +1 -1
- package/dist/cli/commands/start.js +4 -1
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/cli/core/init.d.ts +9 -4
- package/dist/cli/core/init.d.ts.map +1 -1
- package/dist/cli/core/init.js +51 -297
- package/dist/cli/core/init.js.map +1 -1
- package/dist/cli/core/upgrade.d.ts +1 -0
- package/dist/cli/core/upgrade.d.ts.map +1 -1
- package/dist/cli/core/upgrade.js.map +1 -1
- package/dist/cli/shell/index.d.ts.map +1 -1
- package/dist/cli/shell/index.js +23 -1
- package/dist/cli/shell/index.js.map +1 -1
- package/dist/cli-entry.d.ts +7 -0
- package/dist/cli-entry.d.ts.map +1 -1
- package/dist/cli-entry.js +105 -729
- package/dist/cli-entry.js.map +1 -1
- package/package.json +156 -156
- package/templates/workflows/squad-heartbeat.yml +4 -3
package/dist/cli-entry.js
CHANGED
|
@@ -1,14 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
process.env.NODE_NO_WARNINGS = '1';
|
|
3
|
-
// Suppress Node.js experimental feature warnings (e.g., SQLite) from end users
|
|
4
|
-
const originalEmitWarning = process.emitWarning;
|
|
5
|
-
process.emitWarning = (warning, ...args) => {
|
|
6
|
-
if (typeof warning === 'string' && warning.includes('ExperimentalWarning'))
|
|
7
|
-
return;
|
|
8
|
-
if (warning?.name === 'ExperimentalWarning')
|
|
9
|
-
return;
|
|
10
|
-
return originalEmitWarning.call(process, warning, ...args);
|
|
11
|
-
};
|
|
12
2
|
/**
|
|
13
3
|
* Squad CLI — entry point for command-line invocation.
|
|
14
4
|
* Separated from src/index.ts so library consumers can import
|
|
@@ -16,25 +6,6 @@ process.emitWarning = (warning, ...args) => {
|
|
|
16
6
|
*
|
|
17
7
|
* SDK library exports live in src/index.ts (dist/index.js).
|
|
18
8
|
*/
|
|
19
|
-
// Load .env file if present (dev mode)
|
|
20
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
21
|
-
import { resolve } from 'node:path';
|
|
22
|
-
import { fileURLToPath } from 'node:url';
|
|
23
|
-
const envPath = resolve(process.cwd(), '.env');
|
|
24
|
-
if (existsSync(envPath)) {
|
|
25
|
-
for (const line of readFileSync(envPath, 'utf8').split('\n')) {
|
|
26
|
-
const trimmed = line.trim();
|
|
27
|
-
if (!trimmed || trimmed.startsWith('#'))
|
|
28
|
-
continue;
|
|
29
|
-
const eq = trimmed.indexOf('=');
|
|
30
|
-
if (eq > 0) {
|
|
31
|
-
const key = trimmed.slice(0, eq).trim();
|
|
32
|
-
const val = trimmed.slice(eq + 1).trim();
|
|
33
|
-
if (!process.env[key])
|
|
34
|
-
process.env[key] = val;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
9
|
import fs from 'node:fs';
|
|
39
10
|
import path from 'node:path';
|
|
40
11
|
import { fatal, SquadError } from './cli/core/errors.js';
|
|
@@ -42,676 +13,83 @@ import { BOLD, RESET, DIM, RED } from './cli/core/output.js';
|
|
|
42
13
|
import { runInit } from './cli/core/init.js';
|
|
43
14
|
import { resolveSquad, resolveGlobalSquadPath } from '@bradygaster/squad-sdk';
|
|
44
15
|
import { runShell } from './cli/shell/index.js';
|
|
45
|
-
import { loadWelcomeData } from './cli/shell/lifecycle.js';
|
|
46
16
|
// Keep VERSION in index.ts (public API); import it here via re-export
|
|
47
17
|
import { VERSION } from '@bradygaster/squad-sdk';
|
|
48
|
-
/** Debug logger — writes to stderr only when SQUAD_DEBUG=1. */
|
|
49
|
-
function debugLog(...args) {
|
|
50
|
-
if (process.env['SQUAD_DEBUG'] === '1') {
|
|
51
|
-
console.error('[SQUAD_DEBUG]', ...args);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
/** Check if --help or -h appears in args after the subcommand. */
|
|
55
|
-
function hasHelpFlag(args) {
|
|
56
|
-
return args.slice(1).includes('--help') || args.slice(1).includes('-h');
|
|
57
|
-
}
|
|
58
|
-
/** Commands that skip the auto-link check (non-interactive or utility). */
|
|
59
|
-
const SKIP_AUTO_LINK_CMDS = new Set([
|
|
60
|
-
'--version', '-v', 'version',
|
|
61
|
-
'--help', '-h', 'help',
|
|
62
|
-
'export', 'import', 'doctor', 'heartbeat',
|
|
63
|
-
'scrub-emails', '--preview', '--dry-run',
|
|
64
|
-
]);
|
|
65
|
-
/**
|
|
66
|
-
* Dev convenience: when running from source (-preview), check if the CLI
|
|
67
|
-
* is globally linked and offer to link it if not.
|
|
68
|
-
*/
|
|
69
|
-
async function checkAutoLink(cmd, args) {
|
|
70
|
-
try {
|
|
71
|
-
if (!VERSION.includes('-preview'))
|
|
72
|
-
return;
|
|
73
|
-
if (cmd && SKIP_AUTO_LINK_CMDS.has(cmd))
|
|
74
|
-
return;
|
|
75
|
-
if (args.includes('--preview') || args.includes('--dry-run'))
|
|
76
|
-
return;
|
|
77
|
-
if (args.includes('--help') || args.includes('-h'))
|
|
78
|
-
return;
|
|
79
|
-
if (!process.stdin.isTTY)
|
|
80
|
-
return;
|
|
81
|
-
const { homedir } = await import('node:os');
|
|
82
|
-
const home = homedir();
|
|
83
|
-
const squadDir = path.join(home, '.squad');
|
|
84
|
-
const markerPath = path.join(squadDir, '.no-auto-link');
|
|
85
|
-
if (fs.existsSync(markerPath))
|
|
86
|
-
return;
|
|
87
|
-
// Locate this package and the monorepo root
|
|
88
|
-
const thisFile = fileURLToPath(import.meta.url);
|
|
89
|
-
const packageDir = path.resolve(path.dirname(thisFile), '..');
|
|
90
|
-
const repoRoot = path.resolve(packageDir, '..', '..');
|
|
91
|
-
// Check if already globally linked
|
|
92
|
-
const { execSync } = await import('node:child_process');
|
|
93
|
-
let alreadyLinked = false;
|
|
94
|
-
let output = '';
|
|
95
|
-
try {
|
|
96
|
-
output = execSync('npm ls -g @bradygaster/squad-cli --json', {
|
|
97
|
-
encoding: 'utf8',
|
|
98
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
catch (e) {
|
|
102
|
-
const err = e;
|
|
103
|
-
output = err.stdout ?? '';
|
|
104
|
-
}
|
|
105
|
-
if (output) {
|
|
106
|
-
try {
|
|
107
|
-
const parsed = JSON.parse(output);
|
|
108
|
-
const dep = parsed?.dependencies?.['@bradygaster/squad-cli'];
|
|
109
|
-
if (dep?.link === true) {
|
|
110
|
-
alreadyLinked = true;
|
|
111
|
-
}
|
|
112
|
-
else if (typeof dep?.resolved === 'string' && dep.resolved.startsWith('file:')) {
|
|
113
|
-
try {
|
|
114
|
-
const resolvedPath = fileURLToPath(new URL(dep.resolved));
|
|
115
|
-
alreadyLinked = path.resolve(resolvedPath) === path.resolve(packageDir);
|
|
116
|
-
}
|
|
117
|
-
catch {
|
|
118
|
-
// URL parsing failed — skip
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
catch {
|
|
123
|
-
// JSON parse failed
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
if (alreadyLinked)
|
|
127
|
-
return;
|
|
128
|
-
// Prompt the user
|
|
129
|
-
console.log(`\n📦 You're running Squad from source (${VERSION}).`);
|
|
130
|
-
console.log(` Run 'npm link -w packages/squad-cli' to make 'squad' use your local build?`);
|
|
131
|
-
const { createInterface } = await import('node:readline');
|
|
132
|
-
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
133
|
-
const answer = await new Promise((resolve) => {
|
|
134
|
-
rl.question('\n[Y/n] ', (ans) => {
|
|
135
|
-
rl.close();
|
|
136
|
-
resolve(ans.trim().toLowerCase());
|
|
137
|
-
});
|
|
138
|
-
});
|
|
139
|
-
if (answer === '' || answer === 'y' || answer === 'yes') {
|
|
140
|
-
console.log('Linking...');
|
|
141
|
-
try {
|
|
142
|
-
execSync('npm link -w packages/squad-cli', {
|
|
143
|
-
cwd: repoRoot,
|
|
144
|
-
encoding: 'utf8',
|
|
145
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
146
|
-
});
|
|
147
|
-
console.log('✓ Linked successfully. The "squad" command now uses your local build.\n');
|
|
148
|
-
}
|
|
149
|
-
catch (linkErr) {
|
|
150
|
-
debugLog('npm link failed:', linkErr);
|
|
151
|
-
console.log('Link failed — you can run it manually: npm link -w packages/squad-cli\n');
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
else {
|
|
155
|
-
if (!fs.existsSync(squadDir)) {
|
|
156
|
-
fs.mkdirSync(squadDir, { recursive: true });
|
|
157
|
-
}
|
|
158
|
-
fs.writeFileSync(markerPath, '# Created by squad CLI. Delete this file to be prompted again.\n');
|
|
159
|
-
console.log("Got it — won't ask again. Run 'npm link -w packages/squad-cli' manually anytime.\n");
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
catch (err) {
|
|
163
|
-
debugLog('Auto-link check failed, skipping:', err);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
/** Per-command help text. Returns undefined for unknown commands. */
|
|
167
|
-
function getCommandHelp(cmd) {
|
|
168
|
-
const help = {
|
|
169
|
-
init: `
|
|
170
|
-
${BOLD}squad init${RESET} — Initialize Squad
|
|
171
|
-
|
|
172
|
-
${BOLD}USAGE${RESET}
|
|
173
|
-
squad init [prompt] [--file <path>] [--global] [--mode remote <path>]
|
|
174
|
-
|
|
175
|
-
${BOLD}DESCRIPTION${RESET}
|
|
176
|
-
Creates the .squad/ directory structure in your project or personal directory.
|
|
177
|
-
Detects your project type and scaffolds appropriate workflows and templates.
|
|
178
|
-
If a prompt is provided, stores it so the REPL can auto-cast your team.
|
|
179
|
-
|
|
180
|
-
${BOLD}OPTIONS${RESET}
|
|
181
|
-
prompt A project description (quoted string) for team casting
|
|
182
|
-
--file <path> Read the project description from a file
|
|
183
|
-
--global Create personal squad at ~/.squad/
|
|
184
|
-
--mode remote <path> Link to a remote team root (dual-root mode)
|
|
185
|
-
|
|
186
|
-
${BOLD}EXAMPLES${RESET}
|
|
187
|
-
${DIM}# Initialize and describe your project for auto-casting${RESET}
|
|
188
|
-
squad init "Build a snake game in HTML and JavaScript"
|
|
189
|
-
|
|
190
|
-
${DIM}# Initialize with a spec file${RESET}
|
|
191
|
-
squad init --file ./PROJECT.md
|
|
192
|
-
|
|
193
|
-
${DIM}# Initialize without a prompt (cast later interactively)${RESET}
|
|
194
|
-
squad init
|
|
195
|
-
|
|
196
|
-
${DIM}# Create personal squad${RESET}
|
|
197
|
-
squad init --global
|
|
198
|
-
|
|
199
|
-
${DIM}# Link to shared team in parent directory${RESET}
|
|
200
|
-
squad init --mode remote ../team-repo
|
|
201
|
-
`,
|
|
202
|
-
upgrade: `
|
|
203
|
-
${BOLD}squad upgrade${RESET} — Update Squad Files
|
|
204
|
-
|
|
205
|
-
${BOLD}USAGE${RESET}
|
|
206
|
-
squad upgrade [--global] [--migrate-directory]
|
|
207
|
-
|
|
208
|
-
${BOLD}DESCRIPTION${RESET}
|
|
209
|
-
Updates Squad-owned files to the latest version. Your team state
|
|
210
|
-
(team.md, decisions.md, agent history) is never modified.
|
|
211
|
-
|
|
212
|
-
${BOLD}OPTIONS${RESET}
|
|
213
|
-
--global Upgrade personal squad at ~/.squad/
|
|
214
|
-
--migrate-directory Rename .ai-team/ to .squad/ (legacy migration)
|
|
215
|
-
|
|
216
|
-
${BOLD}EXAMPLES${RESET}
|
|
217
|
-
${DIM}# Upgrade current repo's Squad files${RESET}
|
|
218
|
-
squad upgrade
|
|
219
|
-
|
|
220
|
-
${DIM}# Upgrade personal squad${RESET}
|
|
221
|
-
squad upgrade --global
|
|
222
|
-
|
|
223
|
-
${DIM}# Migrate from legacy .ai-team/ directory${RESET}
|
|
224
|
-
squad upgrade --migrate-directory
|
|
225
|
-
`,
|
|
226
|
-
status: `
|
|
227
|
-
${BOLD}squad status${RESET} — Show Active Squad
|
|
228
|
-
|
|
229
|
-
${BOLD}USAGE${RESET}
|
|
230
|
-
squad status
|
|
231
|
-
|
|
232
|
-
${BOLD}DESCRIPTION${RESET}
|
|
233
|
-
Displays which squad is currently active and where it's located.
|
|
234
|
-
Shows repo squad, personal squad path, and resolution order.
|
|
235
|
-
|
|
236
|
-
${BOLD}EXAMPLES${RESET}
|
|
237
|
-
${DIM}# Check active squad${RESET}
|
|
238
|
-
squad status
|
|
239
|
-
`,
|
|
240
|
-
triage: `
|
|
241
|
-
${BOLD}squad triage${RESET} — Auto-Triage Issues
|
|
242
|
-
|
|
243
|
-
${BOLD}USAGE${RESET}
|
|
244
|
-
squad triage [--interval <minutes>]
|
|
245
|
-
squad watch [--interval <minutes>] ${DIM}(alias)${RESET}
|
|
246
|
-
|
|
247
|
-
${BOLD}DESCRIPTION${RESET}
|
|
248
|
-
Ralph's work monitor. Continuously polls GitHub issues and automatically
|
|
249
|
-
assigns them to the right team member based on content and expertise.
|
|
250
|
-
|
|
251
|
-
${BOLD}OPTIONS${RESET}
|
|
252
|
-
--interval <minutes> Polling frequency (default: 10)
|
|
253
|
-
|
|
254
|
-
${BOLD}EXAMPLES${RESET}
|
|
255
|
-
${DIM}# Start triage with default 10-minute interval${RESET}
|
|
256
|
-
squad triage
|
|
257
|
-
|
|
258
|
-
${DIM}# Poll every 5 minutes${RESET}
|
|
259
|
-
squad triage --interval 5
|
|
260
|
-
`,
|
|
261
|
-
copilot: `
|
|
262
|
-
${BOLD}squad copilot${RESET} — Manage Copilot Coding Agent
|
|
263
|
-
|
|
264
|
-
${BOLD}USAGE${RESET}
|
|
265
|
-
squad copilot [--off] [--auto-assign]
|
|
266
|
-
|
|
267
|
-
${BOLD}DESCRIPTION${RESET}
|
|
268
|
-
Add or remove the GitHub Copilot coding agent (@copilot) from your team.
|
|
269
|
-
When enabled, @copilot can pick up issues labeled 'squad:copilot'.
|
|
270
|
-
|
|
271
|
-
${BOLD}OPTIONS${RESET}
|
|
272
|
-
--off Remove @copilot from the team
|
|
273
|
-
--auto-assign Enable automatic issue assignment for @copilot
|
|
274
|
-
|
|
275
|
-
${BOLD}EXAMPLES${RESET}
|
|
276
|
-
${DIM}# Add @copilot to the team${RESET}
|
|
277
|
-
squad copilot
|
|
278
|
-
|
|
279
|
-
${DIM}# Add @copilot with auto-assignment enabled${RESET}
|
|
280
|
-
squad copilot --auto-assign
|
|
281
|
-
|
|
282
|
-
${DIM}# Remove @copilot from the team${RESET}
|
|
283
|
-
squad copilot --off
|
|
284
|
-
`,
|
|
285
|
-
plugin: `
|
|
286
|
-
${BOLD}squad plugin${RESET} — Manage Plugin Marketplaces
|
|
287
|
-
|
|
288
|
-
${BOLD}USAGE${RESET}
|
|
289
|
-
squad plugin marketplace add <owner/repo>
|
|
290
|
-
squad plugin marketplace remove <name>
|
|
291
|
-
squad plugin marketplace list
|
|
292
|
-
squad plugin marketplace browse <name>
|
|
293
|
-
|
|
294
|
-
${BOLD}DESCRIPTION${RESET}
|
|
295
|
-
Manage plugin marketplaces — registries of Squad extensions, skills,
|
|
296
|
-
and agent templates.
|
|
297
|
-
|
|
298
|
-
${BOLD}EXAMPLES${RESET}
|
|
299
|
-
${DIM}# Add official Squad plugins marketplace${RESET}
|
|
300
|
-
squad plugin marketplace add bradygaster/squad-plugins
|
|
301
|
-
|
|
302
|
-
${DIM}# List all registered marketplaces${RESET}
|
|
303
|
-
squad plugin marketplace list
|
|
304
|
-
`,
|
|
305
|
-
export: `
|
|
306
|
-
${BOLD}squad export${RESET} — Export Squad to JSON
|
|
307
|
-
|
|
308
|
-
${BOLD}USAGE${RESET}
|
|
309
|
-
squad export [--out <path>]
|
|
310
|
-
|
|
311
|
-
${BOLD}DESCRIPTION${RESET}
|
|
312
|
-
Creates a portable JSON snapshot of your entire squad — casting state,
|
|
313
|
-
agent charters, accumulated history, and skills.
|
|
314
|
-
|
|
315
|
-
${BOLD}OPTIONS${RESET}
|
|
316
|
-
--out <path> Custom output path (default: squad-export.json)
|
|
317
|
-
|
|
318
|
-
${BOLD}EXAMPLES${RESET}
|
|
319
|
-
${DIM}# Export to default file${RESET}
|
|
320
|
-
squad export
|
|
321
|
-
|
|
322
|
-
${DIM}# Export to custom location${RESET}
|
|
323
|
-
squad export --out ./backups/team-backup.json
|
|
324
|
-
`,
|
|
325
|
-
import: `
|
|
326
|
-
${BOLD}squad import${RESET} — Import Squad from JSON
|
|
327
|
-
|
|
328
|
-
${BOLD}USAGE${RESET}
|
|
329
|
-
squad import <file> [--force]
|
|
330
|
-
|
|
331
|
-
${BOLD}DESCRIPTION${RESET}
|
|
332
|
-
Restores a squad from a JSON export file. Creates .squad/ directory
|
|
333
|
-
and populates it with casting state, agents, skills, and history.
|
|
334
|
-
|
|
335
|
-
${BOLD}OPTIONS${RESET}
|
|
336
|
-
--force Overwrite existing squad (archives old .squad/ first)
|
|
337
|
-
|
|
338
|
-
${BOLD}EXAMPLES${RESET}
|
|
339
|
-
${DIM}# Import into current directory${RESET}
|
|
340
|
-
squad import squad-export.json
|
|
341
|
-
|
|
342
|
-
${DIM}# Import and overwrite existing squad${RESET}
|
|
343
|
-
squad import squad-export.json --force
|
|
344
|
-
`,
|
|
345
|
-
'scrub-emails': `
|
|
346
|
-
${BOLD}squad scrub-emails${RESET} — Remove Email Addresses
|
|
347
|
-
|
|
348
|
-
${BOLD}USAGE${RESET}
|
|
349
|
-
squad scrub-emails [directory]
|
|
350
|
-
|
|
351
|
-
${BOLD}DESCRIPTION${RESET}
|
|
352
|
-
Removes email addresses (PII) from Squad state files. Useful before
|
|
353
|
-
committing to public repos or sharing exports.
|
|
354
|
-
|
|
355
|
-
${BOLD}OPTIONS${RESET}
|
|
356
|
-
[directory] Target directory (default: .squad)
|
|
357
|
-
|
|
358
|
-
${BOLD}EXAMPLES${RESET}
|
|
359
|
-
${DIM}# Scrub current squad${RESET}
|
|
360
|
-
squad scrub-emails .squad
|
|
361
|
-
|
|
362
|
-
${DIM}# Scrub legacy .ai-team directory${RESET}
|
|
363
|
-
squad scrub-emails
|
|
364
|
-
`,
|
|
365
|
-
doctor: `
|
|
366
|
-
${BOLD}squad doctor${RESET} — Validate Squad Setup
|
|
367
|
-
|
|
368
|
-
${BOLD}USAGE${RESET}
|
|
369
|
-
squad doctor
|
|
370
|
-
|
|
371
|
-
${BOLD}DESCRIPTION${RESET}
|
|
372
|
-
Runs a 9-check diagnostic on your squad setup. Reports health of
|
|
373
|
-
expected files, conventions, and directory structure.
|
|
374
|
-
|
|
375
|
-
${BOLD}EXAMPLES${RESET}
|
|
376
|
-
${DIM}# Check current squad setup${RESET}
|
|
377
|
-
squad doctor
|
|
378
|
-
`,
|
|
379
|
-
link: `
|
|
380
|
-
${BOLD}squad link${RESET} — Link to Remote Team
|
|
381
|
-
|
|
382
|
-
${BOLD}USAGE${RESET}
|
|
383
|
-
squad link <team-repo-path>
|
|
384
|
-
|
|
385
|
-
${BOLD}DESCRIPTION${RESET}
|
|
386
|
-
Links the current project to a remote team root. Enables dual-root mode
|
|
387
|
-
where project-specific state lives in .squad/ and team identity lives
|
|
388
|
-
in a shared location.
|
|
389
|
-
|
|
390
|
-
${BOLD}EXAMPLES${RESET}
|
|
391
|
-
${DIM}# Link to parent directory's team${RESET}
|
|
392
|
-
squad link ../team-repo
|
|
393
|
-
|
|
394
|
-
${DIM}# Link to absolute path${RESET}
|
|
395
|
-
squad link /Users/org/shared-squad
|
|
396
|
-
`,
|
|
397
|
-
aspire: `
|
|
398
|
-
${BOLD}squad aspire${RESET} — Launch Aspire Dashboard
|
|
399
|
-
|
|
400
|
-
${BOLD}USAGE${RESET}
|
|
401
|
-
squad aspire [--docker] [--port <number>]
|
|
402
|
-
|
|
403
|
-
${BOLD}DESCRIPTION${RESET}
|
|
404
|
-
Launches the .NET Aspire dashboard for observability. Squad exports
|
|
405
|
-
OpenTelemetry traces and metrics to the dashboard for real-time visibility.
|
|
406
|
-
|
|
407
|
-
${BOLD}OPTIONS${RESET}
|
|
408
|
-
--docker Force Docker mode
|
|
409
|
-
--port <number> OTLP port (default: 4317)
|
|
410
|
-
|
|
411
|
-
${BOLD}EXAMPLES${RESET}
|
|
412
|
-
${DIM}# Launch Aspire dashboard (auto-detect runtime)${RESET}
|
|
413
|
-
squad aspire
|
|
414
|
-
|
|
415
|
-
${DIM}# Force Docker mode${RESET}
|
|
416
|
-
squad aspire --docker
|
|
417
|
-
`,
|
|
418
|
-
upstream: `
|
|
419
|
-
${BOLD}squad upstream${RESET} — Manage Upstream Squad Sources
|
|
420
|
-
|
|
421
|
-
${BOLD}USAGE${RESET}
|
|
422
|
-
squad upstream add <source> [--name <name>] [--ref <branch>]
|
|
423
|
-
squad upstream remove <name>
|
|
424
|
-
squad upstream list
|
|
425
|
-
squad upstream sync [name]
|
|
426
|
-
|
|
427
|
-
${BOLD}DESCRIPTION${RESET}
|
|
428
|
-
Manage upstream Squad sources — external configurations from local
|
|
429
|
-
directories, git repositories, or export files that can be synced
|
|
430
|
-
into your squad.
|
|
431
|
-
|
|
432
|
-
${BOLD}OPTIONS${RESET}
|
|
433
|
-
add <source> Add an upstream (path, git URL, or .json export)
|
|
434
|
-
--name <name> Custom name (auto-derived if omitted)
|
|
435
|
-
--ref <branch> Git branch/tag (default: main)
|
|
436
|
-
remove <name> Remove an upstream by name
|
|
437
|
-
list Show all configured upstreams
|
|
438
|
-
sync [name] Sync all or a specific upstream
|
|
439
|
-
|
|
440
|
-
${BOLD}EXAMPLES${RESET}
|
|
441
|
-
${DIM}# Add a git upstream${RESET}
|
|
442
|
-
squad upstream add https://github.com/org/squad-config.git
|
|
443
|
-
|
|
444
|
-
${DIM}# Add a local upstream with custom name${RESET}
|
|
445
|
-
squad upstream add ../shared-squad --name shared
|
|
446
|
-
|
|
447
|
-
${DIM}# Sync all upstreams${RESET}
|
|
448
|
-
squad upstream sync
|
|
449
|
-
`,
|
|
450
|
-
nap: `
|
|
451
|
-
${BOLD}squad nap${RESET} — Context Hygiene
|
|
452
|
-
|
|
453
|
-
${BOLD}USAGE${RESET}
|
|
454
|
-
squad nap [--deep] [--dry-run]
|
|
455
|
-
|
|
456
|
-
${BOLD}DESCRIPTION${RESET}
|
|
457
|
-
Compresses agent histories, prunes old logs, archives stale decisions,
|
|
458
|
-
and cleans up orphaned inbox files. Shows before/after stats with
|
|
459
|
-
estimated token savings.
|
|
460
|
-
|
|
461
|
-
${BOLD}OPTIONS${RESET}
|
|
462
|
-
--deep Aggressive mode — tighter history compression
|
|
463
|
-
--dry-run Show what would change without modifying files
|
|
464
|
-
|
|
465
|
-
${BOLD}EXAMPLES${RESET}
|
|
466
|
-
${DIM}# Run a standard nap${RESET}
|
|
467
|
-
squad nap
|
|
468
|
-
|
|
469
|
-
${DIM}# Preview changes without modifying files${RESET}
|
|
470
|
-
squad nap --dry-run
|
|
471
|
-
|
|
472
|
-
${DIM}# Deep clean for maximum compression${RESET}
|
|
473
|
-
squad nap --deep
|
|
474
|
-
`,
|
|
475
|
-
shell: `
|
|
476
|
-
${BOLD}squad shell${RESET} — Launch Interactive Shell
|
|
477
|
-
|
|
478
|
-
${BOLD}USAGE${RESET}
|
|
479
|
-
squad shell [--preview] [--timeout <seconds>]
|
|
480
|
-
|
|
481
|
-
${BOLD}DESCRIPTION${RESET}
|
|
482
|
-
Starts the interactive Squad REPL. Messages are routed to the
|
|
483
|
-
right agent automatically based on content and team expertise.
|
|
484
|
-
|
|
485
|
-
${BOLD}OPTIONS${RESET}
|
|
486
|
-
--preview Show team summary without launching shell
|
|
487
|
-
--timeout <seconds> Set REPL inactivity timeout (default: 600)
|
|
488
|
-
|
|
489
|
-
${BOLD}EXAMPLES${RESET}
|
|
490
|
-
${DIM}# Start interactive shell${RESET}
|
|
491
|
-
squad shell
|
|
492
|
-
|
|
493
|
-
${DIM}# Preview team before launching${RESET}
|
|
494
|
-
squad shell --preview
|
|
495
|
-
`,
|
|
496
|
-
};
|
|
497
|
-
// Handle aliases
|
|
498
|
-
const aliases = {
|
|
499
|
-
watch: 'triage',
|
|
500
|
-
loop: 'triage',
|
|
501
|
-
hire: 'init',
|
|
502
|
-
heartbeat: 'doctor',
|
|
503
|
-
};
|
|
504
|
-
const key = aliases[cmd] ?? cmd;
|
|
505
|
-
return help[key];
|
|
506
|
-
}
|
|
507
18
|
async function main() {
|
|
508
19
|
const args = process.argv.slice(2);
|
|
509
20
|
const hasGlobal = args.includes('--global');
|
|
510
|
-
const
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
if (timeoutIdx >= 0 && args[timeoutIdx + 1]) {
|
|
515
|
-
process.env['SQUAD_REPL_TIMEOUT'] = args[timeoutIdx + 1];
|
|
516
|
-
}
|
|
517
|
-
// Dev convenience: offer to npm-link when running from source
|
|
518
|
-
await checkAutoLink(cmd, args);
|
|
519
|
-
// Empty or whitespace-only args should show help, not launch shell
|
|
520
|
-
if (rawCmd !== undefined && !cmd) {
|
|
521
|
-
console.log(`\n${BOLD}squad${RESET} v${VERSION}`);
|
|
522
|
-
console.log(`Your AI agent team\n`);
|
|
523
|
-
console.log(`Usage: squad [command] [options]`);
|
|
524
|
-
console.log(`\nRun 'squad help' for full command list.\n`);
|
|
525
|
-
return;
|
|
526
|
-
}
|
|
527
|
-
// --version / -v / version — canonical format: bare semver
|
|
528
|
-
if (cmd === '--version' || cmd === '-v' || cmd === 'version') {
|
|
529
|
-
console.log(VERSION);
|
|
21
|
+
const cmd = args[0];
|
|
22
|
+
// --version / -v
|
|
23
|
+
if (cmd === '--version' || cmd === '-v') {
|
|
24
|
+
console.log(`squad ${VERSION}`);
|
|
530
25
|
return;
|
|
531
26
|
}
|
|
532
27
|
// --help / -h / help
|
|
533
28
|
if (cmd === '--help' || cmd === '-h' || cmd === 'help') {
|
|
534
|
-
console.log(`\n${BOLD}squad${RESET} v${VERSION}`);
|
|
535
|
-
console.log(`Your AI agent team\n`);
|
|
536
|
-
console.log(`${BOLD}Just type — squad routes your message to the right agent automatically${RESET}`);
|
|
537
|
-
console.log(` squad Start interactive shell`);
|
|
538
|
-
console.log(` squad --global Use your personal squad\n`);
|
|
29
|
+
console.log(`\n${BOLD}squad${RESET} v${VERSION} — Add an AI agent team to any project\n`);
|
|
539
30
|
console.log(`Usage: squad [command] [options]\n`);
|
|
540
|
-
console.log(
|
|
541
|
-
console.log(` ${BOLD}
|
|
542
|
-
console.log(`
|
|
543
|
-
console.log(`
|
|
544
|
-
console.log(`
|
|
545
|
-
console.log(`
|
|
546
|
-
console.log(`
|
|
547
|
-
console.log(`
|
|
548
|
-
console.log(`
|
|
549
|
-
console.log(
|
|
550
|
-
console.log(` ${BOLD}
|
|
551
|
-
console.log(
|
|
552
|
-
console.log(`
|
|
553
|
-
console.log(`
|
|
554
|
-
console.log(`
|
|
555
|
-
console.log(`
|
|
556
|
-
console.log(`
|
|
557
|
-
console.log(`
|
|
558
|
-
console.log(`
|
|
559
|
-
console.log(`
|
|
560
|
-
console.log(`
|
|
561
|
-
console.log(
|
|
562
|
-
console.log(` ${BOLD}
|
|
563
|
-
console.log(`
|
|
564
|
-
console.log(`
|
|
565
|
-
console.log(`
|
|
566
|
-
console.log(`
|
|
567
|
-
console.log(`
|
|
568
|
-
console.log(`
|
|
569
|
-
console.log(`
|
|
570
|
-
console.log(`
|
|
571
|
-
console.log(`
|
|
572
|
-
console.log(`
|
|
573
|
-
console.log(`
|
|
574
|
-
console.log(
|
|
575
|
-
console.log(`
|
|
576
|
-
console.log(
|
|
577
|
-
console.log(` --
|
|
578
|
-
console.log(` --help, -h Show this help`);
|
|
579
|
-
console.log(` --preview Show team summary without launching shell`);
|
|
580
|
-
console.log(` --global Use personal squad path`);
|
|
581
|
-
console.log(` --timeout <seconds> Set REPL inactivity timeout (default: 600)`);
|
|
582
|
-
console.log(`\n${BOLD}Examples${RESET}`);
|
|
583
|
-
console.log(` ${DIM}$ squad init${RESET} Set up a squad in this repo`);
|
|
584
|
-
console.log(` ${DIM}$ squad triage --interval 5${RESET} Poll issues every 5 minutes`);
|
|
585
|
-
console.log(` ${DIM}$ squad export --out ./backups/team.json${RESET}`);
|
|
586
|
-
console.log(` Save squad snapshot`);
|
|
587
|
-
console.log(` ${DIM}$ squad copilot --auto-assign${RESET} Add @copilot with auto-assignment`);
|
|
588
|
-
console.log(` ${DIM}$ squad doctor${RESET} Diagnose setup issues`);
|
|
31
|
+
console.log(`Commands:`);
|
|
32
|
+
console.log(` ${BOLD}(default)${RESET} Launch interactive shell (no args)`);
|
|
33
|
+
console.log(` Flags: --global (init in personal squad directory)`);
|
|
34
|
+
console.log(` ${BOLD}init${RESET} Initialize Squad (skip files that already exist)`);
|
|
35
|
+
console.log(` Flags: --global (init in personal squad directory)`);
|
|
36
|
+
console.log(` ${BOLD}upgrade${RESET} Update Squad-owned files to latest version`);
|
|
37
|
+
console.log(` Overwrites: squad.agent.md, templates dir (.squad-templates/ or .ai-team-templates/)`);
|
|
38
|
+
console.log(` Never touches: .squad/ or .ai-team/ (your team state)`);
|
|
39
|
+
console.log(` Flags: --global (upgrade personal squad), --migrate-directory (rename .ai-team/ → .squad/)`);
|
|
40
|
+
console.log(` ${BOLD}status${RESET} Show which squad is active and why`);
|
|
41
|
+
console.log(` ${BOLD}triage${RESET} Scan for work and categorize issues`);
|
|
42
|
+
console.log(` Usage: triage [--interval <minutes>]`);
|
|
43
|
+
console.log(` Default: checks every 10 minutes (Ctrl+C to stop)`);
|
|
44
|
+
console.log(` ${BOLD}loop${RESET} Continuous work loop (Ralph mode)`);
|
|
45
|
+
console.log(` Usage: loop [--filter <label>] [--interval <minutes>]`);
|
|
46
|
+
console.log(` Default: checks every 10 minutes (Ctrl+C to stop)`);
|
|
47
|
+
console.log(` ${BOLD}hire${RESET} Team creation wizard`);
|
|
48
|
+
console.log(` Usage: hire [--name <name>] [--role <role>]`);
|
|
49
|
+
console.log(` ${BOLD}copilot${RESET} Add/remove the Copilot coding agent (@copilot)`);
|
|
50
|
+
console.log(` Usage: copilot [--off] [--auto-assign]`);
|
|
51
|
+
console.log(` ${BOLD}plugin${RESET} Manage plugin marketplaces`);
|
|
52
|
+
console.log(` Usage: plugin marketplace add|remove|list|browse`);
|
|
53
|
+
console.log(` ${BOLD}export${RESET} Export squad to a portable JSON snapshot`);
|
|
54
|
+
console.log(` Default: squad-export.json (use --out <path> to override)`);
|
|
55
|
+
console.log(` ${BOLD}import${RESET} Import squad from an export file`);
|
|
56
|
+
console.log(` Usage: import <file> [--force]`);
|
|
57
|
+
console.log(` ${BOLD}scrub-emails${RESET} Remove email addresses from Squad state files`);
|
|
58
|
+
console.log(` Usage: scrub-emails [directory] (default: .ai-team/)`);
|
|
59
|
+
console.log(` ${BOLD}start${RESET} Start Copilot with remote access from phone/browser`);
|
|
60
|
+
console.log(` Usage: start [--tunnel] [--port <n>] [--command <cmd>] [copilot flags...]`);
|
|
61
|
+
console.log(` Examples: start --tunnel --yolo`);
|
|
62
|
+
console.log(` start --tunnel --model claude-sonnet-4`);
|
|
63
|
+
console.log(` start --tunnel --command "agency copilot"`);
|
|
64
|
+
console.log(` ${BOLD}help${RESET} Show this help message`);
|
|
65
|
+
console.log(`\nFlags:`);
|
|
66
|
+
console.log(` ${BOLD}--version, -v${RESET} Print version`);
|
|
67
|
+
console.log(` ${BOLD}--help, -h${RESET} Show help`);
|
|
68
|
+
console.log(` ${BOLD}--global${RESET} Use personal (global) squad path (for init, upgrade)`);
|
|
589
69
|
console.log(`\nInstallation:`);
|
|
590
|
-
console.log(` npm
|
|
70
|
+
console.log(` npm install --save-dev @bradygaster/squad-cli`);
|
|
591
71
|
console.log(`\nInsider channel:`);
|
|
592
|
-
console.log(` npm
|
|
593
|
-
console.log(`\nRun 'squad <command> --help' for details.\n`);
|
|
594
|
-
return;
|
|
595
|
-
}
|
|
596
|
-
// --preview / --dry-run — show team summary without launching the interactive shell
|
|
597
|
-
if (cmd === '--preview' || cmd === '--dry-run' || (!cmd && args.includes('--preview')) || (cmd === 'shell' && args.includes('--preview'))) {
|
|
598
|
-
const squadDir = resolveSquad(process.cwd());
|
|
599
|
-
const globalPath = resolveGlobalSquadPath();
|
|
600
|
-
const globalSquadDir = path.join(globalPath, '.squad');
|
|
601
|
-
const teamRoot = squadDir ? path.dirname(squadDir) : fs.existsSync(globalSquadDir) ? globalPath : null;
|
|
602
|
-
if (!teamRoot) {
|
|
603
|
-
console.log(`${RED}✗${RESET} No squad found. Run 'squad init' first.`);
|
|
604
|
-
process.exit(1);
|
|
605
|
-
}
|
|
606
|
-
const data = loadWelcomeData(teamRoot);
|
|
607
|
-
if (!data) {
|
|
608
|
-
console.log(`${RED}✗${RESET} Could not read team configuration.`);
|
|
609
|
-
process.exit(1);
|
|
610
|
-
}
|
|
611
|
-
console.log(`\n${BOLD}Squad Preview${RESET}`);
|
|
612
|
-
console.log(`${'─'.repeat(40)}`);
|
|
613
|
-
console.log(` Team: ${data.projectName}`);
|
|
614
|
-
console.log(` Agents: ${data.agents.length}`);
|
|
615
|
-
if (data.description)
|
|
616
|
-
console.log(` About: ${data.description}`);
|
|
617
|
-
if (data.focus)
|
|
618
|
-
console.log(` Focus: ${data.focus}`);
|
|
619
|
-
console.log(`\n${BOLD}Agents${RESET}`);
|
|
620
|
-
for (const a of data.agents) {
|
|
621
|
-
console.log(` ${a.emoji} ${BOLD}${a.name}${RESET} — ${a.role}`);
|
|
622
|
-
}
|
|
623
|
-
console.log(`\n${BOLD}Shell Commands${RESET}`);
|
|
624
|
-
console.log(` /status — Check your team & what's happening`);
|
|
625
|
-
console.log(` /history — See recent messages`);
|
|
626
|
-
console.log(` /agents — List all team members`);
|
|
627
|
-
console.log(` /sessions — List saved sessions`);
|
|
628
|
-
console.log(` /resume — Restore a past session`);
|
|
629
|
-
console.log(` /clear — Clear the screen`);
|
|
630
|
-
console.log(` /quit — Exit`);
|
|
631
|
-
console.log(`\n${DIM}Run 'squad' to start the interactive shell.${RESET}\n`);
|
|
72
|
+
console.log(` npm install --save-dev @bradygaster/squad-cli@insider\n`);
|
|
632
73
|
return;
|
|
633
74
|
}
|
|
634
|
-
// No args →
|
|
75
|
+
// No args → launch interactive shell
|
|
635
76
|
if (!cmd) {
|
|
636
|
-
|
|
637
|
-
const globalPath = resolveGlobalSquadPath();
|
|
638
|
-
const globalSquadDir = path.join(globalPath, '.squad');
|
|
639
|
-
const hasSquad = squadPath || fs.existsSync(globalSquadDir);
|
|
640
|
-
if (hasSquad) {
|
|
641
|
-
// Squad exists, launch shell
|
|
642
|
-
await runShell();
|
|
643
|
-
}
|
|
644
|
-
else {
|
|
645
|
-
// First run — no squad found. Welcome the user.
|
|
646
|
-
console.log(`\n${BOLD}Welcome to Squad${RESET} v${VERSION}`);
|
|
647
|
-
console.log(`Your AI agent team\n`);
|
|
648
|
-
console.log(`Squad adds a team of AI agents to your project. Each agent`);
|
|
649
|
-
console.log(`has a role — architect, tester, security reviewer — and they`);
|
|
650
|
-
console.log(`collaborate to help you build, review, and ship code.\n`);
|
|
651
|
-
console.log(`${BOLD}Get started:${RESET}`);
|
|
652
|
-
console.log(` ${BOLD}squad init${RESET} Set up a squad in this repo`);
|
|
653
|
-
console.log(` ${BOLD}squad init --global${RESET} Create a personal squad\n`);
|
|
654
|
-
console.log(`${DIM}After init, just run ${BOLD}squad${RESET}${DIM} to start talking to your team.${RESET}`);
|
|
655
|
-
console.log(`${DIM}Run ${BOLD}squad help${RESET}${DIM} for all commands.${RESET}\n`);
|
|
656
|
-
}
|
|
77
|
+
await runShell();
|
|
657
78
|
return;
|
|
658
79
|
}
|
|
659
|
-
// Per-command --help/-h: intercept before dispatching (fixes #511, #512)
|
|
660
|
-
if (hasHelpFlag(args)) {
|
|
661
|
-
const helpText = getCommandHelp(cmd);
|
|
662
|
-
if (helpText) {
|
|
663
|
-
console.log(helpText);
|
|
664
|
-
return;
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
80
|
// Route subcommands
|
|
668
|
-
|
|
669
|
-
if (cmd === 'init' || cmd === 'hire') {
|
|
670
|
-
const modeIdx = args.indexOf('--mode');
|
|
671
|
-
const mode = (modeIdx !== -1 && args[modeIdx + 1]) ? args[modeIdx + 1] : 'local';
|
|
81
|
+
if (cmd === 'init') {
|
|
672
82
|
const dest = hasGlobal ? resolveGlobalSquadPath() : process.cwd();
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
const teamRootArg = args.find((a, i) => i > 0 && a !== '--mode' && a !== 'remote' && a !== '--global' && a !== 'init');
|
|
677
|
-
if (!teamRootArg) {
|
|
678
|
-
fatal('squad init --mode remote <team-root-path>');
|
|
679
|
-
}
|
|
680
|
-
writeRemoteConfig(dest, teamRootArg);
|
|
681
|
-
}
|
|
682
|
-
// Extract project prompt: squad init "Build a snake game" or squad init --file ./spec.txt
|
|
683
|
-
let initPrompt;
|
|
684
|
-
const fileIdx = args.indexOf('--file');
|
|
685
|
-
if (fileIdx !== -1 && args[fileIdx + 1]) {
|
|
686
|
-
const filePath = resolve(args[fileIdx + 1]);
|
|
687
|
-
if (!existsSync(filePath)) {
|
|
688
|
-
fatal(`Prompt file not found: ${filePath}`);
|
|
689
|
-
}
|
|
690
|
-
initPrompt = readFileSync(filePath, 'utf-8').trim();
|
|
691
|
-
}
|
|
692
|
-
else {
|
|
693
|
-
// Look for a positional string arg (not a flag, not 'init'/'hire')
|
|
694
|
-
const skipSet = new Set(['init', 'hire', '--global', '--mode', mode]);
|
|
695
|
-
const positional = args.find((a, i) => i > 0 && !a.startsWith('--') && !skipSet.has(a));
|
|
696
|
-
if (positional)
|
|
697
|
-
initPrompt = positional;
|
|
698
|
-
}
|
|
699
|
-
await runInit(dest, { prompt: initPrompt });
|
|
700
|
-
return;
|
|
701
|
-
}
|
|
702
|
-
if (cmd === 'link') {
|
|
703
|
-
const { runLink } = await import('./cli/commands/link.js');
|
|
704
|
-
const linkTarget = args[1];
|
|
705
|
-
if (!linkTarget) {
|
|
706
|
-
fatal('Run: squad link <team-repo-path>');
|
|
707
|
-
}
|
|
708
|
-
runLink(process.cwd(), linkTarget);
|
|
83
|
+
runInit(dest).catch(err => {
|
|
84
|
+
fatal(err.message);
|
|
85
|
+
});
|
|
709
86
|
return;
|
|
710
87
|
}
|
|
711
88
|
if (cmd === 'upgrade') {
|
|
712
89
|
const { runUpgrade } = await import('./cli/core/upgrade.js');
|
|
713
90
|
const { migrateDirectory } = await import('./cli/core/migrate-directory.js');
|
|
714
91
|
const migrateDir = args.includes('--migrate-directory');
|
|
92
|
+
const selfUpgrade = args.includes('--self');
|
|
715
93
|
const dest = hasGlobal ? resolveGlobalSquadPath() : process.cwd();
|
|
716
94
|
// Handle --migrate-directory flag
|
|
717
95
|
if (migrateDir) {
|
|
@@ -721,26 +99,40 @@ async function main() {
|
|
|
721
99
|
// Run upgrade
|
|
722
100
|
await runUpgrade(dest, {
|
|
723
101
|
migrateDirectory: migrateDir,
|
|
102
|
+
self: selfUpgrade
|
|
724
103
|
});
|
|
725
104
|
return;
|
|
726
105
|
}
|
|
727
|
-
if (cmd === '
|
|
728
|
-
|
|
729
|
-
const squadDir = path.join(hasGlobal ? resolveGlobalSquadPath() : process.cwd(), '.squad');
|
|
730
|
-
const deep = args.includes('--deep');
|
|
731
|
-
const dryRun = args.includes('--dry-run');
|
|
732
|
-
const result = await runNap({ squadDir, deep, dryRun });
|
|
733
|
-
console.log(formatNapReport(result, !!process.env['NO_COLOR']));
|
|
106
|
+
if (cmd === 'triage' || cmd === 'watch') {
|
|
107
|
+
console.log('🕵️ Squad triage — scanning for work... (full implementation pending)');
|
|
734
108
|
return;
|
|
735
109
|
}
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
const
|
|
110
|
+
if (cmd === 'loop') {
|
|
111
|
+
const filterIdx = args.indexOf('--filter');
|
|
112
|
+
const filter = (filterIdx !== -1 && args[filterIdx + 1]) ? args[filterIdx + 1] : undefined;
|
|
739
113
|
const intervalIdx = args.indexOf('--interval');
|
|
740
114
|
const intervalMinutes = (intervalIdx !== -1 && args[intervalIdx + 1])
|
|
741
115
|
? parseInt(args[intervalIdx + 1], 10)
|
|
742
116
|
: 10;
|
|
743
|
-
|
|
117
|
+
console.log(`🔄 Squad loop starting... (full implementation pending)`);
|
|
118
|
+
if (filter) {
|
|
119
|
+
console.log(` Filter: ${filter}`);
|
|
120
|
+
}
|
|
121
|
+
console.log(` Interval: ${intervalMinutes} minutes`);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (cmd === 'hire') {
|
|
125
|
+
const nameIdx = args.indexOf('--name');
|
|
126
|
+
const name = (nameIdx !== -1 && args[nameIdx + 1]) ? args[nameIdx + 1] : undefined;
|
|
127
|
+
const roleIdx = args.indexOf('--role');
|
|
128
|
+
const role = (roleIdx !== -1 && args[roleIdx + 1]) ? args[roleIdx + 1] : undefined;
|
|
129
|
+
console.log('👋 Squad hire — team creation wizard starting... (full implementation pending)');
|
|
130
|
+
if (name) {
|
|
131
|
+
console.log(` Name: ${name}`);
|
|
132
|
+
}
|
|
133
|
+
if (role) {
|
|
134
|
+
console.log(` Role: ${role}`);
|
|
135
|
+
}
|
|
744
136
|
return;
|
|
745
137
|
}
|
|
746
138
|
if (cmd === 'export') {
|
|
@@ -754,7 +146,7 @@ async function main() {
|
|
|
754
146
|
const { runImport } = await import('./cli/commands/import.js');
|
|
755
147
|
const importFile = args[1];
|
|
756
148
|
if (!importFile) {
|
|
757
|
-
fatal('
|
|
149
|
+
fatal('Usage: squad import <file> [--force]');
|
|
758
150
|
}
|
|
759
151
|
const hasForce = args.includes('--force');
|
|
760
152
|
await runImport(process.cwd(), importFile, hasForce);
|
|
@@ -774,35 +166,16 @@ async function main() {
|
|
|
774
166
|
}
|
|
775
167
|
if (cmd === 'scrub-emails') {
|
|
776
168
|
const { scrubEmails } = await import('./cli/core/email-scrub.js');
|
|
777
|
-
const targetDir = args[1] || '.
|
|
169
|
+
const targetDir = args[1] || '.ai-team';
|
|
778
170
|
const count = await scrubEmails(targetDir);
|
|
779
171
|
if (count > 0) {
|
|
780
|
-
console.log(`Scrubbed ${count} email
|
|
172
|
+
console.log(`Scrubbed ${count} email address(es).`);
|
|
781
173
|
}
|
|
782
174
|
else {
|
|
783
|
-
console.log('No
|
|
175
|
+
console.log('No email addresses found.');
|
|
784
176
|
}
|
|
785
177
|
return;
|
|
786
178
|
}
|
|
787
|
-
if (cmd === 'aspire') {
|
|
788
|
-
const { runAspire } = await import('./cli/commands/aspire.js');
|
|
789
|
-
const useDocker = args.includes('--docker');
|
|
790
|
-
const portIdx = args.indexOf('--port');
|
|
791
|
-
const port = (portIdx !== -1 && args[portIdx + 1]) ? parseInt(args[portIdx + 1], 10) : undefined;
|
|
792
|
-
await runAspire({ docker: useDocker, port });
|
|
793
|
-
return;
|
|
794
|
-
}
|
|
795
|
-
if (cmd === 'upstream') {
|
|
796
|
-
const { upstreamCommand } = await import('./cli/commands/upstream.js');
|
|
797
|
-
await upstreamCommand(args.slice(1));
|
|
798
|
-
return;
|
|
799
|
-
}
|
|
800
|
-
// heartbeat → alias for doctor (#503)
|
|
801
|
-
if (cmd === 'doctor' || cmd === 'heartbeat') {
|
|
802
|
-
const { doctorCommand } = await import('./cli/commands/doctor.js');
|
|
803
|
-
await doctorCommand(process.cwd());
|
|
804
|
-
return;
|
|
805
|
-
}
|
|
806
179
|
if (cmd === 'status') {
|
|
807
180
|
const repoSquad = resolveSquad(process.cwd());
|
|
808
181
|
const globalPath = resolveGlobalSquadPath();
|
|
@@ -810,46 +183,49 @@ async function main() {
|
|
|
810
183
|
const globalExists = fs.existsSync(globalSquadDir);
|
|
811
184
|
console.log(`\n${BOLD}Squad Status${RESET}\n`);
|
|
812
185
|
if (repoSquad) {
|
|
813
|
-
console.log(`
|
|
814
|
-
console.log(` Path:
|
|
186
|
+
console.log(` Active squad: ${BOLD}repo${RESET}`);
|
|
187
|
+
console.log(` Path: ${repoSquad}`);
|
|
188
|
+
console.log(` Reason: Found .squad/ in repository tree`);
|
|
815
189
|
}
|
|
816
190
|
else if (globalExists) {
|
|
817
|
-
console.log(`
|
|
818
|
-
console.log(` Path:
|
|
191
|
+
console.log(` Active squad: ${BOLD}personal (global)${RESET}`);
|
|
192
|
+
console.log(` Path: ${globalSquadDir}`);
|
|
193
|
+
console.log(` Reason: No repo .squad/ found; personal squad exists at global path`);
|
|
819
194
|
}
|
|
820
195
|
else {
|
|
821
|
-
console.log(`
|
|
822
|
-
console.log(`
|
|
196
|
+
console.log(` Active squad: ${DIM}none${RESET}`);
|
|
197
|
+
console.log(` Reason: No .squad/ found in repo tree or at global path`);
|
|
823
198
|
}
|
|
824
199
|
console.log();
|
|
825
|
-
console.log(` ${DIM}Repo
|
|
826
|
-
console.log(` ${DIM}Global: ${globalPath}${RESET}`);
|
|
200
|
+
console.log(` ${DIM}Repo resolution: ${repoSquad ?? 'not found'}${RESET}`);
|
|
201
|
+
console.log(` ${DIM}Global path: ${globalPath}${RESET}`);
|
|
202
|
+
console.log(` ${DIM}Global squad: ${globalExists ? globalSquadDir : 'not initialized'}${RESET}`);
|
|
827
203
|
console.log();
|
|
828
204
|
return;
|
|
829
205
|
}
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
206
|
+
if (cmd === 'start') {
|
|
207
|
+
const { runStart } = await import('./cli/commands/start.js');
|
|
208
|
+
const hasTunnel = args.includes('--tunnel');
|
|
209
|
+
const portIdx = args.indexOf('--port');
|
|
210
|
+
const port = (portIdx !== -1 && args[portIdx + 1]) ? parseInt(args[portIdx + 1], 10) : 0;
|
|
211
|
+
// Collect all remaining args to pass through to copilot
|
|
212
|
+
const cmdIdx = args.indexOf('--command');
|
|
213
|
+
const customCmd = (cmdIdx !== -1 && args[cmdIdx + 1]) ? args[cmdIdx + 1] : undefined;
|
|
214
|
+
const squadFlags = ['start', '--tunnel', '--port', port.toString(), '--command', customCmd || ''].filter(Boolean);
|
|
215
|
+
const copilotArgs = args.slice(1).filter(a => !squadFlags.includes(a));
|
|
216
|
+
await runStart(process.cwd(), { tunnel: hasTunnel, port, copilotArgs, command: customCmd });
|
|
833
217
|
return;
|
|
834
218
|
}
|
|
835
219
|
// Unknown command
|
|
836
|
-
fatal(`Unknown command: ${cmd}
|
|
220
|
+
fatal(`Unknown command: ${cmd}\n Run 'squad help' for usage information.`);
|
|
837
221
|
}
|
|
838
222
|
main().catch(err => {
|
|
839
|
-
debugLog('Fatal CLI error:', err);
|
|
840
223
|
if (err instanceof SquadError) {
|
|
841
224
|
console.error(`${RED}✗${RESET} ${err.message}`);
|
|
842
225
|
}
|
|
843
226
|
else {
|
|
844
|
-
|
|
845
|
-
const friendly = msg.replace(/^Error:\s*/i, '');
|
|
846
|
-
console.error(`${RED}✗${RESET} ${friendly}`);
|
|
847
|
-
// Show stack trace only when SQUAD_DEBUG is enabled
|
|
848
|
-
if (process.env['SQUAD_DEBUG'] === '1' && err instanceof Error && err.stack) {
|
|
849
|
-
console.error(`\n${DIM}${err.stack}${RESET}`);
|
|
850
|
-
}
|
|
227
|
+
console.error(err);
|
|
851
228
|
}
|
|
852
|
-
console.error(`\n${DIM}Tip: Run 'squad doctor' for help. Set SQUAD_DEBUG=1 for details.${RESET}`);
|
|
853
229
|
process.exit(1);
|
|
854
230
|
});
|
|
855
231
|
//# sourceMappingURL=cli-entry.js.map
|