@nathapp/nax 0.69.10 → 0.70.0-canary.2

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.
Files changed (2) hide show
  1. package/dist/nax.js +1091 -623
  2. package/package.json +1 -1
package/dist/nax.js CHANGED
@@ -16705,7 +16705,8 @@ var init_schemas_model = __esm(() => {
16705
16705
  ConfiguredModelSchema = exports_external.union([ModelTierSchema, ConfiguredModelObjectSchema]);
16706
16706
  TierConfigSchema = exports_external.object({
16707
16707
  tier: exports_external.string().min(1, "Tier name must be non-empty"),
16708
- attempts: exports_external.number().int().min(1).max(20, { message: "attempts must be 1-20" })
16708
+ attempts: exports_external.number().int().min(1).max(20, { message: "attempts must be 1-20" }),
16709
+ agent: exports_external.string().min(1, { message: "agent must be non-empty" }).optional()
16709
16710
  });
16710
16711
  });
16711
16712
 
@@ -17000,7 +17001,7 @@ var init_schemas_execution = __esm(() => {
17000
17001
  });
17001
17002
 
17002
17003
  // src/config/schemas-infra.ts
17003
- var PlanConfigSchema, AcceptanceFixConfigSchema, AcceptanceConfigSchema, LlmRoutingConfigSchema, RoutingConfigSchema, OptimizerConfigSchema, PluginConfigEntrySchema, HooksConfigSchema, InteractionConfigSchema, StorySizeGateConfigSchema, PromptAuditConfigSchema, AgentFallbackConfigSchema, DEFAULT_AGENT_IDLE_WATCHDOG_CONFIG, AgentIdleWatchdogConfigSchema, AgentAcpConfigSchema, AgentConfigSchema, PrecheckConfigSchema, PromptsConfigSchema, ProjectProfileSchema, VALID_AGENT_TYPES, GenerateConfigSchema, CuratorThresholdsSchema, CuratorConfigSchema;
17004
+ var PlanConfigSchema, AcceptanceFixConfigSchema, AcceptanceConfigSchema, LlmRoutingConfigSchema, AgentRoutingProfileSchema, AgentRoutingConfigSchema, RoutingConfigSchema, OptimizerConfigSchema, PluginConfigEntrySchema, HooksConfigSchema, InteractionConfigSchema, StorySizeGateConfigSchema, PromptAuditConfigSchema, AgentFallbackConfigSchema, DEFAULT_AGENT_IDLE_WATCHDOG_CONFIG, AgentIdleWatchdogConfigSchema, AgentAcpConfigSchema, AgentConfigSchema, PrecheckConfigSchema, PromptsConfigSchema, ProjectProfileSchema, VALID_AGENT_TYPES, GenerateConfigSchema, CuratorThresholdsSchema, CuratorConfigSchema;
17004
17005
  var init_schemas_infra = __esm(() => {
17005
17006
  init_zod();
17006
17007
  init_schemas_model();
@@ -17027,6 +17028,7 @@ var init_schemas_infra = __esm(() => {
17027
17028
  testPath: exports_external.string().min(1, "acceptance.testPath must be non-empty"),
17028
17029
  command: exports_external.string().optional(),
17029
17030
  model: ConfiguredModelSchema.default("fast"),
17031
+ generateModel: ConfiguredModelSchema.optional(),
17030
17032
  refinement: exports_external.boolean().default(true),
17031
17033
  refinementConcurrency: exports_external.number().int().min(1).max(10).default(3),
17032
17034
  redGate: exports_external.boolean().default(true),
@@ -17054,9 +17056,57 @@ var init_schemas_infra = __esm(() => {
17054
17056
  retries: exports_external.number().int().min(0, { message: "llm.retries must be >= 0" }).optional(),
17055
17057
  retryDelayMs: exports_external.number().int().min(0, { message: "llm.retryDelayMs must be >= 0" }).optional()
17056
17058
  });
17059
+ AgentRoutingProfileSchema = exports_external.object({
17060
+ id: exports_external.string().min(1),
17061
+ target: exports_external.object({
17062
+ agent: exports_external.string().min(1),
17063
+ model: ModelTierSchema
17064
+ }),
17065
+ strengths: exports_external.array(exports_external.string().min(1)).min(1),
17066
+ weaknesses: exports_external.array(exports_external.string().min(1)).optional(),
17067
+ costTier: exports_external.enum(["low", "medium", "high"]).optional(),
17068
+ affinity: exports_external.object({
17069
+ taskTypes: exports_external.array(exports_external.string().min(1)).optional(),
17070
+ domains: exports_external.array(exports_external.string().min(1)).optional()
17071
+ }).optional()
17072
+ });
17073
+ AgentRoutingConfigSchema = exports_external.object({
17074
+ enabled: exports_external.boolean().default(true),
17075
+ strategy: exports_external.enum(["off", "llm"]).default("off"),
17076
+ default: exports_external.string().optional(),
17077
+ profiles: exports_external.array(AgentRoutingProfileSchema).default([])
17078
+ }).superRefine((cfg, ctx) => {
17079
+ const ids = cfg.profiles.map((p) => p.id);
17080
+ const seen = new Set;
17081
+ for (const [i, id] of ids.entries()) {
17082
+ if (seen.has(id)) {
17083
+ ctx.addIssue({
17084
+ code: "custom",
17085
+ path: ["profiles", i, "id"],
17086
+ message: `Duplicate profile id "${id}"`
17087
+ });
17088
+ }
17089
+ seen.add(id);
17090
+ }
17091
+ if (cfg.default !== undefined && !ids.includes(cfg.default)) {
17092
+ ctx.addIssue({
17093
+ code: "custom",
17094
+ path: ["default"],
17095
+ message: `Default profile "${cfg.default}" is not in the profiles list`
17096
+ });
17097
+ }
17098
+ if (cfg.strategy === "llm" && cfg.profiles.length === 0) {
17099
+ ctx.addIssue({
17100
+ code: "custom",
17101
+ path: ["strategy"],
17102
+ message: 'strategy "llm" requires at least one profile in routing.agents.profiles'
17103
+ });
17104
+ }
17105
+ });
17057
17106
  RoutingConfigSchema = exports_external.object({
17058
17107
  strategy: exports_external.enum(["keyword", "llm"]),
17059
- llm: LlmRoutingConfigSchema.optional()
17108
+ llm: LlmRoutingConfigSchema.optional(),
17109
+ agents: AgentRoutingConfigSchema.default({ enabled: true, strategy: "off", profiles: [] })
17060
17110
  });
17061
17111
  OptimizerConfigSchema = exports_external.object({
17062
17112
  enabled: exports_external.boolean(),
@@ -17313,7 +17363,8 @@ var init_schemas3 = __esm(() => {
17313
17363
  cacheDecisions: true,
17314
17364
  mode: "hybrid",
17315
17365
  timeoutMs: 30000
17316
- }
17366
+ },
17367
+ agents: { enabled: true, strategy: "off", profiles: [] }
17317
17368
  }),
17318
17369
  execution: ExecutionConfigSchema.default({
17319
17370
  maxIterations: 10,
@@ -17618,6 +17669,48 @@ var init_schemas3 = __esm(() => {
17618
17669
  }).refine((data) => data.version === 1, {
17619
17670
  message: "Invalid version: expected 1",
17620
17671
  path: ["version"]
17672
+ }).superRefine((data, ctx) => {
17673
+ const tierOrder = data.autoMode?.escalation?.tierOrder ?? [];
17674
+ const knownAgents = Object.keys(data.models ?? {});
17675
+ for (const [i, rung] of tierOrder.entries()) {
17676
+ if (rung.agent === undefined)
17677
+ continue;
17678
+ if (!knownAgents.includes(rung.agent)) {
17679
+ ctx.addIssue({
17680
+ code: "custom",
17681
+ path: ["autoMode", "escalation", "tierOrder", i, "agent"],
17682
+ message: `Agent "${rung.agent}" is not defined in config.models (known: ${knownAgents.join(", ")})`
17683
+ });
17684
+ } else {
17685
+ const agentTiers = data.models?.[rung.agent] ?? {};
17686
+ if (!(rung.tier in agentTiers)) {
17687
+ ctx.addIssue({
17688
+ code: "custom",
17689
+ path: ["autoMode", "escalation", "tierOrder", i, "tier"],
17690
+ message: `Tier "${rung.tier}" is not defined for agent "${rung.agent}" in config.models`
17691
+ });
17692
+ }
17693
+ }
17694
+ }
17695
+ const profiles = data.routing.agents?.profiles ?? [];
17696
+ for (const [pi, profile] of profiles.entries()) {
17697
+ const { agent: pAgent, model: pModel } = profile.target;
17698
+ const hasMatchingRung = tierOrder.some((r) => r.tier === pModel && r.agent === pAgent);
17699
+ if (!hasMatchingRung) {
17700
+ ctx.addIssue({
17701
+ code: "custom",
17702
+ path: ["routing", "agents", "profiles", pi, "target"],
17703
+ message: `Profile "${profile.id}" target (${pAgent}@${pModel}) has no matching rung in autoMode.escalation.tierOrder \u2014 escalation from this profile has no defined path. To fix: agent-qualify the ladder by adding a rung { "tier": "${pModel}", "agent": "${pAgent}", "attempts": <n> } (and an agent on every other rung) to autoMode.escalation.tierOrder.`
17704
+ });
17705
+ }
17706
+ if (!knownAgents.includes(pAgent)) {
17707
+ ctx.addIssue({
17708
+ code: "custom",
17709
+ path: ["routing", "agents", "profiles", pi, "target", "agent"],
17710
+ message: `Profile "${profile.id}" target agent "${pAgent}" is not defined in config.models`
17711
+ });
17712
+ }
17713
+ }
17621
17714
  });
17622
17715
  });
17623
17716
 
@@ -19139,8 +19232,8 @@ function reshapeSelector(name, fn) {
19139
19232
  var reviewConfigSelector, planConfigSelector, decomposeConfigSelector, rectifyConfigSelector, acceptanceConfigSelector, acceptanceFixConfigSelector, acceptanceGenConfigSelector, tddConfigSelector, debateConfigSelector, routingConfigSelector, verifyConfigSelector, rectificationGateConfigSelector, agentConfigSelector, agentManagerConfigSelector, interactionConfigSelector, precheckConfigSelector, qualityConfigSelector, autofixConfigSelector, executionGatesConfigSelector, testPatternConfigSelector, contextConfigSelector, contextToolRuntimeConfigSelector, promptLoaderConfigSelector, llmRoutingConfigSelector;
19140
19233
  var init_selectors = __esm(() => {
19141
19234
  reviewConfigSelector = pickSelector("review", "review", "debate", "models", "execution", "project", "quality", "agent");
19142
- planConfigSelector = pickSelector("plan", "plan", "debate", "agent", "project");
19143
- decomposeConfigSelector = pickSelector("decompose", "plan", "agent");
19235
+ planConfigSelector = pickSelector("plan", "plan", "debate", "agent", "project", "routing");
19236
+ decomposeConfigSelector = pickSelector("decompose", "plan", "agent", "routing");
19144
19237
  rectifyConfigSelector = pickSelector("rectify", "execution");
19145
19238
  acceptanceConfigSelector = pickSelector("acceptance", "acceptance");
19146
19239
  acceptanceFixConfigSelector = pickSelector("acceptance-fix", "acceptance", "execution");
@@ -19452,6 +19545,7 @@ __export(exports_config, {
19452
19545
  acceptanceFixConfigSelector: () => acceptanceFixConfigSelector,
19453
19546
  acceptanceConfigSelector: () => acceptanceConfigSelector,
19454
19547
  VALID_TEST_STRATEGIES: () => VALID_TEST_STRATEGIES,
19548
+ TierConfigSchema: () => TierConfigSchema,
19455
19549
  TddConfigSchema: () => TddConfigSchema,
19456
19550
  THREE_SESSION_STRATEGIES: () => THREE_SESSION_STRATEGIES,
19457
19551
  TEST_STRATEGY_GUIDE: () => TEST_STRATEGY_GUIDE,
@@ -19467,12 +19561,15 @@ __export(exports_config, {
19467
19561
  DEFAULT_CONFIG: () => DEFAULT_CONFIG,
19468
19562
  ConfiguredModelSchema: () => ConfiguredModelSchema,
19469
19563
  COMPLEXITY_GUIDE: () => COMPLEXITY_GUIDE,
19564
+ AgentRoutingProfileSchema: () => AgentRoutingProfileSchema,
19565
+ AgentRoutingConfigSchema: () => AgentRoutingConfigSchema,
19470
19566
  AcceptanceConfigSchema: () => AcceptanceConfigSchema,
19471
19567
  AC_QUALITY_RULES: () => AC_QUALITY_RULES
19472
19568
  });
19473
19569
  var init_config = __esm(() => {
19474
19570
  init_schema();
19475
19571
  init_schemas_model();
19572
+ init_schemas_infra();
19476
19573
  init_schemas_debate();
19477
19574
  init_schemas_execution();
19478
19575
  init_loader();
@@ -22155,6 +22252,34 @@ function resolveDefaultAgent(config2) {
22155
22252
  }
22156
22253
  var FALLBACK_DEFAULT_AGENT = "claude";
22157
22254
 
22255
+ // src/agents/shared/agent-profile-resolver.ts
22256
+ function resolveAgentAssignment(selectedProfileId, agentRouting, storyId) {
22257
+ if (agentRouting?.enabled !== true)
22258
+ return null;
22259
+ const profiles = agentRouting.profiles ?? [];
22260
+ if (profiles.length === 0)
22261
+ return null;
22262
+ const defaultProfile = agentRouting.default ? profiles.find((p) => p.id === agentRouting.default) : undefined;
22263
+ if (selectedProfileId) {
22264
+ const profile = profiles.find((p) => p.id === selectedProfileId);
22265
+ if (profile)
22266
+ return toAssignment(profile);
22267
+ getSafeLogger()?.warn("routing", `Story ${storyId} selected unknown agent profile "${selectedProfileId}" \u2014 falling back to ${defaultProfile ? `default profile "${defaultProfile.id}"` : "no profile"}`, { storyId, agentProfileId: selectedProfileId });
22268
+ }
22269
+ return defaultProfile ? toAssignment(defaultProfile) : null;
22270
+ }
22271
+ function toAssignment(p) {
22272
+ return { agent: p.target.agent, agentProfileId: p.id, profileModelTier: p.target.model };
22273
+ }
22274
+ var init_agent_profile_resolver = __esm(() => {
22275
+ init_logger2();
22276
+ });
22277
+
22278
+ // src/agents/shared/index.ts
22279
+ var init_shared = __esm(() => {
22280
+ init_agent_profile_resolver();
22281
+ });
22282
+
22158
22283
  // src/agents/retry/types.ts
22159
22284
  var ParseValidationError;
22160
22285
  var init_types4 = __esm(() => {
@@ -22401,6 +22526,7 @@ var init_agents = __esm(() => {
22401
22526
  init_cost();
22402
22527
  init_version_detection();
22403
22528
  init_manager();
22529
+ init_shared();
22404
22530
  init_retry();
22405
22531
  });
22406
22532
 
@@ -28093,7 +28219,8 @@ function validateStory(raw, index, allIds) {
28093
28219
  complexity,
28094
28220
  testStrategy,
28095
28221
  reasoning: typeof routing.reasoning === "string" && routing.reasoning.trim().length > 0 ? routing.reasoning.trim() : "validated from LLM output",
28096
- ...noTestJustification !== undefined ? { noTestJustification } : {}
28222
+ ...noTestJustification !== undefined ? { noTestJustification } : {},
28223
+ ...typeof routing.agentProfileId === "string" && routing.agentProfileId.trim().length > 0 ? { agentProfileId: routing.agentProfileId.trim() } : {}
28097
28224
  },
28098
28225
  ...workdir !== undefined ? { workdir } : {},
28099
28226
  ...contextFiles.length > 0 ? { contextFiles } : {},
@@ -29887,6 +30014,73 @@ var init_builder = __esm(() => {
29887
30014
  };
29888
30015
  });
29889
30016
 
30017
+ // src/context/greenfield.ts
30018
+ async function gitLsFiles2(workdir) {
30019
+ try {
30020
+ const proc = _greenfieldDeps.spawn(["git", "ls-files"], {
30021
+ cwd: workdir,
30022
+ stdout: "pipe",
30023
+ stderr: "pipe"
30024
+ });
30025
+ const exitCode = await proc.exited;
30026
+ if (exitCode !== 0)
30027
+ return null;
30028
+ const output = await new Response(proc.stdout).text();
30029
+ return output.split(`
30030
+ `).filter(Boolean);
30031
+ } catch {
30032
+ return null;
30033
+ }
30034
+ }
30035
+ async function hasTestFiles(workdir, patterns) {
30036
+ const files = await gitLsFiles2(workdir);
30037
+ if (files !== null) {
30038
+ return files.some((f) => isTestFileByPatterns(f, patterns));
30039
+ }
30040
+ for (const pattern of patterns) {
30041
+ const g = new Bun.Glob(pattern);
30042
+ for await (const path3 of g.scan({ cwd: workdir, onlyFiles: true })) {
30043
+ if (!path3.split("/").some((seg) => IGNORE_DIRS.has(seg))) {
30044
+ return true;
30045
+ }
30046
+ }
30047
+ }
30048
+ return false;
30049
+ }
30050
+ async function isGreenfieldStory(_story, workdir, patterns) {
30051
+ try {
30052
+ return !await hasTestFiles(workdir, patterns ?? DEFAULT_TEST_FILE_PATTERNS);
30053
+ } catch {
30054
+ return false;
30055
+ }
30056
+ }
30057
+ var _greenfieldDeps, IGNORE_DIRS;
30058
+ var init_greenfield = __esm(() => {
30059
+ init_test_runners();
30060
+ _greenfieldDeps = {
30061
+ spawn: Bun.spawn
30062
+ };
30063
+ IGNORE_DIRS = new Set([
30064
+ "node_modules",
30065
+ "dist",
30066
+ ".next",
30067
+ ".nuxt",
30068
+ ".cache",
30069
+ "coverage",
30070
+ "vendor",
30071
+ "__pycache__",
30072
+ ".venv",
30073
+ "venv",
30074
+ ".eggs",
30075
+ "target",
30076
+ ".gradle",
30077
+ "out",
30078
+ "tmp",
30079
+ "temp",
30080
+ ".git"
30081
+ ]);
30082
+ });
30083
+
29890
30084
  // src/context/index.ts
29891
30085
  var init_context = __esm(() => {
29892
30086
  init_feature_resolver();
@@ -29896,6 +30090,7 @@ var init_context = __esm(() => {
29896
30090
  init_engine();
29897
30091
  init_test_scanner();
29898
30092
  init_auto_detect();
30093
+ init_greenfield();
29899
30094
  });
29900
30095
 
29901
30096
  // src/prompts/core/section-accumulator.ts
@@ -34527,8 +34722,10 @@ var init_plan = __esm(() => {
34527
34722
  truncated: () => PlanPromptBuilder.jsonRepair(0, "JSON appears truncated \u2014 please rewrite completely")
34528
34723
  }
34529
34724
  }),
34530
- build(input, _ctx) {
34531
- const { taskContext, outputFormat } = new PlanPromptBuilder().build(input.specContent, input.codebaseContext, input.outputPath, input.packages, input.packageDetails, input.projectProfile);
34725
+ build(input, ctx) {
34726
+ const agentRouting = ctx.config.routing?.agents;
34727
+ const profiles = agentRouting?.enabled === true ? agentRouting.profiles ?? [] : [];
34728
+ const { taskContext, outputFormat } = new PlanPromptBuilder().build(input.specContent, input.codebaseContext, input.outputPath, input.packages, input.packageDetails, input.projectProfile, undefined, profiles);
34532
34729
  return {
34533
34730
  role: { id: "role", content: "", overridable: false },
34534
34731
  task: { id: "task", content: `${taskContext}
@@ -34762,8 +34959,10 @@ var init_plan_refine = __esm(() => {
34762
34959
  }
34763
34960
  }),
34764
34961
  fileOutput: (input) => input.outputPath,
34765
- build(input, _ctx) {
34766
- const { taskContext, outputFormat } = new PlanPromptBuilder().build(input.specContent, input.codebaseContext, input.outputPath, input.packages, input.packageDetails, input.projectProfile);
34962
+ build(input, ctx) {
34963
+ const agentRouting = ctx.config.routing?.agents;
34964
+ const profiles = agentRouting?.enabled === true ? agentRouting.profiles ?? [] : [];
34965
+ const { taskContext, outputFormat } = new PlanPromptBuilder().build(input.specContent, input.codebaseContext, input.outputPath, input.packages, input.packageDetails, input.projectProfile, undefined, profiles);
34767
34966
  return {
34768
34967
  role: { id: "role", content: "", overridable: false },
34769
34968
  task: {
@@ -34834,36 +35033,40 @@ ${outputFormat}`,
34834
35033
 
34835
35034
  // src/agents/shared/decompose.ts
34836
35035
  function parseDecomposeOutput(output) {
34837
- const jsonMatch = output.match(/```(?:json)?\s*(\[[\s\S]*?\])\s*```/);
34838
- let jsonText = jsonMatch ? jsonMatch[1] : output;
34839
- if (!jsonMatch) {
34840
- const arrayMatch = output.match(/\[[\s\S]*\]/);
34841
- if (arrayMatch) {
34842
- jsonText = arrayMatch[0];
34843
- }
34844
- }
34845
35036
  let parsed;
34846
35037
  try {
34847
- parsed = JSON.parse(jsonText.trim());
35038
+ parsed = parseLLMJson(output);
34848
35039
  } catch (error48) {
34849
- throw new Error(`Failed to parse decompose output as JSON: ${error48.message}
34850
-
34851
- Output:
34852
- ${output.slice(0, 500)}`);
35040
+ throw new NaxError("Failed to parse decompose output as JSON", "DECOMPOSE_PARSE_FAILED", {
35041
+ stage: "decompose",
35042
+ outputSnippet: output.slice(0, 500),
35043
+ cause: error48
35044
+ });
34853
35045
  }
34854
35046
  if (!Array.isArray(parsed)) {
34855
- throw new Error("Decompose output is not an array");
35047
+ throw new NaxError("Decompose output is not an array", "DECOMPOSE_PARSE_FAILED", {
35048
+ stage: "decompose"
35049
+ });
34856
35050
  }
34857
35051
  const stories = parsed.map((item, index) => {
34858
35052
  if (typeof item !== "object" || item === null) {
34859
- throw new Error(`Story at index ${index} is not an object`);
35053
+ throw new NaxError(`Story at index ${index} is not an object`, "DECOMPOSE_PARSE_FAILED", {
35054
+ stage: "decompose",
35055
+ index
35056
+ });
34860
35057
  }
34861
35058
  const record2 = item;
34862
35059
  if (!record2.id || typeof record2.id !== "string") {
34863
- throw new Error(`Story at index ${index} missing valid 'id' field`);
35060
+ throw new NaxError(`Story at index ${index} missing valid 'id' field`, "DECOMPOSE_PARSE_FAILED", {
35061
+ stage: "decompose",
35062
+ index
35063
+ });
34864
35064
  }
34865
35065
  if (!record2.title || typeof record2.title !== "string") {
34866
- throw new Error(`Story ${record2.id} missing valid 'title' field`);
35066
+ throw new NaxError(`Story ${record2.id} missing valid 'title' field`, "DECOMPOSE_PARSE_FAILED", {
35067
+ stage: "decompose",
35068
+ storyId: record2.id
35069
+ });
34867
35070
  }
34868
35071
  return {
34869
35072
  id: record2.id,
@@ -34878,11 +35081,14 @@ ${output.slice(0, 500)}`);
34878
35081
  reasoning: String(record2.reasoning || "No reasoning provided"),
34879
35082
  estimatedLOC: Number(record2.estimatedLOC) || 0,
34880
35083
  risks: Array.isArray(record2.risks) ? record2.risks : [],
34881
- testStrategy: resolveTestStrategy(typeof record2.testStrategy === "string" ? record2.testStrategy : undefined)
35084
+ testStrategy: resolveTestStrategy(typeof record2.testStrategy === "string" ? record2.testStrategy : undefined),
35085
+ agentProfileId: typeof record2.agentProfileId === "string" && record2.agentProfileId.length > 0 ? record2.agentProfileId : undefined
34882
35086
  };
34883
35087
  });
34884
35088
  if (stories.length === 0) {
34885
- throw new Error("Decompose returned empty story array");
35089
+ throw new NaxError("Decompose returned empty story array", "DECOMPOSE_PARSE_FAILED", {
35090
+ stage: "decompose"
35091
+ });
34886
35092
  }
34887
35093
  return stories;
34888
35094
  }
@@ -34893,7 +35099,8 @@ function coerceComplexity(value) {
34893
35099
  return "medium";
34894
35100
  }
34895
35101
  var init_decompose = __esm(() => {
34896
- init_test_strategy();
35102
+ init_config();
35103
+ init_errors();
34897
35104
  });
34898
35105
 
34899
35106
  // src/agents/shared/decompose-prompt.ts
@@ -34932,10 +35139,10 @@ function buildPlanModePromptSync(input) {
34932
35139
  `);
34933
35140
  builder = builder.inputData("Sibling Stories", siblingsSummary);
34934
35141
  }
34935
- return builder.jsonSchema(DECOMPOSE_PLAN_SCHEMA).build();
35142
+ return builder.agentProfiles(input.profiles ?? []).jsonSchema(DECOMPOSE_PLAN_SCHEMA).build();
34936
35143
  }
34937
35144
  function buildSpecModePromptSync(input) {
34938
- return OneShotPromptBuilder.for("decomposer").instructions(SPEC_DECOMPOSE_INSTRUCTIONS).inputData("Codebase Context", input.codebaseContext).inputData("Feature Specification", input.specContent).jsonSchema(DECOMPOSE_SPEC_SCHEMA).build();
35145
+ return OneShotPromptBuilder.for("decomposer").instructions(SPEC_DECOMPOSE_INSTRUCTIONS).inputData("Codebase Context", input.codebaseContext).inputData("Feature Specification", input.specContent).agentProfiles(input.profiles ?? []).jsonSchema(DECOMPOSE_SPEC_SCHEMA).build();
34939
35146
  }
34940
35147
  async function buildPlanModePrompt(options) {
34941
35148
  const targetStory = options.targetStory;
@@ -34948,10 +35155,10 @@ async function buildPlanModePrompt(options) {
34948
35155
  `);
34949
35156
  builder = builder.inputData("Sibling Stories", siblingsSummary);
34950
35157
  }
34951
- return builder.jsonSchema(DECOMPOSE_PLAN_SCHEMA).build();
35158
+ return builder.agentProfiles(options.profiles ?? []).jsonSchema(DECOMPOSE_PLAN_SCHEMA).build();
34952
35159
  }
34953
35160
  async function buildSpecModePrompt(options) {
34954
- return OneShotPromptBuilder.for("decomposer").instructions(SPEC_DECOMPOSE_INSTRUCTIONS).inputData("Codebase Context", options.codebaseContext).inputData("Feature Specification", options.specContent).jsonSchema(DECOMPOSE_SPEC_SCHEMA).build();
35161
+ return OneShotPromptBuilder.for("decomposer").instructions(SPEC_DECOMPOSE_INSTRUCTIONS).inputData("Codebase Context", options.codebaseContext).inputData("Feature Specification", options.specContent).agentProfiles(options.profiles ?? []).jsonSchema(DECOMPOSE_SPEC_SCHEMA).build();
34955
35162
  }
34956
35163
  var DECOMPOSE_SPEC_SCHEMA, DECOMPOSE_PLAN_SCHEMA, SPEC_DECOMPOSE_INSTRUCTIONS;
34957
35164
  var init_decompose_prompt = __esm(() => {
@@ -34973,7 +35180,8 @@ var init_decompose_prompt = __esm(() => {
34973
35180
  reasoning: "Why this complexity level",
34974
35181
  estimatedLOC: 150,
34975
35182
  risks: ["Risk 1"],
34976
- testStrategy: "test-after"
35183
+ testStrategy: "test-after",
35184
+ agentProfileId: ""
34977
35185
  }
34978
35186
  ]
34979
35187
  };
@@ -34993,7 +35201,8 @@ var init_decompose_prompt = __esm(() => {
34993
35201
  reasoning: "Why this complexity",
34994
35202
  estimatedLOC: 0,
34995
35203
  risks: [],
34996
- testStrategy: "no-test | tdd-simple | three-session-tdd-lite | three-session-tdd | test-after"
35204
+ testStrategy: "no-test | tdd-simple | three-session-tdd-lite | three-session-tdd | test-after",
35205
+ agentProfileId: ""
34997
35206
  }
34998
35207
  ]
34999
35208
  };
@@ -35013,6 +35222,7 @@ For each story, provide:
35013
35222
  11. risks: Array of implementation risks
35014
35223
  12. testStrategy: "no-test" | "test-after" | "tdd-simple" | "three-session-tdd" | "three-session-tdd-lite"
35015
35224
  13. noTestJustification: string (REQUIRED when testStrategy is "no-test" \u2014 explain why tests are unnecessary)
35225
+ 14. agentProfileId: (optional) profile id from the Agent Profiles table \u2014 assign the best-matching profile for each story; omit if no profiles are listed or none fits well
35016
35226
 
35017
35227
  ${COMPLEXITY_GUIDE}
35018
35228
 
@@ -35033,6 +35243,7 @@ var init_decompose2 = __esm(() => {
35033
35243
  init_decompose();
35034
35244
  init_decompose_prompt();
35035
35245
  init_config();
35246
+ init_logger2();
35036
35247
  decomposeOp = {
35037
35248
  kind: "complete",
35038
35249
  name: "decompose",
@@ -35041,13 +35252,16 @@ var init_decompose2 = __esm(() => {
35041
35252
  config: decomposeConfigSelector,
35042
35253
  model: (_input, ctx) => ctx.config.plan.model,
35043
35254
  timeoutMs: (_input, ctx) => (ctx.config.plan.decomposeTimeoutSeconds ?? ctx.config.plan.timeoutSeconds ?? 600) * 1000,
35044
- build(input, _ctx) {
35255
+ build(input, ctx) {
35256
+ const agentRouting = ctx.config.routing?.agents;
35257
+ const profiles = agentRouting?.enabled === true ? agentRouting.profiles ?? [] : [];
35045
35258
  const prompt = buildDecomposePromptSync({
35046
35259
  specContent: input.specContent,
35047
35260
  codebaseContext: input.codebaseContext,
35048
35261
  targetStory: input.targetStory,
35049
35262
  siblings: input.siblings,
35050
- maxAcCount: input.maxAcCount
35263
+ maxAcCount: input.maxAcCount,
35264
+ profiles
35051
35265
  });
35052
35266
  return {
35053
35267
  role: { id: "role", content: "", overridable: false },
@@ -35471,6 +35685,7 @@ __export(exports_routing, {
35471
35685
  resolveRouting: () => resolveRouting,
35472
35686
  determineTestStrategy: () => determineTestStrategy,
35473
35687
  complexityToModelTier: () => complexityToModelTier,
35688
+ clearCache: () => clearCache,
35474
35689
  classifyComplexity: () => classifyComplexity,
35475
35690
  _tryLlmBatchRouteDeps: () => _tryLlmBatchRouteDeps,
35476
35691
  ROUTING_INSTRUCTIONS: () => ROUTING_INSTRUCTIONS
@@ -35919,7 +36134,7 @@ var init_acceptance_generate = __esm(() => {
35919
36134
  stage: "acceptance",
35920
36135
  session: { role: "acceptance-gen", lifetime: "fresh" },
35921
36136
  config: acceptanceGenConfigSelector,
35922
- model: (_input, ctx) => ctx.config.acceptance.model,
36137
+ model: (_input, ctx) => ctx.config.acceptance.generateModel ?? ctx.config.acceptance.model,
35923
36138
  timeoutMs: (_input, ctx) => ctx.config.execution.sessionTimeoutSeconds * 1000,
35924
36139
  build(input, _ctx) {
35925
36140
  const prompt = new AcceptancePromptBuilder().buildGeneratorFromPRDPrompt({
@@ -36023,6 +36238,7 @@ var init_refinement = () => {};
36023
36238
  var acceptanceRefineOp;
36024
36239
  var init_acceptance_refine = __esm(() => {
36025
36240
  init_refinement();
36241
+ init_retry();
36026
36242
  init_config();
36027
36243
  init_logger2();
36028
36244
  init_prompts();
@@ -36032,7 +36248,8 @@ var init_acceptance_refine = __esm(() => {
36032
36248
  stage: "acceptance",
36033
36249
  jsonMode: true,
36034
36250
  config: acceptanceConfigSelector,
36035
- model: (_input, ctx) => ctx.config.acceptance.model,
36251
+ retry: { preset: "transient-network", maxAttempts: 2, baseDelayMs: 0 },
36252
+ model: (_input, ctx) => ctx.config.acceptance.generateModel ?? ctx.config.acceptance.model,
36036
36253
  timeoutMs: (_input, ctx) => ctx.config.acceptance.timeoutMs,
36037
36254
  build(input, _ctx) {
36038
36255
  const prompt = new AcceptancePromptBuilder().buildRefinementPrompt(input.criteria, input.codebaseContext, {
@@ -36047,8 +36264,11 @@ var init_acceptance_refine = __esm(() => {
36047
36264
  };
36048
36265
  },
36049
36266
  parse(output, input, _ctx) {
36267
+ if (!output || !output.trim()) {
36268
+ throw new ParseValidationError("acceptance-refine: empty output");
36269
+ }
36050
36270
  if (refinementWouldFallback(output)) {
36051
- getSafeLogger()?.warn("acceptance", "AC refinement returned no usable JSON \u2014 falling back to unrefined criteria", { storyId: input.storyId, criteriaCount: input.criteria.length, responseBytes: output?.length ?? 0 });
36271
+ getSafeLogger()?.warn("acceptance", "AC refinement returned no usable JSON \u2014 falling back to unrefined criteria", { storyId: input.storyId, criteriaCount: input.criteria.length, responseBytes: output.length });
36052
36272
  }
36053
36273
  const items = parseRefinementResponse(output, input.criteria);
36054
36274
  return items.map((item) => ({ ...item, storyId: item.storyId || input.storyId }));
@@ -38362,8 +38582,10 @@ var init_plan_draft = __esm(() => {
38362
38582
  model: (_input, ctx) => ctx.config.plan?.model ?? "fast",
38363
38583
  timeoutMs: (_input, ctx) => (ctx.config.plan?.timeoutSeconds ?? 600) * 1000,
38364
38584
  retry: (input) => createDraftRetryStrategy(input.citationThreshold),
38365
- build(input, _ctx) {
38366
- return new PlanPromptBuilder().buildDraft(input);
38585
+ build(input, ctx) {
38586
+ const agentRouting = ctx.config.routing?.agents;
38587
+ const profiles = agentRouting?.enabled === true ? agentRouting.profiles ?? [] : [];
38588
+ return new PlanPromptBuilder().buildDraft({ ...input, profiles });
38367
38589
  },
38368
38590
  parse(output, input, _ctx) {
38369
38591
  return parsePlanDraft(output, input);
@@ -38442,73 +38664,6 @@ var init_plan_critic_llm = __esm(() => {
38442
38664
  };
38443
38665
  });
38444
38666
 
38445
- // src/context/greenfield.ts
38446
- async function gitLsFiles2(workdir) {
38447
- try {
38448
- const proc = _greenfieldDeps.spawn(["git", "ls-files"], {
38449
- cwd: workdir,
38450
- stdout: "pipe",
38451
- stderr: "pipe"
38452
- });
38453
- const exitCode = await proc.exited;
38454
- if (exitCode !== 0)
38455
- return null;
38456
- const output = await new Response(proc.stdout).text();
38457
- return output.split(`
38458
- `).filter(Boolean);
38459
- } catch {
38460
- return null;
38461
- }
38462
- }
38463
- async function hasTestFiles(workdir, patterns) {
38464
- const files = await gitLsFiles2(workdir);
38465
- if (files !== null) {
38466
- return files.some((f) => isTestFileByPatterns(f, patterns));
38467
- }
38468
- for (const pattern of patterns) {
38469
- const g = new Bun.Glob(pattern);
38470
- for await (const path5 of g.scan({ cwd: workdir, onlyFiles: true })) {
38471
- if (!path5.split("/").some((seg) => IGNORE_DIRS.has(seg))) {
38472
- return true;
38473
- }
38474
- }
38475
- }
38476
- return false;
38477
- }
38478
- async function isGreenfieldStory(_story, workdir, patterns) {
38479
- try {
38480
- return !await hasTestFiles(workdir, patterns ?? DEFAULT_TEST_FILE_PATTERNS);
38481
- } catch {
38482
- return false;
38483
- }
38484
- }
38485
- var _greenfieldDeps, IGNORE_DIRS;
38486
- var init_greenfield = __esm(() => {
38487
- init_test_runners();
38488
- _greenfieldDeps = {
38489
- spawn: Bun.spawn
38490
- };
38491
- IGNORE_DIRS = new Set([
38492
- "node_modules",
38493
- "dist",
38494
- ".next",
38495
- ".nuxt",
38496
- ".cache",
38497
- "coverage",
38498
- "vendor",
38499
- "__pycache__",
38500
- ".venv",
38501
- "venv",
38502
- ".eggs",
38503
- "target",
38504
- ".gradle",
38505
- "out",
38506
- "tmp",
38507
- "temp",
38508
- ".git"
38509
- ]);
38510
- });
38511
-
38512
38667
  // src/operations/greenfield-gate.ts
38513
38668
  var greenfieldGateConfigSelector, greenfieldGateOp;
38514
38669
  var init_greenfield_gate = __esm(() => {
@@ -38934,11 +39089,58 @@ var init_full_suite_gate = __esm(() => {
38934
39089
  };
38935
39090
  });
38936
39091
 
39092
+ // src/operations/full-suite-rectify-op.ts
39093
+ var fullSuiteRectifyOp;
39094
+ var init_full_suite_rectify_op = __esm(() => {
39095
+ init_config();
39096
+ init_prompts();
39097
+ init_test_edit_declaration();
39098
+ fullSuiteRectifyOp = {
39099
+ kind: "run",
39100
+ name: "full-suite-rectify",
39101
+ stage: "rectification",
39102
+ session: { role: "implementer", lifetime: "warm" },
39103
+ config: autofixConfigSelector,
39104
+ build(input, _ctx) {
39105
+ const prompt = RectifierPromptBuilder.failingTestRectification(input.findings, input.story);
39106
+ return {
39107
+ role: { id: "role", content: "", overridable: false },
39108
+ task: { id: "task", content: prompt, overridable: false }
39109
+ };
39110
+ },
39111
+ parse(output, _input, _ctx) {
39112
+ const declarations = parseTestEditDeclarations(output);
39113
+ return { applied: true, testEditDeclarations: declarations };
39114
+ }
39115
+ };
39116
+ });
39117
+
38937
39118
  // src/operations/full-suite-rectify.ts
38938
- function makeFullSuiteRectifyStrategy(story, config2) {
39119
+ function makeFullSuiteRectifyStrategy(story, config2, sink) {
39120
+ const appliesTo = (finding) => finding.source === "test-runner" && (finding.category === "failed-test" || finding.category === "execution-failed");
39121
+ if (sink) {
39122
+ return {
39123
+ name: "full-suite-rectify",
39124
+ appliesTo,
39125
+ fixOp: fullSuiteRectifyOp,
39126
+ buildInput: (findings) => ({ story, findings }),
39127
+ extractApplied: (output) => {
39128
+ for (const d of output.testEditDeclarations) {
39129
+ if (d.reason === "mock_structure" && d.files && d.files.length > 0) {
39130
+ sink.mockHandoffs.push({ files: d.files, reasonDetail: d.reasonDetail ?? "" });
39131
+ } else if (d.reason !== "mock_structure") {
39132
+ sink.testEdits.push(d);
39133
+ }
39134
+ }
39135
+ return { targetFiles: [], summary: "Fixed failing tests" };
39136
+ },
39137
+ maxAttempts: config2.execution.rectification.maxAttemptsPerStrategy,
39138
+ coRun: "exclusive"
39139
+ };
39140
+ }
38939
39141
  return {
38940
39142
  name: "full-suite-rectify",
38941
- appliesTo: (finding) => finding.source === "test-runner" && (finding.category === "failed-test" || finding.category === "execution-failed"),
39143
+ appliesTo,
38942
39144
  fixOp: implementerOp,
38943
39145
  buildInput: (findings) => ({
38944
39146
  story,
@@ -38951,6 +39153,7 @@ function makeFullSuiteRectifyStrategy(story, config2) {
38951
39153
  }
38952
39154
  var init_full_suite_rectify = __esm(() => {
38953
39155
  init_prompts();
39156
+ init_full_suite_rectify_op();
38954
39157
  init_implement();
38955
39158
  });
38956
39159
 
@@ -39078,7 +39281,8 @@ function applyTestEditDeclarations(findings, declarations, story, invalidMockStr
39078
39281
  const valid = validatePrdQuote(prdQuote, story);
39079
39282
  if (valid) {
39080
39283
  result = result.map((f) => {
39081
- if (f.file === d.file && f.fixTarget === "source") {
39284
+ const eligible = f.file === d.file && (f.fixTarget === "source" || f.fixTarget == null && f.source === "test-runner");
39285
+ if (eligible) {
39082
39286
  return {
39083
39287
  ...f,
39084
39288
  fixTarget: "test",
@@ -39987,6 +40191,7 @@ var init_operations = __esm(() => {
39987
40191
  init_greenfield_gate();
39988
40192
  init_full_suite_gate();
39989
40193
  init_full_suite_rectify();
40194
+ init_full_suite_rectify_op();
39990
40195
  init_autofix_implementer_strategy();
39991
40196
  init_autofix_test_writer_strategy();
39992
40197
  init_apply_test_edit_declarations();
@@ -42093,6 +42298,23 @@ ${adversarialErrors}
42093
42298
  Do NOT add new features \u2014 only fix valid issues.
42094
42299
  Commit your fixes when done.${scopeConstraint}${noTestIsolationBlock(story)}${escapeHatchFor(story)}`;
42095
42300
  }
42301
+ function formatFailingTestsList(findings) {
42302
+ if (findings.length === 0) {
42303
+ return "The full test suite has failing tests. Fix the implementation to make all tests pass.";
42304
+ }
42305
+ const lines = [`Fix the following ${findings.length} failing test${findings.length === 1 ? "" : "s"}:
42306
+ `];
42307
+ for (const f of findings) {
42308
+ const location = f.file ? `${f.file}` : "(unknown file)";
42309
+ const rule = f.rule ? ` Test: ${f.rule}
42310
+ ` : "";
42311
+ lines.push(`- ${location}
42312
+ ${rule} Error: ${f.message}
42313
+ `);
42314
+ }
42315
+ return lines.join(`
42316
+ `);
42317
+ }
42096
42318
  function mechanicalRectification(checks3, story, scopeConstraint, opts) {
42097
42319
  const errors3 = formatCheckErrors(checks3, opts);
42098
42320
  const scopeDirective = implementerOwnsTests(story) ? `Fix all errors listed above that are within this story's scope. ${SINGLE_SESSION_PERMIT_HEADLINE}` : `Fix all errors listed above that are within this story's scope \u2014 see the ${exceptionCountWord(story)} narrow exceptions appended below for sibling-story spillover. Do NOT change test files or test behavior except via those exceptions.`;
@@ -42777,22 +42999,23 @@ Before editing, break the work into one small fix per finding above (fix -> re-r
42777
42999
  `);
42778
43000
  }
42779
43001
  static failingTestContext(findings) {
42780
- if (findings.length === 0) {
42781
- return "The full test suite has failing tests. Fix the implementation to make all tests pass.";
42782
- }
42783
- const lines = [`Fix the following ${findings.length} failing test${findings.length === 1 ? "" : "s"}:
42784
- `];
42785
- for (const f of findings) {
42786
- const location = f.file ? `${f.file}` : "(unknown file)";
42787
- const rule = f.rule ? ` Test: ${f.rule}
42788
- ` : "";
42789
- lines.push(`- ${location}
42790
- ${rule} Error: ${f.message}
42791
- `);
42792
- }
42793
- lines.push(`
42794
- Fix the implementation (not the tests) to make all failing tests pass. Run the test suite to verify after each change.`);
42795
- return lines.join(`
43002
+ const listing = formatFailingTestsList(findings);
43003
+ if (findings.length === 0)
43004
+ return listing;
43005
+ return `${listing}
43006
+ Fix the implementation (not the tests) to make all failing tests pass. Run the test suite to verify after each change.`;
43007
+ }
43008
+ static failingTestRectification(findings, story) {
43009
+ const listing = formatFailingTestsList(findings);
43010
+ const exCount = exceptionCountWord(story);
43011
+ const prohibition = `Do NOT change test files or test behavior \u2014 see the ${exCount} narrow exceptions appended below.`;
43012
+ const parts = [listing];
43013
+ parts.push(`
43014
+ Fix the implementation (not the tests) to make all failing tests pass. Do not loosen assertions or weaken test expectations. Run the test suite to verify after each change.`);
43015
+ parts.push(`
43016
+ ${testEditHeadline(story, prohibition)}`);
43017
+ parts.push(escapeHatchFor(story));
43018
+ return parts.join(`
42796
43019
  `);
42797
43020
  }
42798
43021
  }
@@ -42879,9 +43102,59 @@ ${body}`
42879
43102
  this.acc.add(jsonSchemaSection(schema));
42880
43103
  return this;
42881
43104
  }
43105
+ agentProfiles(profiles) {
43106
+ const cards = OneShotPromptBuilder.agentCapabilityCards(profiles);
43107
+ if (cards.length === 0)
43108
+ return this;
43109
+ this.acc.add({
43110
+ id: "agent-profiles",
43111
+ overridable: false,
43112
+ content: `${cards}
43113
+
43114
+ ${OneShotPromptBuilder.agentProfileInstruction()}`
43115
+ });
43116
+ return this;
43117
+ }
42882
43118
  build() {
42883
43119
  return this.acc.join();
42884
43120
  }
43121
+ static agentProfileInstruction() {
43122
+ return [
43123
+ "When agent profiles are listed above, pick exactly ONE profile id per story and set it on the `agentProfileId` field. Apply these steps in order:",
43124
+ "1. Eliminate any profile whose weaknesses conflict with the story.",
43125
+ "2. Keep profiles whose strengths or affinity cover the story's main job (task type + primary domain).",
43126
+ "3. If more than one remains, choose the LOWEST cost profile.",
43127
+ "4. If none clearly fit, omit `agentProfileId` entirely \u2014 never invent a profile id."
43128
+ ].join(`
43129
+ `);
43130
+ }
43131
+ static agentCapabilityCards(profiles) {
43132
+ if (profiles.length === 0)
43133
+ return "";
43134
+ const header = [
43135
+ "## Agent Profiles",
43136
+ "",
43137
+ "| ID | Agent | Tier | Strengths | Weaknesses | Affinity | Cost |",
43138
+ "|---|---|---|---|---|---|---|"
43139
+ ];
43140
+ const rows = profiles.map((p) => {
43141
+ const esc2 = OneShotPromptBuilder.escapeCell;
43142
+ const id = esc2(p.id);
43143
+ const agent = esc2(p.target.agent);
43144
+ const model = esc2(p.target.model);
43145
+ const strengths = p.strengths.map(esc2).join(", ");
43146
+ const weaknesses = p.weaknesses?.length ? p.weaknesses.map(esc2).join("; ") : "\u2014";
43147
+ const affinityParts = [...p.affinity?.taskTypes ?? [], ...p.affinity?.domains ?? []];
43148
+ const affinity = affinityParts.length ? affinityParts.map(esc2).join(", ") : "\u2014";
43149
+ const cost = esc2(p.costTier ?? "\u2014");
43150
+ return `| ${id} | ${agent} | ${model} | ${strengths} | ${weaknesses} | ${affinity} | ${cost} |`;
43151
+ });
43152
+ return [...header, ...rows].join(`
43153
+ `);
43154
+ }
43155
+ static escapeCell(value) {
43156
+ return value.replace(/\|/g, "\\|").replace(/\r?\n/g, " ");
43157
+ }
42885
43158
  }
42886
43159
  var init_one_shot_builder = __esm(() => {
42887
43160
  init_core3();
@@ -43014,7 +43287,13 @@ For each one:
43014
43287
  Write the corrected PRD to this file path: ${outputFilePath}
43015
43288
  Do not output the PRD in chat. After writing the file, reply with a brief text confirmation only.`;
43016
43289
  }
43017
- build(specContent, codebaseContext, outputFilePath, packages, packageDetails, projectProfile, proposers) {
43290
+ build(specContent, codebaseContext, outputFilePath, packages, packageDetails, projectProfile, proposers, profiles) {
43291
+ const cards = OneShotPromptBuilder.agentCapabilityCards(profiles ?? []);
43292
+ const agentProfilesSection = cards.length > 0 ? `
43293
+
43294
+ ${cards}
43295
+
43296
+ ${OneShotPromptBuilder.agentProfileInstruction()}` : "";
43018
43297
  const isMonorepo = packages && packages.length > 0;
43019
43298
  const packageDetailsSection = packageDetails && packageDetails.length > 0 ? buildPackageDetailsSection(packageDetails) : "";
43020
43299
  const monorepoHint = isMonorepo ? `
@@ -43069,7 +43348,7 @@ ${buildSharedQualityRules(specContent, projectProfile)}
43069
43348
 
43070
43349
  For each story, set "contextFiles" to the key source files the agent should read before implementing (max 5 per story). Use your Step 2 analysis to identify the most relevant files. Leave empty for greenfield stories with no existing files to reference. Set "expectedFiles" to the NEW files the story creates.
43071
43350
 
43072
- ${CONTEXT_VS_EXPECTED_FILES_RULE}`;
43351
+ ${CONTEXT_VS_EXPECTED_FILES_RULE}${agentProfilesSection}`;
43073
43352
  const suggestedCriteriaField = specContent.trim() ? `
43074
43353
  "suggestedCriteria": ["string \u2014 optional. Behavioral edge cases or negative paths you identified that are NOT in the spec. Plain assertions only \u2014 observable outputs, return values, state changes, or error conditions. No implementation details or vague descriptions. Omit this field if empty."],` : "";
43075
43354
  const outputDirective = outputFilePath ? `Write the PRD JSON directly to this file path: ${outputFilePath}
@@ -43101,7 +43380,8 @@ Generate a JSON object with this exact structure (no markdown, no explanation \u
43101
43380
  "complexity": "simple | medium | complex | expert",
43102
43381
  "testStrategy": "no-test | tdd-simple | three-session-tdd-lite | three-session-tdd | test-after",
43103
43382
  "noTestJustification": "string \u2014 REQUIRED when testStrategy is no-test, explains why tests are unnecessary",
43104
- "reasoning": "string \u2014 brief classification rationale"
43383
+ "reasoning": "string \u2014 brief classification rationale"${cards.length > 0 ? `,
43384
+ "agentProfileId": "string \u2014 optional, the id of the best-matching profile from the Agent Profiles table above; omit if none fits"` : ""}
43105
43385
  },
43106
43386
  "escalations": [],
43107
43387
  "attempts": 0
@@ -43118,6 +43398,12 @@ ${outputDirective}`;
43118
43398
  content: "You are a senior software architect generating a product requirements document (PRD) as JSON. Your intent is to produce a thorough, evidence-grounded plan.",
43119
43399
  overridable: false
43120
43400
  };
43401
+ const cards = OneShotPromptBuilder.agentCapabilityCards(input.profiles ?? []);
43402
+ const agentProfilesSection = cards.length > 0 ? `
43403
+
43404
+ ${cards}
43405
+
43406
+ ${OneShotPromptBuilder.agentProfileInstruction()}` : "";
43121
43407
  const revisionSection = input.revisionFindings && input.revisionFindings.length > 0 ? `
43122
43408
 
43123
43409
  ## Previous draft rejected for the following issues
@@ -43167,7 +43453,7 @@ ${buildSharedQualityRules(input.specContent, input.projectProfile)}
43167
43453
 
43168
43454
  For each story, set "contextFiles" to the key source files the implementer should read before starting (max 5 per story). Cite manifest factIds where relevant. Set "expectedFiles" to the NEW files the story creates.
43169
43455
 
43170
- ${CONTEXT_VS_EXPECTED_FILES_RULE}
43456
+ ${CONTEXT_VS_EXPECTED_FILES_RULE}${agentProfilesSection}
43171
43457
 
43172
43458
  ## Output Schema
43173
43459
 
@@ -43190,7 +43476,8 @@ Produce a JSON object with this exact structure. Field names are mandatory \u201
43190
43476
  "routing": {
43191
43477
  "complexity": "simple | medium | complex | expert",
43192
43478
  "testStrategy": "no-test | tdd-simple | three-session-tdd-lite | three-session-tdd | test-after",
43193
- "reasoning": "string \u2014 brief classification rationale"
43479
+ "reasoning": "string \u2014 brief classification rationale"${cards.length > 0 ? `,
43480
+ "agentProfileId": "string \u2014 optional, the id of the best-matching profile from the Agent Profiles table above; omit if none fits"` : ""}
43194
43481
  }
43195
43482
  }
43196
43483
  ]
@@ -43230,6 +43517,7 @@ var CONTEXT_VS_EXPECTED_FILES_RULE = `**\`contextFiles\` rule \u2014 files reada
43230
43517
  **\`expectedFiles\` rule \u2014 files THIS story CREATES.** List every NEW file this story authors (relative paths). A file this story creates belongs here, NEVER in \`contextFiles\` \u2014 these are the story's outputs, not files to read first. A file created by an upstream dependency and only read/modified here belongs in \`contextFiles\`, NOT here (this story does not author it). A single path may appear in \`contextFiles\` (an existing sibling to mirror) AND \`expectedFiles\` (the new file itself), but the same path must never be in both.`, EXPECTED_FILES_SCHEMA_FIELD = `"expectedFiles": ["string \u2014 NEW files this story creates (relative paths, omit if none)"],`;
43231
43518
  var init_plan_builder = __esm(() => {
43232
43519
  init_config();
43520
+ init_one_shot_builder();
43233
43521
  });
43234
43522
 
43235
43523
  // src/prompts/builders/grounder-builder.ts
@@ -51567,7 +51855,7 @@ var init_precheck = __esm(() => {
51567
51855
  });
51568
51856
 
51569
51857
  // src/prd/decompose-mapper.ts
51570
- function mapDecomposedStoriesToUserStories(stories, parentStoryId, parentWorkdir) {
51858
+ function mapDecomposedStoriesToUserStories(stories, parentStoryId, parentWorkdir, parentRouting) {
51571
51859
  return stories.map((story, entryIndex) => {
51572
51860
  if (!story.id) {
51573
51861
  throw new NaxError(`Entry at index ${entryIndex} is missing required field: id`, "DECOMPOSE_VALIDATION_FAILED", {
@@ -51577,10 +51865,9 @@ function mapDecomposedStoriesToUserStories(stories, parentStoryId, parentWorkdir
51577
51865
  });
51578
51866
  }
51579
51867
  if (!story.contextFiles || story.contextFiles.length === 0) {
51580
- throw new NaxError(`Entry ${entryIndex} (${story.id}) has empty contextFiles`, "DECOMPOSE_VALIDATION_FAILED", {
51581
- stage: "decompose-mapper",
51582
- entryIndex,
51868
+ getSafeLogger()?.warn("decompose-mapper", `Entry ${entryIndex} (${story.id}) has empty contextFiles \u2014 continuing`, {
51583
51869
  storyId: story.id,
51870
+ entryIndex,
51584
51871
  parentStoryId
51585
51872
  });
51586
51873
  }
@@ -51602,13 +51889,26 @@ function mapDecomposedStoriesToUserStories(stories, parentStoryId, parentWorkdir
51602
51889
  complexity: story.complexity,
51603
51890
  testStrategy: story.testStrategy ?? "test-after",
51604
51891
  reasoning: story.reasoning,
51605
- modelTier: "balanced"
51892
+ modelTier: parentRouting?.profileModelTier ?? story.routing?.profileModelTier ?? "balanced",
51893
+ ...story.routing?.agent !== undefined && { agent: story.routing.agent },
51894
+ ...story.routing?.agentProfileId !== undefined && { agentProfileId: story.routing.agentProfileId },
51895
+ ...story.routing?.profileModelTier !== undefined && { profileModelTier: story.routing.profileModelTier },
51896
+ ...parentRouting?.agent !== undefined && { agent: parentRouting.agent },
51897
+ ...parentRouting?.agentProfileId !== undefined && { agentProfileId: parentRouting.agentProfileId },
51898
+ ...parentRouting?.profileModelTier !== undefined && { profileModelTier: parentRouting.profileModelTier },
51899
+ ...parentRouting?.agent !== undefined && {
51900
+ initialAgent: parentRouting.initialAgent ?? parentRouting.agent
51901
+ },
51902
+ ...parentRouting?.agentProfileId !== undefined && {
51903
+ initialProfileId: parentRouting.initialProfileId ?? parentRouting.agentProfileId
51904
+ }
51606
51905
  }
51607
51906
  };
51608
51907
  });
51609
51908
  }
51610
51909
  var init_decompose_mapper = __esm(() => {
51611
51910
  init_errors();
51911
+ init_logger2();
51612
51912
  });
51613
51913
 
51614
51914
  // src/cli/plan-decompose.ts
@@ -51650,8 +51950,12 @@ async function planDecomposeCommand(workdir, config2, options) {
51650
51950
  const rt = createPlanRuntime(config2, workdir, options.feature);
51651
51951
  const agentManager = rt.agentManager;
51652
51952
  const adapterForCapCheck = agentManager.getAgent(agentName);
51653
- if (!adapterForCapCheck)
51654
- throw new Error(`[decompose] No agent adapter found for '${agentName}'`);
51953
+ if (!adapterForCapCheck) {
51954
+ throw new NaxError(`No agent adapter found for '${agentName}'`, "AGENT_NOT_FOUND", {
51955
+ stage: "decompose",
51956
+ agentName
51957
+ });
51958
+ }
51655
51959
  const timeoutSeconds = config2?.plan?.timeoutSeconds ?? DEFAULT_TIMEOUT_SECONDS2;
51656
51960
  const maxAcCount = config2?.precheck?.storySizeGate?.maxAcCount ?? Number.POSITIVE_INFINITY;
51657
51961
  const maxReplanAttempts = config2?.precheck?.storySizeGate?.maxReplanAttempts ?? 3;
@@ -51663,6 +51967,7 @@ async function planDecomposeCommand(workdir, config2, options) {
51663
51967
  for (let attempt = 0;attempt < maxReplanAttempts; attempt++) {
51664
51968
  if (attempt === 0 && debateDecompEnabled) {
51665
51969
  const decomposeStageConfig = debateStages.decompose;
51970
+ const profilesForDebate = [];
51666
51971
  const prompt = await buildDecomposePromptAsync({
51667
51972
  specContent: "",
51668
51973
  codebaseContext,
@@ -51671,7 +51976,8 @@ async function planDecomposeCommand(workdir, config2, options) {
51671
51976
  siblings,
51672
51977
  featureName: options.feature,
51673
51978
  storyId: options.storyId,
51674
- maxAcCount: config2?.precheck?.storySizeGate?.maxAcCount
51979
+ maxAcCount: config2?.precheck?.storySizeGate?.maxAcCount,
51980
+ profiles: profilesForDebate
51675
51981
  });
51676
51982
  const decompCallCtx = {
51677
51983
  runtime: rt,
@@ -51736,7 +52042,7 @@ ${repairHint}` : codebaseContext;
51736
52042
  } finally {
51737
52043
  await rt.close().catch(() => {});
51738
52044
  }
51739
- const subStoriesWithParent = mapDecomposedStoriesToUserStories(decompStories, options.storyId, targetStory.workdir);
52045
+ const subStoriesWithParent = mapDecomposedStoriesToUserStories(decompStories, options.storyId, targetStory.workdir, targetStory.routing);
51740
52046
  const updatedStories = prd.userStories.map((s) => s.id === options.storyId ? { ...s, status: "decomposed" } : s);
51741
52047
  const originalIndex = updatedStories.findIndex((s) => s.id === options.storyId);
51742
52048
  const finalStories = [
@@ -51744,7 +52050,11 @@ ${repairHint}` : codebaseContext;
51744
52050
  ...subStoriesWithParent,
51745
52051
  ...updatedStories.slice(originalIndex + 1)
51746
52052
  ];
51747
- const updatedPrd = { ...prd, userStories: finalStories };
52053
+ const updatedPrd = {
52054
+ ...prd,
52055
+ userStories: finalStories,
52056
+ routingProfile: config2.profile ?? "default"
52057
+ };
51748
52058
  await _planDeps.writeFile(prdPath, JSON.stringify(updatedPrd, null, 2));
51749
52059
  return () => {};
51750
52060
  }
@@ -52681,31 +52991,23 @@ var init_semantic_verdict = __esm(() => {
52681
52991
  });
52682
52992
 
52683
52993
  // src/acceptance/hardening.ts
52684
- async function runHardeningPass(ctx) {
52994
+ import path10 from "path";
52995
+ async function processPackageGroup(ctx, packageDir, groupStories, language, result) {
52685
52996
  const logger = getSafeLogger();
52686
- const result = { promoted: [], discarded: [] };
52687
- const storiesWithSuggested = ctx.prd.userStories.filter((s) => s.suggestedCriteria && s.suggestedCriteria.length > 0);
52688
- if (storiesWithSuggested.length === 0)
52689
- return result;
52690
- logger?.info("acceptance", "Starting hardening pass", {
52691
- storyIds: storiesWithSuggested.map((s) => s.id),
52692
- storiesProcessed: storiesWithSuggested.length,
52693
- totalSuggestedACs: storiesWithSuggested.reduce((n, s) => n + (s.suggestedCriteria?.length ?? 0), 0)
52694
- });
52695
- try {
52696
- const allRefined = [];
52697
- for (const story of storiesWithSuggested) {
52698
- const criteria = story.suggestedCriteria ?? [];
52699
- const callCtx = {
52700
- runtime: ctx.runtime,
52701
- packageView: ctx.runtime.packages.resolve(ctx.workdir),
52702
- packageDir: ctx.workdir,
52703
- storyId: story.id,
52704
- featureName: ctx.prd.feature,
52705
- agentName: ctx.agentManager.getDefault()
52706
- };
52707
- const refined = await _hardeningDeps.callOp(callCtx, acceptanceRefineOp, {
52708
- criteria,
52997
+ const groupRefined = [];
52998
+ for (const story of groupStories) {
52999
+ const callCtx = {
53000
+ runtime: ctx.runtime,
53001
+ packageView: ctx.runtime.packages.resolve(packageDir),
53002
+ packageDir,
53003
+ storyId: story.id,
53004
+ featureName: ctx.prd.feature,
53005
+ agentName: ctx.agentManager.getDefault()
53006
+ };
53007
+ let refined;
53008
+ try {
53009
+ refined = await _hardeningDeps.callOp(callCtx, acceptanceRefineOp, {
53010
+ criteria: story.suggestedCriteria ?? [],
52709
53011
  codebaseContext: "",
52710
53012
  storyId: story.id,
52711
53013
  testStrategy: ctx.config.acceptance?.testStrategy,
@@ -52713,85 +53015,115 @@ async function runHardeningPass(ctx) {
52713
53015
  storyTitle: story.title,
52714
53016
  storyDescription: story.description
52715
53017
  });
52716
- allRefined.push(...refined);
53018
+ } catch {
53019
+ logger?.warn("acceptance", "AC refinement failed after retries \u2014 using unrefined criteria", {
53020
+ storyId: story.id
53021
+ });
53022
+ refined = (story.suggestedCriteria ?? []).map((c) => ({
53023
+ original: c,
53024
+ refined: c,
53025
+ testable: true,
53026
+ storyId: story.id
53027
+ }));
52717
53028
  }
52718
- const language = ctx.config.project?.language;
52719
- const suggestedTestPath = resolveSuggestedPackageFeatureTestPath(ctx.workdir, ctx.prd.feature, ctx.config.acceptance?.suggestedTestPath, language);
52720
- const criteriaList = allRefined.map((c, i) => `AC-${i + 1}: ${c.refined}`).join(`
53029
+ groupRefined.push(...refined);
53030
+ }
53031
+ const suggestedTestPath = resolveSuggestedPackageFeatureTestPath(packageDir, ctx.prd.feature, ctx.config.acceptance?.suggestedTestPath, language);
53032
+ const criteriaList = groupRefined.map((c, i) => `AC-${i + 1}: ${c.refined}`).join(`
52721
53033
  `);
52722
- const frameworkOverrideLine = ctx.config.acceptance?.testFramework ? `
53034
+ const frameworkOverrideLine = ctx.config.acceptance?.testFramework ? `
52723
53035
  [FRAMEWORK OVERRIDE: Use ${ctx.config.acceptance.testFramework} as the test framework regardless of what you detect.]` : "";
52724
- const genCallCtx = {
52725
- runtime: ctx.runtime,
52726
- packageView: ctx.runtime.packages.resolve(ctx.workdir),
52727
- packageDir: ctx.workdir,
52728
- storyId: storiesWithSuggested[0]?.id,
52729
- featureName: ctx.prd.feature,
52730
- agentName: ctx.agentManager.getDefault()
52731
- };
52732
- const genResult = await _hardeningDeps.callOp(genCallCtx, acceptanceGenerateOp, {
52733
- featureName: ctx.prd.feature,
52734
- criteriaList,
52735
- frameworkOverrideLine,
52736
- targetTestFilePath: suggestedTestPath
52737
- });
52738
- let testCode = genResult.testCode;
52739
- if (!testCode) {
52740
- const skeletonCriteria = allRefined.map((c, i) => ({
52741
- id: `AC-${i + 1}`,
52742
- text: c.refined,
52743
- lineNumber: i + 1
52744
- }));
52745
- testCode = generateSkeletonTests(ctx.prd.feature, skeletonCriteria, ctx.config.acceptance?.testFramework, language);
52746
- logger?.warn("acceptance", "Hardening generate op returned no test code \u2014 using skeleton", {
52747
- storyIds: storiesWithSuggested.map((s) => s.id),
52748
- storiesProcessed: storiesWithSuggested.length
52749
- });
52750
- }
52751
- await _hardeningDeps.writeFile(suggestedTestPath, testCode);
52752
- const testCmd = buildAcceptanceRunCommand(suggestedTestPath, ctx.config.project?.testFramework, ctx.config.acceptance?.command, ctx.workdir);
52753
- const proc = _hardeningDeps.spawn(testCmd, {
52754
- cwd: ctx.workdir,
52755
- stdout: "pipe",
52756
- stderr: "pipe"
53036
+ const genCallCtx = {
53037
+ runtime: ctx.runtime,
53038
+ packageView: ctx.runtime.packages.resolve(packageDir),
53039
+ packageDir,
53040
+ storyId: groupStories[0]?.id,
53041
+ featureName: ctx.prd.feature,
53042
+ agentName: ctx.agentManager.getDefault()
53043
+ };
53044
+ const genResult = await _hardeningDeps.callOp(genCallCtx, acceptanceGenerateOp, {
53045
+ featureName: ctx.prd.feature,
53046
+ criteriaList,
53047
+ frameworkOverrideLine,
53048
+ targetTestFilePath: suggestedTestPath
53049
+ });
53050
+ let testCode = genResult.testCode;
53051
+ if (!testCode) {
53052
+ const skeletonCriteria = groupRefined.map((c, i) => ({
53053
+ id: `AC-${i + 1}`,
53054
+ text: c.refined,
53055
+ lineNumber: i + 1
53056
+ }));
53057
+ testCode = generateSkeletonTests(ctx.prd.feature, skeletonCriteria, ctx.config.acceptance?.testFramework, language);
53058
+ logger?.warn("acceptance", "Hardening generate op returned no test code \u2014 using skeleton", {
53059
+ storyIds: groupStories.map((s) => s.id),
53060
+ storiesProcessed: groupStories.length
52757
53061
  });
52758
- const [exitCode, stdout, stderr] = await Promise.all([
52759
- proc.exited,
52760
- new Response(proc.stdout).text(),
52761
- new Response(proc.stderr).text()
52762
- ]);
52763
- const output = `${stdout}
53062
+ }
53063
+ await _hardeningDeps.writeFile(suggestedTestPath, testCode);
53064
+ const testCmd = buildAcceptanceRunCommand(suggestedTestPath, ctx.config.project?.testFramework, ctx.config.acceptance?.command, packageDir);
53065
+ const proc = _hardeningDeps.spawn(testCmd, { cwd: packageDir, stdout: "pipe", stderr: "pipe" });
53066
+ const [exitCode, stdout, stderr] = await Promise.all([
53067
+ proc.exited,
53068
+ new Response(proc.stdout).text(),
53069
+ new Response(proc.stderr).text()
53070
+ ]);
53071
+ const output = `${stdout}
52764
53072
  ${stderr}`;
52765
- const failedACs = parseTestFailures(output);
52766
- const failedSet = new Set(failedACs.map((ac) => ac.toUpperCase()));
52767
- const refinedByStory = new Map;
52768
- for (const r of allRefined) {
52769
- const list = refinedByStory.get(r.storyId) ?? [];
52770
- list.push(r);
52771
- refinedByStory.set(r.storyId, list);
52772
- }
52773
- let acIndex = 0;
52774
- for (const story of storiesWithSuggested) {
52775
- const storyRefined = refinedByStory.get(story.id) ?? [];
52776
- const toPromote = [];
52777
- const toDiscard = [];
52778
- for (const refinedCriterion of storyRefined) {
52779
- acIndex++;
52780
- const acId = `AC-${acIndex}`;
52781
- const nonTestable = refinedCriterion.testable === false;
52782
- if (nonTestable || failedSet.has(acId) || exitCode !== 0 && failedACs.length === 0) {
52783
- toDiscard.push(refinedCriterion.original);
52784
- } else {
52785
- toPromote.push(refinedCriterion.original);
52786
- }
52787
- }
52788
- if (toPromote.length > 0) {
52789
- const existingACs = new Set(story.acceptanceCriteria);
52790
- story.acceptanceCriteria = [...story.acceptanceCriteria, ...toPromote.filter((ac) => !existingACs.has(ac))];
52791
- result.promoted.push(...toPromote);
53073
+ const failedACs = parseTestFailures(output);
53074
+ const failedSet = new Set(failedACs.map((ac) => ac.toUpperCase()));
53075
+ const refinedByStory = new Map;
53076
+ for (const r of groupRefined) {
53077
+ const list = refinedByStory.get(r.storyId) ?? [];
53078
+ list.push(r);
53079
+ refinedByStory.set(r.storyId, list);
53080
+ }
53081
+ let acIndex = 0;
53082
+ for (const story of groupStories) {
53083
+ const storyRefined = refinedByStory.get(story.id) ?? [];
53084
+ const toPromote = [];
53085
+ const toDiscard = [];
53086
+ for (const refined of storyRefined) {
53087
+ acIndex++;
53088
+ const acId = `AC-${acIndex}`;
53089
+ if (refined.testable === false || failedSet.has(acId) || exitCode !== 0 && failedACs.length === 0) {
53090
+ toDiscard.push(refined.original);
53091
+ } else {
53092
+ toPromote.push(refined.original);
52792
53093
  }
52793
- result.discarded.push(...toDiscard);
52794
- story.suggestedCriteria = toDiscard.length > 0 ? toDiscard : undefined;
53094
+ }
53095
+ if (toPromote.length > 0) {
53096
+ const existingACs = new Set(story.acceptanceCriteria);
53097
+ story.acceptanceCriteria = [...story.acceptanceCriteria, ...toPromote.filter((ac) => !existingACs.has(ac))];
53098
+ result.promoted.push(...toPromote);
53099
+ }
53100
+ result.discarded.push(...toDiscard);
53101
+ story.suggestedCriteria = toDiscard.length > 0 ? toDiscard : undefined;
53102
+ }
53103
+ }
53104
+ async function runHardeningPass(ctx) {
53105
+ const logger = getSafeLogger();
53106
+ const result = { promoted: [], discarded: [] };
53107
+ const storiesWithSuggested = ctx.prd.userStories.filter((s) => s.suggestedCriteria && s.suggestedCriteria.length > 0);
53108
+ if (storiesWithSuggested.length === 0)
53109
+ return result;
53110
+ logger?.info("acceptance", "Starting hardening pass", {
53111
+ storyIds: storiesWithSuggested.map((s) => s.id),
53112
+ storiesProcessed: storiesWithSuggested.length,
53113
+ totalSuggestedACs: storiesWithSuggested.reduce((n, s) => n + (s.suggestedCriteria?.length ?? 0), 0)
53114
+ });
53115
+ try {
53116
+ const packageGroups = new Map;
53117
+ for (const story of storiesWithSuggested) {
53118
+ const wd = story.workdir ?? "";
53119
+ if (!packageGroups.has(wd))
53120
+ packageGroups.set(wd, []);
53121
+ packageGroups.get(wd)?.push(story);
53122
+ }
53123
+ for (const [wd, groupStories] of packageGroups.entries()) {
53124
+ const packageDir = wd ? path10.join(ctx.workdir, wd) : ctx.workdir;
53125
+ const detectedLang = await _hardeningDeps.detectLanguage(packageDir);
53126
+ await processPackageGroup(ctx, packageDir, groupStories, detectedLang ?? ctx.config.project?.language, result);
52795
53127
  }
52796
53128
  if (result.promoted.length > 0) {
52797
53129
  await _hardeningDeps.savePRD(ctx.prd, ctx.prdPath);
@@ -52816,6 +53148,7 @@ var init_hardening = __esm(() => {
52816
53148
  init_logger2();
52817
53149
  init_operations();
52818
53150
  init_prd();
53151
+ init_detector();
52819
53152
  init_ac_parser();
52820
53153
  init_generator();
52821
53154
  init_test_path();
@@ -52825,7 +53158,8 @@ var init_hardening = __esm(() => {
52825
53158
  spawn: Bun.spawn,
52826
53159
  writeFile: async (p, c) => {
52827
53160
  await Bun.write(p, c);
52828
- }
53161
+ },
53162
+ detectLanguage
52829
53163
  };
52830
53164
  });
52831
53165
 
@@ -52837,6 +53171,7 @@ __export(exports_acceptance, {
52837
53171
  resolveSuggestedTestFile: () => resolveSuggestedTestFile,
52838
53172
  resolveSuggestedPackageFeatureTestPath: () => resolveSuggestedPackageFeatureTestPath,
52839
53173
  resolveAcceptanceFeatureTestPath: () => resolveAcceptanceFeatureTestPath,
53174
+ refinementWouldFallback: () => refinementWouldFallback,
52840
53175
  parseRefinementResponse: () => parseRefinementResponse,
52841
53176
  parseAcceptanceCriteria: () => parseAcceptanceCriteria,
52842
53177
  parseACTextFromSpec: () => parseACTextFromSpec,
@@ -53079,7 +53414,7 @@ __export(exports_acceptance_setup, {
53079
53414
  acceptanceSetupStage: () => acceptanceSetupStage,
53080
53415
  _acceptanceSetupDeps: () => _acceptanceSetupDeps
53081
53416
  });
53082
- import path10 from "path";
53417
+ import path11 from "path";
53083
53418
  function computeACFingerprint(criteria) {
53084
53419
  const sorted = [...criteria].sort().join(`
53085
53420
  `);
@@ -53152,7 +53487,7 @@ var init_acceptance_setup = __esm(() => {
53152
53487
  },
53153
53488
  autoCommitIfDirty,
53154
53489
  loadGroupConfig: async (projectDir, relativeWorkdir) => {
53155
- return loadConfigForWorkdir(path10.join(projectDir, ".nax", "config.json"), relativeWorkdir || undefined);
53490
+ return loadConfigForWorkdir(path11.join(projectDir, ".nax", "config.json"), relativeWorkdir || undefined);
53156
53491
  },
53157
53492
  runTest: async (_testPath, _workdir, _cmd) => {
53158
53493
  const cmd = _cmd;
@@ -53196,7 +53531,7 @@ ${stderr}` };
53196
53531
  }
53197
53532
  const language = ctx.config.project?.language;
53198
53533
  const testPathConfig = ctx.config.acceptance.testPath;
53199
- const metaPath = path10.join(ctx.featureDir, "acceptance-meta.json");
53534
+ const metaPath = path11.join(ctx.featureDir, "acceptance-meta.json");
53200
53535
  const allCriteria = ctx.prd.userStories.filter((s) => !s.id.startsWith("US-FIX-") && s.status !== "decomposed").flatMap((s) => s.acceptanceCriteria);
53201
53536
  const featureName = ctx.prd.feature ?? ctx.prd.featureName;
53202
53537
  const groups = await groupStoriesByPackage(ctx.prd, ctx.workdir, featureName, testPathConfig, language);
@@ -53251,6 +53586,16 @@ ${stderr}` };
53251
53586
  storyDescription: story.description
53252
53587
  }, story.id).then((refined) => {
53253
53588
  results[i] = refined;
53589
+ }).catch(() => {
53590
+ getSafeLogger()?.warn("acceptance-setup", "AC refinement failed after retries \u2014 using unrefined criteria", {
53591
+ storyId: story.id
53592
+ });
53593
+ results[i] = story.acceptanceCriteria.map((c) => ({
53594
+ original: c,
53595
+ refined: c,
53596
+ testable: true,
53597
+ storyId: story.id
53598
+ }));
53254
53599
  }).finally(() => {
53255
53600
  executing.delete(task);
53256
53601
  });
@@ -53311,7 +53656,7 @@ ${stderr}` };
53311
53656
  testable: c.testable,
53312
53657
  storyId: c.storyId
53313
53658
  })), null, 2);
53314
- await _acceptanceSetupDeps.writeFile(path10.join(ctx.featureDir, "acceptance-refined.json"), refinedJsonContent);
53659
+ await _acceptanceSetupDeps.writeFile(path11.join(ctx.featureDir, "acceptance-refined.json"), refinedJsonContent);
53315
53660
  }
53316
53661
  const fingerprint2 = computeACFingerprint(allCriteria);
53317
53662
  await _acceptanceSetupDeps.writeMeta(metaPath, {
@@ -53325,7 +53670,7 @@ ${stderr}` };
53325
53670
  }
53326
53671
  const acceptanceTestPaths = [];
53327
53672
  for (const g of groups) {
53328
- const relativeWorkdir = path10.relative(ctx.projectDir, g.packageDir);
53673
+ const relativeWorkdir = path11.relative(ctx.projectDir, g.packageDir);
53329
53674
  let groupConfig = ctx.config;
53330
53675
  if (relativeWorkdir && relativeWorkdir !== ".") {
53331
53676
  try {
@@ -53894,7 +54239,7 @@ var init_story_context = __esm(() => {
53894
54239
 
53895
54240
  // src/execution/lock.ts
53896
54241
  import { unlink as unlink2 } from "fs/promises";
53897
- import path11 from "path";
54242
+ import path12 from "path";
53898
54243
  function getSafeLogger3() {
53899
54244
  try {
53900
54245
  return getLogger();
@@ -53911,7 +54256,7 @@ function isProcessAlive(pid) {
53911
54256
  }
53912
54257
  }
53913
54258
  async function acquireLock(workdir) {
53914
- const lockPath = path11.join(workdir, "nax.lock");
54259
+ const lockPath = path12.join(workdir, "nax.lock");
53915
54260
  const lockFile = Bun.file(lockPath);
53916
54261
  try {
53917
54262
  const exists = await lockFile.exists();
@@ -53963,7 +54308,7 @@ async function acquireLock(workdir) {
53963
54308
  }
53964
54309
  }
53965
54310
  async function releaseLock(workdir) {
53966
- const lockPath = path11.join(workdir, "nax.lock");
54311
+ const lockPath = path12.join(workdir, "nax.lock");
53967
54312
  try {
53968
54313
  await unlink2(lockPath);
53969
54314
  } catch (error48) {
@@ -55221,7 +55566,7 @@ async function buildPlanForStrategy(ctx, story, config2, testStrategy, inputs) {
55221
55566
  strategies.push(makeMechanicalFormatFixStrategy());
55222
55567
  }
55223
55568
  if (inputs.fullSuiteGate && (isThreeSession || regressionMode === "per-story")) {
55224
- strategies.push(makeFullSuiteRectifyStrategy(story, config2));
55569
+ strategies.push(makeFullSuiteRectifyStrategy(story, config2, sink));
55225
55570
  }
55226
55571
  if (config2.quality.autofix?.enabled !== false) {
55227
55572
  strategies.push(makeAutofixImplementerStrategy(story, config2, sink, {
@@ -55266,7 +55611,7 @@ async function buildPlanForStrategy(ctx, story, config2, testStrategy, inputs) {
55266
55611
  includeAdversarialReview: false
55267
55612
  }), makeAutofixTestWriterStrategy(story, config2, nbSink));
55268
55613
  }
55269
- nbStrategies.push(makeFullSuiteRectifyStrategy(story, config2));
55614
+ nbStrategies.push(makeFullSuiteRectifyStrategy(story, config2, nbSink));
55270
55615
  builder.addNonBlockingFix(nbf, nbStrategies);
55271
55616
  }
55272
55617
  return builder.build(ctx, { isThreeSession });
@@ -55523,6 +55868,16 @@ var init_plan_inputs = __esm(() => {
55523
55868
  });
55524
55869
 
55525
55870
  // src/pipeline/stages/execution-helpers.ts
55871
+ function resolveExecutionAgent(opts) {
55872
+ const { routedAgent, defaultAgent, getAgent } = opts;
55873
+ if (routedAgent !== undefined) {
55874
+ const routed = getAgent(routedAgent);
55875
+ if (routed)
55876
+ return { agentName: routedAgent, agent: routed, degraded: false };
55877
+ return { agentName: defaultAgent, agent: getAgent(defaultAgent), degraded: true };
55878
+ }
55879
+ return { agentName: defaultAgent, agent: getAgent(defaultAgent), degraded: false };
55880
+ }
55526
55881
  function routeTddFailure(failureCategory, isLiteMode, ctx, reviewReason, failureDetail) {
55527
55882
  const buildReason = (category) => {
55528
55883
  const trimmedDetail = failureDetail?.trim();
@@ -56021,6 +56376,7 @@ var init_execution = __esm(() => {
56021
56376
  init_logger2();
56022
56377
  init_git();
56023
56378
  init_execution_helpers();
56379
+ init_execution_helpers();
56024
56380
  RUNTIME_CRASH_CODES = new Set(["CALL_OP_NO_OUTPUT", "CALL_OP_MAX_RETRIES"]);
56025
56381
  executionStage = {
56026
56382
  name: "execution",
@@ -56028,9 +56384,21 @@ var init_execution = __esm(() => {
56028
56384
  async execute(ctx) {
56029
56385
  const logger = getLogger();
56030
56386
  const defaultAgent = ctx.agentManager?.getDefault() ?? "claude";
56031
- const agent = (ctx.agentGetFn ?? _executionDeps.getAgent)(defaultAgent);
56387
+ const resolved = resolveExecutionAgent({
56388
+ routedAgent: ctx.routing.agent,
56389
+ defaultAgent,
56390
+ getAgent: ctx.agentGetFn ?? _executionDeps.getAgent
56391
+ });
56392
+ if (resolved.degraded) {
56393
+ logger.warn("execution", "Routed agent unavailable \u2014 degrading to default agent", {
56394
+ storyId: ctx.story.id,
56395
+ routedAgent: ctx.routing.agent,
56396
+ defaultAgent
56397
+ });
56398
+ }
56399
+ const agent = resolved.agent;
56032
56400
  if (!agent)
56033
- return { action: "fail", reason: `Agent "${defaultAgent}" not found` };
56401
+ return { action: "fail", reason: `Agent "${resolved.agentName}" not found` };
56034
56402
  let effectiveTier = ctx.routing.modelTier;
56035
56403
  if (!_executionDeps.validateAgentForTier(agent, ctx.routing.modelTier)) {
56036
56404
  effectiveTier = agent.capabilities.supportedTiers[0] ?? ctx.routing.modelTier;
@@ -56054,7 +56422,7 @@ var init_execution = __esm(() => {
56054
56422
  runtime: ctx.runtime,
56055
56423
  packageView,
56056
56424
  packageDir: ctx.workdir,
56057
- agentName: ctx.routing.agent ?? defaultAgent,
56425
+ agentName: resolved.agentName,
56058
56426
  storyId: ctx.story.id,
56059
56427
  featureName: ctx.prd.feature,
56060
56428
  story: ctx.story,
@@ -56472,7 +56840,7 @@ function parseQueueFile(content) {
56472
56840
  var init_queue = () => {};
56473
56841
 
56474
56842
  // src/execution/queue-handler.ts
56475
- import path12 from "path";
56843
+ import path13 from "path";
56476
56844
  function getSafeLogger4() {
56477
56845
  try {
56478
56846
  return getLogger();
@@ -56481,8 +56849,8 @@ function getSafeLogger4() {
56481
56849
  }
56482
56850
  }
56483
56851
  async function readQueueFile(workdir) {
56484
- const queuePath = path12.join(workdir, ".queue.txt");
56485
- const processingPath = path12.join(workdir, ".queue.txt.processing");
56852
+ const queuePath = path13.join(workdir, ".queue.txt");
56853
+ const processingPath = path13.join(workdir, ".queue.txt.processing");
56486
56854
  const logger = getSafeLogger4();
56487
56855
  try {
56488
56856
  const file3 = Bun.file(queuePath);
@@ -56507,7 +56875,7 @@ async function readQueueFile(workdir) {
56507
56875
  }
56508
56876
  }
56509
56877
  async function clearQueueFile(workdir) {
56510
- const processingPath = path12.join(workdir, ".queue.txt.processing");
56878
+ const processingPath = path13.join(workdir, ".queue.txt.processing");
56511
56879
  const logger = getSafeLogger4();
56512
56880
  try {
56513
56881
  const file3 = Bun.file(processingPath);
@@ -56585,13 +56953,12 @@ var init_queue_check = __esm(() => {
56585
56953
  // src/pipeline/stages/routing.ts
56586
56954
  var routingStage, _routingDeps;
56587
56955
  var init_routing2 = __esm(() => {
56588
- init_test_runners();
56589
- init_paths3();
56590
- init_greenfield();
56956
+ init_context();
56591
56957
  init_logger2();
56592
56958
  init_prd();
56593
56959
  init_routing();
56594
- init_llm();
56960
+ init_test_runners();
56961
+ init_paths3();
56595
56962
  routingStage = {
56596
56963
  name: "routing",
56597
56964
  enabled: () => true,
@@ -56603,26 +56970,35 @@ var init_routing2 = __esm(() => {
56603
56970
  const decision = await _routingDeps.resolveRouting(ctx.story, ctx.config, ctx.plugins, ctx);
56604
56971
  const TIER_RANK = { fast: 0, balanced: 1, powerful: 2 };
56605
56972
  const derivedTier = decision.modelTier;
56973
+ const profileTier = ctx.story.routing?.profileModelTier;
56974
+ const candidateTier = profileTier ?? derivedTier;
56975
+ const candidateRank = TIER_RANK[candidateTier];
56606
56976
  const previousTier = ctx.story.routing?.modelTier;
56607
56977
  const previousRank = previousTier !== undefined ? TIER_RANK[previousTier] : undefined;
56608
- const derivedRank = TIER_RANK[derivedTier];
56609
- if (previousTier !== undefined && previousRank === undefined) {
56978
+ const hasEscalationRecords = (ctx.story.escalations?.length ?? 0) > 0;
56979
+ if (previousTier !== undefined && previousRank === undefined && !hasEscalationRecords) {
56610
56980
  logger?.warn("routing", "Ignoring unknown previousTier \u2014 not escalating", {
56611
56981
  storyId: ctx.story.id,
56612
56982
  previousTier,
56613
- derivedTier
56983
+ candidateTier
56614
56984
  });
56615
56985
  }
56616
- const isEscalated = previousTier !== undefined && previousRank !== undefined && derivedRank !== undefined && previousRank > derivedRank;
56617
- const modelTier = isEscalated ? previousTier : derivedTier;
56618
- const routing = { ...decision, modelTier, agent: ctx.story.routing?.agent };
56986
+ const isEscalated = previousTier !== undefined && (previousRank !== undefined && candidateRank !== undefined ? previousRank > candidateRank : hasEscalationRecords);
56987
+ const modelTier = isEscalated ? previousTier : candidateTier;
56988
+ const routing = { ...decision, modelTier, agent: ctx.story.routing?.agent ?? decision.agent };
56989
+ const neverEscalated = !hasEscalationRecords;
56990
+ const initialAgent = ctx.story.routing?.initialAgent ?? (neverEscalated ? routing.agent : undefined);
56991
+ const initialProfileId = ctx.story.routing?.initialProfileId ?? (neverEscalated ? ctx.story.routing?.agentProfileId : undefined);
56619
56992
  ctx.story.routing = {
56620
56993
  ...ctx.story.routing ?? {},
56621
56994
  complexity: routing.complexity,
56622
56995
  initialComplexity: ctx.story.routing?.initialComplexity ?? routing.complexity,
56623
56996
  testStrategy: routing.testStrategy,
56624
56997
  reasoning: routing.reasoning ?? "",
56625
- modelTier: routing.modelTier
56998
+ modelTier: routing.modelTier,
56999
+ ...routing.agent !== undefined && { agent: routing.agent },
57000
+ ...initialAgent !== undefined && { initialAgent },
57001
+ ...initialProfileId !== undefined && { initialProfileId }
56626
57002
  };
56627
57003
  if (ctx.prdPath) {
56628
57004
  await _routingDeps.savePRD(ctx.prd, ctx.prdPath);
@@ -56652,13 +57028,13 @@ var init_routing2 = __esm(() => {
56652
57028
  }
56653
57029
  ctx.routing = routing;
56654
57030
  logger.debug("routing", "Task classified", {
57031
+ storyId: ctx.story.id,
56655
57032
  complexity: ctx.routing.complexity,
56656
57033
  modelTier: ctx.routing.modelTier,
56657
- testStrategy: ctx.routing.testStrategy,
56658
- storyId: ctx.story.id
57034
+ testStrategy: ctx.routing.testStrategy
56659
57035
  });
56660
57036
  if (ctx.stories.length === 1) {
56661
- logger.debug("routing", "Routing reasoning", { reasoning: ctx.routing.reasoning, storyId: ctx.story.id });
57037
+ logger.debug("routing", "Routing reasoning", { storyId: ctx.story.id, reasoning: ctx.routing.reasoning });
56662
57038
  }
56663
57039
  return { action: "continue" };
56664
57040
  }
@@ -56730,6 +57106,7 @@ var init_pipeline = __esm(() => {
56730
57106
  init_runner4();
56731
57107
  init_events();
56732
57108
  init_stages();
57109
+ init_execution_helpers();
56733
57110
  init_event_bus();
56734
57111
  });
56735
57112
 
@@ -57136,11 +57513,11 @@ __export(exports_init_context, {
57136
57513
  _initContextDeps: () => _initContextDeps
57137
57514
  });
57138
57515
  import { basename as basename9, join as join52 } from "path";
57139
- async function bunFileExists(path13) {
57140
- return Bun.file(path13).exists();
57516
+ async function bunFileExists(path14) {
57517
+ return Bun.file(path14).exists();
57141
57518
  }
57142
- async function bunMkdirp(path13) {
57143
- const proc = Bun.spawn(["mkdir", "-p", path13]);
57519
+ async function bunMkdirp(path14) {
57520
+ const proc = Bun.spawn(["mkdir", "-p", path14]);
57144
57521
  await proc.exited;
57145
57522
  }
57146
57523
  async function findFiles(dir, maxFiles = 200) {
@@ -57206,8 +57583,8 @@ async function detectEntryPoints(projectRoot) {
57206
57583
  const candidates = ["src/index.ts", "src/main.ts", "main.go", "src/lib.rs"];
57207
57584
  const found = [];
57208
57585
  for (const candidate of candidates) {
57209
- const path13 = join52(projectRoot, candidate);
57210
- if (await bunFileExists(path13)) {
57586
+ const path14 = join52(projectRoot, candidate);
57587
+ if (await bunFileExists(path14)) {
57211
57588
  found.push(candidate);
57212
57589
  }
57213
57590
  }
@@ -57217,8 +57594,8 @@ async function detectConfigFiles(projectRoot) {
57217
57594
  const candidates = ["tsconfig.json", "biome.json", "turbo.json", ".env.example"];
57218
57595
  const found = [];
57219
57596
  for (const candidate of candidates) {
57220
- const path13 = join52(projectRoot, candidate);
57221
- if (await bunFileExists(path13)) {
57597
+ const path14 = join52(projectRoot, candidate);
57598
+ if (await bunFileExists(path14)) {
57222
57599
  found.push(candidate);
57223
57600
  }
57224
57601
  }
@@ -58004,10 +58381,10 @@ var init_setup_analyze = __esm(() => {
58004
58381
  init_workspace();
58005
58382
  CANONICAL_SCRIPTS = ["build", "test", "lint", "type-check", "lint:fix"];
58006
58383
  _analyzeRepoDeps = {
58007
- fileExists: async (path13) => Bun.file(path13).exists(),
58008
- readJson: async (path13) => {
58384
+ fileExists: async (path14) => Bun.file(path14).exists(),
58385
+ readJson: async (path14) => {
58009
58386
  try {
58010
- const f = Bun.file(path13);
58387
+ const f = Bun.file(path14);
58011
58388
  if (!await f.exists())
58012
58389
  return null;
58013
58390
  return JSON.parse(await f.text());
@@ -58062,9 +58439,9 @@ async function fillScripts(workdir, analysis) {
58062
58439
  var TYPE_CHECK_KEY = "type-check", TYPE_CHECK_SCRIPT = "tsc --noEmit -p tsconfig.json", TYPE_CHECK_TURBO_PASSTHROUGH = "turbo run type-check", _fillScriptsDeps;
58063
58440
  var init_setup_fill = __esm(() => {
58064
58441
  _fillScriptsDeps = {
58065
- readJson: async (path13) => {
58442
+ readJson: async (path14) => {
58066
58443
  try {
58067
- const f = Bun.file(path13);
58444
+ const f = Bun.file(path14);
58068
58445
  if (!await f.exists())
58069
58446
  return null;
58070
58447
  return JSON.parse(await f.text());
@@ -58072,8 +58449,8 @@ var init_setup_fill = __esm(() => {
58072
58449
  return null;
58073
58450
  }
58074
58451
  },
58075
- writeFile: async (path13, content) => {
58076
- await Bun.write(path13, content);
58452
+ writeFile: async (path14, content) => {
58453
+ await Bun.write(path14, content);
58077
58454
  }
58078
58455
  };
58079
58456
  });
@@ -58194,10 +58571,10 @@ var init_setup = __esm(() => {
58194
58571
  },
58195
58572
  generateSetupPlan: (ctx, analysis) => generateSetupPlan(ctx, analysis),
58196
58573
  runGate: (workdir, config2) => runSetupGate(workdir, config2),
58197
- fileExists: (path13) => Bun.file(path13).exists(),
58198
- writeFile: (path13, content) => Bun.write(path13, content).then(() => {}),
58199
- mkdir: async (path13) => {
58200
- const proc = Bun.spawn(["mkdir", "-p", path13]);
58574
+ fileExists: (path14) => Bun.file(path14).exists(),
58575
+ writeFile: (path14, content) => Bun.write(path14, content).then(() => {}),
58576
+ mkdir: async (path14) => {
58577
+ const proc = Bun.spawn(["mkdir", "-p", path14]);
58201
58578
  await proc.exited;
58202
58579
  },
58203
58580
  stdout: (msg) => {
@@ -58212,7 +58589,7 @@ var init_setup = __esm(() => {
58212
58589
  });
58213
58590
 
58214
58591
  // src/plugins/builtin/curator/collect.ts
58215
- import * as path13 from "path";
58592
+ import * as path14 from "path";
58216
58593
  function now() {
58217
58594
  return new Date().toISOString();
58218
58595
  }
@@ -58262,7 +58639,7 @@ function tokenCount(story) {
58262
58639
  }
58263
58640
  async function collectFromMetrics(context) {
58264
58641
  const observations = [];
58265
- const metricsPath = path13.join(context.outputDir, "metrics.json");
58642
+ const metricsPath = path14.join(context.outputDir, "metrics.json");
58266
58643
  try {
58267
58644
  const data = await readJsonFile(metricsPath);
58268
58645
  const runs = Array.isArray(data) ? data : [data];
@@ -58312,11 +58689,11 @@ function findingMessage(finding) {
58312
58689
  }
58313
58690
  async function collectFromReviewAudit(context) {
58314
58691
  const observations = [];
58315
- const auditDir = path13.join(context.outputDir, "review-audit");
58692
+ const auditDir = path14.join(context.outputDir, "review-audit");
58316
58693
  try {
58317
58694
  const glob = new Bun.Glob("**/*.json");
58318
58695
  for await (const file3 of glob.scan({ cwd: auditDir, absolute: false })) {
58319
- const fullPath = path13.join(auditDir, file3);
58696
+ const fullPath = path14.join(auditDir, file3);
58320
58697
  try {
58321
58698
  const audit = asRecord3(await readJsonFile(fullPath));
58322
58699
  if (!audit)
@@ -58356,11 +58733,11 @@ async function collectFromReviewAudit(context) {
58356
58733
  }
58357
58734
  async function collectFromContextManifests(context) {
58358
58735
  const observations = [];
58359
- const featuresDir = path13.join(context.workdir, ".nax", "features");
58736
+ const featuresDir = path14.join(context.workdir, ".nax", "features");
58360
58737
  try {
58361
58738
  const glob = new Bun.Glob("*/stories/*/context-manifest-*.json");
58362
58739
  for await (const file3 of glob.scan({ cwd: featuresDir, absolute: false })) {
58363
- const fullPath = path13.join(featuresDir, file3);
58740
+ const fullPath = path14.join(featuresDir, file3);
58364
58741
  try {
58365
58742
  const parts = file3.split("/");
58366
58743
  const featureId = parts[0] ?? context.feature;
@@ -58913,10 +59290,10 @@ function renderProposals(proposals, runId, observationCount) {
58913
59290
 
58914
59291
  // src/plugins/builtin/curator/rollup.ts
58915
59292
  import { appendFile as appendFile3, mkdir as mkdir9, writeFile } from "fs/promises";
58916
- import * as path14 from "path";
59293
+ import * as path15 from "path";
58917
59294
  async function appendToRollup(observations, rollupPath) {
58918
59295
  try {
58919
- const dir = path14.dirname(rollupPath);
59296
+ const dir = path15.dirname(rollupPath);
58920
59297
  await mkdir9(dir, { recursive: true });
58921
59298
  if (observations.length === 0) {
58922
59299
  const f = Bun.file(rollupPath);
@@ -58935,7 +59312,7 @@ var init_rollup = () => {};
58935
59312
 
58936
59313
  // src/plugins/builtin/curator/index.ts
58937
59314
  import { mkdir as mkdir10 } from "fs/promises";
58938
- import * as path15 from "path";
59315
+ import * as path16 from "path";
58939
59316
  function getCuratorEnabled(context) {
58940
59317
  const cfg = context.config;
58941
59318
  if (!cfg)
@@ -59008,7 +59385,7 @@ var init_curator = __esm(() => {
59008
59385
  const observations = await collectObservations(curatorContext);
59009
59386
  if (context.outputDir) {
59010
59387
  const { observationsPath, rollupPath } = resolveCuratorOutputs(curatorContext);
59011
- const runDir = path15.dirname(observationsPath);
59388
+ const runDir = path16.dirname(observationsPath);
59012
59389
  await mkdir10(runDir, { recursive: true });
59013
59390
  await Bun.write(observationsPath, observations.map((o) => JSON.stringify(o)).join(`
59014
59391
  `) + (observations.length > 0 ? `
@@ -59016,7 +59393,7 @@ var init_curator = __esm(() => {
59016
59393
  const thresholds = getCuratorThresholds(context);
59017
59394
  const proposals = runHeuristics(observations, thresholds);
59018
59395
  const markdown = renderProposals(proposals, context.runId, observations.length);
59019
- const proposalsMdPath = path15.join(runDir, "curator-proposals.md");
59396
+ const proposalsMdPath = path16.join(runDir, "curator-proposals.md");
59020
59397
  await Bun.write(proposalsMdPath, markdown);
59021
59398
  await appendToRollup(observations, rollupPath);
59022
59399
  }
@@ -59386,14 +59763,14 @@ var init_validator = __esm(() => {
59386
59763
 
59387
59764
  // src/plugins/loader.ts
59388
59765
  import * as fs from "fs/promises";
59389
- import * as path16 from "path";
59766
+ import * as path17 from "path";
59390
59767
  function getSafeLogger6() {
59391
59768
  return getSafeLogger();
59392
59769
  }
59393
59770
  function extractPluginName(pluginPath) {
59394
- const basename11 = path16.basename(pluginPath);
59771
+ const basename11 = path17.basename(pluginPath);
59395
59772
  if (basename11 === "index.ts" || basename11 === "index.js" || basename11 === "index.mjs") {
59396
- return path16.basename(path16.dirname(pluginPath));
59773
+ return path17.basename(path17.dirname(pluginPath));
59397
59774
  }
59398
59775
  return basename11.replace(/\.(ts|js|mjs)$/, "");
59399
59776
  }
@@ -59479,7 +59856,7 @@ async function discoverPlugins(dir, isTestFileFn) {
59479
59856
  try {
59480
59857
  const entries = await fs.readdir(dir, { withFileTypes: true });
59481
59858
  for (const entry of entries) {
59482
- const fullPath = path16.join(dir, entry.name);
59859
+ const fullPath = path17.join(dir, entry.name);
59483
59860
  if (entry.isFile()) {
59484
59861
  if (isPluginFile(entry.name, isTestFileFn)) {
59485
59862
  discovered.push({ path: fullPath });
@@ -59487,7 +59864,7 @@ async function discoverPlugins(dir, isTestFileFn) {
59487
59864
  } else if (entry.isDirectory()) {
59488
59865
  const indexPaths = ["index.ts", "index.js", "index.mjs"];
59489
59866
  for (const indexFile of indexPaths) {
59490
- const indexPath = path16.join(fullPath, indexFile);
59867
+ const indexPath = path17.join(fullPath, indexFile);
59491
59868
  try {
59492
59869
  await fs.access(indexPath);
59493
59870
  discovered.push({ path: indexPath });
@@ -59512,13 +59889,13 @@ function isPluginFile(filename, isTestFileFn) {
59512
59889
  return !FALLBACK_TEST_FILE_RE.test(filename);
59513
59890
  }
59514
59891
  function resolveModulePath(modulePath, projectRoot) {
59515
- if (path16.isAbsolute(modulePath) || !modulePath.startsWith("./") && !modulePath.startsWith("../")) {
59892
+ if (path17.isAbsolute(modulePath) || !modulePath.startsWith("./") && !modulePath.startsWith("../")) {
59516
59893
  return modulePath;
59517
59894
  }
59518
59895
  if (projectRoot) {
59519
- return path16.resolve(projectRoot, modulePath);
59896
+ return path17.resolve(projectRoot, modulePath);
59520
59897
  }
59521
- return path16.resolve(modulePath);
59898
+ return path17.resolve(modulePath);
59522
59899
  }
59523
59900
  async function loadAndValidatePlugin(initialModulePath, config2, allowedRoots = [], originalPath) {
59524
59901
  let attemptedPath = initialModulePath;
@@ -59834,7 +60211,7 @@ var package_default;
59834
60211
  var init_package = __esm(() => {
59835
60212
  package_default = {
59836
60213
  name: "@nathapp/nax",
59837
- version: "0.69.10",
60214
+ version: "0.70.0-canary.2",
59838
60215
  description: "AI Coding Agent Orchestrator \u2014 loops until done",
59839
60216
  type: "module",
59840
60217
  bin: {
@@ -59929,8 +60306,8 @@ var init_version = __esm(() => {
59929
60306
  NAX_VERSION = package_default.version;
59930
60307
  NAX_COMMIT = (() => {
59931
60308
  try {
59932
- if (/^[0-9a-f]{6,10}$/.test("5b5bf412"))
59933
- return "5b5bf412";
60309
+ if (/^[0-9a-f]{6,10}$/.test("b070f4c1"))
60310
+ return "b070f4c1";
59934
60311
  } catch {}
59935
60312
  try {
59936
60313
  const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
@@ -60316,7 +60693,7 @@ async function readSourceFileContent(filePath, workdir) {
60316
60693
  var MAX_SOURCE_FILES = 5, MAX_FILE_LINES2 = 500;
60317
60694
 
60318
60695
  // src/execution/lifecycle/acceptance-helpers.ts
60319
- import path18 from "path";
60696
+ import path19 from "path";
60320
60697
  function isStubTestFile(content) {
60321
60698
  return isStubTestContent(content);
60322
60699
  }
@@ -60335,7 +60712,7 @@ function isTestLevelFailure(failedACs, totalACs, semanticVerdicts) {
60335
60712
  async function loadSpecContent(featureDir) {
60336
60713
  if (!featureDir)
60337
60714
  return "";
60338
- const specPath = path18.join(featureDir, "spec.md");
60715
+ const specPath = path19.join(featureDir, "spec.md");
60339
60716
  const specFile = Bun.file(specPath);
60340
60717
  return await specFile.exists() ? await specFile.text() : "";
60341
60718
  }
@@ -60355,7 +60732,7 @@ async function loadAcceptanceTestContent2(featureDir, testPaths, configuredTestP
60355
60732
  }
60356
60733
  if (!configuredTestPath)
60357
60734
  return [];
60358
- const resolvedPath = path18.join(featureDir, configuredTestPath);
60735
+ const resolvedPath = path19.join(featureDir, configuredTestPath);
60359
60736
  const testFile = Bun.file(resolvedPath);
60360
60737
  const content = await testFile.exists() ? await testFile.text() : "";
60361
60738
  return [{ content, path: resolvedPath }];
@@ -60372,7 +60749,7 @@ async function regenerateAcceptanceTest(testPath, acceptanceContext) {
60372
60749
  const { unlink: unlink3 } = await import("fs/promises");
60373
60750
  await unlink3(testPath);
60374
60751
  if (acceptanceContext.featureDir) {
60375
- const metaPath = path18.join(acceptanceContext.featureDir, "acceptance-meta.json");
60752
+ const metaPath = path19.join(acceptanceContext.featureDir, "acceptance-meta.json");
60376
60753
  try {
60377
60754
  await unlink3(metaPath);
60378
60755
  } catch {}
@@ -60386,7 +60763,7 @@ async function regenerateAcceptanceTest(testPath, acceptanceContext) {
60386
60763
  const changedFilesRaw = diffOutput.split(`
60387
60764
  `).map((f) => f.trim()).filter((f) => f.length > 0);
60388
60765
  const repoRoot = acceptanceContext.projectDir ?? workdir;
60389
- const packageDir = acceptanceContext.story.workdir && acceptanceContext.projectDir ? path18.join(acceptanceContext.projectDir, acceptanceContext.story.workdir) : undefined;
60766
+ const packageDir = acceptanceContext.story.workdir && acceptanceContext.projectDir ? path19.join(acceptanceContext.projectDir, acceptanceContext.story.workdir) : undefined;
60390
60767
  const ignoreMatchers = acceptanceContext.naxIgnoreIndex?.getMatchers(packageDir) ?? await resolveNaxIgnorePatterns(repoRoot, packageDir);
60391
60768
  const changedFiles = filterNaxInternalPaths(changedFilesRaw, ignoreMatchers);
60392
60769
  const MAX_BYTES = 51200;
@@ -60395,7 +60772,7 @@ async function regenerateAcceptanceTest(testPath, acceptanceContext) {
60395
60772
  for (const file3 of changedFiles) {
60396
60773
  if (totalBytes >= MAX_BYTES)
60397
60774
  break;
60398
- const filePath = path18.join(workdir, file3);
60775
+ const filePath = path19.join(workdir, file3);
60399
60776
  try {
60400
60777
  const fileContent = await _regenerateDeps.readFile(filePath);
60401
60778
  const remaining = MAX_BYTES - totalBytes;
@@ -60854,9 +61231,9 @@ var init_scratch_purge = __esm(() => {
60854
61231
  return [];
60855
61232
  }
60856
61233
  },
60857
- fileExists: (path19) => Bun.file(path19).exists(),
60858
- readFile: (path19) => Bun.file(path19).text(),
60859
- remove: (path19) => rm(path19, { recursive: true, force: true }),
61234
+ fileExists: (path20) => Bun.file(path20).exists(),
61235
+ readFile: (path20) => Bun.file(path20).text(),
61236
+ remove: (path20) => rm(path20, { recursive: true, force: true }),
60860
61237
  move: async (src, dest) => {
60861
61238
  await mkdir12(dirname12(dest), { recursive: true });
60862
61239
  await rename(src, dest);
@@ -62560,17 +62937,12 @@ var init_merge = __esm(() => {
62560
62937
  });
62561
62938
 
62562
62939
  // src/execution/escalation/escalation.ts
62563
- function escalateTier(currentTier, tierOrder) {
62564
- const getName = (t) => t.tier ?? t.name ?? null;
62565
- const currentIndex = tierOrder.findIndex((t) => getName(t) === currentTier);
62566
- if (currentIndex === -1 || currentIndex === tierOrder.length - 1) {
62567
- return null;
62568
- }
62569
- const next = tierOrder[currentIndex + 1];
62570
- const nextName = getName(next);
62571
- if (!nextName)
62940
+ function escalateTier(currentRung, tierOrder) {
62941
+ const i = currentRung.agent !== undefined ? tierOrder.findIndex((t) => t.tier === currentRung.tier && t.agent === currentRung.agent) : tierOrder.findIndex((t) => t.tier === currentRung.tier);
62942
+ if (i === -1 || i === tierOrder.length - 1)
62572
62943
  return null;
62573
- return { tier: nextName, agent: next.agent };
62944
+ const next = tierOrder[i + 1];
62945
+ return { tier: next.tier, agent: next.agent };
62574
62946
  }
62575
62947
  function calculateMaxIterations(tierOrder) {
62576
62948
  return tierOrder.reduce((sum, t) => sum + t.attempts, 0);
@@ -62633,9 +63005,9 @@ var _quoteIntegrityDeps, CONTEXT_LINES = 3;
62633
63005
  var init_quote_integrity = __esm(() => {
62634
63006
  init_logger2();
62635
63007
  _quoteIntegrityDeps = {
62636
- readFile: async (path20) => {
63008
+ readFile: async (path21) => {
62637
63009
  try {
62638
- return await Bun.file(path20).text();
63010
+ return await Bun.file(path21).text();
62639
63011
  } catch {
62640
63012
  return null;
62641
63013
  }
@@ -62790,7 +63162,10 @@ async function handleTierEscalation(ctx) {
62790
63162
  });
62791
63163
  return { outcome: "retry-same", prdDirty: false, prd: ctx.prd };
62792
63164
  }
62793
- const escalationResult = escalateTier(ctx.routing.modelTier, ctx.config.autoMode.escalation.tierOrder);
63165
+ const escalationTierOrder = ctx.config.autoMode.escalation.tierOrder;
63166
+ const hasAgentRungs = escalationTierOrder.some((r) => r.agent !== undefined);
63167
+ const currentRung = hasAgentRungs ? { tier: ctx.routing.modelTier, agent: ctx.story.routing?.agent } : { tier: ctx.routing.modelTier };
63168
+ const escalationResult = escalateTier(currentRung, escalationTierOrder);
62794
63169
  const nextAgent = escalationResult?.agent;
62795
63170
  const escalateWholeBatch = ctx.config.autoMode.escalation.escalateEntireBatch ?? true;
62796
63171
  const storiesToEscalate = ctx.isBatchExecution && escalateWholeBatch ? ctx.storiesToExecute : [ctx.story];
@@ -62898,7 +63273,8 @@ var init_tier_escalation = __esm(() => {
62898
63273
  init_quote_integrity();
62899
63274
  init_tier_outcome();
62900
63275
  _tierEscalationDeps = {
62901
- savePRD
63276
+ savePRD,
63277
+ getSafeLogger
62902
63278
  };
62903
63279
  });
62904
63280
 
@@ -62912,7 +63288,7 @@ var exports_merge_conflict_rectify = {};
62912
63288
  __export(exports_merge_conflict_rectify, {
62913
63289
  rectifyConflictedStory: () => rectifyConflictedStory
62914
63290
  });
62915
- import path20 from "path";
63291
+ import path21 from "path";
62916
63292
  async function closeStaleAcpSession(worktreePath, sessionName) {
62917
63293
  const logger = getSafeLogger();
62918
63294
  try {
@@ -62939,7 +63315,7 @@ async function rectifyConflictedStory(options) {
62939
63315
  await worktreeManager.remove(workdir, storyId);
62940
63316
  } catch {}
62941
63317
  await worktreeManager.create(workdir, storyId);
62942
- const worktreePath = path20.join(workdir, ".nax-wt", storyId);
63318
+ const worktreePath = path21.join(workdir, ".nax-wt", storyId);
62943
63319
  const { formatSessionName: formatSessionName2 } = await Promise.resolve().then(() => (init_naming(), exports_naming));
62944
63320
  const staleSessionName = formatSessionName2({
62945
63321
  workdir: worktreePath,
@@ -63622,7 +63998,7 @@ __export(exports_parallel_batch, {
63622
63998
  runParallelBatch: () => runParallelBatch,
63623
63999
  _parallelBatchDeps: () => _parallelBatchDeps
63624
64000
  });
63625
- import path21 from "path";
64001
+ import path22 from "path";
63626
64002
  async function runParallelBatch(options) {
63627
64003
  const { stories, ctx, prd } = options;
63628
64004
  const { workdir, config: config2, maxConcurrency, pipelineContext, eventEmitter, agentGetFn, hooks, pluginRegistry } = ctx;
@@ -63641,9 +64017,9 @@ async function runParallelBatch(options) {
63641
64017
  });
63642
64018
  throw error48;
63643
64019
  }
63644
- worktreePaths.set(story.id, path21.join(workdir, ".nax-wt", story.id));
64020
+ worktreePaths.set(story.id, path22.join(workdir, ".nax-wt", story.id));
63645
64021
  }
63646
- const rootConfigPath = path21.join(workdir, ".nax", "config.json");
64022
+ const rootConfigPath = path22.join(workdir, ".nax", "config.json");
63647
64023
  const profileOverride = config2.profile && config2.profile !== "default" ? { profile: config2.profile } : undefined;
63648
64024
  const storyEffectiveConfigs = new Map;
63649
64025
  const configResults = await Promise.allSettled(stories.filter((story) => story.workdir).map(async (story) => {
@@ -64560,7 +64936,7 @@ __export(exports_migrate, {
64560
64936
  });
64561
64937
  import { existsSync as existsSync33 } from "fs";
64562
64938
  import { mkdir as mkdir16, readdir as readdir5, rename as rename3 } from "fs/promises";
64563
- import path22 from "path";
64939
+ import path23 from "path";
64564
64940
  async function detectGeneratedContent(naxDir) {
64565
64941
  if (!existsSync33(naxDir))
64566
64942
  return [];
@@ -64573,17 +64949,17 @@ async function detectGeneratedContent(naxDir) {
64573
64949
  }
64574
64950
  for (const entry of entries) {
64575
64951
  if (GENERATED_NAMES.has(entry)) {
64576
- candidates.push({ name: entry, srcPath: path22.join(naxDir, entry) });
64952
+ candidates.push({ name: entry, srcPath: path23.join(naxDir, entry) });
64577
64953
  }
64578
64954
  }
64579
- const featuresDir = path22.join(naxDir, "features");
64955
+ const featuresDir = path23.join(naxDir, "features");
64580
64956
  if (existsSync33(featuresDir)) {
64581
64957
  let featureDirs = [];
64582
64958
  try {
64583
64959
  featureDirs = await readdir5(featuresDir);
64584
64960
  } catch {}
64585
64961
  for (const fid of featureDirs) {
64586
- const featureDir = path22.join(featuresDir, fid);
64962
+ const featureDir = path23.join(featuresDir, fid);
64587
64963
  let subEntries = [];
64588
64964
  try {
64589
64965
  subEntries = await readdir5(featureDir);
@@ -64593,12 +64969,12 @@ async function detectGeneratedContent(naxDir) {
64593
64969
  for (const sub of subEntries) {
64594
64970
  if (GENERATED_FEATURE_SUBNAMES.has(sub)) {
64595
64971
  candidates.push({
64596
- name: path22.join("features", fid, sub),
64597
- srcPath: path22.join(featureDir, sub)
64972
+ name: path23.join("features", fid, sub),
64973
+ srcPath: path23.join(featureDir, sub)
64598
64974
  });
64599
64975
  }
64600
64976
  if (sub === "stories") {
64601
- const storiesDir = path22.join(featureDir, "stories");
64977
+ const storiesDir = path23.join(featureDir, "stories");
64602
64978
  let storyDirs = [];
64603
64979
  try {
64604
64980
  storyDirs = await readdir5(storiesDir);
@@ -64606,7 +64982,7 @@ async function detectGeneratedContent(naxDir) {
64606
64982
  continue;
64607
64983
  }
64608
64984
  for (const sid of storyDirs) {
64609
- const storyDir = path22.join(storiesDir, sid);
64985
+ const storyDir = path23.join(storiesDir, sid);
64610
64986
  let storyEntries = [];
64611
64987
  try {
64612
64988
  storyEntries = await readdir5(storyDir);
@@ -64616,8 +64992,8 @@ async function detectGeneratedContent(naxDir) {
64616
64992
  for (const se of storyEntries) {
64617
64993
  if (se.startsWith("context-manifest-") && se.endsWith(".json")) {
64618
64994
  candidates.push({
64619
- name: path22.join("features", fid, "stories", sid, se),
64620
- srcPath: path22.join(storyDir, se)
64995
+ name: path23.join("features", fid, "stories", sid, se),
64996
+ srcPath: path23.join(storyDir, se)
64621
64997
  });
64622
64998
  }
64623
64999
  }
@@ -64638,15 +65014,15 @@ async function migrateCommand(options) {
64638
65014
  name: options.reclaim
64639
65015
  });
64640
65016
  }
64641
- const src = path22.join(globalConfigDir(), options.reclaim);
65017
+ const src = path23.join(globalConfigDir(), options.reclaim);
64642
65018
  if (!existsSync33(src)) {
64643
65019
  throw new NaxError(`Nothing to reclaim: ~/.nax/${options.reclaim} does not exist`, "MIGRATE_RECLAIM_NOT_FOUND", {
64644
65020
  stage: "migrate",
64645
65021
  name: options.reclaim
64646
65022
  });
64647
65023
  }
64648
- const archiveBase = path22.join(globalConfigDir(), "_archive");
64649
- const archiveDest = path22.join(archiveBase, `${options.reclaim}-${Date.now()}`);
65024
+ const archiveBase = path23.join(globalConfigDir(), "_archive");
65025
+ const archiveDest = path23.join(archiveBase, `${options.reclaim}-${Date.now()}`);
64650
65026
  await mkdir16(archiveBase, { recursive: true });
64651
65027
  await rename3(src, archiveDest);
64652
65028
  logger.info("migrate", `Reclaimed: archived to ${archiveDest}`, { storyId: "_migrate" });
@@ -64683,8 +65059,8 @@ async function migrateCommand(options) {
64683
65059
  logger.info("migrate", `Merged: identity for "${options.merge}" updated`, { storyId: "_migrate" });
64684
65060
  return;
64685
65061
  }
64686
- const naxDir = path22.join(options.workdir, ".nax");
64687
- const configPath = path22.join(naxDir, "config.json");
65062
+ const naxDir = path23.join(options.workdir, ".nax");
65063
+ const configPath = path23.join(naxDir, "config.json");
64688
65064
  if (!existsSync33(configPath)) {
64689
65065
  throw new NaxError("No .nax/config.json found \u2014 run nax init first", "MIGRATE_NO_CONFIG", {
64690
65066
  stage: "migrate",
@@ -64700,7 +65076,7 @@ async function migrateCommand(options) {
64700
65076
  cause: e
64701
65077
  });
64702
65078
  }
64703
- const projectKey = config2.name?.trim() || path22.basename(options.workdir);
65079
+ const projectKey = config2.name?.trim() || path23.basename(options.workdir);
64704
65080
  const destBase = projectOutputDir(projectKey, config2.outputDir);
64705
65081
  const candidates = await detectGeneratedContent(naxDir);
64706
65082
  if (candidates.length === 0) {
@@ -64709,7 +65085,7 @@ async function migrateCommand(options) {
64709
65085
  }
64710
65086
  if (options.dryRun) {
64711
65087
  for (const c of candidates) {
64712
- logger.info("migrate", `[dry-run] Would move: ${c.srcPath} -> ${path22.join(destBase, c.name)}`, {
65088
+ logger.info("migrate", `[dry-run] Would move: ${c.srcPath} -> ${path23.join(destBase, c.name)}`, {
64713
65089
  storyId: "_migrate"
64714
65090
  });
64715
65091
  }
@@ -64718,8 +65094,8 @@ async function migrateCommand(options) {
64718
65094
  await mkdir16(destBase, { recursive: true });
64719
65095
  let moved = 0;
64720
65096
  for (const candidate of candidates) {
64721
- const dest = path22.join(destBase, candidate.name);
64722
- await mkdir16(path22.dirname(dest), { recursive: true });
65097
+ const dest = path23.join(destBase, candidate.name);
65098
+ await mkdir16(path23.dirname(dest), { recursive: true });
64723
65099
  if (existsSync33(dest)) {
64724
65100
  throw new NaxError(`Migration conflict: destination already exists.
64725
65101
  Source: ${candidate.srcPath}
@@ -64749,7 +65125,7 @@ async function migrateCommand(options) {
64749
65125
  moved++;
64750
65126
  logger.info("migrate", `Moved: ${candidate.name}`, { storyId: "_migrate" });
64751
65127
  }
64752
- await Bun.write(path22.join(destBase, ".migrated-from"), JSON.stringify({ from: options.workdir, migratedAt: new Date().toISOString() }, null, 2));
65128
+ await Bun.write(path23.join(destBase, ".migrated-from"), JSON.stringify({ from: options.workdir, migratedAt: new Date().toISOString() }, null, 2));
64753
65129
  logger.info("migrate", `Migration complete: ${moved} entries moved`, {
64754
65130
  storyId: "_migrate",
64755
65131
  destBase
@@ -64866,7 +65242,7 @@ __export(exports_precheck_runner, {
64866
65242
  runPrecheckValidation: () => runPrecheckValidation
64867
65243
  });
64868
65244
  import { mkdirSync as mkdirSync6 } from "fs";
64869
- import path23 from "path";
65245
+ import path24 from "path";
64870
65246
  async function runPrecheckValidation(ctx) {
64871
65247
  const logger = getSafeLogger();
64872
65248
  if (process.env.NAX_PRECHECK !== "1") {
@@ -64881,7 +65257,7 @@ async function runPrecheckValidation(ctx) {
64881
65257
  silent: true
64882
65258
  });
64883
65259
  if (ctx.logFilePath) {
64884
- mkdirSync6(path23.dirname(ctx.logFilePath), { recursive: true });
65260
+ mkdirSync6(path24.dirname(ctx.logFilePath), { recursive: true });
64885
65261
  const precheckLog = {
64886
65262
  type: "precheck",
64887
65263
  timestamp: new Date().toISOString(),
@@ -65178,11 +65554,33 @@ var init_paused_story_prompts = __esm(() => {
65178
65554
  // src/execution/lifecycle/run-setup.ts
65179
65555
  var exports_run_setup = {};
65180
65556
  __export(exports_run_setup, {
65557
+ warnProfileMismatch: () => warnProfileMismatch,
65181
65558
  warnFallbackMisconfiguration: () => warnFallbackMisconfiguration,
65182
65559
  setupRun: () => setupRun,
65183
65560
  _runSetupDeps: () => _runSetupDeps
65184
65561
  });
65185
- import path24 from "path";
65562
+ import path25 from "path";
65563
+ function warnProfileMismatch(prd, config2, logger) {
65564
+ const profiles = config2.routing?.agents?.profiles ?? [];
65565
+ const profileIds = new Set(profiles.map((p) => p.id));
65566
+ if (prd.routingProfile !== undefined) {
65567
+ const current = config2.profile ?? "default";
65568
+ if (prd.routingProfile !== current) {
65569
+ logger?.warn("prd", `PRD was planned with config profile "${prd.routingProfile}" but this run resolved profile "${current}" \u2014 the escalation ladder and agent profiles may differ from what plan assumed. Re-run with --profile ${prd.routingProfile} to match.`, { storyId: "prd", plannedProfile: prd.routingProfile, currentProfile: current });
65570
+ }
65571
+ }
65572
+ const knownAgents = new Set(Object.keys(config2.models ?? {}));
65573
+ for (const story of prd.userStories) {
65574
+ const profileId = story.routing?.agentProfileId;
65575
+ if (profileId && !profileIds.has(profileId)) {
65576
+ logger?.warn("setup", `Story ${story.id} was planned with profile ${profileId} which no longer exists in config \u2014 routing.agent assignment retained`, { storyId: story.id, agentProfileId: profileId });
65577
+ }
65578
+ const storyAgent = story.routing?.agent;
65579
+ if (storyAgent && !knownAgents.has(storyAgent)) {
65580
+ logger?.warn("setup", `Story ${story.id} routes to agent "${storyAgent}" which is not defined in config.models \u2014 execution will degrade to the default agent`, { storyId: story.id, agent: storyAgent });
65581
+ }
65582
+ }
65583
+ }
65186
65584
  function warnFallbackMisconfiguration(config2, agentGetFn, logger) {
65187
65585
  if (!agentGetFn)
65188
65586
  return;
@@ -65196,6 +65594,7 @@ function warnFallbackMisconfiguration(config2, agentGetFn, logger) {
65196
65594
  continue;
65197
65595
  if (!agentGetFn(candidate)) {
65198
65596
  logger?.warn("fallback", "Fallback candidate not available \u2014 will be skipped if triggered", {
65597
+ storyId: "_setup",
65199
65598
  primaryAgent,
65200
65599
  candidate
65201
65600
  });
@@ -65281,7 +65680,7 @@ async function setupRun(options) {
65281
65680
  statusWriter.setPrd(prd);
65282
65681
  {
65283
65682
  const { detectGeneratedContent: detectGeneratedContent2, migrateCommand: migrateCommand2 } = await Promise.resolve().then(() => (init_migrate(), exports_migrate));
65284
- const naxDir = path24.join(workdir, ".nax");
65683
+ const naxDir = path25.join(workdir, ".nax");
65285
65684
  const candidates = await detectGeneratedContent2(naxDir).catch(() => []);
65286
65685
  if (candidates.length > 0) {
65287
65686
  logger?.info("setup", "Found generated content under .nax/ \u2014 migrating to output dir", {
@@ -65308,7 +65707,7 @@ async function setupRun(options) {
65308
65707
  remoteUrl = new TextDecoder().decode(gitResult.stdout).trim() || null;
65309
65708
  }
65310
65709
  } catch {}
65311
- const projectKey = config2.name?.trim() || path24.basename(workdir);
65710
+ const projectKey = config2.name?.trim() || path25.basename(workdir);
65312
65711
  await claimProjectIdentity2(projectKey, workdir, remoteUrl).catch((err) => {
65313
65712
  if (err instanceof NaxError && err.code === "RUN_NAME_COLLISION") {
65314
65713
  throw err;
@@ -65363,8 +65762,8 @@ async function setupRun(options) {
65363
65762
  explicit: Object.fromEntries(explicitFields.map((f) => [f, existingProjectConfig[f]])),
65364
65763
  detected: Object.fromEntries(autodetectedFields.map((f) => [f, detectedProfile[f]]))
65365
65764
  });
65366
- const globalPluginsDir = path24.join(globalConfigDir(), "plugins");
65367
- const projectPluginsDir = path24.join(workdir, ".nax", "plugins");
65765
+ const globalPluginsDir = path25.join(globalConfigDir(), "plugins");
65766
+ const projectPluginsDir = path25.join(workdir, ".nax", "plugins");
65368
65767
  const configPlugins = config2.plugins || [];
65369
65768
  const resolvedPatterns = await resolveTestFilePatterns(config2, workdir);
65370
65769
  const isTestFileFn = (filename) => resolvedPatterns.regex.some((re) => re.test(filename));
@@ -65393,6 +65792,7 @@ async function setupRun(options) {
65393
65792
  });
65394
65793
  prd = initResult.prd;
65395
65794
  statusWriter.setPrd(prd);
65795
+ warnProfileMismatch(prd, config2, logger);
65396
65796
  let counts = initResult.storyCounts;
65397
65797
  if (counts.paused > 0 && interactionChain !== null) {
65398
65798
  const { promptForPausedStories: promptForPausedStories2 } = await Promise.resolve().then(() => (init_paused_story_prompts(), exports_paused_story_prompts));
@@ -66855,11 +67255,11 @@ var require_react_reconciler_development = __commonJS((exports, module) => {
66855
67255
  fiber = fiber.next, id--;
66856
67256
  return fiber;
66857
67257
  }
66858
- function copyWithSetImpl(obj, path25, index, value) {
66859
- if (index >= path25.length)
67258
+ function copyWithSetImpl(obj, path26, index, value) {
67259
+ if (index >= path26.length)
66860
67260
  return value;
66861
- var key = path25[index], updated = isArrayImpl(obj) ? obj.slice() : assign2({}, obj);
66862
- updated[key] = copyWithSetImpl(obj[key], path25, index + 1, value);
67261
+ var key = path26[index], updated = isArrayImpl(obj) ? obj.slice() : assign2({}, obj);
67262
+ updated[key] = copyWithSetImpl(obj[key], path26, index + 1, value);
66863
67263
  return updated;
66864
67264
  }
66865
67265
  function copyWithRename(obj, oldPath, newPath) {
@@ -66879,11 +67279,11 @@ var require_react_reconciler_development = __commonJS((exports, module) => {
66879
67279
  index + 1 === oldPath.length ? (updated[newPath[index]] = updated[oldKey], isArrayImpl(updated) ? updated.splice(oldKey, 1) : delete updated[oldKey]) : updated[oldKey] = copyWithRenameImpl(obj[oldKey], oldPath, newPath, index + 1);
66880
67280
  return updated;
66881
67281
  }
66882
- function copyWithDeleteImpl(obj, path25, index) {
66883
- var key = path25[index], updated = isArrayImpl(obj) ? obj.slice() : assign2({}, obj);
66884
- if (index + 1 === path25.length)
67282
+ function copyWithDeleteImpl(obj, path26, index) {
67283
+ var key = path26[index], updated = isArrayImpl(obj) ? obj.slice() : assign2({}, obj);
67284
+ if (index + 1 === path26.length)
66885
67285
  return isArrayImpl(updated) ? updated.splice(key, 1) : delete updated[key], updated;
66886
- updated[key] = copyWithDeleteImpl(obj[key], path25, index + 1);
67286
+ updated[key] = copyWithDeleteImpl(obj[key], path26, index + 1);
66887
67287
  return updated;
66888
67288
  }
66889
67289
  function shouldSuspendImpl() {
@@ -76906,29 +77306,29 @@ Check the top-level render call using <` + componentName2 + ">.");
76906
77306
  var didWarnAboutNestedUpdates = false;
76907
77307
  var didWarnAboutFindNodeInStrictMode = {};
76908
77308
  var overrideHookState = null, overrideHookStateDeletePath = null, overrideHookStateRenamePath = null, overrideProps = null, overridePropsDeletePath = null, overridePropsRenamePath = null, scheduleUpdate = null, scheduleRetry = null, setErrorHandler = null, setSuspenseHandler = null;
76909
- overrideHookState = function(fiber, id, path25, value) {
77309
+ overrideHookState = function(fiber, id, path26, value) {
76910
77310
  id = findHook(fiber, id);
76911
- id !== null && (path25 = copyWithSetImpl(id.memoizedState, path25, 0, value), id.memoizedState = path25, id.baseState = path25, fiber.memoizedProps = assign2({}, fiber.memoizedProps), path25 = enqueueConcurrentRenderForLane(fiber, 2), path25 !== null && scheduleUpdateOnFiber(path25, fiber, 2));
77311
+ id !== null && (path26 = copyWithSetImpl(id.memoizedState, path26, 0, value), id.memoizedState = path26, id.baseState = path26, fiber.memoizedProps = assign2({}, fiber.memoizedProps), path26 = enqueueConcurrentRenderForLane(fiber, 2), path26 !== null && scheduleUpdateOnFiber(path26, fiber, 2));
76912
77312
  };
76913
- overrideHookStateDeletePath = function(fiber, id, path25) {
77313
+ overrideHookStateDeletePath = function(fiber, id, path26) {
76914
77314
  id = findHook(fiber, id);
76915
- id !== null && (path25 = copyWithDeleteImpl(id.memoizedState, path25, 0), id.memoizedState = path25, id.baseState = path25, fiber.memoizedProps = assign2({}, fiber.memoizedProps), path25 = enqueueConcurrentRenderForLane(fiber, 2), path25 !== null && scheduleUpdateOnFiber(path25, fiber, 2));
77315
+ id !== null && (path26 = copyWithDeleteImpl(id.memoizedState, path26, 0), id.memoizedState = path26, id.baseState = path26, fiber.memoizedProps = assign2({}, fiber.memoizedProps), path26 = enqueueConcurrentRenderForLane(fiber, 2), path26 !== null && scheduleUpdateOnFiber(path26, fiber, 2));
76916
77316
  };
76917
77317
  overrideHookStateRenamePath = function(fiber, id, oldPath, newPath) {
76918
77318
  id = findHook(fiber, id);
76919
77319
  id !== null && (oldPath = copyWithRename(id.memoizedState, oldPath, newPath), id.memoizedState = oldPath, id.baseState = oldPath, fiber.memoizedProps = assign2({}, fiber.memoizedProps), oldPath = enqueueConcurrentRenderForLane(fiber, 2), oldPath !== null && scheduleUpdateOnFiber(oldPath, fiber, 2));
76920
77320
  };
76921
- overrideProps = function(fiber, path25, value) {
76922
- fiber.pendingProps = copyWithSetImpl(fiber.memoizedProps, path25, 0, value);
77321
+ overrideProps = function(fiber, path26, value) {
77322
+ fiber.pendingProps = copyWithSetImpl(fiber.memoizedProps, path26, 0, value);
76923
77323
  fiber.alternate && (fiber.alternate.pendingProps = fiber.pendingProps);
76924
- path25 = enqueueConcurrentRenderForLane(fiber, 2);
76925
- path25 !== null && scheduleUpdateOnFiber(path25, fiber, 2);
77324
+ path26 = enqueueConcurrentRenderForLane(fiber, 2);
77325
+ path26 !== null && scheduleUpdateOnFiber(path26, fiber, 2);
76926
77326
  };
76927
- overridePropsDeletePath = function(fiber, path25) {
76928
- fiber.pendingProps = copyWithDeleteImpl(fiber.memoizedProps, path25, 0);
77327
+ overridePropsDeletePath = function(fiber, path26) {
77328
+ fiber.pendingProps = copyWithDeleteImpl(fiber.memoizedProps, path26, 0);
76929
77329
  fiber.alternate && (fiber.alternate.pendingProps = fiber.pendingProps);
76930
- path25 = enqueueConcurrentRenderForLane(fiber, 2);
76931
- path25 !== null && scheduleUpdateOnFiber(path25, fiber, 2);
77330
+ path26 = enqueueConcurrentRenderForLane(fiber, 2);
77331
+ path26 !== null && scheduleUpdateOnFiber(path26, fiber, 2);
76932
77332
  };
76933
77333
  overridePropsRenamePath = function(fiber, oldPath, newPath) {
76934
77334
  fiber.pendingProps = copyWithRename(fiber.memoizedProps, oldPath, newPath);
@@ -80983,8 +81383,8 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
80983
81383
  }
80984
81384
  return false;
80985
81385
  }
80986
- function utils_getInObject(object2, path25) {
80987
- return path25.reduce(function(reduced, attr) {
81386
+ function utils_getInObject(object2, path26) {
81387
+ return path26.reduce(function(reduced, attr) {
80988
81388
  if (reduced) {
80989
81389
  if (utils_hasOwnProperty.call(reduced, attr)) {
80990
81390
  return reduced[attr];
@@ -80996,11 +81396,11 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
80996
81396
  return null;
80997
81397
  }, object2);
80998
81398
  }
80999
- function deletePathInObject(object2, path25) {
81000
- var length = path25.length;
81001
- var last2 = path25[length - 1];
81399
+ function deletePathInObject(object2, path26) {
81400
+ var length = path26.length;
81401
+ var last2 = path26[length - 1];
81002
81402
  if (object2 != null) {
81003
- var parent = utils_getInObject(object2, path25.slice(0, length - 1));
81403
+ var parent = utils_getInObject(object2, path26.slice(0, length - 1));
81004
81404
  if (parent) {
81005
81405
  if (src_isArray(parent)) {
81006
81406
  parent.splice(last2, 1);
@@ -81026,11 +81426,11 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81026
81426
  }
81027
81427
  }
81028
81428
  }
81029
- function utils_setInObject(object2, path25, value) {
81030
- var length = path25.length;
81031
- var last2 = path25[length - 1];
81429
+ function utils_setInObject(object2, path26, value) {
81430
+ var length = path26.length;
81431
+ var last2 = path26[length - 1];
81032
81432
  if (object2 != null) {
81033
- var parent = utils_getInObject(object2, path25.slice(0, length - 1));
81433
+ var parent = utils_getInObject(object2, path26.slice(0, length - 1));
81034
81434
  if (parent) {
81035
81435
  parent[last2] = value;
81036
81436
  }
@@ -81561,8 +81961,8 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81561
81961
  unserializable: Symbol("unserializable")
81562
81962
  };
81563
81963
  var LEVEL_THRESHOLD = 2;
81564
- function createDehydrated(type, inspectable, data, cleaned, path25) {
81565
- cleaned.push(path25);
81964
+ function createDehydrated(type, inspectable, data, cleaned, path26) {
81965
+ cleaned.push(path26);
81566
81966
  var dehydrated = {
81567
81967
  inspectable,
81568
81968
  type,
@@ -81580,13 +81980,13 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81580
81980
  }
81581
81981
  return dehydrated;
81582
81982
  }
81583
- function dehydrate(data, cleaned, unserializable, path25, isPathAllowed) {
81983
+ function dehydrate(data, cleaned, unserializable, path26, isPathAllowed) {
81584
81984
  var level = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 0;
81585
81985
  var type = getDataType(data);
81586
81986
  var isPathAllowedCheck;
81587
81987
  switch (type) {
81588
81988
  case "html_element":
81589
- cleaned.push(path25);
81989
+ cleaned.push(path26);
81590
81990
  return {
81591
81991
  inspectable: false,
81592
81992
  preview_short: formatDataForPreview(data, false),
@@ -81595,7 +81995,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81595
81995
  type
81596
81996
  };
81597
81997
  case "function":
81598
- cleaned.push(path25);
81998
+ cleaned.push(path26);
81599
81999
  return {
81600
82000
  inspectable: false,
81601
82001
  preview_short: formatDataForPreview(data, false),
@@ -81604,14 +82004,14 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81604
82004
  type
81605
82005
  };
81606
82006
  case "string":
81607
- isPathAllowedCheck = isPathAllowed(path25);
82007
+ isPathAllowedCheck = isPathAllowed(path26);
81608
82008
  if (isPathAllowedCheck) {
81609
82009
  return data;
81610
82010
  } else {
81611
82011
  return data.length <= 500 ? data : data.slice(0, 500) + "...";
81612
82012
  }
81613
82013
  case "bigint":
81614
- cleaned.push(path25);
82014
+ cleaned.push(path26);
81615
82015
  return {
81616
82016
  inspectable: false,
81617
82017
  preview_short: formatDataForPreview(data, false),
@@ -81620,7 +82020,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81620
82020
  type
81621
82021
  };
81622
82022
  case "symbol":
81623
- cleaned.push(path25);
82023
+ cleaned.push(path26);
81624
82024
  return {
81625
82025
  inspectable: false,
81626
82026
  preview_short: formatDataForPreview(data, false),
@@ -81629,9 +82029,9 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81629
82029
  type
81630
82030
  };
81631
82031
  case "react_element": {
81632
- isPathAllowedCheck = isPathAllowed(path25);
82032
+ isPathAllowedCheck = isPathAllowed(path26);
81633
82033
  if (level >= LEVEL_THRESHOLD && !isPathAllowedCheck) {
81634
- cleaned.push(path25);
82034
+ cleaned.push(path26);
81635
82035
  return {
81636
82036
  inspectable: true,
81637
82037
  preview_short: formatDataForPreview(data, false),
@@ -81648,19 +82048,19 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81648
82048
  preview_long: formatDataForPreview(data, true),
81649
82049
  name: getDisplayNameForReactElement(data) || "Unknown"
81650
82050
  };
81651
- unserializableValue.key = dehydrate(data.key, cleaned, unserializable, path25.concat(["key"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
82051
+ unserializableValue.key = dehydrate(data.key, cleaned, unserializable, path26.concat(["key"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
81652
82052
  if (data.$$typeof === REACT_LEGACY_ELEMENT_TYPE) {
81653
- unserializableValue.ref = dehydrate(data.ref, cleaned, unserializable, path25.concat(["ref"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
82053
+ unserializableValue.ref = dehydrate(data.ref, cleaned, unserializable, path26.concat(["ref"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
81654
82054
  }
81655
- unserializableValue.props = dehydrate(data.props, cleaned, unserializable, path25.concat(["props"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
81656
- unserializable.push(path25);
82055
+ unserializableValue.props = dehydrate(data.props, cleaned, unserializable, path26.concat(["props"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
82056
+ unserializable.push(path26);
81657
82057
  return unserializableValue;
81658
82058
  }
81659
82059
  case "react_lazy": {
81660
- isPathAllowedCheck = isPathAllowed(path25);
82060
+ isPathAllowedCheck = isPathAllowed(path26);
81661
82061
  var payload = data._payload;
81662
82062
  if (level >= LEVEL_THRESHOLD && !isPathAllowedCheck) {
81663
- cleaned.push(path25);
82063
+ cleaned.push(path26);
81664
82064
  var inspectable = payload !== null && hydration_typeof(payload) === "object" && (payload._status === 1 || payload._status === 2 || payload.status === "fulfilled" || payload.status === "rejected");
81665
82065
  return {
81666
82066
  inspectable,
@@ -81677,13 +82077,13 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81677
82077
  preview_long: formatDataForPreview(data, true),
81678
82078
  name: "lazy()"
81679
82079
  };
81680
- _unserializableValue._payload = dehydrate(payload, cleaned, unserializable, path25.concat(["_payload"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
81681
- unserializable.push(path25);
82080
+ _unserializableValue._payload = dehydrate(payload, cleaned, unserializable, path26.concat(["_payload"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
82081
+ unserializable.push(path26);
81682
82082
  return _unserializableValue;
81683
82083
  }
81684
82084
  case "array_buffer":
81685
82085
  case "data_view":
81686
- cleaned.push(path25);
82086
+ cleaned.push(path26);
81687
82087
  return {
81688
82088
  inspectable: false,
81689
82089
  preview_short: formatDataForPreview(data, false),
@@ -81693,21 +82093,21 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81693
82093
  type
81694
82094
  };
81695
82095
  case "array":
81696
- isPathAllowedCheck = isPathAllowed(path25);
82096
+ isPathAllowedCheck = isPathAllowed(path26);
81697
82097
  if (level >= LEVEL_THRESHOLD && !isPathAllowedCheck) {
81698
- return createDehydrated(type, true, data, cleaned, path25);
82098
+ return createDehydrated(type, true, data, cleaned, path26);
81699
82099
  }
81700
82100
  var arr = [];
81701
82101
  for (var i = 0;i < data.length; i++) {
81702
- arr[i] = dehydrateKey(data, i, cleaned, unserializable, path25.concat([i]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
82102
+ arr[i] = dehydrateKey(data, i, cleaned, unserializable, path26.concat([i]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
81703
82103
  }
81704
82104
  return arr;
81705
82105
  case "html_all_collection":
81706
82106
  case "typed_array":
81707
82107
  case "iterator":
81708
- isPathAllowedCheck = isPathAllowed(path25);
82108
+ isPathAllowedCheck = isPathAllowed(path26);
81709
82109
  if (level >= LEVEL_THRESHOLD && !isPathAllowedCheck) {
81710
- return createDehydrated(type, true, data, cleaned, path25);
82110
+ return createDehydrated(type, true, data, cleaned, path26);
81711
82111
  } else {
81712
82112
  var _unserializableValue2 = {
81713
82113
  unserializable: true,
@@ -81719,13 +82119,13 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81719
82119
  name: typeof data.constructor !== "function" || typeof data.constructor.name !== "string" || data.constructor.name === "Object" ? "" : data.constructor.name
81720
82120
  };
81721
82121
  Array.from(data).forEach(function(item, i2) {
81722
- return _unserializableValue2[i2] = dehydrate(item, cleaned, unserializable, path25.concat([i2]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
82122
+ return _unserializableValue2[i2] = dehydrate(item, cleaned, unserializable, path26.concat([i2]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
81723
82123
  });
81724
- unserializable.push(path25);
82124
+ unserializable.push(path26);
81725
82125
  return _unserializableValue2;
81726
82126
  }
81727
82127
  case "opaque_iterator":
81728
- cleaned.push(path25);
82128
+ cleaned.push(path26);
81729
82129
  return {
81730
82130
  inspectable: false,
81731
82131
  preview_short: formatDataForPreview(data, false),
@@ -81734,7 +82134,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81734
82134
  type
81735
82135
  };
81736
82136
  case "date":
81737
- cleaned.push(path25);
82137
+ cleaned.push(path26);
81738
82138
  return {
81739
82139
  inspectable: false,
81740
82140
  preview_short: formatDataForPreview(data, false),
@@ -81743,7 +82143,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81743
82143
  type
81744
82144
  };
81745
82145
  case "regexp":
81746
- cleaned.push(path25);
82146
+ cleaned.push(path26);
81747
82147
  return {
81748
82148
  inspectable: false,
81749
82149
  preview_short: formatDataForPreview(data, false),
@@ -81752,9 +82152,9 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81752
82152
  type
81753
82153
  };
81754
82154
  case "thenable":
81755
- isPathAllowedCheck = isPathAllowed(path25);
82155
+ isPathAllowedCheck = isPathAllowed(path26);
81756
82156
  if (level >= LEVEL_THRESHOLD && !isPathAllowedCheck) {
81757
- cleaned.push(path25);
82157
+ cleaned.push(path26);
81758
82158
  return {
81759
82159
  inspectable: data.status === "fulfilled" || data.status === "rejected",
81760
82160
  preview_short: formatDataForPreview(data, false),
@@ -81775,8 +82175,8 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81775
82175
  preview_long: formatDataForPreview(data, true),
81776
82176
  name: "fulfilled Thenable"
81777
82177
  };
81778
- _unserializableValue3.value = dehydrate(data.value, cleaned, unserializable, path25.concat(["value"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
81779
- unserializable.push(path25);
82178
+ _unserializableValue3.value = dehydrate(data.value, cleaned, unserializable, path26.concat(["value"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
82179
+ unserializable.push(path26);
81780
82180
  return _unserializableValue3;
81781
82181
  }
81782
82182
  case "rejected": {
@@ -81787,12 +82187,12 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81787
82187
  preview_long: formatDataForPreview(data, true),
81788
82188
  name: "rejected Thenable"
81789
82189
  };
81790
- _unserializableValue4.reason = dehydrate(data.reason, cleaned, unserializable, path25.concat(["reason"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
81791
- unserializable.push(path25);
82190
+ _unserializableValue4.reason = dehydrate(data.reason, cleaned, unserializable, path26.concat(["reason"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
82191
+ unserializable.push(path26);
81792
82192
  return _unserializableValue4;
81793
82193
  }
81794
82194
  default:
81795
- cleaned.push(path25);
82195
+ cleaned.push(path26);
81796
82196
  return {
81797
82197
  inspectable: false,
81798
82198
  preview_short: formatDataForPreview(data, false),
@@ -81802,21 +82202,21 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81802
82202
  };
81803
82203
  }
81804
82204
  case "object":
81805
- isPathAllowedCheck = isPathAllowed(path25);
82205
+ isPathAllowedCheck = isPathAllowed(path26);
81806
82206
  if (level >= LEVEL_THRESHOLD && !isPathAllowedCheck) {
81807
- return createDehydrated(type, true, data, cleaned, path25);
82207
+ return createDehydrated(type, true, data, cleaned, path26);
81808
82208
  } else {
81809
82209
  var object2 = {};
81810
82210
  getAllEnumerableKeys(data).forEach(function(key) {
81811
82211
  var name = key.toString();
81812
- object2[name] = dehydrateKey(data, key, cleaned, unserializable, path25.concat([name]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
82212
+ object2[name] = dehydrateKey(data, key, cleaned, unserializable, path26.concat([name]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
81813
82213
  });
81814
82214
  return object2;
81815
82215
  }
81816
82216
  case "class_instance": {
81817
- isPathAllowedCheck = isPathAllowed(path25);
82217
+ isPathAllowedCheck = isPathAllowed(path26);
81818
82218
  if (level >= LEVEL_THRESHOLD && !isPathAllowedCheck) {
81819
- return createDehydrated(type, true, data, cleaned, path25);
82219
+ return createDehydrated(type, true, data, cleaned, path26);
81820
82220
  }
81821
82221
  var value = {
81822
82222
  unserializable: true,
@@ -81828,15 +82228,15 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81828
82228
  };
81829
82229
  getAllEnumerableKeys(data).forEach(function(key) {
81830
82230
  var keyAsString = key.toString();
81831
- value[keyAsString] = dehydrate(data[key], cleaned, unserializable, path25.concat([keyAsString]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
82231
+ value[keyAsString] = dehydrate(data[key], cleaned, unserializable, path26.concat([keyAsString]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
81832
82232
  });
81833
- unserializable.push(path25);
82233
+ unserializable.push(path26);
81834
82234
  return value;
81835
82235
  }
81836
82236
  case "error": {
81837
- isPathAllowedCheck = isPathAllowed(path25);
82237
+ isPathAllowedCheck = isPathAllowed(path26);
81838
82238
  if (level >= LEVEL_THRESHOLD && !isPathAllowedCheck) {
81839
- return createDehydrated(type, true, data, cleaned, path25);
82239
+ return createDehydrated(type, true, data, cleaned, path26);
81840
82240
  }
81841
82241
  var _value = {
81842
82242
  unserializable: true,
@@ -81846,22 +82246,22 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81846
82246
  preview_long: formatDataForPreview(data, true),
81847
82247
  name: data.name
81848
82248
  };
81849
- _value.message = dehydrate(data.message, cleaned, unserializable, path25.concat(["message"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
81850
- _value.stack = dehydrate(data.stack, cleaned, unserializable, path25.concat(["stack"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
82249
+ _value.message = dehydrate(data.message, cleaned, unserializable, path26.concat(["message"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
82250
+ _value.stack = dehydrate(data.stack, cleaned, unserializable, path26.concat(["stack"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
81851
82251
  if ("cause" in data) {
81852
- _value.cause = dehydrate(data.cause, cleaned, unserializable, path25.concat(["cause"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
82252
+ _value.cause = dehydrate(data.cause, cleaned, unserializable, path26.concat(["cause"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
81853
82253
  }
81854
82254
  getAllEnumerableKeys(data).forEach(function(key) {
81855
82255
  var keyAsString = key.toString();
81856
- _value[keyAsString] = dehydrate(data[key], cleaned, unserializable, path25.concat([keyAsString]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
82256
+ _value[keyAsString] = dehydrate(data[key], cleaned, unserializable, path26.concat([keyAsString]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
81857
82257
  });
81858
- unserializable.push(path25);
82258
+ unserializable.push(path26);
81859
82259
  return _value;
81860
82260
  }
81861
82261
  case "infinity":
81862
82262
  case "nan":
81863
82263
  case "undefined":
81864
- cleaned.push(path25);
82264
+ cleaned.push(path26);
81865
82265
  return {
81866
82266
  type
81867
82267
  };
@@ -81869,10 +82269,10 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81869
82269
  return data;
81870
82270
  }
81871
82271
  }
81872
- function dehydrateKey(parent, key, cleaned, unserializable, path25, isPathAllowed) {
82272
+ function dehydrateKey(parent, key, cleaned, unserializable, path26, isPathAllowed) {
81873
82273
  var level = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : 0;
81874
82274
  try {
81875
- return dehydrate(parent[key], cleaned, unserializable, path25, isPathAllowed, level);
82275
+ return dehydrate(parent[key], cleaned, unserializable, path26, isPathAllowed, level);
81876
82276
  } catch (error48) {
81877
82277
  var preview = "";
81878
82278
  if (hydration_typeof(error48) === "object" && error48 !== null && typeof error48.stack === "string") {
@@ -81880,7 +82280,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81880
82280
  } else if (typeof error48 === "string") {
81881
82281
  preview = error48;
81882
82282
  }
81883
- cleaned.push(path25);
82283
+ cleaned.push(path26);
81884
82284
  return {
81885
82285
  inspectable: false,
81886
82286
  preview_short: "[Exception]",
@@ -81890,8 +82290,8 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81890
82290
  };
81891
82291
  }
81892
82292
  }
81893
- function fillInPath(object2, data, path25, value) {
81894
- var target = getInObject(object2, path25);
82293
+ function fillInPath(object2, data, path26, value) {
82294
+ var target = getInObject(object2, path26);
81895
82295
  if (target != null) {
81896
82296
  if (!target[meta3.unserializable]) {
81897
82297
  delete target[meta3.inspectable];
@@ -81906,9 +82306,9 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81906
82306
  }
81907
82307
  if (value !== null && data.unserializable.length > 0) {
81908
82308
  var unserializablePath = data.unserializable[0];
81909
- var isMatch2 = unserializablePath.length === path25.length;
81910
- for (var i = 0;i < path25.length; i++) {
81911
- if (path25[i] !== unserializablePath[i]) {
82309
+ var isMatch2 = unserializablePath.length === path26.length;
82310
+ for (var i = 0;i < path26.length; i++) {
82311
+ if (path26[i] !== unserializablePath[i]) {
81912
82312
  isMatch2 = false;
81913
82313
  break;
81914
82314
  }
@@ -81917,13 +82317,13 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81917
82317
  upgradeUnserializable(value, value);
81918
82318
  }
81919
82319
  }
81920
- setInObject(object2, path25, value);
82320
+ setInObject(object2, path26, value);
81921
82321
  }
81922
82322
  function hydrate(object2, cleaned, unserializable) {
81923
- cleaned.forEach(function(path25) {
81924
- var length = path25.length;
81925
- var last2 = path25[length - 1];
81926
- var parent = getInObject(object2, path25.slice(0, length - 1));
82323
+ cleaned.forEach(function(path26) {
82324
+ var length = path26.length;
82325
+ var last2 = path26[length - 1];
82326
+ var parent = getInObject(object2, path26.slice(0, length - 1));
81927
82327
  if (!parent || !parent.hasOwnProperty(last2)) {
81928
82328
  return;
81929
82329
  }
@@ -81949,10 +82349,10 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81949
82349
  parent[last2] = replaced;
81950
82350
  }
81951
82351
  });
81952
- unserializable.forEach(function(path25) {
81953
- var length = path25.length;
81954
- var last2 = path25[length - 1];
81955
- var parent = getInObject(object2, path25.slice(0, length - 1));
82352
+ unserializable.forEach(function(path26) {
82353
+ var length = path26.length;
82354
+ var last2 = path26[length - 1];
82355
+ var parent = getInObject(object2, path26.slice(0, length - 1));
81956
82356
  if (!parent || !parent.hasOwnProperty(last2)) {
81957
82357
  return;
81958
82358
  }
@@ -82073,11 +82473,11 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
82073
82473
  return gte2(version2, FIRST_DEVTOOLS_BACKEND_LOCKSTEP_VER);
82074
82474
  }
82075
82475
  function cleanForBridge(data, isPathAllowed) {
82076
- var path25 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
82476
+ var path26 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
82077
82477
  if (data !== null) {
82078
82478
  var cleanedPaths = [];
82079
82479
  var unserializablePaths = [];
82080
- var cleanedData = dehydrate(data, cleanedPaths, unserializablePaths, path25, isPathAllowed);
82480
+ var cleanedData = dehydrate(data, cleanedPaths, unserializablePaths, path26, isPathAllowed);
82081
82481
  return {
82082
82482
  data: cleanedData,
82083
82483
  cleaned: cleanedPaths,
@@ -82087,18 +82487,18 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
82087
82487
  return null;
82088
82488
  }
82089
82489
  }
82090
- function copyWithDelete(obj, path25) {
82490
+ function copyWithDelete(obj, path26) {
82091
82491
  var index = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
82092
- var key = path25[index];
82492
+ var key = path26[index];
82093
82493
  var updated = shared_isArray(obj) ? obj.slice() : utils_objectSpread({}, obj);
82094
- if (index + 1 === path25.length) {
82494
+ if (index + 1 === path26.length) {
82095
82495
  if (shared_isArray(updated)) {
82096
82496
  updated.splice(key, 1);
82097
82497
  } else {
82098
82498
  delete updated[key];
82099
82499
  }
82100
82500
  } else {
82101
- updated[key] = copyWithDelete(obj[key], path25, index + 1);
82501
+ updated[key] = copyWithDelete(obj[key], path26, index + 1);
82102
82502
  }
82103
82503
  return updated;
82104
82504
  }
@@ -82119,14 +82519,14 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
82119
82519
  }
82120
82520
  return updated;
82121
82521
  }
82122
- function copyWithSet(obj, path25, value) {
82522
+ function copyWithSet(obj, path26, value) {
82123
82523
  var index = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
82124
- if (index >= path25.length) {
82524
+ if (index >= path26.length) {
82125
82525
  return value;
82126
82526
  }
82127
- var key = path25[index];
82527
+ var key = path26[index];
82128
82528
  var updated = shared_isArray(obj) ? obj.slice() : utils_objectSpread({}, obj);
82129
- updated[key] = copyWithSet(obj[key], path25, value, index + 1);
82529
+ updated[key] = copyWithSet(obj[key], path26, value, index + 1);
82130
82530
  return updated;
82131
82531
  }
82132
82532
  function getEffectDurations(root) {
@@ -83454,12 +83854,12 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
83454
83854
  }
83455
83855
  });
83456
83856
  bridge_defineProperty(_this, "overrideValueAtPath", function(_ref) {
83457
- var { id, path: path25, rendererID, type, value } = _ref;
83857
+ var { id, path: path26, rendererID, type, value } = _ref;
83458
83858
  switch (type) {
83459
83859
  case "context":
83460
83860
  _this.send("overrideContext", {
83461
83861
  id,
83462
- path: path25,
83862
+ path: path26,
83463
83863
  rendererID,
83464
83864
  wasForwarded: true,
83465
83865
  value
@@ -83468,7 +83868,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
83468
83868
  case "hooks":
83469
83869
  _this.send("overrideHookState", {
83470
83870
  id,
83471
- path: path25,
83871
+ path: path26,
83472
83872
  rendererID,
83473
83873
  wasForwarded: true,
83474
83874
  value
@@ -83477,7 +83877,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
83477
83877
  case "props":
83478
83878
  _this.send("overrideProps", {
83479
83879
  id,
83480
- path: path25,
83880
+ path: path26,
83481
83881
  rendererID,
83482
83882
  wasForwarded: true,
83483
83883
  value
@@ -83486,7 +83886,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
83486
83886
  case "state":
83487
83887
  _this.send("overrideState", {
83488
83888
  id,
83489
- path: path25,
83889
+ path: path26,
83490
83890
  rendererID,
83491
83891
  wasForwarded: true,
83492
83892
  value
@@ -83820,12 +84220,12 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
83820
84220
  }
83821
84221
  });
83822
84222
  agent_defineProperty(_this, "copyElementPath", function(_ref5) {
83823
- var { id, path: path25, rendererID } = _ref5;
84223
+ var { id, path: path26, rendererID } = _ref5;
83824
84224
  var renderer = _this._rendererInterfaces[rendererID];
83825
84225
  if (renderer == null) {
83826
84226
  console.warn('Invalid renderer id "'.concat(rendererID, '" for element "').concat(id, '"'));
83827
84227
  } else {
83828
- var value = renderer.getSerializedElementValueByPath(id, path25);
84228
+ var value = renderer.getSerializedElementValueByPath(id, path26);
83829
84229
  if (value != null) {
83830
84230
  _this._bridge.send("saveToClipboard", value);
83831
84231
  } else {
@@ -83834,12 +84234,12 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
83834
84234
  }
83835
84235
  });
83836
84236
  agent_defineProperty(_this, "deletePath", function(_ref6) {
83837
- var { hookID, id, path: path25, rendererID, type } = _ref6;
84237
+ var { hookID, id, path: path26, rendererID, type } = _ref6;
83838
84238
  var renderer = _this._rendererInterfaces[rendererID];
83839
84239
  if (renderer == null) {
83840
84240
  console.warn('Invalid renderer id "'.concat(rendererID, '" for element "').concat(id, '"'));
83841
84241
  } else {
83842
- renderer.deletePath(type, id, hookID, path25);
84242
+ renderer.deletePath(type, id, hookID, path26);
83843
84243
  }
83844
84244
  });
83845
84245
  agent_defineProperty(_this, "getBackendVersion", function() {
@@ -83876,12 +84276,12 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
83876
84276
  }
83877
84277
  });
83878
84278
  agent_defineProperty(_this, "inspectElement", function(_ref9) {
83879
- var { forceFullData, id, path: path25, rendererID, requestID } = _ref9;
84279
+ var { forceFullData, id, path: path26, rendererID, requestID } = _ref9;
83880
84280
  var renderer = _this._rendererInterfaces[rendererID];
83881
84281
  if (renderer == null) {
83882
84282
  console.warn('Invalid renderer id "'.concat(rendererID, '" for element "').concat(id, '"'));
83883
84283
  } else {
83884
- _this._bridge.send("inspectedElement", renderer.inspectElement(requestID, id, path25, forceFullData));
84284
+ _this._bridge.send("inspectedElement", renderer.inspectElement(requestID, id, path26, forceFullData));
83885
84285
  if (_this._persistedSelectionMatch === null || _this._persistedSelectionMatch.id !== id) {
83886
84286
  _this._persistedSelection = null;
83887
84287
  _this._persistedSelectionMatch = null;
@@ -83915,15 +84315,15 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
83915
84315
  }
83916
84316
  for (var rendererID in _this._rendererInterfaces) {
83917
84317
  var renderer = _this._rendererInterfaces[rendererID];
83918
- var path25 = null;
84318
+ var path26 = null;
83919
84319
  if (suspendedByPathIndex !== null && rendererPath !== null) {
83920
84320
  var suspendedByPathRendererIndex = suspendedByPathIndex - suspendedByOffset;
83921
84321
  var rendererHasRequestedSuspendedByPath = renderer.getElementAttributeByPath(id, ["suspendedBy", suspendedByPathRendererIndex]) !== undefined;
83922
84322
  if (rendererHasRequestedSuspendedByPath) {
83923
- path25 = ["suspendedBy", suspendedByPathRendererIndex].concat(rendererPath);
84323
+ path26 = ["suspendedBy", suspendedByPathRendererIndex].concat(rendererPath);
83924
84324
  }
83925
84325
  }
83926
- var inspectedRootsPayload = renderer.inspectElement(requestID, id, path25, forceFullData);
84326
+ var inspectedRootsPayload = renderer.inspectElement(requestID, id, path26, forceFullData);
83927
84327
  switch (inspectedRootsPayload.type) {
83928
84328
  case "hydrated-path":
83929
84329
  inspectedRootsPayload.path[1] += suspendedByOffset;
@@ -84017,20 +84417,20 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
84017
84417
  }
84018
84418
  });
84019
84419
  agent_defineProperty(_this, "overrideValueAtPath", function(_ref15) {
84020
- var { hookID, id, path: path25, rendererID, type, value } = _ref15;
84420
+ var { hookID, id, path: path26, rendererID, type, value } = _ref15;
84021
84421
  var renderer = _this._rendererInterfaces[rendererID];
84022
84422
  if (renderer == null) {
84023
84423
  console.warn('Invalid renderer id "'.concat(rendererID, '" for element "').concat(id, '"'));
84024
84424
  } else {
84025
- renderer.overrideValueAtPath(type, id, hookID, path25, value);
84425
+ renderer.overrideValueAtPath(type, id, hookID, path26, value);
84026
84426
  }
84027
84427
  });
84028
84428
  agent_defineProperty(_this, "overrideContext", function(_ref16) {
84029
- var { id, path: path25, rendererID, wasForwarded, value } = _ref16;
84429
+ var { id, path: path26, rendererID, wasForwarded, value } = _ref16;
84030
84430
  if (!wasForwarded) {
84031
84431
  _this.overrideValueAtPath({
84032
84432
  id,
84033
- path: path25,
84433
+ path: path26,
84034
84434
  rendererID,
84035
84435
  type: "context",
84036
84436
  value
@@ -84038,11 +84438,11 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
84038
84438
  }
84039
84439
  });
84040
84440
  agent_defineProperty(_this, "overrideHookState", function(_ref17) {
84041
- var { id, hookID, path: path25, rendererID, wasForwarded, value } = _ref17;
84441
+ var { id, hookID, path: path26, rendererID, wasForwarded, value } = _ref17;
84042
84442
  if (!wasForwarded) {
84043
84443
  _this.overrideValueAtPath({
84044
84444
  id,
84045
- path: path25,
84445
+ path: path26,
84046
84446
  rendererID,
84047
84447
  type: "hooks",
84048
84448
  value
@@ -84050,11 +84450,11 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
84050
84450
  }
84051
84451
  });
84052
84452
  agent_defineProperty(_this, "overrideProps", function(_ref18) {
84053
- var { id, path: path25, rendererID, wasForwarded, value } = _ref18;
84453
+ var { id, path: path26, rendererID, wasForwarded, value } = _ref18;
84054
84454
  if (!wasForwarded) {
84055
84455
  _this.overrideValueAtPath({
84056
84456
  id,
84057
- path: path25,
84457
+ path: path26,
84058
84458
  rendererID,
84059
84459
  type: "props",
84060
84460
  value
@@ -84062,11 +84462,11 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
84062
84462
  }
84063
84463
  });
84064
84464
  agent_defineProperty(_this, "overrideState", function(_ref19) {
84065
- var { id, path: path25, rendererID, wasForwarded, value } = _ref19;
84465
+ var { id, path: path26, rendererID, wasForwarded, value } = _ref19;
84066
84466
  if (!wasForwarded) {
84067
84467
  _this.overrideValueAtPath({
84068
84468
  id,
84069
- path: path25,
84469
+ path: path26,
84070
84470
  rendererID,
84071
84471
  type: "state",
84072
84472
  value
@@ -84133,12 +84533,12 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
84133
84533
  _this._bridge.send("stopInspectingHost", selected);
84134
84534
  });
84135
84535
  agent_defineProperty(_this, "storeAsGlobal", function(_ref23) {
84136
- var { count, id, path: path25, rendererID } = _ref23;
84536
+ var { count, id, path: path26, rendererID } = _ref23;
84137
84537
  var renderer = _this._rendererInterfaces[rendererID];
84138
84538
  if (renderer == null) {
84139
84539
  console.warn('Invalid renderer id "'.concat(rendererID, '" for element "').concat(id, '"'));
84140
84540
  } else {
84141
- renderer.storeAsGlobal(id, path25, count);
84541
+ renderer.storeAsGlobal(id, path26, count);
84142
84542
  }
84143
84543
  });
84144
84544
  agent_defineProperty(_this, "updateHookSettings", function(settings) {
@@ -84155,12 +84555,12 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
84155
84555
  var rendererID = +rendererIDString;
84156
84556
  var renderer = _this._rendererInterfaces[rendererID];
84157
84557
  if (_this._lastSelectedRendererID === rendererID) {
84158
- var path25 = renderer.getPathForElement(_this._lastSelectedElementID);
84159
- if (path25 !== null) {
84160
- renderer.setTrackedPath(path25);
84558
+ var path26 = renderer.getPathForElement(_this._lastSelectedElementID);
84559
+ if (path26 !== null) {
84560
+ renderer.setTrackedPath(path26);
84161
84561
  _this._persistedSelection = {
84162
84562
  rendererID,
84163
- path: path25
84563
+ path: path26
84164
84564
  };
84165
84565
  }
84166
84566
  }
@@ -84235,11 +84635,11 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
84235
84635
  var rendererID = _this._lastSelectedRendererID;
84236
84636
  var id = _this._lastSelectedElementID;
84237
84637
  var renderer = _this._rendererInterfaces[rendererID];
84238
- var path25 = renderer != null ? renderer.getPathForElement(id) : null;
84239
- if (path25 !== null) {
84638
+ var path26 = renderer != null ? renderer.getPathForElement(id) : null;
84639
+ if (path26 !== null) {
84240
84640
  storage_sessionStorageSetItem(SESSION_STORAGE_LAST_SELECTION_KEY, JSON.stringify({
84241
84641
  rendererID,
84242
- path: path25
84642
+ path: path26
84243
84643
  }));
84244
84644
  } else {
84245
84645
  storage_sessionStorageRemoveItem(SESSION_STORAGE_LAST_SELECTION_KEY);
@@ -84962,7 +85362,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
84962
85362
  hasElementWithId: function hasElementWithId() {
84963
85363
  return false;
84964
85364
  },
84965
- inspectElement: function inspectElement(requestID, id, path25) {
85365
+ inspectElement: function inspectElement(requestID, id, path26) {
84966
85366
  return {
84967
85367
  id,
84968
85368
  responseID: requestID,
@@ -90232,9 +90632,9 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
90232
90632
  }
90233
90633
  return null;
90234
90634
  }
90235
- function getElementAttributeByPath(id, path25) {
90635
+ function getElementAttributeByPath(id, path26) {
90236
90636
  if (isMostRecentlyInspectedElement(id)) {
90237
- return utils_getInObject(mostRecentlyInspectedElement, path25);
90637
+ return utils_getInObject(mostRecentlyInspectedElement, path26);
90238
90638
  }
90239
90639
  return;
90240
90640
  }
@@ -90937,9 +91337,9 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
90937
91337
  function isMostRecentlyInspectedElementCurrent(id) {
90938
91338
  return isMostRecentlyInspectedElement(id) && !hasElementUpdatedSinceLastInspected;
90939
91339
  }
90940
- function mergeInspectedPaths(path25) {
91340
+ function mergeInspectedPaths(path26) {
90941
91341
  var current = currentlyInspectedPaths;
90942
- path25.forEach(function(key) {
91342
+ path26.forEach(function(key) {
90943
91343
  if (!current[key]) {
90944
91344
  current[key] = {};
90945
91345
  }
@@ -90947,21 +91347,21 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
90947
91347
  });
90948
91348
  }
90949
91349
  function createIsPathAllowed(key, secondaryCategory) {
90950
- return function isPathAllowed(path25) {
91350
+ return function isPathAllowed(path26) {
90951
91351
  switch (secondaryCategory) {
90952
91352
  case "hooks":
90953
- if (path25.length === 1) {
91353
+ if (path26.length === 1) {
90954
91354
  return true;
90955
91355
  }
90956
- if (path25[path25.length - 2] === "hookSource" && path25[path25.length - 1] === "fileName") {
91356
+ if (path26[path26.length - 2] === "hookSource" && path26[path26.length - 1] === "fileName") {
90957
91357
  return true;
90958
91358
  }
90959
- if (path25[path25.length - 1] === "subHooks" || path25[path25.length - 2] === "subHooks") {
91359
+ if (path26[path26.length - 1] === "subHooks" || path26[path26.length - 2] === "subHooks") {
90960
91360
  return true;
90961
91361
  }
90962
91362
  break;
90963
91363
  case "suspendedBy":
90964
- if (path25.length < 5) {
91364
+ if (path26.length < 5) {
90965
91365
  return true;
90966
91366
  }
90967
91367
  break;
@@ -90972,8 +91372,8 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
90972
91372
  if (!current) {
90973
91373
  return false;
90974
91374
  }
90975
- for (var i = 0;i < path25.length; i++) {
90976
- current = current[path25[i]];
91375
+ for (var i = 0;i < path26.length; i++) {
91376
+ current = current[path26[i]];
90977
91377
  if (!current) {
90978
91378
  return false;
90979
91379
  }
@@ -91027,38 +91427,38 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
91027
91427
  break;
91028
91428
  }
91029
91429
  }
91030
- function storeAsGlobal(id, path25, count) {
91430
+ function storeAsGlobal(id, path26, count) {
91031
91431
  if (isMostRecentlyInspectedElement(id)) {
91032
- var value = utils_getInObject(mostRecentlyInspectedElement, path25);
91432
+ var value = utils_getInObject(mostRecentlyInspectedElement, path26);
91033
91433
  var key = "$reactTemp".concat(count);
91034
91434
  window[key] = value;
91035
91435
  console.log(key);
91036
91436
  console.log(value);
91037
91437
  }
91038
91438
  }
91039
- function getSerializedElementValueByPath(id, path25) {
91439
+ function getSerializedElementValueByPath(id, path26) {
91040
91440
  if (isMostRecentlyInspectedElement(id)) {
91041
- var valueToCopy = utils_getInObject(mostRecentlyInspectedElement, path25);
91441
+ var valueToCopy = utils_getInObject(mostRecentlyInspectedElement, path26);
91042
91442
  return serializeToString(valueToCopy);
91043
91443
  }
91044
91444
  }
91045
- function inspectElement(requestID, id, path25, forceFullData) {
91046
- if (path25 !== null) {
91047
- mergeInspectedPaths(path25);
91445
+ function inspectElement(requestID, id, path26, forceFullData) {
91446
+ if (path26 !== null) {
91447
+ mergeInspectedPaths(path26);
91048
91448
  }
91049
91449
  if (isMostRecentlyInspectedElement(id) && !forceFullData) {
91050
91450
  if (!hasElementUpdatedSinceLastInspected) {
91051
- if (path25 !== null) {
91451
+ if (path26 !== null) {
91052
91452
  var secondaryCategory = null;
91053
- if (path25[0] === "hooks" || path25[0] === "suspendedBy") {
91054
- secondaryCategory = path25[0];
91453
+ if (path26[0] === "hooks" || path26[0] === "suspendedBy") {
91454
+ secondaryCategory = path26[0];
91055
91455
  }
91056
91456
  return {
91057
91457
  id,
91058
91458
  responseID: requestID,
91059
91459
  type: "hydrated-path",
91060
- path: path25,
91061
- value: cleanForBridge(utils_getInObject(mostRecentlyInspectedElement, path25), createIsPathAllowed(null, secondaryCategory), path25)
91460
+ path: path26,
91461
+ value: cleanForBridge(utils_getInObject(mostRecentlyInspectedElement, path26), createIsPathAllowed(null, secondaryCategory), path26)
91062
91462
  };
91063
91463
  } else {
91064
91464
  return {
@@ -91254,7 +91654,7 @@ The error thrown in the component is:
91254
91654
  console.groupEnd();
91255
91655
  }
91256
91656
  }
91257
- function deletePath(type, id, hookID, path25) {
91657
+ function deletePath(type, id, hookID, path26) {
91258
91658
  var devtoolsInstance = idToDevToolsInstanceMap.get(id);
91259
91659
  if (devtoolsInstance === undefined) {
91260
91660
  console.warn('Could not find DevToolsInstance with id "'.concat(id, '"'));
@@ -91268,11 +91668,11 @@ The error thrown in the component is:
91268
91668
  var instance2 = fiber.stateNode;
91269
91669
  switch (type) {
91270
91670
  case "context":
91271
- path25 = path25.slice(1);
91671
+ path26 = path26.slice(1);
91272
91672
  switch (fiber.tag) {
91273
91673
  case ClassComponent:
91274
- if (path25.length === 0) {} else {
91275
- deletePathInObject(instance2.context, path25);
91674
+ if (path26.length === 0) {} else {
91675
+ deletePathInObject(instance2.context, path26);
91276
91676
  }
91277
91677
  instance2.forceUpdate();
91278
91678
  break;
@@ -91282,21 +91682,21 @@ The error thrown in the component is:
91282
91682
  break;
91283
91683
  case "hooks":
91284
91684
  if (typeof overrideHookStateDeletePath === "function") {
91285
- overrideHookStateDeletePath(fiber, hookID, path25);
91685
+ overrideHookStateDeletePath(fiber, hookID, path26);
91286
91686
  }
91287
91687
  break;
91288
91688
  case "props":
91289
91689
  if (instance2 === null) {
91290
91690
  if (typeof overridePropsDeletePath === "function") {
91291
- overridePropsDeletePath(fiber, path25);
91691
+ overridePropsDeletePath(fiber, path26);
91292
91692
  }
91293
91693
  } else {
91294
- fiber.pendingProps = copyWithDelete(instance2.props, path25);
91694
+ fiber.pendingProps = copyWithDelete(instance2.props, path26);
91295
91695
  instance2.forceUpdate();
91296
91696
  }
91297
91697
  break;
91298
91698
  case "state":
91299
- deletePathInObject(instance2.state, path25);
91699
+ deletePathInObject(instance2.state, path26);
91300
91700
  instance2.forceUpdate();
91301
91701
  break;
91302
91702
  }
@@ -91351,7 +91751,7 @@ The error thrown in the component is:
91351
91751
  }
91352
91752
  }
91353
91753
  }
91354
- function overrideValueAtPath(type, id, hookID, path25, value) {
91754
+ function overrideValueAtPath(type, id, hookID, path26, value) {
91355
91755
  var devtoolsInstance = idToDevToolsInstanceMap.get(id);
91356
91756
  if (devtoolsInstance === undefined) {
91357
91757
  console.warn('Could not find DevToolsInstance with id "'.concat(id, '"'));
@@ -91365,13 +91765,13 @@ The error thrown in the component is:
91365
91765
  var instance2 = fiber.stateNode;
91366
91766
  switch (type) {
91367
91767
  case "context":
91368
- path25 = path25.slice(1);
91768
+ path26 = path26.slice(1);
91369
91769
  switch (fiber.tag) {
91370
91770
  case ClassComponent:
91371
- if (path25.length === 0) {
91771
+ if (path26.length === 0) {
91372
91772
  instance2.context = value;
91373
91773
  } else {
91374
- utils_setInObject(instance2.context, path25, value);
91774
+ utils_setInObject(instance2.context, path26, value);
91375
91775
  }
91376
91776
  instance2.forceUpdate();
91377
91777
  break;
@@ -91381,18 +91781,18 @@ The error thrown in the component is:
91381
91781
  break;
91382
91782
  case "hooks":
91383
91783
  if (typeof overrideHookState === "function") {
91384
- overrideHookState(fiber, hookID, path25, value);
91784
+ overrideHookState(fiber, hookID, path26, value);
91385
91785
  }
91386
91786
  break;
91387
91787
  case "props":
91388
91788
  switch (fiber.tag) {
91389
91789
  case ClassComponent:
91390
- fiber.pendingProps = copyWithSet(instance2.props, path25, value);
91790
+ fiber.pendingProps = copyWithSet(instance2.props, path26, value);
91391
91791
  instance2.forceUpdate();
91392
91792
  break;
91393
91793
  default:
91394
91794
  if (typeof overrideProps === "function") {
91395
- overrideProps(fiber, path25, value);
91795
+ overrideProps(fiber, path26, value);
91396
91796
  }
91397
91797
  break;
91398
91798
  }
@@ -91400,7 +91800,7 @@ The error thrown in the component is:
91400
91800
  case "state":
91401
91801
  switch (fiber.tag) {
91402
91802
  case ClassComponent:
91403
- utils_setInObject(instance2.state, path25, value);
91803
+ utils_setInObject(instance2.state, path26, value);
91404
91804
  instance2.forceUpdate();
91405
91805
  break;
91406
91806
  }
@@ -91686,14 +92086,14 @@ The error thrown in the component is:
91686
92086
  var trackedPathMatchInstance = null;
91687
92087
  var trackedPathMatchDepth = -1;
91688
92088
  var mightBeOnTrackedPath = false;
91689
- function setTrackedPath(path25) {
91690
- if (path25 === null) {
92089
+ function setTrackedPath(path26) {
92090
+ if (path26 === null) {
91691
92091
  trackedPathMatchFiber = null;
91692
92092
  trackedPathMatchInstance = null;
91693
92093
  trackedPathMatchDepth = -1;
91694
92094
  mightBeOnTrackedPath = false;
91695
92095
  }
91696
- trackedPath = path25;
92096
+ trackedPath = path26;
91697
92097
  }
91698
92098
  function updateTrackedPathStateBeforeMount(fiber, fiberInstance) {
91699
92099
  if (trackedPath === null || !mightBeOnTrackedPath) {
@@ -92457,9 +92857,9 @@ The error thrown in the component is:
92457
92857
  }
92458
92858
  var currentlyInspectedElementID = null;
92459
92859
  var currentlyInspectedPaths = {};
92460
- function mergeInspectedPaths(path25) {
92860
+ function mergeInspectedPaths(path26) {
92461
92861
  var current = currentlyInspectedPaths;
92462
- path25.forEach(function(key) {
92862
+ path26.forEach(function(key) {
92463
92863
  if (!current[key]) {
92464
92864
  current[key] = {};
92465
92865
  }
@@ -92467,13 +92867,13 @@ The error thrown in the component is:
92467
92867
  });
92468
92868
  }
92469
92869
  function createIsPathAllowed(key) {
92470
- return function isPathAllowed(path25) {
92870
+ return function isPathAllowed(path26) {
92471
92871
  var current = currentlyInspectedPaths[key];
92472
92872
  if (!current) {
92473
92873
  return false;
92474
92874
  }
92475
- for (var i = 0;i < path25.length; i++) {
92476
- current = current[path25[i]];
92875
+ for (var i = 0;i < path26.length; i++) {
92876
+ current = current[path26[i]];
92477
92877
  if (!current) {
92478
92878
  return false;
92479
92879
  }
@@ -92523,24 +92923,24 @@ The error thrown in the component is:
92523
92923
  break;
92524
92924
  }
92525
92925
  }
92526
- function storeAsGlobal(id, path25, count) {
92926
+ function storeAsGlobal(id, path26, count) {
92527
92927
  var inspectedElement = inspectElementRaw(id);
92528
92928
  if (inspectedElement !== null) {
92529
- var value = utils_getInObject(inspectedElement, path25);
92929
+ var value = utils_getInObject(inspectedElement, path26);
92530
92930
  var key = "$reactTemp".concat(count);
92531
92931
  window[key] = value;
92532
92932
  console.log(key);
92533
92933
  console.log(value);
92534
92934
  }
92535
92935
  }
92536
- function getSerializedElementValueByPath(id, path25) {
92936
+ function getSerializedElementValueByPath(id, path26) {
92537
92937
  var inspectedElement = inspectElementRaw(id);
92538
92938
  if (inspectedElement !== null) {
92539
- var valueToCopy = utils_getInObject(inspectedElement, path25);
92939
+ var valueToCopy = utils_getInObject(inspectedElement, path26);
92540
92940
  return serializeToString(valueToCopy);
92541
92941
  }
92542
92942
  }
92543
- function inspectElement(requestID, id, path25, forceFullData) {
92943
+ function inspectElement(requestID, id, path26, forceFullData) {
92544
92944
  if (forceFullData || currentlyInspectedElementID !== id) {
92545
92945
  currentlyInspectedElementID = id;
92546
92946
  currentlyInspectedPaths = {};
@@ -92553,8 +92953,8 @@ The error thrown in the component is:
92553
92953
  type: "not-found"
92554
92954
  };
92555
92955
  }
92556
- if (path25 !== null) {
92557
- mergeInspectedPaths(path25);
92956
+ if (path26 !== null) {
92957
+ mergeInspectedPaths(path26);
92558
92958
  }
92559
92959
  updateSelectedElement(id);
92560
92960
  inspectedElement.context = cleanForBridge(inspectedElement.context, createIsPathAllowed("context"));
@@ -92757,10 +93157,10 @@ The error thrown in the component is:
92757
93157
  console.groupEnd();
92758
93158
  }
92759
93159
  }
92760
- function getElementAttributeByPath(id, path25) {
93160
+ function getElementAttributeByPath(id, path26) {
92761
93161
  var inspectedElement = inspectElementRaw(id);
92762
93162
  if (inspectedElement !== null) {
92763
- return utils_getInObject(inspectedElement, path25);
93163
+ return utils_getInObject(inspectedElement, path26);
92764
93164
  }
92765
93165
  return;
92766
93166
  }
@@ -92777,14 +93177,14 @@ The error thrown in the component is:
92777
93177
  }
92778
93178
  return element.type;
92779
93179
  }
92780
- function deletePath(type, id, hookID, path25) {
93180
+ function deletePath(type, id, hookID, path26) {
92781
93181
  var internalInstance = idToInternalInstanceMap.get(id);
92782
93182
  if (internalInstance != null) {
92783
93183
  var publicInstance = internalInstance._instance;
92784
93184
  if (publicInstance != null) {
92785
93185
  switch (type) {
92786
93186
  case "context":
92787
- deletePathInObject(publicInstance.context, path25);
93187
+ deletePathInObject(publicInstance.context, path26);
92788
93188
  forceUpdate(publicInstance);
92789
93189
  break;
92790
93190
  case "hooks":
@@ -92792,12 +93192,12 @@ The error thrown in the component is:
92792
93192
  case "props":
92793
93193
  var element = internalInstance._currentElement;
92794
93194
  internalInstance._currentElement = legacy_renderer_objectSpread(legacy_renderer_objectSpread({}, element), {}, {
92795
- props: copyWithDelete(element.props, path25)
93195
+ props: copyWithDelete(element.props, path26)
92796
93196
  });
92797
93197
  forceUpdate(publicInstance);
92798
93198
  break;
92799
93199
  case "state":
92800
- deletePathInObject(publicInstance.state, path25);
93200
+ deletePathInObject(publicInstance.state, path26);
92801
93201
  forceUpdate(publicInstance);
92802
93202
  break;
92803
93203
  }
@@ -92831,14 +93231,14 @@ The error thrown in the component is:
92831
93231
  }
92832
93232
  }
92833
93233
  }
92834
- function overrideValueAtPath(type, id, hookID, path25, value) {
93234
+ function overrideValueAtPath(type, id, hookID, path26, value) {
92835
93235
  var internalInstance = idToInternalInstanceMap.get(id);
92836
93236
  if (internalInstance != null) {
92837
93237
  var publicInstance = internalInstance._instance;
92838
93238
  if (publicInstance != null) {
92839
93239
  switch (type) {
92840
93240
  case "context":
92841
- utils_setInObject(publicInstance.context, path25, value);
93241
+ utils_setInObject(publicInstance.context, path26, value);
92842
93242
  forceUpdate(publicInstance);
92843
93243
  break;
92844
93244
  case "hooks":
@@ -92846,12 +93246,12 @@ The error thrown in the component is:
92846
93246
  case "props":
92847
93247
  var element = internalInstance._currentElement;
92848
93248
  internalInstance._currentElement = legacy_renderer_objectSpread(legacy_renderer_objectSpread({}, element), {}, {
92849
- props: copyWithSet(element.props, path25, value)
93249
+ props: copyWithSet(element.props, path26, value)
92850
93250
  });
92851
93251
  forceUpdate(publicInstance);
92852
93252
  break;
92853
93253
  case "state":
92854
- utils_setInObject(publicInstance.state, path25, value);
93254
+ utils_setInObject(publicInstance.state, path26, value);
92855
93255
  forceUpdate(publicInstance);
92856
93256
  break;
92857
93257
  }
@@ -92892,7 +93292,7 @@ The error thrown in the component is:
92892
93292
  return [];
92893
93293
  }
92894
93294
  function setTraceUpdatesEnabled(enabled) {}
92895
- function setTrackedPath(path25) {}
93295
+ function setTrackedPath(path26) {}
92896
93296
  function getOwnersList(id) {
92897
93297
  return null;
92898
93298
  }
@@ -95166,6 +95566,7 @@ async function buildPlanModeContext(workdir, fullConfig, options, deps) {
95166
95566
  const branchName = options.branch ?? `feat/${options.feature}`;
95167
95567
  const timeoutSeconds = fullConfig?.plan?.timeoutSeconds ?? DEFAULT_TIMEOUT_SECONDS2;
95168
95568
  const config2 = planConfigSelector.select(fullConfig);
95569
+ const profileName = typeof fullConfig?.profile === "string" && fullConfig.profile ? fullConfig.profile : undefined;
95169
95570
  const runtime = createPlanRuntime(fullConfig, workdir, options.feature);
95170
95571
  const interactionChain = fullConfig ? await deps.initInteractionChain(fullConfig, !process.stdin.isTTY) : null;
95171
95572
  let configuredBridge;
@@ -95193,6 +95594,7 @@ async function buildPlanModeContext(workdir, fullConfig, options, deps) {
95193
95594
  branchName,
95194
95595
  timeoutSeconds,
95195
95596
  config: config2,
95597
+ profileName,
95196
95598
  options,
95197
95599
  runtime,
95198
95600
  interactionChain,
@@ -95241,6 +95643,28 @@ function buildPlanComposition(userStageConfig) {
95241
95643
  // src/plan/strategies/write-prd.ts
95242
95644
  init_errors();
95243
95645
  init_prd();
95646
+
95647
+ // src/plan/strategies/finalize-routing.ts
95648
+ init_agents();
95649
+ function finalizePrdRouting(prd, agentRouting, profileName) {
95650
+ const userStories = prd.userStories.map((story) => {
95651
+ const assignment = resolveAgentAssignment(story.routing?.agentProfileId, agentRouting, story.id);
95652
+ if (!assignment)
95653
+ return story;
95654
+ const routing = {
95655
+ ...story.routing,
95656
+ agent: assignment.agent,
95657
+ agentProfileId: assignment.agentProfileId,
95658
+ profileModelTier: assignment.profileModelTier,
95659
+ initialAgent: story.routing?.initialAgent ?? assignment.agent,
95660
+ initialProfileId: story.routing?.initialProfileId ?? assignment.agentProfileId
95661
+ };
95662
+ return { ...story, routing };
95663
+ });
95664
+ return { ...prd, userStories, routingProfile: profileName ?? "default" };
95665
+ }
95666
+
95667
+ // src/plan/strategies/write-prd.ts
95244
95668
  async function writeOrRecoverPrd(ctx, prd, err) {
95245
95669
  const tryExtractPrd = (value) => {
95246
95670
  if (value === null || typeof value !== "object")
@@ -95259,12 +95683,14 @@ async function writeOrRecoverPrd(ctx, prd, err) {
95259
95683
  };
95260
95684
  if (prd !== null) {
95261
95685
  if (Array.isArray(prd.userStories)) {
95262
- await ctx.deps.writeFile(ctx.outputPath, JSON.stringify({ ...prd, project: ctx.projectName }, null, 2));
95686
+ const finalized = finalizePrdRouting({ ...prd, project: ctx.projectName }, ctx.config.routing?.agents, ctx.profileName);
95687
+ await ctx.deps.writeFile(ctx.outputPath, JSON.stringify(finalized, null, 2));
95263
95688
  return ctx.outputPath;
95264
95689
  }
95265
95690
  const normalizedPrd = tryExtractPrd(prd);
95266
95691
  if (normalizedPrd !== null) {
95267
- await ctx.deps.writeFile(ctx.outputPath, JSON.stringify({ ...normalizedPrd, project: ctx.projectName }, null, 2));
95692
+ const finalized = finalizePrdRouting({ ...normalizedPrd, project: ctx.projectName }, ctx.config.routing?.agents, ctx.profileName);
95693
+ await ctx.deps.writeFile(ctx.outputPath, JSON.stringify(finalized, null, 2));
95268
95694
  return ctx.outputPath;
95269
95695
  }
95270
95696
  }
@@ -95284,7 +95710,8 @@ async function writeOrRecoverPrd(ctx, prd, err) {
95284
95710
  }
95285
95711
  }
95286
95712
  recoveredPrd = recoveredPrd ?? validatePlanOutput(rawContent, ctx.options.feature, ctx.branchName);
95287
- await ctx.deps.writeFile(ctx.outputPath, JSON.stringify({ ...recoveredPrd, project: ctx.projectName }, null, 2));
95713
+ const finalized = finalizePrdRouting({ ...recoveredPrd, project: ctx.projectName }, ctx.config.routing?.agents, ctx.profileName);
95714
+ await ctx.deps.writeFile(ctx.outputPath, JSON.stringify(finalized, null, 2));
95288
95715
  return ctx.outputPath;
95289
95716
  } catch {
95290
95717
  throw err;
@@ -95303,7 +95730,9 @@ var _debatePlanDeps = {
95303
95730
  class DebatePlanStrategy {
95304
95731
  mode = "debate";
95305
95732
  async execute(ctx) {
95306
- const { taskContext, outputFormat } = new PlanPromptBuilder().build(ctx.specContent, ctx.codebaseContext, undefined, ctx.relativePackages, ctx.packageDetails, ctx.config.project);
95733
+ const agentRouting = ctx.config.routing?.agents;
95734
+ const profiles = agentRouting?.enabled === true ? agentRouting.profiles ?? [] : [];
95735
+ const { taskContext, outputFormat } = new PlanPromptBuilder().build(ctx.specContent, ctx.codebaseContext, undefined, ctx.relativePackages, ctx.packageDetails, ctx.config.project, undefined, profiles);
95307
95736
  const planStage = ctx.config.debate?.stages?.plan;
95308
95737
  if (!planStage) {
95309
95738
  throw new NaxError("[plan] debate strategy requires config.debate.stages.plan", "PLAN_DEBATE_STAGE_CONFIG_MISSING", {
@@ -95439,7 +95868,8 @@ class PipelinePlanStrategy {
95439
95868
  if (verdict.outcome !== "passed") {
95440
95869
  throw new NaxError(verdict.specDeltasPath ? `Plan pipeline failed; see ${verdict.specDeltasPath}` : "Plan pipeline failed with no spec-deltas path", "PLAN_CRITIC_BLOCKED", { stage: "plan", specDeltasPath: verdict.specDeltasPath });
95441
95870
  }
95442
- await ctx.deps.writeFile(ctx.outputPath, JSON.stringify({ ...verdict.prd, project: ctx.projectName }, null, 2));
95871
+ const prdToWrite = finalizePrdRouting({ ...verdict.prd, project: ctx.projectName }, ctx.config.routing?.agents, ctx.profileName);
95872
+ await ctx.deps.writeFile(ctx.outputPath, JSON.stringify(prdToWrite, null, 2));
95443
95873
  return ctx.outputPath;
95444
95874
  } finally {
95445
95875
  await ctx.runtime.close().catch(() => {});
@@ -95520,13 +95950,15 @@ class SinglePlanStrategy {
95520
95950
  projectProfile: ctx.config.project
95521
95951
  });
95522
95952
  assertIsValidPrd(prd);
95523
- await ctx.deps.writeFile(ctx.outputPath, JSON.stringify({ ...prd, project: ctx.projectName }, null, 2));
95953
+ const finalized = finalizePrdRouting({ ...prd, project: ctx.projectName }, ctx.config.routing?.agents, ctx.profileName);
95954
+ await ctx.deps.writeFile(ctx.outputPath, JSON.stringify(finalized, null, 2));
95524
95955
  return ctx.outputPath;
95525
95956
  } catch (err) {
95526
95957
  if (ctx.deps.existsSync(ctx.outputPath)) {
95527
95958
  const rawContent = await ctx.deps.readFile(ctx.outputPath);
95528
95959
  const recoveredPrd = validatePlanOutput(rawContent, ctx.options.feature, ctx.branchName);
95529
- await ctx.deps.writeFile(ctx.outputPath, JSON.stringify({ ...recoveredPrd, project: ctx.projectName }, null, 2));
95960
+ const finalizedRecovered = finalizePrdRouting({ ...recoveredPrd, project: ctx.projectName }, ctx.config.routing?.agents, ctx.profileName);
95961
+ await ctx.deps.writeFile(ctx.outputPath, JSON.stringify(finalizedRecovered, null, 2));
95530
95962
  return ctx.outputPath;
95531
95963
  }
95532
95964
  throw err;
@@ -96201,10 +96633,10 @@ init_setup();
96201
96633
  // src/cli/plugins.ts
96202
96634
  init_paths();
96203
96635
  init_loader4();
96204
- import * as path17 from "path";
96636
+ import * as path18 from "path";
96205
96637
  async function pluginsListCommand(config2, workdir, overrideGlobalPluginsDir) {
96206
- const globalPluginsDir = overrideGlobalPluginsDir ?? path17.join(globalConfigDir(), "plugins");
96207
- const projectPluginsDir = path17.join(workdir, ".nax", "plugins");
96638
+ const globalPluginsDir = overrideGlobalPluginsDir ?? path18.join(globalConfigDir(), "plugins");
96639
+ const projectPluginsDir = path18.join(workdir, ".nax", "plugins");
96208
96640
  const configPlugins = config2.plugins || [];
96209
96641
  const registry2 = await loadPlugins(globalPluginsDir, projectPluginsDir, configPlugins, workdir, config2.disabledPlugins);
96210
96642
  const plugins = registry2.plugins;
@@ -96254,10 +96686,10 @@ function formatSource(type, sourcePath) {
96254
96686
  return `built-in (${sourcePath})`;
96255
96687
  }
96256
96688
  if (type === "global") {
96257
- return `global (${path17.basename(sourcePath)})`;
96689
+ return `global (${path18.basename(sourcePath)})`;
96258
96690
  }
96259
96691
  if (type === "project") {
96260
- return `project (${path17.basename(sourcePath)})`;
96692
+ return `project (${path18.basename(sourcePath)})`;
96261
96693
  }
96262
96694
  return `config (${sourcePath})`;
96263
96695
  }
@@ -96572,6 +97004,7 @@ var FIELD_DESCRIPTIONS = {
96572
97004
  "acceptance.testPath": "Path to acceptance test file (relative to feature dir)",
96573
97005
  "acceptance.command": "Override command to run acceptance tests. Use {{FILE}} as placeholder for the test file path (default: 'bun test {{FILE}} --timeout=60000')",
96574
97006
  "acceptance.model": 'Model selector for acceptance generation/refinement LLM calls. Accepts a tier string such as "fast", "balanced", or "powerful", or an explicit object like { agent: "codex", model: "gpt-5.4" }. Default: "fast".',
97007
+ "acceptance.generateModel": 'Model selector specifically for acceptance test generation and criteria refinement LLM calls. When set, overrides acceptance.model for these two operations. Accepts a tier string such as "fast", "balanced", or "powerful", or an explicit object like { agent: "opencode", model: "opencode-go/deepseek-v4-flash" }. Defaults to acceptance.model when not set.',
96575
97008
  "acceptance.refinement": "Enable acceptance criteria refinement step before execution (default: true). Disable to skip refinement and use generated criteria as-is.",
96576
97009
  "acceptance.timeoutMs": "Timeout for acceptance test generation in milliseconds (default: 1800000 = 30 min)",
96577
97010
  context: "Context injection configuration",
@@ -96649,10 +97082,10 @@ function deepDiffConfigs(global2, project, currentPath = []) {
96649
97082
  for (const key of Object.keys(project)) {
96650
97083
  const projectValue = project[key];
96651
97084
  const globalValue = global2[key];
96652
- const path18 = [...currentPath, key];
96653
- const pathStr = path18.join(".");
97085
+ const path19 = [...currentPath, key];
97086
+ const pathStr = path19.join(".");
96654
97087
  if (projectValue !== null && typeof projectValue === "object" && !Array.isArray(projectValue) && globalValue !== null && typeof globalValue === "object" && !Array.isArray(globalValue)) {
96655
- const nestedDiffs = deepDiffConfigs(globalValue, projectValue, path18);
97088
+ const nestedDiffs = deepDiffConfigs(globalValue, projectValue, path19);
96656
97089
  diffs.push(...nestedDiffs);
96657
97090
  } else {
96658
97091
  if (!deepEqual(projectValue, globalValue)) {
@@ -96695,11 +97128,11 @@ init_defaults();
96695
97128
  init_loader();
96696
97129
  import { existsSync as existsSync25 } from "fs";
96697
97130
  import { join as join63 } from "path";
96698
- async function loadConfigFile(path18) {
96699
- if (!existsSync25(path18))
97131
+ async function loadConfigFile(path19) {
97132
+ if (!existsSync25(path19))
96700
97133
  return null;
96701
97134
  try {
96702
- return await Bun.file(path18).json();
97135
+ return await Bun.file(path19).json();
96703
97136
  } catch {
96704
97137
  return null;
96705
97138
  }
@@ -96746,10 +97179,10 @@ async function configCommand(config2, options = {}) {
96746
97179
  console.log(`${"Field".padEnd(40)}${"Project Value".padEnd(20)}Global Value`);
96747
97180
  console.log("\u2500".repeat(80));
96748
97181
  for (const diff2 of diffs) {
96749
- const path18 = diff2.path.padEnd(40);
97182
+ const path19 = diff2.path.padEnd(40);
96750
97183
  const projectVal = formatValueForTable(diff2.projectValue);
96751
97184
  const globalVal = formatValueForTable(diff2.globalValue);
96752
- console.log(`${path18}${projectVal.padEnd(20)}${globalVal}`);
97185
+ console.log(`${path19}${projectVal.padEnd(20)}${globalVal}`);
96753
97186
  const description = FIELD_DESCRIPTIONS[diff2.path];
96754
97187
  if (description) {
96755
97188
  console.log(`${"".padEnd(40)}\u21B3 ${description}`);
@@ -96782,26 +97215,26 @@ function determineConfigSources() {
96782
97215
  project: projectPath && fileExists(projectPath) ? projectPath : null
96783
97216
  };
96784
97217
  }
96785
- function fileExists(path18) {
96786
- return existsSync26(path18);
97218
+ function fileExists(path19) {
97219
+ return existsSync26(path19);
96787
97220
  }
96788
- function displayConfigWithDescriptions(obj, path18, sources, indent = 0) {
97221
+ function displayConfigWithDescriptions(obj, path19, sources, indent = 0) {
96789
97222
  const indentStr = " ".repeat(indent);
96790
- const pathStr = path18.join(".");
97223
+ const pathStr = path19.join(".");
96791
97224
  if (obj === null || obj === undefined || typeof obj !== "object" || Array.isArray(obj)) {
96792
97225
  const description = FIELD_DESCRIPTIONS[pathStr];
96793
97226
  const value = formatValue(obj);
96794
97227
  if (description) {
96795
97228
  console.log(`${indentStr}# ${description}`);
96796
97229
  }
96797
- const key = path18[path18.length - 1] || "";
97230
+ const key = path19[path19.length - 1] || "";
96798
97231
  console.log(`${indentStr}${key}: ${value}`);
96799
97232
  console.log();
96800
97233
  return;
96801
97234
  }
96802
97235
  const entries = Object.entries(obj);
96803
97236
  const objAsRecord = obj;
96804
- const isPromptsSection = path18.join(".") === "prompts";
97237
+ const isPromptsSection = path19.join(".") === "prompts";
96805
97238
  if (isPromptsSection && !objAsRecord.overrides) {
96806
97239
  const description = FIELD_DESCRIPTIONS["prompts.overrides"];
96807
97240
  if (description) {
@@ -96824,7 +97257,7 @@ function displayConfigWithDescriptions(obj, path18, sources, indent = 0) {
96824
97257
  }
96825
97258
  for (let i = 0;i < entries.length; i++) {
96826
97259
  const [key, value] = entries[i];
96827
- const currentPath = [...path18, key];
97260
+ const currentPath = [...path19, key];
96828
97261
  const currentPathStr = currentPath.join(".");
96829
97262
  const description = FIELD_DESCRIPTIONS[currentPathStr];
96830
97263
  if (description) {
@@ -97136,11 +97569,11 @@ init_errors();
97136
97569
  import { mkdir as mkdir11 } from "fs/promises";
97137
97570
  import { basename as basename12, join as join66 } from "path";
97138
97571
  var _rulesCLIDeps = {
97139
- readFile: async (path18) => Bun.file(path18).text(),
97140
- writeFile: async (path18, content) => {
97141
- await Bun.write(path18, content);
97572
+ readFile: async (path19) => Bun.file(path19).text(),
97573
+ writeFile: async (path19, content) => {
97574
+ await Bun.write(path19, content);
97142
97575
  },
97143
- fileExists: async (path18) => Bun.file(path18).exists(),
97576
+ fileExists: async (path19) => Bun.file(path19).exists(),
97144
97577
  globInDir: (dir) => {
97145
97578
  try {
97146
97579
  return [...new Bun.Glob("*.md").scanSync({ cwd: dir })].sort().map((f) => join66(dir, f));
@@ -97148,8 +97581,8 @@ var _rulesCLIDeps = {
97148
97581
  return [];
97149
97582
  }
97150
97583
  },
97151
- mkdir: async (path18) => {
97152
- await mkdir11(path18, { recursive: true });
97584
+ mkdir: async (path19) => {
97585
+ await mkdir11(path19, { recursive: true });
97153
97586
  },
97154
97587
  globCanonicalRuleFiles: (workdir) => {
97155
97588
  try {
@@ -97313,6 +97746,35 @@ async function rulesLintCommand(options) {
97313
97746
  const scopeLabel = roots.length === 1 ? "repo root" : `${roots.length} rule roots`;
97314
97747
  console.log(`[OK] Canonical rules lint passed (${totalRuleFiles} file(s) across ${scopeLabel}).`);
97315
97748
  }
97749
+ // src/cli/resolve-run-profile.ts
97750
+ init_config();
97751
+ init_logger2();
97752
+ async function resolveRunProfileOverride(opts) {
97753
+ if (opts.cliProfile)
97754
+ return opts.cliProfile;
97755
+ if (opts.envProfile)
97756
+ return;
97757
+ const readJson = opts._readJson ?? (async (path19) => {
97758
+ const file3 = Bun.file(path19);
97759
+ if (!await file3.exists())
97760
+ return;
97761
+ return file3.json();
97762
+ });
97763
+ try {
97764
+ const prd = await readJson(opts.prdPath);
97765
+ if (prd && typeof prd.routingProfile === "string" && prd.routingProfile.length > 0) {
97766
+ const name = prd.routingProfile;
97767
+ if (name === "default")
97768
+ return name;
97769
+ const listNames = opts._listProfileNames ?? (async () => (await listProfiles(opts.projectRoot)).map((p) => p.name));
97770
+ const available = await listNames();
97771
+ if (available.includes(name))
97772
+ return name;
97773
+ getSafeLogger()?.warn("run", `PRD was planned with config profile "${name}" but no such profile exists \u2014 continuing with current config resolution`, { storyId: "prd", plannedProfile: name });
97774
+ }
97775
+ } catch {}
97776
+ return;
97777
+ }
97316
97778
  // src/commands/detect.ts
97317
97779
  init_source();
97318
97780
  init_config();
@@ -97328,14 +97790,14 @@ function resolveEffective(detected, configPatterns) {
97328
97790
  return "detected";
97329
97791
  return "none";
97330
97792
  }
97331
- async function loadRawConfig(path18) {
97332
- const f = Bun.file(path18);
97793
+ async function loadRawConfig(path19) {
97794
+ const f = Bun.file(path19);
97333
97795
  if (!await f.exists())
97334
97796
  return {};
97335
97797
  return JSON.parse(await f.text());
97336
97798
  }
97337
- async function writeRawConfig(path18, data) {
97338
- await Bun.write(path18, `${JSON.stringify(data, null, 2)}
97799
+ async function writeRawConfig(path19, data) {
97800
+ await Bun.write(path19, `${JSON.stringify(data, null, 2)}
97339
97801
  `);
97340
97802
  }
97341
97803
  function deepSet(obj, keyPath, value) {
@@ -98043,7 +98505,7 @@ init_prd();
98043
98505
  init_git();
98044
98506
  init_crash_recovery();
98045
98507
  init_story_context();
98046
- import path19 from "path";
98508
+ import path20 from "path";
98047
98509
  var _runnerCompletionDeps = {
98048
98510
  async runAcceptanceLoop(ctx) {
98049
98511
  const { runAcceptanceLoop: runAcceptanceLoop2 } = await Promise.resolve().then(() => (init_acceptance_loop(), exports_acceptance_loop));
@@ -98074,11 +98536,11 @@ async function runCompletionPhase(options) {
98074
98536
  options.statusWriter.setPostRunPhase("acceptance", { status: "running" });
98075
98537
  pipelineEventBus.emit({ type: "postrun:phase:started", phase: "acceptance" });
98076
98538
  const acceptanceTestPaths = options.featureDir ? await Promise.all((await groupStoriesByPackage(options.prd, options.workdir, options.feature, options.config.acceptance.testPath, options.config.project?.language)).map(async (g) => {
98077
- const relativeWorkdir = path19.relative(options.workdir, g.packageDir);
98539
+ const relativeWorkdir = path20.relative(options.workdir, g.packageDir);
98078
98540
  let groupConfig = options.config;
98079
98541
  if (relativeWorkdir && relativeWorkdir !== ".") {
98080
98542
  try {
98081
- groupConfig = await _runnerCompletionDeps.loadConfigForWorkdir(path19.join(options.workdir, ".nax", "config.json"), relativeWorkdir);
98543
+ groupConfig = await _runnerCompletionDeps.loadConfigForWorkdir(path20.join(options.workdir, ".nax", "config.json"), relativeWorkdir);
98082
98544
  } catch (error48) {
98083
98545
  logger?.warn("execution", "Falling back to root config for package acceptance settings", {
98084
98546
  packageDir: g.packageDir,
@@ -103325,8 +103787,8 @@ function Text({ color, backgroundColor, dimColor = false, bold = false, italic =
103325
103787
  }
103326
103788
 
103327
103789
  // node_modules/ink/build/components/ErrorOverview.js
103328
- var cleanupPath = (path25) => {
103329
- return path25?.replace(`file://${cwd()}/`, "");
103790
+ var cleanupPath = (path26) => {
103791
+ return path26?.replace(`file://${cwd()}/`, "");
103330
103792
  };
103331
103793
  var stackUtils = new import_stack_utils.default({
103332
103794
  cwd: cwd(),
@@ -106597,8 +107059,14 @@ program2.command("run").description("Run the orchestration loop for a feature").
106597
107059
  }
106598
107060
  const naxDir = findProjectDir(workdir);
106599
107061
  const cliOverrides = {};
106600
- if (options.profile) {
106601
- cliOverrides.profile = options.profile;
107062
+ const profileOverride = naxDir ? await resolveRunProfileOverride({
107063
+ prdPath: join87(naxDir, "features", options.feature, "prd.json"),
107064
+ projectRoot: workdir,
107065
+ cliProfile: options.profile,
107066
+ envProfile: process.env.NAX_PROFILE
107067
+ }) : options.profile;
107068
+ if (profileOverride) {
107069
+ cliOverrides.profile = profileOverride;
106602
107070
  }
106603
107071
  const config2 = await loadConfig(naxDir ?? undefined, cliOverrides);
106604
107072
  if (!naxDir) {
@@ -107032,8 +107500,8 @@ configProfileCmd.command("current").description("Show the currently active profi
107032
107500
  });
107033
107501
  configProfileCmd.command("create <name>").description("Create a new empty profile").option("-d, --dir <path>", "Project directory", process.cwd()).action(async (name, options) => {
107034
107502
  try {
107035
- const path25 = await profileCreateCommand(name, options.dir);
107036
- console.log(`Created profile at: ${path25}`);
107503
+ const path26 = await profileCreateCommand(name, options.dir);
107504
+ console.log(`Created profile at: ${path26}`);
107037
107505
  } catch (err) {
107038
107506
  console.error(source_default.red(`Error: ${err.message}`));
107039
107507
  process.exit(1);