@wrongstack/cli 0.299.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-S4LZQB66.js → acp-DATHHPNT.js} +36 -17
- package/dist/acp-server-agent.d.ts +1 -1
- package/dist/{audit-2ZSFGNIF.js → audit-QRCLEHHW.js} +5 -1
- package/dist/{auth-G5YKKSRH.js → auth-JASC4K3F.js} +151 -38
- package/dist/auth-menu/loopback-server.d.ts +41 -55
- package/dist/auth-menu/openai-codex-oauth.d.ts +36 -123
- package/dist/auto-discover-providers-DRW4OZHG.js +8 -0
- package/dist/boot/dispatch-webui.d.ts +3 -0
- 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-2SLSUDYS.js → chunk-2KDOFTTM.js} +312 -211
- package/dist/{chunk-TGDHN4LM.js → chunk-4GVH7V3S.js} +4 -24
- package/dist/chunk-CSAPOCBP.js +24 -0
- package/dist/{chunk-66T43Q4Y.js → chunk-ETOEGL3V.js} +6 -9
- package/dist/{chunk-PEKUKUCH.js → chunk-GUHQQG63.js} +32 -14
- package/dist/chunk-KE7E7DPX.js +38 -0
- package/dist/{chunk-ZNZJ34RF.js → chunk-MHF2IJDE.js} +21 -4
- package/dist/{chunk-4HH3YGG4.js → chunk-MRLYDHQ7.js} +8 -5
- package/dist/{chunk-L5CE52XW.js → chunk-O7XNGCRT.js} +317 -309
- package/dist/chunk-PYTFS4MC.js +238 -0
- package/dist/{chunk-DPJZQCVP.js → chunk-YMXXOOFN.js} +1 -1
- package/dist/{chunk-4U3DMA2Y.js → chunk-ZECLGUTF.js} +28 -21
- package/dist/{cli-main-3MQDFSYK.js → cli-main-XWC57MGE.js} +849 -242
- package/dist/{execution-ANOYMWPO.js → execution-LHMSMDHB.js} +174 -55
- 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/budget-source.d.ts +18 -0
- package/dist/fleet/host-context.d.ts +1 -1
- package/dist/fleet/host-helpers.d.ts +14 -0
- package/dist/fleet/host-status.d.ts +31 -0
- package/dist/fleet/host-types.d.ts +8 -0
- package/dist/fleet/host.d.ts +5 -0
- package/dist/fleet/status-broadcast.d.ts +1 -1
- package/dist/{hq-BDO56CX6.js → hq-LN5CJHCM.js} +22 -3
- package/dist/hq-server/auth-state.d.ts +29 -1
- package/dist/hq-server/auth.d.ts +16 -0
- package/dist/hq-server/client-address.d.ts +56 -0
- package/dist/hq-server/login-attempt-store.d.ts +30 -10
- package/dist/hq-server/routes/auth-handlers.d.ts +66 -26
- package/dist/hq-server/routes.d.ts +23 -1
- package/dist/hq-server/types.d.ts +10 -0
- package/dist/hq-server/ws.d.ts +17 -6
- package/dist/{hq-server-RJLJJZU7.js → hq-server-S7HZG3PA.js} +3 -2
- package/dist/hq-server.d.ts +19 -0
- package/dist/index.js +69 -104
- package/dist/live-settings-input.d.ts +5 -0
- package/dist/{mcp-CYLPUEHC.js → mcp-OHPJH73U.js} +6 -2
- package/dist/{modeldiag-HENYJ4N7.js → modeldiag-3DOK4BWW.js} +3 -3
- package/dist/{plugin-usage-VTL7ZTVC.js → plugin-usage-YEVLOR33.js} +7 -3
- package/dist/{plugins-ETY6W3DC.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-GDELBHZK.js → providers-models-WEZ4EGLL.js} +38 -12
- 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/slash-commands/command-context.d.ts +19 -0
- package/dist/subcommands/flags.d.ts +23 -0
- package/dist/terminal-format.d.ts +15 -0
- package/dist/webui-server/setup-events.d.ts +17 -0
- package/dist/webui-server/terminal-log-view.d.ts +29 -12
- package/dist/{webui-server-PCLSXX6L.js → webui-server-DD35QFNO.js} +113 -50
- package/dist/webui-server-options.d.ts +16 -0
- package/dist/wiring/brain-and-orchestration.d.ts +4 -1
- package/dist/wiring/director-setup.d.ts +4 -0
- package/dist/wiring/fallback-gate.d.ts +31 -0
- package/dist/wiring/fleet-command-handlers.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 +3 -10
- package/dist/wiring/provider-utility-tools.d.ts +27 -1
- package/dist/wiring/tools.d.ts +4 -5
- package/package.json +23 -23
- package/dist/chunk-GO3TJICK.js +0 -489
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
setupPlugins
|
|
3
|
+
} from "./chunk-ZECLGUTF.js";
|
|
1
4
|
import {
|
|
2
5
|
runProjectPicker
|
|
3
6
|
} from "./chunk-5N34EWJR.js";
|
|
@@ -37,13 +40,10 @@ import {
|
|
|
37
40
|
matchTaskNode,
|
|
38
41
|
sddState
|
|
39
42
|
} from "./chunk-XTIXVJXP.js";
|
|
40
|
-
import {
|
|
41
|
-
setupPlugins
|
|
42
|
-
} from "./chunk-4U3DMA2Y.js";
|
|
43
43
|
import {
|
|
44
44
|
PLUGIN_AUDIT_ENTRIES,
|
|
45
45
|
runPluginManagementCommand
|
|
46
|
-
} from "./chunk-
|
|
46
|
+
} from "./chunk-GUHQQG63.js";
|
|
47
47
|
import {
|
|
48
48
|
configureSimpleUiRuntimeContext,
|
|
49
49
|
detectProjectFacts,
|
|
@@ -70,7 +70,7 @@ import {
|
|
|
70
70
|
loadCachedAcpRegistry,
|
|
71
71
|
refreshAcpRegistry,
|
|
72
72
|
setupProvider
|
|
73
|
-
} from "./chunk-
|
|
73
|
+
} from "./chunk-MRLYDHQ7.js";
|
|
74
74
|
import {
|
|
75
75
|
addCustomProvider,
|
|
76
76
|
addKeyForCatalogProvider,
|
|
@@ -80,17 +80,18 @@ import {
|
|
|
80
80
|
runClaudeOAuthLogin,
|
|
81
81
|
runCopilotOAuthLogin,
|
|
82
82
|
validateFamily
|
|
83
|
-
} from "./chunk-
|
|
83
|
+
} from "./chunk-O7XNGCRT.js";
|
|
84
84
|
import {
|
|
85
85
|
LOCAL_LLM_PRESETS,
|
|
86
86
|
parseSpawnFlags
|
|
87
|
-
} from "./chunk-
|
|
87
|
+
} from "./chunk-MHF2IJDE.js";
|
|
88
88
|
import {
|
|
89
|
-
buildPickableProviders
|
|
90
|
-
|
|
89
|
+
buildPickableProviders,
|
|
90
|
+
visibleModelIds
|
|
91
|
+
} from "./chunk-ETOEGL3V.js";
|
|
91
92
|
import {
|
|
92
93
|
runCodexOAuthLogin
|
|
93
|
-
} from "./chunk-
|
|
94
|
+
} from "./chunk-PYTFS4MC.js";
|
|
94
95
|
import {
|
|
95
96
|
activeLabel,
|
|
96
97
|
loadConfigProviders,
|
|
@@ -101,10 +102,10 @@ import {
|
|
|
101
102
|
} from "./chunk-PJHET45A.js";
|
|
102
103
|
import {
|
|
103
104
|
appendHistory
|
|
104
|
-
} from "./chunk-
|
|
105
|
+
} from "./chunk-263G3FMB.js";
|
|
105
106
|
import {
|
|
106
107
|
activeProfileConfigPath
|
|
107
|
-
} from "./chunk-
|
|
108
|
+
} from "./chunk-YMXXOOFN.js";
|
|
108
109
|
import {
|
|
109
110
|
__require
|
|
110
111
|
} from "./chunk-7OCVIDC7.js";
|
|
@@ -1566,6 +1567,7 @@ function registerBuiltinTools(deps) {
|
|
|
1566
1567
|
tier,
|
|
1567
1568
|
contextTool: createContextManagerTool({ compactor: deps.compactor }),
|
|
1568
1569
|
memory: { enabled: deps.config.features.memory, store: deps.memoryStore },
|
|
1570
|
+
nextSteps: { enabled: deps.config.tools?.nextsteps?.enabled === true },
|
|
1569
1571
|
coordinationTools: [
|
|
1570
1572
|
makeMailboxTool({ projectDir: deps.wpaths.projectDir, events: deps.events }),
|
|
1571
1573
|
makeMailSendTool({ projectDir: deps.wpaths.projectDir, events: deps.events }),
|
|
@@ -2781,6 +2783,9 @@ import {
|
|
|
2781
2783
|
} from "@wrongstack/core/execution";
|
|
2782
2784
|
import { TOKENS as TOKENS6 } from "@wrongstack/core/kernel";
|
|
2783
2785
|
import { createMcpControlTool, createMcpUseTool } from "@wrongstack/core/tools";
|
|
2786
|
+
import {
|
|
2787
|
+
normalizeTokenSavingTier as normalizeTokenSavingTier2
|
|
2788
|
+
} from "@wrongstack/core/types";
|
|
2784
2789
|
|
|
2785
2790
|
// src/boot/brain-decision-log.ts
|
|
2786
2791
|
var MAX_BRAIN_LOG_ENTRIES = 20;
|
|
@@ -2875,9 +2880,7 @@ import { wstackGlobalRoot } from "@wrongstack/core/utils";
|
|
|
2875
2880
|
|
|
2876
2881
|
// src/fleet/host-helpers.ts
|
|
2877
2882
|
import * as path2 from "node:path";
|
|
2878
|
-
import {
|
|
2879
|
-
makeSubagentResultTool
|
|
2880
|
-
} from "@wrongstack/core/coordination";
|
|
2883
|
+
import { makeSubagentResultTool } from "@wrongstack/core/coordination";
|
|
2881
2884
|
import { ToolCapabilities, WIDE_SUBAGENT_CAPABILITIES } from "@wrongstack/core/security";
|
|
2882
2885
|
import { makePreferSideConflictResolver } from "@wrongstack/sdd";
|
|
2883
2886
|
function isInsideDirectory(root, candidate) {
|
|
@@ -2953,10 +2956,13 @@ var DEFAULT_SUBAGENT_HIDDEN_TOOLS = /* @__PURE__ */ new Set([
|
|
|
2953
2956
|
"collab_debug",
|
|
2954
2957
|
"fleet_emit"
|
|
2955
2958
|
]);
|
|
2959
|
+
var NEVER_SUBAGENT_TOOLS = /* @__PURE__ */ new Set(["nextsteps"]);
|
|
2956
2960
|
function selectSubagentTools(allTools, directorToolsByName, allow) {
|
|
2957
2961
|
if (!allow || allow.length === 0) {
|
|
2958
2962
|
const visible = new Map(
|
|
2959
|
-
allTools.filter(
|
|
2963
|
+
allTools.filter(
|
|
2964
|
+
(tool) => !DEFAULT_SUBAGENT_HIDDEN_TOOLS.has(tool.name) && !NEVER_SUBAGENT_TOOLS.has(tool.name)
|
|
2965
|
+
).map((tool) => [tool.name, tool])
|
|
2960
2966
|
);
|
|
2961
2967
|
visible.set("submit_result", makeSubagentResultTool());
|
|
2962
2968
|
return Array.from(visible.values());
|
|
@@ -2964,12 +2970,20 @@ function selectSubagentTools(allTools, directorToolsByName, allow) {
|
|
|
2964
2970
|
const allowSet = new Set(allow);
|
|
2965
2971
|
const result = /* @__PURE__ */ new Map();
|
|
2966
2972
|
for (const tool of allTools) {
|
|
2967
|
-
if (allowSet.has(tool.name)
|
|
2973
|
+
if (allowSet.has(tool.name) && !NEVER_SUBAGENT_TOOLS.has(tool.name))
|
|
2974
|
+
result.set(tool.name, tool);
|
|
2968
2975
|
}
|
|
2969
2976
|
for (const name of allowSet) {
|
|
2977
|
+
if (NEVER_SUBAGENT_TOOLS.has(name)) continue;
|
|
2970
2978
|
const directorTool = directorToolsByName.get(name);
|
|
2971
2979
|
if (directorTool && !result.has(name)) result.set(name, directorTool);
|
|
2972
2980
|
}
|
|
2981
|
+
const missing = [...allowSet].filter(
|
|
2982
|
+
(name) => !NEVER_SUBAGENT_TOOLS.has(name) && !result.has(name)
|
|
2983
|
+
);
|
|
2984
|
+
if (missing.length > 0) {
|
|
2985
|
+
throw new Error(`Subagent tool contract is not registered: ${missing.sort().join(", ")}`);
|
|
2986
|
+
}
|
|
2973
2987
|
result.set("submit_result", makeSubagentResultTool());
|
|
2974
2988
|
return Array.from(result.values());
|
|
2975
2989
|
}
|
|
@@ -3263,6 +3277,10 @@ function registerDirectorStatsBridge(input) {
|
|
|
3263
3277
|
...u.toolCalls !== void 0 ? { toolCalls: u.toolCalls } : {}
|
|
3264
3278
|
};
|
|
3265
3279
|
});
|
|
3280
|
+
const budgetSnap = director.fleetManager?.budgetSnapshot?.();
|
|
3281
|
+
const maxSpawns = budgetSnap?.maxSpawns ?? director.maxSpawns;
|
|
3282
|
+
const usedSpawns = budgetSnap?.usedSpawns ?? director.spawnCount;
|
|
3283
|
+
const remainingSpawns = budgetSnap?.remainingSpawns ?? Math.max(0, (Number.isFinite(maxSpawns) ? maxSpawns : Number.POSITIVE_INFINITY) - usedSpawns);
|
|
3266
3284
|
events.emit("coordinator.stats", {
|
|
3267
3285
|
sessionId,
|
|
3268
3286
|
total: payload.total,
|
|
@@ -3273,6 +3291,11 @@ function registerDirectorStatsBridge(input) {
|
|
|
3273
3291
|
pending: payload.pending,
|
|
3274
3292
|
completed: payload.completed,
|
|
3275
3293
|
...usage?.total?.cost !== void 0 ? { totalCostUsd: usage.total.cost } : {},
|
|
3294
|
+
maxSpawns,
|
|
3295
|
+
usedSpawns,
|
|
3296
|
+
remainingSpawns,
|
|
3297
|
+
...budgetSnap?.checkpointMaxSpawns !== void 0 ? { checkpointMaxSpawns: budgetSnap.checkpointMaxSpawns } : {},
|
|
3298
|
+
...budgetSnap?.ceilingMismatch ? { ceilingMismatch: true } : {},
|
|
3276
3299
|
subagentStatuses
|
|
3277
3300
|
});
|
|
3278
3301
|
});
|
|
@@ -3341,7 +3364,8 @@ import {
|
|
|
3341
3364
|
Agent,
|
|
3342
3365
|
Context,
|
|
3343
3366
|
createDefaultPipelines,
|
|
3344
|
-
createFallbackModelExtension
|
|
3367
|
+
createFallbackModelExtension,
|
|
3368
|
+
renderInstructionLayer
|
|
3345
3369
|
} from "@wrongstack/core/agent";
|
|
3346
3370
|
import {
|
|
3347
3371
|
applyProjectAgentConfig,
|
|
@@ -3366,9 +3390,14 @@ import { EventBus } from "@wrongstack/core/kernel";
|
|
|
3366
3390
|
import { AutoApprovePermissionPolicy } from "@wrongstack/core/security";
|
|
3367
3391
|
|
|
3368
3392
|
// src/fleet/host-context.ts
|
|
3393
|
+
import {
|
|
3394
|
+
missingRequiredRuntimeTools,
|
|
3395
|
+
missingRuntimeCapabilities,
|
|
3396
|
+
runtimeToolReferencesFromText
|
|
3397
|
+
} from "@wrongstack/core/agent-catalog";
|
|
3369
3398
|
import { TOKENS as TOKENS2 } from "@wrongstack/core/kernel";
|
|
3370
3399
|
import { getSageRetrieval } from "@wrongstack/sage";
|
|
3371
|
-
async function resolveHostSubagentSkillContent(deps, roster, subCfg) {
|
|
3400
|
+
async function resolveHostSubagentSkillContent(deps, roster, subCfg, availableToolNames = []) {
|
|
3372
3401
|
const rosterSkillNames = subCfg.role ? roster[subCfg.role]?.skillNames : void 0;
|
|
3373
3402
|
const skillNames = [...new Set(subCfg.skillNames ?? rosterSkillNames ?? [])];
|
|
3374
3403
|
const directContent = subCfg.skillContent?.trim();
|
|
@@ -3381,8 +3410,14 @@ async function resolveHostSubagentSkillContent(deps, roster, subCfg) {
|
|
|
3381
3410
|
try {
|
|
3382
3411
|
const manifest = await deps.skillLoader.find(skillName);
|
|
3383
3412
|
if (!manifest) continue;
|
|
3413
|
+
if (missingRuntimeCapabilities(manifest.requiredCapabilities, availableToolNames).length > 0 || missingRequiredRuntimeTools(manifest.requiredTools, availableToolNames).length > 0) {
|
|
3414
|
+
continue;
|
|
3415
|
+
}
|
|
3384
3416
|
const body = (await deps.skillLoader.readSaveBody(skillName)).trim();
|
|
3385
3417
|
if (!body) continue;
|
|
3418
|
+
if (missingRequiredRuntimeTools(runtimeToolReferencesFromText(body), availableToolNames).length > 0) {
|
|
3419
|
+
continue;
|
|
3420
|
+
}
|
|
3386
3421
|
const entry = `## Skill: ${skillName}
|
|
3387
3422
|
|
|
3388
3423
|
${body.slice(0, maxCharsPerSkill)}`;
|
|
@@ -3798,16 +3833,26 @@ ${message} Falling back to the assigned checkout.` : `${message} Falling back to
|
|
|
3798
3833
|
onlineAgents = await subagentMailbox.getAgentStatuses();
|
|
3799
3834
|
} catch {
|
|
3800
3835
|
}
|
|
3836
|
+
const subagentTools = host.filterTools(effectiveCfg.tools);
|
|
3801
3837
|
const baseSystem = await host.deps.systemPromptBuilder.build({
|
|
3802
3838
|
cwd: subCwd,
|
|
3803
3839
|
projectRoot: host.deps.projectRoot,
|
|
3804
|
-
tools:
|
|
3840
|
+
tools: subagentTools,
|
|
3841
|
+
catalogTools: subagentTools,
|
|
3805
3842
|
model: effModel,
|
|
3806
3843
|
provider: effProvider,
|
|
3807
3844
|
subagent: true,
|
|
3808
3845
|
onlineAgents
|
|
3809
3846
|
});
|
|
3810
|
-
baseSystem.unshift({
|
|
3847
|
+
baseSystem.unshift({
|
|
3848
|
+
type: "text",
|
|
3849
|
+
text: renderInstructionLayer(DEFAULT_SUBAGENT_BASELINE, {
|
|
3850
|
+
toolNames: new Set(subagentTools.map((tool) => tool.name)),
|
|
3851
|
+
tier: "off",
|
|
3852
|
+
subagent: true,
|
|
3853
|
+
strictToolReferences: true
|
|
3854
|
+
})
|
|
3855
|
+
});
|
|
3811
3856
|
if (availabilityNotice) baseSystem.push({ type: "text", text: availabilityNotice });
|
|
3812
3857
|
const audienceMemory = await retrieveHostSubagentMemory(
|
|
3813
3858
|
host.deps,
|
|
@@ -3825,7 +3870,8 @@ ${audienceMemory.map((text) => `- ${text}`).join("\n")}`
|
|
|
3825
3870
|
const roleSkillContent = await resolveHostSubagentSkillContent(
|
|
3826
3871
|
host.deps,
|
|
3827
3872
|
host.roster,
|
|
3828
|
-
effectiveCfg
|
|
3873
|
+
effectiveCfg,
|
|
3874
|
+
subagentTools.map((tool) => tool.name)
|
|
3829
3875
|
);
|
|
3830
3876
|
if (roleSkillContent) {
|
|
3831
3877
|
for (let index = baseSystem.length - 1; index >= 0; index--) {
|
|
@@ -3872,7 +3918,8 @@ ${audienceMemory.map((text) => `- ${text}`).join("\n")}`
|
|
|
3872
3918
|
projectRoot: host.deps.projectRoot,
|
|
3873
3919
|
allowOutsideProjectRoot: config.features?.allowOutsideProjectRoot ?? !(config.tools?.restrictToProjectRoot ?? false),
|
|
3874
3920
|
model: effModel,
|
|
3875
|
-
tools:
|
|
3921
|
+
tools: subagentTools,
|
|
3922
|
+
catalogTools: subagentTools,
|
|
3876
3923
|
agentId: subagentName,
|
|
3877
3924
|
agentName: effectiveCfg.name ?? subagentName
|
|
3878
3925
|
});
|
|
@@ -4125,6 +4172,9 @@ import {
|
|
|
4125
4172
|
var DEFAULT_MIN_INTERVAL_MS = 15e3;
|
|
4126
4173
|
var DEFAULT_GLOBAL_PER_MINUTE = 20;
|
|
4127
4174
|
var BODY_MAX = 200;
|
|
4175
|
+
function isSilentInfrastructureAgent(name) {
|
|
4176
|
+
return name.trim().toLowerCase() === "chimera-review";
|
|
4177
|
+
}
|
|
4128
4178
|
function createFleetStatusBroadcaster(opts) {
|
|
4129
4179
|
const cfg = opts.config;
|
|
4130
4180
|
const minIntervalMs = cfg?.minIntervalMsPerAgent ?? DEFAULT_MIN_INTERVAL_MS;
|
|
@@ -4144,6 +4194,7 @@ function createFleetStatusBroadcaster(opts) {
|
|
|
4144
4194
|
let droppedSinceLastSend = 0;
|
|
4145
4195
|
const announcedSpawn = /* @__PURE__ */ new Set();
|
|
4146
4196
|
const announcedBudget = /* @__PURE__ */ new Set();
|
|
4197
|
+
const silentInfrastructureAgents = /* @__PURE__ */ new Set();
|
|
4147
4198
|
const disposers = [];
|
|
4148
4199
|
let stopped = false;
|
|
4149
4200
|
function underGlobalCap(now) {
|
|
@@ -4208,9 +4259,14 @@ function createFleetStatusBroadcaster(opts) {
|
|
|
4208
4259
|
opts.events.on("subagent.spawned", (e) => {
|
|
4209
4260
|
if (announcedSpawn.has(e.subagentId)) return;
|
|
4210
4261
|
announcedSpawn.add(e.subagentId);
|
|
4262
|
+
const name = e.name ?? nameOf(e.subagentId);
|
|
4263
|
+
if (isSilentInfrastructureAgent(name)) {
|
|
4264
|
+
silentInfrastructureAgents.add(e.subagentId);
|
|
4265
|
+
return;
|
|
4266
|
+
}
|
|
4211
4267
|
broadcast(e.subagentId, {
|
|
4212
|
-
subject: `[${
|
|
4213
|
-
body: `${
|
|
4268
|
+
subject: `[${name}] joined the fleet`,
|
|
4269
|
+
body: `${name} spawned${e.model ? ` on ${e.model}` : ""}${e.description ? ` \u2014 ${e.description.slice(0, 80)}` : ""}`,
|
|
4214
4270
|
priority: "low"
|
|
4215
4271
|
});
|
|
4216
4272
|
}),
|
|
@@ -4224,6 +4280,9 @@ function createFleetStatusBroadcaster(opts) {
|
|
|
4224
4280
|
opts.events.on("subagent.task_completed", (e) => {
|
|
4225
4281
|
heartbeat({ agentId: e.subagentId, status: "idle" });
|
|
4226
4282
|
const name = nameOf(e.subagentId);
|
|
4283
|
+
if (silentInfrastructureAgents.has(e.subagentId) || isSilentInfrastructureAgent(name)) {
|
|
4284
|
+
return;
|
|
4285
|
+
}
|
|
4227
4286
|
const ok = e.status === "success";
|
|
4228
4287
|
const secs = Math.round(e.durationMs / 1e3);
|
|
4229
4288
|
broadcast(e.subagentId, {
|
|
@@ -4234,6 +4293,9 @@ function createFleetStatusBroadcaster(opts) {
|
|
|
4234
4293
|
}),
|
|
4235
4294
|
opts.events.on("subagent.budget_warning", (e) => {
|
|
4236
4295
|
if (!broadcastBudgetWarnings) return;
|
|
4296
|
+
if (silentInfrastructureAgents.has(e.subagentId) || isSilentInfrastructureAgent(nameOf(e.subagentId))) {
|
|
4297
|
+
return;
|
|
4298
|
+
}
|
|
4237
4299
|
const key = `${e.subagentId}|${e.kind}`;
|
|
4238
4300
|
if (announcedBudget.has(key)) return;
|
|
4239
4301
|
announcedBudget.add(key);
|
|
@@ -4260,6 +4322,7 @@ function createFleetStatusBroadcaster(opts) {
|
|
|
4260
4322
|
void mb().deregisterAgent(e.subagentId).catch(() => {
|
|
4261
4323
|
});
|
|
4262
4324
|
announcedSpawn.delete(e.subagentId);
|
|
4325
|
+
silentInfrastructureAgents.delete(e.subagentId);
|
|
4263
4326
|
lastSentAt.delete(e.subagentId);
|
|
4264
4327
|
for (const key of announcedBudget) {
|
|
4265
4328
|
if (key.startsWith(`${e.subagentId}|`)) announcedBudget.delete(key);
|
|
@@ -4366,7 +4429,47 @@ function buildFleetHostStatus(input) {
|
|
|
4366
4429
|
const completedCount = completed.length;
|
|
4367
4430
|
const liveCount = live.filter((s) => s.status === "running" || s.status === "idle").length;
|
|
4368
4431
|
const summary = !input.coordinatorStatus && !input.completedResults ? "No subagents have been spawned." : liveCount > 0 ? `${pending.length} pending, ${liveCount} active, ${completedCount} completed.` : `${pending.length} pending, ${completedCount} completed.`;
|
|
4369
|
-
return {
|
|
4432
|
+
return {
|
|
4433
|
+
pending,
|
|
4434
|
+
completed,
|
|
4435
|
+
live,
|
|
4436
|
+
summary,
|
|
4437
|
+
...input.budget ? { budget: input.budget } : {}
|
|
4438
|
+
};
|
|
4439
|
+
}
|
|
4440
|
+
function formatFleetBudgetLines(budget, colorize) {
|
|
4441
|
+
const bold = colorize?.bold ?? ((s) => s);
|
|
4442
|
+
const dim = colorize?.dim ?? ((s) => s);
|
|
4443
|
+
const amber = colorize?.amber ?? ((s) => s);
|
|
4444
|
+
const fmtNum = (n) => Number.isFinite(n) ? String(n) : "\u221E";
|
|
4445
|
+
const sourceSuffix = budget.effectiveSource ? ` ${dim(`(source: ${budget.effectiveSource})`)}` : "";
|
|
4446
|
+
const lines = [
|
|
4447
|
+
bold("Budget"),
|
|
4448
|
+
` maxConcurrent: ${budget.maxConcurrent} \xB7 activeAgents: ${budget.activeAgents}`,
|
|
4449
|
+
` maxSpawns: ${fmtNum(budget.maxSpawns)} \xB7 usedSpawns: ${budget.usedSpawns} \xB7 remainingSpawns: ${fmtNum(budget.remainingSpawns)}${sourceSuffix}`
|
|
4450
|
+
];
|
|
4451
|
+
if (budget.maxTokens !== void 0 && Number.isFinite(budget.maxTokens) && budget.maxTokens < Number.POSITIVE_INFINITY) {
|
|
4452
|
+
lines.push(
|
|
4453
|
+
` tokens: ${budget.usedTokens ?? 0} / ${fmtNum(budget.maxTokens)} remaining ${fmtNum(budget.remainingTokens ?? 0)}`
|
|
4454
|
+
);
|
|
4455
|
+
}
|
|
4456
|
+
if (budget.maxCostUsd !== void 0 && Number.isFinite(budget.maxCostUsd) && budget.maxCostUsd < Number.POSITIVE_INFINITY) {
|
|
4457
|
+
const used = budget.usedCostUsd ?? 0;
|
|
4458
|
+
const rem = budget.remainingCostUsd ?? 0;
|
|
4459
|
+
lines.push(
|
|
4460
|
+
` costUsd: ${used.toFixed(4)} / ${budget.maxCostUsd.toFixed(4)} remaining ${rem.toFixed(4)}`
|
|
4461
|
+
);
|
|
4462
|
+
}
|
|
4463
|
+
if (budget.ceilingMismatch && budget.checkpointMaxSpawns !== void 0) {
|
|
4464
|
+
lines.push(
|
|
4465
|
+
amber(
|
|
4466
|
+
` \u26A0 checkpoint maxSpawns was ${budget.checkpointMaxSpawns}; live ceiling is ${fmtNum(budget.maxSpawns)}`
|
|
4467
|
+
)
|
|
4468
|
+
);
|
|
4469
|
+
} else if (budget.checkpointMaxSpawns !== void 0) {
|
|
4470
|
+
lines.push(dim(` checkpointMaxSpawns: ${budget.checkpointMaxSpawns}`));
|
|
4471
|
+
}
|
|
4472
|
+
return lines;
|
|
4370
4473
|
}
|
|
4371
4474
|
function aggregateFleetUsage(completed) {
|
|
4372
4475
|
const bySubagent = /* @__PURE__ */ new Map();
|
|
@@ -5074,9 +5177,44 @@ var MultiAgentHost = class {
|
|
|
5074
5177
|
coordinatorStatus: this.director ? this.getCoordinator().getStatus() : null,
|
|
5075
5178
|
fleetStatus: this.fleetManager?.getFleetStatus() ?? null,
|
|
5076
5179
|
completedResults: this.director ? this.director.completedResults() : null,
|
|
5077
|
-
shadowTaskIds: this.shadowTaskIds
|
|
5180
|
+
shadowTaskIds: this.shadowTaskIds,
|
|
5181
|
+
budget: this.budgetView()
|
|
5078
5182
|
});
|
|
5079
5183
|
}
|
|
5184
|
+
/**
|
|
5185
|
+
* Read-only concurrency + lifetime spawn budget for `/fleet status` and
|
|
5186
|
+
* resume diagnostics. Safe when no director/fleet is active yet.
|
|
5187
|
+
*/
|
|
5188
|
+
budgetView() {
|
|
5189
|
+
const snap = this.fleetManager?.budgetSnapshot?.();
|
|
5190
|
+
const maxSpawns = snap?.maxSpawns ?? this.opts.maxSpawns ?? this.director?.maxSpawns ?? Number.POSITIVE_INFINITY;
|
|
5191
|
+
const usedSpawns = snap?.usedSpawns ?? this.director?.spawnCount ?? 0;
|
|
5192
|
+
const remainingSpawns = snap?.remainingSpawns ?? Math.max(0, (Number.isFinite(maxSpawns) ? maxSpawns : Number.POSITIVE_INFINITY) - usedSpawns);
|
|
5193
|
+
const live = this.director ? this.getCoordinator().getStatus().subagents.filter((s) => s.status === "running" || s.status === "idle").length : 0;
|
|
5194
|
+
const maxConcurrentSource = this.opts.budgetSources?.maxConcurrent ?? "default";
|
|
5195
|
+
const maxSpawnsSource = this.opts.budgetSources?.maxSpawns ?? "default";
|
|
5196
|
+
const effectiveSource = `maxConcurrent=${maxConcurrentSource}, maxSpawns=${maxSpawnsSource}`;
|
|
5197
|
+
return {
|
|
5198
|
+
maxConcurrent: this.getMaxConcurrent(),
|
|
5199
|
+
activeAgents: live,
|
|
5200
|
+
maxSpawns,
|
|
5201
|
+
usedSpawns,
|
|
5202
|
+
remainingSpawns,
|
|
5203
|
+
maxConcurrentSource,
|
|
5204
|
+
maxSpawnsSource,
|
|
5205
|
+
effectiveSource,
|
|
5206
|
+
...snap ? {
|
|
5207
|
+
maxTokens: snap.maxTokens,
|
|
5208
|
+
usedTokens: snap.usedTokens,
|
|
5209
|
+
remainingTokens: snap.remainingTokens,
|
|
5210
|
+
maxCostUsd: snap.maxCostUsd,
|
|
5211
|
+
usedCostUsd: snap.usedCostUsd,
|
|
5212
|
+
remainingCostUsd: snap.remainingCostUsd,
|
|
5213
|
+
...snap.checkpointMaxSpawns !== void 0 ? { checkpointMaxSpawns: snap.checkpointMaxSpawns } : {},
|
|
5214
|
+
...snap.ceilingMismatch ? { ceilingMismatch: true } : {}
|
|
5215
|
+
} : {}
|
|
5216
|
+
};
|
|
5217
|
+
}
|
|
5080
5218
|
usage() {
|
|
5081
5219
|
const completed = this.director ? this.director.completedResults().filter((r) => !this.shadowTaskIds.has(r.taskId)) : [];
|
|
5082
5220
|
return aggregateFleetUsage(completed);
|
|
@@ -5176,7 +5314,10 @@ function resolveProviderCfg(config, providerId) {
|
|
|
5176
5314
|
function buildProviderForId(args, providerId) {
|
|
5177
5315
|
const { cfg, factoryType } = resolveProviderCfg(args.config, providerId);
|
|
5178
5316
|
const useRegistry = !!args.config.features.modelsRegistry && args.providerRegistry.has(factoryType);
|
|
5179
|
-
return useRegistry ? args.providerRegistry.create(cfg, factoryType) : makeProviderFromConfig2(
|
|
5317
|
+
return useRegistry ? args.providerRegistry.create(cfg, factoryType) : makeProviderFromConfig2(
|
|
5318
|
+
providerId,
|
|
5319
|
+
factoryType === "ai-gateway" ? { ...cfg, type: factoryType } : cfg
|
|
5320
|
+
);
|
|
5180
5321
|
}
|
|
5181
5322
|
|
|
5182
5323
|
// src/wiring/brain-and-orchestration.ts
|
|
@@ -5415,8 +5556,12 @@ function setupBrainAndOrchestration(deps) {
|
|
|
5415
5556
|
maxCostUsd: config.fleet.budget.maxCostUsd
|
|
5416
5557
|
}
|
|
5417
5558
|
} : {},
|
|
5418
|
-
maxSpawns: config.fleet?.budget?.maxSpawns,
|
|
5559
|
+
maxSpawns: deps.maxSpawns ?? config.fleet?.budget?.maxSpawns,
|
|
5419
5560
|
maxConcurrent,
|
|
5561
|
+
budgetSources: {
|
|
5562
|
+
maxConcurrent: deps.maxConcurrentSource ?? "default",
|
|
5563
|
+
maxSpawns: deps.maxSpawnsSource ?? "default"
|
|
5564
|
+
},
|
|
5420
5565
|
getLeaderMaxContext: () => effectiveMaxContextRef.current,
|
|
5421
5566
|
brain,
|
|
5422
5567
|
agentMonitor,
|
|
@@ -5438,6 +5583,7 @@ function setupBrainAndOrchestration(deps) {
|
|
|
5438
5583
|
events
|
|
5439
5584
|
})
|
|
5440
5585
|
);
|
|
5586
|
+
toolRegistry.exposeToProvider("delegate");
|
|
5441
5587
|
toolRegistry.register(
|
|
5442
5588
|
createMcpControlTool({
|
|
5443
5589
|
getConfig: () => configStore.get(),
|
|
@@ -5445,13 +5591,17 @@ function setupBrainAndOrchestration(deps) {
|
|
|
5445
5591
|
registry: mcpRegistry
|
|
5446
5592
|
})
|
|
5447
5593
|
);
|
|
5448
|
-
if (config.features.tokenSavingMode) {
|
|
5449
|
-
toolRegistry.
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
|
|
5594
|
+
if (normalizeTokenSavingTier2(config.features.tokenSavingMode) !== "off") {
|
|
5595
|
+
toolRegistry.exposeToProvider("mcp_control");
|
|
5596
|
+
}
|
|
5597
|
+
toolRegistry.register(
|
|
5598
|
+
createMcpUseTool({
|
|
5599
|
+
registry: mcpRegistry,
|
|
5600
|
+
toolRegistry
|
|
5601
|
+
})
|
|
5602
|
+
);
|
|
5603
|
+
if (normalizeTokenSavingTier2(config.features.tokenSavingMode) !== "off") {
|
|
5604
|
+
toolRegistry.exposeToProvider("mcp_use");
|
|
5455
5605
|
}
|
|
5456
5606
|
return {
|
|
5457
5607
|
brain,
|
|
@@ -5933,13 +6083,78 @@ import * as path10 from "node:path";
|
|
|
5933
6083
|
import { expectDefined as expectDefined2 } from "@wrongstack/core/utils";
|
|
5934
6084
|
import { createAgentMonitorService } from "@wrongstack/core/coordination";
|
|
5935
6085
|
import { sessionScopedPath as sessionScopedPath2 } from "@wrongstack/core/utils";
|
|
6086
|
+
|
|
6087
|
+
// src/fleet/budget-source.ts
|
|
6088
|
+
import { DEFAULT_MAX_FLEET_SPAWNS as DEFAULT_MAX_FLEET_SPAWNS3 } from "@wrongstack/core/coordination";
|
|
6089
|
+
function positiveInt(raw) {
|
|
6090
|
+
if (typeof raw === "number" && Number.isFinite(raw) && raw > 0) return Math.floor(raw);
|
|
6091
|
+
if (typeof raw === "string" && raw.trim() !== "") {
|
|
6092
|
+
const n = Number.parseInt(raw, 10);
|
|
6093
|
+
if (Number.isFinite(n) && n > 0) return n;
|
|
6094
|
+
}
|
|
6095
|
+
return void 0;
|
|
6096
|
+
}
|
|
6097
|
+
function resolveFleetBudgetSources(input) {
|
|
6098
|
+
const flags = input.flags ?? {};
|
|
6099
|
+
const env = input.env ?? process.env;
|
|
6100
|
+
const config = input.config;
|
|
6101
|
+
const defaultMaxConcurrent = input.defaultMaxConcurrent ?? 4;
|
|
6102
|
+
const defaultMaxSpawns = input.defaultMaxSpawns ?? DEFAULT_MAX_FLEET_SPAWNS3;
|
|
6103
|
+
const maxConcurrentFlag = positiveInt(flags["max-concurrent"]);
|
|
6104
|
+
const maxConcurrentEnv = positiveInt(env["WRONGSTACK_MAX_CONCURRENT"]);
|
|
6105
|
+
const maxConcurrentProfile = positiveInt(config?.maxConcurrent);
|
|
6106
|
+
let maxConcurrent;
|
|
6107
|
+
let maxConcurrentSource;
|
|
6108
|
+
if (maxConcurrentFlag !== void 0) {
|
|
6109
|
+
maxConcurrent = maxConcurrentFlag;
|
|
6110
|
+
maxConcurrentSource = "cli-flag";
|
|
6111
|
+
} else if (maxConcurrentEnv !== void 0) {
|
|
6112
|
+
maxConcurrent = maxConcurrentEnv;
|
|
6113
|
+
maxConcurrentSource = "env";
|
|
6114
|
+
} else if (maxConcurrentProfile !== void 0) {
|
|
6115
|
+
maxConcurrent = maxConcurrentProfile;
|
|
6116
|
+
maxConcurrentSource = "profile";
|
|
6117
|
+
} else {
|
|
6118
|
+
maxConcurrent = defaultMaxConcurrent;
|
|
6119
|
+
maxConcurrentSource = "default";
|
|
6120
|
+
}
|
|
6121
|
+
const maxSpawnsFlag = positiveInt(flags["max-spawns"]);
|
|
6122
|
+
const maxSpawnsEnv = positiveInt(env["WRONGSTACK_MAX_SPAWNS"]);
|
|
6123
|
+
const maxSpawnsProfile = positiveInt(config?.fleet?.budget?.maxSpawns);
|
|
6124
|
+
let maxSpawns;
|
|
6125
|
+
let maxSpawnsSource;
|
|
6126
|
+
if (maxSpawnsFlag !== void 0) {
|
|
6127
|
+
maxSpawns = maxSpawnsFlag;
|
|
6128
|
+
maxSpawnsSource = "cli-flag";
|
|
6129
|
+
} else if (maxSpawnsEnv !== void 0) {
|
|
6130
|
+
maxSpawns = maxSpawnsEnv;
|
|
6131
|
+
maxSpawnsSource = "env";
|
|
6132
|
+
} else if (maxSpawnsProfile !== void 0) {
|
|
6133
|
+
maxSpawns = maxSpawnsProfile;
|
|
6134
|
+
maxSpawnsSource = "profile";
|
|
6135
|
+
} else {
|
|
6136
|
+
maxSpawns = defaultMaxSpawns;
|
|
6137
|
+
maxSpawnsSource = "default";
|
|
6138
|
+
}
|
|
6139
|
+
return {
|
|
6140
|
+
maxConcurrent,
|
|
6141
|
+
maxConcurrentSource,
|
|
6142
|
+
maxSpawns,
|
|
6143
|
+
maxSpawnsSource
|
|
6144
|
+
};
|
|
6145
|
+
}
|
|
6146
|
+
|
|
6147
|
+
// src/wiring/director-setup.ts
|
|
5936
6148
|
function setupDirectorAndAutonomy(deps) {
|
|
5937
6149
|
const { flags, config, wpaths, session, events, autonomyModeRef } = deps;
|
|
5938
6150
|
const directorMode = true;
|
|
5939
|
-
const
|
|
5940
|
-
|
|
5941
|
-
|
|
5942
|
-
|
|
6151
|
+
const {
|
|
6152
|
+
maxConcurrent: resolvedMaxConcurrent,
|
|
6153
|
+
maxConcurrentSource,
|
|
6154
|
+
maxSpawns,
|
|
6155
|
+
maxSpawnsSource
|
|
6156
|
+
} = resolveFleetBudgetSources({ flags, config });
|
|
6157
|
+
const maxConcurrent = maxConcurrentSource === "default" ? void 0 : resolvedMaxConcurrent;
|
|
5943
6158
|
const autonomyMode = (() => {
|
|
5944
6159
|
const v = flags["autonomy"];
|
|
5945
6160
|
if (v === "auto" || v === "suggest" || v === "eternal" || v === "eternal-parallel") return v;
|
|
@@ -5986,6 +6201,9 @@ function setupDirectorAndAutonomy(deps) {
|
|
|
5986
6201
|
director: null,
|
|
5987
6202
|
directorMode,
|
|
5988
6203
|
maxConcurrent,
|
|
6204
|
+
maxSpawns,
|
|
6205
|
+
maxConcurrentSource,
|
|
6206
|
+
maxSpawnsSource,
|
|
5989
6207
|
autonomyMode,
|
|
5990
6208
|
nextPredictEnabled,
|
|
5991
6209
|
currentSuggestions,
|
|
@@ -6105,6 +6323,7 @@ ${color6.dim("\u2500".repeat(40))}` : "";
|
|
|
6105
6323
|
onAgents: (subagentId) => formatAgents(input, subagentId),
|
|
6106
6324
|
onFleet: (action, target) => handleFleetAction(input, action, target),
|
|
6107
6325
|
onFleetStatus: () => input.getDirector()?.status() ?? null,
|
|
6326
|
+
onFleetBudget: () => input.multiAgentHost.budgetView(),
|
|
6108
6327
|
onFleetUsage: () => input.getDirector()?.snapshot() ?? null,
|
|
6109
6328
|
onFleetKill: () => killFleet2(input.getDirector()),
|
|
6110
6329
|
onFleetTerminate: async (subagentId) => {
|
|
@@ -6223,6 +6442,15 @@ async function handleFleetAction(input, action, target) {
|
|
|
6223
6442
|
function formatFleetStatus(host) {
|
|
6224
6443
|
const status = host.status();
|
|
6225
6444
|
const lines = [color6.bold("Fleet status"), ` ${status.summary}`];
|
|
6445
|
+
const budget = status.budget ?? host.budgetView();
|
|
6446
|
+
lines.push(
|
|
6447
|
+
"",
|
|
6448
|
+
...formatFleetBudgetLines(budget, {
|
|
6449
|
+
bold: color6.bold,
|
|
6450
|
+
dim: color6.dim,
|
|
6451
|
+
amber: color6.amber
|
|
6452
|
+
})
|
|
6453
|
+
);
|
|
6226
6454
|
const icons = { running: "\u25CF", idle: "\u25CB", stopped: "\u2298" };
|
|
6227
6455
|
const active2 = status.live.filter((agent) => agent.status === "running" || agent.status === "idle");
|
|
6228
6456
|
if (active2.length > 0) {
|
|
@@ -6762,6 +6990,7 @@ function setupHqTelemetry(deps) {
|
|
|
6762
6990
|
// src/wiring/lifecycle-plugins.ts
|
|
6763
6991
|
import * as path15 from "node:path";
|
|
6764
6992
|
import { getSharedProjectMailbox as getSharedProjectMailbox8 } from "@wrongstack/core/coordination";
|
|
6993
|
+
import { CouncilOrchestrator, OneShotOrchestrator as OneShotOrchestrator2 } from "@wrongstack/core/execution";
|
|
6765
6994
|
import { countShellHooks, HookRegistry, HookRunner, shellHooksEqual } from "@wrongstack/core/hooks";
|
|
6766
6995
|
import { allServers } from "@wrongstack/core/infrastructure";
|
|
6767
6996
|
import { TOKENS as TOKENS8 } from "@wrongstack/core/kernel";
|
|
@@ -6769,7 +6998,7 @@ import { NotifierImpl } from "@wrongstack/core/notifications";
|
|
|
6769
6998
|
import {
|
|
6770
6999
|
SlashCommandRegistry
|
|
6771
7000
|
} from "@wrongstack/core/registry";
|
|
6772
|
-
import { normalizeTokenSavingTier as
|
|
7001
|
+
import { normalizeTokenSavingTier as normalizeTokenSavingTier3 } from "@wrongstack/core/types";
|
|
6773
7002
|
import {
|
|
6774
7003
|
createVaultBackedMcpAuthorizationProviderFactory,
|
|
6775
7004
|
MCPAuthorizationManager,
|
|
@@ -7041,13 +7270,19 @@ function setupMetrics(params) {
|
|
|
7041
7270
|
}
|
|
7042
7271
|
|
|
7043
7272
|
// src/wiring/pipeline.ts
|
|
7044
|
-
import {
|
|
7045
|
-
|
|
7046
|
-
|
|
7273
|
+
import {
|
|
7274
|
+
Agent as Agent2,
|
|
7275
|
+
createDefaultPipelines as createDefaultPipelines2
|
|
7276
|
+
} from "@wrongstack/core/agent";
|
|
7277
|
+
import {
|
|
7278
|
+
AutoCompactionMiddleware,
|
|
7279
|
+
applyModelRuntime as applyModelRuntime2,
|
|
7280
|
+
ToolExecutor as ToolExecutor2
|
|
7281
|
+
} from "@wrongstack/core/execution";
|
|
7047
7282
|
import { TOKENS as TOKENS7 } from "@wrongstack/core/kernel";
|
|
7048
|
-
import {
|
|
7283
|
+
import { createSessionEventBridge as createSessionEventBridge2, resolveAuditLevel } from "@wrongstack/core/storage";
|
|
7049
7284
|
import { resolveContextWindowPolicy } from "@wrongstack/core/types";
|
|
7050
|
-
import {
|
|
7285
|
+
import { estimateRequestTokensCalibrated } from "@wrongstack/core/utils";
|
|
7051
7286
|
|
|
7052
7287
|
// src/wiring/mailbox-bridge-bootstrap.ts
|
|
7053
7288
|
import { resolveProjectDir as resolveProjectDir2 } from "@wrongstack/core/coordination";
|
|
@@ -7159,7 +7394,7 @@ async function bootstrapMailboxBridgeAtStartup(params) {
|
|
|
7159
7394
|
if (!params.projectRoot) {
|
|
7160
7395
|
return null;
|
|
7161
7396
|
}
|
|
7162
|
-
const mode = params.config?.features?.mailboxBridge ?? "
|
|
7397
|
+
const mode = params.config?.features?.mailboxBridge ?? "off";
|
|
7163
7398
|
if (mode === "off") {
|
|
7164
7399
|
return null;
|
|
7165
7400
|
}
|
|
@@ -7181,10 +7416,10 @@ async function bootstrapMailboxBridgeAtStartup(params) {
|
|
|
7181
7416
|
switch (handle.source) {
|
|
7182
7417
|
case "joined":
|
|
7183
7418
|
case "spawned":
|
|
7184
|
-
params.logger.debug(
|
|
7185
|
-
|
|
7186
|
-
|
|
7187
|
-
);
|
|
7419
|
+
params.logger.debug(`mailbox bridge ready via ${handle.source} on ${params.source} boot`, {
|
|
7420
|
+
url: handle.url,
|
|
7421
|
+
lockPath: handle.lockPath
|
|
7422
|
+
});
|
|
7188
7423
|
break;
|
|
7189
7424
|
case "unhealthy":
|
|
7190
7425
|
params.logger.warn(
|
|
@@ -7350,6 +7585,133 @@ function createAgent(params) {
|
|
|
7350
7585
|
});
|
|
7351
7586
|
}
|
|
7352
7587
|
|
|
7588
|
+
// src/wiring/provider-utility-tools.ts
|
|
7589
|
+
import { createContextManagerTool as createContextManagerTool2 } from "@wrongstack/core/infrastructure";
|
|
7590
|
+
import { createCouncilTool, createOneShotLLMTool } from "@wrongstack/core/tools";
|
|
7591
|
+
import {
|
|
7592
|
+
createCouncilPersonaRegistry,
|
|
7593
|
+
createCouncilProfileRegistry,
|
|
7594
|
+
OneShotOrchestrator
|
|
7595
|
+
} from "@wrongstack/core/execution";
|
|
7596
|
+
import { ModelRouter } from "@wrongstack/core/models";
|
|
7597
|
+
async function adoptResumedProvider(input) {
|
|
7598
|
+
if (!input.resumedProvider && !input.resumedModel) return;
|
|
7599
|
+
const config = input.getConfig();
|
|
7600
|
+
const provider = input.resumedProvider?.trim() || config.provider;
|
|
7601
|
+
const model = input.resumedModel?.trim() || config.model;
|
|
7602
|
+
if (provider === config.provider && model === config.model) return;
|
|
7603
|
+
const error = await input.switchProviderAndModel(provider, model);
|
|
7604
|
+
if (error) {
|
|
7605
|
+
const current = input.getConfig();
|
|
7606
|
+
input.logger.warn(
|
|
7607
|
+
`Resume: could not switch to the session's model ${provider}/${model} (${error}); continuing with ${current.provider}/${current.model}.`
|
|
7608
|
+
);
|
|
7609
|
+
}
|
|
7610
|
+
}
|
|
7611
|
+
function createLiveModelRouter(getConfig) {
|
|
7612
|
+
return {
|
|
7613
|
+
pickForTask(role, description) {
|
|
7614
|
+
const config = getConfig();
|
|
7615
|
+
const router = new ModelRouter({
|
|
7616
|
+
...config.modelMatrix ? { matrix: config.modelMatrix } : {},
|
|
7617
|
+
config: {
|
|
7618
|
+
provider: config.provider,
|
|
7619
|
+
model: config.model,
|
|
7620
|
+
...config.providers ? { providers: config.providers } : {}
|
|
7621
|
+
}
|
|
7622
|
+
});
|
|
7623
|
+
return router.pickForTask(role, description);
|
|
7624
|
+
}
|
|
7625
|
+
};
|
|
7626
|
+
}
|
|
7627
|
+
function buildCouncilRegistries(cfg) {
|
|
7628
|
+
const base = {
|
|
7629
|
+
...cfg?.defaultProfile ? { defaultProfile: cfg.defaultProfile } : {},
|
|
7630
|
+
...cfg?.maxConcurrency !== void 0 ? { maxConcurrency: cfg.maxConcurrency } : {}
|
|
7631
|
+
};
|
|
7632
|
+
if (!cfg?.personas?.length && !cfg?.profiles?.length) return base;
|
|
7633
|
+
try {
|
|
7634
|
+
const personas = createCouncilPersonaRegistry(cfg.personas ?? []);
|
|
7635
|
+
const profiles = createCouncilProfileRegistry(
|
|
7636
|
+
cfg.profiles ?? [],
|
|
7637
|
+
personas
|
|
7638
|
+
);
|
|
7639
|
+
return { ...base, personas, profiles };
|
|
7640
|
+
} catch (error) {
|
|
7641
|
+
console.warn(
|
|
7642
|
+
`Council tool: ignoring tools.council personas/profiles \u2014 ${error instanceof Error ? error.message : String(error)}. Falling back to the built-in lenses and panels.`
|
|
7643
|
+
);
|
|
7644
|
+
return base;
|
|
7645
|
+
}
|
|
7646
|
+
}
|
|
7647
|
+
function registerProviderUtilityTools(input) {
|
|
7648
|
+
const config = input.getConfig();
|
|
7649
|
+
const llmTool = createOneShotLLMTool({
|
|
7650
|
+
buildProvider: input.buildProvider,
|
|
7651
|
+
getConfig: input.getConfig,
|
|
7652
|
+
fallbackProfileManager: input.fallbackProfileManager,
|
|
7653
|
+
defaultProvider: config.provider,
|
|
7654
|
+
defaultModel: config.model,
|
|
7655
|
+
wrapProviderCall: input.wrapProviderCall
|
|
7656
|
+
});
|
|
7657
|
+
registerOrOverride(input.toolRegistry, "llm", llmTool);
|
|
7658
|
+
const councilOrchestrator = new OneShotOrchestrator({
|
|
7659
|
+
buildProvider: input.buildProvider,
|
|
7660
|
+
getConfig: input.getConfig,
|
|
7661
|
+
fallbackProfileManager: input.fallbackProfileManager,
|
|
7662
|
+
statusTracker: input.statusTracker,
|
|
7663
|
+
// Council profiles route each seat by ROLE ('planner', 'critic',
|
|
7664
|
+
// 'analyst', 'security-reviewer'…) rather than pinning models. Without a
|
|
7665
|
+
// router those hints were inert: every seat fell through to the session
|
|
7666
|
+
// provider/model, so a three-seat panel asked one model three times and
|
|
7667
|
+
// reported a distinctness warning on every single call.
|
|
7668
|
+
modelRouter: createLiveModelRouter(input.getConfig),
|
|
7669
|
+
wrapProviderCall: input.wrapProviderCall
|
|
7670
|
+
});
|
|
7671
|
+
registerOrOverride(
|
|
7672
|
+
input.toolRegistry,
|
|
7673
|
+
"council",
|
|
7674
|
+
createCouncilTool({
|
|
7675
|
+
caller: councilOrchestrator,
|
|
7676
|
+
fallbackProfileManager: input.fallbackProfileManager,
|
|
7677
|
+
...buildCouncilRegistries(config.tools?.council)
|
|
7678
|
+
})
|
|
7679
|
+
);
|
|
7680
|
+
try {
|
|
7681
|
+
const summarizer = new OneShotOrchestrator({
|
|
7682
|
+
buildProvider: input.buildProvider,
|
|
7683
|
+
getConfig: input.getConfig,
|
|
7684
|
+
fallbackProfileManager: input.fallbackProfileManager,
|
|
7685
|
+
statusTracker: input.statusTracker,
|
|
7686
|
+
wrapProviderCall: input.wrapProviderCall
|
|
7687
|
+
});
|
|
7688
|
+
input.toolRegistry.override(
|
|
7689
|
+
"context_manager",
|
|
7690
|
+
createContextManagerTool2({
|
|
7691
|
+
compactor: input.compactor,
|
|
7692
|
+
summarizer: async (messages) => {
|
|
7693
|
+
const result = await summarizer.call({
|
|
7694
|
+
system: "Summarize concisely. Keep decisions and key facts.",
|
|
7695
|
+
messages,
|
|
7696
|
+
model: "deepseek-chat",
|
|
7697
|
+
maxTokens: 1024,
|
|
7698
|
+
timeoutMs: 3e4
|
|
7699
|
+
});
|
|
7700
|
+
return result.text || "(summary unavailable)";
|
|
7701
|
+
}
|
|
7702
|
+
})
|
|
7703
|
+
);
|
|
7704
|
+
} catch {
|
|
7705
|
+
}
|
|
7706
|
+
}
|
|
7707
|
+
function registerOrOverride(registry, name, tool) {
|
|
7708
|
+
try {
|
|
7709
|
+
registry.register(tool);
|
|
7710
|
+
} catch {
|
|
7711
|
+
registry.override(name, tool);
|
|
7712
|
+
}
|
|
7713
|
+
}
|
|
7714
|
+
|
|
7353
7715
|
// src/wiring/lifecycle-plugins.ts
|
|
7354
7716
|
async function setupLifecycleAndPlugins(deps) {
|
|
7355
7717
|
const {
|
|
@@ -7506,7 +7868,7 @@ async function setupLifecycleAndPlugins(deps) {
|
|
|
7506
7868
|
toolRegistry,
|
|
7507
7869
|
events,
|
|
7508
7870
|
log: logger,
|
|
7509
|
-
lazyMode:
|
|
7871
|
+
lazyMode: normalizeTokenSavingTier3(config.features.tokenSavingMode) !== "off",
|
|
7510
7872
|
cacheDir: wpaths.cacheDir,
|
|
7511
7873
|
authorizationProviderFactory: createVaultBackedMcpAuthorizationProviderFactory({
|
|
7512
7874
|
store: mcpTokenStore
|
|
@@ -7532,6 +7894,31 @@ async function setupLifecycleAndPlugins(deps) {
|
|
|
7532
7894
|
() => hqPublisherRef.current
|
|
7533
7895
|
);
|
|
7534
7896
|
const notifier = new NotifierImpl();
|
|
7897
|
+
const getLiveConfig = () => configStore.get();
|
|
7898
|
+
const fallbackProfileManager = container.resolve(TOKENS8.FallbackProfileManager);
|
|
7899
|
+
const statusTracker = container.resolve(TOKENS8.ProviderModelStatusTracker);
|
|
7900
|
+
const buildUtilityProvider = (providerId) => buildProviderForIdRuntimeFn({ config: getLiveConfig(), providerRegistry }, providerId);
|
|
7901
|
+
const pluginOneShot = new OneShotOrchestrator2({
|
|
7902
|
+
buildProvider: buildUtilityProvider,
|
|
7903
|
+
getConfig: getLiveConfig,
|
|
7904
|
+
fallbackProfileManager,
|
|
7905
|
+
statusTracker,
|
|
7906
|
+
modelRouter: createLiveModelRouter(getLiveConfig),
|
|
7907
|
+
logger,
|
|
7908
|
+
// Route plugin completions through the same extension chain the agent loop
|
|
7909
|
+
// uses. `prompt-firewall` (credential redaction), `llm-cache`,
|
|
7910
|
+
// `model-router` and the token budgeter all live on `wrapProviderRunner`,
|
|
7911
|
+
// and `api.llm` reached the provider without any of them. Resolved per
|
|
7912
|
+
// call so a plugin enabled mid-session joins the chain.
|
|
7913
|
+
wrapProviderCall: (request, inner) => agent.extensions.wrapProviderRunner((_ctx, req) => inner(req), {
|
|
7914
|
+
exclude: ["fallback-model"]
|
|
7915
|
+
})(agent.ctx, request)
|
|
7916
|
+
});
|
|
7917
|
+
const pluginCouncil = new CouncilOrchestrator({
|
|
7918
|
+
caller: pluginOneShot,
|
|
7919
|
+
fallbackProfileManager,
|
|
7920
|
+
...buildCouncilRegistries(getLiveConfig().tools?.council)
|
|
7921
|
+
});
|
|
7535
7922
|
const pluginHost = await setupPlugins({
|
|
7536
7923
|
config,
|
|
7537
7924
|
container,
|
|
@@ -7572,7 +7959,9 @@ async function setupLifecycleAndPlugins(deps) {
|
|
|
7572
7959
|
model: config.model,
|
|
7573
7960
|
getProvider: () => context.provider,
|
|
7574
7961
|
getModel: () => context.model,
|
|
7575
|
-
createProvider: (name) => buildProviderForIdRuntimeFn({ config: configStore.get(), providerRegistry }, name)
|
|
7962
|
+
createProvider: (name) => buildProviderForIdRuntimeFn({ config: configStore.get(), providerRegistry }, name),
|
|
7963
|
+
oneShot: (input) => pluginOneShot.call(input),
|
|
7964
|
+
council: (question) => pluginCouncil.ask(question)
|
|
7576
7965
|
}
|
|
7577
7966
|
});
|
|
7578
7967
|
return {
|
|
@@ -7593,12 +7982,16 @@ async function setupLifecycleAndPlugins(deps) {
|
|
|
7593
7982
|
|
|
7594
7983
|
// src/wiring/management-tools.ts
|
|
7595
7984
|
import * as fs5 from "node:fs/promises";
|
|
7596
|
-
import {
|
|
7985
|
+
import {
|
|
7986
|
+
createFallbackManageTools,
|
|
7987
|
+
createPluginManagerTool
|
|
7988
|
+
} from "@wrongstack/core/tools";
|
|
7597
7989
|
function registerCliManagementTools({
|
|
7598
7990
|
toolRegistry,
|
|
7599
7991
|
configStore,
|
|
7600
7992
|
profileConfigPath,
|
|
7601
|
-
stdinInteractive
|
|
7993
|
+
stdinInteractive,
|
|
7994
|
+
getHookRunner
|
|
7602
7995
|
}) {
|
|
7603
7996
|
const fallbackManageTools = createFallbackManageTools({
|
|
7604
7997
|
getConfig: () => configStore.get(),
|
|
@@ -7628,6 +8021,7 @@ ${prompt}
|
|
|
7628
8021
|
for (const tool of fallbackManageTools) toolRegistry.register(tool);
|
|
7629
8022
|
toolRegistry.register(
|
|
7630
8023
|
createPluginManagerTool({
|
|
8024
|
+
...getHookRunner ? { getHookRunner } : {},
|
|
7631
8025
|
getConfig: () => configStore.get(),
|
|
7632
8026
|
catalog: PLUGIN_AUDIT_ENTRIES.map((entry) => {
|
|
7633
8027
|
const aliases = [
|
|
@@ -7672,6 +8066,61 @@ import {
|
|
|
7672
8066
|
} from "@wrongstack/core/storage";
|
|
7673
8067
|
import { withCatalogCapabilities as withCatalogCapabilities2 } from "@wrongstack/providers";
|
|
7674
8068
|
import { getSageService } from "@wrongstack/sage";
|
|
8069
|
+
|
|
8070
|
+
// src/wiring/fallback-gate.ts
|
|
8071
|
+
function createFallbackGate(_events) {
|
|
8072
|
+
const gateFn = (params) => {
|
|
8073
|
+
const { events: bus, sessionId, from, status, candidates, autoSwitchSeconds, requestId } = params;
|
|
8074
|
+
return runGate(bus, { sessionId, from, status, candidates, autoSwitchSeconds, requestId });
|
|
8075
|
+
};
|
|
8076
|
+
return gateFn;
|
|
8077
|
+
}
|
|
8078
|
+
function runGate(events, gateParams) {
|
|
8079
|
+
const { sessionId, from, status, candidates, autoSwitchSeconds, requestId } = gateParams;
|
|
8080
|
+
if (events.listenerCount("provider.fallback_pending") === 0) {
|
|
8081
|
+
return Promise.resolve(null);
|
|
8082
|
+
}
|
|
8083
|
+
return new Promise((resolve8) => {
|
|
8084
|
+
let settled = false;
|
|
8085
|
+
let timer;
|
|
8086
|
+
let deadline;
|
|
8087
|
+
const cleanup = () => {
|
|
8088
|
+
if (timer) clearTimeout(timer);
|
|
8089
|
+
if (deadline) clearTimeout(deadline);
|
|
8090
|
+
events.off("provider.fallback_choice", handler);
|
|
8091
|
+
};
|
|
8092
|
+
const finish = (result) => {
|
|
8093
|
+
if (settled) return;
|
|
8094
|
+
settled = true;
|
|
8095
|
+
cleanup();
|
|
8096
|
+
resolve8(result);
|
|
8097
|
+
};
|
|
8098
|
+
const handler = (payload) => {
|
|
8099
|
+
const p = payload;
|
|
8100
|
+
if (p?.requestId !== requestId) return;
|
|
8101
|
+
if (p.autoSwitch === true) {
|
|
8102
|
+
finish(null);
|
|
8103
|
+
return;
|
|
8104
|
+
}
|
|
8105
|
+
if (typeof p.providerId === "string" && typeof p.model === "string") {
|
|
8106
|
+
finish({ providerId: p.providerId, model: p.model });
|
|
8107
|
+
}
|
|
8108
|
+
};
|
|
8109
|
+
events.on("provider.fallback_choice", handler);
|
|
8110
|
+
deadline = setTimeout(() => finish(null), Math.round(autoSwitchSeconds * 1500));
|
|
8111
|
+
events.emit("provider.fallback_pending", {
|
|
8112
|
+
...sessionId ? { sessionId } : {},
|
|
8113
|
+
from,
|
|
8114
|
+
status,
|
|
8115
|
+
candidates,
|
|
8116
|
+
autoSwitchSeconds,
|
|
8117
|
+
requestId,
|
|
8118
|
+
timestamp: Date.now()
|
|
8119
|
+
});
|
|
8120
|
+
});
|
|
8121
|
+
}
|
|
8122
|
+
|
|
8123
|
+
// src/wiring/provider-runtime-setup.ts
|
|
7675
8124
|
function serializeProviderRuntimeSnapshot(snapshot) {
|
|
7676
8125
|
return JSON.stringify(snapshot);
|
|
7677
8126
|
}
|
|
@@ -7736,6 +8185,12 @@ function setupProviderRuntime(deps) {
|
|
|
7736
8185
|
events,
|
|
7737
8186
|
logger,
|
|
7738
8187
|
statusTracker,
|
|
8188
|
+
// Fallback gate — shows a modal with countdown + manual pick in every
|
|
8189
|
+
// UI surface (TUI/WebUI/SimpleUI) before switching models. The gate
|
|
8190
|
+
// emits provider.fallback_pending and waits for provider.fallback_choice
|
|
8191
|
+
// or the auto-switch countdown.
|
|
8192
|
+
fallbackGate: createFallbackGate(events),
|
|
8193
|
+
fallbackGateSeconds: 7,
|
|
7739
8194
|
...cfg.fallbackStickiness?.primaryProbeInterval !== void 0 ? { primaryCooldownMs: cfg.fallbackStickiness.primaryProbeInterval } : {},
|
|
7740
8195
|
...cfg.fallbackStickiness?.stickyFallbackTurns !== void 0 ? { stickyFallbackTurns: cfg.fallbackStickiness.stickyFallbackTurns } : {}
|
|
7741
8196
|
})
|
|
@@ -7783,19 +8238,34 @@ function setupProviderRuntime(deps) {
|
|
|
7783
8238
|
if (process.env["WRONGSTACK_DISABLE_CONFIG_WATCH"] !== "1") {
|
|
7784
8239
|
const activeProfile = typeof cfg.activeProfile === "string" && cfg.activeProfile ? cfg.activeProfile : "default";
|
|
7785
8240
|
const configLayers = [
|
|
7786
|
-
{ path: wpaths.profileConfig(activeProfile), priority: 1 },
|
|
7787
|
-
{ path: wpaths.projectLocalConfig, priority: 2 },
|
|
7788
|
-
{ path: wpaths.inProjectConfig, priority: 3 }
|
|
8241
|
+
{ path: wpaths.profileConfig(activeProfile), priority: 1, trusted: true },
|
|
8242
|
+
{ path: wpaths.projectLocalConfig, priority: 2, trusted: true },
|
|
8243
|
+
{ path: wpaths.inProjectConfig, priority: 3, trusted: false }
|
|
7789
8244
|
];
|
|
8245
|
+
const sanitizeUntrustedSnapshot = (snap, path32) => {
|
|
8246
|
+
const { providers, apiKey, baseUrl, ...rest } = snap;
|
|
8247
|
+
const dropped = [
|
|
8248
|
+
...Object.keys(providers ?? {}).length > 0 ? ["providers"] : [],
|
|
8249
|
+
...apiKey !== void 0 ? ["apiKey"] : [],
|
|
8250
|
+
...baseUrl !== void 0 ? ["baseUrl"] : []
|
|
8251
|
+
];
|
|
8252
|
+
if (dropped.length > 0) {
|
|
8253
|
+
logger.warn(
|
|
8254
|
+
`Config watcher: ignored credential field(s) from the repo-committed config "${path32}": ${dropped.join(", ")}. Only your profile config may set these.`
|
|
8255
|
+
);
|
|
8256
|
+
}
|
|
8257
|
+
return { ...rest, providers: {}, snapshotHasProviders: false };
|
|
8258
|
+
};
|
|
7790
8259
|
const readMergedSnapshot = async () => {
|
|
7791
8260
|
let merged;
|
|
7792
8261
|
for (const layer of configLayers.sort((a, b) => a.priority - b.priority)) {
|
|
7793
|
-
const
|
|
8262
|
+
const raw = await readProviderSnapshot(
|
|
7794
8263
|
layer.path,
|
|
7795
8264
|
vault,
|
|
7796
8265
|
(msg) => logger.warn(`Config watcher (${layer.path}): ${msg}`)
|
|
7797
8266
|
);
|
|
7798
|
-
if (!
|
|
8267
|
+
if (!raw) continue;
|
|
8268
|
+
const snap = layer.trusted ? raw : sanitizeUntrustedSnapshot(raw, layer.path);
|
|
7799
8269
|
if (!merged) {
|
|
7800
8270
|
merged = {
|
|
7801
8271
|
...snap,
|
|
@@ -7977,130 +8447,6 @@ function warnUnlessMissing(logger, operation, error) {
|
|
|
7977
8447
|
}
|
|
7978
8448
|
}
|
|
7979
8449
|
|
|
7980
|
-
// src/wiring/provider-utility-tools.ts
|
|
7981
|
-
import { createContextManagerTool as createContextManagerTool2 } from "@wrongstack/core/infrastructure";
|
|
7982
|
-
import { createCouncilTool, createOneShotLLMTool } from "@wrongstack/core/tools";
|
|
7983
|
-
import {
|
|
7984
|
-
createCouncilPersonaRegistry,
|
|
7985
|
-
createCouncilProfileRegistry,
|
|
7986
|
-
OneShotOrchestrator
|
|
7987
|
-
} from "@wrongstack/core/execution";
|
|
7988
|
-
import { ModelRouter } from "@wrongstack/core/models";
|
|
7989
|
-
async function adoptResumedProvider(input) {
|
|
7990
|
-
if (!input.resumedProvider && !input.resumedModel) return;
|
|
7991
|
-
const config = input.getConfig();
|
|
7992
|
-
const provider = input.resumedProvider?.trim() || config.provider;
|
|
7993
|
-
const model = input.resumedModel?.trim() || config.model;
|
|
7994
|
-
if (provider === config.provider && model === config.model) return;
|
|
7995
|
-
const error = await input.switchProviderAndModel(provider, model);
|
|
7996
|
-
if (error) {
|
|
7997
|
-
const current = input.getConfig();
|
|
7998
|
-
input.logger.warn(
|
|
7999
|
-
`Resume: could not switch to the session's model ${provider}/${model} (${error}); continuing with ${current.provider}/${current.model}.`
|
|
8000
|
-
);
|
|
8001
|
-
}
|
|
8002
|
-
}
|
|
8003
|
-
function createLiveModelRouter(getConfig) {
|
|
8004
|
-
return {
|
|
8005
|
-
pickForTask(role, description) {
|
|
8006
|
-
const config = getConfig();
|
|
8007
|
-
const router = new ModelRouter({
|
|
8008
|
-
...config.modelMatrix ? { matrix: config.modelMatrix } : {},
|
|
8009
|
-
config: {
|
|
8010
|
-
provider: config.provider,
|
|
8011
|
-
model: config.model,
|
|
8012
|
-
...config.providers ? { providers: config.providers } : {}
|
|
8013
|
-
}
|
|
8014
|
-
});
|
|
8015
|
-
return router.pickForTask(role, description);
|
|
8016
|
-
}
|
|
8017
|
-
};
|
|
8018
|
-
}
|
|
8019
|
-
function buildCouncilRegistries(cfg) {
|
|
8020
|
-
const base = {
|
|
8021
|
-
...cfg?.defaultProfile ? { defaultProfile: cfg.defaultProfile } : {},
|
|
8022
|
-
...cfg?.maxConcurrency !== void 0 ? { maxConcurrency: cfg.maxConcurrency } : {}
|
|
8023
|
-
};
|
|
8024
|
-
if (!cfg?.personas?.length && !cfg?.profiles?.length) return base;
|
|
8025
|
-
try {
|
|
8026
|
-
const personas = createCouncilPersonaRegistry(cfg.personas ?? []);
|
|
8027
|
-
const profiles = createCouncilProfileRegistry(
|
|
8028
|
-
cfg.profiles ?? [],
|
|
8029
|
-
personas
|
|
8030
|
-
);
|
|
8031
|
-
return { ...base, personas, profiles };
|
|
8032
|
-
} catch (error) {
|
|
8033
|
-
console.warn(
|
|
8034
|
-
`Council tool: ignoring tools.council personas/profiles \u2014 ${error instanceof Error ? error.message : String(error)}. Falling back to the built-in lenses and panels.`
|
|
8035
|
-
);
|
|
8036
|
-
return base;
|
|
8037
|
-
}
|
|
8038
|
-
}
|
|
8039
|
-
function registerProviderUtilityTools(input) {
|
|
8040
|
-
const config = input.getConfig();
|
|
8041
|
-
const llmTool = createOneShotLLMTool({
|
|
8042
|
-
buildProvider: input.buildProvider,
|
|
8043
|
-
getConfig: input.getConfig,
|
|
8044
|
-
fallbackProfileManager: input.fallbackProfileManager,
|
|
8045
|
-
defaultProvider: config.provider,
|
|
8046
|
-
defaultModel: config.model
|
|
8047
|
-
});
|
|
8048
|
-
registerOrOverride(input.toolRegistry, "llm", llmTool);
|
|
8049
|
-
const councilOrchestrator = new OneShotOrchestrator({
|
|
8050
|
-
buildProvider: input.buildProvider,
|
|
8051
|
-
getConfig: input.getConfig,
|
|
8052
|
-
fallbackProfileManager: input.fallbackProfileManager,
|
|
8053
|
-
statusTracker: input.statusTracker,
|
|
8054
|
-
// Council profiles route each seat by ROLE ('planner', 'critic',
|
|
8055
|
-
// 'analyst', 'security-reviewer'…) rather than pinning models. Without a
|
|
8056
|
-
// router those hints were inert: every seat fell through to the session
|
|
8057
|
-
// provider/model, so a three-seat panel asked one model three times and
|
|
8058
|
-
// reported a distinctness warning on every single call.
|
|
8059
|
-
modelRouter: createLiveModelRouter(input.getConfig)
|
|
8060
|
-
});
|
|
8061
|
-
registerOrOverride(
|
|
8062
|
-
input.toolRegistry,
|
|
8063
|
-
"council",
|
|
8064
|
-
createCouncilTool({
|
|
8065
|
-
caller: councilOrchestrator,
|
|
8066
|
-
fallbackProfileManager: input.fallbackProfileManager,
|
|
8067
|
-
...buildCouncilRegistries(config.tools?.council)
|
|
8068
|
-
})
|
|
8069
|
-
);
|
|
8070
|
-
try {
|
|
8071
|
-
const summarizer = new OneShotOrchestrator({
|
|
8072
|
-
buildProvider: input.buildProvider,
|
|
8073
|
-
getConfig: input.getConfig,
|
|
8074
|
-
fallbackProfileManager: input.fallbackProfileManager,
|
|
8075
|
-
statusTracker: input.statusTracker
|
|
8076
|
-
});
|
|
8077
|
-
input.toolRegistry.override(
|
|
8078
|
-
"context_manager",
|
|
8079
|
-
createContextManagerTool2({
|
|
8080
|
-
compactor: input.compactor,
|
|
8081
|
-
summarizer: async (messages) => {
|
|
8082
|
-
const result = await summarizer.call({
|
|
8083
|
-
system: "Summarize concisely. Keep decisions and key facts.",
|
|
8084
|
-
messages,
|
|
8085
|
-
model: "deepseek-chat",
|
|
8086
|
-
maxTokens: 1024,
|
|
8087
|
-
timeoutMs: 3e4
|
|
8088
|
-
});
|
|
8089
|
-
return result.text || "(summary unavailable)";
|
|
8090
|
-
}
|
|
8091
|
-
})
|
|
8092
|
-
);
|
|
8093
|
-
} catch {
|
|
8094
|
-
}
|
|
8095
|
-
}
|
|
8096
|
-
function registerOrOverride(registry, name, tool) {
|
|
8097
|
-
try {
|
|
8098
|
-
registry.register(tool);
|
|
8099
|
-
} catch {
|
|
8100
|
-
registry.override(name, tool);
|
|
8101
|
-
}
|
|
8102
|
-
}
|
|
8103
|
-
|
|
8104
8450
|
// src/wiring/runtime-controller-deps.ts
|
|
8105
8451
|
import { resolveConfiguredRefinerRef, resolveEnhanceFallbackRef } from "@wrongstack/core/execution";
|
|
8106
8452
|
function createRuntimeControllerDeps(input) {
|
|
@@ -9055,8 +9401,9 @@ async function setupSession(params) {
|
|
|
9055
9401
|
const tCounts = {};
|
|
9056
9402
|
for (const t of dirState.tasks) tCounts[t.status] = (tCounts[t.status] ?? 0) + 1;
|
|
9057
9403
|
const summary = Object.entries(tCounts).map(([k, v]) => `${v} ${k}`).join(", ");
|
|
9404
|
+
const spawnPart = typeof dirState.maxSpawns === "number" && Number.isFinite(dirState.maxSpawns) ? `, spawns ${dirState.spawnCount}/${dirState.maxSpawns} (checkpoint ceiling; live profile may differ)` : `, spawns used ${dirState.spawnCount}`;
|
|
9058
9405
|
renderer.writeInfo(
|
|
9059
|
-
`Prior fleet state: ${dirState.subagents.length} subagent${dirState.subagents.length === 1 ? "" : "s"}, tasks ${summary || "(none)"}.`
|
|
9406
|
+
`Prior fleet state: ${dirState.subagents.length} subagent${dirState.subagents.length === 1 ? "" : "s"}, tasks ${summary || "(none)"}${spawnPart}.`
|
|
9060
9407
|
);
|
|
9061
9408
|
}
|
|
9062
9409
|
} catch {
|
|
@@ -10584,15 +10931,16 @@ ${color13.dim("YOLO enabled; tool calls run without approval unless an explicit
|
|
|
10584
10931
|
// src/slash-commands/brain.ts
|
|
10585
10932
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
10586
10933
|
import { readFile as readFile7 } from "node:fs/promises";
|
|
10934
|
+
import { parseModelRef } from "@wrongstack/core/agent";
|
|
10587
10935
|
import { BUILTIN_COUNCIL_PERSONA_IDS, BUILTIN_COUNCIL_PERSONAS } from "@wrongstack/core/execution";
|
|
10588
10936
|
import { color as color14 } from "@wrongstack/core/utils";
|
|
10589
|
-
import { parseModelRef } from "@wrongstack/core/agent";
|
|
10590
10937
|
var RISK_LEVELS = /* @__PURE__ */ new Set(["off", "low", "medium", "high", "all"]);
|
|
10591
10938
|
var COUNCIL_RISKS = /* @__PURE__ */ new Set(["medium", "high", "critical"]);
|
|
10592
10939
|
var COUNCIL_DISTINCTNESS = /* @__PURE__ */ new Set(["none", "model", "provider"]);
|
|
10593
10940
|
var COUNCIL_NUMERIC_OPS = {
|
|
10594
10941
|
timeout: "perCallTimeoutMs",
|
|
10595
10942
|
concurrency: "maxConcurrency",
|
|
10943
|
+
votertokens: "voterMaxTokens",
|
|
10596
10944
|
judgetokens: "judgeMaxTokens"
|
|
10597
10945
|
};
|
|
10598
10946
|
var PERSONA_SHORTHANDS = new Set(BUILTIN_COUNCIL_PERSONA_IDS);
|
|
@@ -10607,7 +10955,14 @@ var DENY_TERMINAL_VALUES = ["never", "when-decided", "always"];
|
|
|
10607
10955
|
var TRACE_CONTENT_VALUES = ["none", "redacted", "full"];
|
|
10608
10956
|
var TERMINAL_POLICY_VALUES = ["conservative", "deny-all", "continue-on-recommended"];
|
|
10609
10957
|
var MONITOR_POLICY_VALUES = ["llm", "steer", "observe"];
|
|
10610
|
-
var DETERMINISTIC_TIER_NAMES = [
|
|
10958
|
+
var DETERMINISTIC_TIER_NAMES = [
|
|
10959
|
+
"rule",
|
|
10960
|
+
"policy",
|
|
10961
|
+
"heuristic",
|
|
10962
|
+
"cache",
|
|
10963
|
+
"ledger-guard",
|
|
10964
|
+
"terminal"
|
|
10965
|
+
];
|
|
10611
10966
|
function parseRefEntry(ref) {
|
|
10612
10967
|
const parsed = parseModelRef(ref);
|
|
10613
10968
|
const model = parsed.model?.trim();
|
|
@@ -10675,7 +11030,7 @@ function buildBrainCommand(opts) {
|
|
|
10675
11030
|
" /brain council personas List the built-in decision lenses",
|
|
10676
11031
|
" /brain council judge <ref|auto> | quorum <0..1> | approval <0..1>",
|
|
10677
11032
|
" /brain council distinctness <none|model|provider> warn on a non-diverse panel",
|
|
10678
|
-
" /brain council timeout|concurrency|judgetokens <n|default>",
|
|
11033
|
+
" /brain council timeout|concurrency|votertokens|judgetokens <n|default>",
|
|
10679
11034
|
" /brain ledger [n] Show the last n rows (default 15) of the persistent decision ledger",
|
|
10680
11035
|
" /brain ledger on|off | autodeny <n>",
|
|
10681
11036
|
" /brain stats Per-tier decision counts: how often the Brain actually calls a model",
|
|
@@ -10787,7 +11142,10 @@ function buildBrainCommand(opts) {
|
|
|
10787
11142
|
return { message: msg2 };
|
|
10788
11143
|
}
|
|
10789
11144
|
if (ref.toLowerCase() === "session") {
|
|
10790
|
-
return applyPatch(
|
|
11145
|
+
return applyPatch(
|
|
11146
|
+
{ models: null },
|
|
11147
|
+
(s) => `Brain decision model: ${color14.cyan("session model")} (pool cleared)${s.councilLabels.length === 0 ? "" : " \u2014 council dissolved"}`
|
|
11148
|
+
);
|
|
10791
11149
|
}
|
|
10792
11150
|
return applyPatch(
|
|
10793
11151
|
{ models: [ref] },
|
|
@@ -10803,7 +11161,10 @@ function buildBrainCommand(opts) {
|
|
|
10803
11161
|
return { message: msg2 };
|
|
10804
11162
|
}
|
|
10805
11163
|
if (op === "clear") {
|
|
10806
|
-
return applyPatch(
|
|
11164
|
+
return applyPatch(
|
|
11165
|
+
{ models: null },
|
|
11166
|
+
() => `Brain LLM pool cleared \u2014 using the ${color14.cyan("session model")}`
|
|
11167
|
+
);
|
|
10807
11168
|
}
|
|
10808
11169
|
if (op === "add") {
|
|
10809
11170
|
const ref = rest[1];
|
|
@@ -10813,7 +11174,10 @@ function buildBrainCommand(opts) {
|
|
|
10813
11174
|
return { message: msg2 };
|
|
10814
11175
|
}
|
|
10815
11176
|
const current = (snapshot?.models ?? []).map(compactEntry);
|
|
10816
|
-
return applyPatch(
|
|
11177
|
+
return applyPatch(
|
|
11178
|
+
{ models: [...current, ref] },
|
|
11179
|
+
(s) => `Brain LLM pool: ${color14.cyan(poolSummary(s))}`
|
|
11180
|
+
);
|
|
10817
11181
|
}
|
|
10818
11182
|
if (op === "remove") {
|
|
10819
11183
|
const target = rest[1];
|
|
@@ -10823,16 +11187,24 @@ function buildBrainCommand(opts) {
|
|
|
10823
11187
|
return { message: msg2 };
|
|
10824
11188
|
}
|
|
10825
11189
|
const current = snapshot.models.map(compactEntry);
|
|
10826
|
-
const idx = /^\d+$/.test(target) ? Number.parseInt(target, 10) - 1 : current.findIndex(
|
|
11190
|
+
const idx = /^\d+$/.test(target) ? Number.parseInt(target, 10) - 1 : current.findIndex(
|
|
11191
|
+
(c) => c === target || c.endsWith(`/${target}`) || c === parseRefEntry(target)?.model
|
|
11192
|
+
);
|
|
10827
11193
|
if (idx < 0 || idx >= current.length) {
|
|
10828
11194
|
const msg2 = `No pool entry matches "${target}". Current pool: ${current.join(", ") || "(empty)"}`;
|
|
10829
11195
|
opts.renderer.writeWarning(msg2);
|
|
10830
11196
|
return { message: msg2 };
|
|
10831
11197
|
}
|
|
10832
11198
|
const next = current.filter((_, i) => i !== idx);
|
|
10833
|
-
return applyPatch(
|
|
11199
|
+
return applyPatch(
|
|
11200
|
+
{ models: next.length > 0 ? next : null },
|
|
11201
|
+
(s) => `Brain LLM pool: ${color14.cyan(poolSummary(s))}`
|
|
11202
|
+
);
|
|
10834
11203
|
}
|
|
10835
|
-
return applyPatch(
|
|
11204
|
+
return applyPatch(
|
|
11205
|
+
{ models: rest },
|
|
11206
|
+
(s) => `Brain LLM pool: ${color14.cyan(poolSummary(s))} ${color14.dim(`(${s.poolLabels.length}/${rest.length} resolved)`)}`
|
|
11207
|
+
);
|
|
10836
11208
|
}
|
|
10837
11209
|
if (subcommand === "strategy") {
|
|
10838
11210
|
const strategy = (rest[0] ?? "").toLowerCase();
|
|
@@ -10882,7 +11254,10 @@ function buildBrainCommand(opts) {
|
|
|
10882
11254
|
return { message: msg3 };
|
|
10883
11255
|
}
|
|
10884
11256
|
if (op === "on" || op === "off") {
|
|
10885
|
-
return applyPatch(
|
|
11257
|
+
return applyPatch(
|
|
11258
|
+
{ council: { enabled: op === "on" } },
|
|
11259
|
+
(s) => `Brain ${councilSummary(s)}${op === "on" && !s.council.enabled ? " \u2014 needs \u22652 resolvable voters (set /brain council voters or a \u22652-model pool)" : ""}`
|
|
11260
|
+
);
|
|
10886
11261
|
}
|
|
10887
11262
|
if (op === "minrisk") {
|
|
10888
11263
|
const level = (rest[1] ?? "").toLowerCase();
|
|
@@ -10891,7 +11266,10 @@ function buildBrainCommand(opts) {
|
|
|
10891
11266
|
opts.renderer.writeWarning(msg3);
|
|
10892
11267
|
return { message: msg3 };
|
|
10893
11268
|
}
|
|
10894
|
-
return applyPatch(
|
|
11269
|
+
return applyPatch(
|
|
11270
|
+
{ council: { minRisk: level } },
|
|
11271
|
+
(s) => `Brain council risk floor set to ${color14.cyan(s.council.minRisk)} \u2014 questions at/above it convene the council`
|
|
11272
|
+
);
|
|
10895
11273
|
}
|
|
10896
11274
|
if (op === "voters") {
|
|
10897
11275
|
const seats = rest.slice(1).map(parseSeat);
|
|
@@ -10900,7 +11278,10 @@ function buildBrainCommand(opts) {
|
|
|
10900
11278
|
opts.renderer.writeWarning(msg3);
|
|
10901
11279
|
return { message: msg3 };
|
|
10902
11280
|
}
|
|
10903
|
-
return applyPatch(
|
|
11281
|
+
return applyPatch(
|
|
11282
|
+
{ council: { voters: seats } },
|
|
11283
|
+
councilSummary
|
|
11284
|
+
);
|
|
10904
11285
|
}
|
|
10905
11286
|
if (op === "personas") {
|
|
10906
11287
|
const lines = [
|
|
@@ -10921,7 +11302,10 @@ function buildBrainCommand(opts) {
|
|
|
10921
11302
|
opts.renderer.writeWarning(msg3);
|
|
10922
11303
|
return { message: msg3 };
|
|
10923
11304
|
}
|
|
10924
|
-
return applyPatch(
|
|
11305
|
+
return applyPatch(
|
|
11306
|
+
{ council: { judge: ref.toLowerCase() === "auto" ? null : ref } },
|
|
11307
|
+
(s) => `Brain council judge: ${color14.cyan(s.council.judge ? compactEntry(s.council.judge) : "auto")}${s.council.judge ? "" : color14.dim(judgeSummary(s).replace(/^, judge: /, " \u2192 "))}`
|
|
11308
|
+
);
|
|
10925
11309
|
}
|
|
10926
11310
|
if (op === "quorum" || op === "approval") {
|
|
10927
11311
|
const value = Number(rest[1]);
|
|
@@ -10956,7 +11340,7 @@ function buildBrainCommand(opts) {
|
|
|
10956
11340
|
return `Brain council ${op} set to ${color14.cyan(applied === void 0 ? "default" : String(applied))}`;
|
|
10957
11341
|
});
|
|
10958
11342
|
}
|
|
10959
|
-
const msg2 = `Unknown council subcommand: ${op}. Use on, off, minrisk, voters, personas, judge, quorum, approval, distinctness, timeout, concurrency, or judgetokens.`;
|
|
11343
|
+
const msg2 = `Unknown council subcommand: ${op}. Use on, off, minrisk, voters, personas, judge, quorum, approval, distinctness, timeout, concurrency, votertokens, or judgetokens.`;
|
|
10960
11344
|
opts.renderer.writeWarning(msg2);
|
|
10961
11345
|
return { message: msg2 };
|
|
10962
11346
|
}
|
|
@@ -11077,7 +11461,9 @@ ${color14.dim(decision.rationale)}` : ""}`;
|
|
|
11077
11461
|
lines.push(` decision timeout: ${color14.cyan(`${snapshot.decisionTimeoutMs}ms`)}`);
|
|
11078
11462
|
}
|
|
11079
11463
|
if (snapshot?.humanTimeoutMs) {
|
|
11080
|
-
lines.push(
|
|
11464
|
+
lines.push(
|
|
11465
|
+
` human timeout: ${color14.cyan(`${snapshot.humanTimeoutMs}ms`)} ${color14.dim("(then terminal policy)")}`
|
|
11466
|
+
);
|
|
11081
11467
|
}
|
|
11082
11468
|
const councilSeats = opts.brainSettings?.councilLabels ?? [];
|
|
11083
11469
|
if (councilSeats.length > 0) {
|
|
@@ -11296,7 +11682,9 @@ ${color14.dim(decision.rationale)}` : ""}`;
|
|
|
11296
11682
|
` enabled ${snapshot.trace.enabled ? color14.cyan("yes") : color14.dim("no")}`,
|
|
11297
11683
|
` content ${color14.cyan(snapshot.trace.content)}`,
|
|
11298
11684
|
snapshot.trace.path ? ` path ${color14.dim(snapshot.trace.path)}` : "",
|
|
11299
|
-
color14.dim(
|
|
11685
|
+
color14.dim(
|
|
11686
|
+
" Records tiers, every pool target (incl. failures), council votes and tokens."
|
|
11687
|
+
)
|
|
11300
11688
|
].filter(Boolean).join("\n");
|
|
11301
11689
|
opts.renderer.write(msg2);
|
|
11302
11690
|
return { message: msg2 };
|
|
@@ -11388,7 +11776,9 @@ Usage: /brain escalation <conservative|deny-all|continue-on-recommended>`;
|
|
|
11388
11776
|
` enabled ${m.enabled === false ? color14.dim("no") : color14.cyan("yes")}`,
|
|
11389
11777
|
` policy ${color14.cyan(m.policy ?? "llm")}`,
|
|
11390
11778
|
color14.dim(" Signals: tool-failure streak, error storm, agent stall, file churn."),
|
|
11391
|
-
color14.dim(
|
|
11779
|
+
color14.dim(
|
|
11780
|
+
" Changes apply live; a change restarts the watchers, resetting signal counters."
|
|
11781
|
+
)
|
|
11392
11782
|
].join("\n");
|
|
11393
11783
|
opts.renderer.write(msg2);
|
|
11394
11784
|
return { message: msg2 };
|
|
@@ -11426,7 +11816,10 @@ Usage: /brain escalation <conservative|deny-all|continue-on-recommended>`;
|
|
|
11426
11816
|
}
|
|
11427
11817
|
const snapshot = opts.brainRuntime?.getSnapshot();
|
|
11428
11818
|
if (snapshot?.cache.enabled) {
|
|
11429
|
-
lines.push(
|
|
11819
|
+
lines.push(
|
|
11820
|
+
"",
|
|
11821
|
+
color14.dim(` cache: ${snapshot.cache.hits} hit / ${snapshot.cache.misses} miss`)
|
|
11822
|
+
);
|
|
11430
11823
|
}
|
|
11431
11824
|
if (snapshot?.circuit && snapshot.circuit.state !== "closed") {
|
|
11432
11825
|
lines.push(color14.dim(` circuit: ${snapshot.circuit.state}`));
|
|
@@ -11437,7 +11830,10 @@ Usage: /brain escalation <conservative|deny-all|continue-on-recommended>`;
|
|
|
11437
11830
|
lines.push(color14.dim(` ${fmtAge(w.at).padEnd(8)} ${w.outcome}`));
|
|
11438
11831
|
}
|
|
11439
11832
|
}
|
|
11440
|
-
lines.push(
|
|
11833
|
+
lines.push(
|
|
11834
|
+
"",
|
|
11835
|
+
color14.dim(` Based on the last ${log.length} logged decision(s) of this session.`)
|
|
11836
|
+
);
|
|
11441
11837
|
const msg2 = lines.join("\n");
|
|
11442
11838
|
opts.renderer.write(msg2);
|
|
11443
11839
|
return { message: msg2 };
|
|
@@ -11574,6 +11970,7 @@ function buildClearCommand(opts) {
|
|
|
11574
11970
|
ctx.contextEvidence = createContextEvidenceState();
|
|
11575
11971
|
ctx.toolAdjacencyDirty = false;
|
|
11576
11972
|
ctx.pendingPostToolContext = void 0;
|
|
11973
|
+
ctx.clearMemoryEvidence?.();
|
|
11577
11974
|
ctx.lastRequestTokens = void 0;
|
|
11578
11975
|
ctx.lastRealInputTokens = void 0;
|
|
11579
11976
|
for (const key of Object.keys(ctx.meta)) ctx.state.deleteMeta(key);
|
|
@@ -11861,8 +12258,17 @@ function buildCompactCommand(opts) {
|
|
|
11861
12258
|
|
|
11862
12259
|
// src/slash-commands/context.ts
|
|
11863
12260
|
import * as fs7 from "node:fs/promises";
|
|
11864
|
-
import {
|
|
11865
|
-
|
|
12261
|
+
import {
|
|
12262
|
+
formatContextWindowModeList,
|
|
12263
|
+
getContextWindowMode,
|
|
12264
|
+
resolveContextWindowPolicy as resolveContextWindowPolicy2
|
|
12265
|
+
} from "@wrongstack/core/types";
|
|
12266
|
+
import {
|
|
12267
|
+
atomicWrite as atomicWrite3,
|
|
12268
|
+
color as color18,
|
|
12269
|
+
getContextBreakdown,
|
|
12270
|
+
repairToolUseAdjacency
|
|
12271
|
+
} from "@wrongstack/core/utils";
|
|
11866
12272
|
function buildContextCommand(opts) {
|
|
11867
12273
|
return {
|
|
11868
12274
|
name: "context",
|
|
@@ -12095,6 +12501,7 @@ function cacheMechanismLabel(providerId, cacheControl) {
|
|
|
12095
12501
|
if (id.includes("google") || id.includes("gemini")) {
|
|
12096
12502
|
return "implicit (auto) + explicit cachedContents (opt-in)";
|
|
12097
12503
|
}
|
|
12504
|
+
if (id.includes("gateway")) return "automatic (Gateway-managed, per routed upstream)";
|
|
12098
12505
|
if (cacheControl === "auto") return "automatic + prompt_cache_key routing";
|
|
12099
12506
|
return "none / provider-managed";
|
|
12100
12507
|
}
|
|
@@ -12133,7 +12540,14 @@ function safeBreakdown(ctx) {
|
|
|
12133
12540
|
return getContextBreakdown(ctx);
|
|
12134
12541
|
} catch (err) {
|
|
12135
12542
|
if (process.env["DEBUG_WS"]) {
|
|
12136
|
-
console.warn(
|
|
12543
|
+
console.warn(
|
|
12544
|
+
JSON.stringify({
|
|
12545
|
+
level: "warn",
|
|
12546
|
+
event: "context.breakdown_failed",
|
|
12547
|
+
message: String(err),
|
|
12548
|
+
timestamp: Date.now()
|
|
12549
|
+
})
|
|
12550
|
+
);
|
|
12137
12551
|
}
|
|
12138
12552
|
return null;
|
|
12139
12553
|
}
|
|
@@ -12161,7 +12575,7 @@ function renderBreakdown(bd, detailed) {
|
|
|
12161
12575
|
`${color18.bold("Breakdown")} (${headerSuffix})`,
|
|
12162
12576
|
` system: ${K(bd.system.total)} (${PCT(bd.system.total, limit)})`,
|
|
12163
12577
|
` tools: ${K(bd.tools.total)} (${PCT(bd.tools.total, limit)}) \xB7 builtin ${K(bd.tools.builtin)}, mcp ${K(bd.tools.mcp)} across ${bd.tools.count} defs`,
|
|
12164
|
-
` history: ${K(bd.history.total)} (${PCT(bd.history.total, limit)}) \xB7 text ${K(bd.history.text)}, tool results ${K(bd.history.toolResults)}`,
|
|
12578
|
+
` history: ${K(bd.history.total)} (${PCT(bd.history.total, limit)}) \xB7 text ${K(bd.history.text)}, tool inputs ${K(bd.history.toolInputs ?? 0)}, results ${K(bd.history.toolResults)}, thinking ${K(bd.history.thinking ?? 0)}`,
|
|
12165
12579
|
` volatile: ${K(bd.volatile.total)} (${PCT(bd.volatile.total, limit)}) \xB7 ledger ${K(bd.volatile.ledger)}, nextsteps ${K(bd.volatile.nextsteps)}`,
|
|
12166
12580
|
` ${color18.bold("total")}: ${K(bd.total)}${overBy > 0 ? "" : ` (${PCT(bd.total, limit)})`}`
|
|
12167
12581
|
];
|
|
@@ -12174,7 +12588,9 @@ function renderBreakdown(bd, detailed) {
|
|
|
12174
12588
|
if (sources.length > 0) {
|
|
12175
12589
|
const top = detailed ? sources : sources.slice(0, 3);
|
|
12176
12590
|
out.push(
|
|
12177
|
-
` ${color18.dim("heaviest static:")} ${top.map(
|
|
12591
|
+
` ${color18.dim("heaviest static:")} ${top.map(
|
|
12592
|
+
([src, tokens]) => `${SOURCE_LABELS[src] ?? src} ${K(tokens)}`
|
|
12593
|
+
).join(", ")}`
|
|
12178
12594
|
);
|
|
12179
12595
|
if (detailed && bd.tools.total > 0 && (bd.system.bySource["tool-usage"] ?? 0) > 0) {
|
|
12180
12596
|
out.push(
|
|
@@ -13097,6 +13513,58 @@ function diagnoseConfig(cfg, plugins = []) {
|
|
|
13097
13513
|
}
|
|
13098
13514
|
}
|
|
13099
13515
|
}
|
|
13516
|
+
if ("fleet" in fixed) {
|
|
13517
|
+
if (!isPlainObject(fixed["fleet"])) {
|
|
13518
|
+
findings.push({
|
|
13519
|
+
path: "fleet",
|
|
13520
|
+
problem: `expected object, got ${JSON.stringify(fixed["fleet"])}`,
|
|
13521
|
+
severity: "error",
|
|
13522
|
+
fix: "removed (built-in defaults apply)"
|
|
13523
|
+
});
|
|
13524
|
+
delete fixed["fleet"];
|
|
13525
|
+
} else {
|
|
13526
|
+
const fleet = fixed["fleet"];
|
|
13527
|
+
if ("budget" in fleet) {
|
|
13528
|
+
if (!isPlainObject(fleet["budget"])) {
|
|
13529
|
+
findings.push({
|
|
13530
|
+
path: "fleet.budget",
|
|
13531
|
+
problem: `expected object, got ${JSON.stringify(fleet["budget"])}`,
|
|
13532
|
+
severity: "error",
|
|
13533
|
+
fix: "removed (built-in defaults apply)"
|
|
13534
|
+
});
|
|
13535
|
+
delete fleet["budget"];
|
|
13536
|
+
} else {
|
|
13537
|
+
const budget = fleet["budget"];
|
|
13538
|
+
for (const key of ["maxSpawns", "maxTokens", "maxCostUsd"]) {
|
|
13539
|
+
if (!(key in budget)) continue;
|
|
13540
|
+
const v = budget[key];
|
|
13541
|
+
const n = coerceNumber(v);
|
|
13542
|
+
if (n === void 0) {
|
|
13543
|
+
delete budget[key];
|
|
13544
|
+
findings.push({
|
|
13545
|
+
path: `fleet.budget.${key}`,
|
|
13546
|
+
problem: `expected a non-negative number, got ${JSON.stringify(v)}`,
|
|
13547
|
+
severity: "error",
|
|
13548
|
+
fix: "removed (built-in default applies)"
|
|
13549
|
+
});
|
|
13550
|
+
} else {
|
|
13551
|
+
const clamped = Math.max(0, n);
|
|
13552
|
+
const next = key === "maxCostUsd" ? clamped : Math.floor(clamped);
|
|
13553
|
+
if (next !== v) {
|
|
13554
|
+
budget[key] = next;
|
|
13555
|
+
findings.push({
|
|
13556
|
+
path: `fleet.budget.${key}`,
|
|
13557
|
+
problem: `expected a non-negative ${key === "maxCostUsd" ? "number" : "integer"}, got ${JSON.stringify(v)}`,
|
|
13558
|
+
severity: "error",
|
|
13559
|
+
fix: `set to ${next}`
|
|
13560
|
+
});
|
|
13561
|
+
}
|
|
13562
|
+
}
|
|
13563
|
+
}
|
|
13564
|
+
}
|
|
13565
|
+
}
|
|
13566
|
+
}
|
|
13567
|
+
}
|
|
13100
13568
|
for (const key of ["provider", "model"]) {
|
|
13101
13569
|
if (key in fixed && typeof fixed[key] !== "string") {
|
|
13102
13570
|
findings.push({
|
|
@@ -13380,7 +13848,7 @@ function buildDoctorCommand(opts) {
|
|
|
13380
13848
|
].join("\n");
|
|
13381
13849
|
async function loadPluginSchemas() {
|
|
13382
13850
|
try {
|
|
13383
|
-
const { BUILTIN_PLUGIN_FACTORIES } = await import("./plugins-
|
|
13851
|
+
const { BUILTIN_PLUGIN_FACTORIES } = await import("./plugins-K3BAUP4D.js");
|
|
13384
13852
|
const settled = await Promise.allSettled(BUILTIN_PLUGIN_FACTORIES.map((f) => f()));
|
|
13385
13853
|
const loaded = [];
|
|
13386
13854
|
for (const s of settled) {
|
|
@@ -15297,6 +15765,17 @@ async function handleStatus(opts, cmd) {
|
|
|
15297
15765
|
lines.push(` ${id} ${name} ${statusColor} ${ext}${task}`);
|
|
15298
15766
|
}
|
|
15299
15767
|
}
|
|
15768
|
+
const budget = opts.onFleetBudget?.();
|
|
15769
|
+
if (budget) {
|
|
15770
|
+
lines.push(
|
|
15771
|
+
"",
|
|
15772
|
+
...formatFleetBudgetLines(budget, {
|
|
15773
|
+
bold: color26.bold,
|
|
15774
|
+
dim: color26.dim,
|
|
15775
|
+
amber: color26.amber
|
|
15776
|
+
})
|
|
15777
|
+
);
|
|
15778
|
+
}
|
|
15300
15779
|
const msg2 = lines.join("\n");
|
|
15301
15780
|
opts.renderer.write(msg2);
|
|
15302
15781
|
return { message: msg2 };
|
|
@@ -20462,6 +20941,7 @@ ${targetMode.description}`
|
|
|
20462
20941
|
|
|
20463
20942
|
// src/slash-commands/modelcaps.ts
|
|
20464
20943
|
import * as fs14 from "node:fs/promises";
|
|
20944
|
+
import { hasProviderCredential } from "@wrongstack/core/models";
|
|
20465
20945
|
import { color as color36 } from "@wrongstack/core/utils";
|
|
20466
20946
|
function fmtTokens(n) {
|
|
20467
20947
|
if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
|
|
@@ -20569,13 +21049,7 @@ function buildModelCapsCommand(opts) {
|
|
|
20569
21049
|
}
|
|
20570
21050
|
const config = opts.configStore.get();
|
|
20571
21051
|
const configProviders = config?.providers ?? {};
|
|
20572
|
-
|
|
20573
|
-
const pc = configProviders[providerId];
|
|
20574
|
-
if (!pc) return false;
|
|
20575
|
-
if (typeof pc.apiKey === "string" && pc.apiKey.length > 0) return true;
|
|
20576
|
-
if (Array.isArray(pc.apiKeys) && pc.apiKeys.some((k) => k?.apiKey)) return true;
|
|
20577
|
-
return false;
|
|
20578
|
-
}
|
|
21052
|
+
const hasKey = (provider) => hasProviderCredential(provider, { providers: configProviders });
|
|
20579
21053
|
const lines = [
|
|
20580
21054
|
`${color36.bold("Available Models")} ${color36.dim("\u2014 capacities + pricing")}`,
|
|
20581
21055
|
""
|
|
@@ -20585,7 +21059,7 @@ function buildModelCapsCommand(opts) {
|
|
|
20585
21059
|
if (trimmed && !trimmed.includes("/") && !prov.id.toLowerCase().includes(trimmed) && !prov.name.toLowerCase().includes(trimmed)) {
|
|
20586
21060
|
continue;
|
|
20587
21061
|
}
|
|
20588
|
-
const keyed = hasKey(prov
|
|
21062
|
+
const keyed = hasKey(prov);
|
|
20589
21063
|
const marker = keyed ? color36.green("\u25CF") : color36.dim("\u25CB");
|
|
20590
21064
|
lines.push(` ${marker} ${color36.bold(prov.id.padEnd(16))} ${color36.dim(`(${prov.name})`)}`);
|
|
20591
21065
|
const models = prov.models ?? [];
|
|
@@ -23502,6 +23976,26 @@ import { fallbackProfileChain } from "@wrongstack/core/agent";
|
|
|
23502
23976
|
import { decryptConfigSecrets as decryptConfigSecrets4, encryptConfigSecrets as encryptConfigSecrets4, noOpVault as noOpVault6 } from "@wrongstack/core/security";
|
|
23503
23977
|
import { MATRIX_PHASE_KEYS, matrixKeyKind, phaseForRole, resolveModelMatrix, resolveModelTargetFromEntry } from "@wrongstack/core/coordination";
|
|
23504
23978
|
import { parseModelRef as parseModelRef3 } from "@wrongstack/core/agent";
|
|
23979
|
+
import { catalogProviderIdFor } from "@wrongstack/providers";
|
|
23980
|
+
async function resolveCatalogModelIds(registry, config, providerIds) {
|
|
23981
|
+
const out = /* @__PURE__ */ new Map();
|
|
23982
|
+
if (!registry) return out;
|
|
23983
|
+
await Promise.all(
|
|
23984
|
+
providerIds.map(async (id) => {
|
|
23985
|
+
try {
|
|
23986
|
+
const catalogId = catalogProviderIdFor(id, config.providers?.[id]?.type);
|
|
23987
|
+
const provider = await registry.getProvider(catalogId);
|
|
23988
|
+
if (provider) out.set(id, provider.models.map((m) => m.id));
|
|
23989
|
+
} catch {
|
|
23990
|
+
}
|
|
23991
|
+
})
|
|
23992
|
+
);
|
|
23993
|
+
return out;
|
|
23994
|
+
}
|
|
23995
|
+
function summarizeModelIds(ids, limit = 8) {
|
|
23996
|
+
if (ids.length <= limit) return ids.join(", ");
|
|
23997
|
+
return `${ids.slice(0, limit).join(", ")} ${color44.dim(`\u2026 +${ids.length - limit} more`)}`;
|
|
23998
|
+
}
|
|
23505
23999
|
function providerHasKey(entry) {
|
|
23506
24000
|
if (!entry) return false;
|
|
23507
24001
|
if (typeof entry.apiKey === "string" && entry.apiKey.length > 0) return true;
|
|
@@ -23703,9 +24197,10 @@ function buildSetModelCommand(opts) {
|
|
|
23703
24197
|
);
|
|
23704
24198
|
const matrix = config.modelMatrix ?? {};
|
|
23705
24199
|
if (sub === "list") {
|
|
24200
|
+
const catalogModels = await resolveCatalogModelIds(opts.modelsRegistry, config, keyed);
|
|
23706
24201
|
const provLines = keyed.map((id) => {
|
|
23707
|
-
const models = config.
|
|
23708
|
-
const ms = models.length ? models
|
|
24202
|
+
const models = visibleModelIds(id, config, catalogModels.get(id) ?? []);
|
|
24203
|
+
const ms = models.length ? summarizeModelIds(models) : color44.dim("(any model id accepted)");
|
|
23709
24204
|
return ` ${color44.cyan(id.padEnd(16))} ${ms}`;
|
|
23710
24205
|
});
|
|
23711
24206
|
const roles = Object.keys(AGENT_CATALOG2).sort();
|
|
@@ -23781,6 +24276,11 @@ function buildSetModelCommand(opts) {
|
|
|
23781
24276
|
if (sub === "doctor") {
|
|
23782
24277
|
const issues = [];
|
|
23783
24278
|
const warnings = [];
|
|
24279
|
+
const doctorCatalogModels = await resolveCatalogModelIds(
|
|
24280
|
+
opts.modelsRegistry,
|
|
24281
|
+
config,
|
|
24282
|
+
keyed
|
|
24283
|
+
);
|
|
23784
24284
|
for (const [key, entry] of Object.entries(matrix)) {
|
|
23785
24285
|
const kind = matrixKeyKind(key);
|
|
23786
24286
|
if (kind === "unknown") {
|
|
@@ -23803,9 +24303,14 @@ function buildSetModelCommand(opts) {
|
|
|
23803
24303
|
const effectiveProvider = entry.provider ?? config.provider;
|
|
23804
24304
|
const provCfg = config.providers?.[effectiveProvider];
|
|
23805
24305
|
if (entry.model && provCfg?.models && provCfg.models.length > 0) {
|
|
23806
|
-
|
|
24306
|
+
const reachable = visibleModelIds(
|
|
24307
|
+
effectiveProvider,
|
|
24308
|
+
config,
|
|
24309
|
+
doctorCatalogModels.get(effectiveProvider) ?? []
|
|
24310
|
+
);
|
|
24311
|
+
if (!reachable.includes(entry.model)) {
|
|
23807
24312
|
warnings.push(
|
|
23808
|
-
`${color44.amber("\u26A0")} ${color44.amber(key)}: model "${entry.model}" not in ${effectiveProvider}'s model list (${
|
|
24313
|
+
`${color44.amber("\u26A0")} ${color44.amber(key)}: model "${entry.model}" not in ${effectiveProvider}'s model list (${summarizeModelIds(reachable)})`
|
|
23809
24314
|
);
|
|
23810
24315
|
}
|
|
23811
24316
|
}
|
|
@@ -25070,8 +25575,13 @@ async function switchProjectCommand(opts, ctx, target, displayName) {
|
|
|
25070
25575
|
const child = spawn7(nodeExe, [cliPath, "--no-interactive"], {
|
|
25071
25576
|
cwd: resolved,
|
|
25072
25577
|
stdio: "inherit",
|
|
25073
|
-
detached: false
|
|
25074
|
-
signal:
|
|
25578
|
+
detached: false
|
|
25579
|
+
// NO abort signal: this child is a long-lived INTERACTIVE session that
|
|
25580
|
+
// is meant to outlive the spawn call. The 30 s timeout fired 30 seconds
|
|
25581
|
+
// after "Switched to <project> … (current session stays open)" and
|
|
25582
|
+
// SIGTERM'd the new session mid-typing, with no message. Sibling
|
|
25583
|
+
// long-lived spawns pass no signal (slash-commands/mailbox-serve.ts:98),
|
|
25584
|
+
// and boot/tui-project-spawn.ts documents this exact bug being removed.
|
|
25075
25585
|
});
|
|
25076
25586
|
child.on("error", (err) => {
|
|
25077
25587
|
console.error(color47.red(`Failed to spawn wstack: ${err.message}`));
|
|
@@ -25207,8 +25717,13 @@ async function spawnInProject(opts, _ctx, root, projectName) {
|
|
|
25207
25717
|
const child = spawn7(nodeExe, [cliPath, "--no-interactive"], {
|
|
25208
25718
|
cwd: root,
|
|
25209
25719
|
stdio: "inherit",
|
|
25210
|
-
detached: false
|
|
25211
|
-
signal:
|
|
25720
|
+
detached: false
|
|
25721
|
+
// NO abort signal: this child is a long-lived INTERACTIVE session that
|
|
25722
|
+
// is meant to outlive the spawn call. The 30 s timeout fired 30 seconds
|
|
25723
|
+
// after "Switched to <project> … (current session stays open)" and
|
|
25724
|
+
// SIGTERM'd the new session mid-typing, with no message. Sibling
|
|
25725
|
+
// long-lived spawns pass no signal (slash-commands/mailbox-serve.ts:98),
|
|
25726
|
+
// and boot/tui-project-spawn.ts documents this exact bug being removed.
|
|
25212
25727
|
});
|
|
25213
25728
|
child.on("error", (err) => {
|
|
25214
25729
|
console.error(color47.red(`Failed to spawn wstack: ${err.message}`));
|
|
@@ -25244,8 +25759,13 @@ async function handleNewSession(_opts, _ctx) {
|
|
|
25244
25759
|
const child = spawn7(nodeExe, [cliPath, "--no-interactive"], {
|
|
25245
25760
|
cwd: process.cwd(),
|
|
25246
25761
|
stdio: "inherit",
|
|
25247
|
-
detached: false
|
|
25248
|
-
signal:
|
|
25762
|
+
detached: false
|
|
25763
|
+
// NO abort signal: this child is a long-lived INTERACTIVE session that
|
|
25764
|
+
// is meant to outlive the spawn call. The 30 s timeout fired 30 seconds
|
|
25765
|
+
// after "Switched to <project> … (current session stays open)" and
|
|
25766
|
+
// SIGTERM'd the new session mid-typing, with no message. Sibling
|
|
25767
|
+
// long-lived spawns pass no signal (slash-commands/mailbox-serve.ts:98),
|
|
25768
|
+
// and boot/tui-project-spawn.ts documents this exact bug being removed.
|
|
25249
25769
|
});
|
|
25250
25770
|
child.on("error", (err) => {
|
|
25251
25771
|
console.error(color47.red(`Failed to spawn wstack: ${err.message}`));
|
|
@@ -25292,6 +25812,7 @@ async function handlePrevSessions(opts, _ctx) {
|
|
|
25292
25812
|
import { spawn as spawn8 } from "node:child_process";
|
|
25293
25813
|
import * as fsp3 from "node:fs/promises";
|
|
25294
25814
|
import * as path27 from "node:path";
|
|
25815
|
+
import { emitReviewIfChanged } from "@wrongstack/core/plugin";
|
|
25295
25816
|
async function runGit2(args, cwd) {
|
|
25296
25817
|
return new Promise((resolve8) => {
|
|
25297
25818
|
const child = spawn8("git", args, {
|
|
@@ -25385,16 +25906,29 @@ function buildReviewCommand(opts) {
|
|
|
25385
25906
|
enabled: true,
|
|
25386
25907
|
provider: ctx.provider.id,
|
|
25387
25908
|
model: ctx.model,
|
|
25388
|
-
maxFiles: limit
|
|
25909
|
+
maxFiles: limit,
|
|
25910
|
+
autoFix: "off",
|
|
25911
|
+
cascadeOn: "off",
|
|
25912
|
+
maxCascadeDepth: 0
|
|
25389
25913
|
},
|
|
25390
25914
|
cwd,
|
|
25391
25915
|
files: filesWithContent
|
|
25392
25916
|
};
|
|
25393
|
-
|
|
25917
|
+
const emitted = await emitReviewIfChanged(
|
|
25918
|
+
{ events: opts.events, emitCustom: opts.events.emitCustom.bind(opts.events) },
|
|
25919
|
+
payload
|
|
25920
|
+
);
|
|
25921
|
+
if (!emitted) {
|
|
25922
|
+
return {
|
|
25923
|
+
message: "\u{1F982} Chimera review skipped \u2014 this file content already has a review in progress."
|
|
25924
|
+
};
|
|
25925
|
+
}
|
|
25926
|
+
const skipped = filesWithContent.length - emitted.files.length;
|
|
25394
25927
|
const note = truncated ? `
|
|
25395
25928
|
${existing.length - limit} more changed file(s) were not included \u2014 raise the cap with /review --limit ${existing.length}.` : "";
|
|
25929
|
+
const skippedNote = skipped > 0 ? ` ${skipped} file(s) already under review were skipped.` : "";
|
|
25396
25930
|
return {
|
|
25397
|
-
message: `\u{1F982} Chimera review triggered for ${
|
|
25931
|
+
message: `\u{1F982} Chimera review triggered for ${emitted.files.length} file(s).${skippedNote}
|
|
25398
25932
|
The review report will appear in chat history shortly.${note}`
|
|
25399
25933
|
};
|
|
25400
25934
|
}
|
|
@@ -25516,6 +26050,7 @@ function buildSettingsCommand(opts) {
|
|
|
25516
26050
|
" /settings context-strategy hybrid|intelligent|selective Compactor strategy",
|
|
25517
26051
|
" /settings context-auto-compact on|off Auto-compact context when thresholds crossed",
|
|
25518
26052
|
" /settings token-saving off|minimal|light|medium|aggressive Token-saving mode",
|
|
26053
|
+
" /settings nextsteps-tool on|off Give the leader a `nextsteps` tool alongside the <nextsteps> block (next session)",
|
|
25519
26054
|
" /settings mcp on|off Load MCP servers declared in config",
|
|
25520
26055
|
" /settings plugins on|off Load npm plugins declared in config",
|
|
25521
26056
|
" /settings memory on|off Register remember/forget tools",
|
|
@@ -25565,6 +26100,7 @@ function buildSettingsCommand(opts) {
|
|
|
25565
26100
|
const contextAutoCompact = context?.autoCompact !== false;
|
|
25566
26101
|
const features = opts.configStore.get().features;
|
|
25567
26102
|
const tokenSavingTier = features?.tokenSavingMode ?? "off";
|
|
26103
|
+
const nextStepsToolEnabled = opts.configStore.get().tools?.nextsteps?.enabled === true;
|
|
25568
26104
|
const maxConcurrent = opts.configStore.get().maxConcurrent ?? 4;
|
|
25569
26105
|
const titleAnimation = autonomy?.terminalTitleAnimation !== false;
|
|
25570
26106
|
const modelRuntime = opts.configStore.get().modelRuntime;
|
|
@@ -25607,6 +26143,7 @@ function buildSettingsCommand(opts) {
|
|
|
25607
26143
|
` context strategy: ${color48.cyan(contextStrategy)} ${color48.dim("change: /settings context-strategy hybrid|intelligent|selective")}`,
|
|
25608
26144
|
` context auto-compact: ${contextAutoCompact ? color48.cyan("on") : color48.dim("off")} ${color48.dim("change: /settings context-auto-compact on|off")}`,
|
|
25609
26145
|
` token-saving: ${color48.cyan(tokenSavingTier)} ${color48.dim("change: /settings token-saving off|minimal|light|medium|aggressive")}`,
|
|
26146
|
+
` nextsteps tool: ${nextStepsToolEnabled ? color48.cyan("on") : color48.dim("off")} ${color48.dim("change: /settings nextsteps-tool on|off")}`,
|
|
25610
26147
|
` MCP features: ${feats?.mcp !== false ? color48.cyan("on") : color48.dim("off")} ${color48.dim("change: /settings mcp on|off")}`,
|
|
25611
26148
|
` plugin features: ${feats?.plugins !== false ? color48.cyan("on") : color48.dim("off")} ${color48.dim("change: /settings plugins on|off")}`,
|
|
25612
26149
|
` memory features: ${feats?.memory !== false ? color48.cyan("on") : color48.dim("off")} ${color48.dim("change: /settings memory on|off")}`,
|
|
@@ -26036,6 +26573,21 @@ function buildSettingsCommand(opts) {
|
|
|
26036
26573
|
message: `${color48.green("\u2713")} context auto-compact \u2192 ${on ? color48.cyan("on") : color48.dim("off")} ${color48.dim("auto-compact context when thresholds crossed")}`
|
|
26037
26574
|
};
|
|
26038
26575
|
}
|
|
26576
|
+
if (sub === "nextsteps-tool") {
|
|
26577
|
+
const raw = (rest[0] ?? "").toLowerCase();
|
|
26578
|
+
if (!["on", "off"].includes(raw)) {
|
|
26579
|
+
return { message: `${color48.amber("Usage:")} /settings nextsteps-tool on|off` };
|
|
26580
|
+
}
|
|
26581
|
+
const on = raw === "on";
|
|
26582
|
+
await persistConfigSetting(persistDeps, (cfg) => {
|
|
26583
|
+
const tools = cfg.tools ?? {};
|
|
26584
|
+
tools.nextsteps = { enabled: on };
|
|
26585
|
+
cfg.tools = tools;
|
|
26586
|
+
});
|
|
26587
|
+
return {
|
|
26588
|
+
message: `${color48.green("\u2713")} nextsteps tool \u2192 ${on ? color48.cyan("on") : color48.dim("off")} ${color48.dim("takes effect in the next session")}`
|
|
26589
|
+
};
|
|
26590
|
+
}
|
|
26039
26591
|
if (sub === "token-saving") {
|
|
26040
26592
|
const raw = (rest[0] ?? "").toLowerCase();
|
|
26041
26593
|
const tiers = ["off", "minimal", "light", "medium", "aggressive"];
|
|
@@ -29846,11 +30398,13 @@ async function runInteractive(cliCtx) {
|
|
|
29846
30398
|
wpaths
|
|
29847
30399
|
});
|
|
29848
30400
|
const stdinInteractive = process.stdin.isTTY;
|
|
30401
|
+
const hookRunnerRef = { current: null };
|
|
29849
30402
|
registerCliManagementTools({
|
|
29850
30403
|
toolRegistry,
|
|
29851
30404
|
configStore,
|
|
29852
30405
|
profileConfigPath,
|
|
29853
|
-
stdinInteractive
|
|
30406
|
+
stdinInteractive,
|
|
30407
|
+
getHookRunner: () => hookRunnerRef.current
|
|
29854
30408
|
});
|
|
29855
30409
|
const { metricsSink, healthRegistry, metricsStatus } = (() => {
|
|
29856
30410
|
const ms = setupMetrics({
|
|
@@ -29884,7 +30438,8 @@ async function runInteractive(cliCtx) {
|
|
|
29884
30438
|
const systemPrompt = await promptBuilder.build({
|
|
29885
30439
|
cwd,
|
|
29886
30440
|
projectRoot,
|
|
29887
|
-
tools: toolRegistry.
|
|
30441
|
+
tools: toolRegistry.listForProvider(),
|
|
30442
|
+
catalogTools: toolRegistry.list(),
|
|
29888
30443
|
provider: config.provider,
|
|
29889
30444
|
model: config.model,
|
|
29890
30445
|
onlineAgents
|
|
@@ -29998,7 +30553,8 @@ async function runInteractive(cliCtx) {
|
|
|
29998
30553
|
slashRegistry,
|
|
29999
30554
|
hqPublisherRef,
|
|
30000
30555
|
brainMailbox,
|
|
30001
|
-
pluginHost
|
|
30556
|
+
pluginHost,
|
|
30557
|
+
hookRunner
|
|
30002
30558
|
} = await setupLifecycleAndPlugins({
|
|
30003
30559
|
flags,
|
|
30004
30560
|
config,
|
|
@@ -30035,6 +30591,7 @@ async function runInteractive(cliCtx) {
|
|
|
30035
30591
|
logger,
|
|
30036
30592
|
teardownHandlers
|
|
30037
30593
|
});
|
|
30594
|
+
hookRunnerRef.current = hookRunner;
|
|
30038
30595
|
const fallbackProfileManager = container.resolve(TOKENS9.FallbackProfileManager);
|
|
30039
30596
|
const statusTracker = await setupProviderStatus({
|
|
30040
30597
|
events,
|
|
@@ -30079,11 +30636,21 @@ async function runInteractive(cliCtx) {
|
|
|
30079
30636
|
getConfig: () => config,
|
|
30080
30637
|
fallbackProfileManager,
|
|
30081
30638
|
statusTracker,
|
|
30639
|
+
wrapProviderCall: (request, inner) => agent.extensions.wrapProviderRunner(
|
|
30640
|
+
(_ctx, wrappedRequest) => inner(wrappedRequest),
|
|
30641
|
+
// OneShotOrchestrator owns the selected provider and fallback chain.
|
|
30642
|
+
// The agent-loop fallback wrapper routes from and mutates agent.ctx,
|
|
30643
|
+
// which may describe a different provider/model than this utility call.
|
|
30644
|
+
{ exclude: ["fallback-model"] }
|
|
30645
|
+
)(agent.ctx, request),
|
|
30082
30646
|
compactor: container.resolve(TOKENS9.Compactor)
|
|
30083
30647
|
});
|
|
30084
30648
|
let {
|
|
30085
30649
|
director,
|
|
30086
30650
|
maxConcurrent,
|
|
30651
|
+
maxSpawns,
|
|
30652
|
+
maxConcurrentSource,
|
|
30653
|
+
maxSpawnsSource,
|
|
30087
30654
|
autonomyMode,
|
|
30088
30655
|
nextPredictEnabled,
|
|
30089
30656
|
currentSuggestions,
|
|
@@ -30136,6 +30703,9 @@ async function runInteractive(cliCtx) {
|
|
|
30136
30703
|
stateCheckpointPath,
|
|
30137
30704
|
fleetRootForPromotion,
|
|
30138
30705
|
maxConcurrent,
|
|
30706
|
+
maxSpawns,
|
|
30707
|
+
maxConcurrentSource,
|
|
30708
|
+
maxSpawnsSource,
|
|
30139
30709
|
effectiveMaxContextRef,
|
|
30140
30710
|
mcpRegistry,
|
|
30141
30711
|
sessResult,
|
|
@@ -30176,11 +30746,30 @@ async function runInteractive(cliCtx) {
|
|
|
30176
30746
|
for (const tool of director.tools(FLEET_ROSTER5)) {
|
|
30177
30747
|
toolRegistry.register(tool);
|
|
30178
30748
|
}
|
|
30179
|
-
|
|
30180
|
-
|
|
30181
|
-
|
|
30182
|
-
|
|
30183
|
-
|
|
30749
|
+
const browserSurface = flags.webui === true || flags.simpleui === true;
|
|
30750
|
+
if (browserSurface) {
|
|
30751
|
+
renderer.writeInfo(
|
|
30752
|
+
`Director mode enabled (${Object.keys(FLEET_ROSTER5).length} roles) \u2192 ${fleetRoot}`
|
|
30753
|
+
);
|
|
30754
|
+
} else {
|
|
30755
|
+
renderer.writeInfo(`Director mode enabled. Roster: ${Object.keys(FLEET_ROSTER5).join(", ")}`);
|
|
30756
|
+
renderer.writeInfo(` fleet root \u2192 ${fleetRoot}`);
|
|
30757
|
+
renderer.writeInfo(` manifest \u2192 ${manifestPath}`);
|
|
30758
|
+
renderer.writeInfo(` scratchpad \u2192 ${sharedScratchpadPath}`);
|
|
30759
|
+
renderer.writeInfo(` subagents \u2192 ${subagentSessionsRoot}`);
|
|
30760
|
+
}
|
|
30761
|
+
if (priorFleetState) {
|
|
30762
|
+
const budget = multiAgentHost.budgetView();
|
|
30763
|
+
const fmt = (n) => Number.isFinite(n) ? String(n) : "\u221E";
|
|
30764
|
+
renderer.writeInfo(
|
|
30765
|
+
` fleet budget \u2192 ${budget.usedSpawns}/${fmt(budget.maxSpawns)} spawns used (${fmt(budget.remainingSpawns)} remaining; maxConcurrent ${budget.maxConcurrent})`
|
|
30766
|
+
);
|
|
30767
|
+
if (budget.ceilingMismatch && budget.checkpointMaxSpawns !== void 0) {
|
|
30768
|
+
renderer.writeInfo(
|
|
30769
|
+
` \u26A0 checkpoint maxSpawns was ${budget.checkpointMaxSpawns}; live ceiling is ${fmt(budget.maxSpawns)}`
|
|
30770
|
+
);
|
|
30771
|
+
}
|
|
30772
|
+
}
|
|
30184
30773
|
} else {
|
|
30185
30774
|
renderer.writeInfo(`Running without Director \u2014 fleet orchestration tools disabled.`);
|
|
30186
30775
|
}
|
|
@@ -30374,7 +30963,25 @@ async function runInteractive(cliCtx) {
|
|
|
30374
30963
|
effectiveMaxContext: effectiveMaxContextRef.current,
|
|
30375
30964
|
configRef,
|
|
30376
30965
|
autonomyModeRef,
|
|
30377
|
-
logger
|
|
30966
|
+
logger,
|
|
30967
|
+
// WITHOUT this the helper primed an engine and dropped it: the only live
|
|
30968
|
+
// holder is the `eternalEngine` binding below, written solely by the slash
|
|
30969
|
+
// handler. `--eternal "<mission>"` therefore forced YOLO on and set the
|
|
30970
|
+
// mode to 'eternal', then the REPL found no engine, printed "no engine
|
|
30971
|
+
// wired — falling back to off" on EVERY loop iteration without actually
|
|
30972
|
+
// flipping the mode back or `continue`-ing, and left the user staring at
|
|
30973
|
+
// unconfirmed tool calls. `cli-eternal-flag.test.ts` passes this ref, so
|
|
30974
|
+
// the test exercised a wiring production never had.
|
|
30975
|
+
// The live holder is `EternalAutonomyEngine | null`; the ref contract is
|
|
30976
|
+
// `| undefined`. Bridge rather than widen either side.
|
|
30977
|
+
eternalEngineRef: {
|
|
30978
|
+
get current() {
|
|
30979
|
+
return eternalEngine ?? void 0;
|
|
30980
|
+
},
|
|
30981
|
+
set current(engine) {
|
|
30982
|
+
eternalEngine = engine ?? null;
|
|
30983
|
+
}
|
|
30984
|
+
}
|
|
30378
30985
|
});
|
|
30379
30986
|
config = configRef.current;
|
|
30380
30987
|
if (eternalFlag.length > 0) {
|
|
@@ -30404,7 +31011,7 @@ async function runInteractive(cliCtx) {
|
|
|
30404
31011
|
onEvent: evOn
|
|
30405
31012
|
});
|
|
30406
31013
|
const savedProviderCfg = config.providers?.[config.provider];
|
|
30407
|
-
const { execute } = await import("./execution-
|
|
31014
|
+
const { execute } = await import("./execution-LHMSMDHB.js");
|
|
30408
31015
|
const stopHeapWatchdog = startSharedHeapWatchdog({
|
|
30409
31016
|
collectStats: () => {
|
|
30410
31017
|
const hqQueue = hqPublisherRef.current?.getQueueStats();
|
|
@@ -30636,4 +31243,4 @@ export {
|
|
|
30636
31243
|
CLI_VERSION,
|
|
30637
31244
|
runInteractive
|
|
30638
31245
|
};
|
|
30639
|
-
//# sourceMappingURL=cli-main-
|
|
31246
|
+
//# sourceMappingURL=cli-main-XWC57MGE.js.map
|