squadrant 0.26.2 → 0.26.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 +519 -315
- package/dist/index.js.map +1 -1
- package/dist/squadrantd.js +164 -2
- package/dist/squadrantd.js.map +1 -1
- package/package.json +1 -1
package/dist/squadrantd.js
CHANGED
|
@@ -4662,9 +4662,13 @@ async function runCrewSpawn(input, config, deps) {
|
|
|
4662
4662
|
await deps.runtime.sendToPane(pane2, `cd ${shellQuote(spawnCwd)} && ${envPrefix}${routerPrefix} ${niceCrewCommand(cliCommand2)}`);
|
|
4663
4663
|
const preLaunchScreen = await deps.runtime.readPaneScreen(pane2) ?? "";
|
|
4664
4664
|
const claudeFirstTurn = spillOversizedFirstTurn(firstTurnTask, rec.id);
|
|
4665
|
-
const
|
|
4665
|
+
const peerBrief = `${firstTurnTask}
|
|
4666
4666
|
|
|
4667
|
-
${buildCompletionProtocol(rec.id, input.project)}
|
|
4667
|
+
${buildCompletionProtocol(rec.id, input.project)}`;
|
|
4668
|
+
const peerResult = deps.sendFirstTurnPeer ? await deps.sendFirstTurnPeer({ pane: pane2, taskId: rec.id, project: input.project, messagingSocketPath, message: peerBrief }).catch(() => ({ kind: "fallback" })) : { kind: "fallback" };
|
|
4669
|
+
const sendPromise = peerResult.kind === "fallback" ? deps.sendFirstTurn(pane2, `${claudeFirstTurn}
|
|
4670
|
+
|
|
4671
|
+
${buildCompletionProtocol(rec.id, input.project)}`, preLaunchScreen) : Promise.resolve({ delivered: peerResult.kind === "delivered" });
|
|
4668
4672
|
let agentNotStarted = false;
|
|
4669
4673
|
const scrapeDelivered = sendPromise.then((r) => {
|
|
4670
4674
|
agentNotStarted = !!r.agentNotStarted;
|
|
@@ -8889,6 +8893,30 @@ async function runCrewAnswer(project, name, option, runtime, workspaceId, deps,
|
|
|
8889
8893
|
if (!crew) {
|
|
8890
8894
|
throw new Error(`Crew '${name}' not found for ${project}. Run 'squadrant crew list ${project}'.`);
|
|
8891
8895
|
}
|
|
8896
|
+
const match = runtime.findDialog && runtime.answerDialog ? await deps.dialogMatch?.() : void 0;
|
|
8897
|
+
if (match) {
|
|
8898
|
+
const dialog = await runtime.findDialog(match).catch(() => void 0);
|
|
8899
|
+
if (dialog) {
|
|
8900
|
+
const log2 = deps.log ?? (() => {
|
|
8901
|
+
});
|
|
8902
|
+
const options2 = dialog.options.map((o) => ({ ...o, highlighted: false }));
|
|
8903
|
+
let target2;
|
|
8904
|
+
try {
|
|
8905
|
+
target2 = resolveOption(options2, option);
|
|
8906
|
+
if (opts?.expect && !target2.label.toLowerCase().includes(opts.expect.toLowerCase()))
|
|
8907
|
+
target2 = void 0;
|
|
8908
|
+
} catch {
|
|
8909
|
+
target2 = void 0;
|
|
8910
|
+
}
|
|
8911
|
+
if (target2) {
|
|
8912
|
+
log2(`\u2192 answering ${target2.index}. "${target2.label}" via the runtime (no keystrokes)`);
|
|
8913
|
+
const ok2 = await runtime.answerDialog(dialog, opts?.text ? { text: opts.text } : { label: target2.label }).catch(() => false);
|
|
8914
|
+
if (ok2)
|
|
8915
|
+
return { selected: target2, closed: true };
|
|
8916
|
+
}
|
|
8917
|
+
log2("runtime answer not applied \u2014 falling back to keystrokes");
|
|
8918
|
+
}
|
|
8919
|
+
}
|
|
8892
8920
|
const modal = await deps.readModalOptions(crew);
|
|
8893
8921
|
if (!modal || modal.options.length === 0) {
|
|
8894
8922
|
throw new Error(`Crew '${name}' has no interactive option prompt visible right now \u2014 nothing to answer. Read its screen with 'squadrant crew read ${project} ${name}' to check its state.`);
|
|
@@ -9268,6 +9296,58 @@ var init_source = __esm({
|
|
|
9268
9296
|
}
|
|
9269
9297
|
});
|
|
9270
9298
|
|
|
9299
|
+
// packages/core/dist/peer-first-turn.js
|
|
9300
|
+
function screenShowsTrustPanel(screen) {
|
|
9301
|
+
return /do you trust the files in this folder|is this a project you created or one you trust|is this a project you trust/i.test(screen);
|
|
9302
|
+
}
|
|
9303
|
+
function trustPanelAcceptKeys(screen) {
|
|
9304
|
+
return /❯\s*(\d\.\s*)?No\b/.test(screen) ? ["Down", "Enter"] : ["Enter"];
|
|
9305
|
+
}
|
|
9306
|
+
async function deliverFirstTurnViaPeer(message, deps) {
|
|
9307
|
+
const pollMs = deps.pollMs ?? DEFAULT_POLL_MS2;
|
|
9308
|
+
const deadline = deps.now() + (deps.readyTimeoutMs ?? DEFAULT_READY_TIMEOUT_MS);
|
|
9309
|
+
let lastTrustAnswer = -Infinity;
|
|
9310
|
+
for (; ; ) {
|
|
9311
|
+
if (deps.statusOf()?.status === "idle")
|
|
9312
|
+
break;
|
|
9313
|
+
if (deps.now() >= deadline)
|
|
9314
|
+
return { kind: "fallback" };
|
|
9315
|
+
if (!deps.statusOf() && deps.now() - lastTrustAnswer >= TRUST_ANSWER_COOLDOWN_MS) {
|
|
9316
|
+
const screen = await deps.readScreen().catch(() => "");
|
|
9317
|
+
if (screenShowsTrustPanel(screen)) {
|
|
9318
|
+
lastTrustAnswer = deps.now();
|
|
9319
|
+
for (const key of trustPanelAcceptKeys(screen))
|
|
9320
|
+
await deps.pressKey(key).catch(() => {
|
|
9321
|
+
});
|
|
9322
|
+
}
|
|
9323
|
+
}
|
|
9324
|
+
await deps.sleep(pollMs);
|
|
9325
|
+
}
|
|
9326
|
+
const outcome = await deps.send(message);
|
|
9327
|
+
if (fallsBackToPane(outcome))
|
|
9328
|
+
return { kind: "fallback" };
|
|
9329
|
+
if (outcome.status === "accepted" && outcome.confirmed)
|
|
9330
|
+
return { kind: "delivered" };
|
|
9331
|
+
const confirmDeadline = deps.now() + (deps.confirmGraceMs ?? DEFAULT_CONFIRM_GRACE_MS);
|
|
9332
|
+
for (; ; ) {
|
|
9333
|
+
if (await deps.isConfirmed().catch(() => false))
|
|
9334
|
+
return { kind: "delivered" };
|
|
9335
|
+
if (deps.now() >= confirmDeadline)
|
|
9336
|
+
return { kind: "unconfirmed" };
|
|
9337
|
+
await deps.sleep(pollMs);
|
|
9338
|
+
}
|
|
9339
|
+
}
|
|
9340
|
+
var DEFAULT_READY_TIMEOUT_MS, DEFAULT_POLL_MS2, DEFAULT_CONFIRM_GRACE_MS, TRUST_ANSWER_COOLDOWN_MS;
|
|
9341
|
+
var init_peer_first_turn = __esm({
|
|
9342
|
+
"packages/core/dist/peer-first-turn.js"() {
|
|
9343
|
+
init_control_channel();
|
|
9344
|
+
DEFAULT_READY_TIMEOUT_MS = 9e4;
|
|
9345
|
+
DEFAULT_POLL_MS2 = 250;
|
|
9346
|
+
DEFAULT_CONFIRM_GRACE_MS = 1e4;
|
|
9347
|
+
TRUST_ANSWER_COOLDOWN_MS = 5e3;
|
|
9348
|
+
}
|
|
9349
|
+
});
|
|
9350
|
+
|
|
9271
9351
|
// packages/core/dist/knowledge/paths.js
|
|
9272
9352
|
import path14 from "path";
|
|
9273
9353
|
function kbDir(hubVault, kb) {
|
|
@@ -12987,6 +13067,7 @@ __export(dist_exports, {
|
|
|
12987
13067
|
defaultIsPidAlive: () => defaultIsPidAlive,
|
|
12988
13068
|
defaultListenError: () => defaultListenError,
|
|
12989
13069
|
defaultWorkRoot: () => defaultWorkRoot,
|
|
13070
|
+
deliverFirstTurnViaPeer: () => deliverFirstTurnViaPeer,
|
|
12990
13071
|
deliverStartupPrompt: () => deliverStartupPrompt,
|
|
12991
13072
|
deliverToCaptain: () => deliverToCaptain,
|
|
12992
13073
|
deliverable: () => deliverable,
|
|
@@ -13168,6 +13249,7 @@ __export(dist_exports, {
|
|
|
13168
13249
|
saveState: () => saveState,
|
|
13169
13250
|
screenHasSplashMarker: () => screenHasSplashMarker,
|
|
13170
13251
|
screenHash: () => screenHash,
|
|
13252
|
+
screenShowsTrustPanel: () => screenShowsTrustPanel,
|
|
13171
13253
|
searchRules: () => searchRules,
|
|
13172
13254
|
selectPromptHits: () => selectPromptHits,
|
|
13173
13255
|
sendRequest: () => sendRequest,
|
|
@@ -13193,6 +13275,7 @@ __export(dist_exports, {
|
|
|
13193
13275
|
toControlEvent: () => toControlEvent,
|
|
13194
13276
|
topicKey: () => topicKey,
|
|
13195
13277
|
topicName: () => topicName,
|
|
13278
|
+
trustPanelAcceptKeys: () => trustPanelAcceptKeys,
|
|
13196
13279
|
tryAcquireDaemonLock: () => tryAcquireDaemonLock,
|
|
13197
13280
|
usageFromJson: () => usageFromJson,
|
|
13198
13281
|
validateKb: () => validateKb,
|
|
@@ -13255,6 +13338,7 @@ var init_dist2 = __esm({
|
|
|
13255
13338
|
init_conformance();
|
|
13256
13339
|
init_source();
|
|
13257
13340
|
init_control_channel();
|
|
13341
|
+
init_peer_first_turn();
|
|
13258
13342
|
init_captain_channel();
|
|
13259
13343
|
init_captain_record();
|
|
13260
13344
|
init_opencode_session();
|
|
@@ -15069,6 +15153,15 @@ async function cmuxHasInputGuards() {
|
|
|
15069
15153
|
inputGuardsCache = major > 0 || minor >= 65;
|
|
15070
15154
|
return inputGuardsCache;
|
|
15071
15155
|
}
|
|
15156
|
+
function feedSessionOf(item) {
|
|
15157
|
+
const parts = item.workstream_id?.split(":");
|
|
15158
|
+
if (parts?.[0] !== "cmux-feed-v1" || !parts[2])
|
|
15159
|
+
return void 0;
|
|
15160
|
+
return Buffer.from(parts[2], "base64").toString("utf-8");
|
|
15161
|
+
}
|
|
15162
|
+
async function feedRpc(method, params) {
|
|
15163
|
+
return JSON.parse(await cmux(["rpc", method, JSON.stringify(params)]));
|
|
15164
|
+
}
|
|
15072
15165
|
function parseList(output) {
|
|
15073
15166
|
let parsed;
|
|
15074
15167
|
try {
|
|
@@ -15433,6 +15526,26 @@ function createCmuxDriver() {
|
|
|
15433
15526
|
await cmux(["send-key", "--workspace", wsId, "--surface", surfaceId, "Enter"]);
|
|
15434
15527
|
return { workspaceId: wsId, surfaceId, title: opts.title };
|
|
15435
15528
|
},
|
|
15529
|
+
// #916: cmux >= 0.65 `surface.input_state` reads the render grid (incl. faint
|
|
15530
|
+
// spans) without touching the pane. The RPC needs a surface UUID, and an
|
|
15531
|
+
// unknown ref would silently fall back to the focused surface, so resolve the
|
|
15532
|
+
// ref through the tree first. Anything unexpected → undefined (old path).
|
|
15533
|
+
async inputState(pane) {
|
|
15534
|
+
try {
|
|
15535
|
+
if (!await cmuxHasInputGuards())
|
|
15536
|
+
return void 0;
|
|
15537
|
+
const tree = JSON.parse(await cmux(["tree", "--workspace", pane.workspaceId, "--json", "--id-format", "both"]));
|
|
15538
|
+
const id = tree.windows?.flatMap((w) => w.workspaces ?? []).flatMap((w) => w.panes ?? []).flatMap((p) => p.surfaces ?? []).find((s) => s.ref === pane.surfaceId)?.id;
|
|
15539
|
+
if (!id)
|
|
15540
|
+
return void 0;
|
|
15541
|
+
const r = JSON.parse(await cmux(["rpc", "surface.input_state", JSON.stringify({ surface_id: id })]));
|
|
15542
|
+
if (r.agent !== true)
|
|
15543
|
+
return "unknown";
|
|
15544
|
+
return r.state === "empty" || r.state === "draft" || r.state === "dialog" ? r.state : "unknown";
|
|
15545
|
+
} catch {
|
|
15546
|
+
return void 0;
|
|
15547
|
+
}
|
|
15548
|
+
},
|
|
15436
15549
|
async sendToSurface(surface, text, opts) {
|
|
15437
15550
|
const ws = surface.workspaceId;
|
|
15438
15551
|
const sf = surface.surfaceId;
|
|
@@ -15459,6 +15572,17 @@ function createCmuxDriver() {
|
|
|
15459
15572
|
`);
|
|
15460
15573
|
}
|
|
15461
15574
|
};
|
|
15575
|
+
if (opts?.agent !== "opencode") {
|
|
15576
|
+
const state = await this.inputState?.(surface);
|
|
15577
|
+
if (state === "draft")
|
|
15578
|
+
throw new DeferDelivery(null, "draft");
|
|
15579
|
+
if (state === "dialog")
|
|
15580
|
+
throw new DeferDelivery(null, "modal");
|
|
15581
|
+
if (state === "empty") {
|
|
15582
|
+
await deliver();
|
|
15583
|
+
return;
|
|
15584
|
+
}
|
|
15585
|
+
}
|
|
15462
15586
|
let screen = "";
|
|
15463
15587
|
try {
|
|
15464
15588
|
screen = await cmux(["read-screen", "--workspace", ws, "--surface", sf]);
|
|
@@ -15537,6 +15661,39 @@ function createCmuxDriver() {
|
|
|
15537
15661
|
args.push("--focus", "true");
|
|
15538
15662
|
await cmux(args);
|
|
15539
15663
|
},
|
|
15664
|
+
// Feed-backed structured answer (#918). cmux >= 0.65 only; any miss
|
|
15665
|
+
// (old cmux, no matching item, unsupported shape) is undefined so the
|
|
15666
|
+
// caller keeps the keystroke path.
|
|
15667
|
+
async findDialog(match) {
|
|
15668
|
+
if (!await cmuxHasInputGuards())
|
|
15669
|
+
return void 0;
|
|
15670
|
+
let items;
|
|
15671
|
+
try {
|
|
15672
|
+
items = (await feedRpc("feed.list", { pending_only: true })).items ?? [];
|
|
15673
|
+
} catch {
|
|
15674
|
+
return void 0;
|
|
15675
|
+
}
|
|
15676
|
+
const mine = items.filter((i) => match.agentSessionId ? feedSessionOf(i) === match.agentSessionId : !!match.cwd && i.cwd === match.cwd);
|
|
15677
|
+
if (mine.length !== 1 || !mine[0].request_id)
|
|
15678
|
+
return void 0;
|
|
15679
|
+
const item = mine[0];
|
|
15680
|
+
if (item.kind !== "question" || item.questions?.length !== 1)
|
|
15681
|
+
return void 0;
|
|
15682
|
+
const labels = (item.questions[0].options ?? []).map((o) => o.label ?? "");
|
|
15683
|
+
if (labels.length === 0)
|
|
15684
|
+
return void 0;
|
|
15685
|
+
return {
|
|
15686
|
+
id: item.request_id,
|
|
15687
|
+
options: labels.map((label, i) => ({ index: i + 1, label }))
|
|
15688
|
+
};
|
|
15689
|
+
},
|
|
15690
|
+
async answerDialog(dialog, answer) {
|
|
15691
|
+
const reply = answer.text ?? answer.label;
|
|
15692
|
+
if (!reply)
|
|
15693
|
+
return false;
|
|
15694
|
+
const res = await feedRpc("feed.question.reply", { request_id: dialog.id, selections: [reply] });
|
|
15695
|
+
return res.delivered === true;
|
|
15696
|
+
},
|
|
15540
15697
|
async showPatch(opts) {
|
|
15541
15698
|
const args = ["diff", "-", "--workspace", opts.workspaceId, "--layout", opts.layout ?? "split"];
|
|
15542
15699
|
if (opts.title)
|
|
@@ -16637,6 +16794,11 @@ async function settleInputBox(runtime, pane) {
|
|
|
16637
16794
|
return sawContent;
|
|
16638
16795
|
}
|
|
16639
16796
|
async function confirmedSendToPane(runtime, pane, message) {
|
|
16797
|
+
const native = await runtime.inputState?.(pane).catch(() => void 0);
|
|
16798
|
+
if (native === "dialog")
|
|
16799
|
+
return { delivered: false, blockedByModal: true };
|
|
16800
|
+
if (native === "draft")
|
|
16801
|
+
return { delivered: false };
|
|
16640
16802
|
const preSendScreen = await runtime.readPaneScreen(pane) ?? "";
|
|
16641
16803
|
if (hasModalOptionList2(preSendScreen)) {
|
|
16642
16804
|
return { delivered: false, blockedByModal: true };
|