squadrant 0.14.1 → 0.14.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/index.js +194 -125
- package/dist/index.js.map +1 -1
- package/dist/squadrantd.js +202 -40
- package/dist/squadrantd.js.map +1 -1
- package/package.json +1 -1
- package/plugin/skills/captain-ops/SKILL.md +10 -7
package/dist/index.js
CHANGED
|
@@ -1601,11 +1601,11 @@ var init_session_freshness = __esm({
|
|
|
1601
1601
|
});
|
|
1602
1602
|
|
|
1603
1603
|
// packages/core/dist/crew-protocol.js
|
|
1604
|
-
function
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
return
|
|
1604
|
+
function normalizeForSplashMatch(text) {
|
|
1605
|
+
return text.toLowerCase().replace(/…/g, "...").replace(/\s+/g, " ").trim();
|
|
1606
|
+
}
|
|
1607
|
+
function screenHasSplashMarker(screen, marker) {
|
|
1608
|
+
return normalizeForSplashMatch(screen).includes(normalizeForSplashMatch(marker));
|
|
1609
1609
|
}
|
|
1610
1610
|
function buildCompletionProtocol(taskId, project) {
|
|
1611
1611
|
return [
|
|
@@ -2186,15 +2186,16 @@ async function dispatchToSibling(opts) {
|
|
|
2186
2186
|
if (!toCfg) {
|
|
2187
2187
|
throw new Error(`target project '${opts.toProject}' not found in config`);
|
|
2188
2188
|
}
|
|
2189
|
-
|
|
2190
|
-
throw new Error(`cannot dispatch: '${opts.toProject}' (group: ${toCfg.group ?? "none"}) is not in the same group as '${opts.fromProject}' (group: ${fromCfg.group ?? "none"})`);
|
|
2191
|
-
}
|
|
2189
|
+
const sameGroup = !!fromCfg?.group && !!toCfg.group && fromCfg.group === toCfg.group;
|
|
2192
2190
|
if (toCfg.acceptDelegations === false) {
|
|
2193
2191
|
throw new Error(`cannot dispatch to '${opts.toProject}': project has acceptDelegations set to false`);
|
|
2194
2192
|
}
|
|
2195
2193
|
const sockPath = opts.sockPath ?? DEFAULT_SOCK_PATH2;
|
|
2196
2194
|
const alive = await isCaptainAlive(opts.toProject, sockPath);
|
|
2197
2195
|
if (!alive) {
|
|
2196
|
+
if (!sameGroup) {
|
|
2197
|
+
throw new Error(`cannot dispatch to '${opts.toProject}': captain is not running and cross-group dispatch does not auto-boot it. Use 'squadrant ping ${opts.toProject} "<msg>"' or start it manually with 'squadrant launch ${opts.toProject}', then retry.`);
|
|
2198
|
+
}
|
|
2198
2199
|
if (opts.bootCaptain) {
|
|
2199
2200
|
await opts.bootCaptain(opts.toProject);
|
|
2200
2201
|
}
|
|
@@ -2643,10 +2644,16 @@ ${buildCompletionProtocol(rec.id, input.project)}`, preLaunchScreen);
|
|
|
2643
2644
|
const opencodeResult = await deps.sendFirstTurn(pane2, `${firstTurnTask}
|
|
2644
2645
|
|
|
2645
2646
|
${buildCompletionProtocol(rec.id, input.project)}`, preLaunchScreen, {
|
|
2646
|
-
// #235: confirm-on-delivery — sendFirstTurnWhenReady polls until
|
|
2647
|
-
//
|
|
2647
|
+
// #235: confirm-on-delivery — sendFirstTurnWhenReady polls until the idle
|
|
2648
|
+
// splash leaves the screen, re-sending every ~3s to cover slow boots
|
|
2648
2649
|
// without duplicating the task. See crew-pane.ts SPLASH_MAX_CHECKS/EVERY_N.
|
|
2649
|
-
|
|
2650
|
+
// #499: match a stable substring ("ask anything", case/whitespace/ellipsis
|
|
2651
|
+
// -insensitive via screenHasSplashMarker) rather than the exact wording —
|
|
2652
|
+
// opencode's real placeholder rotates through example prompts and uses
|
|
2653
|
+
// three ASCII dots ("Ask anything...") or a longer command hint ("Ask
|
|
2654
|
+
// anything, / for commands, @ for context..."), never the literal
|
|
2655
|
+
// "Ask anything…" (U+2026) this used to hardcode, which never matched.
|
|
2656
|
+
splashMarker: "Ask anything"
|
|
2650
2657
|
});
|
|
2651
2658
|
if (!opencodeResult.delivered) {
|
|
2652
2659
|
process.stderr.write(`\u26A0\uFE0F First turn not delivered for crew '${name}' \u2014 use 'squadrant crew send ${input.project} ${name}' to re-send the task.
|
|
@@ -4146,6 +4153,21 @@ async function confirmedSendToPane(runtime, pane, message) {
|
|
|
4146
4153
|
}
|
|
4147
4154
|
return { delivered: false };
|
|
4148
4155
|
}
|
|
4156
|
+
async function resendCrewFirstTurn(runtime, captainName, project, name, message) {
|
|
4157
|
+
const captain = await runtime.status(captainName);
|
|
4158
|
+
if (!captain)
|
|
4159
|
+
return { delivered: false };
|
|
4160
|
+
const surfaces = await runtime.listSurfaces(captain.id);
|
|
4161
|
+
const want = titleFor(project, name);
|
|
4162
|
+
const pane = surfaces.find((s) => s.title === want);
|
|
4163
|
+
if (!pane)
|
|
4164
|
+
return { delivered: false };
|
|
4165
|
+
const screen = await runtime.readPaneScreen(pane) ?? "";
|
|
4166
|
+
if (!hasCCInputBox(screen) || classifyStartupSurface(screen) !== "idle") {
|
|
4167
|
+
return { delivered: false };
|
|
4168
|
+
}
|
|
4169
|
+
return confirmedSendToPane(runtime, pane, message);
|
|
4170
|
+
}
|
|
4149
4171
|
async function sendFirstTurnWhenReady(runtime, pane, task, preLaunchScreen, acceptanceConfig) {
|
|
4150
4172
|
await new Promise((r) => setTimeout(r, SEND_FIRST_TURN_FLOOR_MS));
|
|
4151
4173
|
const maxPolls = Math.floor((SEND_FIRST_TURN_TIMEOUT_MS - SEND_FIRST_TURN_FLOOR_MS) / POLL_INTERVAL_MS);
|
|
@@ -4153,7 +4175,7 @@ async function sendFirstTurnWhenReady(runtime, pane, task, preLaunchScreen, acce
|
|
|
4153
4175
|
let stable = false;
|
|
4154
4176
|
for (let i = 0; i < maxPolls && !stable; i++) {
|
|
4155
4177
|
const screen = await runtime.readPaneScreen(pane) ?? "";
|
|
4156
|
-
const ready = acceptanceConfig?.splashMarker ?
|
|
4178
|
+
const ready = acceptanceConfig?.splashMarker ? screenHasSplashMarker(screen, acceptanceConfig.splashMarker) : hasCCInputBox(screen) && classifyStartupSurface(screen) === "idle";
|
|
4157
4179
|
if (screen.length > 0 && screen === previousScreen && screen !== preLaunchScreen && ready) {
|
|
4158
4180
|
stable = true;
|
|
4159
4181
|
} else {
|
|
@@ -4163,11 +4185,14 @@ async function sendFirstTurnWhenReady(runtime, pane, task, preLaunchScreen, acce
|
|
|
4163
4185
|
}
|
|
4164
4186
|
const preSendScreen = await runtime.readPaneScreen(pane) ?? "";
|
|
4165
4187
|
if (acceptanceConfig?.splashMarker) {
|
|
4188
|
+
let sawSplash = screenHasSplashMarker(preSendScreen, acceptanceConfig.splashMarker);
|
|
4166
4189
|
await runtime.sendToPane(pane, task);
|
|
4167
4190
|
for (let check2 = 0; check2 < SPLASH_MAX_CHECKS; check2++) {
|
|
4168
4191
|
await new Promise((r) => setTimeout(r, POST_SEND_CHECK_MS));
|
|
4169
4192
|
const afterScreen = await runtime.readPaneScreen(pane) ?? "";
|
|
4170
|
-
if (
|
|
4193
|
+
if (screenHasSplashMarker(afterScreen, acceptanceConfig.splashMarker)) {
|
|
4194
|
+
sawSplash = true;
|
|
4195
|
+
} else if (sawSplash) {
|
|
4171
4196
|
return { delivered: true };
|
|
4172
4197
|
}
|
|
4173
4198
|
if ((check2 + 1) % SPLASH_RESEND_EVERY_N === 0 && check2 < SPLASH_MAX_CHECKS - 1) {
|
|
@@ -4251,6 +4276,7 @@ __export(dist_exports, {
|
|
|
4251
4276
|
isInsideCmux: () => isInsideCmux,
|
|
4252
4277
|
listProjectCrews: () => listProjectCrews,
|
|
4253
4278
|
mapSubToLifecycle: () => mapSubToLifecycle,
|
|
4279
|
+
resendCrewFirstTurn: () => resendCrewFirstTurn,
|
|
4254
4280
|
resolveCaptainWorkspace: () => resolveCaptainWorkspace,
|
|
4255
4281
|
sendFirstTurnWhenReady: () => sendFirstTurnWhenReady
|
|
4256
4282
|
});
|
|
@@ -5713,7 +5739,7 @@ var init_sse_bridge = __esm({
|
|
|
5713
5739
|
const fetchImpl = this.deps.fetchImpl ?? fetch;
|
|
5714
5740
|
const sleep2 = this.deps.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
5715
5741
|
const reconnectMs = this.deps.reconnectMs ?? 500;
|
|
5716
|
-
const maxBoot = this.deps.maxBootAttempts ??
|
|
5742
|
+
const maxBoot = this.deps.maxBootAttempts ?? 240;
|
|
5717
5743
|
const url = `http://127.0.0.1:${port}/event`;
|
|
5718
5744
|
let booted = false;
|
|
5719
5745
|
let bootAttempts = 0;
|
|
@@ -6335,7 +6361,7 @@ var init_dist4 = __esm({
|
|
|
6335
6361
|
// packages/cli/src/index.ts
|
|
6336
6362
|
init_dist();
|
|
6337
6363
|
init_dist2();
|
|
6338
|
-
import { Command as
|
|
6364
|
+
import { Command as Command31 } from "commander";
|
|
6339
6365
|
import { readFileSync as readFileSync13, existsSync as existsSync12, writeFileSync as writeFileSync10 } from "fs";
|
|
6340
6366
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
6341
6367
|
import { dirname as dirname7, join as join26 } from "path";
|
|
@@ -8571,7 +8597,11 @@ function collect(snap) {
|
|
|
8571
8597
|
env.vaults.hub.state,
|
|
8572
8598
|
...env.vaults.spokes.map((s) => s.state),
|
|
8573
8599
|
env.config.parseable.state,
|
|
8574
|
-
env.config.sessions.state
|
|
8600
|
+
// Template-hash drift (env.config.sessions.state) is demoted to soft/info:
|
|
8601
|
+
// projects registered but idle/never-launched legitimately sit on older
|
|
8602
|
+
// template versions, so drift alone is not actionable trouble. Its own
|
|
8603
|
+
// status still renders in the Environment tab; it just no longer rolls up
|
|
8604
|
+
// into envT/overall/masterClass.
|
|
8575
8605
|
...env.config.projectPaths.map((p) => p.state)
|
|
8576
8606
|
];
|
|
8577
8607
|
const daemonStates = [];
|
|
@@ -8591,7 +8621,8 @@ function collect(snap) {
|
|
|
8591
8621
|
undelivered++;
|
|
8592
8622
|
}
|
|
8593
8623
|
for (const p of snap.daemon.tier2.projects) {
|
|
8594
|
-
|
|
8624
|
+
const captain = snap.daemon.tier1.find((c) => c.kind === "captain" && c.project === p.project);
|
|
8625
|
+
if (captain?.state === "alive" && p.delivery.behind > 0)
|
|
8595
8626
|
projStates.push("stale");
|
|
8596
8627
|
if (p.store.corruptCount > 0)
|
|
8597
8628
|
projStates.push("gone");
|
|
@@ -10642,49 +10673,85 @@ var healCommand = new Command23("heal").description("Targeted, idempotent remedi
|
|
|
10642
10673
|
);
|
|
10643
10674
|
|
|
10644
10675
|
// packages/cli/src/commands/group.ts
|
|
10676
|
+
import { Command as Command25 } from "commander";
|
|
10677
|
+
import chalk25 from "chalk";
|
|
10678
|
+
|
|
10679
|
+
// packages/cli/src/commands/dispatch.ts
|
|
10645
10680
|
init_dist();
|
|
10646
10681
|
init_dist2();
|
|
10647
|
-
init_dist2();
|
|
10648
10682
|
import { Command as Command24 } from "commander";
|
|
10649
10683
|
import { execSync as execSync13 } from "child_process";
|
|
10650
10684
|
import chalk24 from "chalk";
|
|
10651
|
-
|
|
10652
|
-
|
|
10653
|
-
|
|
10654
|
-
|
|
10655
|
-
|
|
10656
|
-
|
|
10657
|
-
|
|
10658
|
-
|
|
10659
|
-
|
|
10660
|
-
|
|
10661
|
-
|
|
10662
|
-
|
|
10663
|
-
|
|
10664
|
-
|
|
10665
|
-
|
|
10666
|
-
|
|
10667
|
-
|
|
10668
|
-
|
|
10669
|
-
} catch {
|
|
10670
|
-
throw new Error(`failed to launch captain for '${project}' \u2014 is squadrant installed?`);
|
|
10671
|
-
}
|
|
10672
|
-
}
|
|
10673
|
-
});
|
|
10674
|
-
console.log(chalk24.green(`\u2714 Dispatched to '${toProject}' (task ${result.id.slice(0, 8)})`));
|
|
10675
|
-
console.log(chalk24.dim(` originProject: ${result.originProject ?? "none"}`));
|
|
10676
|
-
console.log(chalk24.dim(" You will be notified when the task settles (done/blocked/failed)."));
|
|
10677
|
-
} catch (e) {
|
|
10678
|
-
console.error(chalk24.red(`\u2718 ${e.message}`));
|
|
10679
|
-
process.exit(1);
|
|
10685
|
+
async function runDispatch(toProject, task, opts) {
|
|
10686
|
+
const fromProject = resolveCurrentProject(loadConfig());
|
|
10687
|
+
if (!fromProject) {
|
|
10688
|
+
throw new Error("Could not determine current project from cwd. Run from inside a registered project directory.");
|
|
10689
|
+
}
|
|
10690
|
+
return dispatchToSibling({
|
|
10691
|
+
fromProject,
|
|
10692
|
+
toProject,
|
|
10693
|
+
task,
|
|
10694
|
+
provider: opts.provider,
|
|
10695
|
+
mode: opts.mode,
|
|
10696
|
+
warmupTimeoutMs: opts.warmupTimeout,
|
|
10697
|
+
bootCaptain: async (project) => {
|
|
10698
|
+
try {
|
|
10699
|
+
execSync13(`squadrant launch ${project}`, { stdio: "ignore", timeout: 15e3 });
|
|
10700
|
+
} catch {
|
|
10701
|
+
throw new Error(`failed to launch captain for '${project}' \u2014 is squadrant installed?`);
|
|
10702
|
+
}
|
|
10680
10703
|
}
|
|
10704
|
+
});
|
|
10705
|
+
}
|
|
10706
|
+
async function dispatchAction(toProject, task, opts) {
|
|
10707
|
+
try {
|
|
10708
|
+
const result = await runDispatch(toProject, task, opts);
|
|
10709
|
+
console.log(chalk24.green(`\u2714 Dispatched to '${toProject}' (task ${result.id.slice(0, 8)})`));
|
|
10710
|
+
console.log(chalk24.dim(` originProject: ${result.originProject ?? "none"}`));
|
|
10711
|
+
console.log(chalk24.dim(" You will be notified when the task settles (done/blocked/failed)."));
|
|
10712
|
+
} catch (e) {
|
|
10713
|
+
console.error(chalk24.red(`\u2718 ${e.message}`));
|
|
10714
|
+
process.exit(1);
|
|
10715
|
+
}
|
|
10716
|
+
}
|
|
10717
|
+
var dispatchCommand = new Command24("dispatch").description("Dispatch a task to any registered project (tracked, reports back on settle)").argument("<project>", "Target project name").argument("<task>", "Task description to dispatch").option("--provider <p>", "claude|opencode|codex", "claude").option("--mode <m>", "headless|interactive", "headless").option("--warmup-timeout <s>", "seconds to wait for target captain to boot (same-group only; default: 120)", (v) => parseInt(v, 10) * 1e3).action(dispatchAction);
|
|
10718
|
+
|
|
10719
|
+
// packages/cli/src/commands/group.ts
|
|
10720
|
+
init_dist2();
|
|
10721
|
+
var groupCommand = new Command25("group").description("Cross-project intra-group operations (Phase 1: dispatch)").addCommand(
|
|
10722
|
+
new Command25("dispatch").description("[DEPRECATED \u2014 use 'squadrant dispatch'] Dispatch a task to a sibling project in the same group").argument("<to-project>", "Target project name").argument("<task>", "Task description to dispatch").option("--provider <p>", "claude|opencode|codex", "claude").option("--mode <m>", "headless|interactive", "headless").option("--warmup-timeout <s>", "seconds to wait for target captain to boot (default: 120)", (v) => parseInt(v, 10) * 1e3).action(async (toProject, task, opts) => {
|
|
10723
|
+
console.error(chalk25.yellow(
|
|
10724
|
+
`\u26A0 'squadrant group dispatch' is deprecated \u2014 use 'squadrant dispatch <project> "<task>"' instead.`
|
|
10725
|
+
));
|
|
10726
|
+
await dispatchAction(toProject, task, opts);
|
|
10681
10727
|
})
|
|
10682
10728
|
);
|
|
10683
10729
|
|
|
10730
|
+
// packages/cli/src/commands/ping.ts
|
|
10731
|
+
init_dist();
|
|
10732
|
+
import { Command as Command26 } from "commander";
|
|
10733
|
+
import chalk26 from "chalk";
|
|
10734
|
+
async function runPing(project, message) {
|
|
10735
|
+
const config = loadConfig();
|
|
10736
|
+
const registry = buildRegistry();
|
|
10737
|
+
const resolved = resolveTarget(registry, config, project, false);
|
|
10738
|
+
const ref = await needRef(resolved);
|
|
10739
|
+
await resolved.driver.send(ref, message);
|
|
10740
|
+
}
|
|
10741
|
+
var pingCommand = new Command26("ping").description("Fire-and-forget: deliver a message into a registered project's captain pane (no tracked task, no report-back)").argument("<project>", "Target project name (must be registered)").argument("<message>", "Message to deliver").action(async (project, message) => {
|
|
10742
|
+
try {
|
|
10743
|
+
await runPing(project, message);
|
|
10744
|
+
console.log(chalk26.green(`\u2714 Pinged '${project}'`));
|
|
10745
|
+
} catch (err) {
|
|
10746
|
+
console.error(chalk26.red(err.message));
|
|
10747
|
+
process.exit(1);
|
|
10748
|
+
}
|
|
10749
|
+
});
|
|
10750
|
+
|
|
10684
10751
|
// packages/cli/src/commands/cmux.ts
|
|
10685
10752
|
init_dist();
|
|
10686
|
-
import { Command as
|
|
10687
|
-
import
|
|
10753
|
+
import { Command as Command27 } from "commander";
|
|
10754
|
+
import chalk27 from "chalk";
|
|
10688
10755
|
async function runCmuxAutoconfig(opts) {
|
|
10689
10756
|
const { json, stdout, stderr } = opts;
|
|
10690
10757
|
let r;
|
|
@@ -10703,19 +10770,19 @@ async function runCmuxAutoconfig(opts) {
|
|
|
10703
10770
|
stdout.write(`wrote cmux automation config \u2192 ${r.configPath}
|
|
10704
10771
|
`);
|
|
10705
10772
|
} else {
|
|
10706
|
-
stdout.write(
|
|
10773
|
+
stdout.write(chalk27.dim(`cmux automation config already in place (${r.configPath})
|
|
10707
10774
|
`));
|
|
10708
10775
|
}
|
|
10709
10776
|
if (r.verdict === "reachable") {
|
|
10710
|
-
stdout.write(
|
|
10777
|
+
stdout.write(chalk27.green("\u2714 daemon-direct delivery is reachable \u2014 cmux control socket accepts the daemon\n"));
|
|
10711
10778
|
return 0;
|
|
10712
10779
|
}
|
|
10713
10780
|
if (r.needsRestart) {
|
|
10714
10781
|
stdout.write(
|
|
10715
|
-
|
|
10782
|
+
chalk27.yellow("\u26A0 cmux is still on the old socket mode \u2014 restart cmux to enable daemon-direct delivery.\n")
|
|
10716
10783
|
);
|
|
10717
10784
|
if (r.promptedThisRun) {
|
|
10718
|
-
stdout.write(
|
|
10785
|
+
stdout.write(chalk27.dim(" (one-time prompt \u2014 you won't be nagged again)\n"));
|
|
10719
10786
|
}
|
|
10720
10787
|
return 2;
|
|
10721
10788
|
}
|
|
@@ -10724,8 +10791,8 @@ async function runCmuxAutoconfig(opts) {
|
|
|
10724
10791
|
);
|
|
10725
10792
|
return 1;
|
|
10726
10793
|
}
|
|
10727
|
-
var cmuxCommand = new
|
|
10728
|
-
new
|
|
10794
|
+
var cmuxCommand = new Command27("cmux").description("cmux integration helpers").addCommand(
|
|
10795
|
+
new Command27("autoconfig").description(
|
|
10729
10796
|
"Write the cmux automation socket config and probe whether daemon-direct\ndelivery is reachable. Idempotent; prompts once if a cmux restart is needed."
|
|
10730
10797
|
).option("--json", "output machine-readable JSON (exit 0=reachable, 1=unknown, 2=restart-needed)").action(async (opts) => {
|
|
10731
10798
|
const code = await runCmuxAutoconfig({
|
|
@@ -10741,8 +10808,8 @@ var cmuxCommand = new Command25("cmux").description("cmux integration helpers").
|
|
|
10741
10808
|
init_dist();
|
|
10742
10809
|
import fs26 from "fs";
|
|
10743
10810
|
import path28 from "path";
|
|
10744
|
-
import { Command as
|
|
10745
|
-
import
|
|
10811
|
+
import { Command as Command28 } from "commander";
|
|
10812
|
+
import chalk28 from "chalk";
|
|
10746
10813
|
var VALID_EFFORTS = ["max", "balance", "low"];
|
|
10747
10814
|
var EFFORT_MEANING = {
|
|
10748
10815
|
max: "tokens are plentiful \u2014 bias crew spawns toward claude/opus",
|
|
@@ -10786,22 +10853,22 @@ async function notifyCaptainsOfEffort(effort, config, driver, cwd = process.cwd(
|
|
|
10786
10853
|
}
|
|
10787
10854
|
}
|
|
10788
10855
|
}
|
|
10789
|
-
var effortCommand = new
|
|
10856
|
+
var effortCommand = new Command28("effort").description("Get or set the global crew tokenomics dial (max | balance | low)").argument("[value]", "effort level to set: max | balance | low").action(async (value) => {
|
|
10790
10857
|
if (value === void 0) {
|
|
10791
10858
|
const { effort: effort2, description } = runEffortGet();
|
|
10792
|
-
console.log(
|
|
10793
|
-
console.log(
|
|
10859
|
+
console.log(chalk28.bold("Current effort:"), chalk28.cyan(effort2));
|
|
10860
|
+
console.log(chalk28.dim(EFFORT_MEANING[effort2]));
|
|
10794
10861
|
return;
|
|
10795
10862
|
}
|
|
10796
10863
|
try {
|
|
10797
10864
|
runEffortSet(value);
|
|
10798
10865
|
} catch (err) {
|
|
10799
|
-
console.error(
|
|
10866
|
+
console.error(chalk28.red(err.message));
|
|
10800
10867
|
process.exit(1);
|
|
10801
10868
|
}
|
|
10802
10869
|
const effort = value;
|
|
10803
|
-
console.log(
|
|
10804
|
-
console.log(
|
|
10870
|
+
console.log(chalk28.green(`\u2714 effort \u2192 ${effort}`));
|
|
10871
|
+
console.log(chalk28.dim(EFFORT_MEANING[effort]));
|
|
10805
10872
|
try {
|
|
10806
10873
|
const { createCmuxDriver: createCmuxDriver2, RuntimeRegistry: RuntimeRegistry2 } = await Promise.resolve().then(() => (init_dist3(), dist_exports));
|
|
10807
10874
|
const config = loadConfig();
|
|
@@ -10809,7 +10876,7 @@ var effortCommand = new Command26("effort").description("Get or set the global c
|
|
|
10809
10876
|
const driver = registry.global(config);
|
|
10810
10877
|
await notifyCaptainsOfEffort(effort, config, driver);
|
|
10811
10878
|
} catch {
|
|
10812
|
-
console.log(
|
|
10879
|
+
console.log(chalk28.dim("(no running captain detected \u2014 change applies on next launch)"));
|
|
10813
10880
|
}
|
|
10814
10881
|
});
|
|
10815
10882
|
|
|
@@ -10818,8 +10885,8 @@ init_dist();
|
|
|
10818
10885
|
init_dist2();
|
|
10819
10886
|
import { join as join24, dirname as dirname6 } from "path";
|
|
10820
10887
|
import { emitKeypressEvents } from "readline";
|
|
10821
|
-
import { Command as
|
|
10822
|
-
import
|
|
10888
|
+
import { Command as Command29 } from "commander";
|
|
10889
|
+
import chalk29 from "chalk";
|
|
10823
10890
|
function defaultStateRoot() {
|
|
10824
10891
|
return join24(dirname6(DEFAULT_CONFIG_PATH), "state");
|
|
10825
10892
|
}
|
|
@@ -10866,11 +10933,11 @@ async function questionYesNo(prompt) {
|
|
|
10866
10933
|
});
|
|
10867
10934
|
});
|
|
10868
10935
|
}
|
|
10869
|
-
var telegramCommand = new
|
|
10936
|
+
var telegramCommand = new Command29("telegram").description("Two-way Telegram integration: push crew events to a topic and reply into the captain pane");
|
|
10870
10937
|
telegramCommand.command("status").description("Show Telegram config and linked projects").action(() => {
|
|
10871
10938
|
const { tokenSet, supergroupId, links } = runTelegramStatus({ config: loadConfig(), stateRoot: defaultStateRoot() });
|
|
10872
|
-
console.log(`token: ${tokenSet ?
|
|
10873
|
-
console.log(`supergroup: ${supergroupId ??
|
|
10939
|
+
console.log(`token: ${tokenSet ? chalk29.green("set") : chalk29.yellow("unset")}`);
|
|
10940
|
+
console.log(`supergroup: ${supergroupId ?? chalk29.yellow("unset")}`);
|
|
10874
10941
|
if (links.length === 0) {
|
|
10875
10942
|
console.log("no projects linked");
|
|
10876
10943
|
return;
|
|
@@ -10880,32 +10947,32 @@ telegramCommand.command("status").description("Show Telegram config and linked p
|
|
|
10880
10947
|
telegramCommand.command("link").argument("<project>", "project to bind to a Telegram topic").description("Create (or reuse) a forum topic for a project and bind it").action(async (project) => {
|
|
10881
10948
|
const cfg = loadConfig().telegram;
|
|
10882
10949
|
if (!cfg) {
|
|
10883
|
-
console.error(
|
|
10950
|
+
console.error(chalk29.red("telegram config absent \u2014 add a `telegram` block to ~/.config/squadrant/config.json"));
|
|
10884
10951
|
process.exit(1);
|
|
10885
10952
|
}
|
|
10886
10953
|
const token = cfg.botToken ?? process.env.TELEGRAM_BOT_TOKEN;
|
|
10887
10954
|
if (!token) {
|
|
10888
|
-
console.error(
|
|
10955
|
+
console.error(chalk29.red("no botToken in config and TELEGRAM_BOT_TOKEN is unset"));
|
|
10889
10956
|
process.exit(1);
|
|
10890
10957
|
}
|
|
10891
10958
|
const client = createTelegramClient({ token });
|
|
10892
10959
|
const { topicId, created } = await runTelegramLink({ project, cfg, client, stateRoot: defaultStateRoot() });
|
|
10893
|
-
console.log(
|
|
10960
|
+
console.log(chalk29.green(`${created ? "linked" : "already linked"}: ${project} \u2192 topic ${topicId}`));
|
|
10894
10961
|
});
|
|
10895
10962
|
telegramCommand.command("setup").description("Interactive wizard \u2014 bot token, validate, auto-detect supergroup, write config").option("--reset-token", "force re-entry of the bot token even if one already exists").option("--redetect", "force group re-detection even when a supergroup is already configured").option("--user-id <id>", "allowlist user-id \u2014 enables remote control on a re-run without getUpdates detection", (v) => parseInt(v, 10)).action(async (opts) => {
|
|
10896
10963
|
if (!process.stdin.isTTY) {
|
|
10897
|
-
console.error(
|
|
10964
|
+
console.error(chalk29.red("setup requires a TTY \u2014 pipe input is not supported"));
|
|
10898
10965
|
process.exit(1);
|
|
10899
10966
|
}
|
|
10900
10967
|
console.log();
|
|
10901
|
-
console.log(
|
|
10968
|
+
console.log(chalk29.bold("Telegram setup") + " \u2014 connect squadrant to a Telegram bot for notifications + remote control");
|
|
10902
10969
|
console.log();
|
|
10903
10970
|
console.log("Before you start you need:");
|
|
10904
10971
|
console.log(" 1. A bot token from @BotFather (send /newbot)");
|
|
10905
10972
|
console.log(" 2. A forum supergroup with the bot added as an admin (Topics enabled)");
|
|
10906
10973
|
console.log(" 3. Bot privacy mode set to OFF (@BotFather \u2192 /setprivacy \u2192 Disable)");
|
|
10907
10974
|
console.log();
|
|
10908
|
-
console.log(
|
|
10975
|
+
console.log(chalk29.bold("Step 1/3 \u2014 Bot token"));
|
|
10909
10976
|
const existingCfg = loadConfig().telegram;
|
|
10910
10977
|
const existingToken = existingCfg?.botToken ?? process.env.TELEGRAM_BOT_TOKEN;
|
|
10911
10978
|
const decision = resolveSetupToken(existingToken, { resetToken: opts.resetToken ?? false });
|
|
@@ -10917,67 +10984,67 @@ telegramCommand.command("setup").description("Interactive wizard \u2014 bot toke
|
|
|
10917
10984
|
try {
|
|
10918
10985
|
botUser = await client.getMe();
|
|
10919
10986
|
token = existingToken;
|
|
10920
|
-
console.log(
|
|
10987
|
+
console.log(chalk29.green(`Using existing bot token (@${botUser.username})`));
|
|
10921
10988
|
console.log();
|
|
10922
10989
|
} catch {
|
|
10923
|
-
console.log(
|
|
10990
|
+
console.log(chalk29.yellow("Existing token is invalid \u2014 please enter a new one."));
|
|
10924
10991
|
console.log("Paste your bot token then press Enter (input is hidden):");
|
|
10925
10992
|
token = await questionMasked();
|
|
10926
10993
|
if (!token) {
|
|
10927
|
-
console.error(
|
|
10994
|
+
console.error(chalk29.red("token required"));
|
|
10928
10995
|
process.exit(1);
|
|
10929
10996
|
}
|
|
10930
10997
|
client = createTelegramClient({ token });
|
|
10931
10998
|
try {
|
|
10932
10999
|
botUser = await client.getMe();
|
|
10933
11000
|
} catch (e) {
|
|
10934
|
-
console.error(
|
|
11001
|
+
console.error(chalk29.red(`token rejected: ${e.message}`));
|
|
10935
11002
|
process.exit(1);
|
|
10936
11003
|
}
|
|
10937
|
-
console.log(
|
|
11004
|
+
console.log(chalk29.green(`Connected as @${botUser.username}`));
|
|
10938
11005
|
console.log();
|
|
10939
11006
|
}
|
|
10940
11007
|
} else {
|
|
10941
11008
|
console.log("Paste your bot token then press Enter (input is hidden):");
|
|
10942
11009
|
token = await questionMasked();
|
|
10943
11010
|
if (!token) {
|
|
10944
|
-
console.error(
|
|
11011
|
+
console.error(chalk29.red("token required"));
|
|
10945
11012
|
process.exit(1);
|
|
10946
11013
|
}
|
|
10947
11014
|
client = createTelegramClient({ token });
|
|
10948
11015
|
try {
|
|
10949
11016
|
botUser = await client.getMe();
|
|
10950
11017
|
} catch (e) {
|
|
10951
|
-
console.error(
|
|
11018
|
+
console.error(chalk29.red(`token rejected: ${e.message}`));
|
|
10952
11019
|
process.exit(1);
|
|
10953
11020
|
}
|
|
10954
|
-
console.log(
|
|
11021
|
+
console.log(chalk29.green(`Connected as @${botUser.username}`));
|
|
10955
11022
|
console.log();
|
|
10956
11023
|
}
|
|
10957
|
-
console.log(
|
|
11024
|
+
console.log(chalk29.bold("Step 2/3 \u2014 Supergroup"));
|
|
10958
11025
|
const groupDecision = resolveSetupGroup(existingCfg?.supergroupId, { redetect: opts.redetect ?? false });
|
|
10959
11026
|
let supergroupId;
|
|
10960
11027
|
let detectedUserId;
|
|
10961
11028
|
if (groupDecision === "reuse") {
|
|
10962
11029
|
supergroupId = existingCfg.supergroupId;
|
|
10963
|
-
console.log(
|
|
11030
|
+
console.log(chalk29.green(`Using existing group: ${supergroupId}`));
|
|
10964
11031
|
console.log();
|
|
10965
11032
|
} else {
|
|
10966
11033
|
console.log("Add the bot to your forum supergroup, then send any message in it.");
|
|
10967
|
-
console.log(
|
|
11034
|
+
console.log(chalk29.dim("Waiting for a message (up to 60s)\u2026"));
|
|
10968
11035
|
try {
|
|
10969
11036
|
({ supergroupId, userId: detectedUserId } = await detectGroupAndUser(client, { timeoutMs: 6e4 }));
|
|
10970
11037
|
} catch {
|
|
10971
|
-
console.error(
|
|
10972
|
-
console.error(
|
|
11038
|
+
console.error(chalk29.red("Timed out \u2014 no supergroup message received within 60s."));
|
|
11039
|
+
console.error(chalk29.yellow("Check: bot is an admin in the group \xB7 privacy mode is OFF \xB7 Topics enabled"));
|
|
10973
11040
|
process.exit(1);
|
|
10974
11041
|
}
|
|
10975
|
-
console.log(
|
|
11042
|
+
console.log(chalk29.green(`Found group: ${supergroupId}`));
|
|
10976
11043
|
console.log();
|
|
10977
11044
|
}
|
|
10978
|
-
console.log(
|
|
10979
|
-
console.log(
|
|
10980
|
-
console.log(
|
|
11045
|
+
console.log(chalk29.bold("Step 3/3 \u2014 Remote control + Save"));
|
|
11046
|
+
console.log(chalk29.dim("Remote control enables auto-launching captains and the General command channel"));
|
|
11047
|
+
console.log(chalk29.dim("from your phone \u2014 gated to your Telegram user-id only (fail-closed)."));
|
|
10981
11048
|
const finalUserId = resolveSetupUserId(opts.userId, detectedUserId, defaultStateRoot());
|
|
10982
11049
|
let users;
|
|
10983
11050
|
let remoteControl;
|
|
@@ -10991,32 +11058,32 @@ telegramCommand.command("setup").description("Interactive wizard \u2014 bot toke
|
|
|
10991
11058
|
remoteControl = true;
|
|
10992
11059
|
}
|
|
10993
11060
|
} else if (groupDecision === "detect") {
|
|
10994
|
-
console.log(
|
|
10995
|
-
console.log(
|
|
11061
|
+
console.log(chalk29.yellow("Could not read your user-id from that message \u2014 skipping remote control."));
|
|
11062
|
+
console.log(chalk29.yellow("Re-run with --user-id <id> to enable, or edit telegram.users in config manually."));
|
|
10996
11063
|
printedRemoteControlState = true;
|
|
10997
11064
|
} else {
|
|
10998
11065
|
const existingUsers = existingCfg?.users;
|
|
10999
11066
|
if (existingUsers && existingUsers.length > 0) {
|
|
11000
|
-
console.log(
|
|
11067
|
+
console.log(chalk29.dim(`Remote control: already configured (user-id ${existingUsers[0]}). Use --user-id to update.`));
|
|
11001
11068
|
} else {
|
|
11002
|
-
console.log(
|
|
11069
|
+
console.log(chalk29.dim("Remote control: off. Re-run with --user-id <id> to enable."));
|
|
11003
11070
|
}
|
|
11004
11071
|
printedRemoteControlState = true;
|
|
11005
11072
|
}
|
|
11006
11073
|
writeTelegramConfig(DEFAULT_CONFIG_PATH, { token, supergroupId, users, remoteControl });
|
|
11007
|
-
console.log(
|
|
11074
|
+
console.log(chalk29.green(`Wrote telegram config \u2014 token: ${maskToken(token)} group: ${supergroupId}`));
|
|
11008
11075
|
if (!printedRemoteControlState) {
|
|
11009
11076
|
if (remoteControl) {
|
|
11010
|
-
console.log(
|
|
11077
|
+
console.log(chalk29.green(`Remote control: ON (allowlisted user-id ${users[0]})`));
|
|
11011
11078
|
} else {
|
|
11012
|
-
console.log(
|
|
11079
|
+
console.log(chalk29.dim("Remote control: off (default). Re-run with --user-id <id> to enable."));
|
|
11013
11080
|
}
|
|
11014
11081
|
}
|
|
11015
11082
|
try {
|
|
11016
11083
|
await runRegisterCommands({ client });
|
|
11017
|
-
console.log(
|
|
11084
|
+
console.log(chalk29.dim("Registered the /command menu."));
|
|
11018
11085
|
} catch (e) {
|
|
11019
|
-
console.log(
|
|
11086
|
+
console.log(chalk29.yellow(`command-menu registration skipped: ${e.message}`));
|
|
11020
11087
|
}
|
|
11021
11088
|
const topics = loadState(defaultStateRoot()).topics;
|
|
11022
11089
|
const topicEntries = Object.entries(topics);
|
|
@@ -11025,28 +11092,28 @@ telegramCommand.command("setup").description("Interactive wizard \u2014 bot toke
|
|
|
11025
11092
|
const project = key.slice(0, key.indexOf("::"));
|
|
11026
11093
|
return `${project}\u2192${id}`;
|
|
11027
11094
|
}).join(", ");
|
|
11028
|
-
console.log(
|
|
11095
|
+
console.log(chalk29.dim(`Existing topics: ${summary} (already created \u2014 not recreated)`));
|
|
11029
11096
|
} else {
|
|
11030
|
-
console.log(
|
|
11097
|
+
console.log(chalk29.dim("No project topics yet \u2014 they're created on first delivery or via: squadrant telegram link <project>"));
|
|
11031
11098
|
}
|
|
11032
11099
|
runTelegramPostSetup({});
|
|
11033
11100
|
console.log();
|
|
11034
|
-
console.log(`Next: ${
|
|
11101
|
+
console.log(`Next: ${chalk29.cyan("squadrant telegram link <project>")}`);
|
|
11035
11102
|
});
|
|
11036
11103
|
telegramCommand.command("register-commands").description("Register (or re-register) the bot's / command menu with Telegram").action(async () => {
|
|
11037
11104
|
const cfg = loadConfig().telegram;
|
|
11038
11105
|
if (!cfg) {
|
|
11039
|
-
console.error(
|
|
11106
|
+
console.error(chalk29.red("telegram config absent \u2014 run: squadrant telegram setup"));
|
|
11040
11107
|
process.exit(1);
|
|
11041
11108
|
}
|
|
11042
11109
|
const token = cfg.botToken ?? process.env.TELEGRAM_BOT_TOKEN;
|
|
11043
11110
|
if (!token) {
|
|
11044
|
-
console.error(
|
|
11111
|
+
console.error(chalk29.red("no botToken in config and TELEGRAM_BOT_TOKEN is unset"));
|
|
11045
11112
|
process.exit(1);
|
|
11046
11113
|
}
|
|
11047
11114
|
const client = createTelegramClient({ token });
|
|
11048
11115
|
await runRegisterCommands({ client });
|
|
11049
|
-
console.log(
|
|
11116
|
+
console.log(chalk29.green(`registered ${BOT_COMMANDS.length} bot commands`));
|
|
11050
11117
|
});
|
|
11051
11118
|
telegramCommand.command("notify").argument("[project]", "project to toggle").argument("[state]", "on | off | crew | cap").argument("[value]", "tier for crew (all|alert_only|done_only|none) or on|off for cap").option("--status", "list notification state for all projects").description("Live on|off (state), or crew <tier> / cap <on|off> preference (per-project config)").action(async (project, state, value, opts) => {
|
|
11052
11119
|
const stateRoot = defaultStateRoot();
|
|
@@ -11057,7 +11124,7 @@ telegramCommand.command("notify").argument("[project]", "project to toggle").arg
|
|
|
11057
11124
|
return;
|
|
11058
11125
|
}
|
|
11059
11126
|
for (const r of rows) {
|
|
11060
|
-
console.log(` ${r.project}: ${r.active ?
|
|
11127
|
+
console.log(` ${r.project}: ${r.active ? chalk29.green("on") : chalk29.dim("off (muted)")}`);
|
|
11061
11128
|
}
|
|
11062
11129
|
return;
|
|
11063
11130
|
}
|
|
@@ -11066,53 +11133,53 @@ telegramCommand.command("notify").argument("[project]", "project to toggle").arg
|
|
|
11066
11133
|
const token = tgCfg?.botToken ?? process.env.TELEGRAM_BOT_TOKEN;
|
|
11067
11134
|
if (state === "crew" || state === "cap") {
|
|
11068
11135
|
if (value === void 0) {
|
|
11069
|
-
console.error(
|
|
11136
|
+
console.error(chalk29.red(`usage: squadrant telegram notify <project> ${state} <value>`));
|
|
11070
11137
|
process.exit(1);
|
|
11071
11138
|
}
|
|
11072
11139
|
const resolved2 = resolveNotify(globalNotify, loadProjectOverride(project));
|
|
11073
11140
|
const before2 = { ...resolved2, active: isNotifyActive(stateRoot, project) };
|
|
11074
11141
|
const res = runTelegramNotifyPref({ project, dimension: state, value });
|
|
11075
11142
|
if (!res.ok) {
|
|
11076
|
-
console.error(
|
|
11143
|
+
console.error(chalk29.red(res.message));
|
|
11077
11144
|
process.exit(1);
|
|
11078
11145
|
}
|
|
11079
|
-
console.log(
|
|
11146
|
+
console.log(chalk29.green(`${project} ${state} = ${value}`));
|
|
11080
11147
|
const after2 = state === "crew" ? { ...before2, crew: value } : { ...before2, cap: value === "on" };
|
|
11081
11148
|
if (tgCfg && token) {
|
|
11082
11149
|
const client = createTelegramClient({ token });
|
|
11083
11150
|
const sent = await runNotifyConfirmation({ project, before: before2, after: after2, cfg: tgCfg, client, stateRoot });
|
|
11084
|
-
if (sent) console.log(
|
|
11151
|
+
if (sent) console.log(chalk29.dim(`\u2192 notified ${project} topic`));
|
|
11085
11152
|
}
|
|
11086
11153
|
return;
|
|
11087
11154
|
}
|
|
11088
11155
|
if (state !== "on" && state !== "off") {
|
|
11089
|
-
console.error(
|
|
11156
|
+
console.error(chalk29.red("usage: squadrant telegram notify <project> <on|off|crew <tier>|cap <on|off>>"));
|
|
11090
11157
|
process.exit(1);
|
|
11091
11158
|
}
|
|
11092
11159
|
const resolved = resolveNotify(globalNotify, loadProjectOverride(project));
|
|
11093
11160
|
const before = { ...resolved, active: isNotifyActive(stateRoot, project) };
|
|
11094
11161
|
const after = { ...before, active: state === "on" };
|
|
11095
11162
|
runTelegramNotifySet({ project, active: state === "on", stateRoot });
|
|
11096
|
-
console.log(
|
|
11163
|
+
console.log(chalk29.green(`${project} notifications ${state === "on" ? "ON" : "OFF"}`));
|
|
11097
11164
|
if (tgCfg && token) {
|
|
11098
11165
|
const client = createTelegramClient({ token });
|
|
11099
11166
|
const sent = await runNotifyConfirmation({ project, before, after, cfg: tgCfg, client, stateRoot });
|
|
11100
|
-
if (sent) console.log(
|
|
11167
|
+
if (sent) console.log(chalk29.dim(`\u2192 notified ${project} topic`));
|
|
11101
11168
|
}
|
|
11102
11169
|
});
|
|
11103
11170
|
telegramCommand.command("send").argument("<project>", "project whose topic receives the message").argument("[message...]", "message text (omit to read from stdin)").description("Send a message to a project's linked Telegram topic").action(async (project, messageParts) => {
|
|
11104
11171
|
const cfg = loadConfig().telegram;
|
|
11105
11172
|
if (!cfg) {
|
|
11106
|
-
console.error(
|
|
11173
|
+
console.error(chalk29.red("telegram config absent \u2014 add a `telegram` block to ~/.config/squadrant/config.json"));
|
|
11107
11174
|
process.exit(1);
|
|
11108
11175
|
}
|
|
11109
11176
|
const token = cfg.botToken ?? process.env.TELEGRAM_BOT_TOKEN;
|
|
11110
11177
|
if (!token) {
|
|
11111
|
-
console.error(
|
|
11178
|
+
console.error(chalk29.red("no botToken in config and TELEGRAM_BOT_TOKEN is unset"));
|
|
11112
11179
|
process.exit(1);
|
|
11113
11180
|
}
|
|
11114
11181
|
if (!capAllowed(project, cfg.notify)) {
|
|
11115
|
-
console.log(
|
|
11182
|
+
console.log(chalk29.dim(`${project}: captain messages muted (cap=off) \u2014 not sent`));
|
|
11116
11183
|
return;
|
|
11117
11184
|
}
|
|
11118
11185
|
let message;
|
|
@@ -11125,19 +11192,19 @@ telegramCommand.command("send").argument("<project>", "project whose topic recei
|
|
|
11125
11192
|
for await (const line of rl) lines.push(line);
|
|
11126
11193
|
message = lines.join("\n").trimEnd();
|
|
11127
11194
|
if (!message) {
|
|
11128
|
-
console.error(
|
|
11195
|
+
console.error(chalk29.red("no message provided (stdin was empty)"));
|
|
11129
11196
|
process.exit(1);
|
|
11130
11197
|
}
|
|
11131
11198
|
} else {
|
|
11132
|
-
console.error(
|
|
11199
|
+
console.error(chalk29.red("message required \u2014 pass as argument or pipe via stdin"));
|
|
11133
11200
|
process.exit(1);
|
|
11134
11201
|
}
|
|
11135
11202
|
const client = createTelegramClient({ token });
|
|
11136
11203
|
try {
|
|
11137
11204
|
const { chatId, topicId } = await runTelegramSend({ project, message, cfg, client, stateRoot: defaultStateRoot() });
|
|
11138
|
-
console.log(
|
|
11205
|
+
console.log(chalk29.green(`sent to group ${chatId} topic ${topicId}`));
|
|
11139
11206
|
} catch (e) {
|
|
11140
|
-
console.error(
|
|
11207
|
+
console.error(chalk29.red(e.message));
|
|
11141
11208
|
process.exit(1);
|
|
11142
11209
|
}
|
|
11143
11210
|
});
|
|
@@ -11145,7 +11212,7 @@ telegramCommand.command("send").argument("<project>", "project whose topic recei
|
|
|
11145
11212
|
// packages/cli/src/commands/hooks.ts
|
|
11146
11213
|
init_dist2();
|
|
11147
11214
|
init_dist4();
|
|
11148
|
-
import { Command as
|
|
11215
|
+
import { Command as Command30 } from "commander";
|
|
11149
11216
|
import { join as join25 } from "path";
|
|
11150
11217
|
import { homedir as homedir17 } from "os";
|
|
11151
11218
|
var SOCK4 = join25(homedir17(), ".config", "squadrant", "squadrant.sock");
|
|
@@ -11174,7 +11241,7 @@ function mapHookSub(sub, payload, taskId) {
|
|
|
11174
11241
|
}
|
|
11175
11242
|
}
|
|
11176
11243
|
function hooksCommand() {
|
|
11177
|
-
const hooks = new
|
|
11244
|
+
const hooks = new Command30("hooks").description("(internal) receive lifecycle hook events from agent processes");
|
|
11178
11245
|
hooks.command("claude <sub>", { hidden: true }).description("internal: bridge a NativeHookSource claude hook to squadrantd").action(async (sub) => {
|
|
11179
11246
|
const taskId = process.env.SQUADRANT_CREW_TASK_ID;
|
|
11180
11247
|
const project = process.env.SQUADRANT_CREW_PROJECT;
|
|
@@ -11243,7 +11310,7 @@ if (process.argv[2] !== "config") {
|
|
|
11243
11310
|
if (!process.env.SQUADRANT_DAEMON_SKIP) {
|
|
11244
11311
|
ensureDaemon();
|
|
11245
11312
|
}
|
|
11246
|
-
var program = new
|
|
11313
|
+
var program = new Command31();
|
|
11247
11314
|
program.name("squadrant").description("Multi-project orchestration for your coding agents (Claude, Codex, opencode, Gemini)").version(pkg.version);
|
|
11248
11315
|
program.addCommand(doctorCommand);
|
|
11249
11316
|
program.addCommand(initCommand);
|
|
@@ -11267,6 +11334,8 @@ program.addCommand(codexChatSmokeCommand);
|
|
|
11267
11334
|
program.addCommand(configCommand);
|
|
11268
11335
|
program.addCommand(healCommand);
|
|
11269
11336
|
program.addCommand(groupCommand);
|
|
11337
|
+
program.addCommand(pingCommand);
|
|
11338
|
+
program.addCommand(dispatchCommand);
|
|
11270
11339
|
program.addCommand(cmuxCommand);
|
|
11271
11340
|
program.addCommand(effortCommand);
|
|
11272
11341
|
program.addCommand(telegramCommand);
|