@wrongstack/cli 0.300.0 → 0.301.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/{acp-IDNS2YVE.js → acp-DATHHPNT.js} +34 -15
- package/dist/acp-server-agent.d.ts +1 -1
- package/dist/{audit-2ZSFGNIF.js → audit-QRCLEHHW.js} +5 -1
- package/dist/{auth-6T6ZOT2R.js → auth-JASC4K3F.js} +150 -37
- package/dist/boot/launch-menu.d.ts +2 -4
- package/dist/boot/tool-registry.d.ts +3 -0
- package/dist/chimera-reviewer-policy.d.ts +10 -3
- package/dist/chimera-work-registry.d.ts +19 -0
- package/dist/{chronicle-QQEQFSSE.js → chronicle-63MFCZN6.js} +26 -5
- package/dist/{chunk-YWUPHRGB.js → chunk-263G3FMB.js} +33 -10
- package/dist/{chunk-GYDQABMA.js → chunk-2KDOFTTM.js} +44 -32
- package/dist/chunk-CSAPOCBP.js +24 -0
- package/dist/{chunk-N7ULWBO5.js → chunk-ETOEGL3V.js} +3 -7
- package/dist/{chunk-3MWUZMOL.js → chunk-GUHQQG63.js} +14 -3
- package/dist/chunk-KE7E7DPX.js +38 -0
- package/dist/{chunk-PEMN4T5O.js → chunk-MHF2IJDE.js} +21 -4
- package/dist/{chunk-V76R7DC5.js → chunk-O7XNGCRT.js} +311 -309
- package/dist/{chunk-DPJZQCVP.js → chunk-YMXXOOFN.js} +1 -1
- package/dist/{chunk-4WJKVQJY.js → chunk-ZECLGUTF.js} +15 -3
- package/dist/{cli-main-7B3G2YSG.js → cli-main-XWC57MGE.js} +333 -98
- package/dist/{execution-SHGM7BVC.js → execution-LHMSMDHB.js} +126 -52
- package/dist/execution-chimera-cascade.d.ts +3 -4
- package/dist/execution-chimera-review.d.ts +2 -3
- package/dist/execution-cleanup.d.ts +3 -2
- package/dist/execution.d.ts +1 -1
- package/dist/{export-TPORYVRZ.js → export-DOBGPY23.js} +12 -1
- package/dist/fleet/host-context.d.ts +1 -1
- package/dist/fleet/host-helpers.d.ts +14 -0
- package/dist/fleet/status-broadcast.d.ts +1 -1
- package/dist/{hq-DVDD4XPV.js → hq-LN5CJHCM.js} +2 -2
- package/dist/hq-server/routes.d.ts +10 -1
- package/dist/hq-server/ws.d.ts +17 -6
- package/dist/{hq-server-DQHLNHDL.js → hq-server-S7HZG3PA.js} +3 -2
- package/dist/index.js +63 -98
- package/dist/live-settings-input.d.ts +5 -0
- package/dist/{mcp-CYLPUEHC.js → mcp-OHPJH73U.js} +6 -2
- package/dist/{modeldiag-YOQZHBQV.js → modeldiag-3DOK4BWW.js} +2 -2
- package/dist/{plugin-usage-EOG4ET4S.js → plugin-usage-YEVLOR33.js} +7 -3
- package/dist/{plugins-56CMWMPR.js → plugins-K3BAUP4D.js} +3 -3
- package/dist/profile-config-path.d.ts +0 -2
- package/dist/provider-helpers.d.ts +0 -5
- package/dist/{providers-models-K6RT7ABI.js → providers-models-WEZ4EGLL.js} +6 -5
- package/dist/{replay-KCTXNMZQ.js → replay-FCBNHW3K.js} +5 -1
- package/dist/{rewind-EJMVFVLS.js → rewind-AOD3JIYX.js} +5 -1
- package/dist/{sessions-config-NLCMK3BY.js → sessions-config-XXN7267N.js} +8 -3
- package/dist/subcommands/flags.d.ts +23 -0
- package/dist/terminal-format.d.ts +15 -0
- package/dist/{webui-server-G3EKFXLL.js → webui-server-DD35QFNO.js} +5 -13
- package/dist/wiring/brain-and-orchestration.d.ts +1 -1
- package/dist/wiring/mailbox-bridge-bootstrap.d.ts +3 -1
- package/dist/wiring/management-tools.d.ts +9 -1
- package/dist/wiring/pipeline.d.ts +5 -5
- package/dist/wiring/plugins.d.ts +2 -3
- package/dist/wiring/provider-utility-tools.d.ts +1 -0
- package/dist/wiring/tools.d.ts +4 -5
- package/package.json +23 -23
|
@@ -31,12 +31,19 @@ import {
|
|
|
31
31
|
import {
|
|
32
32
|
fmtTok
|
|
33
33
|
} from "./chunk-TYO2OVAD.js";
|
|
34
|
+
import {
|
|
35
|
+
terminalLink,
|
|
36
|
+
terminalText
|
|
37
|
+
} from "./chunk-KE7E7DPX.js";
|
|
34
38
|
import {
|
|
35
39
|
CLI_VERSION
|
|
36
40
|
} from "./chunk-XJXDOF63.js";
|
|
37
41
|
import {
|
|
38
42
|
resolveActiveApiKey
|
|
39
43
|
} from "./chunk-PJHET45A.js";
|
|
44
|
+
import {
|
|
45
|
+
activeProfileConfigPath
|
|
46
|
+
} from "./chunk-YMXXOOFN.js";
|
|
40
47
|
import "./chunk-7OCVIDC7.js";
|
|
41
48
|
|
|
42
49
|
// src/execution.ts
|
|
@@ -188,7 +195,7 @@ async function runWebUIDispatch(ctx) {
|
|
|
188
195
|
const isSimpleUi = flags["simpleui"] === true;
|
|
189
196
|
agent.disableInteractiveConfirmation();
|
|
190
197
|
renderer.setSilent(true);
|
|
191
|
-
const { runWebUI } = await import("./webui-server-
|
|
198
|
+
const { runWebUI } = await import("./webui-server-DD35QFNO.js");
|
|
192
199
|
const flagValue = (names) => {
|
|
193
200
|
for (const name of names) {
|
|
194
201
|
if (!Object.hasOwn(flags, name)) continue;
|
|
@@ -311,10 +318,12 @@ async function runWebUIDispatch(ctx) {
|
|
|
311
318
|
// the default when it is taken (a second instance, leftover socket).
|
|
312
319
|
onListening: ({ url }) => {
|
|
313
320
|
const surface = isSimpleUi ? "SimpleUI" : "WebUI";
|
|
314
|
-
renderer.writeInfo(color2.green(` \u2726 ${surface} running \u2192 ${color2.bold(url)}`));
|
|
315
321
|
renderer.writeInfo(
|
|
316
|
-
|
|
317
|
-
|
|
322
|
+
` \u2726 ${terminalText(surface, "success", { bold: true })} ${terminalText("running \u2192", "muted")} ${terminalLink(url)}`
|
|
323
|
+
);
|
|
324
|
+
renderer.writeInfo(
|
|
325
|
+
` ${terminalText(`Press Ctrl+C in this terminal to stop the ${surface} server.`, "muted")}
|
|
326
|
+
`
|
|
318
327
|
);
|
|
319
328
|
},
|
|
320
329
|
// Make autonomy.switch from the browser flip the CLI's real
|
|
@@ -837,13 +846,16 @@ async function handleProjectSwitchSpawn(opts) {
|
|
|
837
846
|
const nodeExe = process.execPath;
|
|
838
847
|
const spawnArgs = [cliPath, "--no-interactive"];
|
|
839
848
|
if (resumeSessionId) spawnArgs.push("--resume", resumeSessionId);
|
|
840
|
-
spawn(nodeExe, spawnArgs, {
|
|
849
|
+
const child = spawn(nodeExe, spawnArgs, {
|
|
841
850
|
cwd: root,
|
|
842
851
|
stdio: "ignore",
|
|
843
|
-
detached: true
|
|
844
|
-
|
|
852
|
+
detached: true,
|
|
853
|
+
windowsHide: true
|
|
854
|
+
});
|
|
855
|
+
child.on("error", (err) => {
|
|
845
856
|
console.error(color4.red(`Failed to spawn wstack: ${err.message}`));
|
|
846
857
|
});
|
|
858
|
+
child.unref();
|
|
847
859
|
console.log(
|
|
848
860
|
[
|
|
849
861
|
"",
|
|
@@ -938,6 +950,7 @@ async function switchProjectInPlace(ctx, targetRoot, displayName) {
|
|
|
938
950
|
context.state.replaceMessages([]);
|
|
939
951
|
context.state.replaceTodos([]);
|
|
940
952
|
context.clearFileTracking();
|
|
953
|
+
context.clearMemoryEvidence?.();
|
|
941
954
|
context.tokenCounter.reset();
|
|
942
955
|
context.meta["packageTrackerOpts"] = { storageDir: nextWpaths.projectDir, projectRoot: resolved };
|
|
943
956
|
context.state.setMeta(
|
|
@@ -979,7 +992,8 @@ async function switchProjectInPlace(ctx, targetRoot, displayName) {
|
|
|
979
992
|
context.systemPrompt = await switchBuilder.build({
|
|
980
993
|
cwd: resolved,
|
|
981
994
|
projectRoot: resolved,
|
|
982
|
-
tools: agent.tools.
|
|
995
|
+
tools: agent.tools.listForProvider(),
|
|
996
|
+
catalogTools: agent.tools.list(),
|
|
983
997
|
provider: context.provider.id,
|
|
984
998
|
model: context.model
|
|
985
999
|
});
|
|
@@ -1293,7 +1307,7 @@ import * as fs3 from "node:fs/promises";
|
|
|
1293
1307
|
import * as path7 from "node:path";
|
|
1294
1308
|
import { decryptConfigSecrets, encryptConfigSecrets, noOpVault } from "@wrongstack/core/security";
|
|
1295
1309
|
import { normalizeTokenSavingTier, resolveFleetChatVerbosity } from "@wrongstack/core/types";
|
|
1296
|
-
import { atomicWrite } from "@wrongstack/core/utils";
|
|
1310
|
+
import { atomicWrite, deepMerge } from "@wrongstack/core/utils";
|
|
1297
1311
|
import { getProcessRegistry } from "@wrongstack/tools";
|
|
1298
1312
|
var PANEL_IDS_CLI = [
|
|
1299
1313
|
"projectPicker",
|
|
@@ -1372,6 +1386,7 @@ function createSettingsAdapter(ctx) {
|
|
|
1372
1386
|
auditLevel: cfg.session?.auditLevel ?? "standard",
|
|
1373
1387
|
indexOnStart: cfg.indexing?.onSessionStart !== false,
|
|
1374
1388
|
maxIterations: cfg.tools?.maxIterations ?? 500,
|
|
1389
|
+
nextStepsTool: cfg.tools?.nextsteps?.enabled === true,
|
|
1375
1390
|
restrictFsToRoot: resolvedRestrict,
|
|
1376
1391
|
autoProceedMaxIterations: cfg.autonomy?.autoProceedMaxIterations ?? 50,
|
|
1377
1392
|
debugStream: cfg.debugStream ?? false,
|
|
@@ -1411,12 +1426,15 @@ function createSettingsAdapter(ctx) {
|
|
|
1411
1426
|
}
|
|
1412
1427
|
async function saveSettings(s) {
|
|
1413
1428
|
try {
|
|
1414
|
-
if (s.mode !== void 0 || s.delayMs !== void 0 || s.titleAnimation !== void 0 || s.yolo !== void 0 || s.fleetChatVerbosity !== void 0 || s.chime !== void 0 || s.confirmExit !== void 0 || s.mouseMode !== void 0 || s.featureMcp !== void 0 || s.featurePlugins !== void 0 || s.featureMemory !== void 0 || s.featureSkills !== void 0 || s.featureModelsRegistry !== void 0 || s.featureTokenSaving !== void 0 || s.allowOutsideProjectRoot !== void 0 || s.contextAutoCompact !== void 0 || s.contextStrategy !== void 0 || s.contextMode !== void 0 || s.maxConcurrent !== void 0 || s.logLevel !== void 0 || s.auditLevel !== void 0 || s.indexOnStart !== void 0 || s.maxIterations !== void 0 || s.restrictFsToRoot !== void 0 || s.nextPrediction !== void 0 || s.debugStream !== void 0 || s.shellBangWarningDontShowAgain !== void 0 || s.configScope !== void 0 || s.enhanceDelayMs !== void 0 || s.enhanceEnabled !== void 0 || s.enhanceLanguage !== void 0 || s.midRunSendPicker !== void 0 || s.statuslineMode !== void 0 || s.thinkingWord !== void 0 || s.animationStyle !== void 0 || s.autonomyNextPrompt !== void 0 || s.autoProceedMaxIterations !== void 0 || s.reasoningMode !== void 0 || s.reasoningEffort !== void 0 || s.reasoningPreserve !== void 0 || s.cacheTtl !== void 0 || s.breakerEnabled !== void 0 || s.breakerAutoKillResetMs !== void 0 || s.showModelReasoning !== void 0 || s.showAgentSwarmPanel !== void 0 || s.panelPositions !== void 0 || s.showSageMemoryInject !== void 0 || s.sageMemoryInjectThreshold !== void 0 || s.readSymbols !== void 0) {
|
|
1429
|
+
if (s.mode !== void 0 || s.delayMs !== void 0 || s.titleAnimation !== void 0 || s.yolo !== void 0 || s.fleetChatVerbosity !== void 0 || s.chime !== void 0 || s.confirmExit !== void 0 || s.mouseMode !== void 0 || s.featureMcp !== void 0 || s.featurePlugins !== void 0 || s.featureMemory !== void 0 || s.featureSkills !== void 0 || s.featureModelsRegistry !== void 0 || s.featureTokenSaving !== void 0 || s.allowOutsideProjectRoot !== void 0 || s.contextAutoCompact !== void 0 || s.contextStrategy !== void 0 || s.contextMode !== void 0 || s.maxConcurrent !== void 0 || s.logLevel !== void 0 || s.auditLevel !== void 0 || s.indexOnStart !== void 0 || s.maxIterations !== void 0 || s.nextStepsTool !== void 0 || s.restrictFsToRoot !== void 0 || s.nextPrediction !== void 0 || s.debugStream !== void 0 || s.shellBangWarningDontShowAgain !== void 0 || s.configScope !== void 0 || s.enhanceDelayMs !== void 0 || s.enhanceEnabled !== void 0 || s.enhanceLanguage !== void 0 || s.midRunSendPicker !== void 0 || s.statuslineMode !== void 0 || s.thinkingWord !== void 0 || s.animationStyle !== void 0 || s.autonomyNextPrompt !== void 0 || s.autoProceedMaxIterations !== void 0 || s.reasoningMode !== void 0 || s.reasoningEffort !== void 0 || s.reasoningPreserve !== void 0 || s.cacheTtl !== void 0 || s.breakerEnabled !== void 0 || s.breakerAutoKillResetMs !== void 0 || s.showModelReasoning !== void 0 || s.showAgentSwarmPanel !== void 0 || s.panelPositions !== void 0 || s.showSageMemoryInject !== void 0 || s.sageMemoryInjectThreshold !== void 0 || s.readSymbols !== void 0) {
|
|
1415
1430
|
const cfg = configStore.get();
|
|
1416
|
-
const activeProfileName = cfg.activeProfile ?? "default";
|
|
1417
1431
|
const persistDeps = {
|
|
1418
1432
|
configStore,
|
|
1419
|
-
|
|
1433
|
+
// Third copy of "which profile is active" — an inline cast plus a
|
|
1434
|
+
// `?? 'default'`, identical to `activeProfileConfigPath` two files
|
|
1435
|
+
// over. The comment above already promised this resolution was
|
|
1436
|
+
// delegated; now it is.
|
|
1437
|
+
profileConfigPath: activeProfileConfigPath(wpaths, cfg),
|
|
1420
1438
|
inProjectConfigPath: wpaths.inProjectConfig,
|
|
1421
1439
|
vault: noOpVault,
|
|
1422
1440
|
resolveProfilePath: (name) => wpaths.profileConfig(name)
|
|
@@ -1506,9 +1524,10 @@ function createSettingsAdapter(ctx) {
|
|
|
1506
1524
|
idx.onSessionStart = s.indexOnStart;
|
|
1507
1525
|
decrypted.indexing = idx;
|
|
1508
1526
|
}
|
|
1509
|
-
if (s.maxIterations !== void 0 || fsAccess !== void 0) {
|
|
1527
|
+
if (s.maxIterations !== void 0 || s.nextStepsTool !== void 0 || fsAccess !== void 0) {
|
|
1510
1528
|
const tools = decrypted.tools ?? {};
|
|
1511
1529
|
if (s.maxIterations !== void 0) tools.maxIterations = s.maxIterations;
|
|
1530
|
+
if (s.nextStepsTool !== void 0) tools.nextsteps = { enabled: s.nextStepsTool };
|
|
1512
1531
|
if (fsAccess !== void 0) tools.restrictToProjectRoot = fsAccess.restrictToProjectRoot;
|
|
1513
1532
|
decrypted.tools = tools;
|
|
1514
1533
|
}
|
|
@@ -1563,7 +1582,7 @@ function createSettingsAdapter(ctx) {
|
|
|
1563
1582
|
const destRaw = await fs3.readFile(actualTarget, "utf8");
|
|
1564
1583
|
const destParsed = JSON.parse(destRaw);
|
|
1565
1584
|
const destDecrypted = decryptConfigSecrets(destParsed, noOpVault);
|
|
1566
|
-
mergedToWrite =
|
|
1585
|
+
mergedToWrite = deepMerge(destDecrypted, decrypted);
|
|
1567
1586
|
} catch (err) {
|
|
1568
1587
|
if (err.code !== "ENOENT") {
|
|
1569
1588
|
throw new Error(
|
|
@@ -1620,7 +1639,7 @@ function createSettingsAdapter(ctx) {
|
|
|
1620
1639
|
...decrypted.indexing ?? {}
|
|
1621
1640
|
}
|
|
1622
1641
|
} : {},
|
|
1623
|
-
...s.maxIterations !== void 0 || fsAccess !== void 0 ? {
|
|
1642
|
+
...s.maxIterations !== void 0 || s.nextStepsTool !== void 0 || fsAccess !== void 0 ? {
|
|
1624
1643
|
tools: {
|
|
1625
1644
|
...currentConfig.tools,
|
|
1626
1645
|
...decrypted.tools ?? {}
|
|
@@ -1734,6 +1753,7 @@ function createBrainPanelHost(deps) {
|
|
|
1734
1753
|
councilDistinctness: snap.council.distinctness,
|
|
1735
1754
|
councilPerCallTimeoutMs: snap.council.perCallTimeoutMs,
|
|
1736
1755
|
councilMaxConcurrency: snap.council.maxConcurrency,
|
|
1756
|
+
councilVoterMaxTokens: snap.council.voterMaxTokens,
|
|
1737
1757
|
councilJudgeMaxTokens: snap.council.judgeMaxTokens,
|
|
1738
1758
|
// The EFFECTIVE judge, not `council.judge`. The configured one is
|
|
1739
1759
|
// usually absent, so the panel used to read "auto" and say nothing
|
|
@@ -1815,6 +1835,7 @@ function createBrainPanelHost(deps) {
|
|
|
1815
1835
|
setCouncilDistinctness: (mode) => apply({ council: { distinctness: mode } }),
|
|
1816
1836
|
setCouncilPerCallTimeout: (ms) => apply({ council: { perCallTimeoutMs: ms ?? null } }),
|
|
1817
1837
|
setCouncilMaxConcurrency: (count) => apply({ council: { maxConcurrency: count ?? null } }),
|
|
1838
|
+
setCouncilVoterMaxTokens: (tokens) => apply({ council: { voterMaxTokens: tokens ?? null } }),
|
|
1818
1839
|
setCouncilJudgeMaxTokens: (tokens) => apply({ council: { judgeMaxTokens: tokens ?? null } }),
|
|
1819
1840
|
setLedgerEnabled: (on) => apply({ ledger: { enabled: on } }),
|
|
1820
1841
|
setAutoDeny: (count) => apply({ ledger: { autoDenyAfterFailures: count ?? null } }),
|
|
@@ -1851,7 +1872,7 @@ var reviewerRoundRobinCursor = 0;
|
|
|
1851
1872
|
function __resetReviewerRoundRobinCursor(value = 0) {
|
|
1852
1873
|
reviewerRoundRobinCursor = value;
|
|
1853
1874
|
}
|
|
1854
|
-
function
|
|
1875
|
+
function assignReviewerModels(provider, model, fallbackModels, selection = "round-robin", statusTracker, random = Math.random) {
|
|
1855
1876
|
const pool = buildReviewerModelPool(provider, model, fallbackModels, statusTracker);
|
|
1856
1877
|
if (pool.length <= 1) {
|
|
1857
1878
|
return {
|
|
@@ -1860,20 +1881,24 @@ function assignReviewerModelsRoundRobin(provider, model, fallbackModels, statusT
|
|
|
1860
1881
|
fallbackModels: [...fallbackModels]
|
|
1861
1882
|
};
|
|
1862
1883
|
}
|
|
1884
|
+
const cursor = selection === "random" ? Math.min(pool.length - 1, Math.floor(Math.max(0, random()) * pool.length)) : reviewerRoundRobinCursor;
|
|
1863
1885
|
const assignment = selectRoundRobinReviewerAssignment(
|
|
1864
1886
|
pool,
|
|
1865
|
-
|
|
1887
|
+
cursor,
|
|
1866
1888
|
provider,
|
|
1867
1889
|
model,
|
|
1868
1890
|
statusTracker
|
|
1869
1891
|
);
|
|
1870
|
-
reviewerRoundRobinCursor = assignment.nextCursor;
|
|
1892
|
+
if (selection === "round-robin") reviewerRoundRobinCursor = assignment.nextCursor;
|
|
1871
1893
|
return {
|
|
1872
1894
|
provider: assignment.provider,
|
|
1873
1895
|
model: assignment.model,
|
|
1874
1896
|
fallbackModels: assignment.fallbackModels
|
|
1875
1897
|
};
|
|
1876
1898
|
}
|
|
1899
|
+
function assignReviewerModelsRoundRobin(provider, model, fallbackModels, statusTracker) {
|
|
1900
|
+
return assignReviewerModels(provider, model, fallbackModels, "round-robin", statusTracker);
|
|
1901
|
+
}
|
|
1877
1902
|
var MAX_REVIEWER_ATTEMPTS = 4;
|
|
1878
1903
|
var REVIEWER_ATTEMPT_TIMEOUT_MS = 9e5;
|
|
1879
1904
|
var REVIEWER_LADDER_BUDGET_MS = 12e5;
|
|
@@ -1976,7 +2001,7 @@ async function finalizeExecutionCleanup(input) {
|
|
|
1976
2001
|
session,
|
|
1977
2002
|
tokenCounter,
|
|
1978
2003
|
events,
|
|
1979
|
-
|
|
2004
|
+
chimeraWork,
|
|
1980
2005
|
director,
|
|
1981
2006
|
reader
|
|
1982
2007
|
} = input;
|
|
@@ -2028,25 +2053,34 @@ async function finalizeExecutionCleanup(input) {
|
|
|
2028
2053
|
})
|
|
2029
2054
|
);
|
|
2030
2055
|
});
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
event: "shutdown.chimera_work_failed",
|
|
2044
|
-
message: `Pending chimera work failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
2045
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2046
|
-
})
|
|
2047
|
-
);
|
|
2048
|
-
});
|
|
2056
|
+
const sessionEndProducers = /* @__PURE__ */ new Set();
|
|
2057
|
+
events.emit(
|
|
2058
|
+
"session.ended",
|
|
2059
|
+
{
|
|
2060
|
+
id: activeSession.id,
|
|
2061
|
+
sessionId: activeSession.id,
|
|
2062
|
+
usage: tokenCounter.total(),
|
|
2063
|
+
waitUntil: (work) => {
|
|
2064
|
+
const tracked = Promise.resolve(work).finally(() => sessionEndProducers.delete(tracked));
|
|
2065
|
+
void tracked.catch(() => void 0);
|
|
2066
|
+
sessionEndProducers.add(tracked);
|
|
2067
|
+
}
|
|
2049
2068
|
}
|
|
2069
|
+
);
|
|
2070
|
+
try {
|
|
2071
|
+
while (sessionEndProducers.size > 0) {
|
|
2072
|
+
await Promise.allSettled([...sessionEndProducers]);
|
|
2073
|
+
}
|
|
2074
|
+
await chimeraWork?.drainAndClose();
|
|
2075
|
+
} catch (err) {
|
|
2076
|
+
console.warn(
|
|
2077
|
+
JSON.stringify({
|
|
2078
|
+
level: "warn",
|
|
2079
|
+
event: "shutdown.chimera_work_failed",
|
|
2080
|
+
message: `Pending chimera work failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
2081
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2082
|
+
})
|
|
2083
|
+
);
|
|
2050
2084
|
}
|
|
2051
2085
|
if (director) {
|
|
2052
2086
|
try {
|
|
@@ -2447,6 +2481,43 @@ var FleetStatusLine = class {
|
|
|
2447
2481
|
}
|
|
2448
2482
|
};
|
|
2449
2483
|
|
|
2484
|
+
// src/chimera-work-registry.ts
|
|
2485
|
+
function createChimeraWorkRegistry() {
|
|
2486
|
+
const pending = /* @__PURE__ */ new Set();
|
|
2487
|
+
let accepting = true;
|
|
2488
|
+
let closePromise;
|
|
2489
|
+
const track = (work) => {
|
|
2490
|
+
if (!accepting) return false;
|
|
2491
|
+
const tracked = Promise.resolve(work).finally(() => {
|
|
2492
|
+
pending.delete(tracked);
|
|
2493
|
+
});
|
|
2494
|
+
void tracked.catch(() => void 0);
|
|
2495
|
+
pending.add(tracked);
|
|
2496
|
+
return true;
|
|
2497
|
+
};
|
|
2498
|
+
const snapshot = () => {
|
|
2499
|
+
if (pending.size === 0) return void 0;
|
|
2500
|
+
return Promise.allSettled([...pending]).then(() => void 0);
|
|
2501
|
+
};
|
|
2502
|
+
const drainAndClose = () => {
|
|
2503
|
+
closePromise ??= (async () => {
|
|
2504
|
+
while (pending.size > 0) {
|
|
2505
|
+
await Promise.allSettled([...pending]);
|
|
2506
|
+
}
|
|
2507
|
+
accepting = false;
|
|
2508
|
+
})();
|
|
2509
|
+
return closePromise;
|
|
2510
|
+
};
|
|
2511
|
+
return {
|
|
2512
|
+
track,
|
|
2513
|
+
pending: snapshot,
|
|
2514
|
+
drainAndClose,
|
|
2515
|
+
get size() {
|
|
2516
|
+
return pending.size;
|
|
2517
|
+
}
|
|
2518
|
+
};
|
|
2519
|
+
}
|
|
2520
|
+
|
|
2450
2521
|
// src/execution-chimera-cascade.ts
|
|
2451
2522
|
import * as fsp from "node:fs/promises";
|
|
2452
2523
|
import * as path8 from "node:path";
|
|
@@ -2708,7 +2779,7 @@ function installChimeraCascadeHandler({
|
|
|
2708
2779
|
director,
|
|
2709
2780
|
session,
|
|
2710
2781
|
getPendingWork,
|
|
2711
|
-
|
|
2782
|
+
trackWork,
|
|
2712
2783
|
buildLadder
|
|
2713
2784
|
}) {
|
|
2714
2785
|
events.onPattern("chimera.cascade_needed", (_event, payload) => {
|
|
@@ -2797,7 +2868,7 @@ function installChimeraCascadeHandler({
|
|
|
2797
2868
|
}
|
|
2798
2869
|
await maybeReReviewCascade({ events, session, bundle: p.bundle });
|
|
2799
2870
|
})();
|
|
2800
|
-
|
|
2871
|
+
trackWork(pendingWork);
|
|
2801
2872
|
});
|
|
2802
2873
|
}
|
|
2803
2874
|
async function maybeReReviewCascade({
|
|
@@ -2836,7 +2907,7 @@ async function maybeReReviewCascade({
|
|
|
2836
2907
|
stopReason: "end_turn",
|
|
2837
2908
|
usage: { input: 0, output: 0 }
|
|
2838
2909
|
});
|
|
2839
|
-
const emitted = emitReviewIfChanged(
|
|
2910
|
+
const emitted = await emitReviewIfChanged(
|
|
2840
2911
|
{ events, emitCustom: events.emitCustom.bind(events) },
|
|
2841
2912
|
reReviewBundle
|
|
2842
2913
|
);
|
|
@@ -2908,13 +2979,14 @@ function installChimeraReviewHandler({
|
|
|
2908
2979
|
projectDir,
|
|
2909
2980
|
statusTracker,
|
|
2910
2981
|
persistReview = persistChimeraReview,
|
|
2911
|
-
|
|
2982
|
+
trackWork
|
|
2912
2983
|
}) {
|
|
2913
2984
|
events.onPattern("chimera.review_needed", (_event, payload) => {
|
|
2914
2985
|
const p = payload;
|
|
2915
2986
|
const reviewSessionId = agent.ctx.activeRunSessionId ?? agent.ctx.session?.id ?? session.id;
|
|
2916
2987
|
const dir = director;
|
|
2917
2988
|
if (!dir) {
|
|
2989
|
+
void recordCompletedReview(events, { bundle: p }).catch(() => void 0);
|
|
2918
2990
|
return;
|
|
2919
2991
|
}
|
|
2920
2992
|
if (p.files.length === 0) return;
|
|
@@ -2957,11 +3029,11 @@ function installChimeraReviewHandler({
|
|
|
2957
3029
|
`\u{1F982} Chimera report persistence failed: ${message}. The review remains in the session transcript and mailbox.`
|
|
2958
3030
|
);
|
|
2959
3031
|
} finally {
|
|
2960
|
-
recordCompletedReview(events, completion);
|
|
3032
|
+
await recordCompletedReview(events, completion);
|
|
2961
3033
|
events.emitCustom("chimera.review_complete", completion);
|
|
2962
3034
|
}
|
|
2963
3035
|
};
|
|
2964
|
-
|
|
3036
|
+
trackWork(
|
|
2965
3037
|
(async () => {
|
|
2966
3038
|
let subagentId;
|
|
2967
3039
|
try {
|
|
@@ -2973,10 +3045,11 @@ function installChimeraReviewHandler({
|
|
|
2973
3045
|
const baseProvider = rawProvider || tProvider || config.provider;
|
|
2974
3046
|
const baseModel = rawModel || tModel || config.model;
|
|
2975
3047
|
const baseFallbacks = p.reviewFallbackModels ? [...p.reviewFallbackModels] : resolveReviewerFallbackModels(void 0);
|
|
2976
|
-
const assigned =
|
|
3048
|
+
const assigned = assignReviewerModels(
|
|
2977
3049
|
baseProvider,
|
|
2978
3050
|
baseModel,
|
|
2979
3051
|
baseFallbacks,
|
|
3052
|
+
p.reviewModelSelection ?? "round-robin",
|
|
2980
3053
|
statusTracker
|
|
2981
3054
|
);
|
|
2982
3055
|
const ladder = buildReviewerAttemptLadder({
|
|
@@ -4555,7 +4628,7 @@ async function execute(deps) {
|
|
|
4555
4628
|
const profileName = config.activeProfile ?? "default";
|
|
4556
4629
|
const bootUpdateInfo = initialUpdateInfo;
|
|
4557
4630
|
const offStorageObservability = installStorageObservability(events, context.traceId);
|
|
4558
|
-
|
|
4631
|
+
const chimeraWork = createChimeraWorkRegistry();
|
|
4559
4632
|
installChimeraReviewHandler({
|
|
4560
4633
|
events,
|
|
4561
4634
|
director,
|
|
@@ -4569,8 +4642,8 @@ async function execute(deps) {
|
|
|
4569
4642
|
// this, a 429-stricken model is re-spawned on every concurrent reviewer
|
|
4570
4643
|
// turn and burns the whole chain instead of staying quarantined.
|
|
4571
4644
|
statusTracker,
|
|
4572
|
-
|
|
4573
|
-
|
|
4645
|
+
trackWork: (work) => {
|
|
4646
|
+
chimeraWork.track(work);
|
|
4574
4647
|
}
|
|
4575
4648
|
});
|
|
4576
4649
|
installChimeraCascadeHandler({
|
|
@@ -4581,9 +4654,9 @@ async function execute(deps) {
|
|
|
4581
4654
|
profileChain: effectiveFallbackChain2(config),
|
|
4582
4655
|
session: { provider: config.provider, model: config.model }
|
|
4583
4656
|
}),
|
|
4584
|
-
getPendingWork: () =>
|
|
4585
|
-
|
|
4586
|
-
|
|
4657
|
+
getPendingWork: () => chimeraWork.pending(),
|
|
4658
|
+
trackWork: (work) => {
|
|
4659
|
+
chimeraWork.track(work);
|
|
4587
4660
|
}
|
|
4588
4661
|
});
|
|
4589
4662
|
let code = 0;
|
|
@@ -4995,7 +5068,7 @@ async function execute(deps) {
|
|
|
4995
5068
|
session,
|
|
4996
5069
|
tokenCounter,
|
|
4997
5070
|
events,
|
|
4998
|
-
|
|
5071
|
+
chimeraWork,
|
|
4999
5072
|
director,
|
|
5000
5073
|
reader
|
|
5001
5074
|
});
|
|
@@ -5006,8 +5079,9 @@ export {
|
|
|
5006
5079
|
CHIMERA_REVIEW_READ_ONLY_TOOLS,
|
|
5007
5080
|
__resetReviewerRoundRobinCursor,
|
|
5008
5081
|
applyChimeraReviewerReadOnlyPolicy,
|
|
5082
|
+
assignReviewerModels,
|
|
5009
5083
|
assignReviewerModelsRoundRobin,
|
|
5010
5084
|
execute,
|
|
5011
5085
|
resolveReviewerFallbackModels
|
|
5012
5086
|
};
|
|
5013
|
-
//# sourceMappingURL=execution-
|
|
5087
|
+
//# sourceMappingURL=execution-LHMSMDHB.js.map
|
|
@@ -3,19 +3,18 @@ import type { ExecuteDeps } from './execute-deps.js';
|
|
|
3
3
|
type Director = NonNullable<ExecuteDeps['fleet']['director']>;
|
|
4
4
|
type Events = ExecuteDeps['core']['events'];
|
|
5
5
|
type Session = ExecuteDeps['session']['session'];
|
|
6
|
-
type PendingChimeraWork = Promise<void> | undefined;
|
|
7
6
|
export type InstallChimeraCascadeHandlerOptions = {
|
|
8
7
|
events: Events;
|
|
9
8
|
director: Director | null | undefined;
|
|
10
9
|
session: Session;
|
|
11
|
-
getPendingWork: () =>
|
|
12
|
-
|
|
10
|
+
getPendingWork: () => Promise<void> | undefined;
|
|
11
|
+
trackWork: (work: Promise<void>) => void;
|
|
13
12
|
/**
|
|
14
13
|
* Model ladder for cascade spawns. Supplied by the caller because only it
|
|
15
14
|
* holds the live config. Omit to keep the single unpinned spawn.
|
|
16
15
|
*/
|
|
17
16
|
buildLadder?: (() => ReviewerAttempt[]) | undefined;
|
|
18
17
|
};
|
|
19
|
-
export declare function installChimeraCascadeHandler({ events, director, session, getPendingWork,
|
|
18
|
+
export declare function installChimeraCascadeHandler({ events, director, session, getPendingWork, trackWork, buildLadder, }: InstallChimeraCascadeHandlerOptions): void;
|
|
20
19
|
export {};
|
|
21
20
|
//# sourceMappingURL=execution-chimera-cascade.d.ts.map
|
|
@@ -7,7 +7,6 @@ type Session = ExecuteDeps['session']['session'];
|
|
|
7
7
|
type Mailbox = ExecuteDeps['session']['mailbox'];
|
|
8
8
|
type Agent = ExecuteDeps['core']['agent'];
|
|
9
9
|
type Config = ExecuteDeps['core']['config'];
|
|
10
|
-
type PendingChimeraWork = Promise<void> | undefined;
|
|
11
10
|
/**
|
|
12
11
|
* Canonicalize a file path for citation gating. The reviewer can cite
|
|
13
12
|
* absolute Windows paths (`D:\Codebox\...`) or mix casing on a
|
|
@@ -38,8 +37,8 @@ export type InstallChimeraReviewHandlerOptions = {
|
|
|
38
37
|
*/
|
|
39
38
|
statusTracker?: ProviderModelStatusTracker | undefined;
|
|
40
39
|
persistReview?: ((payload: ChimeraReviewCompletePayload, projectDir: string) => Promise<void>) | undefined;
|
|
41
|
-
|
|
40
|
+
trackWork: (work: Promise<void>) => void;
|
|
42
41
|
};
|
|
43
|
-
export declare function installChimeraReviewHandler({ events, director, session, mailbox, agent, config, projectDir, statusTracker, persistReview,
|
|
42
|
+
export declare function installChimeraReviewHandler({ events, director, session, mailbox, agent, config, projectDir, statusTracker, persistReview, trackWork, }: InstallChimeraReviewHandlerOptions): void;
|
|
44
43
|
export {};
|
|
45
44
|
//# sourceMappingURL=execution-chimera-review.d.ts.map
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Director } from '@wrongstack/core/coordination';
|
|
2
|
+
import type { ChimeraWorkRegistry } from './chimera-work-registry.js';
|
|
2
3
|
import type { ExecuteDeps } from './execute-deps.js';
|
|
3
4
|
import type { FleetStatusLine } from './fleet-statusline.js';
|
|
4
5
|
export interface ExecutionCleanupInput {
|
|
@@ -13,8 +14,8 @@ export interface ExecutionCleanupInput {
|
|
|
13
14
|
session: ExecuteDeps['session']['session'];
|
|
14
15
|
tokenCounter: ExecuteDeps['core']['tokenCounter'];
|
|
15
16
|
events: ExecuteDeps['core']['events'];
|
|
16
|
-
/**
|
|
17
|
-
|
|
17
|
+
/** Session-scoped Chimera work tracker; drained before agent/session teardown. */
|
|
18
|
+
chimeraWork?: ChimeraWorkRegistry | undefined;
|
|
18
19
|
/** Optional director reference for fleet cleanup at session end. */
|
|
19
20
|
director?: Director | null | undefined;
|
|
20
21
|
reader: ExecuteDeps['ui']['reader'];
|
package/dist/execution.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ExecuteDeps } from './execute-deps.js';
|
|
2
2
|
export type { LiveSettingsInput } from './live-settings-input.js';
|
|
3
|
-
export { __resetReviewerRoundRobinCursor, applyChimeraReviewerReadOnlyPolicy, assignReviewerModelsRoundRobin, CHIMERA_REVIEW_READ_ONLY_TOOLS, resolveReviewerFallbackModels, } from './chimera-reviewer-policy.js';
|
|
3
|
+
export { __resetReviewerRoundRobinCursor, applyChimeraReviewerReadOnlyPolicy, assignReviewerModels, assignReviewerModelsRoundRobin, CHIMERA_REVIEW_READ_ONLY_TOOLS, resolveReviewerFallbackModels, } from './chimera-reviewer-policy.js';
|
|
4
4
|
export type { BrainData, BrainLogEntry, ExecuteDeps, McpPickerItem, PluginPickerItem, RestoredToolCall, ToolPickerItem, } from './execute-deps.js';
|
|
5
5
|
export declare function execute(deps: ExecuteDeps): Promise<number>;
|
|
6
6
|
//# sourceMappingURL=execution.d.ts.map
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
restoreFlags
|
|
3
|
+
} from "./chunk-CSAPOCBP.js";
|
|
1
4
|
import "./chunk-7OCVIDC7.js";
|
|
2
5
|
|
|
3
6
|
// src/subcommands/handlers/export.ts
|
|
@@ -7,6 +10,14 @@ import { DefaultSessionReader } from "@wrongstack/core/storage";
|
|
|
7
10
|
import { expectDefined } from "@wrongstack/core/utils";
|
|
8
11
|
import { toErrorMessage } from "@wrongstack/core/utils";
|
|
9
12
|
var exportCmd = async (args, deps) => {
|
|
13
|
+
args = restoreFlags(args, deps, [
|
|
14
|
+
"format",
|
|
15
|
+
"f",
|
|
16
|
+
"out",
|
|
17
|
+
"o",
|
|
18
|
+
"no-tools",
|
|
19
|
+
"no-diagnostics"
|
|
20
|
+
]);
|
|
10
21
|
if (!deps.sessionStore) {
|
|
11
22
|
deps.renderer.writeError("No session store configured.");
|
|
12
23
|
return 1;
|
|
@@ -61,4 +72,4 @@ var exportCmd = async (args, deps) => {
|
|
|
61
72
|
export {
|
|
62
73
|
exportCmd
|
|
63
74
|
};
|
|
64
|
-
//# sourceMappingURL=export-
|
|
75
|
+
//# sourceMappingURL=export-DOBGPY23.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SubagentConfig } from '@wrongstack/core/types';
|
|
2
2
|
import type { MultiAgentDeps } from './host-types.js';
|
|
3
|
-
export declare function resolveHostSubagentSkillContent(deps: MultiAgentDeps, roster: Record<string, SubagentConfig>, subCfg: SubagentConfig): Promise<string>;
|
|
3
|
+
export declare function resolveHostSubagentSkillContent(deps: MultiAgentDeps, roster: Record<string, SubagentConfig>, subCfg: SubagentConfig, availableToolNames?: readonly string[]): Promise<string>;
|
|
4
4
|
export declare function retrieveHostSubagentMemory(deps: MultiAgentDeps, getLeaderMode: (() => string | undefined) | undefined, subCfg: SubagentConfig, taskContext?: Record<string, unknown>): Promise<string[]>;
|
|
5
5
|
//# sourceMappingURL=host-context.d.ts.map
|
|
@@ -10,6 +10,20 @@ export declare function buildShadowAgentTaskDescription(reason: string): string;
|
|
|
10
10
|
export declare function touchLruKey(order: string[], key: string): void;
|
|
11
11
|
export declare function setBoundedLruEntry<T>(map: Map<string, T>, order: string[], key: string, value: T, maxEntries: number): void;
|
|
12
12
|
export declare const DEFAULT_SUBAGENT_HIDDEN_TOOLS: Set<string>;
|
|
13
|
+
/**
|
|
14
|
+
* Tools a subagent can never receive — not even through an explicit
|
|
15
|
+
* `tools: [...]` allowlist.
|
|
16
|
+
*
|
|
17
|
+
* This is stricter than {@link DEFAULT_SUBAGENT_HIDDEN_TOOLS}, which only hides
|
|
18
|
+
* orchestration controls from the unrestricted default slice and still hands
|
|
19
|
+
* them over when a spawn asks for them by name. `nextsteps` records the
|
|
20
|
+
* leader's after-task suggestions: the runtime folds a recorded block into a
|
|
21
|
+
* LEADER turn only (`next-steps-slot.ts`), and `WIDE_SUBAGENT_CAPABILITIES`
|
|
22
|
+
* does not carry `session.nextsteps`. Granting it would produce either a
|
|
23
|
+
* permission rejection or a silent no-op, so asking for it by name is a
|
|
24
|
+
* mistake to correct rather than an intent to honor.
|
|
25
|
+
*/
|
|
26
|
+
export declare const NEVER_SUBAGENT_TOOLS: Set<string>;
|
|
13
27
|
export declare function selectSubagentTools(allTools: readonly Tool[], directorToolsByName: ReadonlyMap<string, Tool>, allow?: readonly string[] | undefined): Tool[];
|
|
14
28
|
export declare function resolveSubagentCapabilities(subCfg: SubagentConfig, toolsForAllow: (allow: readonly string[]) => readonly Tool[]): readonly string[] | undefined;
|
|
15
29
|
export declare function resolveFleetWorktreePolicy(config: Config): FleetWorktreePolicy;
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
*
|
|
23
23
|
* @module fleet/status-broadcast
|
|
24
24
|
*/
|
|
25
|
-
import type { EventBus } from '@wrongstack/core/kernel';
|
|
26
25
|
import type { Mailbox } from '@wrongstack/core/coordination';
|
|
26
|
+
import type { EventBus } from '@wrongstack/core/kernel';
|
|
27
27
|
import type { FleetConfig } from '@wrongstack/core/types';
|
|
28
28
|
export interface FleetStatusBroadcasterOptions {
|
|
29
29
|
/** Host EventBus carrying the re-emitted `subagent.*` lifecycle events. */
|
|
@@ -36,7 +36,7 @@ var hqCmd = async (args, deps) => {
|
|
|
36
36
|
return 1;
|
|
37
37
|
};
|
|
38
38
|
async function startServer(deps) {
|
|
39
|
-
const { startHqServer } = await import("./hq-server-
|
|
39
|
+
const { startHqServer } = await import("./hq-server-S7HZG3PA.js");
|
|
40
40
|
const dataDir = resolveDataDir(deps);
|
|
41
41
|
const flags = deps.flags ?? {};
|
|
42
42
|
const host = typeof flags["host"] === "string" ? flags["host"] : HQ_CLI_DEFAULT_HOST;
|
|
@@ -563,4 +563,4 @@ export {
|
|
|
563
563
|
hqCmd,
|
|
564
564
|
resolveAuditActor
|
|
565
565
|
};
|
|
566
|
-
//# sourceMappingURL=hq-
|
|
566
|
+
//# sourceMappingURL=hq-LN5CJHCM.js.map
|
|
@@ -51,7 +51,16 @@ export interface HqRouterMailboxGateway {
|
|
|
51
51
|
export interface HqRouterDeps {
|
|
52
52
|
trustBoundary: TrustBoundary;
|
|
53
53
|
host: string;
|
|
54
|
-
|
|
54
|
+
/**
|
|
55
|
+
* Getter, not a value. The router is constructed BEFORE `listen()`
|
|
56
|
+
* resolves, so a copied number froze the REQUESTED port. When the default
|
|
57
|
+
* is busy and `strictPort` is off, the scan binds `port+1` and the banner
|
|
58
|
+
* prints it — but the origin guard kept comparing against the old number and
|
|
59
|
+
* answered `403 forbidden: untrusted request origin` to the dashboard and
|
|
60
|
+
* every `/api/*` call. (The WS upgrade handler read the live local, so the
|
|
61
|
+
* failure looked like "the socket connects but the page won't load".)
|
|
62
|
+
*/
|
|
63
|
+
listeningPort: () => number;
|
|
55
64
|
trustedPublicOrigins: Set<string>;
|
|
56
65
|
/** Trust `Origin: file://`. Off by default — see StartHqServerOptions (WS-081). */
|
|
57
66
|
allowFileOrigin?: boolean | undefined;
|
package/dist/hq-server/ws.d.ts
CHANGED
|
@@ -32,11 +32,22 @@ export declare function detectLeaderLoss(lostClient: ConnectedClient, clients: M
|
|
|
32
32
|
/**
|
|
33
33
|
* Server-side fanout of a `hq.kanban_snapshot` envelope after a merge.
|
|
34
34
|
*
|
|
35
|
-
* C2 — broadcasts the post-merge `delta` payload to
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
35
|
+
* C2 — broadcasts the post-merge `delta` payload to every client whose
|
|
36
|
+
* `projectId` matches `projectId`.
|
|
37
|
+
*
|
|
38
|
+
* BROWSERS ARE DELIBERATELY NOT NOTIFIED. They used to be — unscoped, so
|
|
39
|
+
* every browser received every project's deltas — on the strength of a
|
|
40
|
+
* comment claiming "the browser-side projection filters by project when it
|
|
41
|
+
* applies the snapshot". No such projection exists: `hq.kanban_snapshot` is
|
|
42
|
+
* absent from `HqBrowserMessage` and from the SPA's dispatch chain, so
|
|
43
|
+
* `HqWsClient` parsed each frame and dropped it. The board view learns about
|
|
44
|
+
* changes from the `kanban.snapshot` HQ *event* and refetches over HTTP
|
|
45
|
+
* (`views/kanban.tsx`), which is why the drift was invisible.
|
|
46
|
+
*
|
|
47
|
+
* `browsers` stays in the signature: the fan-out is the natural place to wire
|
|
48
|
+
* a real browser consumer, and the parity test in
|
|
49
|
+
* `tests/hq-browser-protocol-parity.test.ts` now fails the moment a
|
|
50
|
+
* browser-bound frame has no handler.
|
|
40
51
|
*
|
|
41
52
|
* The `delta` payload is the same touched-only payload the merge handler
|
|
42
53
|
* builds (full-set broadcasts drive V8 heap exhaustion on long-lived
|
|
@@ -44,7 +55,7 @@ export declare function detectLeaderLoss(lostClient: ConnectedClient, clients: M
|
|
|
44
55
|
*
|
|
45
56
|
* Exported for direct unit testing in `tests/hq-kanban-fanout.test.ts`.
|
|
46
57
|
*/
|
|
47
|
-
export declare function fanoutKanbanDelta(message: string, clients: Map<WebSocket, ConnectedClient>,
|
|
58
|
+
export declare function fanoutKanbanDelta(message: string, clients: Map<WebSocket, ConnectedClient>, _browsers: Set<WebSocket>, projectId: string): {
|
|
48
59
|
clientsNotified: number;
|
|
49
60
|
browsersNotified: number;
|
|
50
61
|
};
|
|
@@ -15,7 +15,8 @@ import {
|
|
|
15
15
|
readLocalSubagentTranscript,
|
|
16
16
|
sanitizeApiError,
|
|
17
17
|
startHqServer
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-2KDOFTTM.js";
|
|
19
|
+
import "./chunk-KE7E7DPX.js";
|
|
19
20
|
import "./chunk-Q5GTM25S.js";
|
|
20
21
|
import "./chunk-7OCVIDC7.js";
|
|
21
22
|
export {
|
|
@@ -36,4 +37,4 @@ export {
|
|
|
36
37
|
sanitizeApiError,
|
|
37
38
|
startHqServer
|
|
38
39
|
};
|
|
39
|
-
//# sourceMappingURL=hq-server-
|
|
40
|
+
//# sourceMappingURL=hq-server-S7HZG3PA.js.map
|