@bradygaster/squad-cli 0.8.1 → 0.8.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/dist/cli/commands/aspire.d.ts +19 -0
- package/dist/cli/commands/aspire.d.ts.map +1 -0
- package/dist/cli/commands/aspire.js +151 -0
- package/dist/cli/commands/aspire.js.map +1 -0
- package/dist/cli/commands/doctor.d.ts +38 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -0
- package/dist/cli/commands/doctor.js +247 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/init-remote.d.ts +18 -0
- package/dist/cli/commands/init-remote.d.ts.map +1 -0
- package/dist/cli/commands/init-remote.js +32 -0
- package/dist/cli/commands/init-remote.js.map +1 -0
- package/dist/cli/commands/link.d.ts +18 -0
- package/dist/cli/commands/link.d.ts.map +1 -0
- package/dist/cli/commands/link.js +49 -0
- package/dist/cli/commands/link.js.map +1 -0
- package/dist/cli/commands/plugin.d.ts.map +1 -1
- package/dist/cli/commands/plugin.js +2 -1
- package/dist/cli/commands/plugin.js.map +1 -1
- package/dist/cli/commands/upstream.d.ts +13 -0
- package/dist/cli/commands/upstream.d.ts.map +1 -0
- package/dist/cli/commands/upstream.js +232 -0
- package/dist/cli/commands/upstream.js.map +1 -0
- package/dist/cli/core/upgrade.js.map +1 -1
- package/dist/cli/shell/components/AgentPanel.d.ts +4 -0
- package/dist/cli/shell/components/AgentPanel.d.ts.map +1 -1
- package/dist/cli/shell/components/AgentPanel.js +9 -12
- package/dist/cli/shell/components/AgentPanel.js.map +1 -1
- package/dist/cli/shell/components/App.d.ts +30 -0
- package/dist/cli/shell/components/App.d.ts.map +1 -0
- package/dist/cli/shell/components/App.js +103 -0
- package/dist/cli/shell/components/App.js.map +1 -0
- package/dist/cli/shell/components/InputPrompt.js +1 -1
- package/dist/cli/shell/components/InputPrompt.js.map +1 -1
- package/dist/cli/shell/components/MessageStream.d.ts +3 -1
- package/dist/cli/shell/components/MessageStream.d.ts.map +1 -1
- package/dist/cli/shell/components/MessageStream.js +35 -3
- package/dist/cli/shell/components/MessageStream.js.map +1 -1
- package/dist/cli/shell/components/index.d.ts +2 -0
- package/dist/cli/shell/components/index.d.ts.map +1 -1
- package/dist/cli/shell/components/index.js +1 -0
- package/dist/cli/shell/components/index.js.map +1 -1
- package/dist/cli/shell/index.d.ts +4 -2
- package/dist/cli/shell/index.d.ts.map +1 -1
- package/dist/cli/shell/index.js +218 -39
- package/dist/cli/shell/index.js.map +1 -1
- package/dist/cli/shell/lifecycle.d.ts +14 -0
- package/dist/cli/shell/lifecycle.d.ts.map +1 -1
- package/dist/cli/shell/lifecycle.js +51 -0
- package/dist/cli/shell/lifecycle.js.map +1 -1
- package/dist/cli/shell/sdk-bridge.d.ts +50 -0
- package/dist/cli/shell/sdk-bridge.d.ts.map +1 -0
- package/dist/cli/shell/sdk-bridge.js +235 -0
- package/dist/cli/shell/sdk-bridge.js.map +1 -0
- package/dist/cli/shell/spawn.d.ts +9 -7
- package/dist/cli/shell/spawn.d.ts.map +1 -1
- package/dist/cli/shell/spawn.js +45 -20
- package/dist/cli/shell/spawn.js.map +1 -1
- package/dist/cli-entry.js +40 -3
- package/dist/cli-entry.js.map +1 -1
- package/package.json +97 -2
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aspire command — Launch .NET Aspire dashboard for Squad observability
|
|
3
|
+
* (Issue #265)
|
|
4
|
+
*
|
|
5
|
+
* Starts the Aspire dashboard and configures OTLP export so Squad
|
|
6
|
+
* traces and metrics flow into the dashboard automatically.
|
|
7
|
+
*/
|
|
8
|
+
export interface AspireOptions {
|
|
9
|
+
/** Use Docker even if dotnet is available */
|
|
10
|
+
docker?: boolean;
|
|
11
|
+
/** Custom OTLP endpoint port */
|
|
12
|
+
port?: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Run the `squad aspire` command.
|
|
16
|
+
* Launches the Aspire dashboard and configures OTLP export.
|
|
17
|
+
*/
|
|
18
|
+
export declare function runAspire(options?: AspireOptions): Promise<void>;
|
|
19
|
+
//# sourceMappingURL=aspire.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aspire.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/aspire.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAyFH,MAAM,WAAW,aAAa;IAC5B,6CAA6C;IAC7C,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,gCAAgC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoE1E"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aspire command — Launch .NET Aspire dashboard for Squad observability
|
|
3
|
+
* (Issue #265)
|
|
4
|
+
*
|
|
5
|
+
* Starts the Aspire dashboard and configures OTLP export so Squad
|
|
6
|
+
* traces and metrics flow into the dashboard automatically.
|
|
7
|
+
*/
|
|
8
|
+
import { execSync, spawn } from 'node:child_process';
|
|
9
|
+
import { BOLD, RESET, DIM, GREEN, RED, YELLOW } from '../core/output.js';
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// Constants
|
|
12
|
+
// ============================================================================
|
|
13
|
+
/** Default OTLP endpoint the Aspire dashboard listens on. */
|
|
14
|
+
const ASPIRE_OTLP_ENDPOINT = 'http://localhost:18888';
|
|
15
|
+
/** Default Aspire dashboard UI port. */
|
|
16
|
+
const ASPIRE_DASHBOARD_PORT = 18888;
|
|
17
|
+
/** Docker image for the Aspire dashboard. */
|
|
18
|
+
const ASPIRE_DOCKER_IMAGE = 'mcr.microsoft.com/dotnet/aspire-dashboard:latest';
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// Detection helpers
|
|
21
|
+
// ============================================================================
|
|
22
|
+
function commandExists(cmd) {
|
|
23
|
+
try {
|
|
24
|
+
execSync(`${cmd} --version`, { stdio: 'ignore' });
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function isDotnetAspireAvailable() {
|
|
32
|
+
if (!commandExists('dotnet'))
|
|
33
|
+
return false;
|
|
34
|
+
try {
|
|
35
|
+
const output = execSync('dotnet tool list -g', { encoding: 'utf8' });
|
|
36
|
+
if (output.toLowerCase().includes('aspire'))
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// Ignore
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
const workloads = execSync('dotnet workload list', { encoding: 'utf8' });
|
|
44
|
+
if (workloads.toLowerCase().includes('aspire'))
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// Ignore
|
|
49
|
+
}
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
function isDockerAvailable() {
|
|
53
|
+
return commandExists('docker');
|
|
54
|
+
}
|
|
55
|
+
// ============================================================================
|
|
56
|
+
// Launch strategies
|
|
57
|
+
// ============================================================================
|
|
58
|
+
function launchWithDocker() {
|
|
59
|
+
console.log(`${DIM}Starting Aspire dashboard via Docker...${RESET}`);
|
|
60
|
+
const child = spawn('docker', [
|
|
61
|
+
'run', '--rm',
|
|
62
|
+
'-p', `${ASPIRE_DASHBOARD_PORT}:18888`,
|
|
63
|
+
'-p', '4317:18889',
|
|
64
|
+
'-e', 'DASHBOARD__FRONTEND__AUTHMODE=Unsecured',
|
|
65
|
+
'-e', 'DASHBOARD__OTLP__AUTHMODE=ApiKey',
|
|
66
|
+
'-e', 'DASHBOARD__OTLP__PRIMARYAPIKEY=squad-dev-key',
|
|
67
|
+
ASPIRE_DOCKER_IMAGE,
|
|
68
|
+
], {
|
|
69
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
70
|
+
detached: false,
|
|
71
|
+
});
|
|
72
|
+
return child;
|
|
73
|
+
}
|
|
74
|
+
function launchWithDotnet() {
|
|
75
|
+
console.log(`${DIM}Starting Aspire dashboard via dotnet...${RESET}`);
|
|
76
|
+
const child = spawn('dotnet', [
|
|
77
|
+
'run', '--project', 'aspire',
|
|
78
|
+
'--', '--dashboard-port', String(ASPIRE_DASHBOARD_PORT),
|
|
79
|
+
], {
|
|
80
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
81
|
+
detached: false,
|
|
82
|
+
});
|
|
83
|
+
return child;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Run the `squad aspire` command.
|
|
87
|
+
* Launches the Aspire dashboard and configures OTLP export.
|
|
88
|
+
*/
|
|
89
|
+
export async function runAspire(options = {}) {
|
|
90
|
+
const port = options.port ?? ASPIRE_DASHBOARD_PORT;
|
|
91
|
+
const endpoint = `http://localhost:${port}`;
|
|
92
|
+
console.log(`\n${BOLD}🔭 Squad Aspire — OpenTelemetry Dashboard${RESET}\n`);
|
|
93
|
+
// Set OTLP environment so OTel providers pick it up
|
|
94
|
+
process.env['OTEL_EXPORTER_OTLP_ENDPOINT'] = endpoint;
|
|
95
|
+
console.log(`${DIM}OTLP endpoint: ${endpoint}${RESET}`);
|
|
96
|
+
// Determine launch strategy
|
|
97
|
+
const useDocker = options.docker || !isDotnetAspireAvailable();
|
|
98
|
+
let child;
|
|
99
|
+
if (useDocker && isDockerAvailable()) {
|
|
100
|
+
child = launchWithDocker();
|
|
101
|
+
}
|
|
102
|
+
else if (!useDocker && isDotnetAspireAvailable()) {
|
|
103
|
+
child = launchWithDotnet();
|
|
104
|
+
}
|
|
105
|
+
else if (isDockerAvailable()) {
|
|
106
|
+
child = launchWithDocker();
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
console.log(`${RED}✗${RESET} Neither Docker nor .NET Aspire workload found.`);
|
|
110
|
+
console.log(`\n Install options:`);
|
|
111
|
+
console.log(` ${BOLD}Docker:${RESET} https://docker.com/get-started`);
|
|
112
|
+
console.log(` ${BOLD}Aspire:${RESET} dotnet workload install aspire\n`);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
// Wire up output
|
|
116
|
+
child.stdout?.on('data', (data) => {
|
|
117
|
+
const text = data.toString().trim();
|
|
118
|
+
if (text)
|
|
119
|
+
console.log(`${DIM}[aspire]${RESET} ${text}`);
|
|
120
|
+
});
|
|
121
|
+
child.stderr?.on('data', (data) => {
|
|
122
|
+
const text = data.toString().trim();
|
|
123
|
+
if (text)
|
|
124
|
+
console.log(`${YELLOW}[aspire]${RESET} ${text}`);
|
|
125
|
+
});
|
|
126
|
+
child.on('error', (err) => {
|
|
127
|
+
console.error(`${RED}✗${RESET} Failed to start Aspire: ${err.message}`);
|
|
128
|
+
});
|
|
129
|
+
// Give the dashboard a moment to start
|
|
130
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
131
|
+
console.log(`\n${GREEN}✓${RESET} Aspire dashboard launching`);
|
|
132
|
+
console.log(` ${BOLD}Dashboard:${RESET} http://localhost:${port}`);
|
|
133
|
+
console.log(` ${BOLD}OTLP gRPC:${RESET} localhost:4317`);
|
|
134
|
+
console.log(`\n${DIM}Squad OTel will automatically export to this endpoint.${RESET}`);
|
|
135
|
+
console.log(`${DIM}Press Ctrl+C to stop.${RESET}\n`);
|
|
136
|
+
// Keep alive until Ctrl+C
|
|
137
|
+
return new Promise((resolve) => {
|
|
138
|
+
const shutdown = () => {
|
|
139
|
+
console.log(`\n${DIM}🔭 Aspire dashboard stopping...${RESET}`);
|
|
140
|
+
child?.kill();
|
|
141
|
+
resolve();
|
|
142
|
+
};
|
|
143
|
+
process.on('SIGINT', shutdown);
|
|
144
|
+
process.on('SIGTERM', shutdown);
|
|
145
|
+
child?.on('close', () => {
|
|
146
|
+
console.log(`${DIM}Aspire process exited.${RESET}`);
|
|
147
|
+
resolve();
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=aspire.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aspire.js","sourceRoot":"","sources":["../../../src/cli/commands/aspire.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* squad doctor — setup validation diagnostic command.
|
|
3
|
+
*
|
|
4
|
+
* Inspects the .squad/ directory (or hub layout) and reports
|
|
5
|
+
* the health of every expected file / convention. Always exits 0
|
|
6
|
+
* because this is a diagnostic tool, not a gate.
|
|
7
|
+
*
|
|
8
|
+
* Inspired by @spboyer (Shayne Boyer)'s doctor command in PR bradygaster/squad#131.
|
|
9
|
+
*
|
|
10
|
+
* @module cli/commands/doctor
|
|
11
|
+
*/
|
|
12
|
+
/** Result of a single diagnostic check. */
|
|
13
|
+
export interface DoctorCheck {
|
|
14
|
+
name: string;
|
|
15
|
+
status: 'pass' | 'fail' | 'warn';
|
|
16
|
+
message: string;
|
|
17
|
+
}
|
|
18
|
+
/** Detected squad layout mode. */
|
|
19
|
+
export type DoctorMode = 'local' | 'remote' | 'hub';
|
|
20
|
+
/**
|
|
21
|
+
* Run all doctor checks for the given working directory.
|
|
22
|
+
* Returns an array of check results — never throws for check failures.
|
|
23
|
+
*/
|
|
24
|
+
export declare function runDoctor(cwd?: string): Promise<DoctorCheck[]>;
|
|
25
|
+
/**
|
|
26
|
+
* Detect the squad mode for the given working directory.
|
|
27
|
+
* Exported for tests and display.
|
|
28
|
+
*/
|
|
29
|
+
export declare function getDoctorMode(cwd?: string): DoctorMode;
|
|
30
|
+
/**
|
|
31
|
+
* Print doctor results to stdout. Intended for CLI use.
|
|
32
|
+
*/
|
|
33
|
+
export declare function printDoctorReport(checks: DoctorCheck[], mode: DoctorMode): void;
|
|
34
|
+
/**
|
|
35
|
+
* CLI entry point — run doctor and print results.
|
|
36
|
+
*/
|
|
37
|
+
export declare function doctorCommand(cwd?: string): Promise<void>;
|
|
38
|
+
//# sourceMappingURL=doctor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,2CAA2C;AAC3C,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IACjC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,kCAAkC;AAClC,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;AAkMpD;;;GAGG;AACH,wBAAsB,SAAS,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CA+BpE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,UAAU,CAEtD;AAUD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,UAAU,GAAG,IAAI,CAc/E;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAK/D"}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* squad doctor — setup validation diagnostic command.
|
|
3
|
+
*
|
|
4
|
+
* Inspects the .squad/ directory (or hub layout) and reports
|
|
5
|
+
* the health of every expected file / convention. Always exits 0
|
|
6
|
+
* because this is a diagnostic tool, not a gate.
|
|
7
|
+
*
|
|
8
|
+
* Inspired by @spboyer (Shayne Boyer)'s doctor command in PR bradygaster/squad#131.
|
|
9
|
+
*
|
|
10
|
+
* @module cli/commands/doctor
|
|
11
|
+
*/
|
|
12
|
+
import fs from 'node:fs';
|
|
13
|
+
import path from 'node:path';
|
|
14
|
+
// ── helpers ─────────────────────────────────────────────────────────
|
|
15
|
+
function fileExists(p) {
|
|
16
|
+
return fs.existsSync(p);
|
|
17
|
+
}
|
|
18
|
+
function isDirectory(p) {
|
|
19
|
+
try {
|
|
20
|
+
return fs.statSync(p).isDirectory();
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function tryReadJson(p) {
|
|
27
|
+
try {
|
|
28
|
+
return JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// ── mode detection ──────────────────────────────────────────────────
|
|
35
|
+
function detectMode(cwd) {
|
|
36
|
+
const squadDir = path.join(cwd, '.squad');
|
|
37
|
+
const configPath = path.join(squadDir, 'config.json');
|
|
38
|
+
// Remote mode: config.json exists with teamRoot
|
|
39
|
+
if (fileExists(configPath)) {
|
|
40
|
+
const cfg = tryReadJson(configPath);
|
|
41
|
+
if (cfg && typeof cfg === 'object' && 'teamRoot' in cfg) {
|
|
42
|
+
const raw = cfg['teamRoot'];
|
|
43
|
+
if (typeof raw === 'string' && raw.length > 0) {
|
|
44
|
+
return { mode: 'remote', squadDir, teamRoot: raw };
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// Hub mode: squad-hub.json in cwd
|
|
49
|
+
if (fileExists(path.join(cwd, 'squad-hub.json'))) {
|
|
50
|
+
return { mode: 'hub', squadDir };
|
|
51
|
+
}
|
|
52
|
+
// Default: local
|
|
53
|
+
return { mode: 'local', squadDir };
|
|
54
|
+
}
|
|
55
|
+
// ── individual checks ───────────────────────────────────────────────
|
|
56
|
+
function checkSquadDir(squadDir) {
|
|
57
|
+
const exists = isDirectory(squadDir);
|
|
58
|
+
return {
|
|
59
|
+
name: '.squad/ directory exists',
|
|
60
|
+
status: exists ? 'pass' : 'fail',
|
|
61
|
+
message: exists ? 'directory present' : 'directory not found',
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function checkConfigJson(squadDir) {
|
|
65
|
+
const configPath = path.join(squadDir, 'config.json');
|
|
66
|
+
if (!fileExists(configPath))
|
|
67
|
+
return undefined; // optional file — skip
|
|
68
|
+
const data = tryReadJson(configPath);
|
|
69
|
+
if (data === undefined) {
|
|
70
|
+
return {
|
|
71
|
+
name: 'config.json valid',
|
|
72
|
+
status: 'fail',
|
|
73
|
+
message: 'file exists but is not valid JSON',
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
if (typeof data === 'object' &&
|
|
77
|
+
data !== null &&
|
|
78
|
+
'teamRoot' in data &&
|
|
79
|
+
typeof data['teamRoot'] !== 'string') {
|
|
80
|
+
return {
|
|
81
|
+
name: 'config.json valid',
|
|
82
|
+
status: 'fail',
|
|
83
|
+
message: 'teamRoot must be a string',
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
name: 'config.json valid',
|
|
88
|
+
status: 'pass',
|
|
89
|
+
message: 'parses as JSON, schema OK',
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function checkAbsoluteTeamRoot(squadDir) {
|
|
93
|
+
const configPath = path.join(squadDir, 'config.json');
|
|
94
|
+
if (!fileExists(configPath))
|
|
95
|
+
return undefined;
|
|
96
|
+
const data = tryReadJson(configPath);
|
|
97
|
+
if (!data || typeof data['teamRoot'] !== 'string')
|
|
98
|
+
return undefined;
|
|
99
|
+
const teamRoot = data['teamRoot'];
|
|
100
|
+
if (path.isAbsolute(teamRoot)) {
|
|
101
|
+
return {
|
|
102
|
+
name: 'absolute path warning',
|
|
103
|
+
status: 'warn',
|
|
104
|
+
message: `teamRoot is absolute (${teamRoot}) — prefer relative paths for portability`,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
function checkTeamRootResolves(squadDir, teamRoot) {
|
|
110
|
+
const resolved = path.isAbsolute(teamRoot)
|
|
111
|
+
? teamRoot
|
|
112
|
+
: path.resolve(path.dirname(squadDir), teamRoot);
|
|
113
|
+
const exists = isDirectory(resolved);
|
|
114
|
+
return {
|
|
115
|
+
name: 'team root resolves',
|
|
116
|
+
status: exists ? 'pass' : 'fail',
|
|
117
|
+
message: exists ? `resolved to ${resolved}` : `directory not found: ${resolved}`,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
function checkTeamMd(squadDir) {
|
|
121
|
+
const teamPath = path.join(squadDir, 'team.md');
|
|
122
|
+
if (!fileExists(teamPath)) {
|
|
123
|
+
return { name: 'team.md found with ## Members header', status: 'fail', message: 'file not found' };
|
|
124
|
+
}
|
|
125
|
+
const content = fs.readFileSync(teamPath, 'utf8');
|
|
126
|
+
if (!content.includes('## Members')) {
|
|
127
|
+
return { name: 'team.md found with ## Members header', status: 'warn', message: 'file exists but missing ## Members header' };
|
|
128
|
+
}
|
|
129
|
+
return { name: 'team.md found with ## Members header', status: 'pass', message: 'file present, header found' };
|
|
130
|
+
}
|
|
131
|
+
function checkRoutingMd(squadDir) {
|
|
132
|
+
const exists = fileExists(path.join(squadDir, 'routing.md'));
|
|
133
|
+
return {
|
|
134
|
+
name: 'routing.md found',
|
|
135
|
+
status: exists ? 'pass' : 'fail',
|
|
136
|
+
message: exists ? 'file present' : 'file not found',
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
function checkAgentsDir(squadDir) {
|
|
140
|
+
const agentsDir = path.join(squadDir, 'agents');
|
|
141
|
+
if (!isDirectory(agentsDir)) {
|
|
142
|
+
return { name: 'agents/ directory exists', status: 'fail', message: 'directory not found' };
|
|
143
|
+
}
|
|
144
|
+
let count = 0;
|
|
145
|
+
try {
|
|
146
|
+
for (const entry of fs.readdirSync(agentsDir, { withFileTypes: true })) {
|
|
147
|
+
if (entry.isDirectory())
|
|
148
|
+
count++;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
catch { /* empty */ }
|
|
152
|
+
return {
|
|
153
|
+
name: 'agents/ directory exists',
|
|
154
|
+
status: 'pass',
|
|
155
|
+
message: `directory present (${count} agent${count === 1 ? '' : 's'})`,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
function checkCastingRegistry(squadDir) {
|
|
159
|
+
const registryPath = path.join(squadDir, 'casting', 'registry.json');
|
|
160
|
+
if (!fileExists(registryPath)) {
|
|
161
|
+
return { name: 'casting/registry.json exists', status: 'fail', message: 'file not found' };
|
|
162
|
+
}
|
|
163
|
+
const data = tryReadJson(registryPath);
|
|
164
|
+
if (data === undefined) {
|
|
165
|
+
return { name: 'casting/registry.json exists', status: 'fail', message: 'file exists but is not valid JSON' };
|
|
166
|
+
}
|
|
167
|
+
return { name: 'casting/registry.json exists', status: 'pass', message: 'file present, valid JSON' };
|
|
168
|
+
}
|
|
169
|
+
function checkDecisionsMd(squadDir) {
|
|
170
|
+
const exists = fileExists(path.join(squadDir, 'decisions.md'));
|
|
171
|
+
return {
|
|
172
|
+
name: 'decisions.md exists',
|
|
173
|
+
status: exists ? 'pass' : 'fail',
|
|
174
|
+
message: exists ? 'file present' : 'file not found',
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
// ── public API ──────────────────────────────────────────────────────
|
|
178
|
+
/**
|
|
179
|
+
* Run all doctor checks for the given working directory.
|
|
180
|
+
* Returns an array of check results — never throws for check failures.
|
|
181
|
+
*/
|
|
182
|
+
export async function runDoctor(cwd) {
|
|
183
|
+
const resolvedCwd = cwd ?? process.cwd();
|
|
184
|
+
const { mode, squadDir, teamRoot } = detectMode(resolvedCwd);
|
|
185
|
+
const checks = [];
|
|
186
|
+
// 1. .squad/ directory
|
|
187
|
+
checks.push(checkSquadDir(squadDir));
|
|
188
|
+
// 2. config.json (if present)
|
|
189
|
+
const configCheck = checkConfigJson(squadDir);
|
|
190
|
+
if (configCheck)
|
|
191
|
+
checks.push(configCheck);
|
|
192
|
+
// 3. Absolute path warning
|
|
193
|
+
const absWarn = checkAbsoluteTeamRoot(squadDir);
|
|
194
|
+
if (absWarn)
|
|
195
|
+
checks.push(absWarn);
|
|
196
|
+
// 4. Remote team root resolution
|
|
197
|
+
if (mode === 'remote' && teamRoot) {
|
|
198
|
+
checks.push(checkTeamRootResolves(squadDir, teamRoot));
|
|
199
|
+
}
|
|
200
|
+
// 5–9 standard files (only if .squad/ exists)
|
|
201
|
+
if (isDirectory(squadDir)) {
|
|
202
|
+
checks.push(checkTeamMd(squadDir));
|
|
203
|
+
checks.push(checkRoutingMd(squadDir));
|
|
204
|
+
checks.push(checkAgentsDir(squadDir));
|
|
205
|
+
checks.push(checkCastingRegistry(squadDir));
|
|
206
|
+
checks.push(checkDecisionsMd(squadDir));
|
|
207
|
+
}
|
|
208
|
+
return checks;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Detect the squad mode for the given working directory.
|
|
212
|
+
* Exported for tests and display.
|
|
213
|
+
*/
|
|
214
|
+
export function getDoctorMode(cwd) {
|
|
215
|
+
return detectMode(cwd ?? process.cwd()).mode;
|
|
216
|
+
}
|
|
217
|
+
// ── CLI output ──────────────────────────────────────────────────────
|
|
218
|
+
const STATUS_ICON = {
|
|
219
|
+
pass: '✅',
|
|
220
|
+
fail: '❌',
|
|
221
|
+
warn: '⚠️',
|
|
222
|
+
};
|
|
223
|
+
/**
|
|
224
|
+
* Print doctor results to stdout. Intended for CLI use.
|
|
225
|
+
*/
|
|
226
|
+
export function printDoctorReport(checks, mode) {
|
|
227
|
+
console.log('\n🩺 Squad Doctor');
|
|
228
|
+
console.log('═══════════════\n');
|
|
229
|
+
console.log(`Mode: ${mode}\n`);
|
|
230
|
+
for (const c of checks) {
|
|
231
|
+
console.log(`${STATUS_ICON[c.status]} ${c.name} — ${c.message}`);
|
|
232
|
+
}
|
|
233
|
+
const passed = checks.filter(c => c.status === 'pass').length;
|
|
234
|
+
const failed = checks.filter(c => c.status === 'fail').length;
|
|
235
|
+
const warned = checks.filter(c => c.status === 'warn').length;
|
|
236
|
+
console.log(`\nSummary: ${passed} passed, ${failed} failed, ${warned} warnings\n`);
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* CLI entry point — run doctor and print results.
|
|
240
|
+
*/
|
|
241
|
+
export async function doctorCommand(cwd) {
|
|
242
|
+
const resolvedCwd = cwd ?? process.cwd();
|
|
243
|
+
const mode = getDoctorMode(resolvedCwd);
|
|
244
|
+
const checks = await runDoctor(resolvedCwd);
|
|
245
|
+
printDoctorReport(checks, mode);
|
|
246
|
+
}
|
|
247
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* squad init --mode remote — remote mode variant of the init command.
|
|
3
|
+
*
|
|
4
|
+
* Creates .squad/ with config.json pointing to an external team root.
|
|
5
|
+
* The standard init scaffolding still runs; this just adds the config link.
|
|
6
|
+
*
|
|
7
|
+
* Remote squad mode concept by @spboyer (Shayne Boyer), PR bradygaster/squad#131.
|
|
8
|
+
*
|
|
9
|
+
* @module cli/commands/init-remote
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Write `.squad/config.json` for remote mode.
|
|
13
|
+
*
|
|
14
|
+
* @param projectDir - Project root (where .squad/ lives or will be created).
|
|
15
|
+
* @param teamRepoPath - Absolute or relative path to the team repo.
|
|
16
|
+
*/
|
|
17
|
+
export declare function writeRemoteConfig(projectDir: string, teamRepoPath: string): void;
|
|
18
|
+
//# sourceMappingURL=init-remote.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-remote.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init-remote.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAmBhF"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* squad init --mode remote — remote mode variant of the init command.
|
|
3
|
+
*
|
|
4
|
+
* Creates .squad/ with config.json pointing to an external team root.
|
|
5
|
+
* The standard init scaffolding still runs; this just adds the config link.
|
|
6
|
+
*
|
|
7
|
+
* Remote squad mode concept by @spboyer (Shayne Boyer), PR bradygaster/squad#131.
|
|
8
|
+
*
|
|
9
|
+
* @module cli/commands/init-remote
|
|
10
|
+
*/
|
|
11
|
+
import fs from 'node:fs';
|
|
12
|
+
import path from 'node:path';
|
|
13
|
+
/**
|
|
14
|
+
* Write `.squad/config.json` for remote mode.
|
|
15
|
+
*
|
|
16
|
+
* @param projectDir - Project root (where .squad/ lives or will be created).
|
|
17
|
+
* @param teamRepoPath - Absolute or relative path to the team repo.
|
|
18
|
+
*/
|
|
19
|
+
export function writeRemoteConfig(projectDir, teamRepoPath) {
|
|
20
|
+
const squadDir = path.join(projectDir, '.squad');
|
|
21
|
+
fs.mkdirSync(squadDir, { recursive: true });
|
|
22
|
+
// Always store a relative path from the project root to the team repo
|
|
23
|
+
const absoluteTeam = path.resolve(projectDir, teamRepoPath);
|
|
24
|
+
const relativePath = path.relative(projectDir, absoluteTeam);
|
|
25
|
+
const config = {
|
|
26
|
+
version: 1,
|
|
27
|
+
teamRoot: relativePath,
|
|
28
|
+
projectKey: null,
|
|
29
|
+
};
|
|
30
|
+
fs.writeFileSync(path.join(squadDir, 'config.json'), JSON.stringify(config, null, 2) + '\n', 'utf-8');
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=init-remote.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-remote.js","sourceRoot":"","sources":["../../../src/cli/commands/init-remote.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,UAAkB,EAAE,YAAoB;IACxE,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IACjD,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE5C,sEAAsE;IACtE,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;IAC5D,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;IAE7D,MAAM,MAAM,GAAG;QACb,OAAO,EAAE,CAAC;QACV,QAAQ,EAAE,YAAY;QACtB,UAAU,EAAE,IAAI;KACjB,CAAC;IAEF,EAAE,CAAC,aAAa,CACd,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,EAClC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EACtC,OAAO,CACR,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* squad link <team-repo-path> — link a project to a remote team root.
|
|
3
|
+
*
|
|
4
|
+
* Writes `.squad/config.json` with a relative `teamRoot` path so the
|
|
5
|
+
* dual-root resolver (resolveSquadPaths) can find the team identity dir.
|
|
6
|
+
*
|
|
7
|
+
* Remote squad mode concept by @spboyer (Shayne Boyer), PR bradygaster/squad#131.
|
|
8
|
+
*
|
|
9
|
+
* @module cli/commands/link
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Link the current project to a remote team root.
|
|
13
|
+
*
|
|
14
|
+
* @param projectDir - Project root (cwd or explicit).
|
|
15
|
+
* @param teamRepoPath - Path (relative or absolute) to the team repo.
|
|
16
|
+
*/
|
|
17
|
+
export declare function runLink(projectDir: string, teamRepoPath: string): void;
|
|
18
|
+
//# sourceMappingURL=link.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/link.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAwCtE"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* squad link <team-repo-path> — link a project to a remote team root.
|
|
3
|
+
*
|
|
4
|
+
* Writes `.squad/config.json` with a relative `teamRoot` path so the
|
|
5
|
+
* dual-root resolver (resolveSquadPaths) can find the team identity dir.
|
|
6
|
+
*
|
|
7
|
+
* Remote squad mode concept by @spboyer (Shayne Boyer), PR bradygaster/squad#131.
|
|
8
|
+
*
|
|
9
|
+
* @module cli/commands/link
|
|
10
|
+
*/
|
|
11
|
+
import fs from 'node:fs';
|
|
12
|
+
import path from 'node:path';
|
|
13
|
+
import { fatal } from '../core/errors.js';
|
|
14
|
+
/**
|
|
15
|
+
* Link the current project to a remote team root.
|
|
16
|
+
*
|
|
17
|
+
* @param projectDir - Project root (cwd or explicit).
|
|
18
|
+
* @param teamRepoPath - Path (relative or absolute) to the team repo.
|
|
19
|
+
*/
|
|
20
|
+
export function runLink(projectDir, teamRepoPath) {
|
|
21
|
+
// Resolve the team repo path to an absolute path
|
|
22
|
+
const absoluteTeam = path.resolve(projectDir, teamRepoPath);
|
|
23
|
+
// Validate the target exists
|
|
24
|
+
if (!fs.existsSync(absoluteTeam)) {
|
|
25
|
+
fatal(`Target path does not exist: ${absoluteTeam}`);
|
|
26
|
+
}
|
|
27
|
+
if (!fs.statSync(absoluteTeam).isDirectory()) {
|
|
28
|
+
fatal(`Target path is not a directory: ${absoluteTeam}`);
|
|
29
|
+
}
|
|
30
|
+
// Validate the target contains a .squad/ or .ai-team/ directory
|
|
31
|
+
const hasSquad = fs.existsSync(path.join(absoluteTeam, '.squad'));
|
|
32
|
+
const hasAiTeam = fs.existsSync(path.join(absoluteTeam, '.ai-team'));
|
|
33
|
+
if (!hasSquad && !hasAiTeam) {
|
|
34
|
+
fatal(`Target does not contain a .squad/ directory: ${absoluteTeam}`);
|
|
35
|
+
}
|
|
36
|
+
// Ensure .squad/ exists locally
|
|
37
|
+
const squadDir = path.join(projectDir, '.squad');
|
|
38
|
+
fs.mkdirSync(squadDir, { recursive: true });
|
|
39
|
+
// Compute relative path from project root to team repo
|
|
40
|
+
const relativePath = path.relative(projectDir, absoluteTeam);
|
|
41
|
+
const config = {
|
|
42
|
+
version: 1,
|
|
43
|
+
teamRoot: relativePath,
|
|
44
|
+
projectKey: null,
|
|
45
|
+
};
|
|
46
|
+
fs.writeFileSync(path.join(squadDir, 'config.json'), JSON.stringify(config, null, 2) + '\n', 'utf-8');
|
|
47
|
+
console.log(`✅ Linked to team root: ${relativePath}`);
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=link.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link.js","sourceRoot":"","sources":["../../../src/cli/commands/link.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE1C;;;;;GAKG;AACH,MAAM,UAAU,OAAO,CAAC,UAAkB,EAAE,YAAoB;IAC9D,iDAAiD;IACjD,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;IAE5D,6BAA6B;IAC7B,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QACjC,KAAK,CAAC,+BAA+B,YAAY,EAAE,CAAC,CAAC;IACvD,CAAC;IAED,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;QAC7C,KAAK,CAAC,mCAAmC,YAAY,EAAE,CAAC,CAAC;IAC3D,CAAC;IAED,gEAAgE;IAChE,MAAM,QAAQ,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC;IAClE,MAAM,SAAS,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC,CAAC;IACrE,IAAI,CAAC,QAAQ,IAAI,CAAC,SAAS,EAAE,CAAC;QAC5B,KAAK,CAAC,gDAAgD,YAAY,EAAE,CAAC,CAAC;IACxE,CAAC;IAED,gCAAgC;IAChC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IACjD,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE5C,uDAAuD;IACvD,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;IAE7D,MAAM,MAAM,GAAG;QACb,OAAO,EAAE,CAAC;QACV,QAAQ,EAAE,YAAY;QACtB,UAAU,EAAE,IAAI;KACjB,CAAC;IAEF,EAAE,CAAC,aAAa,CACd,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,EAClC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EACtC,OAAO,CACR,CAAC;IAEF,OAAO,CAAC,GAAG,CAAC,0BAA0B,YAAY,EAAE,CAAC,CAAC;AACxD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/plugin.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/plugin.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAiBH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,WAAW,EAAE,CAAC;CAC7B;AAID,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAgJ3E"}
|
|
@@ -7,6 +7,7 @@ import { existsSync } from 'node:fs';
|
|
|
7
7
|
import { join } from 'node:path';
|
|
8
8
|
import { execFile } from 'node:child_process';
|
|
9
9
|
import { promisify } from 'node:util';
|
|
10
|
+
import { TIMEOUTS } from '@bradygaster/squad-sdk';
|
|
10
11
|
import { success, info, DIM, BOLD, RESET } from '../core/output.js';
|
|
11
12
|
import { fatal } from '../core/errors.js';
|
|
12
13
|
import { detectSquadDir } from '../core/detect-squad-dir.js';
|
|
@@ -112,7 +113,7 @@ export async function runPlugin(dest, args) {
|
|
|
112
113
|
// Browse the marketplace repo for plugins using gh CLI
|
|
113
114
|
let entries;
|
|
114
115
|
try {
|
|
115
|
-
const { stdout } = await execFileAsync('gh', ['api', `repos/${marketplace.source}/contents`, '--jq', '[.[] | select(.type == "dir") | .name]'], { timeout:
|
|
116
|
+
const { stdout } = await execFileAsync('gh', ['api', `repos/${marketplace.source}/contents`, '--jq', '[.[] | select(.type == "dir") | .name]'], { timeout: TIMEOUTS.PLUGIN_FETCH_MS });
|
|
116
117
|
entries = JSON.parse(stdout.trim());
|
|
117
118
|
}
|
|
118
119
|
catch (err) {
|