squadrant 0.11.1 → 0.11.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.js +161 -47
- package/dist/index.js.map +1 -1
- package/dist/squadrantd.js +2 -2
- package/dist/squadrantd.js.map +1 -1
- package/package.json +1 -1
- package/scripts/migrate-to-squadrant.sh +49 -23
package/README.md
CHANGED
|
@@ -129,7 +129,7 @@ Six internal packages in a one-way dependency DAG. All are private (not publishe
|
|
|
129
129
|
- `dist/index.js` — CLI bin (`squadrant` command), entry: `packages/cli/src/index.ts`
|
|
130
130
|
- `dist/squadrantd.js` — daemon process, entry: `packages/cli/src/daemon-host.ts`
|
|
131
131
|
|
|
132
|
-
See the [architecture diagram](docs/diagrams/2026-06-18-
|
|
132
|
+
See the [architecture diagram](docs/diagrams/2026-06-18-squadrant-monorepo-architecture.html) for a visual overview.
|
|
133
133
|
|
|
134
134
|
## Architecture
|
|
135
135
|
|
package/dist/index.js
CHANGED
|
@@ -428,13 +428,13 @@ var init_compat_manifest = __esm({
|
|
|
428
428
|
"packages/shared/dist/lib/compat-manifest.js"() {
|
|
429
429
|
compatManifest = {
|
|
430
430
|
tools: {
|
|
431
|
-
cmux: { min: "0.64.0", lastVerified: "0.64.
|
|
431
|
+
cmux: { min: "0.64.0", lastVerified: "0.64.17" },
|
|
432
432
|
claude: { min: "2.1.32" },
|
|
433
433
|
node: { min: "18.0.0", lastVerified: "24.6.0" },
|
|
434
434
|
// presence-checked; no floor enforced yet
|
|
435
435
|
codex: { lastVerified: "0.139.0" },
|
|
436
436
|
gemini: { lastVerified: "0.38.2" },
|
|
437
|
-
opencode: { lastVerified: "1.17.
|
|
437
|
+
opencode: { lastVerified: "1.17.9" }
|
|
438
438
|
}
|
|
439
439
|
};
|
|
440
440
|
}
|
|
@@ -4902,7 +4902,8 @@ function healthRow(c, now) {
|
|
|
4902
4902
|
function printServiceHealth(rows, now = Date.now()) {
|
|
4903
4903
|
console.log(chalk2.bold("\nService Health\n"));
|
|
4904
4904
|
if (rows == null) {
|
|
4905
|
-
console.log(` ${chalk2.red("\u2718")} daemon unreachable \u2014 squadrant liveness is unknown
|
|
4905
|
+
console.log(` ${chalk2.red("\u2718")} daemon unreachable \u2014 squadrant liveness is unknown`);
|
|
4906
|
+
console.log(` ${chalk2.cyan("\u2192")} ${chalk2.dim("Run: squadrant heal daemon")}`);
|
|
4906
4907
|
return;
|
|
4907
4908
|
}
|
|
4908
4909
|
if (rows.length === 0) {
|
|
@@ -4983,29 +4984,61 @@ function tryGetVersion(cmd) {
|
|
|
4983
4984
|
return "";
|
|
4984
4985
|
}
|
|
4985
4986
|
}
|
|
4986
|
-
function check(label, pass) {
|
|
4987
|
+
function check(label, pass, hint) {
|
|
4987
4988
|
const icon = pass ? chalk3.green("\u2714 PASS") : chalk3.red("\u2718 FAIL");
|
|
4988
4989
|
console.log(` ${icon} ${label}`);
|
|
4990
|
+
if (!pass && hint) {
|
|
4991
|
+
console.log(` ${chalk3.cyan("\u2192")} ${chalk3.dim(hint)}`);
|
|
4992
|
+
}
|
|
4989
4993
|
return pass;
|
|
4990
4994
|
}
|
|
4991
4995
|
var doctorCommand = new Command("doctor").description("Check system health and prerequisites").action(async () => {
|
|
4992
4996
|
console.log(chalk3.bold("\nSquadrant Doctor\n"));
|
|
4993
4997
|
const results = [];
|
|
4994
|
-
results.push(check(
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
+
results.push(check(
|
|
4999
|
+
"Claude Code installed",
|
|
5000
|
+
commandExists("claude"),
|
|
5001
|
+
"Install from: https://claude.ai/code"
|
|
5002
|
+
));
|
|
5003
|
+
results.push(check(
|
|
5004
|
+
`Claude Code version >= ${compatManifest.tools.claude.min}`,
|
|
5005
|
+
claudeVersionOk(),
|
|
5006
|
+
`Update Claude Code to >= ${compatManifest.tools.claude.min}`
|
|
5007
|
+
));
|
|
5008
|
+
results.push(check(
|
|
5009
|
+
"Obsidian installed",
|
|
5010
|
+
commandExists("obsidian") || fs13.existsSync("/Applications/Obsidian.app"),
|
|
5011
|
+
"Install from: https://obsidian.md"
|
|
5012
|
+
));
|
|
5013
|
+
results.push(check(
|
|
5014
|
+
"Node.js >= 18",
|
|
5015
|
+
nodeVersionOk(),
|
|
5016
|
+
"Install from: https://nodejs.org"
|
|
5017
|
+
));
|
|
4998
5018
|
results.push(
|
|
4999
5019
|
check(
|
|
5000
5020
|
"Agent Teams enabled (CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1)",
|
|
5001
|
-
settingsHaveAgentTeams()
|
|
5021
|
+
settingsHaveAgentTeams(),
|
|
5022
|
+
"Run: squadrant init (enables automatically), or add to shell profile: export CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1"
|
|
5002
5023
|
)
|
|
5003
5024
|
);
|
|
5004
|
-
results.push(check(
|
|
5025
|
+
results.push(check(
|
|
5026
|
+
"Plugin: superpowers",
|
|
5027
|
+
pluginInstalled("superpowers@claude-plugins-official"),
|
|
5028
|
+
"In Claude Code, run: /plugin marketplace add superpowers"
|
|
5029
|
+
));
|
|
5005
5030
|
results.push(
|
|
5006
|
-
check(
|
|
5031
|
+
check(
|
|
5032
|
+
"Plugin: claude-mem",
|
|
5033
|
+
pluginInstalled("claude-mem@thedotmack"),
|
|
5034
|
+
"In Claude Code, run: /plugin marketplace add thedotmack/claude-mem"
|
|
5035
|
+
)
|
|
5007
5036
|
);
|
|
5008
|
-
results.push(check(
|
|
5037
|
+
results.push(check(
|
|
5038
|
+
"Plugin: context7",
|
|
5039
|
+
pluginInstalled("context7@claude-plugins-official"),
|
|
5040
|
+
"In Claude Code, run: /plugin marketplace add context7"
|
|
5041
|
+
));
|
|
5009
5042
|
const config = loadConfig();
|
|
5010
5043
|
const runtimes = new RuntimeRegistry({ cmux: createCmuxDriver() });
|
|
5011
5044
|
const probeResults = await runtimes.probeAll();
|
|
@@ -5013,7 +5046,8 @@ var doctorCommand = new Command("doctor").description("Check system health and p
|
|
|
5013
5046
|
const globalProbe = probeResults[globalRuntimeName];
|
|
5014
5047
|
results.push(check(
|
|
5015
5048
|
`Runtime '${globalRuntimeName}' installed`,
|
|
5016
|
-
!!globalProbe?.installed
|
|
5049
|
+
!!globalProbe?.installed,
|
|
5050
|
+
globalRuntimeName === "cmux" ? "Install: npm install -g cmux or download from https://cmux.dev" : void 0
|
|
5017
5051
|
));
|
|
5018
5052
|
const overrides = /* @__PURE__ */ new Set();
|
|
5019
5053
|
for (const proj of Object.values(config.projects)) {
|
|
@@ -5031,7 +5065,8 @@ var doctorCommand = new Command("doctor").description("Check system health and p
|
|
|
5031
5065
|
const hubProbe = await hubDriver.probe();
|
|
5032
5066
|
results.push(check(
|
|
5033
5067
|
`Workspace '${config.workspace ?? "obsidian"}' \u2014 hub reachable`,
|
|
5034
|
-
hubProbe.installed && hubProbe.rootExists
|
|
5068
|
+
hubProbe.installed && hubProbe.rootExists,
|
|
5069
|
+
"Run: squadrant init to scaffold the hub vault"
|
|
5035
5070
|
));
|
|
5036
5071
|
for (const [name] of Object.entries(config.projects)) {
|
|
5037
5072
|
const spokeDriver = workspaces.forProject(name, config);
|
|
@@ -5081,7 +5116,8 @@ var doctorCommand = new Command("doctor").description("Check system health and p
|
|
|
5081
5116
|
"Squadrant config exists",
|
|
5082
5117
|
fs13.existsSync(
|
|
5083
5118
|
process.env.SQUADRANT_CONFIG || `${process.env.HOME}/.config/squadrant/config.json`
|
|
5084
|
-
)
|
|
5119
|
+
),
|
|
5120
|
+
"Run: squadrant init"
|
|
5085
5121
|
)
|
|
5086
5122
|
);
|
|
5087
5123
|
const passed = results.filter(Boolean).length;
|
|
@@ -5151,10 +5187,12 @@ ${passed === total ? chalk3.green("All checks passed") : chalk3.yellow(`${passed
|
|
|
5151
5187
|
init_dist();
|
|
5152
5188
|
init_dist3();
|
|
5153
5189
|
init_dist();
|
|
5190
|
+
init_dist4();
|
|
5154
5191
|
import { Command as Command2 } from "commander";
|
|
5155
5192
|
import fs14 from "fs";
|
|
5156
5193
|
import path17 from "path";
|
|
5157
5194
|
import os8 from "os";
|
|
5195
|
+
import readline from "readline";
|
|
5158
5196
|
import chalk4 from "chalk";
|
|
5159
5197
|
function findPackageRoot() {
|
|
5160
5198
|
let dir = path17.dirname(new URL(import.meta.url).pathname);
|
|
@@ -5176,50 +5214,82 @@ function copyDirRecursive(src, dest) {
|
|
|
5176
5214
|
}
|
|
5177
5215
|
}
|
|
5178
5216
|
}
|
|
5179
|
-
|
|
5217
|
+
function stepHeader(n, total, label) {
|
|
5218
|
+
console.log(chalk4.bold(`
|
|
5219
|
+
${n}/${total} ${label}`));
|
|
5220
|
+
}
|
|
5221
|
+
function promptLine(question) {
|
|
5222
|
+
return new Promise((resolve3) => {
|
|
5223
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
5224
|
+
rl.question(question, (answer) => {
|
|
5225
|
+
rl.close();
|
|
5226
|
+
resolve3(answer.trim());
|
|
5227
|
+
});
|
|
5228
|
+
});
|
|
5229
|
+
}
|
|
5230
|
+
var initCommand = new Command2("init").description("Guided first-time setup: hub vault, agents, plugins, projects (re-run-safe)").option("--hub <path>", "Hub vault path", "~/squadrant-hub").action(async (opts) => {
|
|
5180
5231
|
const hubPath = resolveHome(opts.hub);
|
|
5181
5232
|
const pkgRoot = findPackageRoot();
|
|
5182
5233
|
const configDir = path17.join(os8.homedir(), ".config", "squadrant");
|
|
5234
|
+
const isTTY = process.stdin.isTTY === true;
|
|
5183
5235
|
console.log(chalk4.bold("\nSquadrant Init\n"));
|
|
5184
|
-
|
|
5236
|
+
if (!isTTY) {
|
|
5237
|
+
console.log(" Run these steps to get started:\n");
|
|
5238
|
+
console.log(chalk4.bold(" 1/5 Hub vault"));
|
|
5239
|
+
console.log(chalk4.cyan(` squadrant init --hub ${opts.hub}`));
|
|
5240
|
+
console.log(chalk4.bold("\n 2/5 Agent + projection setup"));
|
|
5241
|
+
console.log(" (handled automatically by: " + chalk4.cyan("squadrant init") + ")");
|
|
5242
|
+
console.log(chalk4.bold("\n 3/5 Plugins \u2014 open Claude Code and run:"));
|
|
5243
|
+
console.log(chalk4.cyan(" /plugin marketplace add superpowers"));
|
|
5244
|
+
console.log(chalk4.cyan(" /plugin marketplace add thedotmack/claude-mem"));
|
|
5245
|
+
console.log(chalk4.cyan(" /plugin marketplace add context7"));
|
|
5246
|
+
console.log(chalk4.bold("\n 4/5 Register first project"));
|
|
5247
|
+
console.log(chalk4.cyan(" squadrant projects add <name> <path>"));
|
|
5248
|
+
console.log(chalk4.bold("\n 5/5 Telegram (optional)"));
|
|
5249
|
+
console.log(chalk4.cyan(" squadrant telegram setup"));
|
|
5250
|
+
console.log(chalk4.bold("\n Then:"));
|
|
5251
|
+
console.log(chalk4.cyan(" squadrant launch <projectname>\n"));
|
|
5252
|
+
return;
|
|
5253
|
+
}
|
|
5254
|
+
const wsRegistry = new WorkspaceRegistry({ obsidian: createObsidianDriver });
|
|
5185
5255
|
try {
|
|
5186
5256
|
if (fs14.existsSync(DEFAULT_CONFIG_PATH)) {
|
|
5187
5257
|
const existing = JSON.parse(fs14.readFileSync(DEFAULT_CONFIG_PATH, "utf-8"));
|
|
5188
|
-
|
|
5189
|
-
registry.get(wsName);
|
|
5258
|
+
wsRegistry.get(existing.workspace ?? "obsidian");
|
|
5190
5259
|
}
|
|
5191
5260
|
} catch (err) {
|
|
5192
5261
|
console.log(chalk4.red(` \u2718 ${err.message}`));
|
|
5193
5262
|
return;
|
|
5194
5263
|
}
|
|
5264
|
+
stepHeader(1, 5, "Hub vault");
|
|
5195
5265
|
if (fs14.existsSync(DEFAULT_CONFIG_PATH)) {
|
|
5196
|
-
console.log(chalk4.yellow("
|
|
5266
|
+
console.log(chalk4.yellow(" \u26A0 Config already exists, skipping creation"));
|
|
5197
5267
|
} else {
|
|
5198
5268
|
const config = getDefaultConfig();
|
|
5199
5269
|
config.hubVault = hubPath;
|
|
5200
5270
|
saveConfig(config);
|
|
5201
|
-
console.log(chalk4.green(`
|
|
5271
|
+
console.log(chalk4.green(` \u2714 Config created at ${DEFAULT_CONFIG_PATH}`));
|
|
5202
5272
|
}
|
|
5203
5273
|
const hubTemplate = path17.join(pkgRoot, "obsidian", "hub");
|
|
5204
5274
|
if (fs14.existsSync(hubPath)) {
|
|
5205
|
-
console.log(chalk4.yellow(`
|
|
5275
|
+
console.log(chalk4.yellow(` \u26A0 Hub vault already exists at ${hubPath}`));
|
|
5206
5276
|
} else if (fs14.existsSync(hubTemplate)) {
|
|
5207
5277
|
copyDirRecursive(hubTemplate, hubPath);
|
|
5208
|
-
console.log(chalk4.green(`
|
|
5278
|
+
console.log(chalk4.green(` \u2714 Hub vault scaffolded at ${hubPath}`));
|
|
5209
5279
|
} else {
|
|
5210
5280
|
fs14.mkdirSync(hubPath, { recursive: true });
|
|
5211
|
-
console.log(chalk4.yellow(`
|
|
5281
|
+
console.log(chalk4.yellow(` \u26A0 Hub template not found; created empty directory at ${hubPath}`));
|
|
5212
5282
|
}
|
|
5213
5283
|
const hubDashboardSrc = path17.join(pkgRoot, "obsidian", "hub", "dashboard.md");
|
|
5214
5284
|
const hubDashboardDest = path17.join(hubPath, "dashboard.md");
|
|
5215
5285
|
if (fs14.existsSync(hubDashboardSrc)) {
|
|
5216
5286
|
fs14.copyFileSync(hubDashboardSrc, hubDashboardDest);
|
|
5217
|
-
console.log(chalk4.green(`
|
|
5287
|
+
console.log(chalk4.green(` \u2714 Dashboard refreshed`));
|
|
5218
5288
|
}
|
|
5219
|
-
|
|
5220
|
-
fs14.mkdirSync(projectsDir, { recursive: true });
|
|
5289
|
+
fs14.mkdirSync(path17.join(hubPath, "projects"), { recursive: true });
|
|
5221
5290
|
ensureRuntimeSynced({ sourceRoot: pkgRoot, runtimeRoot: configDir });
|
|
5222
|
-
console.log(chalk4.green(`
|
|
5291
|
+
console.log(chalk4.green(` \u2714 Runtime assets synced to ${configDir}`));
|
|
5292
|
+
stepHeader(2, 5, "Agent + projection setup");
|
|
5223
5293
|
const settingsPath = path17.join(os8.homedir(), ".claude", "settings.json");
|
|
5224
5294
|
try {
|
|
5225
5295
|
let settings = {};
|
|
@@ -5231,29 +5301,70 @@ var initCommand = new Command2("init").description("First-time setup: scaffold h
|
|
|
5231
5301
|
settings.env = { ...env, CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS: "1" };
|
|
5232
5302
|
fs14.mkdirSync(path17.dirname(settingsPath), { recursive: true });
|
|
5233
5303
|
fs14.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
5234
|
-
console.log(chalk4.green("
|
|
5304
|
+
console.log(chalk4.green(" \u2714 Agent Teams enabled in ~/.claude/settings.json"));
|
|
5235
5305
|
} else {
|
|
5236
|
-
console.log(chalk4.green("
|
|
5306
|
+
console.log(chalk4.green(" \u2714 Agent Teams already enabled"));
|
|
5237
5307
|
}
|
|
5238
5308
|
} catch {
|
|
5239
|
-
console.log(chalk4.yellow("
|
|
5309
|
+
console.log(chalk4.yellow(" \u26A0 Could not update ~/.claude/settings.json"));
|
|
5310
|
+
console.log(chalk4.dim(" Add manually to shell profile: export CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1"));
|
|
5240
5311
|
}
|
|
5241
|
-
|
|
5242
|
-
|
|
5243
|
-
|
|
5244
|
-
|
|
5245
|
-
|
|
5246
|
-
|
|
5247
|
-
|
|
5248
|
-
|
|
5249
|
-
|
|
5250
|
-
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
5254
|
-
|
|
5255
|
-
|
|
5312
|
+
try {
|
|
5313
|
+
const projRegistry = new ProjectionRegistry({
|
|
5314
|
+
cursor: createCursorEmitter,
|
|
5315
|
+
codex: createCodexEmitter,
|
|
5316
|
+
gemini: createGeminiEmitter,
|
|
5317
|
+
opencode: createOpencodeEmitter
|
|
5318
|
+
});
|
|
5319
|
+
const workspace = createObsidianDriver({ root: process.cwd() });
|
|
5320
|
+
const source = await readUserLevelSource(workspace, { pkgRoot });
|
|
5321
|
+
for (const name of projRegistry.list()) {
|
|
5322
|
+
const emitter = projRegistry.get(name);
|
|
5323
|
+
for (const dest of emitter.destinations("user")) {
|
|
5324
|
+
const result = await emitter.emit(source, dest);
|
|
5325
|
+
if (result.written) {
|
|
5326
|
+
console.log(chalk4.green(` \u2714 ${name} \u2192 ${dest.path}`));
|
|
5327
|
+
} else {
|
|
5328
|
+
console.log(chalk4.dim(` - ${name} \u2192 ${dest.path} (unchanged)`));
|
|
5329
|
+
}
|
|
5330
|
+
}
|
|
5331
|
+
}
|
|
5332
|
+
} catch (err) {
|
|
5333
|
+
console.log(chalk4.yellow(` \u26A0 Projection emit skipped: ${err.message}`));
|
|
5334
|
+
}
|
|
5335
|
+
stepHeader(3, 5, "Plugins");
|
|
5336
|
+
console.log(" Install these plugins inside Claude Code:\n");
|
|
5337
|
+
console.log(chalk4.cyan(" /plugin marketplace add superpowers"));
|
|
5338
|
+
console.log(chalk4.cyan(" /plugin marketplace add thedotmack/claude-mem"));
|
|
5339
|
+
console.log(chalk4.cyan(" /plugin marketplace add context7\n"));
|
|
5340
|
+
console.log(chalk4.dim(" Squadrant never auto-installs plugins \u2014 open Claude Code and run the commands above."));
|
|
5341
|
+
stepHeader(4, 5, "Register first project");
|
|
5342
|
+
const projectPath = await promptLine(
|
|
5343
|
+
chalk4.cyan(" Absolute path to your first project (Enter to skip): ")
|
|
5344
|
+
);
|
|
5345
|
+
if (projectPath) {
|
|
5346
|
+
const projectName = path17.basename(projectPath);
|
|
5347
|
+
console.log(chalk4.bold(`
|
|
5348
|
+
Run this to register it:`));
|
|
5349
|
+
console.log(chalk4.cyan(` squadrant projects add ${projectName} ${projectPath}
|
|
5350
|
+
`));
|
|
5351
|
+
} else {
|
|
5352
|
+
console.log(chalk4.dim(" Skipped. Register later with:"));
|
|
5353
|
+
console.log(chalk4.cyan(" squadrant projects add <name> <path>"));
|
|
5256
5354
|
}
|
|
5355
|
+
stepHeader(5, 5, "Telegram (optional)");
|
|
5356
|
+
console.log(" Get notified on your phone when crews complete tasks:");
|
|
5357
|
+
console.log(chalk4.cyan(" squadrant telegram setup\n"));
|
|
5358
|
+
let launchTarget = "<projectname>";
|
|
5359
|
+
try {
|
|
5360
|
+
const cfg = loadConfig();
|
|
5361
|
+
const first = Object.keys(cfg.projects)[0];
|
|
5362
|
+
if (first) launchTarget = first;
|
|
5363
|
+
} catch {
|
|
5364
|
+
}
|
|
5365
|
+
console.log(chalk4.bold.green("\n \u2714 You are ready!\n"));
|
|
5366
|
+
console.log(` Run: ${chalk4.cyan(`squadrant launch ${launchTarget}`)}
|
|
5367
|
+
`);
|
|
5257
5368
|
});
|
|
5258
5369
|
|
|
5259
5370
|
// packages/cli/src/commands/projects.ts
|
|
@@ -6226,6 +6337,9 @@ var CREW_PERMISSION_ALLOWLIST = [
|
|
|
6226
6337
|
"Bash(sleep:*)",
|
|
6227
6338
|
"Bash(printf:*)"
|
|
6228
6339
|
];
|
|
6340
|
+
function healStaleCockpitRefs(raw) {
|
|
6341
|
+
return raw.replaceAll("cockpit crew _hook", "squadrant crew _hook").replaceAll(".config/cockpit", ".config/squadrant").replaceAll("cockpit-hub", "squadrant-hub");
|
|
6342
|
+
}
|
|
6229
6343
|
function mergeCrewPermissions(settings) {
|
|
6230
6344
|
const next = structuredClone(settings ?? {});
|
|
6231
6345
|
const permissions = next.permissions ??= {};
|
|
@@ -6239,7 +6353,7 @@ function writePerCrewSettingsLocal(o) {
|
|
|
6239
6353
|
const file = join17(dir, "settings.local.json");
|
|
6240
6354
|
let existing = {};
|
|
6241
6355
|
try {
|
|
6242
|
-
const raw = readFileSync9(file, "utf-8");
|
|
6356
|
+
const raw = healStaleCockpitRefs(readFileSync9(file, "utf-8"));
|
|
6243
6357
|
existing = JSON.parse(raw);
|
|
6244
6358
|
} catch {
|
|
6245
6359
|
}
|