@wrongstack/cli 0.302.2 → 0.303.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.
@@ -2880,7 +2880,12 @@ function subscribeBrainDecisionLog(events) {
2880
2880
 
2881
2881
  // src/fleet/host.ts
2882
2882
  import { randomUUID as randomUUID4 } from "node:crypto";
2883
- import { createProjectAgentRoster } from "@wrongstack/core/agent-catalog";
2883
+ import {
2884
+ createProjectAgentRoster,
2885
+ LearningOptimizationScheduler,
2886
+ listProjectAgentRoles,
2887
+ resolveAutoOptimizePolicy
2888
+ } from "@wrongstack/core/agent-catalog";
2884
2889
  import {
2885
2890
  AdaptiveConcurrencyController,
2886
2891
  DEFAULT_MAX_FLEET_SPAWNS as DEFAULT_MAX_FLEET_SPAWNS2,
@@ -2889,7 +2894,8 @@ import {
2889
2894
  HARD_MAX_SPAWN_DEPTH as HARD_MAX_SPAWN_DEPTH2,
2890
2895
  makeDirectorSessionFactory,
2891
2896
  makeFleetEmitTool,
2892
- resolveProjectDir
2897
+ resolveProjectDir,
2898
+ resolveSubagentModelTarget as resolveSubagentModelTarget2
2893
2899
  } from "@wrongstack/core/coordination";
2894
2900
  import { TOKENS as TOKENS5 } from "@wrongstack/core/kernel";
2895
2901
  import { ToolRegistry } from "@wrongstack/core/registry";
@@ -3528,24 +3534,53 @@ function createHostStatusBroadcaster(input) {
3528
3534
  }
3529
3535
 
3530
3536
  // src/fleet/host-learning.ts
3531
- import { captureLearnedFromAgentOutputDetailed } from "@wrongstack/core/agent-catalog";
3537
+ import {
3538
+ captureLearnedFromAgentOutputDetailed,
3539
+ recordSkillOutcome
3540
+ } from "@wrongstack/core/agent-catalog";
3532
3541
  import { TOKENS as TOKENS2 } from "@wrongstack/core/kernel";
3533
- function captureCompletedTaskLearningForHost(result, deps, subagentLearningRoles) {
3534
- if (result.status !== "success") return;
3535
- const role = subagentLearningRoles.get(result.subagentId);
3542
+ function captureCompletedTaskLearningForHost(result, deps, subjects, onCaptured) {
3543
+ const subject = subjects.get(result.subagentId);
3544
+ if (!subject) return;
3545
+ const logger = deps.container.safeResolve(TOKENS2.Logger);
3546
+ if (subject.skills.length > 0) {
3547
+ try {
3548
+ recordSkillOutcome(
3549
+ subject.role,
3550
+ subject.skills,
3551
+ result.status === "success",
3552
+ deps.projectRoot
3553
+ );
3554
+ } catch (error) {
3555
+ logger?.debug?.(`skill affinity update failed for role "${subject.role}": ${describe(error)}`);
3556
+ }
3557
+ }
3536
3558
  const finalText = typeof result.result === "string" ? result.result : result.partial?.text;
3537
- if (!role || !finalText) return;
3559
+ if (!finalText) return;
3538
3560
  try {
3539
- const capture = captureLearnedFromAgentOutputDetailed(finalText, role, deps.projectRoot, false);
3561
+ const capture = captureLearnedFromAgentOutputDetailed(
3562
+ finalText,
3563
+ subject.role,
3564
+ deps.projectRoot,
3565
+ false
3566
+ );
3540
3567
  if (capture.captured > 0) {
3541
- deps.container.safeResolve(TOKENS2.Logger)?.debug(`agent learning captured ${capture.captured} item(s) for role "${role}"`);
3568
+ const routed = capture.skills?.length ? ` (skills: ${capture.skills.join(", ")})` : "";
3569
+ logger?.debug(
3570
+ `agent learning captured ${capture.captured} item(s) for role "${subject.role}"${routed}`
3571
+ );
3572
+ try {
3573
+ onCaptured?.(subject.role);
3574
+ } catch {
3575
+ }
3542
3576
  }
3543
3577
  } catch (error) {
3544
- deps.container.safeResolve(TOKENS2.Logger)?.warn(
3545
- `agent learning capture failed for role "${role}": ${error instanceof Error ? error.message : String(error)}`
3546
- );
3578
+ logger?.warn(`agent learning capture failed for role "${subject.role}": ${describe(error)}`);
3547
3579
  }
3548
3580
  }
3581
+ function describe(error) {
3582
+ return error instanceof Error ? error.message : String(error);
3583
+ }
3549
3584
 
3550
3585
  // src/fleet/host-learning-tracker.ts
3551
3586
  var HostLearningRoleTracker = class {
@@ -3555,11 +3590,17 @@ var HostLearningRoleTracker = class {
3555
3590
  maxEntries;
3556
3591
  roles = /* @__PURE__ */ new Map();
3557
3592
  accessOrder = [];
3558
- record(subagentId, role) {
3559
- setBoundedLruEntry(this.roles, this.accessOrder, subagentId, role, this.maxEntries);
3593
+ record(subagentId, role, skills = []) {
3594
+ setBoundedLruEntry(
3595
+ this.roles,
3596
+ this.accessOrder,
3597
+ subagentId,
3598
+ { role, skills: [...skills] },
3599
+ this.maxEntries
3600
+ );
3560
3601
  }
3561
- capture(result, deps) {
3562
- captureCompletedTaskLearningForHost(result, deps, this.roles);
3602
+ capture(result, deps, onCaptured) {
3603
+ captureCompletedTaskLearningForHost(result, deps, this.roles, onCaptured);
3563
3604
  }
3564
3605
  };
3565
3606
 
@@ -3760,6 +3801,84 @@ function aggregateFleetUsage(completed) {
3760
3801
  return { rows, totals };
3761
3802
  }
3762
3803
 
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
+
3763
3882
  // src/fleet/host-subagent-factory.ts
3764
3883
  import { randomUUID as randomUUID2 } from "node:crypto";
3765
3884
  import { existsSync, statSync } from "node:fs";
@@ -3795,44 +3914,91 @@ import { AutoApprovePermissionPolicy } from "@wrongstack/core/security";
3795
3914
 
3796
3915
  // src/fleet/host-context.ts
3797
3916
  import {
3917
+ loadProjectSkillAugmentation,
3798
3918
  missingRequiredRuntimeTools,
3799
3919
  missingRuntimeCapabilities,
3920
+ rankRoleSkills,
3921
+ recordSkillLoad,
3922
+ resolveRoleSkillCandidates,
3800
3923
  runtimeToolReferencesFromText
3801
3924
  } from "@wrongstack/core/agent-catalog";
3802
3925
  import { TOKENS as TOKENS3 } from "@wrongstack/core/kernel";
3803
3926
  import { getSageRetrieval } from "@wrongstack/sage";
3804
- async function resolveHostSubagentSkillContent(deps, roster, subCfg, availableToolNames = []) {
3805
- const rosterSkillNames = subCfg.role ? roster[subCfg.role]?.skillNames : void 0;
3806
- const skillNames = [...new Set(subCfg.skillNames ?? rosterSkillNames ?? [])];
3927
+ var EAGER_SKILL_LIMIT = 3;
3928
+ async function resolveHostSubagentSkillResolution(deps, roster, subCfg, availableToolNames = []) {
3929
+ const role = subCfg.role;
3930
+ const rosterEntry = role ? roster[role] : void 0;
3807
3931
  const directContent = subCfg.skillContent?.trim();
3808
- if (skillNames.length === 0 || !deps.skillLoader) return directContent ?? "";
3932
+ const dropped = {};
3933
+ const pool = [
3934
+ ...new Set(
3935
+ subCfg.skillNames ?? (role ? [
3936
+ ...rosterEntry?.skillPool ?? rosterEntry?.skillNames ?? [],
3937
+ ...resolveRoleSkillCandidates(role, deps.projectRoot)
3938
+ ] : [])
3939
+ )
3940
+ ];
3941
+ const skillNames = role ? rankRoleSkills(role, pool, deps.projectRoot, EAGER_SKILL_LIMIT) : pool.slice(0, EAGER_SKILL_LIMIT);
3942
+ if (skillNames.length === 0 || !deps.skillLoader) {
3943
+ return { content: directContent ?? "", selected: [], dropped };
3944
+ }
3809
3945
  const resolved = [];
3946
+ const selected = [];
3810
3947
  let usedChars = 0;
3811
3948
  const maxChars = 16e3;
3812
3949
  const maxCharsPerSkill = 4e3;
3813
3950
  for (const skillName of skillNames) {
3814
3951
  try {
3815
3952
  const manifest = await deps.skillLoader.find(skillName);
3816
- if (!manifest) continue;
3817
- if (missingRuntimeCapabilities(manifest.requiredCapabilities, availableToolNames).length > 0 || missingRequiredRuntimeTools(manifest.requiredTools, availableToolNames).length > 0) {
3953
+ if (!manifest) {
3954
+ dropped[skillName] = "not-found";
3955
+ continue;
3956
+ }
3957
+ if (missingRuntimeCapabilities(manifest.requiredCapabilities, availableToolNames).length > 0) {
3958
+ dropped[skillName] = "missing-capability";
3959
+ continue;
3960
+ }
3961
+ if (missingRequiredRuntimeTools(manifest.requiredTools, availableToolNames).length > 0) {
3962
+ dropped[skillName] = "missing-tool";
3818
3963
  continue;
3819
3964
  }
3820
3965
  const body = (await deps.skillLoader.readSaveBody(skillName)).trim();
3821
- if (!body) continue;
3966
+ if (!body) {
3967
+ dropped[skillName] = "empty";
3968
+ continue;
3969
+ }
3822
3970
  if (missingRequiredRuntimeTools(runtimeToolReferencesFromText(body), availableToolNames).length > 0) {
3971
+ dropped[skillName] = "missing-tool";
3823
3972
  continue;
3824
3973
  }
3825
- const entry = `## Skill: ${skillName}
3826
-
3827
- ${body.slice(0, maxCharsPerSkill)}`;
3974
+ const augmentation = role ? loadProjectSkillAugmentation(role, skillName, deps.projectRoot) : "";
3975
+ const entry = [
3976
+ `## Skill: ${skillName}`,
3977
+ "",
3978
+ body.slice(0, maxCharsPerSkill),
3979
+ ...augmentation ? [
3980
+ "",
3981
+ `### Project practice for \`${skillName}\``,
3982
+ "",
3983
+ "Learned in this project. Where this differs from the general method above, follow this.",
3984
+ "",
3985
+ augmentation
3986
+ ] : []
3987
+ ].join("\n");
3828
3988
  if (usedChars + entry.length > maxChars) {
3829
- console.warn(
3830
- `[MultiAgentHost] resolveSubagentSkillContent: budget (${maxChars}) exhausted after ${resolved.length} skill(s); dropping "${skillName}" and remaining skills`
3831
- );
3832
- break;
3989
+ dropped[skillName] = "budget";
3990
+ continue;
3833
3991
  }
3834
3992
  resolved.push(entry);
3993
+ selected.push(skillName);
3835
3994
  usedChars += entry.length;
3995
+ } catch {
3996
+ dropped[skillName] = "not-found";
3997
+ }
3998
+ }
3999
+ if (role && selected.length > 0) {
4000
+ try {
4001
+ recordSkillLoad(role, selected, deps.projectRoot);
3836
4002
  } catch {
3837
4003
  }
3838
4004
  }
@@ -3844,7 +4010,7 @@ Apply these skills first for this assignment.
3844
4010
 
3845
4011
  ${resolved.join("\n\n---\n\n")}` : void 0
3846
4012
  ].filter((section) => Boolean(section));
3847
- return sections.join("\n\n");
4013
+ return { content: sections.join("\n\n"), selected, dropped };
3848
4014
  }
3849
4015
  async function retrieveHostSubagentMemory(deps, getLeaderMode, subCfg, taskContext) {
3850
4016
  const memoryPort = deps.container.safeResolve(TOKENS3.MemoryStore);
@@ -4043,84 +4209,6 @@ function installSubagentEventBridge(opts) {
4043
4209
  };
4044
4210
  }
4045
4211
 
4046
- // src/fleet/host-provider.ts
4047
- import { makeProviderFromConfig, withCatalogCapabilities } from "@wrongstack/providers";
4048
- async function buildHostSubagentProvider(deps, config, overrideId, model) {
4049
- const requestedProviderId = overrideId ?? config.provider;
4050
- const providerId = requestedProviderId === config.provider || config.providers?.[requestedProviderId] !== void 0 || deps.providerRegistry.has(requestedProviderId) ? requestedProviderId : config.provider;
4051
- const newCfg = config.providers?.[providerId] ?? {
4052
- type: providerId,
4053
- apiKey: config.apiKey,
4054
- baseUrl: config.baseUrl
4055
- };
4056
- const cfgWithType = {
4057
- ...newCfg,
4058
- type: providerId,
4059
- ...model ? { model } : {}
4060
- };
4061
- let provider = deps.providerRegistry.has(providerId) ? deps.providerRegistry.create(cfgWithType) : makeProviderFromConfig(providerId, cfgWithType);
4062
- if (deps.modelsRegistry) {
4063
- const resolvedModel = model ?? config.model;
4064
- provider = await withCatalogCapabilities(deps.modelsRegistry, providerId, provider, {
4065
- ...cfgWithType,
4066
- model: resolvedModel
4067
- });
4068
- await refreshRuntimeModelCatalog({
4069
- modelsRegistry: deps.modelsRegistry,
4070
- reason: `${providerId}/${resolvedModel}`
4071
- });
4072
- const mc = await resolveRuntimeMaxContext({
4073
- modelsRegistry: deps.modelsRegistry,
4074
- config,
4075
- provider,
4076
- runtimeProviderConfig: cfgWithType,
4077
- providerId,
4078
- modelId: resolvedModel
4079
- });
4080
- if (mc && mc > 0) provider.capabilities.maxContext = mc;
4081
- }
4082
- return provider;
4083
- }
4084
- async function resolveHostSubagentReasoningConfig(deps, providerId, modelId) {
4085
- if (!deps.modelsRegistry) return void 0;
4086
- try {
4087
- return (await deps.modelsRegistry.getModel(providerId, modelId))?.capabilities.reasoningConfig;
4088
- } catch {
4089
- return void 0;
4090
- }
4091
- }
4092
- function resolveHostSubagentModelSelection(liveConfig, effectiveCfg, matrixTarget) {
4093
- let effProvider = effectiveCfg.provider ?? matrixTarget?.provider ?? liveConfig.provider;
4094
- let effModel = effectiveCfg.model ?? matrixTarget?.model ?? liveConfig.model;
4095
- const modelPolicy = effectiveCfg.modelPolicy;
4096
- const closedModelPolicy = modelPolicy?.strict === true;
4097
- const allowedModels = modelPolicy?.allowed ?? [];
4098
- if (modelPolicy && !allowedModels.some((target) => target.provider === effProvider && target.model === effModel)) {
4099
- const firstAllowed = allowedModels[0];
4100
- if (!firstAllowed) throw new Error(`Agent "${effectiveCfg.role}" has no allowed models.`);
4101
- effProvider = firstAllowed.provider;
4102
- effModel = firstAllowed.model;
4103
- }
4104
- const fallbackProfile = modelPolicy ? void 0 : effectiveCfg.fallbackProfile ?? matrixTarget?.fallbackProfile;
4105
- const runtimeOverride = effectiveCfg.modelRuntime ?? matrixTarget?.modelRuntime;
4106
- const startupTargets = modelPolicy ? [
4107
- { provider: effProvider, model: effModel },
4108
- ...modelPolicy.fallbacks ?? [],
4109
- ...closedModelPolicy || effProvider === liveConfig.provider && effModel === liveConfig.model ? [] : [{ provider: liveConfig.provider, model: liveConfig.model }]
4110
- ] : [
4111
- { provider: effProvider, model: effModel },
4112
- ...effProvider === liveConfig.provider && effModel === liveConfig.model ? [] : [{ provider: liveConfig.provider, model: liveConfig.model }]
4113
- ];
4114
- return {
4115
- effProvider,
4116
- effModel,
4117
- fallbackProfile,
4118
- runtimeOverride,
4119
- closedModelPolicy,
4120
- startupTargets
4121
- };
4122
- }
4123
-
4124
4212
  // src/fleet/host-session-writer.ts
4125
4213
  function createParentSubagentSessionWriter(parentSession) {
4126
4214
  return {
@@ -4269,17 +4357,26 @@ ${message} Falling back to the assigned checkout.` : `${message} Falling back to
4269
4357
  ${audienceMemory.map((text) => `- ${text}`).join("\n")}`
4270
4358
  });
4271
4359
  }
4272
- const roleSkillContent = await resolveHostSubagentSkillContent(
4360
+ const skillResolution = await resolveHostSubagentSkillResolution(
4273
4361
  host.deps,
4274
4362
  host.roster,
4275
4363
  effectiveCfg,
4276
4364
  subagentTools.map((tool) => tool.name)
4277
4365
  );
4278
- if (roleSkillContent) {
4366
+ if (skillResolution.content) {
4279
4367
  for (let index = baseSystem.length - 1; index >= 0; index--) {
4280
4368
  if (baseSystem[index]?.text.includes("# Active Skills")) baseSystem.splice(index, 1);
4281
4369
  }
4282
- baseSystem.push({ type: "text", text: roleSkillContent });
4370
+ baseSystem.push({ type: "text", text: skillResolution.content });
4371
+ }
4372
+ const droppedSkills = Object.entries(skillResolution.dropped);
4373
+ if (droppedSkills.length > 0) {
4374
+ host.deps.events.emit("subagent.skills.dropped", {
4375
+ sessionId: host.deps.session.id,
4376
+ role: effectiveCfg.role,
4377
+ selected: skillResolution.selected,
4378
+ dropped: Object.fromEntries(droppedSkills)
4379
+ });
4283
4380
  }
4284
4381
  const rawRolePrompt = effectiveCfg.systemPromptOverride ?? effectiveCfg.prompt ?? (effectiveCfg.role ? host.roster[effectiveCfg.role]?.prompt : void 0);
4285
4382
  const rolePrompt = rawRolePrompt && effectiveCfg.role ? buildProjectContextualizedPrompt(rawRolePrompt, effectiveCfg.role, projectRoot, {
@@ -4290,7 +4387,7 @@ ${audienceMemory.map((text) => `- ${text}`).join("\n")}`
4290
4387
  }
4291
4388
  const subagentName = effectiveCfg.id ?? effectiveCfg.name ?? `sub_${randomUUID2().slice(0, 8)}`;
4292
4389
  if (effectiveCfg.role) {
4293
- host.recordLearningRole(subagentName, effectiveCfg.role);
4390
+ host.recordLearningRole(subagentName, effectiveCfg.role, skillResolution.selected);
4294
4391
  }
4295
4392
  let subSession;
4296
4393
  if (host.sessionFactory) {
@@ -4347,7 +4444,8 @@ ${audienceMemory.map((text) => `- ${text}`).join("\n")}`
4347
4444
  iterationTimeoutMs: config.tools?.iterationTimeoutMs ?? 12e4,
4348
4445
  maxToolTimeoutMs: config.tools?.maxToolTimeoutMs ?? 3e5,
4349
4446
  perIterationOutputCapBytes: config.tools?.perIterationOutputCapBytes ?? 1e5,
4350
- tracer: void 0
4447
+ tracer: void 0,
4448
+ requireKanbanGovernance: true
4351
4449
  });
4352
4450
  const subagentConfigStore = host.deps.configStore;
4353
4451
  const pipelines = createDefaultPipelines();
@@ -4623,6 +4721,9 @@ var MultiAgentHost = class {
4623
4721
  * Bounded to 20 entries with LRU eviction to prevent unbounded memory growth. */
4624
4722
  acpRunnerCache = new HostAcpRunnerCache();
4625
4723
  learningRoles = new HostLearningRoleTracker();
4724
+ /** Background distillation of captured learning into per-skill addenda. */
4725
+ learningOptimizer = null;
4726
+ learningSwept = false;
4626
4727
  /** Adaptive concurrency controller — created in buildDirector() when config has
4627
4728
  * adaptiveConcurrency.enabled = true. Monitors FleetBus for 429 errors and
4628
4729
  * automatically adjusts maxConcurrent to prevent rate limiting. */
@@ -4688,6 +4789,7 @@ var MultiAgentHost = class {
4688
4789
  async buildDirector() {
4689
4790
  if (this.director) return;
4690
4791
  const config = this.deps.configStore.get();
4792
+ this.sweepLearningOptimization();
4691
4793
  const fleetManager = createHostFleetManager(this.opts);
4692
4794
  this.fleetManager = fleetManager;
4693
4795
  if (this.opts.sessionsRoot && !this.sessionFactory) {
@@ -4959,7 +5061,7 @@ var MultiAgentHost = class {
4959
5061
  sessionFactory: this.sessionFactory,
4960
5062
  filterTools: (allow) => this.filterTools(allow),
4961
5063
  mailboxProjectDir: () => this.mailboxProjectDir(),
4962
- recordLearningRole: (subagentId, role) => this.recordLearningRole(subagentId, role),
5064
+ recordLearningRole: (subagentId, role, skills) => this.recordLearningRole(subagentId, role, skills),
4963
5065
  subagentToolRegistry: (allow) => this.subagentToolRegistry(allow)
4964
5066
  });
4965
5067
  }
@@ -4982,6 +5084,7 @@ var MultiAgentHost = class {
4982
5084
  await this.ensureCoordinator(config);
4983
5085
  const coordinator = this.getCoordinator();
4984
5086
  const acpRunner = await this.buildACPRunner(subagentId);
5087
+ this.recordLearningRole(subagentId, subagentId);
4985
5088
  coordinator.setRunner(acpRunner);
4986
5089
  this.directorRunnerSet = true;
4987
5090
  await coordinator.spawn({
@@ -5184,11 +5287,75 @@ var MultiAgentHost = class {
5184
5287
  emitLifecycleCompleted(taskId, result) {
5185
5288
  emitHostLifecycleCompleted(this.deps.events, this.deps.session.id, taskId, result);
5186
5289
  }
5187
- recordLearningRole(subagentId, role) {
5188
- this.learningRoles.record(subagentId, role);
5290
+ recordLearningRole(subagentId, role, skills = []) {
5291
+ this.learningRoles.record(subagentId, role, skills);
5189
5292
  }
5190
5293
  captureCompletedTaskLearning(result) {
5191
- this.learningRoles.capture(result, this.deps);
5294
+ this.learningRoles.capture(
5295
+ result,
5296
+ this.deps,
5297
+ (role) => this.getLearningOptimizer()?.notifyCaptured(role)
5298
+ );
5299
+ }
5300
+ /**
5301
+ * Lazily built so a session that never spawns a subagent pays nothing, and
5302
+ * so the policy is read from the live config rather than frozen at boot.
5303
+ * Returns null when auto-optimization is switched off.
5304
+ */
5305
+ getLearningOptimizer() {
5306
+ const settings = this.deps.configStore.get().fleet?.learning?.autoOptimize;
5307
+ if (settings?.enabled === false) return null;
5308
+ if (!this.learningOptimizer) {
5309
+ this.learningOptimizer = new LearningOptimizationScheduler({
5310
+ projectRoot: this.deps.projectRoot,
5311
+ getPolicy: () => resolveAutoOptimizePolicy(this.deps.configStore.get().fleet?.learning?.autoOptimize),
5312
+ getLlm: () => this.resolveOptimizerLlm(),
5313
+ onEvent: (event) => {
5314
+ this.deps.events.emit("agent.learning.optimized", {
5315
+ sessionId: this.deps.session.id,
5316
+ role: event.role,
5317
+ trigger: event.trigger,
5318
+ status: event.result?.status ?? "failed",
5319
+ skills: event.result?.skills ?? [],
5320
+ ...event.error ? { error: event.error } : {}
5321
+ });
5322
+ }
5323
+ });
5324
+ }
5325
+ return this.learningOptimizer;
5326
+ }
5327
+ /**
5328
+ * Resolve a model for the distillation pass. Uses the `memory-curator` slot
5329
+ * of the model matrix when one is configured — curating learned knowledge is
5330
+ * exactly that role's job — and the session default otherwise. A failure
5331
+ * here is not fatal: the pass still writes the deterministic skill addenda.
5332
+ */
5333
+ async resolveOptimizerLlm() {
5334
+ try {
5335
+ const config = this.deps.configStore.get();
5336
+ const target = resolveSubagentModelTarget2(config, "memory-curator");
5337
+ const providerId = target?.provider ?? config.provider;
5338
+ const model = target?.model ?? config.model;
5339
+ if (!providerId || !model) return void 0;
5340
+ const provider = await buildHostSubagentProvider(this.deps, config, providerId, model);
5341
+ return { provider, model };
5342
+ } catch {
5343
+ return void 0;
5344
+ }
5345
+ }
5346
+ /**
5347
+ * Evaluate every role with learning data once per session. Without it, a
5348
+ * role that became eligible before this session would wait for its next
5349
+ * capture — which for a rarely-used role can be never.
5350
+ */
5351
+ sweepLearningOptimization() {
5352
+ if (this.learningSwept) return;
5353
+ this.learningSwept = true;
5354
+ if (this.deps.configStore.get().fleet?.learning?.autoOptimize?.sweepOnStart === false) return;
5355
+ try {
5356
+ this.getLearningOptimizer()?.sweep(listProjectAgentRoles(this.deps.projectRoot));
5357
+ } catch {
5358
+ }
5192
5359
  }
5193
5360
  status() {
5194
5361
  return buildFleetHostStatus({
@@ -5285,6 +5452,8 @@ var MultiAgentHost = class {
5285
5452
  * Safe to call multiple times — subsequent calls are no-ops.
5286
5453
  */
5287
5454
  async dispose() {
5455
+ this.learningOptimizer?.dispose();
5456
+ this.learningOptimizer = null;
5288
5457
  this.clearShadowAgent();
5289
5458
  for (const off of this.shadowActivityOffHandles) {
5290
5459
  off();
@@ -7580,7 +7749,8 @@ function createAgent(params) {
7580
7749
  perIterationOutputCapBytes: params.config.tools.perIterationOutputCapBytes,
7581
7750
  tracer: params.tracer,
7582
7751
  logger,
7583
- hookRunner: params.hookRunner
7752
+ hookRunner: params.hookRunner,
7753
+ requireKanbanGovernance: true
7584
7754
  };
7585
7755
  const toolExecutor = new ToolExecutor2(params.tools, toolExecutorOptions);
7586
7756
  void bootstrapMailboxBridgeAtStartup({
@@ -10412,17 +10582,21 @@ function stripQuotes(s) {
10412
10582
 
10413
10583
  // src/slash-commands/agent-improve.ts
10414
10584
  import {
10415
- buildConsolidationInstruction,
10416
- captureLearnedFromAgentOutput,
10585
+ captureLearnedFromAgentOutputDetailed as captureLearnedFromAgentOutputDetailed2,
10417
10586
  getProjectAgentLearnStats,
10418
- isConsolidated,
10587
+ listProjectSkillAugmentations,
10419
10588
  loadConsolidationMetadata,
10420
10589
  loadProjectAgentConfig as loadProjectAgentConfig2,
10421
10590
  loadProjectAgentIdentity,
10422
10591
  loadProjectAgentLearned,
10592
+ loadProjectSkillAugmentation as loadProjectSkillAugmentation2,
10423
10593
  loadRoleKnowledgeManifest,
10594
+ loadSkillAffinity,
10595
+ optimizeProjectAgentLearning,
10424
10596
  refreshProjectAgentIdentity,
10425
10597
  resetProjectAgentIdentity,
10598
+ resolveRoleSkillCandidates as resolveRoleSkillCandidates2,
10599
+ setSkillPinned,
10426
10600
  updateProjectAgentIdentity
10427
10601
  } from "@wrongstack/core/agent-catalog";
10428
10602
  import { color as color11 } from "@wrongstack/core/utils";
@@ -10440,7 +10614,7 @@ function buildAgentImproveCommand(opts) {
10440
10614
  return {
10441
10615
  name: "agent-improve",
10442
10616
  category: "Config",
10443
- description: "Manage project-custom agent identities: show, update, refresh or reset per-role overrides.",
10617
+ description: "Inspect and develop a roster agent for this project: learned directives, per-skill project addenda and the optimization pass.",
10444
10618
  help: [
10445
10619
  "Usage:",
10446
10620
  " /agent-improve [role] Show customization for a role (or all roles)",
@@ -10448,20 +10622,26 @@ function buildAgentImproveCommand(opts) {
10448
10622
  " /agent-improve [role] update Update identity + learned content",
10449
10623
  " /agent-improve [role] refresh Reset identity + learned to empty templates",
10450
10624
  " /agent-improve [role] capture Scan last output for ## LEARNED blocks and persist them",
10451
- " /agent-improve [role] consolidate Optimize raw learned entries into a consolidated document",
10625
+ " /agent-improve [role] optimize Distil learning into skill addenda + a consolidated doc",
10626
+ " /agent-improve [role] skills Show the role's skills, affinity and project addenda",
10627
+ " /agent-improve [role] skills <skill> Show one skill's project addendum",
10628
+ " /agent-improve [role] skills <skill> pin|unpin Always/never keep this skill loaded",
10452
10629
  " /agent-improve [role] reset Delete ALL custom files for this role",
10453
10630
  " /agent-improve * reset Delete ALL custom files for every role",
10454
10631
  "",
10455
10632
  "Use without arguments to see which roles have project-customizations.",
10456
10633
  "",
10457
- "Knowledge automation:",
10458
- " Agents output a ## LEARNED section in their response to persist",
10459
- " project-specific patterns. The runtime captures these automatically.",
10460
- ' Use "capture" to manually re-scan any text for LEARNED blocks.',
10461
- ' Use "consolidate" to synthesize all raw entries into a single',
10462
- " narrowly-scoped document that replaces raw entries in the agent prompt.",
10634
+ "Learning loop (runs on its own):",
10635
+ " Agents end a run with a ## LEARNED block, optionally tagged with the",
10636
+ " skill it refines: `## LEARNED [skill: testing]`. The runtime captures it,",
10637
+ " routes it to that skill, and a background pass distils it into that skill\u2019s",
10638
+ " project addendum \u2014 injected beneath the bundled skill body on the next spawn.",
10639
+ ' Capture also runs on failed tasks. Use "capture" to re-scan the last turn',
10640
+ ' by hand and "optimize" to force a distillation early.',
10463
10641
  "",
10464
- "Files live under: .wrongstack/agents/<role>/"
10642
+ "Files live under: .wrongstack/agents/<role>/ (committed; skills/affinity.json",
10643
+ "and archive/ stay local). Disable the automatic pass with",
10644
+ "fleet.learning.autoOptimize.enabled = false."
10465
10645
  ].join("\n"),
10466
10646
  async run(args) {
10467
10647
  const parts = args.trim().split(/\s+/).filter(Boolean);
@@ -10500,7 +10680,11 @@ ${lines.join("\n")}`;
10500
10680
  const idText = loadProjectAgentIdentity(role, projectRoot);
10501
10681
  const learned = loadProjectAgentLearned(role, projectRoot);
10502
10682
  const kn = loadRoleKnowledgeManifest(role, projectRoot);
10683
+ const developedSkills = listProjectSkillAugmentations(role, projectRoot);
10503
10684
  const lines = [`${color11.bold(role)} project identity:`];
10685
+ if (developedSkills.length > 0) {
10686
+ lines.push(` skills developed: ${developedSkills.join(", ")}`);
10687
+ }
10504
10688
  if (cfg) lines.push(` config: ${JSON.stringify(cfg)}`);
10505
10689
  if (kn)
10506
10690
  lines.push(
@@ -10535,33 +10719,108 @@ Or edit files directly under .wrongstack/agents/${role}/`
10535
10719
  case "capture": {
10536
10720
  const storedOutput = opts.context?.meta["lastAgentOutput"];
10537
10721
  const recentOutput = typeof storedOutput === "string" ? storedOutput : "";
10538
- const captured = captureLearnedFromAgentOutput(recentOutput, role, projectRoot, true);
10539
- if (captured > 0) {
10540
- const msg = `Captured ${captured} learned item(s) for role "${role}". Use /agent-improve ${role} to see them.`;
10722
+ if (!recentOutput) {
10723
+ return {
10724
+ message: "No agent output recorded yet in this session. Run a turn first, then re-run capture."
10725
+ };
10726
+ }
10727
+ const result = captureLearnedFromAgentOutputDetailed2(
10728
+ recentOutput,
10729
+ role,
10730
+ projectRoot,
10731
+ true
10732
+ );
10733
+ if (result.captured > 0) {
10734
+ const routed = result.skills?.length ? ` Routed to skill(s): ${result.skills.join(", ")}.` : "";
10735
+ const msg = `Captured ${result.captured} learned item(s) for role "${role}".${routed} Use /agent-improve ${role} to see them.`;
10541
10736
  opts.renderer.write(msg);
10542
10737
  return { message: msg };
10543
10738
  }
10544
10739
  return {
10545
- message: `No ## LEARNED blocks found in recent output for role "${role}".`
10740
+ message: result.reason ?? `No ## LEARNED blocks found in recent output for role "${role}" (status: ${result.status}).`
10546
10741
  };
10547
10742
  }
10743
+ case "optimize":
10548
10744
  case "consolidate": {
10549
10745
  const stats = getProjectAgentLearnStats(role, projectRoot);
10550
10746
  if (stats.entryCount === 0) {
10551
- const msg = `No raw learned entries for role "${role}" to consolidate.`;
10747
+ const msg = `No raw learned entries for role "${role}" to optimize.`;
10552
10748
  opts.renderer.write(msg);
10553
10749
  return { message: msg };
10554
10750
  }
10555
- const { instruction } = buildConsolidationInstruction(role, projectRoot);
10556
- const prompt = `Optimize what the "${role}" agent has learned for its skills. ${instruction}`;
10557
- const consolidatedAlready = isConsolidated(role, projectRoot);
10558
- const meta = loadConsolidationMetadata(role, projectRoot);
10559
- const summary = `${color11.cyan(role)}: ${stats.entryCount} raw entries (${stats.totalBytes}B)` + (consolidatedAlready && meta ? ` \xB7 last consolidated ${meta.consolidatedAt.slice(0, 10)} (${meta.sourceBytes}B \u2192 ${meta.consolidatedBytes}B)` : " \xB7 no prior consolidation") + "\n\nSending consolidation instruction to the agent...";
10560
- opts.renderer.write(summary);
10561
- return {
10562
- message: summary,
10563
- runText: prompt
10564
- };
10751
+ const before = loadConsolidationMetadata(role, projectRoot);
10752
+ opts.renderer.write(
10753
+ `${color11.cyan(role)}: optimizing ${stats.entryCount} directive(s) (${stats.totalBytes}B)` + (before ? ` \xB7 last optimized ${before.consolidatedAt.slice(0, 10)}` : " \xB7 no prior optimization") + "\u2026"
10754
+ );
10755
+ const llm = opts.llmProvider && opts.llmModel ? { provider: opts.llmProvider, model: opts.llmModel } : void 0;
10756
+ const result = await optimizeProjectAgentLearning(role, projectRoot, {
10757
+ ...llm ? { llm } : {},
10758
+ trigger: "manual"
10759
+ });
10760
+ const skillNote = result.skills.length ? ` Skill addenda refreshed: ${result.skills.join(", ")}.` : "";
10761
+ switch (result.status) {
10762
+ case "optimized": {
10763
+ const after = loadConsolidationMetadata(role, projectRoot);
10764
+ const msg = `Optimized "${role}": ${result.rawEntryCount} directive(s) \u2192 ${after?.consolidatedBytes ?? 0}B consolidated.` + skillNote + (result.pruned ? " Raw buffer archived and reset." : "");
10765
+ opts.renderer.write(msg);
10766
+ return { message: msg };
10767
+ }
10768
+ case "empty-synthesis":
10769
+ return {
10770
+ message: `Model "${result.model}" returned an empty document; the existing knowledge for "${role}" was left untouched.${skillNote}`
10771
+ };
10772
+ case "failed":
10773
+ return { message: `Optimization failed for "${role}": ${result.error}${skillNote}` };
10774
+ case "no-llm":
10775
+ return {
10776
+ message: `No active model; routing the "${role}" consolidation through the agent.${skillNote}`,
10777
+ runText: `${result.instruction}
10778
+
10779
+ ---
10780
+
10781
+ When the document is ready, save it to .wrongstack/agents/${role}/consolidated.md \u2014 or re-run the optimization with a model configured so the runtime persists it for you.`
10782
+ };
10783
+ default:
10784
+ return { message: `Nothing to optimize for "${role}".` };
10785
+ }
10786
+ }
10787
+ case "skills": {
10788
+ const candidates = resolveRoleSkillCandidates2(role, projectRoot);
10789
+ const developed = listProjectSkillAugmentations(role, projectRoot);
10790
+ const affinity = loadSkillAffinity(role, projectRoot);
10791
+ const target = parts[2];
10792
+ if (target && parts[3]) {
10793
+ const skillAction = parts[3];
10794
+ if (skillAction !== "pin" && skillAction !== "unpin") {
10795
+ return { message: `Unknown skill action "${skillAction}". Use pin or unpin.` };
10796
+ }
10797
+ setSkillPinned(role, target, skillAction === "pin", projectRoot);
10798
+ const msg2 = `${skillAction === "pin" ? "Pinned" : "Unpinned"} skill "${target}" for role "${role}".`;
10799
+ opts.renderer.write(msg2);
10800
+ return { message: msg2 };
10801
+ }
10802
+ if (target) {
10803
+ const body = loadProjectSkillAugmentation2(role, target, projectRoot);
10804
+ const msg2 = body ? `${color11.bold(`${role} \xB7 ${target}`)}
10805
+
10806
+ ${body}` : `No project addendum for skill "${target}" on role "${role}" yet.`;
10807
+ opts.renderer.write(msg2);
10808
+ return { message: msg2 };
10809
+ }
10810
+ const skillLines = candidates.map((skill) => {
10811
+ const entry = affinity.entries[skill];
10812
+ const marks = [
10813
+ developed.includes(skill) ? "developed" : "",
10814
+ entry?.pinned ? "pinned" : "",
10815
+ entry?.learned ? `${entry.learned} learned` : "",
10816
+ entry ? `${entry.succeeded}\u2713/${entry.failed}\u2717 of ${entry.loaded} loads` : "unused"
10817
+ ].filter(Boolean);
10818
+ return ` ${color11.cyan(skill.padEnd(22))} ${marks.join(" \xB7 ")}`;
10819
+ });
10820
+ const msg = candidates.length ? `Skills for ${color11.bold(role)}:
10821
+ ${skillLines.join("\n")}` : `Role "${role}" has no curated skills.`;
10822
+ opts.renderer.write(msg);
10823
+ return { message: msg };
10565
10824
  }
10566
10825
  case "reset": {
10567
10826
  const removed = resetProjectAgentIdentity(role === "*" ? void 0 : role, projectRoot);
@@ -10577,7 +10836,7 @@ Or edit files directly under .wrongstack/agents/${role}/`
10577
10836
  }
10578
10837
  default:
10579
10838
  return {
10580
- message: `Unknown action "${action}". Use: show, update, refresh, capture, consolidate, reset, or reset-all.`
10839
+ message: `Unknown action "${action}". Use: show, update, refresh, capture, optimize, skills, reset, or reset-all.`
10581
10840
  };
10582
10841
  }
10583
10842
  }
@@ -11122,7 +11381,7 @@ function buildBrainCommand(opts) {
11122
11381
  const trimmed = args.trim();
11123
11382
  const [sub, ...rest] = trimmed.split(/\s+/);
11124
11383
  const subcommand = (sub ?? "").toLowerCase();
11125
- const applyPatch = async (patch, describe) => {
11384
+ const applyPatch = async (patch, describe2) => {
11126
11385
  if (!opts.brainRuntime) {
11127
11386
  const msg2 = "The Brain runtime is not available in this session.";
11128
11387
  opts.renderer.writeWarning(msg2);
@@ -11132,7 +11391,7 @@ function buildBrainCommand(opts) {
11132
11391
  const { snapshot, persisted } = opts.brainRuntime.apply(patch);
11133
11392
  const result = await persisted;
11134
11393
  const note = result.ok ? color14.dim(" \u2014 saved to the active profile config") : ` \u2014 applied live but NOT saved: ${result.error ?? "unknown error"}`;
11135
- const msg2 = `${describe(snapshot)}${note}`;
11394
+ const msg2 = `${describe2(snapshot)}${note}`;
11136
11395
  if (result.ok) opts.renderer.write(msg2);
11137
11396
  else opts.renderer.writeWarning(msg2);
11138
11397
  return { message: msg2 };
@@ -11941,6 +12200,7 @@ function buildBtwCommand(opts) {
11941
12200
  }
11942
12201
 
11943
12202
  // src/slash-commands/clear.ts
12203
+ import { resetCaptureWindows } from "@wrongstack/core/agent-catalog";
11944
12204
  import { createContextEvidenceState } from "@wrongstack/core/utils";
11945
12205
 
11946
12206
  // src/slash-commands/interrupt.ts
@@ -12040,6 +12300,7 @@ function buildClearCommand(opts) {
12040
12300
  if (opts.sessionStore) {
12041
12301
  await opts.sessionStore.clearHistory(ctx?.session.id ?? "");
12042
12302
  }
12303
+ resetCaptureWindows();
12043
12304
  opts.onClear?.();
12044
12305
  await opts.onNewSession?.();
12045
12306
  opts.renderer.clear();
@@ -17196,6 +17457,8 @@ function stripQuotes2(value) {
17196
17457
  import { color as color31 } from "@wrongstack/core/utils";
17197
17458
  import {
17198
17459
  areDependenciesMet,
17460
+ evaluateContractGraph,
17461
+ evaluateContractGraphReadiness,
17199
17462
  findBlockedTasks
17200
17463
  } from "@wrongstack/kanban";
17201
17464
  var HEADING = (s) => color31.bold(s);
@@ -17351,6 +17614,19 @@ function formatTaskDetail(board, task) {
17351
17614
  if (metric.notes) lines.push(` ${DIM(metric.notes)}`);
17352
17615
  }
17353
17616
  }
17617
+ const readiness = evaluateContractGraphReadiness(board, task.id);
17618
+ const completion = evaluateContractGraph(board, task.id);
17619
+ lines.push("");
17620
+ lines.push(HEADING(" Contract Map:"));
17621
+ lines.push(
17622
+ ` ${readiness.ready ? color31.green("\u25CF Start ready") : color31.yellow(`\u25B3 ${readiness.issues.length} setup gaps`)} \xB7 ${completion.issues.length === 0 ? color31.green("closed") : color31.yellow(`${completion.issues.length} completion open`)}`
17623
+ );
17624
+ for (const issue of readiness.issues.slice(0, 5)) {
17625
+ lines.push(` ${color31.yellow("!")} ${issue.message}`);
17626
+ }
17627
+ if (readiness.issues.length > 5) {
17628
+ lines.push(` ${DIM(`+${readiness.issues.length - 5} more setup gaps`)}`);
17629
+ }
17354
17630
  if (task.estimatedHours || task.actualHours) {
17355
17631
  lines.push("");
17356
17632
  lines.push(
@@ -21940,6 +22216,7 @@ import {
21940
22216
  setPlanItemStatus
21941
22217
  } from "@wrongstack/core/storage";
21942
22218
  import { formatTaskList, formatTodosList } from "@wrongstack/core/utils";
22219
+ import { todoTool } from "@wrongstack/tools";
21943
22220
  function findPlanItemIndex(plan, query) {
21944
22221
  const asNum = Number.parseInt(query, 10);
21945
22222
  if (!Number.isNaN(asNum) && asNum >= 1 && asNum <= plan.items.length) return asNum - 1;
@@ -22043,6 +22320,7 @@ ${formatTaskList(taskFile.tasks)}`,
22043
22320
  let outputMessage = "";
22044
22321
  let outputError;
22045
22322
  let outputExtra = {};
22323
+ let todosToReplace = null;
22046
22324
  const finalPlan = await mutatePlan(planPath, sessionId, async (plan) => {
22047
22325
  switch (verb) {
22048
22326
  case "add": {
@@ -22087,6 +22365,18 @@ ${formatPlan(updated)}`;
22087
22365
  outputError = { code: "usage", message: outputMessage };
22088
22366
  return plan;
22089
22367
  }
22368
+ const itemIdx = findPlanItemIndex(plan, restJoined);
22369
+ const item = itemIdx >= 0 ? plan.items[itemIdx] : void 0;
22370
+ if (!item) {
22371
+ outputMessage = `No plan item matched "${restJoined}".`;
22372
+ outputError = { code: "item_not_found", message: outputMessage };
22373
+ return plan;
22374
+ }
22375
+ if (item.status !== "done") {
22376
+ outputMessage = `Plan item "${item.title}" is unfinished and cannot be removed. Complete it first.`;
22377
+ outputError = { code: "unfinished_item", message: outputMessage };
22378
+ return plan;
22379
+ }
22090
22380
  const updated = removePlanItem(plan, restJoined);
22091
22381
  outputMessage = formatPlan(updated);
22092
22382
  return updated;
@@ -22114,7 +22404,7 @@ ${formatPlan(updated)}`;
22114
22404
  outputError = { code: "item_not_found", message: outputMessage };
22115
22405
  return plan;
22116
22406
  }
22117
- opts.context?.state?.replaceTodos(derived.todos);
22407
+ todosToReplace = derived.todos;
22118
22408
  const label = verb === "derive" ? "Derived" : "Promoted to";
22119
22409
  outputMessage = `${label} ${derived.todos.length} todo(s):
22120
22410
  ${formatTodosList(derived.todos)}
@@ -22152,6 +22442,12 @@ ${formatPlan(updated)}`;
22152
22442
  return plan;
22153
22443
  }
22154
22444
  case "clear": {
22445
+ const unfinished = plan.items.filter((item) => item.status !== "done");
22446
+ if (unfinished.length > 0) {
22447
+ outputMessage = `Plan contains unfinished items and cannot be cleared: ${unfinished.map((item) => item.id).join(", ")}.`;
22448
+ outputError = { code: "unfinished_items", message: outputMessage };
22449
+ return plan;
22450
+ }
22155
22451
  const updated = clearPlan(plan);
22156
22452
  outputMessage = "Plan cleared.";
22157
22453
  return updated;
@@ -22162,6 +22458,11 @@ ${formatPlan(updated)}`;
22162
22458
  return plan;
22163
22459
  }
22164
22460
  });
22461
+ if (todosToReplace && opts.context) {
22462
+ await todoTool.execute({ todos: todosToReplace }, opts.context, {
22463
+ signal: AbortSignal.timeout(3e4)
22464
+ });
22465
+ }
22165
22466
  const payload = outputError ? { ok: false, plan: finalPlan, error: outputError } : { ok: true, plan: finalPlan, ...outputExtra };
22166
22467
  return result(outputMessage, payload, json);
22167
22468
  }
@@ -25287,6 +25588,134 @@ function buildWebuiCommand() {
25287
25588
  };
25288
25589
  }
25289
25590
 
25591
+ // src/slash-commands/theme.ts
25592
+ import { color as color46, writeOut as writeOut3 } from "@wrongstack/core/utils";
25593
+ var THEME_OPTIONS = [
25594
+ { id: "catppuccin", name: "Catppuccin Mocha", desc: "Soft pastel dark theme (Default)" },
25595
+ { id: "tokyo-night", name: "Tokyo Night", desc: "Deep violet, neon orange & cyan" },
25596
+ { id: "nord", name: "Nord", desc: "Cool arctic blue & slate pastels" },
25597
+ { id: "cyberpunk", name: "Cyberpunk Neon", desc: "High-contrast magenta, cyan & yellow" },
25598
+ { id: "dracula", name: "Dracula", desc: "Vibrant purple, pink & green" },
25599
+ { id: "gruvbox-dark", name: "Gruvbox Dark", desc: "Warm earthy retro \u2014 orange, olive & aqua" },
25600
+ { id: "solarized-dark", name: "Solarized Dark", desc: "Base16 classic \u2014 teal & ochre precision" },
25601
+ { id: "one-dark", name: "One Dark", desc: "Atom's iconic palette \u2014 blue-led, warm accents" },
25602
+ { id: "monokai", name: "Monokai", desc: "Sublime classic \u2014 vivid magenta, cyan & lime" },
25603
+ { id: "rose-pine", name: "Ros\xE9 Pine", desc: "Aesthetic pine & foam \u2014 soft evening pastels" },
25604
+ { id: "kanagawa", name: "Kanagawa", desc: "Hokusai-inspired waves \u2014 sumi ink on washi" },
25605
+ { id: "ayu-dark", name: "Ayu Dark", desc: "Simple pleasant dark \u2014 warm orange + cool blue" },
25606
+ { id: "everforest", name: "Everforest", desc: "Green-based comfort \u2014 forest greens & warm tans" },
25607
+ { id: "night-owl", name: "Night Owl", desc: "Sarah Drasner's night \u2014 deep navy + bold accents" },
25608
+ { id: "synthwave", name: "Synthwave '84", desc: "Hot pink + neon cyan on deep purple" }
25609
+ ];
25610
+ async function runThemePicker(reader, activeId) {
25611
+ let cursor = THEME_OPTIONS.findIndex((p) => p.id === activeId);
25612
+ if (cursor < 0) cursor = 0;
25613
+ const render = (currentCursor) => {
25614
+ const lines = [];
25615
+ lines.push(`
25616
+ ${color46.bold(color46.amber("WrongStack") + color46.dim(" \u2014 TUI Theme Selection"))}
25617
+ `);
25618
+ lines.push(color46.dim(" \u2191\u2193 navigate Enter select q quit\n"));
25619
+ lines.push("");
25620
+ for (const [i, p] of THEME_OPTIONS.entries()) {
25621
+ const mark = p.id === activeId ? color46.green(" [active]") : "";
25622
+ const prefix = i === currentCursor ? color46.bold("\u276F ") : " ";
25623
+ const name = i === currentCursor ? color46.bold(p.name) : p.name;
25624
+ lines.push(` ${prefix}${name.padEnd(18)} ${color46.dim(p.desc)}${mark}`);
25625
+ }
25626
+ lines.push("");
25627
+ return lines.join("\n");
25628
+ };
25629
+ writeOut3(render(cursor));
25630
+ const options = [
25631
+ { key: "\x1B[A", label: "\u2191", value: "up" },
25632
+ { key: "\x1B[B", label: "\u2193", value: "down" },
25633
+ { key: "\r", label: "Enter", value: "enter" },
25634
+ { key: "q", label: "q", value: "quit" }
25635
+ ];
25636
+ while (true) {
25637
+ const answer = await reader.readKey("", options);
25638
+ if (answer === "quit") return void 0;
25639
+ if (answer === "enter") return THEME_OPTIONS[cursor]?.id ?? THEME_OPTIONS[0].id;
25640
+ if (answer === "up") {
25641
+ cursor = cursor > 0 ? cursor - 1 : THEME_OPTIONS.length - 1;
25642
+ } else if (answer === "down") {
25643
+ cursor = cursor < THEME_OPTIONS.length - 1 ? cursor + 1 : 0;
25644
+ }
25645
+ writeOut3("\x1B[J");
25646
+ writeOut3(render(cursor));
25647
+ }
25648
+ }
25649
+ function buildThemeCommand(opts) {
25650
+ return {
25651
+ name: "theme",
25652
+ category: "Config",
25653
+ description: "Switch or select the TUI color theme preset interactively",
25654
+ argsHint: "[catppuccin | tokyo-night | nord | cyberpunk | dracula | gruvbox-dark | solarized-dark | one-dark | monokai | rose-pine | kanagawa | ayu-dark | everforest | night-owl | synthwave]",
25655
+ help: [
25656
+ "Usage:",
25657
+ " /theme Interactive menu selection or view available theme presets",
25658
+ " /theme <preset> Switch directly to a theme preset",
25659
+ "",
25660
+ "Available presets:",
25661
+ " catppuccin, tokyo-night, nord, cyberpunk, dracula,",
25662
+ " gruvbox-dark, solarized-dark, one-dark, monokai, rose-pine,",
25663
+ " kanagawa, ayu-dark, everforest, night-owl, synthwave"
25664
+ ].join("\n"),
25665
+ async run(args) {
25666
+ const validPresets = THEME_OPTIONS.map((t) => t.id);
25667
+ const currentConfig = opts.configStore?.get();
25668
+ const activePreset = currentConfig?.themePreset ?? "catppuccin";
25669
+ if (!args.trim()) {
25670
+ if (opts.inputReader) {
25671
+ const selected = await runThemePicker(opts.inputReader, activePreset);
25672
+ if (!selected) {
25673
+ return { message: "Theme selection cancelled." };
25674
+ }
25675
+ if (opts.configStore) {
25676
+ try {
25677
+ opts.configStore.update({ themePreset: selected });
25678
+ } catch {
25679
+ }
25680
+ }
25681
+ return {
25682
+ message: color46.green(`Switched TUI theme preset to "${selected}" (saved to config).`),
25683
+ metadata: { themePreset: selected }
25684
+ };
25685
+ }
25686
+ const lines = [
25687
+ color46.bold(`Current TUI theme: ${activePreset}`),
25688
+ "",
25689
+ color46.bold("Available Theme Presets:")
25690
+ ];
25691
+ for (const t of THEME_OPTIONS) {
25692
+ const mark = t.id === activePreset ? color46.green(" [active]") : "";
25693
+ lines.push(` \u2022 ${color46.bold(t.id.padEnd(14))} ${t.desc}${mark}`);
25694
+ }
25695
+ lines.push("");
25696
+ lines.push(color46.dim("Usage: /theme <preset>"));
25697
+ return { message: lines.join("\n") };
25698
+ }
25699
+ const preset = args.trim().toLowerCase();
25700
+ if (!validPresets.includes(preset)) {
25701
+ return {
25702
+ message: `Unknown theme preset "${preset}". Available options: ${validPresets.join(", ")}`
25703
+ };
25704
+ }
25705
+ if (opts.configStore) {
25706
+ try {
25707
+ opts.configStore.update({ themePreset: preset });
25708
+ } catch {
25709
+ }
25710
+ }
25711
+ return {
25712
+ message: color46.green(`Switched TUI theme preset to "${preset}" (saved to config).`),
25713
+ metadata: { themePreset: preset }
25714
+ };
25715
+ }
25716
+ };
25717
+ }
25718
+
25290
25719
  // src/slash-commands/agents.ts
25291
25720
  import { noOpVault as noOpVault7 } from "@wrongstack/core/security";
25292
25721
  function formatAgentLine(a) {
@@ -25528,7 +25957,7 @@ ${lines.join("\n")}` };
25528
25957
  // src/slash-commands/hq.ts
25529
25958
  import { readHqRuntimeFileSync, resolveHqConfig, resolveHqDataDir } from "@wrongstack/core/hq";
25530
25959
  import { noOpVault as noOpVault8 } from "@wrongstack/core/security";
25531
- import { color as color46 } from "@wrongstack/core/utils";
25960
+ import { color as color47 } from "@wrongstack/core/utils";
25532
25961
  function maskToken(t) {
25533
25962
  if (t.length <= 10) return `${t.slice(0, 2)}\u2026(${t.length})`;
25534
25963
  return `${t.slice(0, 6)}\u2026${t.slice(-4)} (${t.length} chars)`;
@@ -25539,12 +25968,12 @@ async function probeHq(url) {
25539
25968
  const timer = setTimeout(() => ctrl.abort(), 2500);
25540
25969
  const res = await fetch(url, { signal: ctrl.signal, redirect: "manual" }).catch(() => null);
25541
25970
  clearTimeout(timer);
25542
- if (!res) return color46.red("unreachable");
25543
- if (res.ok) return color46.green("reachable");
25544
- if (res.status === 401) return color46.green("reachable") + color46.dim(" (token required)");
25545
- return color46.amber(`reachable (HTTP ${res.status})`);
25971
+ if (!res) return color47.red("unreachable");
25972
+ if (res.ok) return color47.green("reachable");
25973
+ if (res.status === 401) return color47.green("reachable") + color47.dim(" (token required)");
25974
+ return color47.amber(`reachable (HTTP ${res.status})`);
25546
25975
  } catch {
25547
- return color46.red("unreachable");
25976
+ return color47.red("unreachable");
25548
25977
  }
25549
25978
  }
25550
25979
  function buildHqCommand(opts) {
@@ -25578,7 +26007,7 @@ function buildHqCommand(opts) {
25578
26007
  const { cmd, rest } = parseSubcommand(args);
25579
26008
  const sub = cmd;
25580
26009
  if (!opts.configStore || !opts.paths) {
25581
- return { message: `${color46.red("\u2717")} HQ config is unavailable in this surface.` };
26010
+ return { message: `${color47.red("\u2717")} HQ config is unavailable in this surface.` };
25582
26011
  }
25583
26012
  const persistDeps = {
25584
26013
  configStore: opts.configStore,
@@ -25592,14 +26021,14 @@ function buildHqCommand(opts) {
25592
26021
  const url = (rest[0] ?? "").trim();
25593
26022
  const token = rest.slice(1).join(" ").trim();
25594
26023
  if (!url) {
25595
- return { message: `${color46.amber("Usage:")} /hq set <http://host:3499> [client-token]` };
26024
+ return { message: `${color47.amber("Usage:")} /hq set <http://host:3499> [client-token]` };
25596
26025
  }
25597
26026
  try {
25598
26027
  const parsed = new URL(url);
25599
26028
  if (parsed.protocol !== "http:" && parsed.protocol !== "https:") throw new Error("proto");
25600
26029
  } catch {
25601
26030
  return {
25602
- message: `${color46.red("Invalid URL:")} ${url} ${color46.dim("(expected http://host:3499)")}`
26031
+ message: `${color47.red("Invalid URL:")} ${url} ${color47.dim("(expected http://host:3499)")}`
25603
26032
  };
25604
26033
  }
25605
26034
  await persistConfigSetting(persistDeps, (cfg) => {
@@ -25611,16 +26040,16 @@ function buildHqCommand(opts) {
25611
26040
  });
25612
26041
  const reach = await probeHq(url);
25613
26042
  const tokLine = token ? `
25614
- token: ${color46.dim(maskToken(token))}` : "";
26043
+ token: ${color47.dim(maskToken(token))}` : "";
25615
26044
  return {
25616
- message: `${color46.green("\u2713")} HQ set \u2192 ${color46.cyan(url)}${tokLine}
26045
+ message: `${color47.green("\u2713")} HQ set \u2192 ${color47.cyan(url)}${tokLine}
25617
26046
  status: ${reach}
25618
- ${color46.dim("Connects on the next session start.")}`
26047
+ ${color47.dim("Connects on the next session start.")}`
25619
26048
  };
25620
26049
  }
25621
26050
  if (sub === "token") {
25622
26051
  const token = rest.join(" ").trim();
25623
- if (!token) return { message: `${color46.amber("Usage:")} /hq token <client-token>` };
26052
+ if (!token) return { message: `${color47.amber("Usage:")} /hq token <client-token>` };
25624
26053
  await persistConfigSetting(persistDeps, (cfg) => {
25625
26054
  const hq = cfg.hq ?? {};
25626
26055
  hq.token = token;
@@ -25628,14 +26057,14 @@ function buildHqCommand(opts) {
25628
26057
  cfg.hq = hq;
25629
26058
  });
25630
26059
  return {
25631
- message: `${color46.green("\u2713")} HQ client token saved ${color46.dim(maskToken(token))}`
26060
+ message: `${color47.green("\u2713")} HQ client token saved ${color47.dim(maskToken(token))}`
25632
26061
  };
25633
26062
  }
25634
26063
  if (sub === "raw") {
25635
26064
  const mode = (rest[0] ?? "").trim().toLowerCase();
25636
26065
  if (mode !== "on" && mode !== "off") {
25637
26066
  return {
25638
- message: `${color46.amber("Usage:")} /hq raw on|off ${color46.dim("(publish raw chat/tool content to HQ)")}`
26067
+ message: `${color47.amber("Usage:")} /hq raw on|off ${color47.dim("(publish raw chat/tool content to HQ)")}`
25639
26068
  };
25640
26069
  }
25641
26070
  const on = mode === "on";
@@ -25645,8 +26074,8 @@ function buildHqCommand(opts) {
25645
26074
  cfg.hq = hq;
25646
26075
  });
25647
26076
  return {
25648
- message: `${color46.green("\u2713")} HQ raw content \u2192 ${on ? color46.amber("on (unredacted)") : color46.dim("off (redacted)")}
25649
- ${color46.dim("Applies to sessions started after this change. Only enable for HQ servers you trust.")}`
26077
+ message: `${color47.green("\u2713")} HQ raw content \u2192 ${on ? color47.amber("on (unredacted)") : color47.dim("off (redacted)")}
26078
+ ${color47.dim("Applies to sessions started after this change. Only enable for HQ servers you trust.")}`
25650
26079
  };
25651
26080
  }
25652
26081
  if (sub === "on" || sub === "off") {
@@ -25657,29 +26086,29 @@ function buildHqCommand(opts) {
25657
26086
  cfg.hq = hq;
25658
26087
  });
25659
26088
  return {
25660
- message: `${color46.green("\u2713")} HQ publishing \u2192 ${on ? color46.cyan("on") : color46.dim("off")}`
26089
+ message: `${color47.green("\u2713")} HQ publishing \u2192 ${on ? color47.cyan("on") : color47.dim("off")}`
25661
26090
  };
25662
26091
  }
25663
26092
  if (sub === "clear") {
25664
26093
  await persistConfigSetting(persistDeps, (cfg) => {
25665
26094
  delete cfg.hq;
25666
26095
  });
25667
- return { message: `${color46.green("\u2713")} HQ configuration cleared.` };
26096
+ return { message: `${color47.green("\u2713")} HQ configuration cleared.` };
25668
26097
  }
25669
26098
  if (sub === "" || sub === "status") {
25670
26099
  const dataDir = resolveHqDataDir(currentHq?.dataDir);
25671
26100
  const runtime = readHqRuntimeFileSync(dataDir);
25672
26101
  const resolved = resolveHqConfig({ config: currentHq });
25673
- const lines = [`${color46.bold("\u{1F4CB} WrongStack HQ \u2014 connection")}`, ""];
26102
+ const lines = [`${color47.bold("\u{1F4CB} WrongStack HQ \u2014 connection")}`, ""];
25674
26103
  if (!resolved) {
25675
26104
  lines.push(
25676
- ` ${color46.dim("Not configured.")} Use ${color46.cyan("/hq set <url> [token]")} to connect,`
26105
+ ` ${color47.dim("Not configured.")} Use ${color47.cyan("/hq set <url> [token]")} to connect,`
25677
26106
  );
25678
- lines.push(` or run ${color46.cyan("wstack --hq")} locally (auto-discovered).`);
26107
+ lines.push(` or run ${color47.cyan("wstack --hq")} locally (auto-discovered).`);
25679
26108
  if (runtime) {
25680
26109
  lines.push("");
25681
26110
  lines.push(
25682
- ` ${color46.green("A local HQ is running")} at ${color46.cyan(runtime.url)} ${color46.dim("(start a new session to attach)")}`
26111
+ ` ${color47.green("A local HQ is running")} at ${color47.cyan(runtime.url)} ${color47.dim("(start a new session to attach)")}`
25683
26112
  );
25684
26113
  }
25685
26114
  const message = lines.join("\n");
@@ -25687,35 +26116,35 @@ function buildHqCommand(opts) {
25687
26116
  }
25688
26117
  if (resolved.discover && !runtime) {
25689
26118
  lines.push(
25690
- ` mode: ${color46.cyan("auto-discovery")} ${color46.dim("(no local HQ running yet)")}`
26119
+ ` mode: ${color47.cyan("auto-discovery")} ${color47.dim("(no local HQ running yet)")}`
25691
26120
  );
25692
26121
  lines.push(
25693
- ` ${color46.dim("This session will attach automatically when `wstack --hq` starts")}`
26122
+ ` ${color47.dim("This session will attach automatically when `wstack --hq` starts")}`
25694
26123
  );
25695
- lines.push(` ${color46.dim(`on this machine (watching ${dataDir}).`)}`);
25696
- lines.push(` ${color46.dim("Disable with WRONGSTACK_HQ_ENABLED=0 or /hq off.")}`);
26124
+ lines.push(` ${color47.dim(`on this machine (watching ${dataDir}).`)}`);
26125
+ lines.push(` ${color47.dim("Disable with WRONGSTACK_HQ_ENABLED=0 or /hq off.")}`);
25697
26126
  return { message: lines.join("\n") };
25698
26127
  }
25699
26128
  const source = process.env["WRONGSTACK_HQ_URL"] ? "WRONGSTACK_HQ_URL env" : currentHq?.url ? "config.json" : runtime ? `local HQ marker (pid ${runtime.pid ?? "?"})` : "default";
25700
- lines.push(` url: ${color46.cyan(resolved.url)}`);
26129
+ lines.push(` url: ${color47.cyan(resolved.url)}`);
25701
26130
  lines.push(
25702
- ` enabled: ${resolved.enabled === false ? color46.dim("false") : color46.green("true")}`
26131
+ ` enabled: ${resolved.enabled === false ? color47.dim("false") : color47.green("true")}`
25703
26132
  );
25704
- if (resolved.discover) lines.push(` mode: ${color46.cyan("auto-discovery")}`);
25705
- lines.push(` source: ${color46.dim(source)}`);
26133
+ if (resolved.discover) lines.push(` mode: ${color47.cyan("auto-discovery")}`);
26134
+ lines.push(` source: ${color47.dim(source)}`);
25706
26135
  lines.push(
25707
- ` token: ${resolved.token ? color46.dim(maskToken(resolved.token)) : color46.dim("none (open mode)")}`
26136
+ ` token: ${resolved.token ? color47.dim(maskToken(resolved.token)) : color47.dim("none (open mode)")}`
25708
26137
  );
25709
26138
  lines.push(
25710
- ` content: ${resolved.rawContent === true ? color46.amber("raw (unredacted)") : color46.dim("redacted \u2014 explicitly disabled; enable with /hq raw on")}`
26139
+ ` content: ${resolved.rawContent === true ? color47.amber("raw (unredacted)") : color47.dim("redacted \u2014 explicitly disabled; enable with /hq raw on")}`
25711
26140
  );
25712
- if (resolved.projectAlias) lines.push(` alias: ${color46.cyan(resolved.projectAlias)}`);
26141
+ if (resolved.projectAlias) lines.push(` alias: ${color47.cyan(resolved.projectAlias)}`);
25713
26142
  lines.push(` status: ${await probeHq(resolved.url)}`);
25714
26143
  return { message: lines.join("\n") };
25715
26144
  }
25716
26145
  return {
25717
- message: `${color46.red("Unknown subcommand:")} ${sub}
25718
- ${color46.dim("Try /hq, /hq set <url> [token], /hq raw on|off, /hq on|off, /hq clear, or /help hq")}`
26146
+ message: `${color47.red("Unknown subcommand:")} ${sub}
26147
+ ${color47.dim("Try /hq, /hq set <url> [token], /hq raw on|off, /hq on|off, /hq clear, or /help hq")}`
25719
26148
  };
25720
26149
  }
25721
26150
  };
@@ -25762,7 +26191,7 @@ import * as fs17 from "node:fs/promises";
25762
26191
  import { createRequire } from "node:module";
25763
26192
  import * as path26 from "node:path";
25764
26193
  import {
25765
- color as color47,
26194
+ color as color48,
25766
26195
  ensureProjectGitignore,
25767
26196
  ensureProjectIdentity as ensureProjectIdentity2,
25768
26197
  projectIdentityPath,
@@ -25895,17 +26324,17 @@ async function projectIdentityCommand(opts, ctx, action, confirmed) {
25895
26324
  if (action === "show") {
25896
26325
  const identity = await readProjectIdentity(root);
25897
26326
  return identity ? {
25898
- message: `${color47.bold("Project ID:")} ${color47.cyan(identity.projectId)}
25899
- ${color47.dim(filePath)}`
25900
- } : { message: `No committed project identity. Run ${color47.cyan("/project init")}.` };
26327
+ message: `${color48.bold("Project ID:")} ${color48.cyan(identity.projectId)}
26328
+ ${color48.dim(filePath)}`
26329
+ } : { message: `No committed project identity. Run ${color48.cyan("/project init")}.` };
25901
26330
  }
25902
26331
  if (action === "init") {
25903
26332
  const result2 = await ensureProjectIdentity2(root);
25904
26333
  await ensureProjectGitignore(root);
25905
26334
  return {
25906
- message: result2.created ? `${color47.green("Created")} ${filePath}
25907
- ${color47.cyan(result2.identity.projectId)}
25908
- ${color47.dim("Commit this file so every clone and machine shares the same HQ project.")}` : `${color47.dim("Project identity already exists:")} ${color47.cyan(result2.identity.projectId)}`
26335
+ message: result2.created ? `${color48.green("Created")} ${filePath}
26336
+ ${color48.cyan(result2.identity.projectId)}
26337
+ ${color48.dim("Commit this file so every clone and machine shares the same HQ project.")}` : `${color48.dim("Project identity already exists:")} ${color48.cyan(result2.identity.projectId)}`
25909
26338
  };
25910
26339
  }
25911
26340
  if (!confirmed && opts.confirm) {
@@ -25920,17 +26349,17 @@ ${color47.dim("Commit this file so every clone and machine shares the same HQ pr
25920
26349
  }
25921
26350
  if (!confirmed) {
25922
26351
  return {
25923
- message: `Rekey requires confirmation. Pass ${color47.cyan("--yes")} or ${color47.cyan("-y")}.`
26352
+ message: `Rekey requires confirmation. Pass ${color48.cyan("--yes")} or ${color48.cyan("-y")}.`
25924
26353
  };
25925
26354
  }
25926
26355
  const result = await rekeyProjectIdentity(root);
25927
26356
  await ensureProjectGitignore(root);
25928
26357
  return {
25929
26358
  message: [
25930
- result.previous ? color47.dim(`Previous: ${result.previous.projectId}`) : color47.dim("Previous: none"),
25931
- `${color47.green("New project ID:")} ${color47.cyan(result.identity.projectId)}`,
25932
- color47.dim(`Commit ${filePath} to make this fork independent on every machine.`),
25933
- color47.dim("Restart WrongStack before publishing HQ or Kanban updates under the new ID.")
26359
+ result.previous ? color48.dim(`Previous: ${result.previous.projectId}`) : color48.dim("Previous: none"),
26360
+ `${color48.green("New project ID:")} ${color48.cyan(result.identity.projectId)}`,
26361
+ color48.dim(`Commit ${filePath} to make this fork independent on every machine.`),
26362
+ color48.dim("Restart WrongStack before publishing HQ or Kanban updates under the new ID.")
25934
26363
  ].join("\n")
25935
26364
  };
25936
26365
  }
@@ -25939,7 +26368,7 @@ async function listProjectsCommand(opts, ctx) {
25939
26368
  const currentRoot = ctx?.projectRoot;
25940
26369
  if (manifest.projects.length === 0) {
25941
26370
  return {
25942
- message: color47.dim("No projects registered. Add one: /project add <path> [name]")
26371
+ message: color48.dim("No projects registered. Add one: /project add <path> [name]")
25943
26372
  };
25944
26373
  }
25945
26374
  const sorted = [...manifest.projects].sort((a, b) => {
@@ -25951,19 +26380,19 @@ async function listProjectsCommand(opts, ctx) {
25951
26380
  const lines = [`Projects (${sorted.length}) registered in projects.json:`, ""];
25952
26381
  for (const p of sorted) {
25953
26382
  const isCurrent = p.root === currentRoot;
25954
- const marker = isCurrent ? color47.green("\u25CF") : color47.dim("\u25CB");
25955
- const name = isCurrent ? color47.bold(p.name) : p.name;
25956
- const slug = color47.dim(`[${p.slug}]`);
25957
- const last = color47.dim(fmtLastSeen(p.lastSeen));
26383
+ const marker = isCurrent ? color48.green("\u25CF") : color48.dim("\u25CB");
26384
+ const name = isCurrent ? color48.bold(p.name) : p.name;
26385
+ const slug = color48.dim(`[${p.slug}]`);
26386
+ const last = color48.dim(fmtLastSeen(p.lastSeen));
25958
26387
  lines.push(` ${marker} ${name} ${slug} ${last}`);
25959
26388
  lines.push(` ${p.root}`);
25960
26389
  if (isCurrent) {
25961
- lines.push(` ${color47.green("\u2190 active session")}`);
26390
+ lines.push(` ${color48.green("\u2190 active session")}`);
25962
26391
  }
25963
26392
  lines.push("");
25964
26393
  }
25965
26394
  lines.push(
25966
- color47.dim(
26395
+ color48.dim(
25967
26396
  "Commands: add <path> [name] | rename <slug> <name> | remove <slug> | switch [dir] (no args = picker)"
25968
26397
  )
25969
26398
  );
@@ -25974,17 +26403,17 @@ async function addProjectCommand(opts, ctx, targetPath, displayName) {
25974
26403
  try {
25975
26404
  await fs17.access(resolved);
25976
26405
  } catch {
25977
- return { message: color47.red(`Directory not found: ${resolved}`) };
26406
+ return { message: color48.red(`Directory not found: ${resolved}`) };
25978
26407
  }
25979
26408
  const stat5 = await fs17.stat(resolved);
25980
26409
  if (!stat5.isDirectory()) {
25981
- return { message: color47.red(`Not a directory: ${resolved}`) };
26410
+ return { message: color48.red(`Not a directory: ${resolved}`) };
25982
26411
  }
25983
26412
  const manifest = await loadManifest(opts.paths?.globalConfig);
25984
26413
  const existing = manifest.projects.find((p) => p.root === resolved);
25985
26414
  if (existing) {
25986
26415
  return {
25987
- message: color47.yellow(`Project already registered: "${existing.name}" (${existing.slug})`)
26416
+ message: color48.yellow(`Project already registered: "${existing.name}" (${existing.slug})`)
25988
26417
  };
25989
26418
  }
25990
26419
  const name = displayName?.trim() || path26.basename(resolved);
@@ -25996,9 +26425,9 @@ async function addProjectCommand(opts, ctx, targetPath, displayName) {
25996
26425
  return {
25997
26426
  message: [
25998
26427
  "",
25999
- color47.green(` Added project: ${name}`),
26000
- color47.dim(` Root: ${resolved}`),
26001
- color47.dim(` Slug: ${slug}`),
26428
+ color48.green(` Added project: ${name}`),
26429
+ color48.dim(` Root: ${resolved}`),
26430
+ color48.dim(` Slug: ${slug}`),
26002
26431
  ""
26003
26432
  ].join("\n")
26004
26433
  };
@@ -26008,7 +26437,7 @@ async function renameProjectCommand(opts, _ctx, slugOrName, newName) {
26008
26437
  const project = findProject(manifest, slugOrName);
26009
26438
  if (!project) {
26010
26439
  return {
26011
- message: color47.red(
26440
+ message: color48.red(
26012
26441
  `Project not found: "${slugOrName}". Use /project list to see available projects.`
26013
26442
  )
26014
26443
  };
@@ -26016,7 +26445,7 @@ async function renameProjectCommand(opts, _ctx, slugOrName, newName) {
26016
26445
  const oldName = project.name;
26017
26446
  project.name = newName;
26018
26447
  await saveManifest(manifest, opts.paths?.globalConfig);
26019
- return { message: color47.green(`Renamed: "${oldName}" \u2192 "${newName}" (${project.slug})`) };
26448
+ return { message: color48.green(`Renamed: "${oldName}" \u2192 "${newName}" (${project.slug})`) };
26020
26449
  }
26021
26450
  async function removeProjectCommand(opts, _ctx, slugOrName) {
26022
26451
  const manifest = await loadManifest(opts.paths?.globalConfig);
@@ -26025,7 +26454,7 @@ async function removeProjectCommand(opts, _ctx, slugOrName) {
26025
26454
  );
26026
26455
  if (idx === -1) {
26027
26456
  return {
26028
- message: color47.red(
26457
+ message: color48.red(
26029
26458
  `Project not found: "${slugOrName}". Use /project list to see available projects.`
26030
26459
  )
26031
26460
  };
@@ -26034,7 +26463,7 @@ async function removeProjectCommand(opts, _ctx, slugOrName) {
26034
26463
  manifest.projects.splice(idx, 1);
26035
26464
  await saveManifest(manifest, opts.paths?.globalConfig);
26036
26465
  return {
26037
- message: color47.dim(
26466
+ message: color48.dim(
26038
26467
  `Removed: "${removed.name}" (${removed.root}) \u2014 data directory kept at ~/.wrongstack/projects/${removed.slug}/`
26039
26468
  )
26040
26469
  };
@@ -26044,11 +26473,11 @@ async function switchProjectCommand(opts, ctx, target, displayName) {
26044
26473
  try {
26045
26474
  await fs17.access(resolved);
26046
26475
  } catch {
26047
- return { message: color47.red(`Directory not found: ${resolved}`) };
26476
+ return { message: color48.red(`Directory not found: ${resolved}`) };
26048
26477
  }
26049
26478
  const stat5 = await fs17.stat(resolved);
26050
26479
  if (!stat5.isDirectory()) {
26051
- return { message: color47.red(`Not a directory: ${resolved}`) };
26480
+ return { message: color48.red(`Not a directory: ${resolved}`) };
26052
26481
  }
26053
26482
  let cliPath;
26054
26483
  try {
@@ -26061,7 +26490,7 @@ async function switchProjectCommand(opts, ctx, target, displayName) {
26061
26490
  cliPath = process.argv[1] ?? "";
26062
26491
  if (!cliPath) {
26063
26492
  return {
26064
- message: color47.red(
26493
+ message: color48.red(
26065
26494
  "Could not locate the CLI entry point. Run `wstack` manually in the target directory."
26066
26495
  )
26067
26496
  };
@@ -26094,14 +26523,14 @@ async function switchProjectCommand(opts, ctx, target, displayName) {
26094
26523
  // and boot/tui-project-spawn.ts documents this exact bug being removed.
26095
26524
  });
26096
26525
  child.on("error", (err) => {
26097
- console.error(color47.red(`Failed to spawn wstack: ${err.message}`));
26526
+ console.error(color48.red(`Failed to spawn wstack: ${err.message}`));
26098
26527
  });
26099
26528
  child.unref();
26100
26529
  return {
26101
26530
  message: [
26102
26531
  "",
26103
- color47.green(` Spawning wstack in ${resolved} ...`),
26104
- color47.dim(" (current session stays open \u2014 Ctrl+C to return)"),
26532
+ color48.green(` Spawning wstack in ${resolved} ...`),
26533
+ color48.dim(" (current session stays open \u2014 Ctrl+C to return)"),
26105
26534
  ""
26106
26535
  ].join("\n")
26107
26536
  };
@@ -26115,45 +26544,45 @@ async function confirmProjectSwitch(opts, targetName) {
26115
26544
  const parallelActive = parallelEngine?.currentState === "running";
26116
26545
  const hasActiveAgents = fleetRunning > 0 || eternalActive || parallelActive;
26117
26546
  if (!hasActiveAgents) return true;
26118
- const parts = [color47.yellow(`\u26A0 Switching projects will stop all running agents.`), ""];
26547
+ const parts = [color48.yellow(`\u26A0 Switching projects will stop all running agents.`), ""];
26119
26548
  if (fleetRunning > 0) {
26120
- parts.push(color47.dim(` \u2022 ${fleetRunning} subagent(s) currently running`));
26549
+ parts.push(color48.dim(` \u2022 ${fleetRunning} subagent(s) currently running`));
26121
26550
  }
26122
26551
  if (eternalActive) {
26123
- parts.push(color47.dim(" \u2022 Eternal engine is active"));
26552
+ parts.push(color48.dim(" \u2022 Eternal engine is active"));
26124
26553
  }
26125
26554
  if (parallelActive) {
26126
- parts.push(color47.dim(" \u2022 Parallel engine is active"));
26555
+ parts.push(color48.dim(" \u2022 Parallel engine is active"));
26127
26556
  }
26128
26557
  parts.push("");
26129
- parts.push(color47.dim(` Target: ${targetName}`));
26558
+ parts.push(color48.dim(` Target: ${targetName}`));
26130
26559
  opts.renderer.write(`
26131
26560
  ${parts.join("\n")}
26132
26561
  `);
26133
26562
  if (!opts.confirm) return true;
26134
26563
  const confirmed = await opts.confirm(
26135
- color47.yellow(`Stop all agents and switch to "${targetName}"?`),
26564
+ color48.yellow(`Stop all agents and switch to "${targetName}"?`),
26136
26565
  false
26137
26566
  // default to No for safety
26138
26567
  );
26139
26568
  if (!confirmed) {
26140
- opts.renderer.write(color47.dim(" Switch cancelled.\n"));
26569
+ opts.renderer.write(color48.dim(" Switch cancelled.\n"));
26141
26570
  return false;
26142
26571
  }
26143
26572
  if (fleetRunning > 0) {
26144
26573
  const killed = opts.onFleetKill ? await opts.onFleetKill() : 0;
26145
26574
  if (killed > 0) {
26146
- opts.renderer.write(color47.dim(` Stopped ${killed} subagent(s).
26575
+ opts.renderer.write(color48.dim(` Stopped ${killed} subagent(s).
26147
26576
  `));
26148
26577
  }
26149
26578
  }
26150
26579
  if (eternalActive) {
26151
26580
  eternalEngine?.stop();
26152
- opts.renderer.write(color47.dim(" Stopped eternal engine.\n"));
26581
+ opts.renderer.write(color48.dim(" Stopped eternal engine.\n"));
26153
26582
  }
26154
26583
  if (parallelActive) {
26155
26584
  parallelEngine?.stop();
26156
- opts.renderer.write(color47.dim(" Stopped parallel engine.\n"));
26585
+ opts.renderer.write(color48.dim(" Stopped parallel engine.\n"));
26157
26586
  }
26158
26587
  return true;
26159
26588
  }
@@ -26165,16 +26594,16 @@ async function switchInteractiveCommand(opts, ctx) {
26165
26594
  currentProjectRoot: currentRoot
26166
26595
  });
26167
26596
  if (!result) {
26168
- return { message: color47.dim("Cancelled.") };
26597
+ return { message: color48.dim("Cancelled.") };
26169
26598
  }
26170
26599
  switch (result.kind) {
26171
26600
  case "project": {
26172
26601
  const project = manifest.projects.find((p) => p.slug === result.key);
26173
26602
  if (!project) {
26174
- return { message: color47.red(`Project not found: ${result.key}`) };
26603
+ return { message: color48.red(`Project not found: ${result.key}`) };
26175
26604
  }
26176
26605
  if (project.root === currentRoot) {
26177
- return { message: color47.dim(`Already in ${project.name} (${project.root})`) };
26606
+ return { message: color48.dim(`Already in ${project.name} (${project.root})`) };
26178
26607
  }
26179
26608
  const canSwitch = await confirmProjectSwitch(opts, project.name);
26180
26609
  if (!canSwitch) return { message: "" };
@@ -26187,11 +26616,11 @@ async function switchInteractiveCommand(opts, ctx) {
26187
26616
  case "prev-sessions":
26188
26617
  return handlePrevSessions(opts, ctx);
26189
26618
  default:
26190
- return { message: color47.dim("Cancelled.") };
26619
+ return { message: color48.dim("Cancelled.") };
26191
26620
  }
26192
26621
  }
26193
26622
  default:
26194
- return { message: color47.dim("Cancelled.") };
26623
+ return { message: color48.dim("Cancelled.") };
26195
26624
  }
26196
26625
  }
26197
26626
  async function spawnInProject(opts, _ctx, root, projectName) {
@@ -26206,7 +26635,7 @@ async function spawnInProject(opts, _ctx, root, projectName) {
26206
26635
  cliPath = process.argv[1] ?? "";
26207
26636
  if (!cliPath) {
26208
26637
  return {
26209
- message: color47.red(
26638
+ message: color48.red(
26210
26639
  "Could not locate the CLI entry point. Run `wstack` manually in the target directory."
26211
26640
  )
26212
26641
  };
@@ -26236,15 +26665,15 @@ async function spawnInProject(opts, _ctx, root, projectName) {
26236
26665
  // and boot/tui-project-spawn.ts documents this exact bug being removed.
26237
26666
  });
26238
26667
  child.on("error", (err) => {
26239
- console.error(color47.red(`Failed to spawn wstack: ${err.message}`));
26668
+ console.error(color48.red(`Failed to spawn wstack: ${err.message}`));
26240
26669
  });
26241
26670
  child.unref();
26242
26671
  return {
26243
26672
  message: [
26244
26673
  "",
26245
- color47.green(` Switched to ${projectName}`),
26246
- color47.dim(` Root: ${root}`),
26247
- color47.dim(" (current session stays open \u2014 Ctrl+C to return)"),
26674
+ color48.green(` Switched to ${projectName}`),
26675
+ color48.dim(` Root: ${root}`),
26676
+ color48.dim(" (current session stays open \u2014 Ctrl+C to return)"),
26248
26677
  ""
26249
26678
  ].join("\n")
26250
26679
  };
@@ -26261,7 +26690,7 @@ async function handleNewSession(_opts, _ctx) {
26261
26690
  cliPath = process.argv[1] ?? "";
26262
26691
  if (!cliPath) {
26263
26692
  return {
26264
- message: color47.red("Could not locate the CLI entry point. Run `wstack` manually.")
26693
+ message: color48.red("Could not locate the CLI entry point. Run `wstack` manually.")
26265
26694
  };
26266
26695
  }
26267
26696
  }
@@ -26278,14 +26707,14 @@ async function handleNewSession(_opts, _ctx) {
26278
26707
  // and boot/tui-project-spawn.ts documents this exact bug being removed.
26279
26708
  });
26280
26709
  child.on("error", (err) => {
26281
- console.error(color47.red(`Failed to spawn wstack: ${err.message}`));
26710
+ console.error(color48.red(`Failed to spawn wstack: ${err.message}`));
26282
26711
  });
26283
26712
  child.unref();
26284
26713
  return {
26285
26714
  message: [
26286
26715
  "",
26287
- color47.green(" Starting new session ..."),
26288
- color47.dim(" (current session stays open \u2014 Ctrl+C to return)"),
26716
+ color48.green(" Starting new session ..."),
26717
+ color48.dim(" (current session stays open \u2014 Ctrl+C to return)"),
26289
26718
  ""
26290
26719
  ].join("\n")
26291
26720
  };
@@ -26296,25 +26725,25 @@ async function handlePrevSessions(opts, _ctx) {
26296
26725
  }
26297
26726
  const list = await opts.sessionStore.list(15);
26298
26727
  if (list.length === 0) {
26299
- return { message: color47.dim("No saved sessions.") };
26728
+ return { message: color48.dim("No saved sessions.") };
26300
26729
  }
26301
26730
  const currentId = opts.context?.session?.id;
26302
- const lines = [color47.bold(`Recent sessions (${list.length}):`), ""];
26731
+ const lines = [color48.bold(`Recent sessions (${list.length}):`), ""];
26303
26732
  for (const s of list) {
26304
26733
  const isCurrent = s.id === currentId;
26305
- const marker = isCurrent ? color47.cyan("\u25CF") : " ";
26306
- const date = color47.dim(s.startedAt.slice(0, 16).replace("T", " "));
26734
+ const marker = isCurrent ? color48.cyan("\u25CF") : " ";
26735
+ const date = color48.dim(s.startedAt.slice(0, 16).replace("T", " "));
26307
26736
  const stats = [
26308
- color47.dim(`${s.tokenTotal.toLocaleString()} tok`),
26309
- s.toolCallCount ? color47.cyan(`${s.toolCallCount} calls`) : "",
26310
- s.iterationCount ? color47.dim(`${s.iterationCount} iter`) : ""
26737
+ color48.dim(`${s.tokenTotal.toLocaleString()} tok`),
26738
+ s.toolCallCount ? color48.cyan(`${s.toolCallCount} calls`) : "",
26739
+ s.iterationCount ? color48.dim(`${s.iterationCount} iter`) : ""
26311
26740
  ].filter(Boolean).join(" ");
26312
- const outcome = s.outcome === "completed" ? color47.green("\u2713") : s.outcome === "aborted" ? color47.yellow("\u26A0") : s.outcome === "error" ? color47.red("\u2717") : color47.dim("?");
26313
- lines.push(` ${marker} ${color47.bold(s.id)} ${date}`);
26314
- lines.push(` ${stats} ${outcome} ${color47.dim(s.title)}`);
26741
+ const outcome = s.outcome === "completed" ? color48.green("\u2713") : s.outcome === "aborted" ? color48.yellow("\u26A0") : s.outcome === "error" ? color48.red("\u2717") : color48.dim("?");
26742
+ lines.push(` ${marker} ${color48.bold(s.id)} ${date}`);
26743
+ lines.push(` ${stats} ${outcome} ${color48.dim(s.title)}`);
26315
26744
  lines.push("");
26316
26745
  }
26317
- lines.push(color47.dim("Resume: /sessions or wstack resume <id>"));
26746
+ lines.push(color48.dim("Resume: /sessions or wstack resume <id>"));
26318
26747
  return { message: lines.join("\n") };
26319
26748
  }
26320
26749
 
@@ -26522,7 +26951,7 @@ function buildSecurityCommand(opts) {
26522
26951
  // src/slash-commands/settings.ts
26523
26952
  import { noOpVault as noOpVault9 } from "@wrongstack/core/security";
26524
26953
  import { resolveFleetChatVerbosity as resolveFleetChatVerbosity2 } from "@wrongstack/core/types";
26525
- import { color as color48, toErrorMessage as toErrorMessage24 } from "@wrongstack/core/utils";
26954
+ import { color as color49, toErrorMessage as toErrorMessage24 } from "@wrongstack/core/utils";
26526
26955
  import { getProcessRegistry } from "@wrongstack/tools";
26527
26956
 
26528
26957
  // src/utils/delay-format.ts
@@ -26630,56 +27059,56 @@ function buildSettingsCommand(opts) {
26630
27059
  const idx = opts.configStore.get().indexing;
26631
27060
  const sess = opts.configStore.get().session;
26632
27061
  return [
26633
- `${color48.bold("WrongStack")} ${color48.dim("\u2014 Settings")}`,
27062
+ `${color49.bold("WrongStack")} ${color49.dim("\u2014 Settings")}`,
26634
27063
  "",
26635
- ` auto-proceed delay: ${color48.cyan(formatDelay(delay))} ${color48.dim("change: /settings delay <seconds>")}`,
26636
- ` default autonomy mode: ${color48.cyan(mode)} ${color48.dim("change: /settings mode off|suggest|auto")}`,
26637
- ` fleet chat: ${color48.cyan(resolveFleetChatVerbosity2(au))} ${color48.dim("change: /settings stream-fleet off|full")}`,
26638
- ` completion chime: ${au?.chime === true ? color48.cyan("on") : color48.dim("off")} ${color48.dim("change: /settings chime on|off")}`,
26639
- ` confirm before exit: ${au?.confirmExit !== false ? color48.cyan("on") : color48.dim("off")} ${color48.dim("change: /settings confirm-exit on|off")}`,
26640
- ` launch hints: ${hints ? color48.cyan("on") : color48.dim("off")} ${color48.dim("change: /settings hints on|off")}`,
26641
- ` debug stream: ${debugStream ? color48.cyan("on") : color48.dim("off")} ${color48.dim("change: /settings debug-stream on|off")}`,
26642
- ` config scope: ${color48.cyan(configScope)} ${color48.dim("change: /settings config-scope global|project")}`,
26643
- ` filesystem access: ${color48.cyan(fsAccess)} ${color48.dim("change: /settings fs-access unrestricted|project")}`,
26644
- ` refine: ${enhanceEnabled ? color48.cyan("on") : color48.dim("off")} ${color48.dim("change: /settings refine on|off")}`,
26645
- ` refine-delay: ${color48.cyan(formatDelay(enhanceDelay))} ${color48.dim("change: /settings refine-delay <seconds>")}`,
26646
- ` refine-language: ${color48.cyan(enhanceLanguage)} ${color48.dim("change: /settings refine-language original|english")}`,
26647
- ` refiner-provider: ${color48.cyan(au?.refinerProvider ?? color48.dim("(unset)"))} ${color48.dim("change: /settings refiner-provider <id>")}`,
26648
- ` refiner-model: ${color48.cyan(au?.refinerModel ?? color48.dim("(unset)"))} ${color48.dim("change: /settings refiner-model <model>")}`,
26649
- ` refiner-fallback-profile: ${color48.cyan(au?.refinerFallbackProfile ?? color48.dim("(unset)"))} ${color48.dim("change: /settings refiner-fallback-profile <name>")}`,
26650
- ` semver default part: ${color48.cyan(semverPart)} ${color48.dim("change: /settings semver-part patch|minor|major|auto")}`,
26651
- ` circuit breaker: ${breakerEnabled ? color48.cyan("on") : color48.dim("off")} (${breakerTimeout > 0 ? formatDelay(breakerTimeout) : color48.dim("manual")}) ${color48.dim("change: /settings breaker on|off")}`,
26652
- ` context mode: ${color48.cyan(contextMode)} ${color48.dim("change: /settings context-mode balanced|frugal|deep")}`,
26653
- ` context strategy: ${color48.cyan(contextStrategy)} ${color48.dim("change: /settings context-strategy hybrid|intelligent|selective")}`,
26654
- ` context auto-compact: ${contextAutoCompact ? color48.cyan("on") : color48.dim("off")} ${color48.dim("change: /settings context-auto-compact on|off")}`,
26655
- ` token-saving: ${color48.cyan(tokenSavingTier)} ${color48.dim("change: /settings token-saving off|minimal|light|medium|aggressive")}`,
26656
- ` nextsteps tool: ${nextStepsToolEnabled ? color48.cyan("on") : color48.dim("off")} ${color48.dim("change: /settings nextsteps-tool on|off")}`,
26657
- ` MCP features: ${feats?.mcp !== false ? color48.cyan("on") : color48.dim("off")} ${color48.dim("change: /settings mcp on|off")}`,
26658
- ` plugin features: ${feats?.plugins !== false ? color48.cyan("on") : color48.dim("off")} ${color48.dim("change: /settings plugins on|off")}`,
26659
- ` memory features: ${feats?.memory !== false ? color48.cyan("on") : color48.dim("off")} ${color48.dim("change: /settings memory on|off")}`,
26660
- ` skills features: ${feats?.skills !== false ? color48.cyan("on") : color48.dim("off")} ${color48.dim("change: /settings skills on|off")}`,
26661
- ` models registry: ${feats?.modelsRegistry !== false ? color48.cyan("on") : color48.dim("off")} ${color48.dim("change: /settings models-registry on|off")}`,
26662
- ` max concurrent: ${color48.cyan(maxConcurrent === 0 ? "default" : String(maxConcurrent))} ${color48.dim("change: /settings max-concurrent <n>")}`,
26663
- ` max iterations: ${color48.cyan(String(tools?.maxIterations ?? "default"))} ${color48.dim("change: /settings max-iterations <n>")}`,
26664
- ` auto-proceed max iters: ${color48.cyan(String(au?.autoProceedMaxIterations ?? "unlimited"))} ${color48.dim("change: /settings auto-proceed-max-iterations <n>")}`,
26665
- ` title animation: ${titleAnimation ? color48.cyan("on") : color48.dim("off")} ${color48.dim("change: /settings title-animation on|off")}`,
26666
- ` thinking word: ${color48.cyan(au?.thinkingWord ?? "thinking")} ${color48.dim("change: /settings thinking-word <word>")}`,
26667
- ` statusline mode: ${color48.cyan(au?.statuslineMode ?? "minimum")} ${color48.dim("change: /settings statusline minimum|detailed|no-color")}`,
26668
- ` animation style: ${color48.cyan(au?.animationStyle ?? "rainbow")} ${color48.dim("change: /settings animation rainbow|wave|pulse|dots|breathe|cycle")}`,
26669
- ` read symbols: ${au?.readAdvancedMode === true ? color48.cyan("on") : color48.dim("off")} ${color48.dim("change: /settings read-symbols on|off")}`,
26670
- ` reasoning mode: ${color48.cyan(reasoningMode)} ${color48.dim("change: /settings reasoning auto|on|off")}`,
26671
- ` reasoning effort: ${color48.cyan(reasoningEffort)} ${color48.dim("change: /settings reasoning-effort <level>")}`,
26672
- ` reasoning preserve: ${reasoningPreserve ? color48.cyan("on") : color48.dim("off")} ${color48.dim("change: /settings reasoning-preserve on|off")}`,
26673
- ` cache TTL: ${color48.cyan(cacheTtl)} ${color48.dim("change: /settings cache-ttl 5m|1h")}`,
26674
- ` index on start: ${idx?.onSessionStart !== false ? color48.cyan("on") : color48.dim("off")} ${color48.dim("change: /settings index-on-start on|off")}`,
26675
- ` log level: ${color48.cyan(log?.level ?? "info")} ${color48.dim("change: /settings log-level error|warn|info|debug|trace")}`,
26676
- ` audit level: ${color48.cyan(sess?.auditLevel ?? "standard")} ${color48.dim("change: /settings audit-level minimal|standard|full")}`,
26677
- ` HQ publishing: ${hqEnabled ? color48.cyan("on") : color48.dim("off")} ${color48.dim("change: /settings hq on|off")}`,
26678
- ` HQ URL: ${color48.cyan(hqUrl)} ${color48.dim("change: /settings hq-url <url>")}`,
26679
- ` HQ token: ${color48.cyan(hqToken)} ${color48.dim("change: /settings hq-token <token>")}`,
26680
- ` HQ raw content: ${hq?.rawContent === true ? color48.cyan("on") : color48.dim("off")} ${color48.dim("change: /settings hq-raw on|off")}`,
27064
+ ` auto-proceed delay: ${color49.cyan(formatDelay(delay))} ${color49.dim("change: /settings delay <seconds>")}`,
27065
+ ` default autonomy mode: ${color49.cyan(mode)} ${color49.dim("change: /settings mode off|suggest|auto")}`,
27066
+ ` fleet chat: ${color49.cyan(resolveFleetChatVerbosity2(au))} ${color49.dim("change: /settings stream-fleet off|full")}`,
27067
+ ` completion chime: ${au?.chime === true ? color49.cyan("on") : color49.dim("off")} ${color49.dim("change: /settings chime on|off")}`,
27068
+ ` confirm before exit: ${au?.confirmExit !== false ? color49.cyan("on") : color49.dim("off")} ${color49.dim("change: /settings confirm-exit on|off")}`,
27069
+ ` launch hints: ${hints ? color49.cyan("on") : color49.dim("off")} ${color49.dim("change: /settings hints on|off")}`,
27070
+ ` debug stream: ${debugStream ? color49.cyan("on") : color49.dim("off")} ${color49.dim("change: /settings debug-stream on|off")}`,
27071
+ ` config scope: ${color49.cyan(configScope)} ${color49.dim("change: /settings config-scope global|project")}`,
27072
+ ` filesystem access: ${color49.cyan(fsAccess)} ${color49.dim("change: /settings fs-access unrestricted|project")}`,
27073
+ ` refine: ${enhanceEnabled ? color49.cyan("on") : color49.dim("off")} ${color49.dim("change: /settings refine on|off")}`,
27074
+ ` refine-delay: ${color49.cyan(formatDelay(enhanceDelay))} ${color49.dim("change: /settings refine-delay <seconds>")}`,
27075
+ ` refine-language: ${color49.cyan(enhanceLanguage)} ${color49.dim("change: /settings refine-language original|english")}`,
27076
+ ` refiner-provider: ${color49.cyan(au?.refinerProvider ?? color49.dim("(unset)"))} ${color49.dim("change: /settings refiner-provider <id>")}`,
27077
+ ` refiner-model: ${color49.cyan(au?.refinerModel ?? color49.dim("(unset)"))} ${color49.dim("change: /settings refiner-model <model>")}`,
27078
+ ` refiner-fallback-profile: ${color49.cyan(au?.refinerFallbackProfile ?? color49.dim("(unset)"))} ${color49.dim("change: /settings refiner-fallback-profile <name>")}`,
27079
+ ` semver default part: ${color49.cyan(semverPart)} ${color49.dim("change: /settings semver-part patch|minor|major|auto")}`,
27080
+ ` circuit breaker: ${breakerEnabled ? color49.cyan("on") : color49.dim("off")} (${breakerTimeout > 0 ? formatDelay(breakerTimeout) : color49.dim("manual")}) ${color49.dim("change: /settings breaker on|off")}`,
27081
+ ` context mode: ${color49.cyan(contextMode)} ${color49.dim("change: /settings context-mode balanced|frugal|deep")}`,
27082
+ ` context strategy: ${color49.cyan(contextStrategy)} ${color49.dim("change: /settings context-strategy hybrid|intelligent|selective")}`,
27083
+ ` context auto-compact: ${contextAutoCompact ? color49.cyan("on") : color49.dim("off")} ${color49.dim("change: /settings context-auto-compact on|off")}`,
27084
+ ` token-saving: ${color49.cyan(tokenSavingTier)} ${color49.dim("change: /settings token-saving off|minimal|light|medium|aggressive")}`,
27085
+ ` nextsteps tool: ${nextStepsToolEnabled ? color49.cyan("on") : color49.dim("off")} ${color49.dim("change: /settings nextsteps-tool on|off")}`,
27086
+ ` MCP features: ${feats?.mcp !== false ? color49.cyan("on") : color49.dim("off")} ${color49.dim("change: /settings mcp on|off")}`,
27087
+ ` plugin features: ${feats?.plugins !== false ? color49.cyan("on") : color49.dim("off")} ${color49.dim("change: /settings plugins on|off")}`,
27088
+ ` memory features: ${feats?.memory !== false ? color49.cyan("on") : color49.dim("off")} ${color49.dim("change: /settings memory on|off")}`,
27089
+ ` skills features: ${feats?.skills !== false ? color49.cyan("on") : color49.dim("off")} ${color49.dim("change: /settings skills on|off")}`,
27090
+ ` models registry: ${feats?.modelsRegistry !== false ? color49.cyan("on") : color49.dim("off")} ${color49.dim("change: /settings models-registry on|off")}`,
27091
+ ` max concurrent: ${color49.cyan(maxConcurrent === 0 ? "default" : String(maxConcurrent))} ${color49.dim("change: /settings max-concurrent <n>")}`,
27092
+ ` max iterations: ${color49.cyan(String(tools?.maxIterations ?? "default"))} ${color49.dim("change: /settings max-iterations <n>")}`,
27093
+ ` auto-proceed max iters: ${color49.cyan(String(au?.autoProceedMaxIterations ?? "unlimited"))} ${color49.dim("change: /settings auto-proceed-max-iterations <n>")}`,
27094
+ ` title animation: ${titleAnimation ? color49.cyan("on") : color49.dim("off")} ${color49.dim("change: /settings title-animation on|off")}`,
27095
+ ` thinking word: ${color49.cyan(au?.thinkingWord ?? "thinking")} ${color49.dim("change: /settings thinking-word <word>")}`,
27096
+ ` statusline mode: ${color49.cyan(au?.statuslineMode ?? "minimum")} ${color49.dim("change: /settings statusline minimum|detailed|no-color")}`,
27097
+ ` animation style: ${color49.cyan(au?.animationStyle ?? "rainbow")} ${color49.dim("change: /settings animation rainbow|wave|pulse|dots|breathe|cycle")}`,
27098
+ ` read symbols: ${au?.readAdvancedMode === true ? color49.cyan("on") : color49.dim("off")} ${color49.dim("change: /settings read-symbols on|off")}`,
27099
+ ` reasoning mode: ${color49.cyan(reasoningMode)} ${color49.dim("change: /settings reasoning auto|on|off")}`,
27100
+ ` reasoning effort: ${color49.cyan(reasoningEffort)} ${color49.dim("change: /settings reasoning-effort <level>")}`,
27101
+ ` reasoning preserve: ${reasoningPreserve ? color49.cyan("on") : color49.dim("off")} ${color49.dim("change: /settings reasoning-preserve on|off")}`,
27102
+ ` cache TTL: ${color49.cyan(cacheTtl)} ${color49.dim("change: /settings cache-ttl 5m|1h")}`,
27103
+ ` index on start: ${idx?.onSessionStart !== false ? color49.cyan("on") : color49.dim("off")} ${color49.dim("change: /settings index-on-start on|off")}`,
27104
+ ` log level: ${color49.cyan(log?.level ?? "info")} ${color49.dim("change: /settings log-level error|warn|info|debug|trace")}`,
27105
+ ` audit level: ${color49.cyan(sess?.auditLevel ?? "standard")} ${color49.dim("change: /settings audit-level minimal|standard|full")}`,
27106
+ ` HQ publishing: ${hqEnabled ? color49.cyan("on") : color49.dim("off")} ${color49.dim("change: /settings hq on|off")}`,
27107
+ ` HQ URL: ${color49.cyan(hqUrl)} ${color49.dim("change: /settings hq-url <url>")}`,
27108
+ ` HQ token: ${color49.cyan(hqToken)} ${color49.dim("change: /settings hq-token <token>")}`,
27109
+ ` HQ raw content: ${hq?.rawContent === true ? color49.cyan("on") : color49.dim("off")} ${color49.dim("change: /settings hq-raw on|off")}`,
26681
27110
  "",
26682
- color48.dim(` Persisted to ${persistedTo} \xB7 /settings help for more`)
27111
+ color49.dim(` Persisted to ${persistedTo} \xB7 /settings help for more`)
26683
27112
  ].join("\n");
26684
27113
  }
26685
27114
  return {
@@ -26694,7 +27123,7 @@ function buildSettingsCommand(opts) {
26694
27123
  return { message: this.help ?? "" };
26695
27124
  }
26696
27125
  if (!opts.configStore || !opts.paths) {
26697
- return { message: `${color48.red("Error")} config store not available.` };
27126
+ return { message: `${color49.red("Error")} config store not available.` };
26698
27127
  }
26699
27128
  if (!sub) {
26700
27129
  return { message: currentView() };
@@ -26702,16 +27131,16 @@ function buildSettingsCommand(opts) {
26702
27131
  if (sub === "defaults") {
26703
27132
  return {
26704
27133
  message: [
26705
- `${color48.bold("Default Values")}`,
27134
+ `${color49.bold("Default Values")}`,
26706
27135
  "",
26707
- ` auto-proceed delay: ${color48.cyan("45s")} ${color48.dim("(WRONGSTACK_AUTO_PROCEED_DELAY_MS env)")}`,
26708
- ` default autonomy mode: ${color48.cyan("off")}`,
26709
- ` launch hints: ${color48.cyan("on")}`,
26710
- ` iteration timeout: ${color48.cyan("5 min")}`,
26711
- ` session timeout: ${color48.cyan("30 min")}`,
26712
- ` max iterations: ${color48.cyan("100")}`,
26713
- ` max concurrent: ${color48.cyan("4")}`,
26714
- ` semver default part: ${color48.cyan("patch")}`
27136
+ ` auto-proceed delay: ${color49.cyan("45s")} ${color49.dim("(WRONGSTACK_AUTO_PROCEED_DELAY_MS env)")}`,
27137
+ ` default autonomy mode: ${color49.cyan("off")}`,
27138
+ ` launch hints: ${color49.cyan("on")}`,
27139
+ ` iteration timeout: ${color49.cyan("5 min")}`,
27140
+ ` session timeout: ${color49.cyan("30 min")}`,
27141
+ ` max iterations: ${color49.cyan("100")}`,
27142
+ ` max concurrent: ${color49.cyan("4")}`,
27143
+ ` semver default part: ${color49.cyan("patch")}`
26715
27144
  ].join("\n")
26716
27145
  };
26717
27146
  }
@@ -26726,7 +27155,7 @@ function buildSettingsCommand(opts) {
26726
27155
  if (sub === "hq") {
26727
27156
  const raw = (rest[0] ?? "").toLowerCase();
26728
27157
  if (!["on", "off"].includes(raw)) {
26729
- return { message: `${color48.amber("Usage:")} /settings hq on|off` };
27158
+ return { message: `${color49.amber("Usage:")} /settings hq on|off` };
26730
27159
  }
26731
27160
  const on = raw === "on";
26732
27161
  await persistConfigSetting({ ...persistDeps, forceGlobal: true }, (cfg) => {
@@ -26735,19 +27164,19 @@ function buildSettingsCommand(opts) {
26735
27164
  cfg.hq = hq;
26736
27165
  });
26737
27166
  return {
26738
- message: `${color48.green("\u2713")} HQ publishing \u2192 ${on ? color48.cyan("on") : color48.dim("off")}`
27167
+ message: `${color49.green("\u2713")} HQ publishing \u2192 ${on ? color49.cyan("on") : color49.dim("off")}`
26739
27168
  };
26740
27169
  }
26741
27170
  if (sub === "hq-url") {
26742
27171
  const raw = rest.join(" ").trim();
26743
27172
  if (!raw)
26744
- return { message: `${color48.amber("Usage:")} /settings hq-url <http://host:3499>` };
27173
+ return { message: `${color49.amber("Usage:")} /settings hq-url <http://host:3499>` };
26745
27174
  try {
26746
27175
  const url = new URL(raw);
26747
27176
  if (url.protocol !== "http:" && url.protocol !== "https:")
26748
27177
  throw new Error("bad protocol");
26749
27178
  } catch {
26750
- return { message: `${color48.red("Invalid URL")}: ${raw}` };
27179
+ return { message: `${color49.red("Invalid URL")}: ${raw}` };
26751
27180
  }
26752
27181
  await persistConfigSetting({ ...persistDeps, forceGlobal: true }, (cfg) => {
26753
27182
  const hq = cfg.hq ?? {};
@@ -26755,12 +27184,12 @@ function buildSettingsCommand(opts) {
26755
27184
  hq.enabled = true;
26756
27185
  cfg.hq = hq;
26757
27186
  });
26758
- return { message: `${color48.green("\u2713")} HQ URL \u2192 ${color48.cyan(raw)}` };
27187
+ return { message: `${color49.green("\u2713")} HQ URL \u2192 ${color49.cyan(raw)}` };
26759
27188
  }
26760
27189
  if (sub === "hq-token") {
26761
27190
  const token = rest.join(" ").trim();
26762
27191
  if (!token)
26763
- return { message: `${color48.amber("Usage:")} /settings hq-token <client-token>` };
27192
+ return { message: `${color49.amber("Usage:")} /settings hq-token <client-token>` };
26764
27193
  await persistConfigSetting({ ...persistDeps, forceGlobal: true }, (cfg) => {
26765
27194
  const hq = cfg.hq ?? {};
26766
27195
  hq.token = token;
@@ -26768,13 +27197,13 @@ function buildSettingsCommand(opts) {
26768
27197
  cfg.hq = hq;
26769
27198
  });
26770
27199
  return {
26771
- message: `${color48.green("\u2713")} HQ token saved ${color48.dim("(active profile config)")}`
27200
+ message: `${color49.green("\u2713")} HQ token saved ${color49.dim("(active profile config)")}`
26772
27201
  };
26773
27202
  }
26774
27203
  if (sub === "hq-raw") {
26775
27204
  const raw = (rest[0] ?? "").toLowerCase();
26776
27205
  if (!["on", "off"].includes(raw)) {
26777
- return { message: `${color48.amber("Usage:")} /settings hq-raw on|off` };
27206
+ return { message: `${color49.amber("Usage:")} /settings hq-raw on|off` };
26778
27207
  }
26779
27208
  const on = raw === "on";
26780
27209
  await persistConfigSetting({ ...persistDeps, forceGlobal: true }, (cfg) => {
@@ -26783,56 +27212,56 @@ function buildSettingsCommand(opts) {
26783
27212
  cfg.hq = hq;
26784
27213
  });
26785
27214
  return {
26786
- message: `${color48.green("\u2713")} HQ raw content \u2192 ${on ? color48.cyan("on") : color48.dim("off")}`
27215
+ message: `${color49.green("\u2713")} HQ raw content \u2192 ${on ? color49.cyan("on") : color49.dim("off")}`
26787
27216
  };
26788
27217
  }
26789
27218
  if (sub === "delay") {
26790
27219
  const raw = rest[0];
26791
27220
  if (raw === void 0) {
26792
27221
  return {
26793
- message: `${color48.amber("Usage:")} /settings delay <seconds> ${color48.dim("(0 disables)")}`
27222
+ message: `${color49.amber("Usage:")} /settings delay <seconds> ${color49.dim("(0 disables)")}`
26794
27223
  };
26795
27224
  }
26796
27225
  const seconds = Number.parseFloat(raw);
26797
27226
  if (Number.isNaN(seconds) || seconds < 0) {
26798
27227
  return {
26799
- message: `${color48.red("Invalid number")}: "${raw}". Enter seconds, e.g. /settings delay 30`
27228
+ message: `${color49.red("Invalid number")}: "${raw}". Enter seconds, e.g. /settings delay 30`
26800
27229
  };
26801
27230
  }
26802
27231
  const ms = Math.round(seconds * 1e3);
26803
27232
  await persistAutonomySetting(persistDeps, (autonomy) => {
26804
27233
  autonomy.autoProceedDelayMs = ms;
26805
27234
  });
26806
- return { message: `${color48.green("\u2713")} auto-proceed delay \u2192 ${formatDelay(ms)}` };
27235
+ return { message: `${color49.green("\u2713")} auto-proceed delay \u2192 ${formatDelay(ms)}` };
26807
27236
  }
26808
27237
  if (sub === "mode") {
26809
27238
  const raw = (rest[0] ?? "").toLowerCase();
26810
27239
  const modes = ["off", "suggest", "auto"];
26811
27240
  if (!modes.includes(raw)) {
26812
- return { message: `${color48.amber("Usage:")} /settings mode off|suggest|auto` };
27241
+ return { message: `${color49.amber("Usage:")} /settings mode off|suggest|auto` };
26813
27242
  }
26814
27243
  await persistAutonomySetting(persistDeps, (autonomy) => {
26815
27244
  autonomy.defaultMode = raw;
26816
27245
  });
26817
- return { message: `${color48.green("\u2713")} default autonomy \u2192 ${color48.bold(raw)}` };
27246
+ return { message: `${color49.green("\u2713")} default autonomy \u2192 ${color49.bold(raw)}` };
26818
27247
  }
26819
27248
  if (sub === "hints") {
26820
27249
  const raw = (rest[0] ?? "").toLowerCase();
26821
27250
  if (!["on", "off"].includes(raw)) {
26822
- return { message: `${color48.amber("Usage:")} /settings hints on|off` };
27251
+ return { message: `${color49.amber("Usage:")} /settings hints on|off` };
26823
27252
  }
26824
27253
  const on = raw === "on";
26825
27254
  await persistConfigSetting(persistDeps, (cfg) => {
26826
27255
  cfg.hints = on;
26827
27256
  });
26828
27257
  return {
26829
- message: `${color48.green("\u2713")} launch hints \u2192 ${on ? color48.cyan("on") : color48.dim("off")}`
27258
+ message: `${color49.green("\u2713")} launch hints \u2192 ${on ? color49.cyan("on") : color49.dim("off")}`
26830
27259
  };
26831
27260
  }
26832
27261
  if (sub === "debug-stream") {
26833
27262
  const raw = (rest[0] ?? "").toLowerCase();
26834
27263
  if (!["on", "off"].includes(raw)) {
26835
- return { message: `${color48.amber("Usage:")} /settings debug-stream on|off` };
27264
+ return { message: `${color49.amber("Usage:")} /settings debug-stream on|off` };
26836
27265
  }
26837
27266
  const on = raw === "on";
26838
27267
  const { setDebugStreamEnabled } = await import("@wrongstack/providers");
@@ -26841,24 +27270,24 @@ function buildSettingsCommand(opts) {
26841
27270
  cfg.debugStream = on;
26842
27271
  });
26843
27272
  return {
26844
- message: `${color48.green("\u2713")} debug stream \u2192 ${on ? color48.cyan("on") : color48.dim("off")} ${color48.dim("raw SSE hex-dump to stderr")}`
27273
+ message: `${color49.green("\u2713")} debug stream \u2192 ${on ? color49.cyan("on") : color49.dim("off")} ${color49.dim("raw SSE hex-dump to stderr")}`
26845
27274
  };
26846
27275
  }
26847
27276
  if (sub === "config-scope") {
26848
27277
  const raw = (rest[0] ?? "").toLowerCase();
26849
27278
  if (!["global", "project"].includes(raw)) {
26850
- return { message: `${color48.amber("Usage:")} /settings config-scope global|project` };
27279
+ return { message: `${color49.amber("Usage:")} /settings config-scope global|project` };
26851
27280
  }
26852
27281
  await persistConfigSetting(persistDeps, (cfg) => {
26853
27282
  cfg.configScope = raw;
26854
27283
  });
26855
- const label = raw === "project" ? `${color48.cyan("project")} \u2014 settings saved to <project>/.wrongstack/config.json` : `${color48.cyan("global")} \u2014 settings saved to ~/.wrongstack/profiles/${activeProfile}/config.json`;
26856
- return { message: `${color48.green("\u2713")} config scope \u2192 ${label}` };
27284
+ const label = raw === "project" ? `${color49.cyan("project")} \u2014 settings saved to <project>/.wrongstack/config.json` : `${color49.cyan("global")} \u2014 settings saved to ~/.wrongstack/profiles/${activeProfile}/config.json`;
27285
+ return { message: `${color49.green("\u2713")} config scope \u2192 ${label}` };
26857
27286
  }
26858
27287
  if (sub === "fs-access") {
26859
27288
  const raw = (rest[0] ?? "").toLowerCase();
26860
27289
  if (!["unrestricted", "project"].includes(raw)) {
26861
- return { message: `${color48.amber("Usage:")} /settings fs-access unrestricted|project` };
27290
+ return { message: `${color49.amber("Usage:")} /settings fs-access unrestricted|project` };
26862
27291
  }
26863
27292
  const restrict = raw === "project";
26864
27293
  const fsAccess = deriveFsAccessPair({ restrictFsToRoot: restrict });
@@ -26870,15 +27299,15 @@ function buildSettingsCommand(opts) {
26870
27299
  features.allowOutsideProjectRoot = fsAccess.allowOutsideProjectRoot;
26871
27300
  cfg.features = features;
26872
27301
  });
26873
- const label = restrict ? `${color48.cyan("project")} \u2014 file tools confined to the project root` : `${color48.cyan("unrestricted")} \u2014 file tools may access paths outside the project root`;
27302
+ const label = restrict ? `${color49.cyan("project")} \u2014 file tools confined to the project root` : `${color49.cyan("unrestricted")} \u2014 file tools may access paths outside the project root`;
26874
27303
  return {
26875
- message: `${color48.green("\u2713")} filesystem access \u2192 ${label} ${color48.dim("(restart or re-open the session to apply)")}`
27304
+ message: `${color49.green("\u2713")} filesystem access \u2192 ${label} ${color49.dim("(restart or re-open the session to apply)")}`
26876
27305
  };
26877
27306
  }
26878
27307
  if (sub === "refine") {
26879
27308
  const raw = (rest[0] ?? "").toLowerCase();
26880
27309
  if (!["on", "off"].includes(raw)) {
26881
- return { message: `${color48.amber("Usage:")} /settings refine on|off` };
27310
+ return { message: `${color49.amber("Usage:")} /settings refine on|off` };
26882
27311
  }
26883
27312
  const on = raw === "on";
26884
27313
  await persistAutonomySetting(persistDeps, (autonomy) => {
@@ -26888,52 +27317,52 @@ function buildSettingsCommand(opts) {
26888
27317
  opts.enhanceController.setEnabled(on);
26889
27318
  }
26890
27319
  return {
26891
- message: `${color48.green("\u2713")} refine \u2192 ${on ? color48.cyan("on") : color48.dim("off")} ${color48.dim(on ? "prompts will be refined before sending" : "prompts sent verbatim")}`
27320
+ message: `${color49.green("\u2713")} refine \u2192 ${on ? color49.cyan("on") : color49.dim("off")} ${color49.dim(on ? "prompts will be refined before sending" : "prompts sent verbatim")}`
26892
27321
  };
26893
27322
  }
26894
27323
  if (sub === "refine-delay") {
26895
27324
  const raw = rest[0];
26896
27325
  if (raw === void 0) {
26897
- return { message: `${color48.amber("Usage:")} /settings refine-delay <seconds>` };
27326
+ return { message: `${color49.amber("Usage:")} /settings refine-delay <seconds>` };
26898
27327
  }
26899
27328
  const seconds = Number.parseFloat(raw);
26900
27329
  if (Number.isNaN(seconds) || seconds < 0) {
26901
27330
  return {
26902
- message: `${color48.red("Invalid number")}: "${raw}". Enter seconds, e.g. /settings refine-delay 30`
27331
+ message: `${color49.red("Invalid number")}: "${raw}". Enter seconds, e.g. /settings refine-delay 30`
26903
27332
  };
26904
27333
  }
26905
27334
  const ms = Math.round(seconds * 1e3);
26906
27335
  await persistAutonomySetting(persistDeps, (autonomy) => {
26907
27336
  autonomy.enhanceDelayMs = ms;
26908
27337
  });
26909
- return { message: `${color48.green("\u2713")} refine-delay \u2192 ${formatDelay(ms)}` };
27338
+ return { message: `${color49.green("\u2713")} refine-delay \u2192 ${formatDelay(ms)}` };
26910
27339
  }
26911
27340
  if (sub === "refine-language") {
26912
27341
  const raw = (rest[0] ?? "").toLowerCase();
26913
27342
  if (!["original", "english"].includes(raw)) {
26914
27343
  return {
26915
- message: `${color48.amber("Usage:")} /settings refine-language original|english`
27344
+ message: `${color49.amber("Usage:")} /settings refine-language original|english`
26916
27345
  };
26917
27346
  }
26918
27347
  await persistAutonomySetting(persistDeps, (autonomy) => {
26919
27348
  autonomy.enhanceLanguage = raw;
26920
27349
  });
26921
- const label = raw === "original" ? `${color48.cyan("original")} \u2014 use the language you wrote in` : `${color48.cyan("english")} \u2014 translate to English`;
26922
- return { message: `${color48.green("\u2713")} refine-language \u2192 ${label}` };
27350
+ const label = raw === "original" ? `${color49.cyan("original")} \u2014 use the language you wrote in` : `${color49.cyan("english")} \u2014 translate to English`;
27351
+ return { message: `${color49.green("\u2713")} refine-language \u2192 ${label}` };
26923
27352
  }
26924
27353
  if (sub === "refiner-provider") {
26925
27354
  const raw = rest.join(" ").trim();
26926
27355
  const currentProvider = opts.configStore.get().autonomy?.refinerProvider;
26927
27356
  if (!raw) {
26928
27357
  return {
26929
- message: `${color48.amber("Usage:")} /settings refiner-provider <providerId> ${color48.dim('(e.g. "openai", "anthropic")' + (currentProvider ? ` Current: ${currentProvider}` : ""))}`
27358
+ message: `${color49.amber("Usage:")} /settings refiner-provider <providerId> ${color49.dim('(e.g. "openai", "anthropic")' + (currentProvider ? ` Current: ${currentProvider}` : ""))}`
26930
27359
  };
26931
27360
  }
26932
27361
  await persistAutonomySetting(persistDeps, (autonomy) => {
26933
27362
  autonomy.refinerProvider = raw;
26934
27363
  });
26935
27364
  return {
26936
- message: `${color48.green("\u2713")} refiner-provider \u2192 ${color48.cyan(raw)} ${color48.dim("goal refinement will use this provider when refiner-model is also set")}`
27365
+ message: `${color49.green("\u2713")} refiner-provider \u2192 ${color49.cyan(raw)} ${color49.dim("goal refinement will use this provider when refiner-model is also set")}`
26937
27366
  };
26938
27367
  }
26939
27368
  if (sub === "refiner-model") {
@@ -26941,14 +27370,14 @@ function buildSettingsCommand(opts) {
26941
27370
  const currentModel = opts.configStore.get().autonomy?.refinerModel;
26942
27371
  if (!raw) {
26943
27372
  return {
26944
- message: `${color48.amber("Usage:")} /settings refiner-model <modelId> ${color48.dim('(must be a favorite or the active model; e.g. "gpt-4o-mini")' + (currentModel ? ` Current: ${currentModel}` : ""))}`
27373
+ message: `${color49.amber("Usage:")} /settings refiner-model <modelId> ${color49.dim('(must be a favorite or the active model; e.g. "gpt-4o-mini")' + (currentModel ? ` Current: ${currentModel}` : ""))}`
26945
27374
  };
26946
27375
  }
26947
27376
  await persistAutonomySetting(persistDeps, (autonomy) => {
26948
27377
  autonomy.refinerModel = raw;
26949
27378
  });
26950
27379
  return {
26951
- message: `${color48.green("\u2713")} refiner-model \u2192 ${color48.cyan(raw)} ${color48.dim("goal refinement will use this model when it passes favorites/active validation")}`
27380
+ message: `${color49.green("\u2713")} refiner-model \u2192 ${color49.cyan(raw)} ${color49.dim("goal refinement will use this model when it passes favorites/active validation")}`
26952
27381
  };
26953
27382
  }
26954
27383
  if (sub === "refiner-fallback-profile") {
@@ -26956,14 +27385,14 @@ function buildSettingsCommand(opts) {
26956
27385
  const currentProfile = opts.configStore.get().autonomy?.refinerFallbackProfile;
26957
27386
  if (!raw) {
26958
27387
  return {
26959
- message: `${color48.amber("Usage:")} /settings refiner-fallback-profile <name> ${color48.dim('(e.g. "default")' + (currentProfile ? ` Current: ${currentProfile}` : ""))}`
27388
+ message: `${color49.amber("Usage:")} /settings refiner-fallback-profile <name> ${color49.dim('(e.g. "default")' + (currentProfile ? ` Current: ${currentProfile}` : ""))}`
26960
27389
  };
26961
27390
  }
26962
27391
  await persistAutonomySetting(persistDeps, (autonomy) => {
26963
27392
  autonomy.refinerFallbackProfile = raw;
26964
27393
  });
26965
27394
  return {
26966
- message: `${color48.green("\u2713")} refiner-fallback-profile \u2192 ${color48.cyan(raw)} ${color48.dim("goal refinement will use the first valid entry from this profile chain")}`
27395
+ message: `${color49.green("\u2713")} refiner-fallback-profile \u2192 ${color49.cyan(raw)} ${color49.dim("goal refinement will use the first valid entry from this profile chain")}`
26967
27396
  };
26968
27397
  }
26969
27398
  if (sub === "refiner-clear") {
@@ -26973,7 +27402,7 @@ function buildSettingsCommand(opts) {
26973
27402
  autonomy.refinerFallbackProfile = void 0;
26974
27403
  });
26975
27404
  return {
26976
- message: `${color48.green("\u2713")} Refiner config cleared ${color48.dim("goal refinement will use the session provider+model")}`
27405
+ message: `${color49.green("\u2713")} Refiner config cleared ${color49.dim("goal refinement will use the session provider+model")}`
26977
27406
  };
26978
27407
  }
26979
27408
  if (sub === "semver-part") {
@@ -26981,7 +27410,7 @@ function buildSettingsCommand(opts) {
26981
27410
  const parts = ["patch", "minor", "major", "auto"];
26982
27411
  if (!parts.includes(raw)) {
26983
27412
  return {
26984
- message: `${color48.amber("Usage:")} /settings semver-part patch|minor|major|auto`
27413
+ message: `${color49.amber("Usage:")} /settings semver-part patch|minor|major|auto`
26985
27414
  };
26986
27415
  }
26987
27416
  await persistConfigSetting({ ...persistDeps, inProjectConfigPath: void 0 }, (cfg) => {
@@ -26990,13 +27419,13 @@ function buildSettingsCommand(opts) {
26990
27419
  cfg.extensions = ext;
26991
27420
  });
26992
27421
  return {
26993
- message: `${color48.green("\u2713")} semver default part \u2192 ${color48.bold(raw)} ${color48.dim("saved to active profile config; used when /semver or semver_bump gets no explicit part")}`
27422
+ message: `${color49.green("\u2713")} semver default part \u2192 ${color49.bold(raw)} ${color49.dim("saved to active profile config; used when /semver or semver_bump gets no explicit part")}`
26994
27423
  };
26995
27424
  }
26996
27425
  if (sub === "breaker") {
26997
27426
  const raw = (rest[0] ?? "").toLowerCase();
26998
27427
  if (!["on", "off"].includes(raw)) {
26999
- return { message: `${color48.amber("Usage:")} /settings breaker on|off` };
27428
+ return { message: `${color49.amber("Usage:")} /settings breaker on|off` };
27000
27429
  }
27001
27430
  const on = raw === "on";
27002
27431
  await persistConfigSetting(persistDeps, (cfg) => {
@@ -27005,20 +27434,20 @@ function buildSettingsCommand(opts) {
27005
27434
  });
27006
27435
  getProcessRegistry().setBreakerConfig({ enabled: on });
27007
27436
  return {
27008
- message: `${color48.green("\u2713")} circuit breaker \u2192 ${on ? color48.cyan("on") : color48.dim("off")} ${color48.dim(on ? "bash/exec gated on repeated failures; trips arm the kill/reset countdown" : "bash/exec always proceed")}`
27437
+ message: `${color49.green("\u2713")} circuit breaker \u2192 ${on ? color49.cyan("on") : color49.dim("off")} ${color49.dim(on ? "bash/exec gated on repeated failures; trips arm the kill/reset countdown" : "bash/exec always proceed")}`
27009
27438
  };
27010
27439
  }
27011
27440
  if (sub === "breaker-timeout") {
27012
27441
  const raw = rest[0];
27013
27442
  if (raw === void 0) {
27014
27443
  return {
27015
- message: `${color48.amber("Usage:")} /settings breaker-timeout <seconds> ${color48.dim("(0 = manual recovery only)")}`
27444
+ message: `${color49.amber("Usage:")} /settings breaker-timeout <seconds> ${color49.dim("(0 = manual recovery only)")}`
27016
27445
  };
27017
27446
  }
27018
27447
  const seconds = Number.parseFloat(raw);
27019
27448
  if (Number.isNaN(seconds) || seconds < 0) {
27020
27449
  return {
27021
- message: `${color48.red("Invalid number")}: "${raw}". Enter seconds, e.g. /settings breaker-timeout 60`
27450
+ message: `${color49.red("Invalid number")}: "${raw}". Enter seconds, e.g. /settings breaker-timeout 60`
27022
27451
  };
27023
27452
  }
27024
27453
  const ms = Math.round(seconds * 1e3);
@@ -27031,7 +27460,7 @@ function buildSettingsCommand(opts) {
27031
27460
  });
27032
27461
  getProcessRegistry().setBreakerConfig({ autoKillResetMs: ms });
27033
27462
  return {
27034
- message: `${color48.green("\u2713")} breaker kill/reset timeout \u2192 ${ms > 0 ? formatDelay(ms) : color48.dim("manual")} ${color48.dim(ms > 0 ? "statusline shows a countdown when the breaker trips" : "breaker trips require /kill reset")}`
27463
+ message: `${color49.green("\u2713")} breaker kill/reset timeout \u2192 ${ms > 0 ? formatDelay(ms) : color49.dim("manual")} ${color49.dim(ms > 0 ? "statusline shows a countdown when the breaker trips" : "breaker trips require /kill reset")}`
27035
27464
  };
27036
27465
  }
27037
27466
  if (sub === "context-mode") {
@@ -27039,7 +27468,7 @@ function buildSettingsCommand(opts) {
27039
27468
  const modes = ["balanced", "frugal", "deep"];
27040
27469
  if (!modes.includes(raw)) {
27041
27470
  return {
27042
- message: `${color48.amber("Usage:")} /settings context-mode balanced|frugal|deep`
27471
+ message: `${color49.amber("Usage:")} /settings context-mode balanced|frugal|deep`
27043
27472
  };
27044
27473
  }
27045
27474
  await persistConfigSetting(persistDeps, (cfg) => {
@@ -27048,7 +27477,7 @@ function buildSettingsCommand(opts) {
27048
27477
  cfg.context = ctx;
27049
27478
  });
27050
27479
  return {
27051
- message: `${color48.green("\u2713")} context mode \u2192 ${color48.cyan(raw)} ${color48.dim("context window policy")}`
27480
+ message: `${color49.green("\u2713")} context mode \u2192 ${color49.cyan(raw)} ${color49.dim("context window policy")}`
27052
27481
  };
27053
27482
  }
27054
27483
  if (sub === "context-strategy") {
@@ -27056,7 +27485,7 @@ function buildSettingsCommand(opts) {
27056
27485
  const strategies = ["hybrid", "intelligent", "selective"];
27057
27486
  if (!strategies.includes(raw)) {
27058
27487
  return {
27059
- message: `${color48.amber("Usage:")} /settings context-strategy hybrid|intelligent|selective`
27488
+ message: `${color49.amber("Usage:")} /settings context-strategy hybrid|intelligent|selective`
27060
27489
  };
27061
27490
  }
27062
27491
  await persistConfigSetting(persistDeps, (cfg) => {
@@ -27065,13 +27494,13 @@ function buildSettingsCommand(opts) {
27065
27494
  cfg.context = ctx;
27066
27495
  });
27067
27496
  return {
27068
- message: `${color48.green("\u2713")} context strategy \u2192 ${color48.cyan(raw)} ${color48.dim("compactor strategy")}`
27497
+ message: `${color49.green("\u2713")} context strategy \u2192 ${color49.cyan(raw)} ${color49.dim("compactor strategy")}`
27069
27498
  };
27070
27499
  }
27071
27500
  if (sub === "context-auto-compact") {
27072
27501
  const raw = (rest[0] ?? "").toLowerCase();
27073
27502
  if (!["on", "off"].includes(raw)) {
27074
- return { message: `${color48.amber("Usage:")} /settings context-auto-compact on|off` };
27503
+ return { message: `${color49.amber("Usage:")} /settings context-auto-compact on|off` };
27075
27504
  }
27076
27505
  const on = raw === "on";
27077
27506
  await persistConfigSetting(persistDeps, (cfg) => {
@@ -27080,13 +27509,13 @@ function buildSettingsCommand(opts) {
27080
27509
  cfg.context = ctx;
27081
27510
  });
27082
27511
  return {
27083
- message: `${color48.green("\u2713")} context auto-compact \u2192 ${on ? color48.cyan("on") : color48.dim("off")} ${color48.dim("auto-compact context when thresholds crossed")}`
27512
+ message: `${color49.green("\u2713")} context auto-compact \u2192 ${on ? color49.cyan("on") : color49.dim("off")} ${color49.dim("auto-compact context when thresholds crossed")}`
27084
27513
  };
27085
27514
  }
27086
27515
  if (sub === "nextsteps-tool") {
27087
27516
  const raw = (rest[0] ?? "").toLowerCase();
27088
27517
  if (!["on", "off"].includes(raw)) {
27089
- return { message: `${color48.amber("Usage:")} /settings nextsteps-tool on|off` };
27518
+ return { message: `${color49.amber("Usage:")} /settings nextsteps-tool on|off` };
27090
27519
  }
27091
27520
  const on = raw === "on";
27092
27521
  await persistConfigSetting(persistDeps, (cfg) => {
@@ -27095,7 +27524,7 @@ function buildSettingsCommand(opts) {
27095
27524
  cfg.tools = tools;
27096
27525
  });
27097
27526
  return {
27098
- message: `${color48.green("\u2713")} nextsteps tool \u2192 ${on ? color48.cyan("on") : color48.dim("off")} ${color48.dim("takes effect in the next session")}`
27527
+ message: `${color49.green("\u2713")} nextsteps tool \u2192 ${on ? color49.cyan("on") : color49.dim("off")} ${color49.dim("takes effect in the next session")}`
27099
27528
  };
27100
27529
  }
27101
27530
  if (sub === "token-saving") {
@@ -27103,7 +27532,7 @@ function buildSettingsCommand(opts) {
27103
27532
  const tiers = ["off", "minimal", "light", "medium", "aggressive"];
27104
27533
  if (!tiers.includes(raw)) {
27105
27534
  return {
27106
- message: `${color48.amber("Usage:")} /settings token-saving off|minimal|light|medium|aggressive`
27535
+ message: `${color49.amber("Usage:")} /settings token-saving off|minimal|light|medium|aggressive`
27107
27536
  };
27108
27537
  }
27109
27538
  await persistConfigSetting(persistDeps, (cfg) => {
@@ -27112,47 +27541,47 @@ function buildSettingsCommand(opts) {
27112
27541
  cfg.features = feat;
27113
27542
  });
27114
27543
  return {
27115
- message: `${color48.green("\u2713")} token-saving \u2192 ${color48.cyan(raw)} ${color48.dim("token-saving mode")}`
27544
+ message: `${color49.green("\u2713")} token-saving \u2192 ${color49.cyan(raw)} ${color49.dim("token-saving mode")}`
27116
27545
  };
27117
27546
  }
27118
27547
  if (sub === "max-concurrent") {
27119
27548
  const raw = rest[0];
27120
27549
  if (raw === void 0) {
27121
27550
  return {
27122
- message: `${color48.amber("Usage:")} /settings max-concurrent <n> ${color48.dim("(0 = default)")}`
27551
+ message: `${color49.amber("Usage:")} /settings max-concurrent <n> ${color49.dim("(0 = default)")}`
27123
27552
  };
27124
27553
  }
27125
27554
  const n = Number.parseInt(raw, 10);
27126
27555
  if (Number.isNaN(n) || n < 0) {
27127
27556
  return {
27128
- message: `${color48.red("Invalid number")}: "${raw}". Enter a non-negative integer (0 = default)`
27557
+ message: `${color49.red("Invalid number")}: "${raw}". Enter a non-negative integer (0 = default)`
27129
27558
  };
27130
27559
  }
27131
27560
  await persistConfigSetting(persistDeps, (cfg) => {
27132
27561
  cfg.maxConcurrent = n;
27133
27562
  });
27134
27563
  return {
27135
- message: `${color48.green("\u2713")} max-concurrent \u2192 ${color48.cyan(n === 0 ? "default" : String(n))} ${color48.dim("max concurrent subagents")}`
27564
+ message: `${color49.green("\u2713")} max-concurrent \u2192 ${color49.cyan(n === 0 ? "default" : String(n))} ${color49.dim("max concurrent subagents")}`
27136
27565
  };
27137
27566
  }
27138
27567
  if (sub === "title-animation") {
27139
27568
  const raw = (rest[0] ?? "").toLowerCase();
27140
27569
  if (!["on", "off"].includes(raw)) {
27141
- return { message: `${color48.amber("Usage:")} /settings title-animation on|off` };
27570
+ return { message: `${color49.amber("Usage:")} /settings title-animation on|off` };
27142
27571
  }
27143
27572
  const on = raw === "on";
27144
27573
  await persistAutonomySetting(persistDeps, (autonomy) => {
27145
27574
  autonomy.terminalTitleAnimation = on;
27146
27575
  });
27147
27576
  return {
27148
- message: `${color48.green("\u2713")} title animation \u2192 ${on ? color48.cyan("on") : color48.dim("off")} ${color48.dim("terminal title animation")}`
27577
+ message: `${color49.green("\u2713")} title animation \u2192 ${on ? color49.cyan("on") : color49.dim("off")} ${color49.dim("terminal title animation")}`
27149
27578
  };
27150
27579
  }
27151
27580
  if (sub === "reasoning") {
27152
27581
  const raw = (rest[0] ?? "").toLowerCase();
27153
27582
  const modes = ["auto", "on", "off"];
27154
27583
  if (!modes.includes(raw)) {
27155
- return { message: `${color48.amber("Usage:")} /settings reasoning auto|on|off` };
27584
+ return { message: `${color49.amber("Usage:")} /settings reasoning auto|on|off` };
27156
27585
  }
27157
27586
  await persistConfigSetting(persistDeps, (cfg) => {
27158
27587
  const mr = cfg.modelRuntime;
@@ -27160,14 +27589,14 @@ function buildSettingsCommand(opts) {
27160
27589
  reasoning.mode = raw;
27161
27590
  cfg.modelRuntime = { ...mr, reasoning };
27162
27591
  });
27163
- return { message: `${color48.green("\u2713")} reasoning mode \u2192 ${color48.bold(raw)}` };
27592
+ return { message: `${color49.green("\u2713")} reasoning mode \u2192 ${color49.bold(raw)}` };
27164
27593
  }
27165
27594
  if (sub === "reasoning-effort") {
27166
27595
  const raw = (rest[0] ?? "").toLowerCase();
27167
27596
  const efforts = ["none", "minimal", "low", "medium", "high", "xhigh", "max"];
27168
27597
  if (!efforts.includes(raw)) {
27169
27598
  return {
27170
- message: `${color48.amber("Usage:")} /settings reasoning-effort none|minimal|low|medium|high|xhigh|max`
27599
+ message: `${color49.amber("Usage:")} /settings reasoning-effort none|minimal|low|medium|high|xhigh|max`
27171
27600
  };
27172
27601
  }
27173
27602
  await persistConfigSetting(persistDeps, (cfg) => {
@@ -27176,12 +27605,12 @@ function buildSettingsCommand(opts) {
27176
27605
  reasoning.effort = raw;
27177
27606
  cfg.modelRuntime = { ...mr, reasoning };
27178
27607
  });
27179
- return { message: `${color48.green("\u2713")} reasoning effort \u2192 ${color48.bold(raw)}` };
27608
+ return { message: `${color49.green("\u2713")} reasoning effort \u2192 ${color49.bold(raw)}` };
27180
27609
  }
27181
27610
  if (sub === "reasoning-preserve") {
27182
27611
  const raw = (rest[0] ?? "").toLowerCase();
27183
27612
  if (!["on", "off"].includes(raw)) {
27184
- return { message: `${color48.amber("Usage:")} /settings reasoning-preserve on|off` };
27613
+ return { message: `${color49.amber("Usage:")} /settings reasoning-preserve on|off` };
27185
27614
  }
27186
27615
  const on = raw === "on";
27187
27616
  await persistConfigSetting(persistDeps, (cfg) => {
@@ -27191,24 +27620,24 @@ function buildSettingsCommand(opts) {
27191
27620
  cfg.modelRuntime = { ...mr, reasoning };
27192
27621
  });
27193
27622
  return {
27194
- message: `${color48.green("\u2713")} reasoning preserve \u2192 ${on ? color48.cyan("on") : color48.dim("off")}`
27623
+ message: `${color49.green("\u2713")} reasoning preserve \u2192 ${on ? color49.cyan("on") : color49.dim("off")}`
27195
27624
  };
27196
27625
  }
27197
27626
  if (sub === "cache-ttl") {
27198
27627
  const raw = (rest[0] ?? "").toLowerCase();
27199
27628
  if (!["5m", "1h"].includes(raw)) {
27200
- return { message: `${color48.amber("Usage:")} /settings cache-ttl 5m|1h` };
27629
+ return { message: `${color49.amber("Usage:")} /settings cache-ttl 5m|1h` };
27201
27630
  }
27202
27631
  await persistConfigSetting(persistDeps, (cfg) => {
27203
27632
  const mr = cfg.modelRuntime;
27204
27633
  cfg.modelRuntime = { ...mr, cache: { ttl: raw } };
27205
27634
  });
27206
- return { message: `${color48.green("\u2713")} cache TTL \u2192 ${color48.bold(raw)}` };
27635
+ return { message: `${color49.green("\u2713")} cache TTL \u2192 ${color49.bold(raw)}` };
27207
27636
  }
27208
27637
  if (sub === "mcp") {
27209
27638
  const raw = (rest[0] ?? "").toLowerCase();
27210
27639
  if (!["on", "off"].includes(raw))
27211
- return { message: `${color48.amber("Usage:")} /settings mcp on|off` };
27640
+ return { message: `${color49.amber("Usage:")} /settings mcp on|off` };
27212
27641
  const on = raw === "on";
27213
27642
  await persistConfigSetting(persistDeps, (cfg) => {
27214
27643
  const feats = cfg.features ?? {};
@@ -27216,13 +27645,13 @@ function buildSettingsCommand(opts) {
27216
27645
  cfg.features = feats;
27217
27646
  });
27218
27647
  return {
27219
- message: `${color48.green("\u2713")} MCP features \u2192 ${on ? color48.cyan("on") : color48.dim("off")} ${color48.dim("restart to apply")}`
27648
+ message: `${color49.green("\u2713")} MCP features \u2192 ${on ? color49.cyan("on") : color49.dim("off")} ${color49.dim("restart to apply")}`
27220
27649
  };
27221
27650
  }
27222
27651
  if (sub === "plugins") {
27223
27652
  const raw = (rest[0] ?? "").toLowerCase();
27224
27653
  if (!["on", "off"].includes(raw))
27225
- return { message: `${color48.amber("Usage:")} /settings plugins on|off` };
27654
+ return { message: `${color49.amber("Usage:")} /settings plugins on|off` };
27226
27655
  const on = raw === "on";
27227
27656
  await persistConfigSetting(persistDeps, (cfg) => {
27228
27657
  const feats = cfg.features ?? {};
@@ -27230,13 +27659,13 @@ function buildSettingsCommand(opts) {
27230
27659
  cfg.features = feats;
27231
27660
  });
27232
27661
  return {
27233
- message: `${color48.green("\u2713")} Plugin features \u2192 ${on ? color48.cyan("on") : color48.dim("off")} ${color48.dim("restart to apply")}`
27662
+ message: `${color49.green("\u2713")} Plugin features \u2192 ${on ? color49.cyan("on") : color49.dim("off")} ${color49.dim("restart to apply")}`
27234
27663
  };
27235
27664
  }
27236
27665
  if (sub === "memory") {
27237
27666
  const raw = (rest[0] ?? "").toLowerCase();
27238
27667
  if (!["on", "off"].includes(raw))
27239
- return { message: `${color48.amber("Usage:")} /settings memory on|off` };
27668
+ return { message: `${color49.amber("Usage:")} /settings memory on|off` };
27240
27669
  const on = raw === "on";
27241
27670
  await persistConfigSetting(persistDeps, (cfg) => {
27242
27671
  const feats = cfg.features ?? {};
@@ -27244,13 +27673,13 @@ function buildSettingsCommand(opts) {
27244
27673
  cfg.features = feats;
27245
27674
  });
27246
27675
  return {
27247
- message: `${color48.green("\u2713")} Memory features \u2192 ${on ? color48.cyan("on") : color48.dim("off")} ${color48.dim("restart to apply")}`
27676
+ message: `${color49.green("\u2713")} Memory features \u2192 ${on ? color49.cyan("on") : color49.dim("off")} ${color49.dim("restart to apply")}`
27248
27677
  };
27249
27678
  }
27250
27679
  if (sub === "skills") {
27251
27680
  const raw = (rest[0] ?? "").toLowerCase();
27252
27681
  if (!["on", "off"].includes(raw))
27253
- return { message: `${color48.amber("Usage:")} /settings skills on|off` };
27682
+ return { message: `${color49.amber("Usage:")} /settings skills on|off` };
27254
27683
  const on = raw === "on";
27255
27684
  await persistConfigSetting(persistDeps, (cfg) => {
27256
27685
  const feats = cfg.features ?? {};
@@ -27258,13 +27687,13 @@ function buildSettingsCommand(opts) {
27258
27687
  cfg.features = feats;
27259
27688
  });
27260
27689
  return {
27261
- message: `${color48.green("\u2713")} Skills features \u2192 ${on ? color48.cyan("on") : color48.dim("off")} ${color48.dim("restart to apply")}`
27690
+ message: `${color49.green("\u2713")} Skills features \u2192 ${on ? color49.cyan("on") : color49.dim("off")} ${color49.dim("restart to apply")}`
27262
27691
  };
27263
27692
  }
27264
27693
  if (sub === "models-registry") {
27265
27694
  const raw = (rest[0] ?? "").toLowerCase();
27266
27695
  if (!["on", "off"].includes(raw))
27267
- return { message: `${color48.amber("Usage:")} /settings models-registry on|off` };
27696
+ return { message: `${color49.amber("Usage:")} /settings models-registry on|off` };
27268
27697
  const on = raw === "on";
27269
27698
  await persistConfigSetting(persistDeps, (cfg) => {
27270
27699
  const feats = cfg.features ?? {};
@@ -27272,7 +27701,7 @@ function buildSettingsCommand(opts) {
27272
27701
  cfg.features = feats;
27273
27702
  });
27274
27703
  return {
27275
- message: `${color48.green("\u2713")} Models registry \u2192 ${on ? color48.cyan("on") : color48.dim("off")} ${color48.dim("restart to apply")}`
27704
+ message: `${color49.green("\u2713")} Models registry \u2192 ${on ? color49.cyan("on") : color49.dim("off")} ${color49.dim("restart to apply")}`
27276
27705
  };
27277
27706
  }
27278
27707
  if (sub === "stream-fleet") {
@@ -27280,7 +27709,7 @@ function buildSettingsCommand(opts) {
27280
27709
  const mode = raw === "on" ? "full" : raw === "off" || raw === "full" ? raw : void 0;
27281
27710
  if (!mode)
27282
27711
  return {
27283
- message: `${color48.amber("Usage:")} /settings stream-fleet off|full (on = full)`
27712
+ message: `${color49.amber("Usage:")} /settings stream-fleet off|full (on = full)`
27284
27713
  };
27285
27714
  await persistAutonomySetting(persistDeps, (autonomy) => {
27286
27715
  autonomy.fleetChatVerbosity = mode;
@@ -27288,43 +27717,43 @@ function buildSettingsCommand(opts) {
27288
27717
  opts.fleetStreamController?.setMode(mode);
27289
27718
  const desc = mode === "full" ? "every subagent tool call and message in chat" : "subagent chat lines hidden (F2/F3 stay live)";
27290
27719
  return {
27291
- message: `${color48.green("\u2713")} fleet chat \u2192 ${color48.cyan(mode)} ${color48.dim(desc)}`
27720
+ message: `${color49.green("\u2713")} fleet chat \u2192 ${color49.cyan(mode)} ${color49.dim(desc)}`
27292
27721
  };
27293
27722
  }
27294
27723
  if (sub === "chime") {
27295
27724
  const raw = (rest[0] ?? "").toLowerCase();
27296
27725
  if (!["on", "off"].includes(raw))
27297
- return { message: `${color48.amber("Usage:")} /settings chime on|off` };
27726
+ return { message: `${color49.amber("Usage:")} /settings chime on|off` };
27298
27727
  const on = raw === "on";
27299
27728
  await persistAutonomySetting(persistDeps, (autonomy) => {
27300
27729
  autonomy.chime = on;
27301
27730
  });
27302
27731
  return {
27303
- message: `${color48.green("\u2713")} completion chime \u2192 ${on ? color48.cyan("on") : color48.dim("off")}`
27732
+ message: `${color49.green("\u2713")} completion chime \u2192 ${on ? color49.cyan("on") : color49.dim("off")}`
27304
27733
  };
27305
27734
  }
27306
27735
  if (sub === "confirm-exit") {
27307
27736
  const raw = (rest[0] ?? "").toLowerCase();
27308
27737
  if (!["on", "off"].includes(raw))
27309
- return { message: `${color48.amber("Usage:")} /settings confirm-exit on|off` };
27738
+ return { message: `${color49.amber("Usage:")} /settings confirm-exit on|off` };
27310
27739
  const on = raw === "on";
27311
27740
  await persistAutonomySetting(persistDeps, (autonomy) => {
27312
27741
  autonomy.confirmExit = on;
27313
27742
  });
27314
27743
  return {
27315
- message: `${color48.green("\u2713")} confirm before exit \u2192 ${on ? color48.cyan("on") : color48.dim("off")}`
27744
+ message: `${color49.green("\u2713")} confirm before exit \u2192 ${on ? color49.cyan("on") : color49.dim("off")}`
27316
27745
  };
27317
27746
  }
27318
27747
  if (sub === "max-iterations") {
27319
27748
  const raw = rest[0];
27320
27749
  if (raw === void 0)
27321
27750
  return {
27322
- message: `${color48.amber("Usage:")} /settings max-iterations <n> ${color48.dim("(0 = default)")}`
27751
+ message: `${color49.amber("Usage:")} /settings max-iterations <n> ${color49.dim("(0 = default)")}`
27323
27752
  };
27324
27753
  const n = Number.parseInt(raw, 10);
27325
27754
  if (Number.isNaN(n) || n < 0)
27326
27755
  return {
27327
- message: `${color48.red("Invalid number")}: "${raw}". Enter a non-negative integer.`
27756
+ message: `${color49.red("Invalid number")}: "${raw}". Enter a non-negative integer.`
27328
27757
  };
27329
27758
  await persistConfigSetting(persistDeps, (cfg) => {
27330
27759
  const tools = cfg.tools ?? {};
@@ -27332,31 +27761,31 @@ function buildSettingsCommand(opts) {
27332
27761
  cfg.tools = tools;
27333
27762
  });
27334
27763
  return {
27335
- message: `${color48.green("\u2713")} max iterations \u2192 ${color48.cyan(n === 0 ? "default" : String(n))} ${color48.dim("agent pauses after this many iterations")}`
27764
+ message: `${color49.green("\u2713")} max iterations \u2192 ${color49.cyan(n === 0 ? "default" : String(n))} ${color49.dim("agent pauses after this many iterations")}`
27336
27765
  };
27337
27766
  }
27338
27767
  if (sub === "auto-proceed-max-iterations") {
27339
27768
  const raw = rest[0];
27340
27769
  if (raw === void 0)
27341
27770
  return {
27342
- message: `${color48.amber("Usage:")} /settings auto-proceed-max-iterations <n> ${color48.dim("(0 = unlimited)")}`
27771
+ message: `${color49.amber("Usage:")} /settings auto-proceed-max-iterations <n> ${color49.dim("(0 = unlimited)")}`
27343
27772
  };
27344
27773
  const n = Number.parseInt(raw, 10);
27345
27774
  if (Number.isNaN(n) || n < 0)
27346
27775
  return {
27347
- message: `${color48.red("Invalid number")}: "${raw}". Enter a non-negative integer.`
27776
+ message: `${color49.red("Invalid number")}: "${raw}". Enter a non-negative integer.`
27348
27777
  };
27349
27778
  await persistAutonomySetting(persistDeps, (autonomy) => {
27350
27779
  autonomy.autoProceedMaxIterations = n;
27351
27780
  });
27352
27781
  return {
27353
- message: `${color48.green("\u2713")} auto-proceed max iterations \u2192 ${color48.cyan(n === 0 ? "unlimited" : String(n))}`
27782
+ message: `${color49.green("\u2713")} auto-proceed max iterations \u2192 ${color49.cyan(n === 0 ? "unlimited" : String(n))}`
27354
27783
  };
27355
27784
  }
27356
27785
  if (sub === "index-on-start") {
27357
27786
  const raw = (rest[0] ?? "").toLowerCase();
27358
27787
  if (!["on", "off"].includes(raw))
27359
- return { message: `${color48.amber("Usage:")} /settings index-on-start on|off` };
27788
+ return { message: `${color49.amber("Usage:")} /settings index-on-start on|off` };
27360
27789
  const on = raw === "on";
27361
27790
  await persistConfigSetting(persistDeps, (cfg) => {
27362
27791
  const idx = cfg.indexing ?? {};
@@ -27364,7 +27793,7 @@ function buildSettingsCommand(opts) {
27364
27793
  cfg.indexing = idx;
27365
27794
  });
27366
27795
  return {
27367
- message: `${color48.green("\u2713")} index on session start \u2192 ${on ? color48.cyan("on") : color48.dim("off")} ${color48.dim("effective next session")}`
27796
+ message: `${color49.green("\u2713")} index on session start \u2192 ${on ? color49.cyan("on") : color49.dim("off")} ${color49.dim("effective next session")}`
27368
27797
  };
27369
27798
  }
27370
27799
  if (sub === "log-level") {
@@ -27372,21 +27801,21 @@ function buildSettingsCommand(opts) {
27372
27801
  const levels = ["error", "warn", "info", "debug", "trace"];
27373
27802
  if (!levels.includes(raw))
27374
27803
  return {
27375
- message: `${color48.amber("Usage:")} /settings log-level error|warn|info|debug|trace`
27804
+ message: `${color49.amber("Usage:")} /settings log-level error|warn|info|debug|trace`
27376
27805
  };
27377
27806
  await persistConfigSetting(persistDeps, (cfg) => {
27378
27807
  const log = cfg.log ?? {};
27379
27808
  log.level = raw;
27380
27809
  cfg.log = log;
27381
27810
  });
27382
- return { message: `${color48.green("\u2713")} log level \u2192 ${color48.cyan(raw)}` };
27811
+ return { message: `${color49.green("\u2713")} log level \u2192 ${color49.cyan(raw)}` };
27383
27812
  }
27384
27813
  if (sub === "audit-level") {
27385
27814
  const raw = (rest[0] ?? "").toLowerCase();
27386
27815
  const levels = ["minimal", "standard", "full"];
27387
27816
  if (!levels.includes(raw))
27388
27817
  return {
27389
- message: `${color48.amber("Usage:")} /settings audit-level minimal|standard|full`
27818
+ message: `${color49.amber("Usage:")} /settings audit-level minimal|standard|full`
27390
27819
  };
27391
27820
  await persistConfigSetting(persistDeps, (cfg) => {
27392
27821
  const sess = cfg.session ?? {};
@@ -27394,38 +27823,38 @@ function buildSettingsCommand(opts) {
27394
27823
  cfg.session = sess;
27395
27824
  });
27396
27825
  return {
27397
- message: `${color48.green("\u2713")} audit level \u2192 ${color48.cyan(raw)} ${color48.dim("restart to apply")}`
27826
+ message: `${color49.green("\u2713")} audit level \u2192 ${color49.cyan(raw)} ${color49.dim("restart to apply")}`
27398
27827
  };
27399
27828
  }
27400
27829
  if (sub === "thinking-word") {
27401
27830
  const raw = rest.join(" ").trim();
27402
27831
  if (!raw)
27403
27832
  return {
27404
- message: `${color48.amber("Usage:")} /settings thinking-word <word> ${color48.dim('single short word, e.g. "thinking", "vibing", "cooking"')}`
27833
+ message: `${color49.amber("Usage:")} /settings thinking-word <word> ${color49.dim('single short word, e.g. "thinking", "vibing", "cooking"')}`
27405
27834
  };
27406
27835
  if (raw.length > 16)
27407
- return { message: `${color48.red("Word too long")}: max 16 characters.` };
27836
+ return { message: `${color49.red("Word too long")}: max 16 characters.` };
27408
27837
  await persistAutonomySetting(persistDeps, (autonomy) => {
27409
27838
  autonomy.thinkingWord = raw;
27410
27839
  });
27411
- return { message: `${color48.green("\u2713")} thinking word \u2192 ${color48.cyan(raw)}` };
27840
+ return { message: `${color49.green("\u2713")} thinking word \u2192 ${color49.cyan(raw)}` };
27412
27841
  }
27413
27842
  if (sub === "statusline") {
27414
27843
  const raw = (rest[0] ?? "").toLowerCase();
27415
27844
  const modes = ["minimum", "detailed", "no-color"];
27416
27845
  if (!modes.includes(raw))
27417
27846
  return {
27418
- message: `${color48.amber("Usage:")} /settings statusline minimum|detailed|no-color`
27847
+ message: `${color49.amber("Usage:")} /settings statusline minimum|detailed|no-color`
27419
27848
  };
27420
27849
  await persistAutonomySetting(persistDeps, (autonomy) => {
27421
27850
  autonomy.statuslineMode = raw;
27422
27851
  });
27423
- return { message: `${color48.green("\u2713")} statusline mode \u2192 ${color48.cyan(raw)}` };
27852
+ return { message: `${color49.green("\u2713")} statusline mode \u2192 ${color49.cyan(raw)}` };
27424
27853
  }
27425
27854
  if (sub === "read-symbols") {
27426
27855
  const raw = (rest[0] ?? "").toLowerCase();
27427
27856
  if (!["on", "off"].includes(raw)) {
27428
- return { message: `${color48.amber("Usage:")} /settings read-symbols on|off` };
27857
+ return { message: `${color49.amber("Usage:")} /settings read-symbols on|off` };
27429
27858
  }
27430
27859
  const on = raw === "on";
27431
27860
  await persistAutonomySetting(persistDeps, (autonomy) => {
@@ -27435,7 +27864,7 @@ function buildSettingsCommand(opts) {
27435
27864
  opts.context.meta["tools.read.advancedMode"] = on;
27436
27865
  }
27437
27866
  return {
27438
- message: `${color48.green("\u2713")} read symbols \u2192 ${on ? color48.cyan("on") : color48.dim("off")} ${color48.dim(on ? "codebase-index symbols will be included in read tool results" : "read tool returns file content only")}`
27867
+ message: `${color49.green("\u2713")} read symbols \u2192 ${on ? color49.cyan("on") : color49.dim("off")} ${color49.dim(on ? "codebase-index symbols will be included in read tool results" : "read tool returns file content only")}`
27439
27868
  };
27440
27869
  }
27441
27870
  if (sub === "animation") {
@@ -27443,19 +27872,19 @@ function buildSettingsCommand(opts) {
27443
27872
  const styles = ["rainbow", "wave", "pulse", "dots", "breathe", "cycle"];
27444
27873
  if (!styles.includes(raw))
27445
27874
  return {
27446
- message: `${color48.amber("Usage:")} /settings animation rainbow|wave|pulse|dots|breathe|cycle`
27875
+ message: `${color49.amber("Usage:")} /settings animation rainbow|wave|pulse|dots|breathe|cycle`
27447
27876
  };
27448
27877
  await persistAutonomySetting(persistDeps, (autonomy) => {
27449
27878
  autonomy.animationStyle = raw;
27450
27879
  });
27451
- return { message: `${color48.green("\u2713")} animation style \u2192 ${color48.cyan(raw)}` };
27880
+ return { message: `${color49.green("\u2713")} animation style \u2192 ${color49.cyan(raw)}` };
27452
27881
  }
27453
27882
  return {
27454
- message: `${color48.red("Unknown setting")} "${sub}". ${unknownSubcommand(sub, ["delay", "mode", "hints", "debug-stream", "config-scope", "fs-access", "refine", "refine-delay", "refine-language", "refiner-provider", "refiner-model", "refiner-fallback-profile", "refiner-clear", "semver-part", "breaker", "breaker-timeout", "context-mode", "context-strategy", "context-auto-compact", "token-saving", "max-concurrent", "title-animation", "reasoning", "reasoning-effort", "reasoning-preserve", "cache-ttl", "stream-fleet", "chime", "confirm-exit", "mcp", "plugins", "memory", "skills", "models-registry", "max-iterations", "auto-proceed-max-iterations", "index-on-start", "log-level", "audit-level", "thinking-word", "statusline", "animation", "read-symbols", "defaults"], "settings")}`
27883
+ message: `${color49.red("Unknown setting")} "${sub}". ${unknownSubcommand(sub, ["delay", "mode", "hints", "debug-stream", "config-scope", "fs-access", "refine", "refine-delay", "refine-language", "refiner-provider", "refiner-model", "refiner-fallback-profile", "refiner-clear", "semver-part", "breaker", "breaker-timeout", "context-mode", "context-strategy", "context-auto-compact", "token-saving", "max-concurrent", "title-animation", "reasoning", "reasoning-effort", "reasoning-preserve", "cache-ttl", "stream-fleet", "chime", "confirm-exit", "mcp", "plugins", "memory", "skills", "models-registry", "max-iterations", "auto-proceed-max-iterations", "index-on-start", "log-level", "audit-level", "thinking-word", "statusline", "animation", "read-symbols", "defaults"], "settings")}`
27455
27884
  };
27456
27885
  } catch (err) {
27457
27886
  return {
27458
- message: `${color48.red("Settings error")}: ${toErrorMessage24(err)}`
27887
+ message: `${color49.red("Settings error")}: ${toErrorMessage24(err)}`
27459
27888
  };
27460
27889
  }
27461
27890
  }
@@ -27464,7 +27893,7 @@ function buildSettingsCommand(opts) {
27464
27893
 
27465
27894
  // src/slash-commands/shadow.ts
27466
27895
  import { ToolValidationError as ToolValidationError5 } from "@wrongstack/core/types";
27467
- import { color as color49 } from "@wrongstack/core/utils";
27896
+ import { color as color50 } from "@wrongstack/core/utils";
27468
27897
  var DEFAULT_SHADOW_INTERVAL_MS = 3e4;
27469
27898
  var MIN_SHADOW_INTERVAL_MS = 5e3;
27470
27899
  function buildShadowCommand(opts) {
@@ -27534,7 +27963,7 @@ function buildShadowCommand(opts) {
27534
27963
  if (opts.shadowController?.activeId != null) {
27535
27964
  return {
27536
27965
  message: [
27537
- `${color49.yellow("\u26A0")} A Shadow Agent is already running (${opts.shadowController.activeId.slice(0, 8)}).`,
27966
+ `${color50.yellow("\u26A0")} A Shadow Agent is already running (${opts.shadowController.activeId.slice(0, 8)}).`,
27538
27967
  "",
27539
27968
  "Only one Shadow Agent instance is allowed per session.",
27540
27969
  "Use /shadow status to view the current instance."
@@ -27573,16 +28002,16 @@ function buildShadowCommand(opts) {
27573
28002
  shadowIntervalMs: intervalMs
27574
28003
  });
27575
28004
  return {
27576
- message: `${color49.green("\u2713")} Shadow Agent queued: ${spawnId}
27577
- ${color49.dim("Mode:")} one-shot quiet check
27578
- ${color49.dim("Model:")} ${modelRef.label}`
28005
+ message: `${color50.green("\u2713")} Shadow Agent queued: ${spawnId}
28006
+ ${color50.dim("Mode:")} one-shot quiet check
28007
+ ${color50.dim("Model:")} ${modelRef.label}`
27579
28008
  };
27580
28009
  }
27581
28010
  case "stop": {
27582
28011
  const activeId = opts.shadowController?.activeId;
27583
28012
  if (!activeId) {
27584
28013
  return {
27585
- message: `${color49.yellow("\u26A0")} No active Shadow Agent is registered for this session.`
28014
+ message: `${color50.yellow("\u26A0")} No active Shadow Agent is registered for this session.`
27586
28015
  };
27587
28016
  }
27588
28017
  if (!opts.onFleetTerminate) {
@@ -27591,12 +28020,12 @@ ${color49.dim("Model:")} ${modelRef.label}`
27591
28020
  const ok = await opts.onFleetTerminate(activeId);
27592
28021
  if (ok) {
27593
28022
  opts.shadowController?.clear();
27594
- return { message: `${color49.green("\u2713")} Shadow Agent stopped: ${activeId}` };
28023
+ return { message: `${color50.green("\u2713")} Shadow Agent stopped: ${activeId}` };
27595
28024
  }
27596
28025
  return {
27597
28026
  message: [
27598
- `${color49.red("\u2717")} Failed to stop Shadow Agent ${color49.bold(activeId)}.`,
27599
- `It may already be stopped. Use ${color49.bold("/shadow status")} to inspect active agents.`
28027
+ `${color50.red("\u2717")} Failed to stop Shadow Agent ${color50.bold(activeId)}.`,
28028
+ `It may already be stopped. Use ${color50.bold("/shadow status")} to inspect active agents.`
27600
28029
  ].join("\n")
27601
28030
  };
27602
28031
  }
@@ -27624,10 +28053,10 @@ ${color49.dim("Model:")} ${modelRef.label}`
27624
28053
  opts.shadowController?.clear();
27625
28054
  return {
27626
28055
  message: [
27627
- `${color49.red("\u26A0")} HOOP: Stopped ${killed} running agent(s)`,
28056
+ `${color50.red("\u26A0")} HOOP: Stopped ${killed} running agent(s)`,
27628
28057
  "",
27629
- `Target: ${color49.bold("all")}`,
27630
- `Reason: ${color49.yellow(reason)}`
28058
+ `Target: ${color50.bold("all")}`,
28059
+ `Reason: ${color50.yellow(reason)}`
27631
28060
  ].join("\n")
27632
28061
  };
27633
28062
  }
@@ -27641,10 +28070,10 @@ ${color49.dim("Model:")} ${modelRef.label}`
27641
28070
  }
27642
28071
  return {
27643
28072
  message: [
27644
- ok ? `${color49.red("\u26A0")} HOOP: Stopped agent` : `${color49.red("\u2717")} HOOP: Failed to stop agent`,
28073
+ ok ? `${color50.red("\u26A0")} HOOP: Stopped agent` : `${color50.red("\u2717")} HOOP: Failed to stop agent`,
27645
28074
  "",
27646
- `Target: ${color49.bold(targetId)}`,
27647
- `Reason: ${color49.yellow(reason)}`,
28075
+ `Target: ${color50.bold(targetId)}`,
28076
+ `Reason: ${color50.yellow(reason)}`,
27648
28077
  agentInfo ? `
27649
28078
  Agent info:
27650
28079
  ${agentInfo}` : ""
@@ -27669,7 +28098,7 @@ Current default: ${defaultModelRef.label}`
27669
28098
  opts.shadowController?.setDefaults?.({ provider: parsed.provider, model: parsed.model });
27670
28099
  return {
27671
28100
  message: `/shadow model ${parsed.label}
27672
- ${color49.dim("Model will be applied on next /shadow start")}`
28101
+ ${color50.dim("Model will be applied on next /shadow start")}`
27673
28102
  };
27674
28103
  }
27675
28104
  case "interval": {
@@ -27689,7 +28118,7 @@ Current default: ${DEFAULT_SHADOW_INTERVAL_MS}ms (30 seconds)`
27689
28118
  opts.shadowController?.setDefaults?.({ intervalMs: ms });
27690
28119
  return {
27691
28120
  message: `/shadow interval ${ms}ms
27692
- ${color49.dim("Interval will be applied on next /shadow start")}`
28121
+ ${color50.dim("Interval will be applied on next /shadow start")}`
27693
28122
  };
27694
28123
  }
27695
28124
  default: {
@@ -27962,7 +28391,7 @@ function buildStatuslineCommand(deps) {
27962
28391
  }
27963
28392
 
27964
28393
  // src/slash-commands/supervisor.ts
27965
- import { color as color50 } from "@wrongstack/core/utils";
28394
+ import { color as color51 } from "@wrongstack/core/utils";
27966
28395
  function fmtAge4(at) {
27967
28396
  const s = Math.max(0, Math.round((Date.now() - at) / 1e3));
27968
28397
  if (s < 60) return `${s}s ago`;
@@ -27998,13 +28427,13 @@ function buildSupervisorCommand(opts) {
27998
28427
  }
27999
28428
  if (sub === "on") {
28000
28429
  supervisor.start();
28001
- const msg2 = `Fleet supervisor ${color50.green("armed")} \u2014 evaluating every ${Math.round(supervisor.configSnapshot().intervalMs / 1e3)}s.`;
28430
+ const msg2 = `Fleet supervisor ${color51.green("armed")} \u2014 evaluating every ${Math.round(supervisor.configSnapshot().intervalMs / 1e3)}s.`;
28002
28431
  opts.renderer.write(msg2);
28003
28432
  return { message: msg2 };
28004
28433
  }
28005
28434
  if (sub === "off") {
28006
28435
  supervisor.stop();
28007
- const msg2 = `Fleet supervisor ${color50.yellow("disarmed")} \u2014 no further automatic interventions this session.`;
28436
+ const msg2 = `Fleet supervisor ${color51.yellow("disarmed")} \u2014 no further automatic interventions this session.`;
28008
28437
  opts.renderer.write(msg2);
28009
28438
  return { message: msg2 };
28010
28439
  }
@@ -28017,10 +28446,10 @@ function buildSupervisorCommand(opts) {
28017
28446
  return { message: msg3 };
28018
28447
  }
28019
28448
  const lines2 = entries.map((e) => {
28020
- const who = e.subagentId ? ` ${color50.cyan(e.subagentId)}` : "";
28449
+ const who = e.subagentId ? ` ${color51.cyan(e.subagentId)}` : "";
28021
28450
  const task = e.taskId ? ` task=${e.taskId.slice(0, 8)}` : "";
28022
- const outcome = e.outcome === "approved" ? color50.green(e.outcome) : e.outcome === "denied" || e.outcome === "error" ? color50.red(e.outcome) : color50.yellow(e.outcome);
28023
- return `${color50.dim(fmtAge4(e.at))} ${e.kind}${who}${task} \u2192 ${e.proposedAction} [${outcome}] ${color50.dim(e.detail)}`;
28451
+ const outcome = e.outcome === "approved" ? color51.green(e.outcome) : e.outcome === "denied" || e.outcome === "error" ? color51.red(e.outcome) : color51.yellow(e.outcome);
28452
+ return `${color51.dim(fmtAge4(e.at))} ${e.kind}${who}${task} \u2192 ${e.proposedAction} [${outcome}] ${color51.dim(e.detail)}`;
28024
28453
  });
28025
28454
  const msg2 = lines2.join("\n");
28026
28455
  opts.renderer.write(msg2);
@@ -28030,12 +28459,12 @@ function buildSupervisorCommand(opts) {
28030
28459
  const history = supervisor.history();
28031
28460
  const last = history[history.length - 1];
28032
28461
  const lines = [
28033
- `Fleet supervisor: ${supervisor.isRunning() ? color50.green("armed") : color50.yellow("disarmed")}`,
28462
+ `Fleet supervisor: ${supervisor.isRunning() ? color51.green("armed") : color51.yellow("disarmed")}`,
28034
28463
  ` interval ${Math.round(cfg.intervalMs / 1e3)}s \xB7 cooldown ${Math.round(cfg.cooldownMs / 1e3)}s \xB7 max ${cfg.maxInterventionsPerSubagent} interventions/agent`,
28035
28464
  ` signals: starvation>${Math.round(cfg.pinnedWaitMs / 1e3)}s \xB7 overload\u2265${cfg.overloadPinnedThreshold} pinned \xB7 backlog>${cfg.backlogFactor}\xD7workers \xB7 stuck>${Math.round(cfg.stuckMs / 1e3)}s \xB7 failstreak\u2265${cfg.failureStreak}`,
28036
28465
  ` actions: retarget \u2713 \xB7 spawn ${cfg.allowSpawn ? "\u2713" : "\u2717"} \xB7 steer \u2713 \xB7 terminate ${cfg.allowTerminate ? "\u2713" : "\u2717 (config fleet.supervisor.allowTerminate)"}`,
28037
28466
  ` activity: ${history.length} engagement(s)${last ? ` \u2014 last: ${last.kind} \u2192 ${last.proposedAction} [${last.outcome}] ${fmtAge4(last.at)}` : ""}`,
28038
- color50.dim(" decisions are gated by the Brain \u2014 see /brain (risk ceiling applies)")
28467
+ color51.dim(" decisions are gated by the Brain \u2014 see /brain (risk ceiling applies)")
28039
28468
  ];
28040
28469
  const msg = lines.join("\n");
28041
28470
  opts.renderer.write(msg);
@@ -28061,6 +28490,7 @@ import {
28061
28490
  formatTaskProgress,
28062
28491
  recordCompletedWorkEvidence
28063
28492
  } from "@wrongstack/core/utils";
28493
+ import { todoTool as todoTool2 } from "@wrongstack/tools";
28064
28494
  function findTask(tasks, query) {
28065
28495
  const asIndex = Number.parseInt(query, 10);
28066
28496
  if (!Number.isNaN(asIndex)) {
@@ -28179,6 +28609,7 @@ ${formatPlan2(updated)}`;
28179
28609
  }
28180
28610
  let outputMessage = "";
28181
28611
  let completedTask = null;
28612
+ let todosToReplace = null;
28182
28613
  await mutateTasks(taskPath, sessionId, async (file) => {
28183
28614
  switch (cmd) {
28184
28615
  case "add": {
@@ -28241,7 +28672,17 @@ ${formatTaskProgress(file.tasks)}`;
28241
28672
  done: "Completed",
28242
28673
  fail: "Failed"
28243
28674
  };
28244
- found.item.status = statusMap[cmd] ?? "pending";
28675
+ const nextStatus = statusMap[cmd] ?? "pending";
28676
+ if (nextStatus === "in_progress" || nextStatus === "completed") {
28677
+ const unmet = (found.item.dependsOn ?? []).filter(
28678
+ (dependencyId) => file.tasks.find((task) => task.id === dependencyId)?.status !== "completed"
28679
+ );
28680
+ if (unmet.length > 0) {
28681
+ outputMessage = `Cannot mark "${found.item.title}" ${nextStatus}; dependencies are unfinished: ${unmet.join(", ")}.`;
28682
+ return file;
28683
+ }
28684
+ }
28685
+ found.item.status = nextStatus;
28245
28686
  found.item.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
28246
28687
  if (cmd === "done") {
28247
28688
  completedTask = { id: found.item.id, title: found.item.title };
@@ -28267,6 +28708,15 @@ ${formatTaskProgress(file.tasks)}`;
28267
28708
  outputMessage = `No task matched "${targetId}".`;
28268
28709
  return file;
28269
28710
  }
28711
+ if (newStatus === "in_progress" || newStatus === "review" || newStatus === "completed") {
28712
+ const unmet = (found.item.dependsOn ?? []).filter(
28713
+ (dependencyId) => file.tasks.find((task) => task.id === dependencyId)?.status !== "completed"
28714
+ );
28715
+ if (unmet.length > 0) {
28716
+ outputMessage = `Cannot mark "${found.item.title}" ${newStatus}; dependencies are unfinished: ${unmet.join(", ")}.`;
28717
+ return file;
28718
+ }
28719
+ }
28270
28720
  found.item.status = newStatus;
28271
28721
  found.item.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
28272
28722
  if (newStatus === "completed") {
@@ -28290,6 +28740,21 @@ ${formatTaskProgress(file.tasks)}`;
28290
28740
  outputMessage = `No task matched "${targetId}".`;
28291
28741
  return file;
28292
28742
  }
28743
+ const knownIds = new Set(file.tasks.map((task) => task.id));
28744
+ const missing = depIds.filter((dependencyId) => !knownIds.has(dependencyId));
28745
+ if (missing.length > 0) {
28746
+ outputMessage = `Unknown dependency task IDs: ${missing.join(", ")}.`;
28747
+ return file;
28748
+ }
28749
+ if (found.item.status === "in_progress" || found.item.status === "review" || found.item.status === "completed") {
28750
+ const unmet = depIds.filter(
28751
+ (dependencyId) => file.tasks.find((task) => task.id === dependencyId)?.status !== "completed"
28752
+ );
28753
+ if (unmet.length > 0) {
28754
+ outputMessage = `Cannot add unfinished dependencies to active task "${found.item.title}": ${unmet.join(", ")}.`;
28755
+ return file;
28756
+ }
28757
+ }
28293
28758
  found.item.dependsOn = depIds;
28294
28759
  found.item.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
28295
28760
  outputMessage = `Dependencies set for "${found.item.title}": ${depIds.join(", ")}`;
@@ -28322,6 +28787,13 @@ ${formatTaskProgress(file.tasks)}`;
28322
28787
  outputMessage = `No task matched "${restJoined}".`;
28323
28788
  return file;
28324
28789
  }
28790
+ const unmet = (found.item.dependsOn ?? []).filter(
28791
+ (dependencyId) => file.tasks.find((task) => task.id === dependencyId)?.status !== "completed"
28792
+ );
28793
+ if (unmet.length > 0) {
28794
+ outputMessage = `Cannot promote "${found.item.title}"; dependencies are unfinished: ${unmet.join(", ")}.`;
28795
+ return file;
28796
+ }
28325
28797
  found.item.status = "in_progress";
28326
28798
  found.item.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
28327
28799
  const todos = [
@@ -28344,7 +28816,7 @@ ${formatTaskProgress(file.tasks)}`;
28344
28816
  const existing = ctx.state.todos.filter(
28345
28817
  (t) => t.promotedFromTask !== found.item.id
28346
28818
  );
28347
- ctx.state.replaceTodos([...existing, ...todos]);
28819
+ todosToReplace = [...existing, ...todos];
28348
28820
  outputMessage = `Promoted to ${todos.length} todo(s): "${found.item.title}"
28349
28821
 
28350
28822
  ${formatTaskProgress(file.tasks)}`;
@@ -28356,6 +28828,11 @@ ${formatTaskProgress(file.tasks)}`;
28356
28828
  outputMessage = "Tasks were already empty.";
28357
28829
  return file;
28358
28830
  }
28831
+ const unfinished = file.tasks.filter((task) => task.status !== "completed");
28832
+ if (unfinished.length > 0) {
28833
+ outputMessage = `Cannot clear unfinished tasks: ${unfinished.map((task) => task.id).join(", ")}. Complete them first.`;
28834
+ return file;
28835
+ }
28359
28836
  file.tasks = [];
28360
28837
  outputMessage = `Cleared ${n} task${n === 1 ? "" : "s"}.`;
28361
28838
  break;
@@ -28382,6 +28859,11 @@ ${formatTaskProgress(file.tasks)}`;
28382
28859
  }
28383
28860
  return file;
28384
28861
  });
28862
+ if (todosToReplace) {
28863
+ await todoTool2.execute({ todos: todosToReplace }, ctx, {
28864
+ signal: AbortSignal.timeout(3e4)
28865
+ });
28866
+ }
28385
28867
  if (completedTask) {
28386
28868
  const done = completedTask;
28387
28869
  try {
@@ -28411,7 +28893,7 @@ ${formatTaskProgress(file.tasks)}`;
28411
28893
  // src/slash-commands/techstack.ts
28412
28894
  import * as fs18 from "node:fs/promises";
28413
28895
  import * as path28 from "node:path";
28414
- import { color as color51, toErrorMessage as toErrorMessage26 } from "@wrongstack/core/utils";
28896
+ import { color as color52, toErrorMessage as toErrorMessage26 } from "@wrongstack/core/utils";
28415
28897
  async function discoverPackageFiles(projectRoot) {
28416
28898
  const files = [];
28417
28899
  const rootPkg = path28.join(projectRoot, "package.json");
@@ -28561,10 +29043,10 @@ function buildTechStackCommand(opts) {
28561
29043
  " 1. Reads every package.json in the project",
28562
29044
  " 2. Looks up latest versions on the npm registry",
28563
29045
  " 3. Flags outdated, dead, or obsolete packages",
28564
- ` 4. Writes a ${color51.cyan("techstack.md")} (or .json) report to the project root`,
29046
+ ` 4. Writes a ${color52.cyan("techstack.md")} (or .json) report to the project root`,
28565
29047
  "",
28566
29048
  "Uses the `tech-stack` skill for version verification rules.",
28567
- `Hooked into ${color51.cyan("/init")} \u2014 runs automatically on first project setup.`
29049
+ `Hooked into ${color52.cyan("/init")} \u2014 runs automatically on first project setup.`
28568
29050
  ].join("\n"),
28569
29051
  async run(args, _ctx) {
28570
29052
  const trimmed = args.trim().toLowerCase();
@@ -28648,12 +29130,12 @@ function buildTechStackCommand(opts) {
28648
29130
  try {
28649
29131
  packageFiles = await discoverPackageFiles(opts.projectRoot);
28650
29132
  if (packageFiles.length === 0) {
28651
- discoveryNote = color51.amber(
29133
+ discoveryNote = color52.amber(
28652
29134
  "\u26A0 No package.json files found. This does not look like a Node.js project."
28653
29135
  );
28654
29136
  }
28655
29137
  } catch (err) {
28656
- discoveryNote = color51.red(`Could not scan for package files: ${toErrorMessage26(err)}`);
29138
+ discoveryNote = color52.red(`Could not scan for package files: ${toErrorMessage26(err)}`);
28657
29139
  }
28658
29140
  const task = buildTechStackTask({
28659
29141
  projectRoot: opts.projectRoot,
@@ -28676,11 +29158,11 @@ function buildTechStackCommand(opts) {
28676
29158
  };
28677
29159
  }
28678
29160
  const header = isInit ? "Tech Stack Init Audit" : "Tech Stack Audit";
28679
- const label = `${color51.cyan("\u{1F50D}")} ${color51.bold(header)} ${color51.dim(`(${packageFiles.length} package files)`)}`;
29161
+ const label = `${color52.cyan("\u{1F50D}")} ${color52.bold(header)} ${color52.dim(`(${packageFiles.length} package files)`)}`;
28680
29162
  opts.renderer.write(label);
28681
29163
  if (discoveryNote) opts.renderer.write(discoveryNote);
28682
29164
  opts.renderer.write(
28683
- color51.dim(
29165
+ color52.dim(
28684
29166
  `Spawning tech-stack subagent \u2192 writes ${outputFormat === "json" ? "techstack.json" : "techstack.md"} when done.`
28685
29167
  )
28686
29168
  );
@@ -28702,10 +29184,10 @@ function buildTechStackCommand(opts) {
28702
29184
  }
28703
29185
 
28704
29186
  // src/slash-commands/telegram-settings.ts
28705
- import { color as color53, toErrorMessage as toErrorMessage27 } from "@wrongstack/core/utils";
29187
+ import { color as color54, toErrorMessage as toErrorMessage27 } from "@wrongstack/core/utils";
28706
29188
 
28707
29189
  // src/slash-commands/telegram-setup.ts
28708
- import { color as color52 } from "@wrongstack/core/utils";
29190
+ import { color as color53 } from "@wrongstack/core/utils";
28709
29191
 
28710
29192
  // src/slash-commands/telegram-pairing.ts
28711
29193
  var DISCOVERY_LIMIT = 25;
@@ -28821,31 +29303,31 @@ function buildTelegramSetupCommand(opts) {
28821
29303
  if (BOT_TOKEN_RE.test(first)) {
28822
29304
  return {
28823
29305
  message: [
28824
- `${color52.red("\u2717")} Bot tokens are no longer accepted as slash-command arguments.`,
28825
- `Run ${color52.cyan("/telegram-setup [chatId]")} and enter it at the masked prompt.`
29306
+ `${color53.red("\u2717")} Bot tokens are no longer accepted as slash-command arguments.`,
29307
+ `Run ${color53.cyan("/telegram-setup [chatId]")} and enter it at the masked prompt.`
28826
29308
  ].join("\n")
28827
29309
  };
28828
29310
  }
28829
29311
  if (parts.length > 1) {
28830
- return { message: `${color52.amber("Usage:")} /telegram-setup [chatId]` };
29312
+ return { message: `${color53.amber("Usage:")} /telegram-setup [chatId]` };
28831
29313
  }
28832
29314
  if (!opts.readSecret || !opts.vault || !opts.paths?.globalConfig) {
28833
29315
  return {
28834
- message: `${color52.red("\u2717")} Secure Telegram setup is unavailable in this session.`
29316
+ message: `${color53.red("\u2717")} Secure Telegram setup is unavailable in this session.`
28835
29317
  };
28836
29318
  }
28837
29319
  let botToken;
28838
29320
  try {
28839
- botToken = (await opts.readSecret(`Telegram bot token ${color52.dim("(hidden, paste OK)")}: `)).trim();
29321
+ botToken = (await opts.readSecret(`Telegram bot token ${color53.dim("(hidden, paste OK)")}: `)).trim();
28840
29322
  } catch {
28841
- return { message: color52.dim("Telegram setup cancelled.") };
29323
+ return { message: color53.dim("Telegram setup cancelled.") };
28842
29324
  }
28843
- if (!botToken) return { message: color52.dim("Telegram setup cancelled.") };
29325
+ if (!botToken) return { message: color53.dim("Telegram setup cancelled.") };
28844
29326
  if (!BOT_TOKEN_RE.test(botToken)) {
28845
29327
  return {
28846
29328
  message: [
28847
- `${color52.red("\u2717")} Invalid token format.`,
28848
- `Expected: ${color52.dim("123456789:ABCdefGHIjkl...")}`,
29329
+ `${color53.red("\u2717")} Invalid token format.`,
29330
+ `Expected: ${color53.dim("123456789:ABCdefGHIjkl...")}`,
28849
29331
  "",
28850
29332
  "Get a valid token from @BotFather on Telegram."
28851
29333
  ].join("\n")
@@ -28860,7 +29342,7 @@ function buildTelegramSetupCommand(opts) {
28860
29342
  } catch {
28861
29343
  return {
28862
29344
  message: [
28863
- `${color52.red("\u2717")} Could not reach Telegram API.`,
29345
+ `${color53.red("\u2717")} Could not reach Telegram API.`,
28864
29346
  "",
28865
29347
  "Check your network connection and try again."
28866
29348
  ].join("\n")
@@ -28869,7 +29351,7 @@ function buildTelegramSetupCommand(opts) {
28869
29351
  if (!botInfo.ok || !botInfo.result) {
28870
29352
  return {
28871
29353
  message: [
28872
- `${color52.red("\u2717")} Invalid bot token.`,
29354
+ `${color53.red("\u2717")} Invalid bot token.`,
28873
29355
  "",
28874
29356
  "Get a valid token from @BotFather on Telegram."
28875
29357
  ].join("\n")
@@ -28879,13 +29361,13 @@ function buildTelegramSetupCommand(opts) {
28879
29361
  const classifiedChatId = chatId ? classifyTelegramChatId(chatId) : void 0;
28880
29362
  if (classifiedChatId?.kind === "invalid") {
28881
29363
  return {
28882
- message: `${color52.red("\u2717")} Invalid Telegram chat ID. Expected a positive private chat ID.`
29364
+ message: `${color53.red("\u2717")} Invalid Telegram chat ID. Expected a positive private chat ID.`
28883
29365
  };
28884
29366
  }
28885
29367
  if (classifiedChatId?.kind === "group") {
28886
29368
  return {
28887
29369
  message: [
28888
- `${color52.amber("\u26A0")} Shared group, supergroup, and channel IDs cannot be paired by manual ID.`,
29370
+ `${color53.amber("\u26A0")} Shared group, supergroup, and channel IDs cannot be paired by manual ID.`,
28889
29371
  "Run /telegram-setup without a chat ID and select a discovered private identity.",
28890
29372
  "No configuration was changed."
28891
29373
  ].join("\n")
@@ -28899,7 +29381,7 @@ function buildTelegramSetupCommand(opts) {
28899
29381
  } catch {
28900
29382
  return {
28901
29383
  message: [
28902
- `${color52.red("\u2717")} Could not discover recent Telegram chats.`,
29384
+ `${color53.red("\u2717")} Could not discover recent Telegram chats.`,
28903
29385
  "Message the bot once, then run /telegram-setup again.",
28904
29386
  "No configuration was changed."
28905
29387
  ].join("\n")
@@ -28908,7 +29390,7 @@ function buildTelegramSetupCommand(opts) {
28908
29390
  if (candidates.length === 0) {
28909
29391
  return {
28910
29392
  message: [
28911
- `${color52.amber("No recent chats found.")}`,
29393
+ `${color53.amber("No recent chats found.")}`,
28912
29394
  "Message the bot from the private account you want to pair, then run setup again.",
28913
29395
  "No configuration was changed."
28914
29396
  ].join("\n")
@@ -28916,31 +29398,31 @@ function buildTelegramSetupCommand(opts) {
28916
29398
  }
28917
29399
  opts.renderer.write(
28918
29400
  [
28919
- color52.bold("Recent Telegram identities"),
29401
+ color53.bold("Recent Telegram identities"),
28920
29402
  formatTelegramPairingCandidates(candidates),
28921
29403
  "",
28922
- color52.dim("Choose a private candidate number, or press Enter to cancel.")
29404
+ color53.dim("Choose a private candidate number, or press Enter to cancel.")
28923
29405
  ].join("\n")
28924
29406
  );
28925
29407
  let choiceInput;
28926
29408
  try {
28927
29409
  choiceInput = opts.readText ? await opts.readText("Pair candidate \u203A ") : await opts.reader.readLine("Pair candidate \u203A ");
28928
29410
  } catch {
28929
- return { message: color52.dim("Telegram setup cancelled. No configuration was changed.") };
29411
+ return { message: color53.dim("Telegram setup cancelled. No configuration was changed.") };
28930
29412
  }
28931
29413
  const choice = parseTelegramPairingChoice(choiceInput, candidates);
28932
29414
  if (choice.kind === "cancel") {
28933
- return { message: color52.dim("Telegram setup cancelled. No configuration was changed.") };
29415
+ return { message: color53.dim("Telegram setup cancelled. No configuration was changed.") };
28934
29416
  }
28935
29417
  if (choice.kind === "invalid") {
28936
29418
  return {
28937
- message: `${color52.red("\u2717")} Invalid pairing choice. No configuration was changed.`
29419
+ message: `${color53.red("\u2717")} Invalid pairing choice. No configuration was changed.`
28938
29420
  };
28939
29421
  }
28940
29422
  if (!choice.candidate.eligible) {
28941
29423
  return {
28942
29424
  message: [
28943
- `${color52.amber("\u26A0")} Shared, group, or ambiguous identities are not paired automatically.`,
29425
+ `${color53.amber("\u26A0")} Shared, group, or ambiguous identities are not paired automatically.`,
28944
29426
  "Use a private chat where chat_id and user_id identify the same account.",
28945
29427
  "No configuration was changed."
28946
29428
  ].join("\n")
@@ -28982,7 +29464,7 @@ function buildTelegramSetupCommand(opts) {
28982
29464
  } catch {
28983
29465
  return {
28984
29466
  message: [
28985
- `${color52.red("\u2717")} Failed to save Telegram configuration.`,
29467
+ `${color53.red("\u2717")} Failed to save Telegram configuration.`,
28986
29468
  "The token was not printed. Check the config path and vault, then try again."
28987
29469
  ].join("\n")
28988
29470
  };
@@ -28990,15 +29472,15 @@ function buildTelegramSetupCommand(opts) {
28990
29472
  const bot = botInfo.result;
28991
29473
  return {
28992
29474
  message: [
28993
- `${color52.green("\u2713")} Telegram configured successfully.`,
29475
+ `${color53.green("\u2713")} Telegram configured successfully.`,
28994
29476
  "",
28995
- `Bot: ${color52.bold(`@${bot.username ?? bot.first_name}`)}`,
29477
+ `Bot: ${color53.bold(`@${bot.username ?? bot.first_name}`)}`,
28996
29478
  ...pairedCandidate ? [
28997
- `Paired private chat: ${color52.green(String(pairedCandidate.chatId))}`,
28998
- `Paired user: ${color52.green(String(pairedCandidate.userId))}`
28999
- ] : chatId ? [`Default chat: ${color52.green(chatId)}`] : [],
29479
+ `Paired private chat: ${color53.green(String(pairedCandidate.chatId))}`,
29480
+ `Paired user: ${color53.green(String(pairedCandidate.userId))}`
29481
+ ] : chatId ? [`Default chat: ${color53.green(chatId)}`] : [],
29000
29482
  "",
29001
- `${color52.amber("\u26A0")} Restart WrongStack for the plugin to load the new token.`
29483
+ `${color53.amber("\u26A0")} Restart WrongStack for the plugin to load the new token.`
29002
29484
  ].join("\n")
29003
29485
  };
29004
29486
  }
@@ -29032,15 +29514,15 @@ function buildTelegramSettingsCommand(opts) {
29032
29514
  const chat = tg.notifyChatId !== void 0 && tg.notifyChatId !== null ? String(tg.notifyChatId) : "not set";
29033
29515
  const hasToken = typeof tg.botToken === "string" && tg.botToken.length > 0;
29034
29516
  return [
29035
- `${color53.bold("Telegram")} ${color53.dim("\u2014 Notification Settings")}`,
29517
+ `${color54.bold("Telegram")} ${color54.dim("\u2014 Notification Settings")}`,
29036
29518
  "",
29037
- ` session end: ${sessionEnd ? color53.cyan("on") : color53.dim("off")} ${color53.dim("change: /telegram-settings session-end on|off")}`,
29038
- ` delegate done: ${delegate ? color53.cyan("on") : color53.dim("off")} ${color53.dim("change: /telegram-settings delegate on|off")}`,
29039
- ` long tool: ${color53.cyan(longTool)} ${color53.dim("change: /telegram-settings long-tool <ms|off>")}`,
29040
- ` poll interval: ${color53.cyan(poll)} ${color53.dim("change: /telegram-settings poll <seconds>")}`,
29041
- ` notify chat: ${color53.cyan(chat)} ${color53.dim("change: /telegram-settings chat <chatId>")}`,
29519
+ ` session end: ${sessionEnd ? color54.cyan("on") : color54.dim("off")} ${color54.dim("change: /telegram-settings session-end on|off")}`,
29520
+ ` delegate done: ${delegate ? color54.cyan("on") : color54.dim("off")} ${color54.dim("change: /telegram-settings delegate on|off")}`,
29521
+ ` long tool: ${color54.cyan(longTool)} ${color54.dim("change: /telegram-settings long-tool <ms|off>")}`,
29522
+ ` poll interval: ${color54.cyan(poll)} ${color54.dim("change: /telegram-settings poll <seconds>")}`,
29523
+ ` notify chat: ${color54.cyan(chat)} ${color54.dim("change: /telegram-settings chat <chatId>")}`,
29042
29524
  "",
29043
- hasToken ? color53.dim(" Bot token configured. Changes apply immediately.") : `${color53.amber("\u26A0")} No bot token configured. Run: /telegram-setup <botToken> [chatId]`
29525
+ hasToken ? color54.dim(" Bot token configured. Changes apply immediately.") : `${color54.amber("\u26A0")} No bot token configured. Run: /telegram-setup <botToken> [chatId]`
29044
29526
  ].join("\n");
29045
29527
  }
29046
29528
  return {
@@ -29056,7 +29538,7 @@ function buildTelegramSettingsCommand(opts) {
29056
29538
  return { message: HELP2 };
29057
29539
  }
29058
29540
  if (!opts.configStore || !opts.paths?.globalConfig || !opts.vault) {
29059
- return { message: `${color53.red("Error")} secure config persistence not available.` };
29541
+ return { message: `${color54.red("Error")} secure config persistence not available.` };
29060
29542
  }
29061
29543
  if (!sub) {
29062
29544
  return { message: currentView() };
@@ -29070,7 +29552,7 @@ function buildTelegramSettingsCommand(opts) {
29070
29552
  if (sub === "all") {
29071
29553
  const raw = (rest[0] ?? "").toLowerCase();
29072
29554
  if (!["on", "off"].includes(raw)) {
29073
- return { message: `${color53.amber("Usage:")} /telegram-settings all on|off` };
29555
+ return { message: `${color54.amber("Usage:")} /telegram-settings all on|off` };
29074
29556
  }
29075
29557
  const on = raw === "on";
29076
29558
  await persistTelegramConfig(persistDeps, (tg) => {
@@ -29078,40 +29560,40 @@ function buildTelegramSettingsCommand(opts) {
29078
29560
  tg.notifyOnDelegate = on;
29079
29561
  });
29080
29562
  return {
29081
- message: `${color53.green("\u2713")} all event notifications \u2192 ${on ? color53.cyan("on") : color53.dim("off")} ${color53.dim("(session-end, delegate)")}`
29563
+ message: `${color54.green("\u2713")} all event notifications \u2192 ${on ? color54.cyan("on") : color54.dim("off")} ${color54.dim("(session-end, delegate)")}`
29082
29564
  };
29083
29565
  }
29084
29566
  if (sub === "session-end") {
29085
29567
  const raw = (rest[0] ?? "").toLowerCase();
29086
29568
  if (!["on", "off"].includes(raw)) {
29087
- return { message: `${color53.amber("Usage:")} /telegram-settings session-end on|off` };
29569
+ return { message: `${color54.amber("Usage:")} /telegram-settings session-end on|off` };
29088
29570
  }
29089
29571
  const on = raw === "on";
29090
29572
  await persistTelegramConfig(persistDeps, (tg) => {
29091
29573
  tg.notifyOnSessionEnd = on;
29092
29574
  });
29093
29575
  return {
29094
- message: `${color53.green("\u2713")} session-end \u2192 ${on ? color53.cyan("on") : color53.dim("off")}`
29576
+ message: `${color54.green("\u2713")} session-end \u2192 ${on ? color54.cyan("on") : color54.dim("off")}`
29095
29577
  };
29096
29578
  }
29097
29579
  if (sub === "delegate") {
29098
29580
  const raw = (rest[0] ?? "").toLowerCase();
29099
29581
  if (!["on", "off"].includes(raw)) {
29100
- return { message: `${color53.amber("Usage:")} /telegram-settings delegate on|off` };
29582
+ return { message: `${color54.amber("Usage:")} /telegram-settings delegate on|off` };
29101
29583
  }
29102
29584
  const on = raw === "on";
29103
29585
  await persistTelegramConfig(persistDeps, (tg) => {
29104
29586
  tg.notifyOnDelegate = on;
29105
29587
  });
29106
29588
  return {
29107
- message: `${color53.green("\u2713")} delegate \u2192 ${on ? color53.cyan("on") : color53.dim("off")}`
29589
+ message: `${color54.green("\u2713")} delegate \u2192 ${on ? color54.cyan("on") : color54.dim("off")}`
29108
29590
  };
29109
29591
  }
29110
29592
  if (sub === "long-tool") {
29111
29593
  const raw = rest[0];
29112
29594
  if (raw === void 0) {
29113
29595
  return {
29114
- message: `${color53.amber("Usage:")} /telegram-settings long-tool <ms|off> ${color53.dim("(0 or off disables)")}`
29596
+ message: `${color54.amber("Usage:")} /telegram-settings long-tool <ms|off> ${color54.dim("(0 or off disables)")}`
29115
29597
  };
29116
29598
  }
29117
29599
  if (raw === "off") {
@@ -29119,57 +29601,57 @@ function buildTelegramSettingsCommand(opts) {
29119
29601
  tg.longToolThresholdMs = 0;
29120
29602
  });
29121
29603
  return {
29122
- message: `${color53.green("\u2713")} long-tool \u2192 ${color53.dim("off")}`
29604
+ message: `${color54.green("\u2713")} long-tool \u2192 ${color54.dim("off")}`
29123
29605
  };
29124
29606
  }
29125
29607
  const ms = Number.parseInt(raw, 10);
29126
29608
  if (Number.isNaN(ms) || ms < 0) {
29127
29609
  return {
29128
- message: `${color53.red("Invalid number")}: "${raw}". Enter milliseconds, e.g. /telegram-settings long-tool 15000`
29610
+ message: `${color54.red("Invalid number")}: "${raw}". Enter milliseconds, e.g. /telegram-settings long-tool 15000`
29129
29611
  };
29130
29612
  }
29131
29613
  await persistTelegramConfig(persistDeps, (tg) => {
29132
29614
  tg.longToolThresholdMs = ms;
29133
29615
  });
29134
29616
  return {
29135
- message: `${color53.green("\u2713")} long-tool \u2192 ${color53.cyan(`${ms}ms`)}`
29617
+ message: `${color54.green("\u2713")} long-tool \u2192 ${color54.cyan(`${ms}ms`)}`
29136
29618
  };
29137
29619
  }
29138
29620
  if (sub === "poll") {
29139
29621
  const raw = rest[0];
29140
29622
  if (raw === void 0) {
29141
29623
  return {
29142
- message: `${color53.amber("Usage:")} /telegram-settings poll <seconds> ${color53.dim("(1\u201360)")}`
29624
+ message: `${color54.amber("Usage:")} /telegram-settings poll <seconds> ${color54.dim("(1\u201360)")}`
29143
29625
  };
29144
29626
  }
29145
29627
  const sec = Number.parseInt(raw, 10);
29146
29628
  if (Number.isNaN(sec) || sec < 1 || sec > 60) {
29147
29629
  return {
29148
- message: `${color53.red("Invalid value")}: "${raw}". Enter seconds between 1 and 60.`
29630
+ message: `${color54.red("Invalid value")}: "${raw}". Enter seconds between 1 and 60.`
29149
29631
  };
29150
29632
  }
29151
29633
  await persistTelegramConfig(persistDeps, (tg) => {
29152
29634
  tg.pollIntervalSec = sec;
29153
29635
  });
29154
29636
  return {
29155
- message: `${color53.green("\u2713")} poll \u2192 ${color53.cyan(`${sec}s`)}`
29637
+ message: `${color54.green("\u2713")} poll \u2192 ${color54.cyan(`${sec}s`)}`
29156
29638
  };
29157
29639
  }
29158
29640
  if (sub === "chat") {
29159
29641
  const raw = rest[0];
29160
29642
  if (!raw) {
29161
- return { message: `${color53.amber("Usage:")} /telegram-settings chat <chatId>` };
29643
+ return { message: `${color54.amber("Usage:")} /telegram-settings chat <chatId>` };
29162
29644
  }
29163
29645
  const classification = classifyTelegramChatId(raw);
29164
29646
  if (classification.kind === "invalid") {
29165
- return { message: `${color53.red("Invalid chat ID")}: expected a non-zero integer.` };
29647
+ return { message: `${color54.red("Invalid chat ID")}: expected a non-zero integer.` };
29166
29648
  }
29167
29649
  const current = opts.configStore.get();
29168
29650
  const allowGroupChats = current.extensions?.telegram?.allowGroupChats === true;
29169
29651
  if (classification.kind === "group" && !allowGroupChats) {
29170
29652
  return {
29171
29653
  message: [
29172
- `${color53.amber("\u26A0")} Group, supergroup, and channel targets require explicit allowGroupChats=true.`,
29654
+ `${color54.amber("\u26A0")} Group, supergroup, and channel targets require explicit allowGroupChats=true.`,
29173
29655
  "No configuration was changed."
29174
29656
  ].join("\n")
29175
29657
  };
@@ -29192,15 +29674,15 @@ function buildTelegramSettingsCommand(opts) {
29192
29674
  }
29193
29675
  });
29194
29676
  return {
29195
- message: `${color53.green("\u2713")} notify chat \u2192 ${color53.cyan(raw)}`
29677
+ message: `${color54.green("\u2713")} notify chat \u2192 ${color54.cyan(raw)}`
29196
29678
  };
29197
29679
  }
29198
29680
  return {
29199
- message: `${color53.red("Unknown setting")} "${sub}". ${unknownSubcommand(sub, ["session-end", "delegate", "long-tool", "poll", "chat", "all"], "telegram-settings")}`
29681
+ message: `${color54.red("Unknown setting")} "${sub}". ${unknownSubcommand(sub, ["session-end", "delegate", "long-tool", "poll", "chat", "all"], "telegram-settings")}`
29200
29682
  };
29201
29683
  } catch (err) {
29202
29684
  return {
29203
- message: `${color53.red("Settings error")}: ${toErrorMessage27(err)}`
29685
+ message: `${color54.red("Settings error")}: ${toErrorMessage27(err)}`
29204
29686
  };
29205
29687
  }
29206
29688
  }
@@ -29210,6 +29692,7 @@ function buildTelegramSettingsCommand(opts) {
29210
29692
  // src/slash-commands/todos.ts
29211
29693
  import { randomUUID as randomUUID7 } from "node:crypto";
29212
29694
  import { formatTodosList as formatTodosList2 } from "@wrongstack/core/utils";
29695
+ import { todoTool as todoTool3 } from "@wrongstack/tools";
29213
29696
  function findTodo(todos, query) {
29214
29697
  const asIndex = Number.parseInt(query, 10);
29215
29698
  if (!Number.isNaN(asIndex)) {
@@ -29240,73 +29723,105 @@ function buildTodosCommand(opts) {
29240
29723
  if (!ctx) return { message: "No active context." };
29241
29724
  const { cmd, rest } = parseSubcommand(args);
29242
29725
  const restJoined = rest.join(" ").trim();
29243
- switch (cmd) {
29244
- case "":
29245
- case "show":
29246
- case "list": {
29247
- return { message: formatTodosList2(ctx.todos) };
29248
- }
29249
- case "clear": {
29250
- const n = ctx.todos.length;
29251
- if (n === 0) return { message: "Todos were already empty." };
29252
- ctx.state.replaceTodos([]);
29253
- return { message: `Cleared ${n} todo${n === 1 ? "" : "s"}.` };
29254
- }
29255
- case "add": {
29256
- if (!restJoined) return { message: "Usage: /todos add <text>" };
29257
- const item = {
29258
- id: `todo_${Date.now()}_${randomUUID7().slice(0, 7)}`,
29259
- content: restJoined,
29260
- status: "pending"
29261
- };
29262
- ctx.state.replaceTodos([...ctx.todos, item]);
29263
- return { message: `Added: ${restJoined}` };
29264
- }
29265
- case "done-all":
29266
- case "complete-all": {
29267
- const pending = ctx.todos.filter((t) => t.status !== "completed");
29268
- if (pending.length === 0) return { message: "No pending todos to complete." };
29269
- ctx.state.replaceTodos(
29270
- ctx.todos.map(
29271
- (t) => t.status === "completed" ? t : { ...t, status: "completed" }
29272
- )
29273
- );
29274
- return {
29275
- message: `Marked ${pending.length} todo${pending.length === 1 ? "" : "s"} done.`
29276
- };
29277
- }
29278
- case "done":
29279
- case "complete": {
29280
- if (!restJoined) return { message: "Usage: /todos done <id|index>" };
29281
- const found = findTodo(ctx.todos, restJoined);
29282
- if (!found) return { message: `No todo matched "${restJoined}".` };
29283
- const doneItem = { ...found.item, status: "completed" };
29284
- const nextTodos = [
29285
- ...ctx.todos.slice(0, found.idx),
29286
- doneItem,
29287
- ...ctx.todos.slice(found.idx + 1)
29288
- ];
29289
- ctx.state.replaceTodos(nextTodos);
29290
- return { message: `Marked done: ${doneItem.content}` };
29291
- }
29292
- case "remove":
29293
- case "rm":
29294
- case "delete": {
29295
- if (!restJoined) return { message: "Usage: /todos remove <id|index>" };
29296
- const found = findTodo(ctx.todos, restJoined);
29297
- if (!found) return { message: `No todo matched "${restJoined}".` };
29298
- const nextTodos = [...ctx.todos.slice(0, found.idx), ...ctx.todos.slice(found.idx + 1)];
29299
- ctx.state.replaceTodos(nextTodos);
29300
- return { message: `Removed: ${found.item.content}` };
29726
+ const updateTodos = (todos) => todoTool3.execute({ todos }, ctx, { signal: AbortSignal.timeout(3e4) });
29727
+ const isManagedProjection = (todo) => Boolean(todo.kanbanBoardId && todo.kanbanTaskId);
29728
+ try {
29729
+ switch (cmd) {
29730
+ case "":
29731
+ case "show":
29732
+ case "list": {
29733
+ return { message: formatTodosList2(ctx.todos) };
29734
+ }
29735
+ case "clear": {
29736
+ const n = ctx.todos.length;
29737
+ if (n === 0) return { message: "Todos were already empty." };
29738
+ if (ctx.todos.some(isManagedProjection)) {
29739
+ return {
29740
+ message: "Kanban-bound todos are task projections. Change or remove the tasks from Kanban."
29741
+ };
29742
+ }
29743
+ ctx.state.replaceTodos([]);
29744
+ return { message: `Cleared ${n} todo${n === 1 ? "" : "s"}.` };
29745
+ }
29746
+ case "add": {
29747
+ if (!restJoined) return { message: "Usage: /todos add <text>" };
29748
+ if (ctx.todos.some(isManagedProjection)) {
29749
+ return { message: "This Todo list is a Kanban projection. Add the task in Kanban." };
29750
+ }
29751
+ const item = {
29752
+ id: `todo_${Date.now()}_${randomUUID7().slice(0, 7)}`,
29753
+ content: restJoined,
29754
+ status: "pending"
29755
+ };
29756
+ await updateTodos([...ctx.todos, item]);
29757
+ return { message: `Added: ${restJoined}` };
29758
+ }
29759
+ case "done-all":
29760
+ case "complete-all": {
29761
+ const pending = ctx.todos.filter((t) => t.status !== "completed");
29762
+ if (pending.length === 0) return { message: "No pending todos to complete." };
29763
+ if (ctx.todos.some(isManagedProjection)) {
29764
+ return {
29765
+ message: "Kanban-bound todos must complete through their real task lifecycle; complete the active task individually."
29766
+ };
29767
+ }
29768
+ await updateTodos(
29769
+ ctx.todos.map(
29770
+ (t) => t.status === "completed" ? t : { ...t, status: "completed" }
29771
+ )
29772
+ );
29773
+ return {
29774
+ message: `Marked ${pending.length} todo${pending.length === 1 ? "" : "s"} done.`
29775
+ };
29776
+ }
29777
+ case "done":
29778
+ case "complete": {
29779
+ if (!restJoined) return { message: "Usage: /todos done <id|index>" };
29780
+ const found = findTodo(ctx.todos, restJoined);
29781
+ if (!found) return { message: `No todo matched "${restJoined}".` };
29782
+ const doneItem = { ...found.item, status: "completed" };
29783
+ const nextTodos = [
29784
+ ...ctx.todos.slice(0, found.idx),
29785
+ doneItem,
29786
+ ...ctx.todos.slice(found.idx + 1)
29787
+ ];
29788
+ const result = await updateTodos(nextTodos);
29789
+ const projected = ctx.todos.find((todo) => todo.id === doneItem.id);
29790
+ if (isManagedProjection(doneItem) && projected?.status !== "completed") {
29791
+ return {
29792
+ message: result.kanban_warnings?.[0] ?? `Kanban kept ${doneItem.content} at ${projected?.status ?? "its current state"}.`
29793
+ };
29794
+ }
29795
+ return { message: `Marked done: ${doneItem.content}` };
29796
+ }
29797
+ case "remove":
29798
+ case "rm":
29799
+ case "delete": {
29800
+ if (!restJoined) return { message: "Usage: /todos remove <id|index>" };
29801
+ const found = findTodo(ctx.todos, restJoined);
29802
+ if (!found) return { message: `No todo matched "${restJoined}".` };
29803
+ if (isManagedProjection(found.item)) {
29804
+ return {
29805
+ message: "Kanban-bound todos are task projections. Remove the task from Kanban instead."
29806
+ };
29807
+ }
29808
+ const nextTodos = [...ctx.todos.slice(0, found.idx), ...ctx.todos.slice(found.idx + 1)];
29809
+ ctx.state.replaceTodos(nextTodos);
29810
+ return { message: `Removed: ${found.item.content}` };
29811
+ }
29812
+ default:
29813
+ return {
29814
+ message: unknownSubcommand(
29815
+ cmd,
29816
+ ["show", "clear", "add", "done", "done-all", "remove"],
29817
+ "todos"
29818
+ ) + "\n\nRelated: /plan (session-persistent roadmap) | /tasks (structured tasks with priorities)"
29819
+ };
29301
29820
  }
29302
- default:
29303
- return {
29304
- message: unknownSubcommand(
29305
- cmd,
29306
- ["show", "clear", "add", "done", "done-all", "remove"],
29307
- "todos"
29308
- ) + "\n\nRelated: /plan (session-persistent roadmap) | /tasks (structured tasks with priorities)"
29309
- };
29821
+ } catch (error) {
29822
+ return {
29823
+ message: `Todo update failed: ${error instanceof Error ? error.message : String(error)}`
29824
+ };
29310
29825
  }
29311
29826
  }
29312
29827
  };
@@ -29315,7 +29830,7 @@ function buildTodosCommand(opts) {
29315
29830
  // src/slash-commands/tool.ts
29316
29831
  import { noOpVault as noOpVault10 } from "@wrongstack/core/security";
29317
29832
  import {
29318
- color as color54,
29833
+ color as color55,
29319
29834
  getToolDescriptionMode as getToolDescriptionMode2,
29320
29835
  getToolResultRenderMode,
29321
29836
  normalizeToolDescriptionMode,
@@ -29329,11 +29844,11 @@ function fit(text, width) {
29329
29844
  }
29330
29845
  function formatDescriptionMode(mode) {
29331
29846
  const raw = `desc:${mode}`;
29332
- return mode === "simple" ? color54.amber(raw) : color54.cyan(raw);
29847
+ return mode === "simple" ? color55.amber(raw) : color55.cyan(raw);
29333
29848
  }
29334
29849
  function formatResultRenderMode(mode) {
29335
29850
  const raw = `result:${mode}`;
29336
- return mode === "simple" ? color54.amber(raw) : color54.cyan(raw);
29851
+ return mode === "simple" ? color55.amber(raw) : color55.cyan(raw);
29337
29852
  }
29338
29853
  function buildToolCommand(opts) {
29339
29854
  const help = [
@@ -29439,38 +29954,38 @@ function buildToolCommand(opts) {
29439
29954
  const resultSimple = Object.entries(configured.resultRenderMode ?? {}).filter(([, mode]) => normalizeToolResultRenderMode(mode) === "simple").map(([name]) => name).sort();
29440
29955
  const disabled = opts.toolRegistry.listDisabled();
29441
29956
  const lines = [
29442
- `${color54.bold("Tool modes")} ${color54.dim("(default: extend on both axes)")}`,
29957
+ `${color55.bold("Tool modes")} ${color55.dim("(default: extend on both axes)")}`,
29443
29958
  "",
29444
- `${formatDescriptionMode("simple")}: ${descSimple.length > 0 ? descSimple.map((n) => color54.cyan(n)).join(", ") : color54.dim("none")}`,
29445
- `${formatResultRenderMode("simple")}: ${resultSimple.length > 0 ? resultSimple.map((n) => color54.cyan(n)).join(", ") : color54.dim("none")}`,
29959
+ `${formatDescriptionMode("simple")}: ${descSimple.length > 0 ? descSimple.map((n) => color55.cyan(n)).join(", ") : color55.dim("none")}`,
29960
+ `${formatResultRenderMode("simple")}: ${resultSimple.length > 0 ? resultSimple.map((n) => color55.cyan(n)).join(", ") : color55.dim("none")}`,
29446
29961
  ""
29447
29962
  ];
29448
29963
  if (disabled.length > 0) {
29449
29964
  lines.push(
29450
- `${color54.bold("Disabled tools")}`,
29965
+ `${color55.bold("Disabled tools")}`,
29451
29966
  "",
29452
- ` ${color54.red("disabled")}: ${disabled.map(({ tool }) => color54.dim(tool.name)).join(", ")}`,
29967
+ ` ${color55.red("disabled")}: ${disabled.map(({ tool }) => color55.dim(tool.name)).join(", ")}`,
29453
29968
  ""
29454
29969
  );
29455
29970
  }
29456
29971
  lines.push(
29457
- color54.dim(
29972
+ color55.dim(
29458
29973
  " /tool <name> desc simple \xB7 /tool <name> result simple \xB7 /tool list \xB7 /tool disable|enable <name>"
29459
29974
  )
29460
29975
  );
29461
29976
  return lines.join("\n");
29462
29977
  }
29463
29978
  function formatList() {
29464
- const header = ` ${color54.dim(fit("tool", 28))} ${color54.dim(fit("owner", 28))} ${color54.dim(fit("status", 10))} ${color54.dim(fit("desc", 14))} ` + color54.dim("result");
29979
+ const header = ` ${color55.dim(fit("tool", 28))} ${color55.dim(fit("owner", 28))} ${color55.dim(fit("status", 10))} ${color55.dim(fit("desc", 14))} ` + color55.dim("result");
29465
29980
  const rows = opts.toolRegistry.listWithOwner().map(({ tool }) => {
29466
29981
  const descMode = getToolDescriptionMode2(opts.toolRegistry, tool.name);
29467
29982
  const resultMode = getToolResultRenderMode(opts.toolRegistry, tool.name);
29468
29983
  const owner = opts.toolRegistry.ownerOf(tool.name) ?? "core";
29469
- const status = opts.toolRegistry.isDisabled(tool.name) ? color54.red("disabled") : color54.green("active");
29470
- return ` ${fit(tool.name, 28)} ${color54.dim(fit(`[${owner}]`, 28))} ${fit(status, 10)} ${fit(formatDescriptionMode(descMode), 14)} ` + formatResultRenderMode(resultMode);
29984
+ const status = opts.toolRegistry.isDisabled(tool.name) ? color55.red("disabled") : color55.green("active");
29985
+ return ` ${fit(tool.name, 28)} ${color55.dim(fit(`[${owner}]`, 28))} ${fit(status, 10)} ${fit(formatDescriptionMode(descMode), 14)} ` + formatResultRenderMode(resultMode);
29471
29986
  });
29472
29987
  return [
29473
- `${color54.bold("Tool modes")} ${color54.dim("(default: extend on both axes)")}`,
29988
+ `${color55.bold("Tool modes")} ${color55.dim("(default: extend on both axes)")}`,
29474
29989
  "",
29475
29990
  header,
29476
29991
  ...rows
@@ -29481,55 +29996,55 @@ function buildToolCommand(opts) {
29481
29996
  const tool = reg.get(name);
29482
29997
  if (!tool) {
29483
29998
  if (reg.isDisabled(name)) {
29484
- return `${color54.amber(name)} is disabled. Use ${color54.dim(`/tool enable ${name}`)} to restore.`;
29999
+ return `${color55.amber(name)} is disabled. Use ${color55.dim(`/tool enable ${name}`)} to restore.`;
29485
30000
  }
29486
- return `${color54.red("Unknown tool")}: ${name}. Use ${color54.dim("/tools")} to list registered tools.`;
30001
+ return `${color55.red("Unknown tool")}: ${name}. Use ${color55.dim("/tools")} to list registered tools.`;
29487
30002
  }
29488
30003
  const descMode = getToolDescriptionMode2(reg, name);
29489
30004
  const resultMode = getToolResultRenderMode(reg, name);
29490
- const status = reg.isDisabled(name) ? color54.red("disabled") : color54.green("active");
30005
+ const status = reg.isDisabled(name) ? color55.red("disabled") : color55.green("active");
29491
30006
  return [
29492
- `${color54.bold(name)} ${status}`,
30007
+ `${color55.bold(name)} ${status}`,
29493
30008
  `description mode: ${formatDescriptionMode(descMode)}`,
29494
30009
  `result mode: ${formatResultRenderMode(resultMode)}`,
29495
30010
  "",
29496
- color54.dim(tool.description)
30011
+ color55.dim(tool.description)
29497
30012
  ].join("\n");
29498
30013
  }
29499
30014
  async function cmdEnable(name) {
29500
30015
  const reg = opts.toolRegistry;
29501
30016
  if (!reg.isDisabled(name)) {
29502
- return `${color54.amber(name)} is not disabled.`;
30017
+ return `${color55.amber(name)} is not disabled.`;
29503
30018
  }
29504
30019
  const ok = reg.enable(name);
29505
- if (!ok) return `${color54.red("Could not enable")}: ${name}.`;
30020
+ if (!ok) return `${color55.red("Could not enable")}: ${name}.`;
29506
30021
  const disabled = currentDisabledSet();
29507
30022
  disabled.delete(name);
29508
30023
  await persistDisabled(Array.from(disabled));
29509
- return `${color54.green("\u2713")} ${color54.cyan(name)} re-enabled \u2014 will appear in next provider request.`;
30024
+ return `${color55.green("\u2713")} ${color55.cyan(name)} re-enabled \u2014 will appear in next provider request.`;
29510
30025
  }
29511
30026
  async function cmdEnableAll() {
29512
30027
  const reg = opts.toolRegistry;
29513
30028
  const count = reg.enableAll();
29514
- if (count === 0) return `${color54.amber("No disabled tools to re-enable.")}`;
30029
+ if (count === 0) return `${color55.amber("No disabled tools to re-enable.")}`;
29515
30030
  await persistDisabled([]);
29516
- return `${color54.green("\u2713")} All ${count} disabled tool(s) re-enabled.`;
30031
+ return `${color55.green("\u2713")} All ${count} disabled tool(s) re-enabled.`;
29517
30032
  }
29518
30033
  async function cmdDisable(name) {
29519
30034
  const reg = opts.toolRegistry;
29520
30035
  const tool = reg.get(name);
29521
30036
  if (!tool) {
29522
30037
  if (reg.isDisabled(name)) {
29523
- return `${color54.amber(name)} is already disabled.`;
30038
+ return `${color55.amber(name)} is already disabled.`;
29524
30039
  }
29525
- return `${color54.red("Unknown tool")}: ${name}. Use ${color54.dim("/tools")} to list registered tools.`;
30040
+ return `${color55.red("Unknown tool")}: ${name}. Use ${color55.dim("/tools")} to list registered tools.`;
29526
30041
  }
29527
30042
  const ok = reg.disable(name);
29528
- if (!ok) return `${color54.red("Could not disable")}: ${name}.`;
30043
+ if (!ok) return `${color55.red("Could not disable")}: ${name}.`;
29529
30044
  const disabled = currentDisabledSet();
29530
30045
  disabled.add(name);
29531
30046
  await persistDisabled(Array.from(disabled));
29532
- return `${color54.green("\u2713")} ${color54.cyan(name)} disabled \u2014 removed from system prompt and tool registry.`;
30047
+ return `${color55.green("\u2713")} ${color55.cyan(name)} disabled \u2014 removed from system prompt and tool registry.`;
29533
30048
  }
29534
30049
  function applyDescMode(name, mode) {
29535
30050
  opts.toolRegistry.setDescriptionMode?.(name, mode);
@@ -29545,7 +30060,7 @@ function buildToolCommand(opts) {
29545
30060
  help,
29546
30061
  async run(args) {
29547
30062
  if (!opts.configStore) {
29548
- return { message: `${color54.red("Error")} config store not available.` };
30063
+ return { message: `${color55.red("Error")} config store not available.` };
29549
30064
  }
29550
30065
  const parts = args.trim().split(/\s+/).filter(Boolean);
29551
30066
  const sub = (parts[0] ?? "").toLowerCase();
@@ -29556,7 +30071,7 @@ function buildToolCommand(opts) {
29556
30071
  try {
29557
30072
  return { message: await cmdEnableAll() };
29558
30073
  } catch (err) {
29559
- return { message: `${color54.red("Error")}: ${toErrorMessage28(err)}` };
30074
+ return { message: `${color55.red("Error")}: ${toErrorMessage28(err)}` };
29560
30075
  }
29561
30076
  }
29562
30077
  const name = parts[0] ?? "";
@@ -29564,43 +30079,43 @@ function buildToolCommand(opts) {
29564
30079
  if (sub === "disable") {
29565
30080
  const targets = parts.slice(1);
29566
30081
  if (targets.length === 0)
29567
- return { message: `${color54.amber("Usage:")} /tool disable <name> [name...]` };
30082
+ return { message: `${color55.amber("Usage:")} /tool disable <name> [name...]` };
29568
30083
  try {
29569
30084
  const results = [];
29570
30085
  for (const t of targets) results.push(await cmdDisable(t));
29571
30086
  return { message: results.join("\n") };
29572
30087
  } catch (err) {
29573
- return { message: `${color54.red("Error")}: ${toErrorMessage28(err)}` };
30088
+ return { message: `${color55.red("Error")}: ${toErrorMessage28(err)}` };
29574
30089
  }
29575
30090
  }
29576
30091
  if (sub === "enable") {
29577
30092
  const targets = parts.slice(1);
29578
30093
  if (targets.length === 0)
29579
- return { message: `${color54.amber("Usage:")} /tool enable <name> [name...]` };
30094
+ return { message: `${color55.amber("Usage:")} /tool enable <name> [name...]` };
29580
30095
  try {
29581
30096
  const results = [];
29582
30097
  for (const t of targets) results.push(await cmdEnable(t));
29583
30098
  return { message: results.join("\n") };
29584
30099
  } catch (err) {
29585
- return { message: `${color54.red("Error")}: ${toErrorMessage28(err)}` };
30100
+ return { message: `${color55.red("Error")}: ${toErrorMessage28(err)}` };
29586
30101
  }
29587
30102
  }
29588
30103
  const action = parts[1]?.toLowerCase();
29589
30104
  if (action === "disable" || action === "enable") {
29590
30105
  if (parts.length > 2) {
29591
30106
  return {
29592
- message: `${color54.amber("Usage:")} /tool ${name} ${action}`
30107
+ message: `${color55.amber("Usage:")} /tool ${name} ${action}`
29593
30108
  };
29594
30109
  }
29595
30110
  try {
29596
30111
  return { message: action === "disable" ? await cmdDisable(name) : await cmdEnable(name) };
29597
30112
  } catch (err) {
29598
- return { message: `${color54.red("Error")}: ${toErrorMessage28(err)}` };
30113
+ return { message: `${color55.red("Error")}: ${toErrorMessage28(err)}` };
29599
30114
  }
29600
30115
  }
29601
30116
  if (!opts.toolRegistry.get(name) && !opts.toolRegistry.isDisabled(name)) {
29602
30117
  return {
29603
- message: `${color54.red("Unknown tool")}: ${name}. Use ${color54.dim("/tools")} to list registered tools.`
30118
+ message: `${color55.red("Unknown tool")}: ${name}. Use ${color55.dim("/tools")} to list registered tools.`
29604
30119
  };
29605
30120
  }
29606
30121
  if (parts.length === 1) return { message: formatOne(name) };
@@ -29609,53 +30124,53 @@ function buildToolCommand(opts) {
29609
30124
  const rawMode = parts[2];
29610
30125
  if (!rawMode) {
29611
30126
  return {
29612
- message: `${color54.amber("Usage:")} /tool ${name} ${axis} simple|extend`
30127
+ message: `${color55.amber("Usage:")} /tool ${name} ${axis} simple|extend`
29613
30128
  };
29614
30129
  }
29615
30130
  const mode2 = normalizeToolDescriptionMode(rawMode);
29616
30131
  if (!mode2) {
29617
30132
  return {
29618
- message: `${color54.amber("Usage:")} /tool ${name} ${axis} simple|extend`
30133
+ message: `${color55.amber("Usage:")} /tool ${name} ${axis} simple|extend`
29619
30134
  };
29620
30135
  }
29621
30136
  try {
29622
30137
  if (axis === "desc") {
29623
30138
  const persisted2 = await persistModeForAxis(name, "desc", mode2);
29624
30139
  applyDescMode(name, mode2);
29625
- const persistence2 = persisted2 ? color54.dim("saved") : color54.dim("runtime only; config paths unavailable");
30140
+ const persistence2 = persisted2 ? color55.dim("saved") : color55.dim("runtime only; config paths unavailable");
29626
30141
  return {
29627
- message: `${color54.green("\u2713")} ${color54.cyan(name)} ${formatDescriptionMode(mode2)} ${persistence2}`
30142
+ message: `${color55.green("\u2713")} ${color55.cyan(name)} ${formatDescriptionMode(mode2)} ${persistence2}`
29628
30143
  };
29629
30144
  }
29630
30145
  const persisted = await persistModeForAxis(name, "result", mode2);
29631
30146
  applyResultMode(name, mode2);
29632
- const persistence = persisted ? color54.dim("saved") : color54.dim("runtime only; config paths unavailable");
30147
+ const persistence = persisted ? color55.dim("saved") : color55.dim("runtime only; config paths unavailable");
29633
30148
  return {
29634
- message: `${color54.green("\u2713")} ${color54.cyan(name)} ${formatResultRenderMode(mode2)} ${persistence}`
30149
+ message: `${color55.green("\u2713")} ${color55.cyan(name)} ${formatResultRenderMode(mode2)} ${persistence}`
29635
30150
  };
29636
30151
  } catch (err) {
29637
30152
  return {
29638
- message: `${color54.red("Could not save tool setting")}: ${toErrorMessage28(err)}`
30153
+ message: `${color55.red("Could not save tool setting")}: ${toErrorMessage28(err)}`
29639
30154
  };
29640
30155
  }
29641
30156
  }
29642
30157
  const mode = normalizeToolDescriptionMode(axis);
29643
30158
  if (!mode) {
29644
30159
  return {
29645
- message: `${color54.amber("Usage:")} /tool ${name} [desc|result] simple|extend`
30160
+ message: `${color55.amber("Usage:")} /tool ${name} [desc|result] simple|extend`
29646
30161
  };
29647
30162
  }
29648
30163
  try {
29649
30164
  const persisted = await persistModeBoth(name, mode);
29650
30165
  applyDescMode(name, mode);
29651
30166
  applyResultMode(name, mode);
29652
- const persistence = persisted ? color54.dim("saved (both axes)") : color54.dim("runtime only; config paths unavailable");
30167
+ const persistence = persisted ? color55.dim("saved (both axes)") : color55.dim("runtime only; config paths unavailable");
29653
30168
  return {
29654
- message: `${color54.green("\u2713")} ${color54.cyan(name)} ${formatDescriptionMode(mode)} + ${formatResultRenderMode(mode)} ${persistence}`
30169
+ message: `${color55.green("\u2713")} ${color55.cyan(name)} ${formatDescriptionMode(mode)} + ${formatResultRenderMode(mode)} ${persistence}`
29655
30170
  };
29656
30171
  } catch (err) {
29657
30172
  return {
29658
- message: `${color54.red("Could not save tool setting")}: ${toErrorMessage28(err)}`
30173
+ message: `${color55.red("Could not save tool setting")}: ${toErrorMessage28(err)}`
29659
30174
  };
29660
30175
  }
29661
30176
  }
@@ -29663,14 +30178,14 @@ function buildToolCommand(opts) {
29663
30178
  }
29664
30179
 
29665
30180
  // src/slash-commands/tools.ts
29666
- import { color as color55, getToolDescriptionMode as getToolDescriptionMode3 } from "@wrongstack/core/utils";
30181
+ import { color as color56, getToolDescriptionMode as getToolDescriptionMode3 } from "@wrongstack/core/utils";
29667
30182
  function fit2(text, width) {
29668
30183
  if (text.length <= width) return text.padEnd(width);
29669
30184
  return `${text.slice(0, Math.max(0, width - 3))}...`;
29670
30185
  }
29671
30186
  function formatDescriptionMode2(mode) {
29672
30187
  const raw = `desc:${mode}`;
29673
- return mode === "simple" ? color55.amber(raw) : color55.dim(raw);
30188
+ return mode === "simple" ? color56.amber(raw) : color56.dim(raw);
29674
30189
  }
29675
30190
  function buildToolsCommand(opts) {
29676
30191
  return {
@@ -29691,21 +30206,21 @@ function buildToolsCommand(opts) {
29691
30206
  if (opened) return { message: "" };
29692
30207
  }
29693
30208
  if (filter && all.length === 0) {
29694
- const msg2 = `${color55.bold("Tools")} \u2014 no tool name or owner matched "${filter}".`;
30209
+ const msg2 = `${color56.bold("Tools")} \u2014 no tool name or owner matched "${filter}".`;
29695
30210
  opts.renderer.write(msg2);
29696
30211
  return { message: msg2 };
29697
30212
  }
29698
- const header = ` ${color55.dim(fit2("tool", 28))} ${color55.dim(fit2("owner", 28))} ${color55.dim(fit2("rw", 4))} ${color55.dim(fit2("perm", 8))} ${color55.dim(fit2("status", 10))} ` + color55.dim("description");
30213
+ const header = ` ${color56.dim(fit2("tool", 28))} ${color56.dim(fit2("owner", 28))} ${color56.dim(fit2("rw", 4))} ${color56.dim(fit2("perm", 8))} ${color56.dim(fit2("status", 10))} ` + color56.dim("description");
29699
30214
  const lines = all.map(({ tool, owner }) => {
29700
30215
  const mode = getToolDescriptionMode3(reg, tool.name);
29701
- const rw = tool.mutating ? color55.yellow(fit2("mut", 4)) : color55.cyan(fit2("ro", 4));
29702
- const status = reg.isDisabled(tool.name) ? color55.red("disabled") : color55.green("active");
29703
- return ` ${fit2(tool.name, 28)} ${color55.dim(fit2(`[${owner}]`, 28))} ${rw} ${color55.dim(fit2(tool.permission, 8))} ${fit2(status, 10)} ` + formatDescriptionMode2(mode);
30216
+ const rw = tool.mutating ? color56.yellow(fit2("mut", 4)) : color56.cyan(fit2("ro", 4));
30217
+ const status = reg.isDisabled(tool.name) ? color56.red("disabled") : color56.green("active");
30218
+ return ` ${fit2(tool.name, 28)} ${color56.dim(fit2(`[${owner}]`, 28))} ${rw} ${color56.dim(fit2(tool.permission, 8))} ${fit2(status, 10)} ` + formatDescriptionMode2(mode);
29704
30219
  });
29705
30220
  const extra = disabled.length > 0 ? `
29706
- ${color55.dim(`${disabled.length} tool(s) disabled. Use /tool enable <name> or /tool enable-all to restore.`)}` : "";
29707
- const filterNote = filter ? color55.dim(` matching "${filter}" (${all.length} of ${allTools.length})`) : "";
29708
- const msg = `${color55.bold("Tools")}${filterNote} (${all.length} shown, ${disabled.length} disabled) ${color55.dim("description detail via /tool <name> simple|extend")}:
30221
+ ${color56.dim(`${disabled.length} tool(s) disabled. Use /tool enable <name> or /tool enable-all to restore.`)}` : "";
30222
+ const filterNote = filter ? color56.dim(` matching "${filter}" (${all.length} of ${allTools.length})`) : "";
30223
+ const msg = `${color56.bold("Tools")}${filterNote} (${all.length} shown, ${disabled.length} disabled) ${color56.dim("description detail via /tool <name> simple|extend")}:
29709
30224
  ${header}
29710
30225
  ${lines.join("\n")}${extra}
29711
30226
  `;
@@ -29719,7 +30234,7 @@ ${lines.join("\n")}${extra}
29719
30234
  import * as fs19 from "node:fs/promises";
29720
30235
  import * as os3 from "node:os";
29721
30236
  import * as path29 from "node:path";
29722
- import { atomicWrite as atomicWrite10, color as color56 } from "@wrongstack/core/utils";
30237
+ import { atomicWrite as atomicWrite10, color as color57 } from "@wrongstack/core/utils";
29723
30238
 
29724
30239
  // src/tuneup.ts
29725
30240
  var DEFAULT_EAGER_MAX_CHARS = 24e3;
@@ -30197,17 +30712,17 @@ function buildTuneupCommand(opts) {
30197
30712
  const parsed = parseArgs(args);
30198
30713
  if (parsed.mode === "help") return { message: help };
30199
30714
  if (parsed.mode === "usage") {
30200
- return { message: `${color56.amber("Usage:")} /tuneup [fix [--power] [--pick] | deep]` };
30715
+ return { message: `${color57.amber("Usage:")} /tuneup [fix [--power] [--pick] | deep]` };
30201
30716
  }
30202
30717
  if (!opts.paths) {
30203
- return { message: `${color56.red("Error")} config paths not available.` };
30718
+ return { message: `${color57.red("Error")} config paths not available.` };
30204
30719
  }
30205
30720
  const input = await gatherInput(opts, parsed.power);
30206
30721
  const report = runTuneup(input);
30207
- const lines = [`${color56.bold("WrongStack")} ${color56.dim("\u2014 Tune-up")}`];
30722
+ const lines = [`${color57.bold("WrongStack")} ${color57.dim("\u2014 Tune-up")}`];
30208
30723
  renderFindings(lines, report.findings);
30209
30724
  if (parsed.mode === "deep") {
30210
- lines.push("", color56.dim(" \u2192 asking the agent for a project-specific optimization plan\u2026"));
30725
+ lines.push("", color57.dim(" \u2192 asking the agent for a project-specific optimization plan\u2026"));
30211
30726
  return { message: lines.join("\n"), runText: buildDeepPrompt(report) };
30212
30727
  }
30213
30728
  if (parsed.mode === "report") {
@@ -30229,18 +30744,18 @@ function buildTuneupCommand(opts) {
30229
30744
  const applied = await applyActions(actions, opts);
30230
30745
  lines.push("");
30231
30746
  if (applied.messages.length === 0) {
30232
- lines.push(color56.dim(" no deterministic fixes to apply"));
30747
+ lines.push(color57.dim(" no deterministic fixes to apply"));
30233
30748
  } else {
30234
- for (const m of applied.messages) lines.push(` ${color56.green("\u2713")} ${m}`);
30749
+ for (const m of applied.messages) lines.push(` ${color57.green("\u2713")} ${m}`);
30235
30750
  if (applied.changed) {
30236
30751
  lines.push(
30237
- ` ${color56.green("\u2713")} written ${color56.dim("(backup: config.json.last + timestamped .bak)")}`
30752
+ ` ${color57.green("\u2713")} written ${color57.dim("(backup: config.json.last + timestamped .bak)")}`
30238
30753
  );
30239
30754
  }
30240
30755
  }
30241
30756
  const runText = report.agentHandoff || void 0;
30242
30757
  if (runText) {
30243
- lines.push("", color56.dim(" \u2192 handing instruction-file cleanups to the agent\u2026"));
30758
+ lines.push("", color57.dim(" \u2192 handing instruction-file cleanups to the agent\u2026"));
30244
30759
  }
30245
30760
  return { message: lines.join("\n"), ...runText ? { runText } : {} };
30246
30761
  }
@@ -30401,7 +30916,7 @@ async function applyActions(actions, opts) {
30401
30916
  parsed = JSON.parse(raw);
30402
30917
  } catch {
30403
30918
  return {
30404
- messages: [`${color56.red("\u2717")} global config is not valid JSON \u2014 run /doctor fix first`],
30919
+ messages: [`${color57.red("\u2717")} global config is not valid JSON \u2014 run /doctor fix first`],
30405
30920
  changed: false
30406
30921
  };
30407
30922
  }
@@ -30510,26 +31025,26 @@ var CATEGORY_ORDER = [
30510
31025
  function severityIcon(severity) {
30511
31026
  switch (severity) {
30512
31027
  case "error":
30513
- return color56.red("\u2717");
31028
+ return color57.red("\u2717");
30514
31029
  case "warning":
30515
- return color56.amber("!");
31030
+ return color57.amber("!");
30516
31031
  case "ok":
30517
- return color56.green("\u2713");
31032
+ return color57.green("\u2713");
30518
31033
  default:
30519
- return color56.cyan("\xB7");
31034
+ return color57.cyan("\xB7");
30520
31035
  }
30521
31036
  }
30522
31037
  function renderFindings(lines, findings) {
30523
31038
  for (const category of CATEGORY_ORDER) {
30524
31039
  const group = findings.filter((f) => f.category === category);
30525
31040
  if (group.length === 0) continue;
30526
- lines.push("", color56.bold(CATEGORY_LABELS[category]));
31041
+ lines.push("", color57.bold(CATEGORY_LABELS[category]));
30527
31042
  for (const f of group) {
30528
31043
  lines.push(` ${severityIcon(f.severity)} ${f.problem}`);
30529
31044
  if (f.suggestion) {
30530
- for (const s of f.suggestion.split("\n")) lines.push(color56.dim(` ${s}`));
31045
+ for (const s of f.suggestion.split("\n")) lines.push(color57.dim(` ${s}`));
30531
31046
  }
30532
- if (f.fix) lines.push(color56.dim(` \u2192 fixable: ${f.fix}`));
31047
+ if (f.fix) lines.push(color57.dim(` \u2192 fixable: ${f.fix}`));
30533
31048
  }
30534
31049
  }
30535
31050
  }
@@ -30538,20 +31053,20 @@ function summaryLine(findings, fixable, handoffs, power) {
30538
31053
  (f) => f.severity === "warning" || f.severity === "error"
30539
31054
  ).length;
30540
31055
  if (warnings === 0 && fixable === 0 && handoffs === 0) {
30541
- return `${color56.green("\u2713")} everything looks healthy`;
31056
+ return `${color57.green("\u2713")} everything looks healthy`;
30542
31057
  }
30543
31058
  const parts = [];
30544
31059
  if (warnings > 0) parts.push(`${warnings} warning(s)`);
30545
31060
  if (fixable > 0) parts.push(`${fixable} auto-fixable`);
30546
31061
  if (handoffs > 0) parts.push(`${handoffs} for the agent`);
30547
31062
  const cmd = power ? "/tuneup fix --power" : "/tuneup fix";
30548
- return `${parts.join(", ")} ${color56.dim(`\u2014 run ${cmd}`)}`;
31063
+ return `${parts.join(", ")} ${color57.dim(`\u2014 run ${cmd}`)}`;
30549
31064
  }
30550
31065
 
30551
31066
  // src/slash-commands/working-dir.ts
30552
31067
  import * as fs20 from "node:fs/promises";
30553
31068
  import * as path30 from "node:path";
30554
- import { color as color57, toErrorMessage as toErrorMessage29 } from "@wrongstack/core/utils";
31069
+ import { color as color58, toErrorMessage as toErrorMessage29 } from "@wrongstack/core/utils";
30555
31070
  function buildWorkingDirCommand(_opts) {
30556
31071
  return {
30557
31072
  name: "working_dir",
@@ -30570,16 +31085,16 @@ function buildWorkingDirCommand(_opts) {
30570
31085
  ].join("\n"),
30571
31086
  async run(args, ctx) {
30572
31087
  if (!ctx) {
30573
- return { message: color57.yellow("No active context. Start a session first.") };
31088
+ return { message: color58.yellow("No active context. Start a session first.") };
30574
31089
  }
30575
31090
  const trimmed = args.trim();
30576
31091
  if (!trimmed) {
30577
31092
  const rel2 = path30.relative(ctx.projectRoot, ctx.workingDir) || ".";
30578
31093
  return {
30579
31094
  message: [
30580
- `Working directory: ${color57.bold(ctx.workingDir)}`,
30581
- color57.dim(` (relative to root: ${rel2})`),
30582
- color57.dim(` Project root: ${ctx.projectRoot}`)
31095
+ `Working directory: ${color58.bold(ctx.workingDir)}`,
31096
+ color58.dim(` (relative to root: ${rel2})`),
31097
+ color58.dim(` Project root: ${ctx.projectRoot}`)
30583
31098
  ].join("\n")
30584
31099
  };
30585
31100
  }
@@ -30588,7 +31103,7 @@ function buildWorkingDirCommand(_opts) {
30588
31103
  const rel = path30.relative(root, resolved);
30589
31104
  if (rel.startsWith("..") || path30.isAbsolute(rel)) {
30590
31105
  return {
30591
- message: color57.red(
31106
+ message: color58.red(
30592
31107
  `Directory "${trimmed}" is outside the project root.
30593
31108
  Resolved: ${resolved}
30594
31109
  Root: ${root}`
@@ -30598,25 +31113,25 @@ function buildWorkingDirCommand(_opts) {
30598
31113
  try {
30599
31114
  const stat5 = await fs20.stat(resolved);
30600
31115
  if (!stat5.isDirectory()) {
30601
- return { message: color57.red(`Not a directory: ${resolved}`) };
31116
+ return { message: color58.red(`Not a directory: ${resolved}`) };
30602
31117
  }
30603
31118
  } catch {
30604
- return { message: color57.red(`Directory does not exist: ${resolved}`) };
31119
+ return { message: color58.red(`Directory does not exist: ${resolved}`) };
30605
31120
  }
30606
31121
  const previous = ctx.workingDir;
30607
31122
  try {
30608
31123
  ctx.setWorkingDir(resolved);
30609
31124
  } catch (err) {
30610
31125
  return {
30611
- message: color57.red(toErrorMessage29(err))
31126
+ message: color58.red(toErrorMessage29(err))
30612
31127
  };
30613
31128
  }
30614
31129
  const prevRel = path30.relative(ctx.projectRoot, previous) || ".";
30615
31130
  const newRel = path30.relative(ctx.projectRoot, resolved) || ".";
30616
31131
  return {
30617
31132
  message: [
30618
- color57.green(` \u2713 ${prevRel} \u2192 ${color57.bold(newRel)}`),
30619
- color57.dim(` ${resolved}`)
31133
+ color58.green(` \u2713 ${prevRel} \u2192 ${color58.bold(newRel)}`),
31134
+ color58.dim(` ${resolved}`)
30620
31135
  ].join("\n")
30621
31136
  };
30622
31137
  }
@@ -30685,7 +31200,7 @@ function buildWorktreeCommand(opts) {
30685
31200
  }
30686
31201
 
30687
31202
  // src/slash-commands/yolo.ts
30688
- import { color as color58 } from "@wrongstack/core/utils";
31203
+ import { color as color59 } from "@wrongstack/core/utils";
30689
31204
  function buildYoloCommand(opts) {
30690
31205
  return {
30691
31206
  name: "yolo",
@@ -30709,7 +31224,7 @@ function buildYoloCommand(opts) {
30709
31224
  }
30710
31225
  if (!arg) {
30711
31226
  const current = opts.onYolo();
30712
- const status = current ? `${color58.yellow("ON")} ${color58.dim("(auto-approving tool calls)")}` : `${color58.green("OFF")} ${color58.dim("(permission prompts active)")}`;
31227
+ const status = current ? `${color59.yellow("ON")} ${color59.dim("(auto-approving tool calls)")}` : `${color59.green("OFF")} ${color59.dim("(permission prompts active)")}`;
30713
31228
  const msg2 = `YOLO mode: ${status}`;
30714
31229
  opts.renderer.write(msg2);
30715
31230
  return { message: msg2 };
@@ -30724,11 +31239,11 @@ function buildYoloCommand(opts) {
30724
31239
  } else if (arg === "destructive") {
30725
31240
  const currentMode = opts.onYolo();
30726
31241
  if (!currentMode) {
30727
- const msg3 = `${color58.amber("YOLO is OFF.")} Destructive-gate flags are deprecated; prompts are active because YOLO is off.`;
31242
+ const msg3 = `${color59.amber("YOLO is OFF.")} Destructive-gate flags are deprecated; prompts are active because YOLO is off.`;
30728
31243
  opts.renderer.writeWarning(msg3);
30729
31244
  return { message: msg3 };
30730
31245
  }
30731
- const msg2 = `${color58.amber("Destructive gate:")} ${color58.dim("deprecated \u2014 YOLO auto-approves all non-denied tool calls.")}`;
31246
+ const msg2 = `${color59.amber("Destructive gate:")} ${color59.dim("deprecated \u2014 YOLO auto-approves all non-denied tool calls.")}`;
30732
31247
  opts.renderer.writeWarning(msg2);
30733
31248
  return { message: msg2 };
30734
31249
  } else {
@@ -30737,7 +31252,7 @@ function buildYoloCommand(opts) {
30737
31252
  return { message: msg2 };
30738
31253
  }
30739
31254
  opts.onYolo(newState);
30740
- const label = newState ? `${color58.yellow("ENABLED")} \u2014 tool calls will be auto-approved unless explicitly denied` : `${color58.green("DISABLED")} \u2014 permission prompts are active`;
31255
+ const label = newState ? `${color59.yellow("ENABLED")} \u2014 tool calls will be auto-approved unless explicitly denied` : `${color59.green("DISABLED")} \u2014 permission prompts are active`;
30741
31256
  const msg = `YOLO mode: ${label}`;
30742
31257
  opts.renderer.write(msg);
30743
31258
  return { message: msg };
@@ -30802,6 +31317,7 @@ function buildBuiltinSlashCommands(opts) {
30802
31317
  buildBtwCommand(opts),
30803
31318
  buildNextCommand(opts),
30804
31319
  buildModeCommand(opts),
31320
+ buildThemeCommand(opts),
30805
31321
  buildDesignCommand(opts),
30806
31322
  buildMailboxDemoCommand(opts),
30807
31323
  buildMailboxCommand(opts),
@@ -31559,7 +32075,7 @@ async function runInteractive(cliCtx) {
31559
32075
  onEvent: evOn
31560
32076
  });
31561
32077
  const savedProviderCfg = config.providers?.[config.provider];
31562
- const { execute } = await import("./execution-LZRYRGDD.js");
32078
+ const { execute } = await import("./execution-MVOH6PAQ.js");
31563
32079
  const stopHeapWatchdog = startSharedHeapWatchdog({
31564
32080
  collectStats: () => {
31565
32081
  const hqQueue = hqPublisherRef.current?.getQueueStats();
@@ -31792,4 +32308,4 @@ export {
31792
32308
  CLI_VERSION,
31793
32309
  runInteractive
31794
32310
  };
31795
- //# sourceMappingURL=cli-main-PJMDZHDK.js.map
32311
+ //# sourceMappingURL=cli-main-37XO26GK.js.map