@wairon/cli 5.1.1-dev.57 → 5.1.1-dev.58

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -65,7 +65,7 @@ var init_defaults = __esm({
65
65
  copilot: ".github/prompts",
66
66
  codex: ".codex/agents"
67
67
  };
68
- WAIRON_VERSION = "5.1.1-dev.57";
68
+ WAIRON_VERSION = "5.1.1-dev.58";
69
69
  GITHUB_REPO = "SYW-Apps/Waffle-AIron";
70
70
  SUPPORTED_ALIASES = ["wai"];
71
71
  SCAN_EXCLUDE_DIRS = /* @__PURE__ */ new Set([
@@ -546,6 +546,21 @@ var init_yaml = __esm({
546
546
  });
547
547
 
548
548
  // src/models/execution.ts
549
+ function summarize(budget, profile) {
550
+ const lines = [
551
+ `- **Work shape**: ${profile.breadth} breadth, ${profile.reasoningDepth} reasoning${profile.writes ? "" : ", read-only"}${profile.delegates ? ", delegating" : ""}`,
552
+ `- **Why**: ${profile.rationale}`
553
+ ];
554
+ if (budget.modelTier) lines.push(`- **Capability tier**: ${budget.modelTier}`);
555
+ if (budget.effort) lines.push(`- **Effort**: ${budget.effort}`);
556
+ if (budget.maxTurns !== void 0) {
557
+ lines.push(`- **Turn ceiling**: ${budget.maxTurns} (a circuit breaker \u2014 hitting it should read as a scoping error, not a limit to work up to)`);
558
+ }
559
+ lines.push(`- **Tool grant**: ${budget.toolClass}`);
560
+ lines.push(`- **May delegate further**: ${budget.allowNestedDelegation ? "yes" : "no"}`);
561
+ lines.push(`- **MCP access**: ${budget.mcp}`);
562
+ return lines;
563
+ }
549
564
  var import_zod, WorkBreadthSchema, ReasoningDepthSchema, ExecutionProfileSchema, ModelTierSchema, EffortTierSchema, ToolClassSchema, McpAccessSchema, ExecutionBudgetSchema, BudgetTierSchema, BUDGET_TIER_DESCRIPTIONS, ExecutionConfigSchema;
550
565
  var init_execution = __esm({
551
566
  "src/models/execution.ts"() {
@@ -14256,12 +14271,109 @@ var init_carried_debt = __esm({
14256
14271
  }
14257
14272
  });
14258
14273
 
14274
+ // src/core/rules/heuristic/method-cohesion.ts
14275
+ function groupsSharingCollaborators(calledBy) {
14276
+ const parent = /* @__PURE__ */ new Map();
14277
+ const find = (m) => {
14278
+ let root = m;
14279
+ while (parent.get(root) !== root) root = parent.get(root);
14280
+ return root;
14281
+ };
14282
+ const union = (a, b) => {
14283
+ const [ra, rb] = [find(a), find(b)];
14284
+ if (ra !== rb) parent.set(ra, rb);
14285
+ };
14286
+ const methods = [...calledBy.keys()];
14287
+ for (const m of methods) parent.set(m, m);
14288
+ for (let i = 0; i < methods.length; i++) {
14289
+ for (let j = i + 1; j < methods.length; j++) {
14290
+ const shares = [...calledBy.get(methods[i])].some((c) => calledBy.get(methods[j])?.has(c));
14291
+ if (shares) union(methods[i], methods[j]);
14292
+ }
14293
+ }
14294
+ const groups = /* @__PURE__ */ new Map();
14295
+ for (const m of methods) {
14296
+ const root = find(m);
14297
+ groups.set(root, [...groups.get(root) ?? [], m]);
14298
+ }
14299
+ return [...groups.values()];
14300
+ }
14301
+ function isForwardingMethod(narrative) {
14302
+ let handoffs = 0;
14303
+ for (const step of narrative) {
14304
+ if (step.type === "call" || step.type === "dispatch") handoffs++;
14305
+ else if (step.type !== "return") return false;
14306
+ }
14307
+ return handoffs === 1;
14308
+ }
14309
+ function isPureForwarder(methods) {
14310
+ const narrated = methods.filter((m) => (m.narrative ?? []).length > 0);
14311
+ return narrated.length > 0 && narrated.every((m) => isForwardingMethod(m.narrative ?? []));
14312
+ }
14313
+ function pureForwarderComponents(ctx) {
14314
+ const realized = /* @__PURE__ */ new Map();
14315
+ for (const impl of ctx.implementations) {
14316
+ const intf = ctx.interfaceMap.get(impl.contract);
14317
+ if (!intf) continue;
14318
+ realized.set(intf.component, [...realized.get(intf.component) ?? [], ...impl.methods]);
14319
+ }
14320
+ return new Set([...realized].filter(([, methods]) => isPureForwarder(methods)).map(([id]) => id));
14321
+ }
14322
+ var methodCohesionRule;
14323
+ var init_method_cohesion = __esm({
14324
+ "src/core/rules/heuristic/method-cohesion.ts"() {
14325
+ "use strict";
14326
+ methodCohesionRule = {
14327
+ name: "method-cohesion",
14328
+ description: "An Orchestrator's methods share collaborators; when they split into groups that call no component in common, the component holds more than one responsibility. Reported only where two or more groups each hold two or more methods, so a single specialized method is not a finding \u2014 and never on a pure forwarder, whose every narrated method is a single hand-off and whose responsibility therefore lives in what it forwards to.",
14329
+ codes: [
14330
+ { code: "INCOHESIVE_METHODS", defaultSeverity: "warning", summary: "Orchestrator's methods form two or more groups of two or more that share no called component" }
14331
+ ],
14332
+ check(ctx) {
14333
+ const subjects = [];
14334
+ for (const impl of ctx.implementations) {
14335
+ const intf = ctx.interfaceMap.get(impl.contract);
14336
+ const comp = intf ? ctx.componentMap.get(intf.component) : void 0;
14337
+ if (!comp || comp.componentType !== "Orchestrator") continue;
14338
+ if (isPureForwarder(impl.methods)) continue;
14339
+ const calledBy = /* @__PURE__ */ new Map();
14340
+ for (const method2 of impl.methods) {
14341
+ const reached = /* @__PURE__ */ new Set();
14342
+ for (const step of method2.narrative ?? []) {
14343
+ if ((step.type === "call" || step.type === "dispatch") && step.targetComponent) reached.add(step.targetComponent);
14344
+ }
14345
+ if (reached.size > 0) calledBy.set(method2.name, reached);
14346
+ }
14347
+ subjects.push({ implementation: impl, component: comp, calledBy });
14348
+ }
14349
+ for (const { component, calledBy } of subjects) {
14350
+ if (calledBy.size < 2) continue;
14351
+ const groups = groupsSharingCollaborators(calledBy).filter((g) => g.length >= 2);
14352
+ if (groups.length < 2) continue;
14353
+ const described = groups.map((g) => {
14354
+ const collaborators = [...new Set(g.flatMap((m) => [...calledBy.get(m)]))].sort();
14355
+ return `${g.join(", ")} (calling ${collaborators.join(", ")})`;
14356
+ }).join("; ");
14357
+ ctx.addIssue(
14358
+ "warning",
14359
+ "INCOHESIVE_METHODS",
14360
+ `Orchestrator "${component.id}" holds ${groups.length} groups of methods that share no called component: ${described}. Split it along those groups, move the logic out until every method is a single hand-off (a pure forwarder is exempt), or acknowledge a deliberate facade with a reasoned lint.allow for INCOHESIVE_METHODS.`,
14361
+ component.id,
14362
+ ctx.isComponentDraft(component.id)
14363
+ );
14364
+ }
14365
+ }
14366
+ };
14367
+ }
14368
+ });
14369
+
14259
14370
  // src/core/rules/heuristic/coupling-health.ts
14260
14371
  var DEFAULT_GOD_COMPONENT_THRESHOLD, couplingRule;
14261
14372
  var init_coupling_health = __esm({
14262
14373
  "src/core/rules/heuristic/coupling-health.ts"() {
14263
14374
  "use strict";
14264
14375
  init_models();
14376
+ init_method_cohesion();
14265
14377
  DEFAULT_GOD_COMPONENT_THRESHOLD = 8;
14266
14378
  couplingRule = {
14267
14379
  name: "coupling-health",
@@ -14270,7 +14382,7 @@ var init_coupling_health = __esm({
14270
14382
  { code: "MUTUAL_SUBSYSTEM_DEPENDENCY", defaultSeverity: "warning", summary: "Subsystems depend on each other without a declared trusted link" },
14271
14383
  { code: "INVALID_TRUSTED_LINK", defaultSeverity: "error", summary: "trustedLinks references a non-existent subsystem" },
14272
14384
  { code: "UNUSED_TRUSTED_LINK", defaultSeverity: "warning", summary: "trustedLinks declares a peer no dependency actually reaches" },
14273
- { code: "GOD_COMPONENT", defaultSeverity: "warning", summary: "Component with excessive dependency fan-out" }
14385
+ { code: "GOD_COMPONENT", defaultSeverity: "warning", summary: "Component with excessive dependency fan-out; not reported on a pure forwarder, whose every narrated method is a single hand-off" }
14274
14386
  ],
14275
14387
  check(ctx) {
14276
14388
  const subsystemDeps = /* @__PURE__ */ new Map();
@@ -14342,9 +14454,10 @@ var init_coupling_health = __esm({
14342
14454
  );
14343
14455
  }
14344
14456
  }
14457
+ const forwarders = pureForwarderComponents(ctx);
14345
14458
  for (const comp of ctx.components) {
14346
14459
  const threshold = ctx.complexityConfigFor(comp.subsystem)?.maxComponentDependencies ?? DEFAULT_GOD_COMPONENT_THRESHOLD;
14347
- if (comp.dependsOn.length > threshold) {
14460
+ if (comp.dependsOn.length > threshold && !forwarders.has(comp.id)) {
14348
14461
  ctx.addIssue(
14349
14462
  "warning",
14350
14463
  "GOD_COMPONENT",
@@ -14968,6 +15081,7 @@ var init_complexity_and_metadata = __esm({
14968
15081
  "src/core/rules/heuristic/complexity-and-metadata.ts"() {
14969
15082
  "use strict";
14970
15083
  init_models();
15084
+ init_method_cohesion();
14971
15085
  complexityRule = {
14972
15086
  name: "complexity-and-metadata",
14973
15087
  description: "Enforces metadata documentation completeness (checking if descriptions are missing or too short) and structural complexity caps (limits on methods per interface, parameters per method, dependencies per component, and components per subsystem) configured globally or in architectural profiles. A narrative's own length and shape are judged by narrative-complexity.",
@@ -14976,7 +15090,7 @@ var init_complexity_and_metadata = __esm({
14976
15090
  { code: "DESCRIPTION_TOO_SHORT", defaultSeverity: "warning", summary: "Description is shorter than the configured minimum length" },
14977
15091
  { code: "EXCESSIVE_METHODS", defaultSeverity: "warning", summary: "Interface declares more methods than the configured limit" },
14978
15092
  { code: "EXCESSIVE_METHOD_PARAMS", defaultSeverity: "warning", summary: "Interface method declares more parameters than the configured limit" },
14979
- { code: "EXCESSIVE_DEPENDENCIES", defaultSeverity: "warning", summary: "Component has more dependencies than the configured limit" },
15093
+ { code: "EXCESSIVE_DEPENDENCIES", defaultSeverity: "warning", summary: "Component has more dependencies than the configured limit; not reported on a pure forwarder, whose fan-out is a routing table rather than knowledge" },
14980
15094
  { code: "EXCESSIVE_SUBSYSTEM_COMPONENTS", defaultSeverity: "warning", summary: "Subsystem has more direct components than the configured limit" }
14981
15095
  ],
14982
15096
  check(ctx) {
@@ -14996,6 +15110,7 @@ var init_complexity_and_metadata = __esm({
14996
15110
  );
14997
15111
  }
14998
15112
  }
15113
+ const forwarders = pureForwarderComponents(ctx);
14999
15114
  for (const comp of ctx.components) {
15000
15115
  const docConfig = ctx.documentationConfigFor(comp.subsystem);
15001
15116
  const complexityConfig = ctx.complexityConfigFor(comp.subsystem);
@@ -15009,7 +15124,7 @@ var init_complexity_and_metadata = __esm({
15009
15124
  "Component",
15010
15125
  isDraft
15011
15126
  );
15012
- if (complexityConfig?.maxComponentDependencies !== void 0 && comp.dependsOn.length > complexityConfig.maxComponentDependencies) {
15127
+ if (complexityConfig?.maxComponentDependencies !== void 0 && comp.dependsOn.length > complexityConfig.maxComponentDependencies && !forwarders.has(comp.id)) {
15013
15128
  ctx.addIssue(
15014
15129
  "warning",
15015
15130
  "EXCESSIVE_DEPENDENCIES",
@@ -15308,90 +15423,6 @@ var init_naming_discipline = __esm({
15308
15423
  }
15309
15424
  });
15310
15425
 
15311
- // src/core/rules/heuristic/method-cohesion.ts
15312
- function groupsSharingCollaborators(calledBy) {
15313
- const parent = /* @__PURE__ */ new Map();
15314
- const find = (m) => {
15315
- let root = m;
15316
- while (parent.get(root) !== root) root = parent.get(root);
15317
- return root;
15318
- };
15319
- const union = (a, b) => {
15320
- const [ra, rb] = [find(a), find(b)];
15321
- if (ra !== rb) parent.set(ra, rb);
15322
- };
15323
- const methods = [...calledBy.keys()];
15324
- for (const m of methods) parent.set(m, m);
15325
- for (let i = 0; i < methods.length; i++) {
15326
- for (let j = i + 1; j < methods.length; j++) {
15327
- const shares = [...calledBy.get(methods[i])].some((c) => calledBy.get(methods[j])?.has(c));
15328
- if (shares) union(methods[i], methods[j]);
15329
- }
15330
- }
15331
- const groups = /* @__PURE__ */ new Map();
15332
- for (const m of methods) {
15333
- const root = find(m);
15334
- groups.set(root, [...groups.get(root) ?? [], m]);
15335
- }
15336
- return [...groups.values()];
15337
- }
15338
- function isForwardingMethod(narrative) {
15339
- let handoffs = 0;
15340
- for (const step of narrative) {
15341
- if (step.type === "call" || step.type === "dispatch") handoffs++;
15342
- else if (step.type !== "return") return false;
15343
- }
15344
- return handoffs === 1;
15345
- }
15346
- var methodCohesionRule;
15347
- var init_method_cohesion = __esm({
15348
- "src/core/rules/heuristic/method-cohesion.ts"() {
15349
- "use strict";
15350
- methodCohesionRule = {
15351
- name: "method-cohesion",
15352
- description: "An Orchestrator's methods share collaborators; when they split into groups that call no component in common, the component holds more than one responsibility. Reported only where two or more groups each hold two or more methods, so a single specialized method is not a finding \u2014 and never on a pure forwarder, whose every narrated method is a single hand-off and whose responsibility therefore lives in what it forwards to.",
15353
- codes: [
15354
- { code: "INCOHESIVE_METHODS", defaultSeverity: "warning", summary: "Orchestrator's methods form two or more groups of two or more that share no called component" }
15355
- ],
15356
- check(ctx) {
15357
- const subjects = [];
15358
- for (const impl of ctx.implementations) {
15359
- const intf = ctx.interfaceMap.get(impl.contract);
15360
- const comp = intf ? ctx.componentMap.get(intf.component) : void 0;
15361
- if (!comp || comp.componentType !== "Orchestrator") continue;
15362
- const narrated = impl.methods.filter((m) => (m.narrative ?? []).length > 0);
15363
- if (narrated.length > 0 && narrated.every((m) => isForwardingMethod(m.narrative ?? []))) continue;
15364
- const calledBy = /* @__PURE__ */ new Map();
15365
- for (const method2 of impl.methods) {
15366
- const reached = /* @__PURE__ */ new Set();
15367
- for (const step of method2.narrative ?? []) {
15368
- if ((step.type === "call" || step.type === "dispatch") && step.targetComponent) reached.add(step.targetComponent);
15369
- }
15370
- if (reached.size > 0) calledBy.set(method2.name, reached);
15371
- }
15372
- subjects.push({ implementation: impl, component: comp, calledBy });
15373
- }
15374
- for (const { component, calledBy } of subjects) {
15375
- if (calledBy.size < 2) continue;
15376
- const groups = groupsSharingCollaborators(calledBy).filter((g) => g.length >= 2);
15377
- if (groups.length < 2) continue;
15378
- const described = groups.map((g) => {
15379
- const collaborators = [...new Set(g.flatMap((m) => [...calledBy.get(m)]))].sort();
15380
- return `${g.join(", ")} (calling ${collaborators.join(", ")})`;
15381
- }).join("; ");
15382
- ctx.addIssue(
15383
- "warning",
15384
- "INCOHESIVE_METHODS",
15385
- `Orchestrator "${component.id}" holds ${groups.length} groups of methods that share no called component: ${described}. Split it along those groups, move the logic out until every method is a single hand-off (a pure forwarder is exempt), or acknowledge a deliberate facade with a reasoned lint.allow for INCOHESIVE_METHODS.`,
15386
- component.id,
15387
- ctx.isComponentDraft(component.id)
15388
- );
15389
- }
15390
- }
15391
- };
15392
- }
15393
- });
15394
-
15395
15426
  // src/core/rules/repository.ts
15396
15427
  function addRule(rule) {
15397
15428
  ruleSet.push(rule);
@@ -23251,21 +23282,6 @@ function resolveBudget(profile, config, agentId) {
23251
23282
  const override = config.overrides[agentId];
23252
23283
  return override ? { ...budget, ...override } : budget;
23253
23284
  }
23254
- function describeBudget(profile, budget) {
23255
- const lines = [
23256
- `- **Work shape**: ${profile.breadth} breadth, ${profile.reasoningDepth} reasoning${profile.writes ? "" : ", read-only"}${profile.delegates ? ", delegating" : ""}`,
23257
- `- **Why**: ${profile.rationale}`
23258
- ];
23259
- if (budget.modelTier) lines.push(`- **Capability tier**: ${budget.modelTier}`);
23260
- if (budget.effort) lines.push(`- **Effort**: ${budget.effort}`);
23261
- if (budget.maxTurns !== void 0) {
23262
- lines.push(`- **Turn ceiling**: ${budget.maxTurns} (a circuit breaker \u2014 hitting it should read as a scoping error, not a limit to work up to)`);
23263
- }
23264
- lines.push(`- **Tool grant**: ${budget.toolClass}`);
23265
- lines.push(`- **May delegate further**: ${budget.allowNestedDelegation ? "yes" : "no"}`);
23266
- lines.push(`- **MCP access**: ${budget.mcp}`);
23267
- return lines;
23268
- }
23269
23285
  var TIER_ORDER, TIER_STEPS;
23270
23286
  var init_budget_policy = __esm({
23271
23287
  "src/core/budget_policy.ts"() {
@@ -23406,7 +23422,7 @@ function inferSourcePathForComponent(comp, subsystems) {
23406
23422
  return null;
23407
23423
  }
23408
23424
  }
23409
- function summarize(text2, max = 140) {
23425
+ function summarize2(text2, max = 140) {
23410
23426
  const clean = text2.replace(/\s+/g, " ").trim();
23411
23427
  const period = clean.indexOf(". ");
23412
23428
  const firstSentence = period > 0 ? clean.slice(0, period + 1) : clean;
@@ -23433,7 +23449,7 @@ function resolveAgentTopology() {
23433
23449
  agents.push({
23434
23450
  id: "system-architect",
23435
23451
  name: `${system.name} Architect`,
23436
- description: `Global architect for ${system.name} \u2014 owns the spec tree and topology. ${summarize(system.vision)}`,
23452
+ description: `Global architect for ${system.name} \u2014 owns the spec tree and topology. ${summarize2(system.vision)}`,
23437
23453
  template: "architect",
23438
23454
  creationReason: "Automatically inferred from L0 system spec",
23439
23455
  ownedPaths: [".wai/specs/**"],
@@ -23513,7 +23529,7 @@ function resolveAgentTopology() {
23513
23529
  agents.push({
23514
23530
  id: `${sub.id}-owner`,
23515
23531
  name: `${sub.name} Owner`,
23516
- description: `Owns the ${sub.id} subsystem. ${summarize(sub.description)}`,
23532
+ description: `Owns the ${sub.id} subsystem. ${summarize2(sub.description)}`,
23517
23533
  template: "domain-owner",
23518
23534
  creationReason: `Automatically inferred from L1 subsystem spec: ${sub.id}`,
23519
23535
  domainRoot: sub.id,
@@ -23578,7 +23594,7 @@ function resolveAgentTopology() {
23578
23594
  agents.push({
23579
23595
  id: `${dom.id}-owner`,
23580
23596
  name: `${dom.name ?? dom.id} Owner`,
23581
- description: dom.description ? summarize(dom.description) : `Owner agent for the free-standing "${dom.id}" domain.`,
23597
+ description: dom.description ? summarize2(dom.description) : `Owner agent for the free-standing "${dom.id}" domain.`,
23582
23598
  template: "domain-owner",
23583
23599
  creationReason: "Inferred from a free-standing domain in .wai/topology.yaml",
23584
23600
  domainRoot: dom.id,
@@ -28257,6 +28273,8 @@ var init_core = __esm({
28257
28273
  init_approver();
28258
28274
  init_specs2();
28259
28275
  init_project_config();
28276
+ init_execution_profile();
28277
+ init_budget_policy();
28260
28278
  }
28261
28279
  });
28262
28280
 
@@ -28958,7 +28976,7 @@ function renderAgentBriefMarkdown(brief) {
28958
28976
  "",
28959
28977
  "## Execution budget",
28960
28978
  "",
28961
- ...describeBudget(brief.profile, brief.budget),
28979
+ ...summarize(brief.budget, brief.profile),
28962
28980
  "",
28963
28981
  "Advisory \u2014 apply these when spawning. Map the capability tier onto your host tool's models; a tool that cannot express a field should ignore it rather than approximate it."
28964
28982
  );
@@ -30346,7 +30364,7 @@ var init_server = __esm({
30346
30364
  init_variants();
30347
30365
  init_agent_resolver();
30348
30366
  init_core();
30349
- init_budget_policy();
30367
+ init_execution();
30350
30368
  init_surfaces();
30351
30369
  TYPE_REF_GRAMMAR = (what) => `${what}: a primitive/builtin or a defined type id (qualified across subsystems, e.g. "billing.Invoice" or "billing::Invoice"). Generics, arrays and UNIONS are all read, at any depth: "Invoice | null" (the commonest shape there is), "Invoice | undefined", "Invoice | Receipt", "Promise<Invoice | null>", "Map<string, Invoice | null>", "Invoice[] | null", "(Invoice | null)[]". Every identifier the string names must resolve \u2014 a union of two defined types means BOTH must exist. A union of string literals ("read" | "write") names no type and resolves to nothing.`;
30352
30370
  staleServerOutput = {
@@ -31116,6 +31134,12 @@ function removeDomain2(id) {
31116
31134
  function detectDomainCandidates2(projectRoot2, trackedPaths, trackedIds) {
31117
31135
  return detectDomainCandidates(projectRoot2, trackedPaths, trackedIds);
31118
31136
  }
31137
+ function deriveExecutionProfile2(agent) {
31138
+ return deriveExecutionProfile(agent);
31139
+ }
31140
+ function resolveBudget2(profile, config, agentId) {
31141
+ return resolveBudget(profile, config, agentId);
31142
+ }
31119
31143
  async function runSubsystemAdd(id, options = {}) {
31120
31144
  logger.header("wairon subsystem add");
31121
31145
  if (!projectConfigExists2()) {
@@ -48372,15 +48396,12 @@ function report(outcome) {
48372
48396
  }
48373
48397
 
48374
48398
  // src/cli/index.ts
48375
- init_budget_policy();
48399
+ init_execution();
48376
48400
 
48377
48401
  // src/commands/execution.ts
48378
48402
  var import_chalk21 = __toESM(require("chalk"));
48379
48403
  init_logger();
48380
48404
  init_errors();
48381
- init_agent_resolver();
48382
- init_execution_profile();
48383
- init_budget_policy();
48384
48405
  init_execution();
48385
48406
  function assertInitialized() {
48386
48407
  if (!projectConfigExists2()) {
@@ -48408,7 +48429,7 @@ async function showExecution() {
48408
48429
  logger.info(`Enable with ${import_chalk21.default.bold("wairon execution set-tier default")}.`);
48409
48430
  return;
48410
48431
  }
48411
- const agents = resolveAgentTopology();
48432
+ const agents = resolveAgentTopology2();
48412
48433
  if (agents.length === 0) {
48413
48434
  logger.blank();
48414
48435
  logger.warn("No agents in the topology yet \u2014 nothing to budget.");
@@ -48416,8 +48437,8 @@ async function showExecution() {
48416
48437
  }
48417
48438
  logger.blank();
48418
48439
  const rows = agents.map((agent) => {
48419
- const profile = deriveExecutionProfile(agent);
48420
- const budget = resolveBudget(profile, config.execution, agent.id);
48440
+ const profile = deriveExecutionProfile2(agent);
48441
+ const budget = resolveBudget2(profile, config.execution, agent.id);
48421
48442
  return { agent, profile, budget };
48422
48443
  });
48423
48444
  const idWidth = Math.max(...rows.map((r) => r.agent.id.length));
@@ -48752,7 +48773,7 @@ async function runAgent(action, id) {
48752
48773
  if (brief.budget && brief.profile) {
48753
48774
  logger.blank();
48754
48775
  logger.info("Execution budget (advisory \u2014 apply when spawning):");
48755
- for (const line2 of describeBudget(brief.profile, brief.budget)) {
48776
+ for (const line2 of summarize(brief.budget, brief.profile)) {
48756
48777
  logger.info(` ${line2.replace(/^- \*\*(.+?)\*\*: /, "$1: ")}`);
48757
48778
  }
48758
48779
  }