squadrant 0.23.0 → 0.24.0
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 +150 -142
- package/dist/index.js.map +1 -1
- package/dist/squadrantd.js +46 -25
- package/dist/squadrantd.js.map +1 -1
- package/package.json +1 -1
- package/plugin/skills/gate/SKILL.md +8 -0
- package/plugin/skills/set-gate/SKILL.md +66 -0
package/dist/index.js
CHANGED
|
@@ -225,7 +225,12 @@ var init_config = __esm({
|
|
|
225
225
|
|
|
226
226
|
// packages/shared/dist/provider-preset.js
|
|
227
227
|
function isProviderPresetId(v2) {
|
|
228
|
-
return v2 === "a" || v2 === "b" || v2 === "c"
|
|
228
|
+
return v2 === "a" || v2 === "b" || v2 === "c";
|
|
229
|
+
}
|
|
230
|
+
function normalizePresetId(v2) {
|
|
231
|
+
if (v2 === "d")
|
|
232
|
+
return "c";
|
|
233
|
+
return isProviderPresetId(v2) ? v2 : void 0;
|
|
229
234
|
}
|
|
230
235
|
function presetCrewRouting(id) {
|
|
231
236
|
const base = (tier) => {
|
|
@@ -248,17 +253,10 @@ function presetCrewRouting(id) {
|
|
|
248
253
|
{ ...base("daily"), agent: "opencode", model: OPENCODE_MODEL }
|
|
249
254
|
];
|
|
250
255
|
case "c":
|
|
251
|
-
return [
|
|
252
|
-
{ ...base("extreme"), agent: "claude", backend: "proxy", model: ROUTER_PRESET_MODEL },
|
|
253
|
-
{ ...base("hard"), agent: "claude", backend: "proxy", model: ROUTER_PRESET_MODEL },
|
|
254
|
-
codex("mobile"),
|
|
255
|
-
{ ...base("daily"), agent: "opencode", model: OPENCODE_MODEL }
|
|
256
|
-
];
|
|
257
|
-
case "d":
|
|
258
256
|
return ["extreme", "hard", "mobile", "daily"].map(codex);
|
|
259
257
|
}
|
|
260
258
|
}
|
|
261
|
-
function providerPresetDefaults(id
|
|
259
|
+
function providerPresetDefaults(id) {
|
|
262
260
|
switch (id) {
|
|
263
261
|
case "a":
|
|
264
262
|
return {
|
|
@@ -287,28 +285,6 @@ function providerPresetDefaults(id, router) {
|
|
|
287
285
|
};
|
|
288
286
|
}
|
|
289
287
|
case "c": {
|
|
290
|
-
if (!router) {
|
|
291
|
-
throw new Error("preset C (claude harness + router backend) requires a router config \u2014 set defaults.router first");
|
|
292
|
-
}
|
|
293
|
-
const routed = { agent: "claude", backend: "proxy", model: ROUTER_PRESET_MODEL };
|
|
294
|
-
return {
|
|
295
|
-
roles: {
|
|
296
|
-
command: { ...routed },
|
|
297
|
-
captain: { ...routed },
|
|
298
|
-
crew: { ...routed },
|
|
299
|
-
exploration: { ...routed },
|
|
300
|
-
side: { ...routed }
|
|
301
|
-
},
|
|
302
|
-
// Auto mode's classifier is hardcoded to Sonnet 5 and fails closed on a
|
|
303
|
-
// router upstream — every claude session must use a manual mode so the
|
|
304
|
-
// U7 gate owns the prompt.
|
|
305
|
-
permissions: { command: "default", captain: "default", crew: "default" },
|
|
306
|
-
crewRouting: { rules: presetCrewRouting("c") },
|
|
307
|
-
router,
|
|
308
|
-
gate: { mode: "on" }
|
|
309
|
-
};
|
|
310
|
-
}
|
|
311
|
-
case "d": {
|
|
312
288
|
const codex = { agent: "codex" };
|
|
313
289
|
return {
|
|
314
290
|
roles: {
|
|
@@ -319,7 +295,7 @@ function providerPresetDefaults(id, router) {
|
|
|
319
295
|
side: { ...codex }
|
|
320
296
|
},
|
|
321
297
|
permissions: {},
|
|
322
|
-
crewRouting: { rules: presetCrewRouting("
|
|
298
|
+
crewRouting: { rules: presetCrewRouting("c") }
|
|
323
299
|
};
|
|
324
300
|
}
|
|
325
301
|
}
|
|
@@ -329,13 +305,11 @@ function detectProviderPresetId(config) {
|
|
|
329
305
|
if (crew?.agent === "opencode")
|
|
330
306
|
return "b";
|
|
331
307
|
if (crew?.agent === "codex")
|
|
332
|
-
return "d";
|
|
333
|
-
if (crew?.backend && crew.backend !== "native")
|
|
334
308
|
return "c";
|
|
335
309
|
return "a";
|
|
336
310
|
}
|
|
337
311
|
function applyProviderPreset(config, id, opts) {
|
|
338
|
-
const preset = providerPresetDefaults(id
|
|
312
|
+
const preset = providerPresetDefaults(id);
|
|
339
313
|
const next = structuredClone(config);
|
|
340
314
|
const changes = [];
|
|
341
315
|
if (opts.overwrite) {
|
|
@@ -361,21 +335,9 @@ function applyProviderPreset(config, id, opts) {
|
|
|
361
335
|
next.defaults.permissions = { ...preset.permissions };
|
|
362
336
|
changes.push("defaults.permissions");
|
|
363
337
|
}
|
|
364
|
-
if (preset.router) {
|
|
365
|
-
if (opts.overwrite || next.defaults.router === void 0) {
|
|
366
|
-
next.defaults.router = structuredClone(preset.router);
|
|
367
|
-
changes.push("defaults.router");
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
if (preset.gate) {
|
|
371
|
-
if (opts.overwrite || next.defaults.gate === void 0) {
|
|
372
|
-
next.defaults.gate = { ...preset.gate };
|
|
373
|
-
changes.push("defaults.gate");
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
338
|
return { config: next, changes };
|
|
377
339
|
}
|
|
378
|
-
var PROVIDER_PRESETS,
|
|
340
|
+
var PROVIDER_PRESETS, OPENCODE_MODEL;
|
|
379
341
|
var init_provider_preset = __esm({
|
|
380
342
|
"packages/shared/dist/provider-preset.js"() {
|
|
381
343
|
init_config();
|
|
@@ -394,20 +356,11 @@ var init_provider_preset = __esm({
|
|
|
394
356
|
},
|
|
395
357
|
{
|
|
396
358
|
id: "c",
|
|
397
|
-
label: "Claude harness + router backend (advanced)",
|
|
398
|
-
summary: "Claude harness against a router upstream. The U7 gate replaces auto mode.",
|
|
399
|
-
requiresAnthropic: false
|
|
400
|
-
},
|
|
401
|
-
{
|
|
402
|
-
id: "d",
|
|
403
359
|
label: "Codex (ChatGPT Pro)",
|
|
404
360
|
summary: "All roles run on the codex harness.",
|
|
405
361
|
requiresAnthropic: false
|
|
406
362
|
}
|
|
407
363
|
];
|
|
408
|
-
ROUTER_PRESET_MODEL = "deepseek-v4.1-flash";
|
|
409
|
-
DEFAULT_ROUTER_KIND = "opencode-go";
|
|
410
|
-
DEFAULT_ROUTER_BASE_URL = "https://opencode.ai/zen/go";
|
|
411
364
|
OPENCODE_MODEL = "opencode-go/deepseek-v4.1-flash";
|
|
412
365
|
}
|
|
413
366
|
});
|
|
@@ -1661,15 +1614,12 @@ __export(dist_exports, {
|
|
|
1661
1614
|
DEFAULT_CONFIG_PATH: () => DEFAULT_CONFIG_PATH,
|
|
1662
1615
|
DEFAULT_CREW_ROUTING_RULES: () => DEFAULT_CREW_ROUTING_RULES,
|
|
1663
1616
|
DEFAULT_NOTIFY: () => DEFAULT_NOTIFY,
|
|
1664
|
-
DEFAULT_ROUTER_BASE_URL: () => DEFAULT_ROUTER_BASE_URL,
|
|
1665
|
-
DEFAULT_ROUTER_KIND: () => DEFAULT_ROUTER_KIND,
|
|
1666
1617
|
GATE_ENGINES: () => GATE_ENGINES,
|
|
1667
1618
|
GATE_MODES: () => GATE_MODES,
|
|
1668
1619
|
GATE_POLICIES: () => GATE_POLICIES,
|
|
1669
1620
|
MANAGED_TARGETS: () => MANAGED_TARGETS,
|
|
1670
1621
|
PROVIDER_PRESETS: () => PROVIDER_PRESETS,
|
|
1671
1622
|
ROUTER_KINDS: () => ROUTER_KINDS,
|
|
1672
|
-
ROUTER_PRESET_MODEL: () => ROUTER_PRESET_MODEL,
|
|
1673
1623
|
SAFE_KINDS: () => SAFE_KINDS,
|
|
1674
1624
|
SOCKET_CONTROL_MODE_PATH: () => SOCKET_CONTROL_MODE_PATH,
|
|
1675
1625
|
SPOKE_SUBDIRS: () => SPOKE_SUBDIRS,
|
|
@@ -1726,6 +1676,7 @@ __export(dist_exports, {
|
|
|
1726
1676
|
mirrorDir: () => mirrorDir,
|
|
1727
1677
|
mirrorFlat: () => mirrorFlat,
|
|
1728
1678
|
needsCheck: () => needsCheck,
|
|
1679
|
+
normalizePresetId: () => normalizePresetId,
|
|
1729
1680
|
notifyIfUpdateAvailable: () => notifyIfUpdateAvailable,
|
|
1730
1681
|
parseSection: () => parseSection,
|
|
1731
1682
|
parseThinkingLevel: () => parseThinkingLevel,
|
|
@@ -5448,8 +5399,10 @@ async function resolveAndPersistOpencodeCaptain(opts) {
|
|
|
5448
5399
|
sleep: opts.sleep,
|
|
5449
5400
|
fetchImpl: opts.fetchImpl
|
|
5450
5401
|
});
|
|
5451
|
-
if (!sessionId)
|
|
5402
|
+
if (!sessionId) {
|
|
5403
|
+
opts.log?.(`opencode captain session resolution timed out for ${opts.project} (${opts.directory}) \u2014 captain.json has no session id yet; the daemon's own re-resolve fills it in once a session appears`);
|
|
5452
5404
|
return null;
|
|
5405
|
+
}
|
|
5453
5406
|
writeCaptainAddress(opts.stateRoot, opts.project, {
|
|
5454
5407
|
agent: "opencode",
|
|
5455
5408
|
port: opts.port,
|
|
@@ -5469,6 +5422,33 @@ var init_opencode_session = __esm({
|
|
|
5469
5422
|
function discoverCaptainSurface(surfaces, captainTitle) {
|
|
5470
5423
|
return surfaces.find((s) => s.title === captainTitle) ?? null;
|
|
5471
5424
|
}
|
|
5425
|
+
async function reresolveOpencodeAddress(rec) {
|
|
5426
|
+
const live = discoverLiveOpencodeServer({ directory: rec.directory, sessionId: rec.sessionId });
|
|
5427
|
+
const port = live?.port ?? rec.port;
|
|
5428
|
+
if (port === void 0)
|
|
5429
|
+
return null;
|
|
5430
|
+
const newest = newestSessionInDirectory(await listSessions(port), rec.directory, Date.parse(rec.launchedAt));
|
|
5431
|
+
const sessionId = newest ?? live?.sessionId ?? rec.sessionId;
|
|
5432
|
+
if (!sessionId || port === rec.port && sessionId === rec.sessionId)
|
|
5433
|
+
return null;
|
|
5434
|
+
return { port, sessionId };
|
|
5435
|
+
}
|
|
5436
|
+
async function healStaleOpencodeAddress(stateRoot, project, log, logPrefix) {
|
|
5437
|
+
const rec = readCaptainAddress(stateRoot, project);
|
|
5438
|
+
if (!rec)
|
|
5439
|
+
return false;
|
|
5440
|
+
const resolved = await reresolveOpencodeAddress(rec);
|
|
5441
|
+
if (!resolved)
|
|
5442
|
+
return false;
|
|
5443
|
+
const current = readCaptainAddress(stateRoot, project);
|
|
5444
|
+
if (!current || current.launchedAt !== rec.launchedAt) {
|
|
5445
|
+
log(`captain-channel ${project}: skipped stale-address heal \u2014 a newer launch record won the race`);
|
|
5446
|
+
return false;
|
|
5447
|
+
}
|
|
5448
|
+
writeCaptainAddress(stateRoot, project, { ...current, port: resolved.port, sessionId: resolved.sessionId });
|
|
5449
|
+
log(`captain-channel ${project}: ${logPrefix} \u2192 port ${resolved.port}`);
|
|
5450
|
+
return true;
|
|
5451
|
+
}
|
|
5472
5452
|
async function reapOrphanedCrews(store, project, isSurfaceAlive) {
|
|
5473
5453
|
let reaped = 0;
|
|
5474
5454
|
for (const r of store.list(project)) {
|
|
@@ -5693,27 +5673,7 @@ function createDelivery(ctx, daemonCmux, isSurfaceAlive) {
|
|
|
5693
5673
|
log(`captain-channel ${project}: threw, falling back to pane \u2014 ${e.message}`);
|
|
5694
5674
|
}
|
|
5695
5675
|
if (agent === "opencode" && mode !== "off") {
|
|
5696
|
-
const
|
|
5697
|
-
let healed = false;
|
|
5698
|
-
if (rec?.port) {
|
|
5699
|
-
const fresh = newestSessionInDirectory(await listSessions(rec.port), rec.directory, Date.parse(rec.launchedAt));
|
|
5700
|
-
if (fresh && fresh !== rec.sessionId) {
|
|
5701
|
-
writeCaptainAddress(stateRoot, project, { ...rec, sessionId: fresh });
|
|
5702
|
-
healed = true;
|
|
5703
|
-
}
|
|
5704
|
-
}
|
|
5705
|
-
if (!healed && rec) {
|
|
5706
|
-
const live = discoverLiveOpencodeServer({ directory: rec.directory, sessionId: rec.sessionId });
|
|
5707
|
-
if (live && (live.port !== rec.port || live.sessionId && live.sessionId !== rec.sessionId)) {
|
|
5708
|
-
writeCaptainAddress(stateRoot, project, {
|
|
5709
|
-
...rec,
|
|
5710
|
-
port: live.port,
|
|
5711
|
-
sessionId: live.sessionId ?? rec.sessionId
|
|
5712
|
-
});
|
|
5713
|
-
log(`captain-channel ${project}: re-resolved opencode address \u2192 port ${live.port}`);
|
|
5714
|
-
healed = true;
|
|
5715
|
-
}
|
|
5716
|
-
}
|
|
5676
|
+
const healed = await healStaleOpencodeAddress(stateRoot, project, log, "re-resolved opencode address");
|
|
5717
5677
|
if (healed) {
|
|
5718
5678
|
try {
|
|
5719
5679
|
const retry = await deliverToCaptain(project, text, { channel: picked, mode, log });
|
|
@@ -6571,11 +6531,15 @@ function parseCommand(text) {
|
|
|
6571
6531
|
}
|
|
6572
6532
|
return entry.build(args);
|
|
6573
6533
|
}
|
|
6574
|
-
var WRITABLE_CONFIG_KEYS, EFFORT_MODES, REGISTRY;
|
|
6534
|
+
var WRITABLE_CONFIG_KEYS, EFFORT_MODES, GATE_MODES2, CONFIG_VALUE_VALIDATORS, REGISTRY;
|
|
6575
6535
|
var init_commands = __esm({
|
|
6576
6536
|
"packages/core/dist/telegram/commands.js"() {
|
|
6577
|
-
WRITABLE_CONFIG_KEYS = ["defaults.effort"];
|
|
6537
|
+
WRITABLE_CONFIG_KEYS = ["defaults.effort", "defaults.gate.mode"];
|
|
6578
6538
|
EFFORT_MODES = /* @__PURE__ */ new Set(["max", "balance", "low"]);
|
|
6539
|
+
GATE_MODES2 = /* @__PURE__ */ new Set(["on", "off", "auto"]);
|
|
6540
|
+
CONFIG_VALUE_VALIDATORS = {
|
|
6541
|
+
"defaults.gate.mode": { valid: GATE_MODES2, usage: "usage: /config set defaults.gate.mode <on|off|auto>" }
|
|
6542
|
+
};
|
|
6579
6543
|
REGISTRY = {
|
|
6580
6544
|
status: { usage: "/status", build: () => ok("status", ["status"]) },
|
|
6581
6545
|
projects: { usage: "/projects", build: () => ok("projects", ["projects", "list"]) },
|
|
@@ -6622,6 +6586,10 @@ var init_commands = __esm({
|
|
|
6622
6586
|
message: `\u26D4 '${key}' is not writable over Telegram. Allowed: ${WRITABLE_CONFIG_KEYS.join(", ")}`
|
|
6623
6587
|
};
|
|
6624
6588
|
}
|
|
6589
|
+
const validator = CONFIG_VALUE_VALIDATORS[key];
|
|
6590
|
+
if (validator && !validator.valid.has(value)) {
|
|
6591
|
+
return usage("config", validator.usage);
|
|
6592
|
+
}
|
|
6625
6593
|
return ok("config", ["config", "set", key, value]);
|
|
6626
6594
|
}
|
|
6627
6595
|
return usage("config", "usage: /config get <key> | /config set <key> <value>");
|
|
@@ -9119,7 +9087,7 @@ var init_permission_gate = __esm({
|
|
|
9119
9087
|
});
|
|
9120
9088
|
|
|
9121
9089
|
// packages/core/dist/auto-gate.js
|
|
9122
|
-
import { createAutoGate, projectGateConfig } from "@squadrant-ai/auto-gate";
|
|
9090
|
+
import { createAutoGate, projectGateConfig, resolveApiKey } from "@squadrant-ai/auto-gate";
|
|
9123
9091
|
function gateForProjection(config) {
|
|
9124
9092
|
const gate = config.defaults.gate;
|
|
9125
9093
|
if (!gate)
|
|
@@ -9133,6 +9101,9 @@ function gateForProjection(config) {
|
|
|
9133
9101
|
out.deny = gate.deny;
|
|
9134
9102
|
return out;
|
|
9135
9103
|
}
|
|
9104
|
+
function hasAutoGateCredential(env = process.env, home) {
|
|
9105
|
+
return Boolean(resolveApiKey({ env, ...home !== void 0 ? { home } : {} }));
|
|
9106
|
+
}
|
|
9136
9107
|
function createSquadrantAutoGate(deps) {
|
|
9137
9108
|
const env = deps.env ?? process.env;
|
|
9138
9109
|
const taskId = env.SQUADRANT_CREW_TASK_ID;
|
|
@@ -10107,6 +10078,7 @@ __export(dist_exports2, {
|
|
|
10107
10078
|
freshTrace: () => freshTrace,
|
|
10108
10079
|
gateCacheKey: () => gateCacheKey,
|
|
10109
10080
|
getDaemonPid: () => getDaemonPid,
|
|
10081
|
+
hasAutoGateCredential: () => hasAutoGateCredential,
|
|
10110
10082
|
hasModalOptionList: () => hasModalOptionList,
|
|
10111
10083
|
healCmdFor: () => healCmdFor,
|
|
10112
10084
|
inboundBody: () => inboundBody,
|
|
@@ -16454,27 +16426,6 @@ function promptLine(question) {
|
|
|
16454
16426
|
});
|
|
16455
16427
|
});
|
|
16456
16428
|
}
|
|
16457
|
-
async function resolveRouter(config, opts, isTTY) {
|
|
16458
|
-
if (config.defaults?.router) return config.defaults.router;
|
|
16459
|
-
let kind = opts.routerKind;
|
|
16460
|
-
let baseUrl = opts.routerBaseUrl;
|
|
16461
|
-
let apiKeyEnv = opts.routerApiKeyEnv;
|
|
16462
|
-
if (isTTY && (!kind || !baseUrl)) {
|
|
16463
|
-
const k = await promptLine(chalk4.cyan(` Router kind [${DEFAULT_ROUTER_KIND}]: `));
|
|
16464
|
-
kind = kind ?? (k || DEFAULT_ROUTER_KIND);
|
|
16465
|
-
const b = await promptLine(chalk4.cyan(` Router base URL [${DEFAULT_ROUTER_BASE_URL}]: `));
|
|
16466
|
-
baseUrl = baseUrl ?? (b || DEFAULT_ROUTER_BASE_URL);
|
|
16467
|
-
const e = await promptLine(chalk4.cyan(" Env var holding the API key (optional): "));
|
|
16468
|
-
apiKeyEnv = apiKeyEnv ?? (e || void 0);
|
|
16469
|
-
}
|
|
16470
|
-
const resolvedKind = kind && isRouterKind(kind) ? kind : DEFAULT_ROUTER_KIND;
|
|
16471
|
-
const resolvedBase = baseUrl || DEFAULT_ROUTER_BASE_URL;
|
|
16472
|
-
if (!isTTY && !opts.routerBaseUrl) {
|
|
16473
|
-
console.log(chalk4.dim(` - no router flags given; defaulting to ${resolvedKind} (${resolvedBase})`));
|
|
16474
|
-
console.log(chalk4.dim(" set a credential: squadrant config set defaults.router.apiKeyEnv <VAR>"));
|
|
16475
|
-
}
|
|
16476
|
-
return { kind: resolvedKind, baseUrl: resolvedBase, ...apiKeyEnv ? { apiKeyEnv } : {} };
|
|
16477
|
-
}
|
|
16478
16429
|
async function askProvider(current, auth) {
|
|
16479
16430
|
console.log(chalk4.bold("\n Choose your provider:"));
|
|
16480
16431
|
for (const p of PROVIDER_PRESETS) {
|
|
@@ -16483,10 +16434,10 @@ async function askProvider(current, auth) {
|
|
|
16483
16434
|
console.log(chalk4.dim(` ${p.summary}`));
|
|
16484
16435
|
}
|
|
16485
16436
|
if (!auth.authenticated) {
|
|
16486
|
-
console.log(chalk4.yellow("\n \u26A0 No Anthropic credential detected \u2014 preset a will not work; consider b
|
|
16437
|
+
console.log(chalk4.yellow("\n \u26A0 No Anthropic credential detected \u2014 preset a will not work; consider b."));
|
|
16487
16438
|
}
|
|
16488
16439
|
const answer = (await promptLine(chalk4.cyan(`
|
|
16489
|
-
Provider [a/b/c
|
|
16440
|
+
Provider [a/b/c] (default ${current}): `))).toLowerCase();
|
|
16490
16441
|
if (!answer) return current;
|
|
16491
16442
|
if (isProviderPresetId(answer)) return answer;
|
|
16492
16443
|
console.log(chalk4.yellow(` \u26A0 Unknown choice '${answer}' \u2014 keeping '${current}'.`));
|
|
@@ -16495,9 +16446,9 @@ async function askProvider(current, auth) {
|
|
|
16495
16446
|
function warnIfNoAnthropic(preset, auth) {
|
|
16496
16447
|
if (preset !== "a" || auth.authenticated) return;
|
|
16497
16448
|
console.log(chalk4.yellow(" \u26A0 No Anthropic credential detected (`claude auth status`)."));
|
|
16498
|
-
console.log(chalk4.dim(" Preset A (Claude Pro/Max or an API key) may not work \u2014 consider preset b
|
|
16449
|
+
console.log(chalk4.dim(" Preset A (Claude Pro/Max or an API key) may not work \u2014 consider preset b."));
|
|
16499
16450
|
}
|
|
16500
|
-
var initCommand = new Command2("init").description("Guided first-time setup: provider, hub vault, agents, plugins, projects (re-run-safe)").option("--hub <path>", "Hub vault path", "~/squadrant-hub").option("--preset <id>", "provider preset: a|b|c
|
|
16451
|
+
var initCommand = new Command2("init").description("Guided first-time setup: provider, hub vault, agents, plugins, projects (re-run-safe)").option("--hub <path>", "Hub vault path", "~/squadrant-hub").option("--preset <id>", "provider preset: a|b|c (non-interactive; d accepted as a deprecated alias for c)").action(async (opts) => {
|
|
16501
16452
|
const hubPath = resolveHome(opts.hub);
|
|
16502
16453
|
const pkgRoot = findPackageRoot();
|
|
16503
16454
|
const configDir = path23.join(os13.homedir(), ".config", "squadrant");
|
|
@@ -16505,9 +16456,9 @@ var initCommand = new Command2("init").description("Guided first-time setup: pro
|
|
|
16505
16456
|
console.log(chalk4.bold("\nSquadrant Init\n"));
|
|
16506
16457
|
let explicitPreset;
|
|
16507
16458
|
if (opts.preset !== void 0) {
|
|
16508
|
-
const candidate = opts.preset.toLowerCase();
|
|
16509
|
-
if (!
|
|
16510
|
-
console.error(chalk4.red(` \u2718 Unknown --preset '${opts.preset}'. Valid values: a, b, c
|
|
16459
|
+
const candidate = normalizePresetId(opts.preset.toLowerCase());
|
|
16460
|
+
if (!candidate) {
|
|
16461
|
+
console.error(chalk4.red(` \u2718 Unknown --preset '${opts.preset}'. Valid values: a, b, c`));
|
|
16511
16462
|
process.exitCode = 1;
|
|
16512
16463
|
return;
|
|
16513
16464
|
}
|
|
@@ -16517,7 +16468,7 @@ var initCommand = new Command2("init").description("Guided first-time setup: pro
|
|
|
16517
16468
|
console.log(" Run these steps to get started:\n");
|
|
16518
16469
|
console.log(chalk4.bold(" 1/5 Hub vault + provider"));
|
|
16519
16470
|
console.log(chalk4.cyan(` squadrant init --hub ${opts.hub}`));
|
|
16520
|
-
console.log(chalk4.dim(" Choose a provider: squadrant init --preset a|b|c
|
|
16471
|
+
console.log(chalk4.dim(" Choose a provider: squadrant init --preset a|b|c"));
|
|
16521
16472
|
console.log(chalk4.bold("\n 2/5 Agent + projection setup"));
|
|
16522
16473
|
console.log(" (handled automatically by: " + chalk4.cyan("squadrant init") + ")");
|
|
16523
16474
|
console.log(chalk4.bold("\n 3/5 Plugins \u2014 open Claude Code and run:"));
|
|
@@ -16563,9 +16514,8 @@ var initCommand = new Command2("init").description("Guided first-time setup: pro
|
|
|
16563
16514
|
let appliedChanges = [];
|
|
16564
16515
|
if (chosenPreset) {
|
|
16565
16516
|
const label = PROVIDER_PRESETS.find((p) => p.id === chosenPreset)?.label ?? chosenPreset;
|
|
16566
|
-
const router = chosenPreset === "c" ? await resolveRouter(config, opts, isTTY) : void 0;
|
|
16567
16517
|
const overwrite = !configExists || explicitPreset !== void 0;
|
|
16568
|
-
const result = applyProviderPreset(config, chosenPreset, {
|
|
16518
|
+
const result = applyProviderPreset(config, chosenPreset, { overwrite });
|
|
16569
16519
|
appliedChanges = result.changes;
|
|
16570
16520
|
config = result.config;
|
|
16571
16521
|
console.log(chalk4.bold(`
|
|
@@ -20175,7 +20125,7 @@ var launchCommand = new Command14("launch").description(
|
|
|
20175
20125
|
sessionId: priorRecord?.sessionId
|
|
20176
20126
|
});
|
|
20177
20127
|
if (!live) return;
|
|
20178
|
-
const sessionId = live.sessionId ?? priorRecord?.sessionId;
|
|
20128
|
+
const sessionId = live.sessionId ?? (live.port === priorRecord?.port ? priorRecord?.sessionId : void 0);
|
|
20179
20129
|
if (priorRecord && priorRecord.port === live.port && priorRecord.sessionId === sessionId) return;
|
|
20180
20130
|
writeCaptainAddress(stateRoot, projectName, {
|
|
20181
20131
|
agent: "opencode",
|
|
@@ -20189,13 +20139,20 @@ var launchCommand = new Command14("launch").description(
|
|
|
20189
20139
|
console.log(chalk15.green(` \u2714 Workspace '${name}' created`));
|
|
20190
20140
|
if (!projectName) return;
|
|
20191
20141
|
if (isOpencodeCaptain && captainPort) {
|
|
20142
|
+
writeCaptainAddress(stateRoot, projectName, {
|
|
20143
|
+
agent: "opencode",
|
|
20144
|
+
port: captainPort,
|
|
20145
|
+
directory: realpathOrSelf(cwd),
|
|
20146
|
+
launchedAt
|
|
20147
|
+
});
|
|
20192
20148
|
void resolveAndPersistOpencodeCaptain({
|
|
20193
20149
|
stateRoot,
|
|
20194
20150
|
project: projectName,
|
|
20195
20151
|
port: captainPort,
|
|
20196
20152
|
directory: realpathOrSelf(cwd),
|
|
20197
20153
|
launchedAt,
|
|
20198
|
-
sessionId: opencodeResumeSessionId
|
|
20154
|
+
sessionId: opencodeResumeSessionId,
|
|
20155
|
+
log: (m) => console.error(chalk15.yellow(` \u26A0 ${m}`))
|
|
20199
20156
|
}).catch(() => {
|
|
20200
20157
|
});
|
|
20201
20158
|
} else if (role === "captain") {
|
|
@@ -22585,6 +22542,7 @@ init_dist2();
|
|
|
22585
22542
|
init_dist();
|
|
22586
22543
|
init_dist3();
|
|
22587
22544
|
import { Command as Command32 } from "commander";
|
|
22545
|
+
import chalk33 from "chalk";
|
|
22588
22546
|
var SOCK4 = DAEMON_SOCK_PATH;
|
|
22589
22547
|
async function runAutoGateClaudeHook(o) {
|
|
22590
22548
|
const make = o.deps.createAutoGate ?? createSquadrantAutoGate;
|
|
@@ -22669,10 +22627,60 @@ async function runGatePermissionRequest(deps) {
|
|
|
22669
22627
|
return evaluation;
|
|
22670
22628
|
}
|
|
22671
22629
|
var DEFAULT_EVENT = "permission-request";
|
|
22630
|
+
function runGateModeGet(configPath = DEFAULT_CONFIG_PATH, env = process.env) {
|
|
22631
|
+
const config = loadConfig(configPath);
|
|
22632
|
+
const mode = resolveGateMode(env, config.defaults.gate);
|
|
22633
|
+
const source = env.SQUADRANT_GATE !== void 0 && isGateMode(env.SQUADRANT_GATE) ? "env" : config.defaults.gate?.mode && isGateMode(config.defaults.gate.mode) ? "config" : "default";
|
|
22634
|
+
return { mode, source };
|
|
22635
|
+
}
|
|
22636
|
+
function runGateModeSet(value, configPath = DEFAULT_CONFIG_PATH) {
|
|
22637
|
+
if (!isGateMode(value)) {
|
|
22638
|
+
throw new Error(`Invalid gate mode '${value}'. Valid values: ${GATE_MODES.join(" | ")}`);
|
|
22639
|
+
}
|
|
22640
|
+
const config = loadConfig(configPath);
|
|
22641
|
+
const old = config.defaults.gate?.mode && isGateMode(config.defaults.gate.mode) ? config.defaults.gate.mode : "auto";
|
|
22642
|
+
config.defaults.gate = { ...config.defaults.gate, mode: value };
|
|
22643
|
+
saveConfig(config, configPath);
|
|
22644
|
+
return { old, next: value };
|
|
22645
|
+
}
|
|
22646
|
+
function runGateStatus(configPath = DEFAULT_CONFIG_PATH, env = process.env) {
|
|
22647
|
+
const config = loadConfig(configPath);
|
|
22648
|
+
const { mode, source } = runGateModeGet(configPath, env);
|
|
22649
|
+
const engine = resolveGateEngine(env, config.defaults.gate);
|
|
22650
|
+
const model = resolveClassifierModel(env, config);
|
|
22651
|
+
const credentialPresent = engine === "auto-gate" ? hasAutoGateCredential(env) : Boolean(config.defaults.router?.apiKey ?? (config.defaults.router?.apiKeyEnv ? env[config.defaults.router.apiKeyEnv] : void 0));
|
|
22652
|
+
return { mode, source, engine, model, credentialPresent };
|
|
22653
|
+
}
|
|
22672
22654
|
function gateCommand() {
|
|
22673
22655
|
const gate = new Command32("gate").description(
|
|
22674
|
-
"(
|
|
22656
|
+
"Permission gate (#782/#854): get/set defaults.gate.mode; 'claude <event>' is an internal hook handler"
|
|
22675
22657
|
);
|
|
22658
|
+
gate.command("mode [value]").description("Get or set the permission gate mode (on | off | auto)").action((value) => {
|
|
22659
|
+
if (value === void 0) {
|
|
22660
|
+
const result2 = runGateModeGet();
|
|
22661
|
+
console.log(chalk33.bold("Gate mode:"), chalk33.cyan(result2.mode), chalk33.dim(`(${result2.source})`));
|
|
22662
|
+
return;
|
|
22663
|
+
}
|
|
22664
|
+
let result;
|
|
22665
|
+
try {
|
|
22666
|
+
result = runGateModeSet(value);
|
|
22667
|
+
} catch (e) {
|
|
22668
|
+
console.error(chalk33.red(e.message));
|
|
22669
|
+
process.exit(1);
|
|
22670
|
+
}
|
|
22671
|
+
console.log(chalk33.green(`\u2714 gate mode: ${result.old} \u2192 ${result.next}`));
|
|
22672
|
+
console.log(chalk33.dim("No daemon bounce needed \u2014 defaults.gate.mode is read live."));
|
|
22673
|
+
if (isGateMode(process.env.SQUADRANT_GATE ?? "") && process.env.SQUADRANT_GATE !== result.next) {
|
|
22674
|
+
console.log(chalk33.yellow(`Note: SQUADRANT_GATE=${process.env.SQUADRANT_GATE} in this session still overrides the config value.`));
|
|
22675
|
+
}
|
|
22676
|
+
});
|
|
22677
|
+
gate.command("status").description("Show the effective gate mode, engine, classifier model, and credential presence").action(() => {
|
|
22678
|
+
const result = runGateStatus();
|
|
22679
|
+
console.log(chalk33.bold("Gate mode:"), chalk33.cyan(result.mode), chalk33.dim(`(${result.source})`));
|
|
22680
|
+
console.log(chalk33.bold("Engine:"), result.engine);
|
|
22681
|
+
console.log(chalk33.bold("Classifier model:"), result.model ?? chalk33.dim("(unset)"));
|
|
22682
|
+
console.log(chalk33.bold("Credential:"), result.credentialPresent ? chalk33.green("present") : chalk33.yellow("absent"));
|
|
22683
|
+
});
|
|
22676
22684
|
gate.command("claude <event>", { hidden: true }).description("internal: classify a claude PermissionRequest with the configured router model").action(async (event) => {
|
|
22677
22685
|
let stdin = "";
|
|
22678
22686
|
try {
|
|
@@ -22826,7 +22834,7 @@ init_dist();
|
|
|
22826
22834
|
init_dist2();
|
|
22827
22835
|
import path34 from "path";
|
|
22828
22836
|
import { Command as Command34 } from "commander";
|
|
22829
|
-
import
|
|
22837
|
+
import chalk34 from "chalk";
|
|
22830
22838
|
function detectCurrentProject(config, cwd = process.cwd()) {
|
|
22831
22839
|
for (const [name, proj] of Object.entries(config.projects)) {
|
|
22832
22840
|
const projPath = resolveHome(proj.path);
|
|
@@ -22866,21 +22874,21 @@ function visibleItems(items, includeDone) {
|
|
|
22866
22874
|
function stateColor(state) {
|
|
22867
22875
|
switch (state) {
|
|
22868
22876
|
case "done":
|
|
22869
|
-
return
|
|
22877
|
+
return chalk34.green;
|
|
22870
22878
|
case "cancelled":
|
|
22871
|
-
return
|
|
22879
|
+
return chalk34.dim;
|
|
22872
22880
|
case "blocked":
|
|
22873
|
-
return
|
|
22881
|
+
return chalk34.red;
|
|
22874
22882
|
case "paused":
|
|
22875
|
-
return
|
|
22883
|
+
return chalk34.yellow;
|
|
22876
22884
|
default:
|
|
22877
|
-
return
|
|
22885
|
+
return chalk34.cyan;
|
|
22878
22886
|
}
|
|
22879
22887
|
}
|
|
22880
22888
|
function printItem(item, indent) {
|
|
22881
22889
|
const color = stateColor(item.state);
|
|
22882
|
-
const line = " ".repeat(indent) + `${
|
|
22883
|
-
console.log(TERMINAL_WORK_STATES.has(item.state) ?
|
|
22890
|
+
const line = " ".repeat(indent) + `${chalk34.dim(item.id)} ${item.title} ${color(`[${item.state}]`)}` + (indent === 0 ? chalk34.dim(` (${item.project})`) : "");
|
|
22891
|
+
console.log(TERMINAL_WORK_STATES.has(item.state) ? chalk34.dim(line) : line);
|
|
22884
22892
|
}
|
|
22885
22893
|
function printTree(items) {
|
|
22886
22894
|
const { roots, childrenOf } = groupByParent(items);
|
|
@@ -22899,15 +22907,15 @@ var startCmd = new Command34("start").description("Start a new work item").argum
|
|
|
22899
22907
|
purgeExpiredWorkItems(store);
|
|
22900
22908
|
const project = opts.project ?? detectCurrentProject(config);
|
|
22901
22909
|
if (!project) {
|
|
22902
|
-
console.error(
|
|
22910
|
+
console.error(chalk34.red("No --project given and cwd is not inside a registered project."));
|
|
22903
22911
|
process.exit(1);
|
|
22904
22912
|
}
|
|
22905
22913
|
if (opts.parent && !findWorkItemById(store, opts.parent)) {
|
|
22906
|
-
console.error(
|
|
22914
|
+
console.error(chalk34.red(`Parent work item '${opts.parent}' not found.`));
|
|
22907
22915
|
process.exit(1);
|
|
22908
22916
|
}
|
|
22909
22917
|
const item = createWorkItem(store, { project, title, parent: opts.parent ?? null, tags: opts.tag });
|
|
22910
|
-
console.log(
|
|
22918
|
+
console.log(chalk34.green(`\u2713 ${item.id}`) + ` ${item.title}` + chalk34.dim(` (${item.project})`));
|
|
22911
22919
|
});
|
|
22912
22920
|
var listCmd2 = new Command34("list").description("List work items").option("--project <name>", "scope to one project").option("--all", "list across every project").option("--tree", "render parent/child nesting").option("--include-done", "include done/cancelled items").action((opts) => {
|
|
22913
22921
|
const config = loadConfig();
|
|
@@ -22921,14 +22929,14 @@ var listCmd2 = new Command34("list").description("List work items").option("--pr
|
|
|
22921
22929
|
} else {
|
|
22922
22930
|
const project = detectCurrentProject(config);
|
|
22923
22931
|
if (!project) {
|
|
22924
|
-
console.error(
|
|
22932
|
+
console.error(chalk34.red("cwd is not inside a registered project \u2014 pass --project or --all."));
|
|
22925
22933
|
process.exit(1);
|
|
22926
22934
|
}
|
|
22927
22935
|
items = store.list(project);
|
|
22928
22936
|
}
|
|
22929
22937
|
items = visibleItems(items, opts.includeDone ?? false);
|
|
22930
22938
|
if (items.length === 0) {
|
|
22931
|
-
console.log(
|
|
22939
|
+
console.log(chalk34.dim("\nNo work items.\n"));
|
|
22932
22940
|
return;
|
|
22933
22941
|
}
|
|
22934
22942
|
console.log();
|
|
@@ -22942,15 +22950,15 @@ function closeCommand(name, state, flag, key, desc) {
|
|
|
22942
22950
|
purgeExpiredWorkItems(store);
|
|
22943
22951
|
const item = closeWorkItem(store, id, state, { note: opts[key] });
|
|
22944
22952
|
if (!item) {
|
|
22945
|
-
console.error(
|
|
22953
|
+
console.error(chalk34.red(`Work item '${id}' not found.`));
|
|
22946
22954
|
process.exit(1);
|
|
22947
22955
|
}
|
|
22948
|
-
console.log(
|
|
22956
|
+
console.log(chalk34.green(`\u2713 ${item.id}`) + ` ${item.title} ${chalk34.dim(`[${item.state}]`)}`);
|
|
22949
22957
|
if (state === "done") {
|
|
22950
22958
|
const openChildren = findOpenChildren(store, item.id);
|
|
22951
22959
|
if (openChildren.length > 0) {
|
|
22952
22960
|
const names = openChildren.map((c) => `${c.id} [${c.state}]`).join(", ");
|
|
22953
|
-
console.log(
|
|
22961
|
+
console.log(chalk34.yellow(`\u26A0 still has ${openChildren.length} unfinished child item(s): ${names}`));
|
|
22954
22962
|
}
|
|
22955
22963
|
}
|
|
22956
22964
|
});
|
|
@@ -23433,7 +23441,7 @@ handoffCommand.command("facts <project>").description(
|
|
|
23433
23441
|
init_dist();
|
|
23434
23442
|
init_dist3();
|
|
23435
23443
|
import { Command as Command36 } from "commander";
|
|
23436
|
-
import
|
|
23444
|
+
import chalk35 from "chalk";
|
|
23437
23445
|
var KNOWN_AGENTS = ["claude", "opencode", "codex", "gemini"];
|
|
23438
23446
|
function normalized(p) {
|
|
23439
23447
|
return p.replace(/\/+$/, "");
|
|
@@ -23486,7 +23494,7 @@ async function collectSessions(drivers) {
|
|
|
23486
23494
|
}
|
|
23487
23495
|
var sessionsCommand = new Command36("sessions").description("List live agent sessions squadrant can introspect (read-only; claude + opencode)").option("--json", "emit machine-readable JSON").option("--agent <name>", `filter to one agent (${KNOWN_AGENTS.join("|")})`).option("--project <name>", "filter to one registered project").option("--live-only", "drop sessions whose process is dead (status: stale)").action(async (opts) => {
|
|
23488
23496
|
if (opts.agent && !KNOWN_AGENTS.includes(opts.agent)) {
|
|
23489
|
-
console.error(
|
|
23497
|
+
console.error(chalk35.red(`
|
|
23490
23498
|
\u2718 Unknown agent '${opts.agent}'. Known agents: ${KNOWN_AGENTS.join(", ")}
|
|
23491
23499
|
`));
|
|
23492
23500
|
process.exit(1);
|
|
@@ -23494,7 +23502,7 @@ var sessionsCommand = new Command36("sessions").description("List live agent ses
|
|
|
23494
23502
|
const config = loadConfig();
|
|
23495
23503
|
if (opts.project && !(opts.project in config.projects)) {
|
|
23496
23504
|
const known = Object.keys(config.projects).sort().join(", ") || "(none registered)";
|
|
23497
|
-
console.error(
|
|
23505
|
+
console.error(chalk35.red(`
|
|
23498
23506
|
\u2718 Unknown project '${opts.project}'. Known projects: ${known}
|
|
23499
23507
|
`));
|
|
23500
23508
|
process.exit(1);
|
|
@@ -23510,7 +23518,7 @@ var sessionsCommand = new Command36("sessions").description("List live agent ses
|
|
|
23510
23518
|
};
|
|
23511
23519
|
const { rows, unsupported } = await collectSessions(drivers);
|
|
23512
23520
|
if (opts.agent && unsupported.includes(opts.agent)) {
|
|
23513
|
-
console.error(
|
|
23521
|
+
console.error(chalk35.red(`
|
|
23514
23522
|
\u2718 Agent '${opts.agent}' does not support session introspection.
|
|
23515
23523
|
`));
|
|
23516
23524
|
process.exit(1);
|
|
@@ -23526,7 +23534,7 @@ var sessionsCommand = new Command36("sessions").description("List live agent ses
|
|
|
23526
23534
|
} else {
|
|
23527
23535
|
console.log(formatSessionTable(filtered));
|
|
23528
23536
|
if (!opts.agent && unsupported.length > 0) {
|
|
23529
|
-
console.error(
|
|
23537
|
+
console.error(chalk35.dim(`(unsupported for session introspection: ${unsupported.join(", ")})`));
|
|
23530
23538
|
}
|
|
23531
23539
|
}
|
|
23532
23540
|
});
|
|
@@ -23538,7 +23546,7 @@ init_dist3();
|
|
|
23538
23546
|
import os20 from "os";
|
|
23539
23547
|
import path38 from "path";
|
|
23540
23548
|
import { Command as Command37 } from "commander";
|
|
23541
|
-
import
|
|
23549
|
+
import chalk36 from "chalk";
|
|
23542
23550
|
|
|
23543
23551
|
// packages/cli/src/lib/whoami.ts
|
|
23544
23552
|
function projectForCwd(cwd, projects) {
|
|
@@ -23697,7 +23705,7 @@ var whoamiCommand = new Command37("whoami").description("Show the agent session
|
|
|
23697
23705
|
} else {
|
|
23698
23706
|
console.log(formatWhoami(result));
|
|
23699
23707
|
if (!result.ok) {
|
|
23700
|
-
console.error(
|
|
23708
|
+
console.error(chalk36.yellow("\n Could not identify a squadrant agent session for this invocation."));
|
|
23701
23709
|
}
|
|
23702
23710
|
}
|
|
23703
23711
|
if (!result.ok) process.exitCode = 1;
|