@wrongstack/cli 0.303.0 → 0.305.1
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-AQMGKW6O.js → acp-5ZLGFHWP.js} +4 -2
- package/dist/{auth-K7CYVVKH.js → auth-EPERLKYI.js} +3 -3
- package/dist/boot/system-prompt-builder.d.ts +24 -1
- package/dist/boot/tui-project-switch.d.ts +1 -1
- package/dist/boot/tui-runtime-state.d.ts +14 -0
- package/dist/{chunk-C5NXM2SI.js → chunk-2H47YMCV.js} +5 -1
- package/dist/{chunk-FJVCVZIV.js → chunk-5KFLLTSQ.js} +2 -2
- package/dist/{chunk-JW75HY4F.js → chunk-FKWHSFX4.js} +33 -4
- package/dist/{chunk-LUAFQIXT.js → chunk-RHLQT3EV.js} +11 -1
- package/dist/{cli-main-37XO26GK.js → cli-main-6YE423OH.js} +479 -326
- package/dist/diag-doctor-WTBHPOMB.js +329 -0
- package/dist/execute-deps.d.ts +16 -0
- package/dist/{execution-MVOH6PAQ.js → execution-QYFWDD3Y.js} +70 -35
- package/dist/fleet/host-context.d.ts +2 -0
- package/dist/fleet/host-session-writer.d.ts +33 -0
- package/dist/fleet/host.d.ts +10 -0
- package/dist/{hq-CD77GVSS.js → hq-5G6D5YIU.js} +2 -2
- package/dist/{hq-server-DME6EWIO.js → hq-server-IVZLVCFV.js} +2 -2
- package/dist/index.js +17 -60
- package/dist/{mailbox-serve-DBOOOOWZ.js → mailbox-serve-V3QIJBDH.js} +2 -2
- package/dist/{mcp-AX6ZAFJR.js → mcp-MSARYOPN.js} +4 -2
- package/dist/replay-XU6ZD7GM.js +34 -0
- package/dist/slash-commands/memory-triage.d.ts +4 -17
- package/dist/subcommands/handlers/daemon-inventory.d.ts +41 -0
- package/dist/{webui-server-E3OPEKU5.js → webui-server-FTG7JAZU.js} +5 -5
- package/dist/wiring/domain-glossary.d.ts +58 -0
- package/dist/wiring/domain-terms-mirror.d.ts +52 -0
- package/dist/wiring/pipeline.d.ts +2 -0
- package/dist/wiring/replay.d.ts +11 -1
- package/dist/wiring/sage.d.ts +4 -16
- package/package.json +24 -23
- package/dist/diag-doctor-ZF5BF2MK.js +0 -169
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
} from "./chunk-V3XH6XBJ.js";
|
|
30
30
|
import {
|
|
31
31
|
startCliHqConnection
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-FKWHSFX4.js";
|
|
33
33
|
import {
|
|
34
34
|
advanceToNextTask,
|
|
35
35
|
findSpec,
|
|
@@ -59,7 +59,7 @@ import {
|
|
|
59
59
|
runClaudeOAuthLogin,
|
|
60
60
|
runCopilotOAuthLogin,
|
|
61
61
|
validateFamily
|
|
62
|
-
} from "./chunk-
|
|
62
|
+
} from "./chunk-5KFLLTSQ.js";
|
|
63
63
|
import {
|
|
64
64
|
runCodexOAuthLogin
|
|
65
65
|
} from "./chunk-SSSJQVUY.js";
|
|
@@ -78,7 +78,7 @@ import {
|
|
|
78
78
|
import {
|
|
79
79
|
LOCAL_LLM_PRESETS,
|
|
80
80
|
parseSpawnFlags
|
|
81
|
-
} from "./chunk-
|
|
81
|
+
} from "./chunk-2H47YMCV.js";
|
|
82
82
|
import {
|
|
83
83
|
buildPickableProviders,
|
|
84
84
|
visibleModelIds
|
|
@@ -117,7 +117,7 @@ import { gatedEnhancerReasoning } from "@wrongstack/core/execution";
|
|
|
117
117
|
import { TOKENS as TOKENS9 } from "@wrongstack/core/kernel";
|
|
118
118
|
import { ToolRegistry as ToolRegistry2 } from "@wrongstack/core/registry";
|
|
119
119
|
import { getSessionRegistry } from "@wrongstack/core/storage";
|
|
120
|
-
import { startSharedHeapWatchdog, writeErr as
|
|
120
|
+
import { startSharedHeapWatchdog, writeErr as writeErr3 } from "@wrongstack/core/utils";
|
|
121
121
|
|
|
122
122
|
// src/auth-menu/panel-service.ts
|
|
123
123
|
var ANSI_RE = /\u001b\[[0-9;]*m/g;
|
|
@@ -900,6 +900,12 @@ function bindSystemPromptBuilder(deps) {
|
|
|
900
900
|
// full-shape interfaces; the helper just needs the
|
|
901
901
|
// passthrough.
|
|
902
902
|
memoryStore: deps.memoryStore,
|
|
903
|
+
// Thread the narrow domain-term adapter so the builder emits a
|
|
904
|
+
// compact `[Project Jargon Dictionary]` block. `deps.domainGlossary`
|
|
905
|
+
// is an optional closure over the resolved SAGE `memoryStore`
|
|
906
|
+
// that returns only entries tagged `domain-term`; when omitted
|
|
907
|
+
// (e.g. in tests or subagent prompts) the builder emits no block.
|
|
908
|
+
domainGlossary: deps.domainGlossary,
|
|
903
909
|
// SAGE's turn middleware is the single memory-injection channel.
|
|
904
910
|
// Disable the builder's static "# Relevant Memory" section so memories
|
|
905
911
|
// are injected once, per-turn, relevance-scored — not duplicated here.
|
|
@@ -2904,6 +2910,38 @@ import {
|
|
|
2904
2910
|
} from "@wrongstack/core/types";
|
|
2905
2911
|
import { wstackGlobalRoot } from "@wrongstack/core/utils";
|
|
2906
2912
|
|
|
2913
|
+
// src/services/dispatch-classifier.ts
|
|
2914
|
+
import { makeLLMClassifier } from "@wrongstack/core/coordination";
|
|
2915
|
+
function makeProviderClassifier(provider, model) {
|
|
2916
|
+
return makeLLMClassifier(async (prompt) => {
|
|
2917
|
+
const ctrl = new AbortController();
|
|
2918
|
+
const timeout = setTimeout(() => ctrl.abort(), 15e3);
|
|
2919
|
+
try {
|
|
2920
|
+
const resp = await provider.complete(
|
|
2921
|
+
{
|
|
2922
|
+
model,
|
|
2923
|
+
system: [
|
|
2924
|
+
{
|
|
2925
|
+
type: "text",
|
|
2926
|
+
text: 'You are an agent router. Choose the single best agent for the task. Reply with ONLY a compact JSON object {"role":"...","reason":"..."}.'
|
|
2927
|
+
}
|
|
2928
|
+
],
|
|
2929
|
+
messages: [{ role: "user", content: [{ type: "text", text: prompt }] }],
|
|
2930
|
+
maxTokens: 120,
|
|
2931
|
+
temperature: 0
|
|
2932
|
+
},
|
|
2933
|
+
{ signal: ctrl.signal }
|
|
2934
|
+
);
|
|
2935
|
+
const content = resp.content;
|
|
2936
|
+
return Array.isArray(content) ? content[0]?.text ?? "" : "";
|
|
2937
|
+
} catch {
|
|
2938
|
+
return "";
|
|
2939
|
+
} finally {
|
|
2940
|
+
clearTimeout(timeout);
|
|
2941
|
+
}
|
|
2942
|
+
});
|
|
2943
|
+
}
|
|
2944
|
+
|
|
2907
2945
|
// src/fleet/host-acp.ts
|
|
2908
2946
|
import {
|
|
2909
2947
|
ACP_AGENT_COMMANDS,
|
|
@@ -3536,6 +3574,7 @@ function createHostStatusBroadcaster(input) {
|
|
|
3536
3574
|
// src/fleet/host-learning.ts
|
|
3537
3575
|
import {
|
|
3538
3576
|
captureLearnedFromAgentOutputDetailed,
|
|
3577
|
+
recordDirectiveOutcomes,
|
|
3539
3578
|
recordSkillOutcome
|
|
3540
3579
|
} from "@wrongstack/core/agent-catalog";
|
|
3541
3580
|
import { TOKENS as TOKENS2 } from "@wrongstack/core/kernel";
|
|
@@ -3543,20 +3582,38 @@ function captureCompletedTaskLearningForHost(result, deps, subjects, onCaptured)
|
|
|
3543
3582
|
const subject = subjects.get(result.subagentId);
|
|
3544
3583
|
if (!subject) return;
|
|
3545
3584
|
const logger = deps.container.safeResolve(TOKENS2.Logger);
|
|
3546
|
-
|
|
3585
|
+
const graded = result.status !== "stopped";
|
|
3586
|
+
const succeeded = result.status === "success";
|
|
3587
|
+
if (graded && subject.skills.length > 0) {
|
|
3547
3588
|
try {
|
|
3548
|
-
recordSkillOutcome(
|
|
3549
|
-
subject.role,
|
|
3550
|
-
subject.skills,
|
|
3551
|
-
result.status === "success",
|
|
3552
|
-
deps.projectRoot
|
|
3553
|
-
);
|
|
3589
|
+
recordSkillOutcome(subject.role, subject.skills, succeeded, deps.projectRoot);
|
|
3554
3590
|
} catch (error) {
|
|
3555
|
-
logger?.debug?.(
|
|
3591
|
+
logger?.debug?.(
|
|
3592
|
+
`skill affinity update failed for role "${subject.role}": ${describe(error)}`
|
|
3593
|
+
);
|
|
3556
3594
|
}
|
|
3557
3595
|
}
|
|
3558
3596
|
const finalText = typeof result.result === "string" ? result.result : result.partial?.text;
|
|
3559
3597
|
if (!finalText) return;
|
|
3598
|
+
if (graded) {
|
|
3599
|
+
try {
|
|
3600
|
+
const outcome = recordDirectiveOutcomes(subject.role, finalText, succeeded, deps.projectRoot);
|
|
3601
|
+
if (outcome.attributed > 0) {
|
|
3602
|
+
logger?.debug?.(
|
|
3603
|
+
`directive outcomes: ${outcome.attributed} applied for role "${subject.role}" (${succeeded ? "success" : "failure"})`
|
|
3604
|
+
);
|
|
3605
|
+
}
|
|
3606
|
+
for (const retired of outcome.quarantined) {
|
|
3607
|
+
logger?.info?.(
|
|
3608
|
+
`retired a directive for role "${subject.role}" after repeated failures: ${retired.slice(0, 120)}`
|
|
3609
|
+
);
|
|
3610
|
+
}
|
|
3611
|
+
} catch (error) {
|
|
3612
|
+
logger?.debug?.(
|
|
3613
|
+
`directive outcome update failed for role "${subject.role}": ${describe(error)}`
|
|
3614
|
+
);
|
|
3615
|
+
}
|
|
3616
|
+
}
|
|
3560
3617
|
try {
|
|
3561
3618
|
const capture = captureLearnedFromAgentOutputDetailed(
|
|
3562
3619
|
finalText,
|
|
@@ -3636,6 +3693,84 @@ function applyFleetRootDefaults(opts) {
|
|
|
3636
3693
|
}
|
|
3637
3694
|
}
|
|
3638
3695
|
|
|
3696
|
+
// src/fleet/host-provider.ts
|
|
3697
|
+
import { makeProviderFromConfig, withCatalogCapabilities } from "@wrongstack/providers";
|
|
3698
|
+
async function buildHostSubagentProvider(deps, config, overrideId, model) {
|
|
3699
|
+
const requestedProviderId = overrideId ?? config.provider;
|
|
3700
|
+
const providerId = requestedProviderId === config.provider || config.providers?.[requestedProviderId] !== void 0 || deps.providerRegistry.has(requestedProviderId) ? requestedProviderId : config.provider;
|
|
3701
|
+
const newCfg = config.providers?.[providerId] ?? {
|
|
3702
|
+
type: providerId,
|
|
3703
|
+
apiKey: config.apiKey,
|
|
3704
|
+
baseUrl: config.baseUrl
|
|
3705
|
+
};
|
|
3706
|
+
const cfgWithType = {
|
|
3707
|
+
...newCfg,
|
|
3708
|
+
type: providerId,
|
|
3709
|
+
...model ? { model } : {}
|
|
3710
|
+
};
|
|
3711
|
+
let provider = deps.providerRegistry.has(providerId) ? deps.providerRegistry.create(cfgWithType) : makeProviderFromConfig(providerId, cfgWithType);
|
|
3712
|
+
if (deps.modelsRegistry) {
|
|
3713
|
+
const resolvedModel = model ?? config.model;
|
|
3714
|
+
provider = await withCatalogCapabilities(deps.modelsRegistry, providerId, provider, {
|
|
3715
|
+
...cfgWithType,
|
|
3716
|
+
model: resolvedModel
|
|
3717
|
+
});
|
|
3718
|
+
await refreshRuntimeModelCatalog({
|
|
3719
|
+
modelsRegistry: deps.modelsRegistry,
|
|
3720
|
+
reason: `${providerId}/${resolvedModel}`
|
|
3721
|
+
});
|
|
3722
|
+
const mc = await resolveRuntimeMaxContext({
|
|
3723
|
+
modelsRegistry: deps.modelsRegistry,
|
|
3724
|
+
config,
|
|
3725
|
+
provider,
|
|
3726
|
+
runtimeProviderConfig: cfgWithType,
|
|
3727
|
+
providerId,
|
|
3728
|
+
modelId: resolvedModel
|
|
3729
|
+
});
|
|
3730
|
+
if (mc && mc > 0) provider.capabilities.maxContext = mc;
|
|
3731
|
+
}
|
|
3732
|
+
return provider;
|
|
3733
|
+
}
|
|
3734
|
+
async function resolveHostSubagentReasoningConfig(deps, providerId, modelId) {
|
|
3735
|
+
if (!deps.modelsRegistry) return void 0;
|
|
3736
|
+
try {
|
|
3737
|
+
return (await deps.modelsRegistry.getModel(providerId, modelId))?.capabilities.reasoningConfig;
|
|
3738
|
+
} catch {
|
|
3739
|
+
return void 0;
|
|
3740
|
+
}
|
|
3741
|
+
}
|
|
3742
|
+
function resolveHostSubagentModelSelection(liveConfig, effectiveCfg, matrixTarget) {
|
|
3743
|
+
let effProvider = effectiveCfg.provider ?? matrixTarget?.provider ?? liveConfig.provider;
|
|
3744
|
+
let effModel = effectiveCfg.model ?? matrixTarget?.model ?? liveConfig.model;
|
|
3745
|
+
const modelPolicy = effectiveCfg.modelPolicy;
|
|
3746
|
+
const closedModelPolicy = modelPolicy?.strict === true;
|
|
3747
|
+
const allowedModels = modelPolicy?.allowed ?? [];
|
|
3748
|
+
if (modelPolicy && !allowedModels.some((target) => target.provider === effProvider && target.model === effModel)) {
|
|
3749
|
+
const firstAllowed = allowedModels[0];
|
|
3750
|
+
if (!firstAllowed) throw new Error(`Agent "${effectiveCfg.role}" has no allowed models.`);
|
|
3751
|
+
effProvider = firstAllowed.provider;
|
|
3752
|
+
effModel = firstAllowed.model;
|
|
3753
|
+
}
|
|
3754
|
+
const fallbackProfile = modelPolicy ? void 0 : effectiveCfg.fallbackProfile ?? matrixTarget?.fallbackProfile;
|
|
3755
|
+
const runtimeOverride = effectiveCfg.modelRuntime ?? matrixTarget?.modelRuntime;
|
|
3756
|
+
const startupTargets = modelPolicy ? [
|
|
3757
|
+
{ provider: effProvider, model: effModel },
|
|
3758
|
+
...modelPolicy.fallbacks ?? [],
|
|
3759
|
+
...closedModelPolicy || effProvider === liveConfig.provider && effModel === liveConfig.model ? [] : [{ provider: liveConfig.provider, model: liveConfig.model }]
|
|
3760
|
+
] : [
|
|
3761
|
+
{ provider: effProvider, model: effModel },
|
|
3762
|
+
...effProvider === liveConfig.provider && effModel === liveConfig.model ? [] : [{ provider: liveConfig.provider, model: liveConfig.model }]
|
|
3763
|
+
];
|
|
3764
|
+
return {
|
|
3765
|
+
effProvider,
|
|
3766
|
+
effModel,
|
|
3767
|
+
fallbackProfile,
|
|
3768
|
+
runtimeOverride,
|
|
3769
|
+
closedModelPolicy,
|
|
3770
|
+
startupTargets
|
|
3771
|
+
};
|
|
3772
|
+
}
|
|
3773
|
+
|
|
3639
3774
|
// src/fleet/host-shadow-pass.ts
|
|
3640
3775
|
async function runHostShadowPass(ctx, reason) {
|
|
3641
3776
|
try {
|
|
@@ -3801,84 +3936,6 @@ function aggregateFleetUsage(completed) {
|
|
|
3801
3936
|
return { rows, totals };
|
|
3802
3937
|
}
|
|
3803
3938
|
|
|
3804
|
-
// src/fleet/host-provider.ts
|
|
3805
|
-
import { makeProviderFromConfig, withCatalogCapabilities } from "@wrongstack/providers";
|
|
3806
|
-
async function buildHostSubagentProvider(deps, config, overrideId, model) {
|
|
3807
|
-
const requestedProviderId = overrideId ?? config.provider;
|
|
3808
|
-
const providerId = requestedProviderId === config.provider || config.providers?.[requestedProviderId] !== void 0 || deps.providerRegistry.has(requestedProviderId) ? requestedProviderId : config.provider;
|
|
3809
|
-
const newCfg = config.providers?.[providerId] ?? {
|
|
3810
|
-
type: providerId,
|
|
3811
|
-
apiKey: config.apiKey,
|
|
3812
|
-
baseUrl: config.baseUrl
|
|
3813
|
-
};
|
|
3814
|
-
const cfgWithType = {
|
|
3815
|
-
...newCfg,
|
|
3816
|
-
type: providerId,
|
|
3817
|
-
...model ? { model } : {}
|
|
3818
|
-
};
|
|
3819
|
-
let provider = deps.providerRegistry.has(providerId) ? deps.providerRegistry.create(cfgWithType) : makeProviderFromConfig(providerId, cfgWithType);
|
|
3820
|
-
if (deps.modelsRegistry) {
|
|
3821
|
-
const resolvedModel = model ?? config.model;
|
|
3822
|
-
provider = await withCatalogCapabilities(deps.modelsRegistry, providerId, provider, {
|
|
3823
|
-
...cfgWithType,
|
|
3824
|
-
model: resolvedModel
|
|
3825
|
-
});
|
|
3826
|
-
await refreshRuntimeModelCatalog({
|
|
3827
|
-
modelsRegistry: deps.modelsRegistry,
|
|
3828
|
-
reason: `${providerId}/${resolvedModel}`
|
|
3829
|
-
});
|
|
3830
|
-
const mc = await resolveRuntimeMaxContext({
|
|
3831
|
-
modelsRegistry: deps.modelsRegistry,
|
|
3832
|
-
config,
|
|
3833
|
-
provider,
|
|
3834
|
-
runtimeProviderConfig: cfgWithType,
|
|
3835
|
-
providerId,
|
|
3836
|
-
modelId: resolvedModel
|
|
3837
|
-
});
|
|
3838
|
-
if (mc && mc > 0) provider.capabilities.maxContext = mc;
|
|
3839
|
-
}
|
|
3840
|
-
return provider;
|
|
3841
|
-
}
|
|
3842
|
-
async function resolveHostSubagentReasoningConfig(deps, providerId, modelId) {
|
|
3843
|
-
if (!deps.modelsRegistry) return void 0;
|
|
3844
|
-
try {
|
|
3845
|
-
return (await deps.modelsRegistry.getModel(providerId, modelId))?.capabilities.reasoningConfig;
|
|
3846
|
-
} catch {
|
|
3847
|
-
return void 0;
|
|
3848
|
-
}
|
|
3849
|
-
}
|
|
3850
|
-
function resolveHostSubagentModelSelection(liveConfig, effectiveCfg, matrixTarget) {
|
|
3851
|
-
let effProvider = effectiveCfg.provider ?? matrixTarget?.provider ?? liveConfig.provider;
|
|
3852
|
-
let effModel = effectiveCfg.model ?? matrixTarget?.model ?? liveConfig.model;
|
|
3853
|
-
const modelPolicy = effectiveCfg.modelPolicy;
|
|
3854
|
-
const closedModelPolicy = modelPolicy?.strict === true;
|
|
3855
|
-
const allowedModels = modelPolicy?.allowed ?? [];
|
|
3856
|
-
if (modelPolicy && !allowedModels.some((target) => target.provider === effProvider && target.model === effModel)) {
|
|
3857
|
-
const firstAllowed = allowedModels[0];
|
|
3858
|
-
if (!firstAllowed) throw new Error(`Agent "${effectiveCfg.role}" has no allowed models.`);
|
|
3859
|
-
effProvider = firstAllowed.provider;
|
|
3860
|
-
effModel = firstAllowed.model;
|
|
3861
|
-
}
|
|
3862
|
-
const fallbackProfile = modelPolicy ? void 0 : effectiveCfg.fallbackProfile ?? matrixTarget?.fallbackProfile;
|
|
3863
|
-
const runtimeOverride = effectiveCfg.modelRuntime ?? matrixTarget?.modelRuntime;
|
|
3864
|
-
const startupTargets = modelPolicy ? [
|
|
3865
|
-
{ provider: effProvider, model: effModel },
|
|
3866
|
-
...modelPolicy.fallbacks ?? [],
|
|
3867
|
-
...closedModelPolicy || effProvider === liveConfig.provider && effModel === liveConfig.model ? [] : [{ provider: liveConfig.provider, model: liveConfig.model }]
|
|
3868
|
-
] : [
|
|
3869
|
-
{ provider: effProvider, model: effModel },
|
|
3870
|
-
...effProvider === liveConfig.provider && effModel === liveConfig.model ? [] : [{ provider: liveConfig.provider, model: liveConfig.model }]
|
|
3871
|
-
];
|
|
3872
|
-
return {
|
|
3873
|
-
effProvider,
|
|
3874
|
-
effModel,
|
|
3875
|
-
fallbackProfile,
|
|
3876
|
-
runtimeOverride,
|
|
3877
|
-
closedModelPolicy,
|
|
3878
|
-
startupTargets
|
|
3879
|
-
};
|
|
3880
|
-
}
|
|
3881
|
-
|
|
3882
3939
|
// src/fleet/host-subagent-factory.ts
|
|
3883
3940
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
3884
3941
|
import { existsSync, statSync } from "node:fs";
|
|
@@ -3914,6 +3971,7 @@ import { AutoApprovePermissionPolicy } from "@wrongstack/core/security";
|
|
|
3914
3971
|
|
|
3915
3972
|
// src/fleet/host-context.ts
|
|
3916
3973
|
import {
|
|
3974
|
+
DEFAULT_EAGER_SKILL_LIMIT,
|
|
3917
3975
|
loadProjectSkillAugmentation,
|
|
3918
3976
|
missingRequiredRuntimeTools,
|
|
3919
3977
|
missingRuntimeCapabilities,
|
|
@@ -3924,7 +3982,8 @@ import {
|
|
|
3924
3982
|
} from "@wrongstack/core/agent-catalog";
|
|
3925
3983
|
import { TOKENS as TOKENS3 } from "@wrongstack/core/kernel";
|
|
3926
3984
|
import { getSageRetrieval } from "@wrongstack/sage";
|
|
3927
|
-
var EAGER_SKILL_LIMIT =
|
|
3985
|
+
var EAGER_SKILL_LIMIT = DEFAULT_EAGER_SKILL_LIMIT;
|
|
3986
|
+
var MIN_TRIMMED_BODY_CHARS = 800;
|
|
3928
3987
|
async function resolveHostSubagentSkillResolution(deps, roster, subCfg, availableToolNames = []) {
|
|
3929
3988
|
const role = subCfg.role;
|
|
3930
3989
|
const rosterEntry = role ? roster[role] : void 0;
|
|
@@ -3940,10 +3999,11 @@ async function resolveHostSubagentSkillResolution(deps, roster, subCfg, availabl
|
|
|
3940
3999
|
];
|
|
3941
4000
|
const skillNames = role ? rankRoleSkills(role, pool, deps.projectRoot, EAGER_SKILL_LIMIT) : pool.slice(0, EAGER_SKILL_LIMIT);
|
|
3942
4001
|
if (skillNames.length === 0 || !deps.skillLoader) {
|
|
3943
|
-
return { content: directContent ?? "", selected: [], dropped };
|
|
4002
|
+
return { content: directContent ?? "", selected: [], dropped, trimmed: [] };
|
|
3944
4003
|
}
|
|
3945
4004
|
const resolved = [];
|
|
3946
4005
|
const selected = [];
|
|
4006
|
+
const trimmed = [];
|
|
3947
4007
|
let usedChars = 0;
|
|
3948
4008
|
const maxChars = 16e3;
|
|
3949
4009
|
const maxCharsPerSkill = 4e3;
|
|
@@ -3972,10 +4032,12 @@ async function resolveHostSubagentSkillResolution(deps, roster, subCfg, availabl
|
|
|
3972
4032
|
continue;
|
|
3973
4033
|
}
|
|
3974
4034
|
const augmentation = role ? loadProjectSkillAugmentation(role, skillName, deps.projectRoot) : "";
|
|
3975
|
-
const
|
|
4035
|
+
const compose = (bodyChars) => [
|
|
3976
4036
|
`## Skill: ${skillName}`,
|
|
3977
4037
|
"",
|
|
3978
|
-
body.slice(0,
|
|
4038
|
+
body.length > bodyChars ? `${body.slice(0, bodyChars).trimEnd()}
|
|
4039
|
+
|
|
4040
|
+
_(body trimmed)_` : body,
|
|
3979
4041
|
...augmentation ? [
|
|
3980
4042
|
"",
|
|
3981
4043
|
`### Project practice for \`${skillName}\``,
|
|
@@ -3985,9 +4047,16 @@ async function resolveHostSubagentSkillResolution(deps, roster, subCfg, availabl
|
|
|
3985
4047
|
augmentation
|
|
3986
4048
|
] : []
|
|
3987
4049
|
].join("\n");
|
|
4050
|
+
let entry = compose(maxCharsPerSkill);
|
|
3988
4051
|
if (usedChars + entry.length > maxChars) {
|
|
3989
|
-
|
|
3990
|
-
|
|
4052
|
+
const overhead = entry.length - Math.min(body.length, maxCharsPerSkill);
|
|
4053
|
+
const room = maxChars - usedChars - overhead;
|
|
4054
|
+
if (!augmentation || room < MIN_TRIMMED_BODY_CHARS) {
|
|
4055
|
+
dropped[skillName] = "budget";
|
|
4056
|
+
continue;
|
|
4057
|
+
}
|
|
4058
|
+
entry = compose(room);
|
|
4059
|
+
trimmed.push(skillName);
|
|
3991
4060
|
}
|
|
3992
4061
|
resolved.push(entry);
|
|
3993
4062
|
selected.push(skillName);
|
|
@@ -4010,7 +4079,7 @@ Apply these skills first for this assignment.
|
|
|
4010
4079
|
|
|
4011
4080
|
${resolved.join("\n\n---\n\n")}` : void 0
|
|
4012
4081
|
].filter((section) => Boolean(section));
|
|
4013
|
-
return { content: sections.join("\n\n"), selected, dropped };
|
|
4082
|
+
return { content: sections.join("\n\n"), selected, dropped, trimmed };
|
|
4014
4083
|
}
|
|
4015
4084
|
async function retrieveHostSubagentMemory(deps, getLeaderMode, subCfg, taskContext) {
|
|
4016
4085
|
const memoryPort = deps.container.safeResolve(TOKENS3.MemoryStore);
|
|
@@ -4222,10 +4291,8 @@ function createParentSubagentSessionWriter(parentSession) {
|
|
|
4222
4291
|
flush: () => parentSession.flush(),
|
|
4223
4292
|
close: async () => {
|
|
4224
4293
|
},
|
|
4225
|
-
recordFileChange: () =>
|
|
4226
|
-
|
|
4227
|
-
recordSideEffect: () => {
|
|
4228
|
-
},
|
|
4294
|
+
recordFileChange: (input) => parentSession.recordFileChange(input),
|
|
4295
|
+
recordSideEffect: (input) => parentSession.recordSideEffect(input),
|
|
4229
4296
|
writeCheckpoint: async () => {
|
|
4230
4297
|
},
|
|
4231
4298
|
writeFileSnapshot: async () => {
|
|
@@ -4239,6 +4306,21 @@ function createParentSubagentSessionWriter(parentSession) {
|
|
|
4239
4306
|
}
|
|
4240
4307
|
};
|
|
4241
4308
|
}
|
|
4309
|
+
function withParentFileSnapshots(subagentSession, parentSession) {
|
|
4310
|
+
if (subagentSession === parentSession) return subagentSession;
|
|
4311
|
+
return new Proxy(subagentSession, {
|
|
4312
|
+
get(target, property, receiver) {
|
|
4313
|
+
if (property === "recordFileChange") {
|
|
4314
|
+
return (input) => {
|
|
4315
|
+
target.recordFileChange(input);
|
|
4316
|
+
parentSession.recordFileChange(input);
|
|
4317
|
+
};
|
|
4318
|
+
}
|
|
4319
|
+
const value = Reflect.get(target, property, receiver);
|
|
4320
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
4321
|
+
}
|
|
4322
|
+
});
|
|
4323
|
+
}
|
|
4242
4324
|
|
|
4243
4325
|
// src/fleet/host-subagent-factory.ts
|
|
4244
4326
|
function createHostSubagentFactory(config, host) {
|
|
@@ -4370,12 +4452,13 @@ ${audienceMemory.map((text) => `- ${text}`).join("\n")}`
|
|
|
4370
4452
|
baseSystem.push({ type: "text", text: skillResolution.content });
|
|
4371
4453
|
}
|
|
4372
4454
|
const droppedSkills = Object.entries(skillResolution.dropped);
|
|
4373
|
-
if (droppedSkills.length > 0) {
|
|
4455
|
+
if (droppedSkills.length > 0 || skillResolution.trimmed.length > 0) {
|
|
4374
4456
|
host.deps.events.emit("subagent.skills.dropped", {
|
|
4375
4457
|
sessionId: host.deps.session.id,
|
|
4376
4458
|
role: effectiveCfg.role,
|
|
4377
4459
|
selected: skillResolution.selected,
|
|
4378
|
-
dropped: Object.fromEntries(droppedSkills)
|
|
4460
|
+
dropped: Object.fromEntries(droppedSkills),
|
|
4461
|
+
...skillResolution.trimmed.length > 0 ? { trimmed: skillResolution.trimmed } : {}
|
|
4379
4462
|
});
|
|
4380
4463
|
}
|
|
4381
4464
|
const rawRolePrompt = effectiveCfg.systemPromptOverride ?? effectiveCfg.prompt ?? (effectiveCfg.role ? host.roster[effectiveCfg.role]?.prompt : void 0);
|
|
@@ -4391,12 +4474,15 @@ ${audienceMemory.map((text) => `- ${text}`).join("\n")}`
|
|
|
4391
4474
|
}
|
|
4392
4475
|
let subSession;
|
|
4393
4476
|
if (host.sessionFactory) {
|
|
4394
|
-
subSession =
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
|
|
4398
|
-
|
|
4399
|
-
|
|
4477
|
+
subSession = withParentFileSnapshots(
|
|
4478
|
+
await host.sessionFactory.createSubagentSession({
|
|
4479
|
+
subagentId: subagentName,
|
|
4480
|
+
provider: effProvider,
|
|
4481
|
+
model: effModel,
|
|
4482
|
+
title: `subagent: ${subagentName}`
|
|
4483
|
+
}),
|
|
4484
|
+
host.deps.session
|
|
4485
|
+
);
|
|
4400
4486
|
} else {
|
|
4401
4487
|
subSession = createParentSubagentSessionWriter(host.deps.session);
|
|
4402
4488
|
}
|
|
@@ -4445,7 +4531,11 @@ ${audienceMemory.map((text) => `- ${text}`).join("\n")}`
|
|
|
4445
4531
|
maxToolTimeoutMs: config.tools?.maxToolTimeoutMs ?? 3e5,
|
|
4446
4532
|
perIterationOutputCapBytes: config.tools?.perIterationOutputCapBytes ?? 1e5,
|
|
4447
4533
|
tracer: void 0,
|
|
4448
|
-
|
|
4534
|
+
// Kanban tracks work; it does not gate it. Off unless the operator opts
|
|
4535
|
+
// in — and then subagents inherit it, because a worker dispatched by
|
|
4536
|
+
// `kanban_queue` already carries board/task/lease identity in ctx.meta
|
|
4537
|
+
// and can satisfy the same gate its leader was held to.
|
|
4538
|
+
requireKanbanGovernance: config.tools?.kanbanGovernance ?? false
|
|
4449
4539
|
});
|
|
4450
4540
|
const subagentConfigStore = host.deps.configStore;
|
|
4451
4541
|
const pipelines = createDefaultPipelines();
|
|
@@ -4836,6 +4926,12 @@ var MultiAgentHost = class {
|
|
|
4836
4926
|
// pass so director.fleetManager is never undefined
|
|
4837
4927
|
brain: this.opts.brain,
|
|
4838
4928
|
roster: this.roster,
|
|
4929
|
+
// The dispatcher is two-stage by design — keyword heuristic, then a model
|
|
4930
|
+
// to break the tie — but nothing ever supplied stage two here, so every
|
|
4931
|
+
// description the keywords could not resolve fell through to the
|
|
4932
|
+
// `executor` generalist. That is one half of why a 77-role roster was
|
|
4933
|
+
// being served by a handful of agents.
|
|
4934
|
+
dispatchClassifier: (task, candidates) => this.classifyDispatch(task, candidates),
|
|
4839
4935
|
// Fire-and-forget report-back: when an assign_task completes with no
|
|
4840
4936
|
// pending await, post the result to this session's leader via the
|
|
4841
4937
|
// project mailbox (injected inline before the leader's next step).
|
|
@@ -5324,6 +5420,28 @@ var MultiAgentHost = class {
|
|
|
5324
5420
|
}
|
|
5325
5421
|
return this.learningOptimizer;
|
|
5326
5422
|
}
|
|
5423
|
+
/**
|
|
5424
|
+
* Break a dispatch tie with a model when the keyword heuristic is ambiguous.
|
|
5425
|
+
*
|
|
5426
|
+
* Routes through the `dispatcher` model-matrix slot when one is configured —
|
|
5427
|
+
* picking a role is a short classification, so it belongs on a cheap fast
|
|
5428
|
+
* model rather than the leader's — and the session default otherwise.
|
|
5429
|
+
* Returning `null` on any failure leaves the dispatcher on its heuristic
|
|
5430
|
+
* result, so routing degrades rather than breaking a spawn.
|
|
5431
|
+
*/
|
|
5432
|
+
async classifyDispatch(task, candidates) {
|
|
5433
|
+
try {
|
|
5434
|
+
const config = this.deps.configStore.get();
|
|
5435
|
+
const target = resolveSubagentModelTarget2(config, "dispatcher");
|
|
5436
|
+
const providerId = target?.provider ?? config.provider;
|
|
5437
|
+
const model = target?.model ?? config.model;
|
|
5438
|
+
if (!providerId || !model) return null;
|
|
5439
|
+
const provider = await buildHostSubagentProvider(this.deps, config, providerId, model);
|
|
5440
|
+
return await makeProviderClassifier(provider, model)(task, candidates);
|
|
5441
|
+
} catch {
|
|
5442
|
+
return null;
|
|
5443
|
+
}
|
|
5444
|
+
}
|
|
5327
5445
|
/**
|
|
5328
5446
|
* Resolve a model for the distillation pass. Uses the `memory-curator` slot
|
|
5329
5447
|
* of the model matrix when one is configured — curating learned knowledge is
|
|
@@ -6417,6 +6535,58 @@ function setupDirectorAndAutonomy(deps) {
|
|
|
6417
6535
|
};
|
|
6418
6536
|
}
|
|
6419
6537
|
|
|
6538
|
+
// src/wiring/domain-glossary.ts
|
|
6539
|
+
import { getSageService } from "@wrongstack/sage";
|
|
6540
|
+
var DOMAIN_GLOSSARY_LIMIT = 16;
|
|
6541
|
+
function createDomainGlossaryAdapter(memoryStore) {
|
|
6542
|
+
return {
|
|
6543
|
+
async list(scope, limit) {
|
|
6544
|
+
try {
|
|
6545
|
+
const service = getSageService(memoryStore);
|
|
6546
|
+
if (!service) return [];
|
|
6547
|
+
if (scope !== "project-memory") return [];
|
|
6548
|
+
const effectiveLimit = Math.min(
|
|
6549
|
+
Math.max(1, limit ?? DOMAIN_GLOSSARY_LIMIT),
|
|
6550
|
+
DOMAIN_GLOSSARY_LIMIT
|
|
6551
|
+
);
|
|
6552
|
+
const hits = await service.searchSage("domain-term", { limit: effectiveLimit });
|
|
6553
|
+
return hits.map((hit) => sageToGlossaryEntry(hit));
|
|
6554
|
+
} catch {
|
|
6555
|
+
return [];
|
|
6556
|
+
}
|
|
6557
|
+
}
|
|
6558
|
+
};
|
|
6559
|
+
}
|
|
6560
|
+
function sageToGlossaryEntry(sage) {
|
|
6561
|
+
const priority = sage.importance >= 0.9 ? "critical" : sage.importance >= 0.75 ? "high" : sage.importance >= 0.4 ? "medium" : "low";
|
|
6562
|
+
return {
|
|
6563
|
+
scope: "project-memory",
|
|
6564
|
+
text: sage.text,
|
|
6565
|
+
ts: sage.updatedAt || sage.createdAt,
|
|
6566
|
+
type: "reference",
|
|
6567
|
+
tags: sage.tags.slice(),
|
|
6568
|
+
priority,
|
|
6569
|
+
confidence: sage.confidence,
|
|
6570
|
+
lastAccessed: sage.lastAccessedAt
|
|
6571
|
+
};
|
|
6572
|
+
}
|
|
6573
|
+
|
|
6574
|
+
// src/wiring/domain-terms-mirror.ts
|
|
6575
|
+
import { writeErr as writeErr2 } from "@wrongstack/core/utils";
|
|
6576
|
+
import { SageDomainTermExtractor } from "@wrongstack/sage";
|
|
6577
|
+
async function refreshDomainTermsMirror(options) {
|
|
6578
|
+
try {
|
|
6579
|
+
const extractor = new SageDomainTermExtractor();
|
|
6580
|
+
return await extractor.writeDomainTermsFile(options.projectRoot, options.memoryStore);
|
|
6581
|
+
} catch (err) {
|
|
6582
|
+
writeErr2(
|
|
6583
|
+
`[wrongstack] domain-terms mirror refresh failed: ${err instanceof Error ? err.message : String(err)}
|
|
6584
|
+
`
|
|
6585
|
+
);
|
|
6586
|
+
return null;
|
|
6587
|
+
}
|
|
6588
|
+
}
|
|
6589
|
+
|
|
6420
6590
|
// src/wiring/eternal-command-handlers.ts
|
|
6421
6591
|
import { EternalAutonomyEngine as EternalAutonomyEngine2, ParallelEternalEngine } from "@wrongstack/core/execution";
|
|
6422
6592
|
function createEternalCommandHandlers(input) {
|
|
@@ -7750,7 +7920,20 @@ function createAgent(params) {
|
|
|
7750
7920
|
tracer: params.tracer,
|
|
7751
7921
|
logger,
|
|
7752
7922
|
hookRunner: params.hookRunner,
|
|
7753
|
-
|
|
7923
|
+
// Kanban tracks work; it does not gate it. When this was hard-wired `true`
|
|
7924
|
+
// a mutating tool was refused until a managed card existed, carried a
|
|
7925
|
+
// description and acceptance criteria, and had been started — so the
|
|
7926
|
+
// session spent its effort on card ceremony instead of the work the card
|
|
7927
|
+
// describes. Cards still advance and boards still mirror; path-scoped
|
|
7928
|
+
// `boundary` policies (the actual access control) are unaffected and still
|
|
7929
|
+
// enforced.
|
|
7930
|
+
//
|
|
7931
|
+
// It stays OFF by default, but is now an operator switch rather than a
|
|
7932
|
+
// literal: `tools.kanbanGovernance: true` opts an installation in. The
|
|
7933
|
+
// four hosts (this pipeline, mcp-serve, acp-server-agent, and the fleet
|
|
7934
|
+
// subagent factory) must resolve it identically, or a subagent would run
|
|
7935
|
+
// under a different contract than the leader that dispatched it.
|
|
7936
|
+
requireKanbanGovernance: params.config.tools.kanbanGovernance ?? false
|
|
7754
7937
|
};
|
|
7755
7938
|
const toolExecutor = new ToolExecutor2(params.tools, toolExecutorOptions);
|
|
7756
7939
|
void bootstrapMailboxBridgeAtStartup({
|
|
@@ -7771,6 +7954,7 @@ function createAgent(params) {
|
|
|
7771
7954
|
events: params.events,
|
|
7772
7955
|
pipelines: params.pipelines,
|
|
7773
7956
|
context: params.context,
|
|
7957
|
+
refreshSystemPrompt: true,
|
|
7774
7958
|
maxIterations: params.config.tools.maxIterations,
|
|
7775
7959
|
iterationTimeoutMs: params.config.tools.iterationTimeoutMs,
|
|
7776
7960
|
executionStrategy: params.config.tools.defaultExecutionStrategy,
|
|
@@ -8262,7 +8446,7 @@ import {
|
|
|
8262
8446
|
watchProviderConfig
|
|
8263
8447
|
} from "@wrongstack/core/storage";
|
|
8264
8448
|
import { withCatalogCapabilities as withCatalogCapabilities2 } from "@wrongstack/providers";
|
|
8265
|
-
import { getSageService } from "@wrongstack/sage";
|
|
8449
|
+
import { getSageService as getSageService2 } from "@wrongstack/sage";
|
|
8266
8450
|
|
|
8267
8451
|
// src/wiring/fallback-gate.ts
|
|
8268
8452
|
function createFallbackGate(_events) {
|
|
@@ -8401,7 +8585,7 @@ function setupProviderRuntime(deps) {
|
|
|
8401
8585
|
})
|
|
8402
8586
|
);
|
|
8403
8587
|
if (cfg.features.memory && cfg.features.memoryConsolidation !== false) {
|
|
8404
|
-
const consSage =
|
|
8588
|
+
const consSage = getSageService2(memoryStore);
|
|
8405
8589
|
agent.extensions.register(
|
|
8406
8590
|
new SessionMemoryConsolidator({
|
|
8407
8591
|
memoryStore,
|
|
@@ -8818,88 +9002,11 @@ async function setupCodebaseIndexing(deps) {
|
|
|
8818
9002
|
|
|
8819
9003
|
// src/wiring/sage.ts
|
|
8820
9004
|
import {
|
|
8821
|
-
|
|
8822
|
-
|
|
8823
|
-
|
|
8824
|
-
|
|
8825
|
-
InjectionTracker
|
|
9005
|
+
AUTO_HYGIENE_INTERVAL_MS,
|
|
9006
|
+
_resetAutoHygieneThrottleForTesting,
|
|
9007
|
+
sageHygieneOptionsFromConfig,
|
|
9008
|
+
setupSage
|
|
8826
9009
|
} from "@wrongstack/sage";
|
|
8827
|
-
var lastAutoHygieneAt = 0;
|
|
8828
|
-
var AUTO_HYGIENE_INTERVAL_MS = 60 * 6e4;
|
|
8829
|
-
function setupSage(deps) {
|
|
8830
|
-
const cfg = deps.config.Sage;
|
|
8831
|
-
const noop = async () => {
|
|
8832
|
-
};
|
|
8833
|
-
if (deps.config.features.memory === false) return noop;
|
|
8834
|
-
if (cfg?.enabled === false) return noop;
|
|
8835
|
-
if (!deps.memoryStore) return noop;
|
|
8836
|
-
const memoryStore = deps.memoryStore;
|
|
8837
|
-
const retrieval = getSageRetrieval2(memoryStore);
|
|
8838
|
-
if (!retrieval) {
|
|
8839
|
-
deps.logger.debug("sage middleware skipped: memory store does not support retrieval");
|
|
8840
|
-
return noop;
|
|
8841
|
-
}
|
|
8842
|
-
const injectionTracker = new InjectionTracker();
|
|
8843
|
-
if (cfg?.inject?.toolResults !== false) {
|
|
8844
|
-
deps.pipelines.toolCall.use(
|
|
8845
|
-
createSageToolCallMiddleware({
|
|
8846
|
-
memory: retrieval,
|
|
8847
|
-
maxHintsPerTool: cfg?.inject?.maxHintsPerTool,
|
|
8848
|
-
maxCharsPerTool: cfg?.inject?.maxCharsPerTool,
|
|
8849
|
-
taskAware: cfg?.inject?.taskAware,
|
|
8850
|
-
minScore: cfg?.inject?.minScore,
|
|
8851
|
-
minImportance: cfg?.inject?.minImportance,
|
|
8852
|
-
relationFloor: cfg?.inject?.relationFloor,
|
|
8853
|
-
repeatCooldownMs: cfg?.inject?.repeatCooldownMs,
|
|
8854
|
-
verifyOnMutation: cfg?.hygiene?.autoOnFileChange,
|
|
8855
|
-
triggers: cfg?.inject?.triggers,
|
|
8856
|
-
tracker: injectionTracker,
|
|
8857
|
-
events: deps.events,
|
|
8858
|
-
getSessionId: deps.getSessionId
|
|
8859
|
-
})
|
|
8860
|
-
);
|
|
8861
|
-
}
|
|
8862
|
-
if (cfg?.inject?.turnContext === true) {
|
|
8863
|
-
deps.pipelines.request.use(
|
|
8864
|
-
createSageTurnMiddleware({
|
|
8865
|
-
memory: retrieval,
|
|
8866
|
-
maxMemories: cfg?.inject?.maxTurnMemories,
|
|
8867
|
-
maxChars: cfg?.inject?.maxCharsPerTurn,
|
|
8868
|
-
minScore: cfg?.inject?.minScore,
|
|
8869
|
-
metadataWeight: cfg?.retrieval?.metadataWeight,
|
|
8870
|
-
tracker: injectionTracker,
|
|
8871
|
-
getSessionId: deps.getSessionId
|
|
8872
|
-
})
|
|
8873
|
-
);
|
|
8874
|
-
}
|
|
8875
|
-
deps.pipelines.request.use(
|
|
8876
|
-
createSageContextMonitorMiddleware({
|
|
8877
|
-
tracker: injectionTracker,
|
|
8878
|
-
events: deps.events,
|
|
8879
|
-
getSessionId: deps.getSessionId
|
|
8880
|
-
})
|
|
8881
|
-
);
|
|
8882
|
-
return async () => {
|
|
8883
|
-
await retrieval.flushPendingCounters?.();
|
|
8884
|
-
if (cfg?.hygiene?.autoAfterSession === false) return;
|
|
8885
|
-
const now = Date.now();
|
|
8886
|
-
if (now - lastAutoHygieneAt < AUTO_HYGIENE_INTERVAL_MS) {
|
|
8887
|
-
deps.logger.debug(
|
|
8888
|
-
`sage auto-hygiene skipped: last run ${Math.round((now - lastAutoHygieneAt) / 1e3)}s ago (throttle: ${AUTO_HYGIENE_INTERVAL_MS / 1e3}s)`
|
|
8889
|
-
);
|
|
8890
|
-
return;
|
|
8891
|
-
}
|
|
8892
|
-
await memoryStore.hygiene?.({
|
|
8893
|
-
retentionDays: cfg?.hygiene?.retentionDays,
|
|
8894
|
-
sessionRetentionDays: cfg?.hygiene?.sessionRetentionDays,
|
|
8895
|
-
archiveLowConfidenceAfterDays: cfg?.hygiene?.archiveLowConfidenceAfterDays,
|
|
8896
|
-
archiveUnusedAfterDays: cfg?.hygiene?.archiveUnusedAfterDays,
|
|
8897
|
-
unusedMinInjections: cfg?.hygiene?.unusedMinInjections,
|
|
8898
|
-
purgeDeletedAfterDays: cfg?.hygiene?.purgeDeletedAfterDays
|
|
8899
|
-
});
|
|
8900
|
-
lastAutoHygieneAt = now;
|
|
8901
|
-
};
|
|
8902
|
-
}
|
|
8903
9010
|
|
|
8904
9011
|
// src/wiring/runtime-dispatch-state.ts
|
|
8905
9012
|
async function prepareRuntimeDispatch(input) {
|
|
@@ -8909,7 +9016,8 @@ async function prepareRuntimeDispatch(input) {
|
|
|
8909
9016
|
memoryStore: input.memoryStore,
|
|
8910
9017
|
logger: input.logger,
|
|
8911
9018
|
events: input.events,
|
|
8912
|
-
getSessionId: () => input.agent.ctx.session.id
|
|
9019
|
+
getSessionId: () => input.agent.ctx.session.id,
|
|
9020
|
+
projectRoot: input.projectRoot
|
|
8913
9021
|
});
|
|
8914
9022
|
const disposeIndexing = await setupCodebaseIndexing({
|
|
8915
9023
|
config: input.getConfig(),
|
|
@@ -8954,6 +9062,7 @@ async function prepareRuntimeDispatch(input) {
|
|
|
8954
9062
|
owner,
|
|
8955
9063
|
category: tool.category ?? "Other",
|
|
8956
9064
|
enabled: !input.toolRegistry.isDisabled(tool.name),
|
|
9065
|
+
exposure: input.toolRegistry.isDisabled(tool.name) ? "disabled" : input.toolRegistry.isExposedToProvider(tool.name) ? "direct" : "lazy",
|
|
8957
9066
|
mutating: tool.mutating,
|
|
8958
9067
|
permission: tool.permission,
|
|
8959
9068
|
descMode: getToolDescriptionMode(input.toolRegistry, tool.name),
|
|
@@ -9433,7 +9542,11 @@ import {
|
|
|
9433
9542
|
sessionScopedPath as sessionScopedPath3,
|
|
9434
9543
|
toErrorMessage as toErrorMessage5
|
|
9435
9544
|
} from "@wrongstack/core/utils";
|
|
9436
|
-
import {
|
|
9545
|
+
import {
|
|
9546
|
+
attachSessionKanbanMirror,
|
|
9547
|
+
hydrateSessionKanban,
|
|
9548
|
+
sessionKanbanDegradation
|
|
9549
|
+
} from "@wrongstack/tools/session-kanban";
|
|
9437
9550
|
async function setupSession(params) {
|
|
9438
9551
|
const {
|
|
9439
9552
|
config,
|
|
@@ -9597,6 +9710,12 @@ async function setupSession(params) {
|
|
|
9597
9710
|
const taskPath = sessionScopedPath3(wpaths.projectSessions, sessionId, ".tasks.json");
|
|
9598
9711
|
context.state.setMeta("task.path", taskPath);
|
|
9599
9712
|
await hydrateSessionKanban(context);
|
|
9713
|
+
const kanbanDown = sessionKanbanDegradation();
|
|
9714
|
+
if (kanbanDown) {
|
|
9715
|
+
renderer.writeInfo(
|
|
9716
|
+
`Kanban board sync unavailable \u2014 continuing without it (${kanbanDown}). Run \`wstack doctor --daemons\` for detail.`
|
|
9717
|
+
);
|
|
9718
|
+
}
|
|
9600
9719
|
const detachSessionKanbanMirror = attachSessionKanbanMirror(context);
|
|
9601
9720
|
const detachTodosCheckpoint = async () => {
|
|
9602
9721
|
detachSessionKanbanMirror();
|
|
@@ -9688,38 +9807,6 @@ ${diff}`;
|
|
|
9688
9807
|
return "chore: update";
|
|
9689
9808
|
}
|
|
9690
9809
|
|
|
9691
|
-
// src/services/dispatch-classifier.ts
|
|
9692
|
-
import { makeLLMClassifier } from "@wrongstack/core/coordination";
|
|
9693
|
-
function makeProviderClassifier(provider, model) {
|
|
9694
|
-
return makeLLMClassifier(async (prompt) => {
|
|
9695
|
-
const ctrl = new AbortController();
|
|
9696
|
-
const timeout = setTimeout(() => ctrl.abort(), 15e3);
|
|
9697
|
-
try {
|
|
9698
|
-
const resp = await provider.complete(
|
|
9699
|
-
{
|
|
9700
|
-
model,
|
|
9701
|
-
system: [
|
|
9702
|
-
{
|
|
9703
|
-
type: "text",
|
|
9704
|
-
text: 'You are an agent router. Choose the single best agent for the task. Reply with ONLY a compact JSON object {"role":"...","reason":"..."}.'
|
|
9705
|
-
}
|
|
9706
|
-
],
|
|
9707
|
-
messages: [{ role: "user", content: [{ type: "text", text: prompt }] }],
|
|
9708
|
-
maxTokens: 120,
|
|
9709
|
-
temperature: 0
|
|
9710
|
-
},
|
|
9711
|
-
{ signal: ctrl.signal }
|
|
9712
|
-
);
|
|
9713
|
-
const content = resp.content;
|
|
9714
|
-
return Array.isArray(content) ? content[0]?.text ?? "" : "";
|
|
9715
|
-
} catch {
|
|
9716
|
-
return "";
|
|
9717
|
-
} finally {
|
|
9718
|
-
clearTimeout(timeout);
|
|
9719
|
-
}
|
|
9720
|
-
});
|
|
9721
|
-
}
|
|
9722
|
-
|
|
9723
9810
|
// src/services/mcp-management.ts
|
|
9724
9811
|
import {
|
|
9725
9812
|
color as color8,
|
|
@@ -10681,10 +10768,17 @@ ${lines.join("\n")}`;
|
|
|
10681
10768
|
const learned = loadProjectAgentLearned(role, projectRoot);
|
|
10682
10769
|
const kn = loadRoleKnowledgeManifest(role, projectRoot);
|
|
10683
10770
|
const developedSkills = listProjectSkillAugmentations(role, projectRoot);
|
|
10771
|
+
const stats = getProjectAgentLearnStats(role, projectRoot);
|
|
10684
10772
|
const lines = [`${color11.bold(role)} project identity:`];
|
|
10685
10773
|
if (developedSkills.length > 0) {
|
|
10686
10774
|
lines.push(` skills developed: ${developedSkills.join(", ")}`);
|
|
10687
10775
|
}
|
|
10776
|
+
if (stats.entryCount > 0) {
|
|
10777
|
+
const hitRate = stats.directiveHitRate === null ? "no directive exercised yet" : `${Math.round(stats.directiveHitRate * 100)}% hit rate over ${stats.appliedEntryCount} exercised`;
|
|
10778
|
+
lines.push(
|
|
10779
|
+
` directives: ${stats.entryCount} buffered \xB7 ${hitRate} \xB7 ${stats.deadEntryCount} never used`
|
|
10780
|
+
);
|
|
10781
|
+
}
|
|
10688
10782
|
if (cfg) lines.push(` config: ${JSON.stringify(cfg)}`);
|
|
10689
10783
|
if (kn)
|
|
10690
10784
|
lines.push(
|
|
@@ -12886,6 +12980,7 @@ var SOURCE_LABELS = {
|
|
|
12886
12980
|
"leader-after-task": "leader-after-task (post-tool summary)",
|
|
12887
12981
|
contributor: "contributor",
|
|
12888
12982
|
ledger: "completed-work ledger",
|
|
12983
|
+
glossary: "project jargon dictionary",
|
|
12889
12984
|
nextsteps: "next-steps gate",
|
|
12890
12985
|
other: "other (untagged)"
|
|
12891
12986
|
};
|
|
@@ -13697,6 +13792,8 @@ var KNOWN_TOP_LEVEL_KEYS = [
|
|
|
13697
13792
|
"fallbackBridge",
|
|
13698
13793
|
"fallbackProfiles",
|
|
13699
13794
|
"fallbackAuto",
|
|
13795
|
+
"fallbackMaxLastResortCandidates",
|
|
13796
|
+
"fallbackStickiness",
|
|
13700
13797
|
"hooks",
|
|
13701
13798
|
"plugins",
|
|
13702
13799
|
"pluginManager",
|
|
@@ -13842,6 +13939,37 @@ function diagnoseConfig(cfg, plugins = []) {
|
|
|
13842
13939
|
}
|
|
13843
13940
|
}
|
|
13844
13941
|
}
|
|
13942
|
+
if ("fallbackMaxLastResortCandidates" in fixed) {
|
|
13943
|
+
const v = fixed["fallbackMaxLastResortCandidates"];
|
|
13944
|
+
const n = coerceNumber(v);
|
|
13945
|
+
if (n === void 0) {
|
|
13946
|
+
delete fixed["fallbackMaxLastResortCandidates"];
|
|
13947
|
+
findings.push({
|
|
13948
|
+
path: "fallbackMaxLastResortCandidates",
|
|
13949
|
+
problem: `expected a non-negative number, got ${JSON.stringify(v)}`,
|
|
13950
|
+
severity: "error",
|
|
13951
|
+
fix: "removed (built-in default of 12 applies)"
|
|
13952
|
+
});
|
|
13953
|
+
} else {
|
|
13954
|
+
const clamped = Math.max(0, Math.floor(n));
|
|
13955
|
+
if (clamped !== v) {
|
|
13956
|
+
fixed["fallbackMaxLastResortCandidates"] = clamped;
|
|
13957
|
+
findings.push({
|
|
13958
|
+
path: "fallbackMaxLastResortCandidates",
|
|
13959
|
+
problem: `expected a non-negative integer, got ${JSON.stringify(v)}`,
|
|
13960
|
+
severity: "error",
|
|
13961
|
+
fix: `set to ${clamped}`
|
|
13962
|
+
});
|
|
13963
|
+
} else if (clamped === 0) {
|
|
13964
|
+
findings.push({
|
|
13965
|
+
path: "fallbackMaxLastResortCandidates",
|
|
13966
|
+
problem: "is 0 \u2014 last-resort auto-discovery append is disabled",
|
|
13967
|
+
severity: "warning",
|
|
13968
|
+
fix: "no change (explicit user choice)"
|
|
13969
|
+
});
|
|
13970
|
+
}
|
|
13971
|
+
}
|
|
13972
|
+
}
|
|
13845
13973
|
if ("fleet" in fixed) {
|
|
13846
13974
|
if (!isPlainObject(fixed["fleet"])) {
|
|
13847
13975
|
findings.push({
|
|
@@ -14673,6 +14801,9 @@ function buildFallbackCommand(opts) {
|
|
|
14673
14801
|
const favorites = config.favoriteModels ?? [];
|
|
14674
14802
|
const bridge = config.fallbackBridge?.trim();
|
|
14675
14803
|
const auto = config.fallbackAuto !== false;
|
|
14804
|
+
const rawCap = config.fallbackMaxLastResortCandidates;
|
|
14805
|
+
const capValue = typeof rawCap === "number" && Number.isFinite(rawCap) && rawCap >= 0 ? Math.floor(rawCap) : 12;
|
|
14806
|
+
const capLabel = capValue === 0 ? color24.dim("disabled") : color24.green(String(capValue));
|
|
14676
14807
|
const filteredReason = (ref) => refInactiveReason(ref, config);
|
|
14677
14808
|
const lines = [
|
|
14678
14809
|
`${color24.bold("WrongStack")} ${color24.dim("\u2014 Fallback chain")}`,
|
|
@@ -14710,6 +14841,7 @@ function buildFallbackCommand(opts) {
|
|
|
14710
14841
|
"",
|
|
14711
14842
|
` ${color24.bold("auto")} ${auto ? color24.green("on") : color24.dim("off")} ${color24.dim("/fallback auto on|off")}`,
|
|
14712
14843
|
` ${color24.bold("favorites only")} ${config.favoriteModelsOnly ? color24.green("on") : color24.dim("off")} ${color24.dim("/fallback fav only on|off")}`,
|
|
14844
|
+
` ${color24.bold("last-resort cap")} ${capLabel} ${color24.dim("(max auto-discovered models appended, 0=disabled)")}`,
|
|
14713
14845
|
"",
|
|
14714
14846
|
` ${color24.bold("profiles")} ${Object.keys(profiles).length ? "" : color24.dim("(none)")}`,
|
|
14715
14847
|
...Object.entries(profiles).sort(([a], [b]) => a.localeCompare(b)).flatMap(([name, chain]) => {
|
|
@@ -17298,7 +17430,6 @@ function buildIntakeCommand(opts) {
|
|
|
17298
17430
|
import { color as color32 } from "@wrongstack/core/utils";
|
|
17299
17431
|
import {
|
|
17300
17432
|
addCheckToTask,
|
|
17301
|
-
addColumn,
|
|
17302
17433
|
addDependency,
|
|
17303
17434
|
addGoalMetricToTask,
|
|
17304
17435
|
addNoteToTask,
|
|
@@ -17324,7 +17455,6 @@ import {
|
|
|
17324
17455
|
parseLinesIntoTasks,
|
|
17325
17456
|
releaseTaskClaim,
|
|
17326
17457
|
removeBoard,
|
|
17327
|
-
removeColumn,
|
|
17328
17458
|
removeTask,
|
|
17329
17459
|
setTaskChain,
|
|
17330
17460
|
splitTask,
|
|
@@ -17752,9 +17882,6 @@ var KANBAN_COMMAND_HELP = [
|
|
|
17752
17882
|
"",
|
|
17753
17883
|
" /kanban task check add <boardId> <taskId> <desc> Add success check",
|
|
17754
17884
|
"",
|
|
17755
|
-
" /kanban column add <boardId> <title> Add column",
|
|
17756
|
-
" /kanban column rm <boardId> <colId> Remove column",
|
|
17757
|
-
"",
|
|
17758
17885
|
" /kanban generate <description> Auto-generate board from text",
|
|
17759
17886
|
" /kanban export <boardId> Export board as markdown",
|
|
17760
17887
|
" /kanban graph export <boardId> [graphId] Save board as SDD TaskGraph",
|
|
@@ -17930,9 +18057,6 @@ function buildKanbanCommand(opts) {
|
|
|
17930
18057
|
if (cmd === "task" || cmd === "t") {
|
|
17931
18058
|
return handleTaskSubcommand(opts, projectRoot, rest, showHelp);
|
|
17932
18059
|
}
|
|
17933
|
-
if (cmd === "column" || cmd === "col" || cmd === "c") {
|
|
17934
|
-
return handleColumnSubcommand(projectRoot, rest, showHelp);
|
|
17935
|
-
}
|
|
17936
18060
|
return {
|
|
17937
18061
|
message: unknownSubcommand(
|
|
17938
18062
|
cmd,
|
|
@@ -18612,27 +18736,6 @@ ${summary}` };
|
|
|
18612
18736
|
}
|
|
18613
18737
|
return showHelp();
|
|
18614
18738
|
}
|
|
18615
|
-
async function handleColumnSubcommand(projectRoot, args, showHelp) {
|
|
18616
|
-
const [sub, boardId, ...rest] = args;
|
|
18617
|
-
if (!sub || !boardId) return showHelp();
|
|
18618
|
-
if (sub === "add") {
|
|
18619
|
-
const title = rest.join(" ");
|
|
18620
|
-
if (!title) return { message: color32.red("Usage: /kanban column add <boardId> <title>") };
|
|
18621
|
-
const result = await addColumn(projectRoot, boardId, { title });
|
|
18622
|
-
if (!result) return { message: color32.red(`Board not found: ${boardId}`) };
|
|
18623
|
-
return { message: color32.green(`\u2705 Column added: ${result.column.title}`) };
|
|
18624
|
-
}
|
|
18625
|
-
if (sub === "rm" || sub === "remove" || sub === "delete") {
|
|
18626
|
-
const colId = rest[0];
|
|
18627
|
-
if (!colId) return { message: color32.red("Usage: /kanban column rm <boardId> <columnId>") };
|
|
18628
|
-
const updated = await removeColumn(projectRoot, boardId, colId, {
|
|
18629
|
-
moveTasksToColumnId: rest[1]
|
|
18630
|
-
});
|
|
18631
|
-
if (!updated) return { message: color32.red(`Column not found: ${colId}`) };
|
|
18632
|
-
return { message: color32.green(`\u2705 Column removed: ${colId}`) };
|
|
18633
|
-
}
|
|
18634
|
-
return showHelp();
|
|
18635
|
-
}
|
|
18636
18739
|
function extractSpawnedSubagentId(summary) {
|
|
18637
18740
|
return summary.match(/Spawned subagent\s+([^\s]+)/)?.[1];
|
|
18638
18741
|
}
|
|
@@ -18650,12 +18753,6 @@ function formatLifecycleDiagnosis(err, action) {
|
|
|
18650
18753
|
if (field === "assignee") {
|
|
18651
18754
|
return `\u274C /kanban task ${action} needs an assignee. Run \`/kanban task assign <boardId> <taskId> <agent>\` first.`;
|
|
18652
18755
|
}
|
|
18653
|
-
if (field === "dueDate") {
|
|
18654
|
-
return `\u274C /kanban task ${action} needs a valid due date. Add one via the \`kanban.update_task\` tool action (patch.dueDate = "YYYY-MM-DD").`;
|
|
18655
|
-
}
|
|
18656
|
-
if (field === "labels") {
|
|
18657
|
-
return `\u274C /kanban task ${action} needs at least one label. Add one via the \`kanban.update_task\` tool action (patch.labels = ["..."]).`;
|
|
18658
|
-
}
|
|
18659
18756
|
if (field === "childTaskIds") {
|
|
18660
18757
|
return `\u274C /kanban task ${action} is an atomic parent with no persisted children. Decompose it via the kanban tool (\`split_atomic\`) before moving it forward.`;
|
|
18661
18758
|
}
|
|
@@ -20253,7 +20350,11 @@ function formatSageShow(stats, memories) {
|
|
|
20253
20350
|
|
|
20254
20351
|
// src/slash-commands/memory-triage.ts
|
|
20255
20352
|
import { toErrorMessage as toErrorMessage17 } from "@wrongstack/core/utils";
|
|
20256
|
-
import {
|
|
20353
|
+
import {
|
|
20354
|
+
fileTriageProposals,
|
|
20355
|
+
formatTriageReport,
|
|
20356
|
+
runTriage
|
|
20357
|
+
} from "@wrongstack/sage";
|
|
20257
20358
|
var DEFAULT_MAX_PHASE3 = 1e3;
|
|
20258
20359
|
var DEFAULT_MAX_PHASE4_PAIRS = 50;
|
|
20259
20360
|
async function runTriageCommand(opts, args) {
|
|
@@ -20450,41 +20551,7 @@ async function applyDispatch(Sage, report) {
|
|
|
20450
20551
|
return lines.join("\n");
|
|
20451
20552
|
}
|
|
20452
20553
|
async function fileProposals(Sage, proposals) {
|
|
20453
|
-
|
|
20454
|
-
const failures = [];
|
|
20455
|
-
let filed = 0;
|
|
20456
|
-
for (const proposal of proposals) {
|
|
20457
|
-
const input = {
|
|
20458
|
-
text: proposal.memoryText,
|
|
20459
|
-
targetMemoryId: proposal.memoryId,
|
|
20460
|
-
reviewReason: proposal.reason,
|
|
20461
|
-
suggestedAction: proposal.suggestedAction,
|
|
20462
|
-
kind: "memory_review",
|
|
20463
|
-
scope: "project",
|
|
20464
|
-
importance: 0.5,
|
|
20465
|
-
confidence: 0.9,
|
|
20466
|
-
tags: ["triage"],
|
|
20467
|
-
anchors: [],
|
|
20468
|
-
sources: [{ type: "project_instruction" }]
|
|
20469
|
-
};
|
|
20470
|
-
inputs.push(input);
|
|
20471
|
-
try {
|
|
20472
|
-
await Sage.createCandidate(input);
|
|
20473
|
-
filed++;
|
|
20474
|
-
} catch (err) {
|
|
20475
|
-
failures.push({
|
|
20476
|
-
memoryId: proposal.memoryId,
|
|
20477
|
-
error: toErrorMessage17(err)
|
|
20478
|
-
});
|
|
20479
|
-
}
|
|
20480
|
-
}
|
|
20481
|
-
return {
|
|
20482
|
-
filed,
|
|
20483
|
-
failed: failures.length,
|
|
20484
|
-
total: proposals.length,
|
|
20485
|
-
failures,
|
|
20486
|
-
inputs
|
|
20487
|
-
};
|
|
20554
|
+
return fileTriageProposals(Sage, proposals);
|
|
20488
20555
|
}
|
|
20489
20556
|
|
|
20490
20557
|
// src/slash-commands/memory.ts
|
|
@@ -25589,24 +25656,78 @@ function buildWebuiCommand() {
|
|
|
25589
25656
|
}
|
|
25590
25657
|
|
|
25591
25658
|
// src/slash-commands/theme.ts
|
|
25659
|
+
import { THEME_PRESET_IDS } from "@wrongstack/core/types";
|
|
25592
25660
|
import { color as color46, writeOut as writeOut3 } from "@wrongstack/core/utils";
|
|
25593
|
-
var
|
|
25594
|
-
|
|
25595
|
-
|
|
25596
|
-
|
|
25597
|
-
|
|
25598
|
-
|
|
25599
|
-
|
|
25600
|
-
|
|
25601
|
-
|
|
25602
|
-
|
|
25603
|
-
|
|
25604
|
-
|
|
25605
|
-
|
|
25606
|
-
|
|
25607
|
-
|
|
25608
|
-
|
|
25609
|
-
|
|
25661
|
+
var THEME_META = {
|
|
25662
|
+
catppuccin: { name: "Catppuccin Mocha", desc: "Soft pastel dark theme (Default)" },
|
|
25663
|
+
"tokyo-night": { name: "Tokyo Night", desc: "Deep violet, neon orange & cyan" },
|
|
25664
|
+
nord: { name: "Nord", desc: "Cool arctic blue & slate pastels" },
|
|
25665
|
+
cyberpunk: { name: "Cyberpunk Neon", desc: "High-contrast magenta, cyan & yellow" },
|
|
25666
|
+
dracula: { name: "Dracula", desc: "Vibrant purple, pink & green" },
|
|
25667
|
+
"gruvbox-dark": { name: "Gruvbox Dark", desc: "Warm earthy retro \u2014 orange, olive & aqua" },
|
|
25668
|
+
"solarized-dark": { name: "Solarized Dark", desc: "Base16 classic \u2014 teal & ochre precision" },
|
|
25669
|
+
"one-dark": { name: "One Dark", desc: "Atom's iconic palette \u2014 blue-led, warm accents" },
|
|
25670
|
+
monokai: { name: "Monokai", desc: "Sublime classic \u2014 vivid magenta, cyan & lime" },
|
|
25671
|
+
"rose-pine": { name: "Ros\xE9 Pine", desc: "Aesthetic pine & foam \u2014 soft evening pastels" },
|
|
25672
|
+
kanagawa: { name: "Kanagawa", desc: "Hokusai-inspired waves \u2014 sumi ink on washi" },
|
|
25673
|
+
"ayu-dark": { name: "Ayu Dark", desc: "Simple pleasant dark \u2014 warm orange + cool blue" },
|
|
25674
|
+
everforest: { name: "Everforest", desc: "Green-based comfort \u2014 forest greens & warm tans" },
|
|
25675
|
+
"night-owl": { name: "Night Owl", desc: "Sarah Drasner's night \u2014 deep navy + bold accents" },
|
|
25676
|
+
synthwave: { name: "Synthwave '84", desc: "Hot pink + neon cyan on deep purple" },
|
|
25677
|
+
"github-dark": { name: "GitHub Dark", desc: "GitHub's default dark \u2014 crisp blue on near-black" },
|
|
25678
|
+
"material-ocean": {
|
|
25679
|
+
name: "Material Ocean",
|
|
25680
|
+
desc: "Deepest Material variant \u2014 ink blue with pastel accents"
|
|
25681
|
+
},
|
|
25682
|
+
nightfox: { name: "Nightfox", desc: "Balanced slate blue with muted sage and rose" },
|
|
25683
|
+
oxocarbon: {
|
|
25684
|
+
name: "Oxocarbon",
|
|
25685
|
+
desc: "IBM Carbon-derived \u2014 neutral greys, electric blue & pink"
|
|
25686
|
+
},
|
|
25687
|
+
"catppuccin-macchiato": {
|
|
25688
|
+
name: "Catppuccin Macchiato",
|
|
25689
|
+
desc: "Warmer, one shade lighter than Mocha"
|
|
25690
|
+
},
|
|
25691
|
+
"catppuccin-frappe": {
|
|
25692
|
+
name: "Catppuccin Frapp\xE9",
|
|
25693
|
+
desc: "The lightest Catppuccin dark \u2014 gentle midday contrast"
|
|
25694
|
+
},
|
|
25695
|
+
"gruvbox-material": {
|
|
25696
|
+
name: "Gruvbox Material",
|
|
25697
|
+
desc: "Softened Gruvbox \u2014 same warmth, lower eye strain"
|
|
25698
|
+
},
|
|
25699
|
+
"tokyo-night-storm": {
|
|
25700
|
+
name: "Tokyo Night Storm",
|
|
25701
|
+
desc: "Tokyo Night on a lifted blue-grey base"
|
|
25702
|
+
},
|
|
25703
|
+
"rose-pine-moon": {
|
|
25704
|
+
name: "Ros\xE9 Pine Moon",
|
|
25705
|
+
desc: "Ros\xE9 Pine at dusk \u2014 deeper base, same soft accents"
|
|
25706
|
+
},
|
|
25707
|
+
zenburn: { name: "Zenburn", desc: "The classic low-contrast grey \u2014 desaturated and calm" },
|
|
25708
|
+
palenight: { name: "Palenight", desc: "Material Palenight \u2014 indigo base, candy accents" },
|
|
25709
|
+
horizon: { name: "Horizon", desc: "Warm coral and mint on charcoal \u2014 sunset gradient" },
|
|
25710
|
+
sonokai: { name: "Sonokai", desc: "Monokai Pro descendant \u2014 punchy on warm graphite" },
|
|
25711
|
+
"edge-dark": { name: "Edge Dark", desc: "Clean, evenly-weighted palette on desaturated navy" },
|
|
25712
|
+
moonfly: { name: "Moonfly", desc: "Near-black base with high-chroma accents \u2014 max contrast" },
|
|
25713
|
+
melange: { name: "Melange", desc: "Warm sepia and clay \u2014 the least blue dark theme here" },
|
|
25714
|
+
poimandres: { name: "Poimandres", desc: "Teal-forward, low-saturation \u2014 mint on deep indigo" },
|
|
25715
|
+
"vitesse-dark": {
|
|
25716
|
+
name: "Vitesse Dark",
|
|
25717
|
+
desc: "Anthony Fu's minimal palette \u2014 muted, print-like"
|
|
25718
|
+
},
|
|
25719
|
+
aura: { name: "Aura Dark", desc: "Vivid purple and spring green on near-black violet" },
|
|
25720
|
+
"dark-plus": { name: "VS Code Dark+", desc: "VS Code's default \u2014 familiar blue/orange/teal" }
|
|
25721
|
+
};
|
|
25722
|
+
var THEME_OPTIONS = THEME_PRESET_IDS.map((id) => ({ id, ...THEME_META[id] }));
|
|
25723
|
+
function presetHelpLines(perLine = 4) {
|
|
25724
|
+
const lines = [];
|
|
25725
|
+
for (let i = 0; i < THEME_PRESET_IDS.length; i += perLine) {
|
|
25726
|
+
const chunk = THEME_PRESET_IDS.slice(i, i + perLine).join(", ");
|
|
25727
|
+
lines.push(` ${chunk}${i + perLine < THEME_PRESET_IDS.length ? "," : ""}`);
|
|
25728
|
+
}
|
|
25729
|
+
return lines;
|
|
25730
|
+
}
|
|
25610
25731
|
async function runThemePicker(reader, activeId) {
|
|
25611
25732
|
let cursor = THEME_OPTIONS.findIndex((p) => p.id === activeId);
|
|
25612
25733
|
if (cursor < 0) cursor = 0;
|
|
@@ -25621,7 +25742,7 @@ ${color46.bold(color46.amber("WrongStack") + color46.dim(" \u2014 TUI Theme Sele
|
|
|
25621
25742
|
const mark = p.id === activeId ? color46.green(" [active]") : "";
|
|
25622
25743
|
const prefix = i === currentCursor ? color46.bold("\u276F ") : " ";
|
|
25623
25744
|
const name = i === currentCursor ? color46.bold(p.name) : p.name;
|
|
25624
|
-
lines.push(` ${prefix}${name.padEnd(
|
|
25745
|
+
lines.push(` ${prefix}${name.padEnd(21)} ${color46.dim(p.desc)}${mark}`);
|
|
25625
25746
|
}
|
|
25626
25747
|
lines.push("");
|
|
25627
25748
|
return lines.join("\n");
|
|
@@ -25651,16 +25772,14 @@ function buildThemeCommand(opts) {
|
|
|
25651
25772
|
name: "theme",
|
|
25652
25773
|
category: "Config",
|
|
25653
25774
|
description: "Switch or select the TUI color theme preset interactively",
|
|
25654
|
-
argsHint:
|
|
25775
|
+
argsHint: `[<preset>] (${THEME_PRESET_IDS.length} available \u2014 run /theme to pick)`,
|
|
25655
25776
|
help: [
|
|
25656
25777
|
"Usage:",
|
|
25657
25778
|
" /theme Interactive menu selection or view available theme presets",
|
|
25658
25779
|
" /theme <preset> Switch directly to a theme preset",
|
|
25659
25780
|
"",
|
|
25660
|
-
|
|
25661
|
-
|
|
25662
|
-
" gruvbox-dark, solarized-dark, one-dark, monokai, rose-pine,",
|
|
25663
|
-
" kanagawa, ayu-dark, everforest, night-owl, synthwave"
|
|
25781
|
+
`Available presets (${THEME_PRESET_IDS.length}):`,
|
|
25782
|
+
...presetHelpLines()
|
|
25664
25783
|
].join("\n"),
|
|
25665
25784
|
async run(args) {
|
|
25666
25785
|
const validPresets = THEME_OPTIONS.map((t) => t.id);
|
|
@@ -25690,7 +25809,7 @@ function buildThemeCommand(opts) {
|
|
|
25690
25809
|
];
|
|
25691
25810
|
for (const t of THEME_OPTIONS) {
|
|
25692
25811
|
const mark = t.id === activePreset ? color46.green(" [active]") : "";
|
|
25693
|
-
lines.push(` \u2022 ${color46.bold(t.id.padEnd(
|
|
25812
|
+
lines.push(` \u2022 ${color46.bold(t.id.padEnd(21))} ${t.desc}${mark}`);
|
|
25694
25813
|
}
|
|
25695
25814
|
lines.push("");
|
|
25696
25815
|
lines.push(color46.dim("Usage: /theme <preset>"));
|
|
@@ -31404,7 +31523,7 @@ async function runInteractive(cliCtx) {
|
|
|
31404
31523
|
activeMode
|
|
31405
31524
|
});
|
|
31406
31525
|
if (modeResult.kind === "exit") {
|
|
31407
|
-
|
|
31526
|
+
writeErr3(`${modeResult.message}
|
|
31408
31527
|
`);
|
|
31409
31528
|
await reader.close();
|
|
31410
31529
|
return modeResult.code;
|
|
@@ -31425,6 +31544,15 @@ async function runInteractive(cliCtx) {
|
|
|
31425
31544
|
container,
|
|
31426
31545
|
modeStore,
|
|
31427
31546
|
memoryStore,
|
|
31547
|
+
// Provide a narrow domain-term adapter so the prompt builder emits a
|
|
31548
|
+
// compact `[Project Jargon Dictionary]` block. Closes over the resolved
|
|
31549
|
+
// SAGE `memoryStore` (a `MemoryPort`) and uses the typed
|
|
31550
|
+
// `SageServiceLike` capability (NOT `@wrongstack/sage-mcp` — the
|
|
31551
|
+
// in-process consumer rule from `packages/sage/docs/direct-icp-usage.md`).
|
|
31552
|
+
// Returns only memories tagged `domain-term` via the capability's
|
|
31553
|
+
// `searchSage` op, which performs the tag-filter at the SQL layer rather
|
|
31554
|
+
// than scanning the whole corpus on every prompt build.
|
|
31555
|
+
domainGlossary: createDomainGlossaryAdapter(memoryStore),
|
|
31428
31556
|
skillLoader,
|
|
31429
31557
|
sessionRef,
|
|
31430
31558
|
autonomyModeRef,
|
|
@@ -31445,6 +31573,7 @@ async function runInteractive(cliCtx) {
|
|
|
31445
31573
|
pathJoiner: { join: (a, b) => path31.join(a, b) },
|
|
31446
31574
|
systemPromptBuilderToken: TOKENS9.SystemPromptBuilder
|
|
31447
31575
|
});
|
|
31576
|
+
await refreshDomainTermsMirror({ projectRoot, memoryStore });
|
|
31448
31577
|
const toolRegistry = new ToolRegistry2();
|
|
31449
31578
|
registerBuiltinTools({
|
|
31450
31579
|
toolRegistry,
|
|
@@ -31540,7 +31669,26 @@ async function runInteractive(cliCtx) {
|
|
|
31540
31669
|
}
|
|
31541
31670
|
});
|
|
31542
31671
|
const { context, planPath, session } = sessResult;
|
|
31672
|
+
context.meta["promptOnlineAgents"] = onlineAgents;
|
|
31543
31673
|
sessionRef.current = session;
|
|
31674
|
+
const replayFlag = flags["replay"];
|
|
31675
|
+
const recordFlag = flags["record"];
|
|
31676
|
+
if (typeof replayFlag === "string" || recordFlag === true) {
|
|
31677
|
+
const { bindReplayToContainer } = await import("./replay-XU6ZD7GM.js");
|
|
31678
|
+
const mode = recordFlag === true ? "record" : "replay";
|
|
31679
|
+
bindReplayToContainer({
|
|
31680
|
+
container,
|
|
31681
|
+
wpaths,
|
|
31682
|
+
// Recording follows the live session across `/resume` and new-session
|
|
31683
|
+
// swaps; replaying is pinned to the id the user named.
|
|
31684
|
+
sessionId: typeof replayFlag === "string" ? replayFlag : () => sessionRef.current?.id ?? "",
|
|
31685
|
+
mode,
|
|
31686
|
+
logger
|
|
31687
|
+
});
|
|
31688
|
+
logger.info(
|
|
31689
|
+
`replay: ProviderRunner bound in '${mode}' mode for session ${typeof replayFlag === "string" ? replayFlag : session.id}`
|
|
31690
|
+
);
|
|
31691
|
+
}
|
|
31544
31692
|
const governanceHandle = await setupCliGovernance({
|
|
31545
31693
|
projectRoot,
|
|
31546
31694
|
projectId: wpaths.projectSlug,
|
|
@@ -32075,7 +32223,7 @@ async function runInteractive(cliCtx) {
|
|
|
32075
32223
|
onEvent: evOn
|
|
32076
32224
|
});
|
|
32077
32225
|
const savedProviderCfg = config.providers?.[config.provider];
|
|
32078
|
-
const { execute } = await import("./execution-
|
|
32226
|
+
const { execute } = await import("./execution-QYFWDD3Y.js");
|
|
32079
32227
|
const stopHeapWatchdog = startSharedHeapWatchdog({
|
|
32080
32228
|
collectStats: () => {
|
|
32081
32229
|
const hqQueue = hqPublisherRef.current?.getQueueStats();
|
|
@@ -32126,6 +32274,11 @@ async function runInteractive(cliCtx) {
|
|
|
32126
32274
|
events,
|
|
32127
32275
|
slashRegistry,
|
|
32128
32276
|
tokenCounter,
|
|
32277
|
+
// Forward the boot sessionRef so `resumeSession` can repoint
|
|
32278
|
+
// it when an in-process `/resume` swaps the active writer.
|
|
32279
|
+
// Without this, provider-side `getSessionId` callbacks and the
|
|
32280
|
+
// record-mode binding keep referring to the boot session.
|
|
32281
|
+
sessionRef,
|
|
32129
32282
|
activateSessionIdentity: activateSession,
|
|
32130
32283
|
config,
|
|
32131
32284
|
configStore,
|
|
@@ -32308,4 +32461,4 @@ export {
|
|
|
32308
32461
|
CLI_VERSION,
|
|
32309
32462
|
runInteractive
|
|
32310
32463
|
};
|
|
32311
|
-
//# sourceMappingURL=cli-main-
|
|
32464
|
+
//# sourceMappingURL=cli-main-6YE423OH.js.map
|