@nathapp/nax 0.69.9 → 0.70.0-canary.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/nax.js +926 -584
  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();
@@ -17054,9 +17055,57 @@ var init_schemas_infra = __esm(() => {
17054
17055
  retries: exports_external.number().int().min(0, { message: "llm.retries must be >= 0" }).optional(),
17055
17056
  retryDelayMs: exports_external.number().int().min(0, { message: "llm.retryDelayMs must be >= 0" }).optional()
17056
17057
  });
17058
+ AgentRoutingProfileSchema = exports_external.object({
17059
+ id: exports_external.string().min(1),
17060
+ target: exports_external.object({
17061
+ agent: exports_external.string().min(1),
17062
+ model: ModelTierSchema
17063
+ }),
17064
+ strengths: exports_external.array(exports_external.string().min(1)).min(1),
17065
+ weaknesses: exports_external.array(exports_external.string().min(1)).optional(),
17066
+ costTier: exports_external.enum(["low", "medium", "high"]).optional(),
17067
+ affinity: exports_external.object({
17068
+ taskTypes: exports_external.array(exports_external.string().min(1)).optional(),
17069
+ domains: exports_external.array(exports_external.string().min(1)).optional()
17070
+ }).optional()
17071
+ });
17072
+ AgentRoutingConfigSchema = exports_external.object({
17073
+ enabled: exports_external.boolean().default(true),
17074
+ strategy: exports_external.enum(["off", "llm"]).default("off"),
17075
+ default: exports_external.string().optional(),
17076
+ profiles: exports_external.array(AgentRoutingProfileSchema).default([])
17077
+ }).superRefine((cfg, ctx) => {
17078
+ const ids = cfg.profiles.map((p) => p.id);
17079
+ const seen = new Set;
17080
+ for (const [i, id] of ids.entries()) {
17081
+ if (seen.has(id)) {
17082
+ ctx.addIssue({
17083
+ code: "custom",
17084
+ path: ["profiles", i, "id"],
17085
+ message: `Duplicate profile id "${id}"`
17086
+ });
17087
+ }
17088
+ seen.add(id);
17089
+ }
17090
+ if (cfg.default !== undefined && !ids.includes(cfg.default)) {
17091
+ ctx.addIssue({
17092
+ code: "custom",
17093
+ path: ["default"],
17094
+ message: `Default profile "${cfg.default}" is not in the profiles list`
17095
+ });
17096
+ }
17097
+ if (cfg.strategy === "llm" && cfg.profiles.length === 0) {
17098
+ ctx.addIssue({
17099
+ code: "custom",
17100
+ path: ["strategy"],
17101
+ message: 'strategy "llm" requires at least one profile in routing.agents.profiles'
17102
+ });
17103
+ }
17104
+ });
17057
17105
  RoutingConfigSchema = exports_external.object({
17058
17106
  strategy: exports_external.enum(["keyword", "llm"]),
17059
- llm: LlmRoutingConfigSchema.optional()
17107
+ llm: LlmRoutingConfigSchema.optional(),
17108
+ agents: AgentRoutingConfigSchema.default({ enabled: true, strategy: "off", profiles: [] })
17060
17109
  });
17061
17110
  OptimizerConfigSchema = exports_external.object({
17062
17111
  enabled: exports_external.boolean(),
@@ -17313,7 +17362,8 @@ var init_schemas3 = __esm(() => {
17313
17362
  cacheDecisions: true,
17314
17363
  mode: "hybrid",
17315
17364
  timeoutMs: 30000
17316
- }
17365
+ },
17366
+ agents: { enabled: true, strategy: "off", profiles: [] }
17317
17367
  }),
17318
17368
  execution: ExecutionConfigSchema.default({
17319
17369
  maxIterations: 10,
@@ -17618,6 +17668,48 @@ var init_schemas3 = __esm(() => {
17618
17668
  }).refine((data) => data.version === 1, {
17619
17669
  message: "Invalid version: expected 1",
17620
17670
  path: ["version"]
17671
+ }).superRefine((data, ctx) => {
17672
+ const tierOrder = data.autoMode?.escalation?.tierOrder ?? [];
17673
+ const knownAgents = Object.keys(data.models ?? {});
17674
+ for (const [i, rung] of tierOrder.entries()) {
17675
+ if (rung.agent === undefined)
17676
+ continue;
17677
+ if (!knownAgents.includes(rung.agent)) {
17678
+ ctx.addIssue({
17679
+ code: "custom",
17680
+ path: ["autoMode", "escalation", "tierOrder", i, "agent"],
17681
+ message: `Agent "${rung.agent}" is not defined in config.models (known: ${knownAgents.join(", ")})`
17682
+ });
17683
+ } else {
17684
+ const agentTiers = data.models?.[rung.agent] ?? {};
17685
+ if (!(rung.tier in agentTiers)) {
17686
+ ctx.addIssue({
17687
+ code: "custom",
17688
+ path: ["autoMode", "escalation", "tierOrder", i, "tier"],
17689
+ message: `Tier "${rung.tier}" is not defined for agent "${rung.agent}" in config.models`
17690
+ });
17691
+ }
17692
+ }
17693
+ }
17694
+ const profiles = data.routing.agents?.profiles ?? [];
17695
+ for (const [pi, profile] of profiles.entries()) {
17696
+ const { agent: pAgent, model: pModel } = profile.target;
17697
+ const hasMatchingRung = tierOrder.some((r) => r.tier === pModel && r.agent === pAgent);
17698
+ if (!hasMatchingRung) {
17699
+ ctx.addIssue({
17700
+ code: "custom",
17701
+ path: ["routing", "agents", "profiles", pi, "target"],
17702
+ 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.`
17703
+ });
17704
+ }
17705
+ if (!knownAgents.includes(pAgent)) {
17706
+ ctx.addIssue({
17707
+ code: "custom",
17708
+ path: ["routing", "agents", "profiles", pi, "target", "agent"],
17709
+ message: `Profile "${profile.id}" target agent "${pAgent}" is not defined in config.models`
17710
+ });
17711
+ }
17712
+ }
17621
17713
  });
17622
17714
  });
17623
17715
 
@@ -19140,7 +19232,7 @@ var reviewConfigSelector, planConfigSelector, decomposeConfigSelector, rectifyCo
19140
19232
  var init_selectors = __esm(() => {
19141
19233
  reviewConfigSelector = pickSelector("review", "review", "debate", "models", "execution", "project", "quality", "agent");
19142
19234
  planConfigSelector = pickSelector("plan", "plan", "debate", "agent", "project");
19143
- decomposeConfigSelector = pickSelector("decompose", "plan", "agent");
19235
+ decomposeConfigSelector = pickSelector("decompose", "plan", "agent", "routing");
19144
19236
  rectifyConfigSelector = pickSelector("rectify", "execution");
19145
19237
  acceptanceConfigSelector = pickSelector("acceptance", "acceptance");
19146
19238
  acceptanceFixConfigSelector = pickSelector("acceptance-fix", "acceptance", "execution");
@@ -19452,6 +19544,7 @@ __export(exports_config, {
19452
19544
  acceptanceFixConfigSelector: () => acceptanceFixConfigSelector,
19453
19545
  acceptanceConfigSelector: () => acceptanceConfigSelector,
19454
19546
  VALID_TEST_STRATEGIES: () => VALID_TEST_STRATEGIES,
19547
+ TierConfigSchema: () => TierConfigSchema,
19455
19548
  TddConfigSchema: () => TddConfigSchema,
19456
19549
  THREE_SESSION_STRATEGIES: () => THREE_SESSION_STRATEGIES,
19457
19550
  TEST_STRATEGY_GUIDE: () => TEST_STRATEGY_GUIDE,
@@ -19467,12 +19560,15 @@ __export(exports_config, {
19467
19560
  DEFAULT_CONFIG: () => DEFAULT_CONFIG,
19468
19561
  ConfiguredModelSchema: () => ConfiguredModelSchema,
19469
19562
  COMPLEXITY_GUIDE: () => COMPLEXITY_GUIDE,
19563
+ AgentRoutingProfileSchema: () => AgentRoutingProfileSchema,
19564
+ AgentRoutingConfigSchema: () => AgentRoutingConfigSchema,
19470
19565
  AcceptanceConfigSchema: () => AcceptanceConfigSchema,
19471
19566
  AC_QUALITY_RULES: () => AC_QUALITY_RULES
19472
19567
  });
19473
19568
  var init_config = __esm(() => {
19474
19569
  init_schema();
19475
19570
  init_schemas_model();
19571
+ init_schemas_infra();
19476
19572
  init_schemas_debate();
19477
19573
  init_schemas_execution();
19478
19574
  init_loader();
@@ -22826,8 +22922,12 @@ async function _detectLanguageImpl(workdir, pkg) {
22826
22922
  };
22827
22923
  if ("typescript" in allDeps)
22828
22924
  return "typescript";
22925
+ if (await deps.fileExists(join5(workdir, "tsconfig.json")))
22926
+ return "typescript";
22829
22927
  return "javascript";
22830
22928
  }
22929
+ if (await deps.fileExists(join5(workdir, "tsconfig.json")))
22930
+ return "typescript";
22831
22931
  return;
22832
22932
  }
22833
22933
  function detectType(pkg) {
@@ -29883,6 +29983,73 @@ var init_builder = __esm(() => {
29883
29983
  };
29884
29984
  });
29885
29985
 
29986
+ // src/context/greenfield.ts
29987
+ async function gitLsFiles2(workdir) {
29988
+ try {
29989
+ const proc = _greenfieldDeps.spawn(["git", "ls-files"], {
29990
+ cwd: workdir,
29991
+ stdout: "pipe",
29992
+ stderr: "pipe"
29993
+ });
29994
+ const exitCode = await proc.exited;
29995
+ if (exitCode !== 0)
29996
+ return null;
29997
+ const output = await new Response(proc.stdout).text();
29998
+ return output.split(`
29999
+ `).filter(Boolean);
30000
+ } catch {
30001
+ return null;
30002
+ }
30003
+ }
30004
+ async function hasTestFiles(workdir, patterns) {
30005
+ const files = await gitLsFiles2(workdir);
30006
+ if (files !== null) {
30007
+ return files.some((f) => isTestFileByPatterns(f, patterns));
30008
+ }
30009
+ for (const pattern of patterns) {
30010
+ const g = new Bun.Glob(pattern);
30011
+ for await (const path3 of g.scan({ cwd: workdir, onlyFiles: true })) {
30012
+ if (!path3.split("/").some((seg) => IGNORE_DIRS.has(seg))) {
30013
+ return true;
30014
+ }
30015
+ }
30016
+ }
30017
+ return false;
30018
+ }
30019
+ async function isGreenfieldStory(_story, workdir, patterns) {
30020
+ try {
30021
+ return !await hasTestFiles(workdir, patterns ?? DEFAULT_TEST_FILE_PATTERNS);
30022
+ } catch {
30023
+ return false;
30024
+ }
30025
+ }
30026
+ var _greenfieldDeps, IGNORE_DIRS;
30027
+ var init_greenfield = __esm(() => {
30028
+ init_test_runners();
30029
+ _greenfieldDeps = {
30030
+ spawn: Bun.spawn
30031
+ };
30032
+ IGNORE_DIRS = new Set([
30033
+ "node_modules",
30034
+ "dist",
30035
+ ".next",
30036
+ ".nuxt",
30037
+ ".cache",
30038
+ "coverage",
30039
+ "vendor",
30040
+ "__pycache__",
30041
+ ".venv",
30042
+ "venv",
30043
+ ".eggs",
30044
+ "target",
30045
+ ".gradle",
30046
+ "out",
30047
+ "tmp",
30048
+ "temp",
30049
+ ".git"
30050
+ ]);
30051
+ });
30052
+
29886
30053
  // src/context/index.ts
29887
30054
  var init_context = __esm(() => {
29888
30055
  init_feature_resolver();
@@ -29892,6 +30059,7 @@ var init_context = __esm(() => {
29892
30059
  init_engine();
29893
30060
  init_test_scanner();
29894
30061
  init_auto_detect();
30062
+ init_greenfield();
29895
30063
  });
29896
30064
 
29897
30065
  // src/prompts/core/section-accumulator.ts
@@ -34830,36 +34998,40 @@ ${outputFormat}`,
34830
34998
 
34831
34999
  // src/agents/shared/decompose.ts
34832
35000
  function parseDecomposeOutput(output) {
34833
- const jsonMatch = output.match(/```(?:json)?\s*(\[[\s\S]*?\])\s*```/);
34834
- let jsonText = jsonMatch ? jsonMatch[1] : output;
34835
- if (!jsonMatch) {
34836
- const arrayMatch = output.match(/\[[\s\S]*\]/);
34837
- if (arrayMatch) {
34838
- jsonText = arrayMatch[0];
34839
- }
34840
- }
34841
35001
  let parsed;
34842
35002
  try {
34843
- parsed = JSON.parse(jsonText.trim());
35003
+ parsed = parseLLMJson(output);
34844
35004
  } catch (error48) {
34845
- throw new Error(`Failed to parse decompose output as JSON: ${error48.message}
34846
-
34847
- Output:
34848
- ${output.slice(0, 500)}`);
35005
+ throw new NaxError("Failed to parse decompose output as JSON", "DECOMPOSE_PARSE_FAILED", {
35006
+ stage: "decompose",
35007
+ outputSnippet: output.slice(0, 500),
35008
+ cause: error48
35009
+ });
34849
35010
  }
34850
35011
  if (!Array.isArray(parsed)) {
34851
- throw new Error("Decompose output is not an array");
35012
+ throw new NaxError("Decompose output is not an array", "DECOMPOSE_PARSE_FAILED", {
35013
+ stage: "decompose"
35014
+ });
34852
35015
  }
34853
35016
  const stories = parsed.map((item, index) => {
34854
35017
  if (typeof item !== "object" || item === null) {
34855
- throw new Error(`Story at index ${index} is not an object`);
35018
+ throw new NaxError(`Story at index ${index} is not an object`, "DECOMPOSE_PARSE_FAILED", {
35019
+ stage: "decompose",
35020
+ index
35021
+ });
34856
35022
  }
34857
35023
  const record2 = item;
34858
35024
  if (!record2.id || typeof record2.id !== "string") {
34859
- throw new Error(`Story at index ${index} missing valid 'id' field`);
35025
+ throw new NaxError(`Story at index ${index} missing valid 'id' field`, "DECOMPOSE_PARSE_FAILED", {
35026
+ stage: "decompose",
35027
+ index
35028
+ });
34860
35029
  }
34861
35030
  if (!record2.title || typeof record2.title !== "string") {
34862
- throw new Error(`Story ${record2.id} missing valid 'title' field`);
35031
+ throw new NaxError(`Story ${record2.id} missing valid 'title' field`, "DECOMPOSE_PARSE_FAILED", {
35032
+ stage: "decompose",
35033
+ storyId: record2.id
35034
+ });
34863
35035
  }
34864
35036
  return {
34865
35037
  id: record2.id,
@@ -34874,11 +35046,14 @@ ${output.slice(0, 500)}`);
34874
35046
  reasoning: String(record2.reasoning || "No reasoning provided"),
34875
35047
  estimatedLOC: Number(record2.estimatedLOC) || 0,
34876
35048
  risks: Array.isArray(record2.risks) ? record2.risks : [],
34877
- testStrategy: resolveTestStrategy(typeof record2.testStrategy === "string" ? record2.testStrategy : undefined)
35049
+ testStrategy: resolveTestStrategy(typeof record2.testStrategy === "string" ? record2.testStrategy : undefined),
35050
+ agentProfileId: typeof record2.agentProfileId === "string" && record2.agentProfileId.length > 0 ? record2.agentProfileId : undefined
34878
35051
  };
34879
35052
  });
34880
35053
  if (stories.length === 0) {
34881
- throw new Error("Decompose returned empty story array");
35054
+ throw new NaxError("Decompose returned empty story array", "DECOMPOSE_PARSE_FAILED", {
35055
+ stage: "decompose"
35056
+ });
34882
35057
  }
34883
35058
  return stories;
34884
35059
  }
@@ -34889,7 +35064,8 @@ function coerceComplexity(value) {
34889
35064
  return "medium";
34890
35065
  }
34891
35066
  var init_decompose = __esm(() => {
34892
- init_test_strategy();
35067
+ init_config();
35068
+ init_errors();
34893
35069
  });
34894
35070
 
34895
35071
  // src/agents/shared/decompose-prompt.ts
@@ -34928,10 +35104,10 @@ function buildPlanModePromptSync(input) {
34928
35104
  `);
34929
35105
  builder = builder.inputData("Sibling Stories", siblingsSummary);
34930
35106
  }
34931
- return builder.jsonSchema(DECOMPOSE_PLAN_SCHEMA).build();
35107
+ return builder.agentProfiles(input.profiles ?? []).jsonSchema(DECOMPOSE_PLAN_SCHEMA).build();
34932
35108
  }
34933
35109
  function buildSpecModePromptSync(input) {
34934
- return OneShotPromptBuilder.for("decomposer").instructions(SPEC_DECOMPOSE_INSTRUCTIONS).inputData("Codebase Context", input.codebaseContext).inputData("Feature Specification", input.specContent).jsonSchema(DECOMPOSE_SPEC_SCHEMA).build();
35110
+ 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();
34935
35111
  }
34936
35112
  async function buildPlanModePrompt(options) {
34937
35113
  const targetStory = options.targetStory;
@@ -34944,10 +35120,10 @@ async function buildPlanModePrompt(options) {
34944
35120
  `);
34945
35121
  builder = builder.inputData("Sibling Stories", siblingsSummary);
34946
35122
  }
34947
- return builder.jsonSchema(DECOMPOSE_PLAN_SCHEMA).build();
35123
+ return builder.agentProfiles(options.profiles ?? []).jsonSchema(DECOMPOSE_PLAN_SCHEMA).build();
34948
35124
  }
34949
35125
  async function buildSpecModePrompt(options) {
34950
- return OneShotPromptBuilder.for("decomposer").instructions(SPEC_DECOMPOSE_INSTRUCTIONS).inputData("Codebase Context", options.codebaseContext).inputData("Feature Specification", options.specContent).jsonSchema(DECOMPOSE_SPEC_SCHEMA).build();
35126
+ 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();
34951
35127
  }
34952
35128
  var DECOMPOSE_SPEC_SCHEMA, DECOMPOSE_PLAN_SCHEMA, SPEC_DECOMPOSE_INSTRUCTIONS;
34953
35129
  var init_decompose_prompt = __esm(() => {
@@ -34969,7 +35145,8 @@ var init_decompose_prompt = __esm(() => {
34969
35145
  reasoning: "Why this complexity level",
34970
35146
  estimatedLOC: 150,
34971
35147
  risks: ["Risk 1"],
34972
- testStrategy: "test-after"
35148
+ testStrategy: "test-after",
35149
+ agentProfileId: ""
34973
35150
  }
34974
35151
  ]
34975
35152
  };
@@ -34989,7 +35166,8 @@ var init_decompose_prompt = __esm(() => {
34989
35166
  reasoning: "Why this complexity",
34990
35167
  estimatedLOC: 0,
34991
35168
  risks: [],
34992
- testStrategy: "no-test | tdd-simple | three-session-tdd-lite | three-session-tdd | test-after"
35169
+ testStrategy: "no-test | tdd-simple | three-session-tdd-lite | three-session-tdd | test-after",
35170
+ agentProfileId: ""
34993
35171
  }
34994
35172
  ]
34995
35173
  };
@@ -35009,6 +35187,7 @@ For each story, provide:
35009
35187
  11. risks: Array of implementation risks
35010
35188
  12. testStrategy: "no-test" | "test-after" | "tdd-simple" | "three-session-tdd" | "three-session-tdd-lite"
35011
35189
  13. noTestJustification: string (REQUIRED when testStrategy is "no-test" \u2014 explain why tests are unnecessary)
35190
+ 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
35012
35191
 
35013
35192
  ${COMPLEXITY_GUIDE}
35014
35193
 
@@ -35024,11 +35203,15 @@ Consider:
35024
35203
  });
35025
35204
 
35026
35205
  // src/operations/decompose.ts
35027
- var decomposeOp;
35206
+ var _decomposeOpDeps, decomposeOp;
35028
35207
  var init_decompose2 = __esm(() => {
35029
35208
  init_decompose();
35030
35209
  init_decompose_prompt();
35031
35210
  init_config();
35211
+ init_logger2();
35212
+ _decomposeOpDeps = {
35213
+ getSafeLogger
35214
+ };
35032
35215
  decomposeOp = {
35033
35216
  kind: "complete",
35034
35217
  name: "decompose",
@@ -35037,21 +35220,62 @@ var init_decompose2 = __esm(() => {
35037
35220
  config: decomposeConfigSelector,
35038
35221
  model: (_input, ctx) => ctx.config.plan.model,
35039
35222
  timeoutMs: (_input, ctx) => (ctx.config.plan.decomposeTimeoutSeconds ?? ctx.config.plan.timeoutSeconds ?? 600) * 1000,
35040
- build(input, _ctx) {
35223
+ build(input, ctx) {
35224
+ const agentRouting = ctx.config.routing?.agents;
35225
+ const profiles = agentRouting?.enabled === true ? agentRouting.profiles ?? [] : [];
35041
35226
  const prompt = buildDecomposePromptSync({
35042
35227
  specContent: input.specContent,
35043
35228
  codebaseContext: input.codebaseContext,
35044
35229
  targetStory: input.targetStory,
35045
35230
  siblings: input.siblings,
35046
- maxAcCount: input.maxAcCount
35231
+ maxAcCount: input.maxAcCount,
35232
+ profiles
35047
35233
  });
35048
35234
  return {
35049
35235
  role: { id: "role", content: "", overridable: false },
35050
35236
  task: { id: "task", content: prompt, overridable: false }
35051
35237
  };
35052
35238
  },
35053
- parse(output, _input, _ctx) {
35054
- return parseDecomposeOutput(output);
35239
+ parse(output, _input, ctx) {
35240
+ const stories = parseDecomposeOutput(output);
35241
+ const agentRouting = ctx.config.routing?.agents;
35242
+ if (agentRouting?.enabled !== true) {
35243
+ return stories;
35244
+ }
35245
+ const profiles = agentRouting.profiles ?? [];
35246
+ if (profiles.length === 0) {
35247
+ return stories;
35248
+ }
35249
+ const defaultProfile = agentRouting.default ? profiles.find((p) => p.id === agentRouting.default) : undefined;
35250
+ return stories.map((story) => {
35251
+ if (story.agentProfileId) {
35252
+ const profile = profiles.find((p) => p.id === story.agentProfileId);
35253
+ if (profile) {
35254
+ return {
35255
+ ...story,
35256
+ routing: {
35257
+ ...story.routing,
35258
+ agent: profile.target.agent,
35259
+ agentProfileId: profile.id,
35260
+ profileModelTier: profile.target.model
35261
+ }
35262
+ };
35263
+ }
35264
+ _decomposeOpDeps.getSafeLogger()?.warn("decompose", `Story ${story.id} selected unknown agent profile "${story.agentProfileId}" \u2014 falling back to ${defaultProfile ? `default profile "${defaultProfile.id}"` : "no profile"}`, { storyId: story.id, agentProfileId: story.agentProfileId });
35265
+ }
35266
+ if (defaultProfile) {
35267
+ return {
35268
+ ...story,
35269
+ routing: {
35270
+ ...story.routing,
35271
+ agent: defaultProfile.target.agent,
35272
+ agentProfileId: defaultProfile.id,
35273
+ profileModelTier: defaultProfile.target.model
35274
+ }
35275
+ };
35276
+ }
35277
+ return story;
35278
+ });
35055
35279
  }
35056
35280
  };
35057
35281
  });
@@ -35467,6 +35691,7 @@ __export(exports_routing, {
35467
35691
  resolveRouting: () => resolveRouting,
35468
35692
  determineTestStrategy: () => determineTestStrategy,
35469
35693
  complexityToModelTier: () => complexityToModelTier,
35694
+ clearCache: () => clearCache,
35470
35695
  classifyComplexity: () => classifyComplexity,
35471
35696
  _tryLlmBatchRouteDeps: () => _tryLlmBatchRouteDeps,
35472
35697
  ROUTING_INSTRUCTIONS: () => ROUTING_INSTRUCTIONS
@@ -35568,6 +35793,22 @@ ${BATCH_ROUTING_SCHEMA_INLINE}`;
35568
35793
 
35569
35794
  // src/acceptance/test-path.ts
35570
35795
  import path3 from "path";
35796
+ async function _readPackageTestPath(workdir, relativeDir) {
35797
+ if (!relativeDir)
35798
+ return;
35799
+ if (path3.isAbsolute(relativeDir) || relativeDir.split(path3.sep).includes(".."))
35800
+ return;
35801
+ const cfgPath = path3.join(workdir, ".nax", "mono", relativeDir, "config.json");
35802
+ const file3 = Bun.file(cfgPath);
35803
+ if (!await file3.exists())
35804
+ return;
35805
+ try {
35806
+ const cfg = JSON.parse(await file3.text());
35807
+ return cfg?.acceptance?.testPath;
35808
+ } catch {
35809
+ return;
35810
+ }
35811
+ }
35571
35812
  function acceptanceTestFilename(language) {
35572
35813
  switch (language?.toLowerCase()) {
35573
35814
  case "go":
@@ -35617,10 +35858,12 @@ async function groupStoriesByPackage(prd, workdir, featureName, testPathConfig,
35617
35858
  }
35618
35859
  return Promise.all(Array.from(groupMap.entries()).map(async ([wd, { stories, criteria }]) => {
35619
35860
  const packageDir = wd ? path3.join(workdir, wd) : workdir;
35861
+ const pkgTestPath = await _groupDeps.readPackageTestPath(workdir, wd);
35620
35862
  const detectedLang = await _groupDeps.detectLanguage(packageDir);
35621
35863
  const resolvedLang = detectedLang ?? language;
35622
- const testPath = resolveAcceptancePackageFeatureTestPath(packageDir, featureName, testPathConfig, resolvedLang);
35623
- return { testPath, packageDir, stories, criteria };
35864
+ const resolvedTestPathConfig = pkgTestPath ?? testPathConfig;
35865
+ const testPath = resolveAcceptancePackageFeatureTestPath(packageDir, featureName, resolvedTestPathConfig, resolvedLang);
35866
+ return { testPath, packageDir, stories, criteria, language: resolvedLang };
35624
35867
  }));
35625
35868
  }
35626
35869
  function suggestedTestFilename(language) {
@@ -35668,7 +35911,8 @@ var _groupDeps;
35668
35911
  var init_test_path = __esm(() => {
35669
35912
  init_detector();
35670
35913
  _groupDeps = {
35671
- detectLanguage
35914
+ detectLanguage,
35915
+ readPackageTestPath: _readPackageTestPath
35672
35916
  };
35673
35917
  });
35674
35918
 
@@ -38419,73 +38663,6 @@ var init_plan_critic_llm = __esm(() => {
38419
38663
  };
38420
38664
  });
38421
38665
 
38422
- // src/context/greenfield.ts
38423
- async function gitLsFiles2(workdir) {
38424
- try {
38425
- const proc = _greenfieldDeps.spawn(["git", "ls-files"], {
38426
- cwd: workdir,
38427
- stdout: "pipe",
38428
- stderr: "pipe"
38429
- });
38430
- const exitCode = await proc.exited;
38431
- if (exitCode !== 0)
38432
- return null;
38433
- const output = await new Response(proc.stdout).text();
38434
- return output.split(`
38435
- `).filter(Boolean);
38436
- } catch {
38437
- return null;
38438
- }
38439
- }
38440
- async function hasTestFiles(workdir, patterns) {
38441
- const files = await gitLsFiles2(workdir);
38442
- if (files !== null) {
38443
- return files.some((f) => isTestFileByPatterns(f, patterns));
38444
- }
38445
- for (const pattern of patterns) {
38446
- const g = new Bun.Glob(pattern);
38447
- for await (const path5 of g.scan({ cwd: workdir, onlyFiles: true })) {
38448
- if (!path5.split("/").some((seg) => IGNORE_DIRS.has(seg))) {
38449
- return true;
38450
- }
38451
- }
38452
- }
38453
- return false;
38454
- }
38455
- async function isGreenfieldStory(_story, workdir, patterns) {
38456
- try {
38457
- return !await hasTestFiles(workdir, patterns ?? DEFAULT_TEST_FILE_PATTERNS);
38458
- } catch {
38459
- return false;
38460
- }
38461
- }
38462
- var _greenfieldDeps, IGNORE_DIRS;
38463
- var init_greenfield = __esm(() => {
38464
- init_test_runners();
38465
- _greenfieldDeps = {
38466
- spawn: Bun.spawn
38467
- };
38468
- IGNORE_DIRS = new Set([
38469
- "node_modules",
38470
- "dist",
38471
- ".next",
38472
- ".nuxt",
38473
- ".cache",
38474
- "coverage",
38475
- "vendor",
38476
- "__pycache__",
38477
- ".venv",
38478
- "venv",
38479
- ".eggs",
38480
- "target",
38481
- ".gradle",
38482
- "out",
38483
- "tmp",
38484
- "temp",
38485
- ".git"
38486
- ]);
38487
- });
38488
-
38489
38666
  // src/operations/greenfield-gate.ts
38490
38667
  var greenfieldGateConfigSelector, greenfieldGateOp;
38491
38668
  var init_greenfield_gate = __esm(() => {
@@ -42856,9 +43033,59 @@ ${body}`
42856
43033
  this.acc.add(jsonSchemaSection(schema));
42857
43034
  return this;
42858
43035
  }
43036
+ agentProfiles(profiles) {
43037
+ const cards = OneShotPromptBuilder.agentCapabilityCards(profiles);
43038
+ if (cards.length === 0)
43039
+ return this;
43040
+ this.acc.add({
43041
+ id: "agent-profiles",
43042
+ overridable: false,
43043
+ content: `${cards}
43044
+
43045
+ ${OneShotPromptBuilder.agentProfileInstruction()}`
43046
+ });
43047
+ return this;
43048
+ }
42859
43049
  build() {
42860
43050
  return this.acc.join();
42861
43051
  }
43052
+ static agentProfileInstruction() {
43053
+ return [
43054
+ "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:",
43055
+ "1. Eliminate any profile whose weaknesses conflict with the story.",
43056
+ "2. Keep profiles whose strengths or affinity cover the story's main job (task type + primary domain).",
43057
+ "3. If more than one remains, choose the LOWEST cost profile.",
43058
+ "4. If none clearly fit, omit `agentProfileId` entirely \u2014 never invent a profile id."
43059
+ ].join(`
43060
+ `);
43061
+ }
43062
+ static agentCapabilityCards(profiles) {
43063
+ if (profiles.length === 0)
43064
+ return "";
43065
+ const header = [
43066
+ "## Agent Profiles",
43067
+ "",
43068
+ "| ID | Agent | Tier | Strengths | Weaknesses | Affinity | Cost |",
43069
+ "|---|---|---|---|---|---|---|"
43070
+ ];
43071
+ const rows = profiles.map((p) => {
43072
+ const esc2 = OneShotPromptBuilder.escapeCell;
43073
+ const id = esc2(p.id);
43074
+ const agent = esc2(p.target.agent);
43075
+ const model = esc2(p.target.model);
43076
+ const strengths = p.strengths.map(esc2).join(", ");
43077
+ const weaknesses = p.weaknesses?.length ? p.weaknesses.map(esc2).join("; ") : "\u2014";
43078
+ const affinityParts = [...p.affinity?.taskTypes ?? [], ...p.affinity?.domains ?? []];
43079
+ const affinity = affinityParts.length ? affinityParts.map(esc2).join(", ") : "\u2014";
43080
+ const cost = esc2(p.costTier ?? "\u2014");
43081
+ return `| ${id} | ${agent} | ${model} | ${strengths} | ${weaknesses} | ${affinity} | ${cost} |`;
43082
+ });
43083
+ return [...header, ...rows].join(`
43084
+ `);
43085
+ }
43086
+ static escapeCell(value) {
43087
+ return value.replace(/\|/g, "\\|").replace(/\r?\n/g, " ");
43088
+ }
42862
43089
  }
42863
43090
  var init_one_shot_builder = __esm(() => {
42864
43091
  init_core3();
@@ -51554,10 +51781,9 @@ function mapDecomposedStoriesToUserStories(stories, parentStoryId, parentWorkdir
51554
51781
  });
51555
51782
  }
51556
51783
  if (!story.contextFiles || story.contextFiles.length === 0) {
51557
- throw new NaxError(`Entry ${entryIndex} (${story.id}) has empty contextFiles`, "DECOMPOSE_VALIDATION_FAILED", {
51558
- stage: "decompose-mapper",
51559
- entryIndex,
51784
+ getSafeLogger()?.warn("decompose-mapper", `Entry ${entryIndex} (${story.id}) has empty contextFiles \u2014 continuing`, {
51560
51785
  storyId: story.id,
51786
+ entryIndex,
51561
51787
  parentStoryId
51562
51788
  });
51563
51789
  }
@@ -51579,13 +51805,17 @@ function mapDecomposedStoriesToUserStories(stories, parentStoryId, parentWorkdir
51579
51805
  complexity: story.complexity,
51580
51806
  testStrategy: story.testStrategy ?? "test-after",
51581
51807
  reasoning: story.reasoning,
51582
- modelTier: "balanced"
51808
+ modelTier: story.routing?.profileModelTier ?? "balanced",
51809
+ ...story.routing?.agent !== undefined && { agent: story.routing.agent },
51810
+ ...story.routing?.agentProfileId !== undefined && { agentProfileId: story.routing.agentProfileId },
51811
+ ...story.routing?.profileModelTier !== undefined && { profileModelTier: story.routing.profileModelTier }
51583
51812
  }
51584
51813
  };
51585
51814
  });
51586
51815
  }
51587
51816
  var init_decompose_mapper = __esm(() => {
51588
51817
  init_errors();
51818
+ init_logger2();
51589
51819
  });
51590
51820
 
51591
51821
  // src/cli/plan-decompose.ts
@@ -51627,8 +51857,12 @@ async function planDecomposeCommand(workdir, config2, options) {
51627
51857
  const rt = createPlanRuntime(config2, workdir, options.feature);
51628
51858
  const agentManager = rt.agentManager;
51629
51859
  const adapterForCapCheck = agentManager.getAgent(agentName);
51630
- if (!adapterForCapCheck)
51631
- throw new Error(`[decompose] No agent adapter found for '${agentName}'`);
51860
+ if (!adapterForCapCheck) {
51861
+ throw new NaxError(`No agent adapter found for '${agentName}'`, "AGENT_NOT_FOUND", {
51862
+ stage: "decompose",
51863
+ agentName
51864
+ });
51865
+ }
51632
51866
  const timeoutSeconds = config2?.plan?.timeoutSeconds ?? DEFAULT_TIMEOUT_SECONDS2;
51633
51867
  const maxAcCount = config2?.precheck?.storySizeGate?.maxAcCount ?? Number.POSITIVE_INFINITY;
51634
51868
  const maxReplanAttempts = config2?.precheck?.storySizeGate?.maxReplanAttempts ?? 3;
@@ -51640,6 +51874,8 @@ async function planDecomposeCommand(workdir, config2, options) {
51640
51874
  for (let attempt = 0;attempt < maxReplanAttempts; attempt++) {
51641
51875
  if (attempt === 0 && debateDecompEnabled) {
51642
51876
  const decomposeStageConfig = debateStages.decompose;
51877
+ const agentRoutingForDebate = config2.routing?.agents;
51878
+ const profilesForDebate = agentRoutingForDebate?.enabled === true ? agentRoutingForDebate.profiles ?? [] : [];
51643
51879
  const prompt = await buildDecomposePromptAsync({
51644
51880
  specContent: "",
51645
51881
  codebaseContext,
@@ -51648,7 +51884,8 @@ async function planDecomposeCommand(workdir, config2, options) {
51648
51884
  siblings,
51649
51885
  featureName: options.feature,
51650
51886
  storyId: options.storyId,
51651
- maxAcCount: config2?.precheck?.storySizeGate?.maxAcCount
51887
+ maxAcCount: config2?.precheck?.storySizeGate?.maxAcCount,
51888
+ profiles: profilesForDebate
51652
51889
  });
51653
51890
  const decompCallCtx = {
51654
51891
  runtime: rt,
@@ -51721,7 +51958,11 @@ ${repairHint}` : codebaseContext;
51721
51958
  ...subStoriesWithParent,
51722
51959
  ...updatedStories.slice(originalIndex + 1)
51723
51960
  ];
51724
- const updatedPrd = { ...prd, userStories: finalStories };
51961
+ const updatedPrd = {
51962
+ ...prd,
51963
+ userStories: finalStories,
51964
+ routingProfile: config2.profile ?? "default"
51965
+ };
51725
51966
  await _planDeps.writeFile(prdPath, JSON.stringify(updatedPrd, null, 2));
51726
51967
  return () => {};
51727
51968
  }
@@ -52658,6 +52899,103 @@ var init_semantic_verdict = __esm(() => {
52658
52899
  });
52659
52900
 
52660
52901
  // src/acceptance/hardening.ts
52902
+ import path10 from "path";
52903
+ async function processPackageGroup(ctx, packageDir, groupStories, language, result) {
52904
+ const logger = getSafeLogger();
52905
+ const groupRefined = [];
52906
+ for (const story of groupStories) {
52907
+ const callCtx = {
52908
+ runtime: ctx.runtime,
52909
+ packageView: ctx.runtime.packages.resolve(packageDir),
52910
+ packageDir,
52911
+ storyId: story.id,
52912
+ featureName: ctx.prd.feature,
52913
+ agentName: ctx.agentManager.getDefault()
52914
+ };
52915
+ const refined = await _hardeningDeps.callOp(callCtx, acceptanceRefineOp, {
52916
+ criteria: story.suggestedCriteria ?? [],
52917
+ codebaseContext: "",
52918
+ storyId: story.id,
52919
+ testStrategy: ctx.config.acceptance?.testStrategy,
52920
+ testFramework: ctx.config.acceptance?.testFramework,
52921
+ storyTitle: story.title,
52922
+ storyDescription: story.description
52923
+ });
52924
+ groupRefined.push(...refined);
52925
+ }
52926
+ const suggestedTestPath = resolveSuggestedPackageFeatureTestPath(packageDir, ctx.prd.feature, ctx.config.acceptance?.suggestedTestPath, language);
52927
+ const criteriaList = groupRefined.map((c, i) => `AC-${i + 1}: ${c.refined}`).join(`
52928
+ `);
52929
+ const frameworkOverrideLine = ctx.config.acceptance?.testFramework ? `
52930
+ [FRAMEWORK OVERRIDE: Use ${ctx.config.acceptance.testFramework} as the test framework regardless of what you detect.]` : "";
52931
+ const genCallCtx = {
52932
+ runtime: ctx.runtime,
52933
+ packageView: ctx.runtime.packages.resolve(packageDir),
52934
+ packageDir,
52935
+ storyId: groupStories[0]?.id,
52936
+ featureName: ctx.prd.feature,
52937
+ agentName: ctx.agentManager.getDefault()
52938
+ };
52939
+ const genResult = await _hardeningDeps.callOp(genCallCtx, acceptanceGenerateOp, {
52940
+ featureName: ctx.prd.feature,
52941
+ criteriaList,
52942
+ frameworkOverrideLine,
52943
+ targetTestFilePath: suggestedTestPath
52944
+ });
52945
+ let testCode = genResult.testCode;
52946
+ if (!testCode) {
52947
+ const skeletonCriteria = groupRefined.map((c, i) => ({
52948
+ id: `AC-${i + 1}`,
52949
+ text: c.refined,
52950
+ lineNumber: i + 1
52951
+ }));
52952
+ testCode = generateSkeletonTests(ctx.prd.feature, skeletonCriteria, ctx.config.acceptance?.testFramework, language);
52953
+ logger?.warn("acceptance", "Hardening generate op returned no test code \u2014 using skeleton", {
52954
+ storyIds: groupStories.map((s) => s.id),
52955
+ storiesProcessed: groupStories.length
52956
+ });
52957
+ }
52958
+ await _hardeningDeps.writeFile(suggestedTestPath, testCode);
52959
+ const testCmd = buildAcceptanceRunCommand(suggestedTestPath, ctx.config.project?.testFramework, ctx.config.acceptance?.command, packageDir);
52960
+ const proc = _hardeningDeps.spawn(testCmd, { cwd: packageDir, stdout: "pipe", stderr: "pipe" });
52961
+ const [exitCode, stdout, stderr] = await Promise.all([
52962
+ proc.exited,
52963
+ new Response(proc.stdout).text(),
52964
+ new Response(proc.stderr).text()
52965
+ ]);
52966
+ const output = `${stdout}
52967
+ ${stderr}`;
52968
+ const failedACs = parseTestFailures(output);
52969
+ const failedSet = new Set(failedACs.map((ac) => ac.toUpperCase()));
52970
+ const refinedByStory = new Map;
52971
+ for (const r of groupRefined) {
52972
+ const list = refinedByStory.get(r.storyId) ?? [];
52973
+ list.push(r);
52974
+ refinedByStory.set(r.storyId, list);
52975
+ }
52976
+ let acIndex = 0;
52977
+ for (const story of groupStories) {
52978
+ const storyRefined = refinedByStory.get(story.id) ?? [];
52979
+ const toPromote = [];
52980
+ const toDiscard = [];
52981
+ for (const refined of storyRefined) {
52982
+ acIndex++;
52983
+ const acId = `AC-${acIndex}`;
52984
+ if (refined.testable === false || failedSet.has(acId) || exitCode !== 0 && failedACs.length === 0) {
52985
+ toDiscard.push(refined.original);
52986
+ } else {
52987
+ toPromote.push(refined.original);
52988
+ }
52989
+ }
52990
+ if (toPromote.length > 0) {
52991
+ const existingACs = new Set(story.acceptanceCriteria);
52992
+ story.acceptanceCriteria = [...story.acceptanceCriteria, ...toPromote.filter((ac) => !existingACs.has(ac))];
52993
+ result.promoted.push(...toPromote);
52994
+ }
52995
+ result.discarded.push(...toDiscard);
52996
+ story.suggestedCriteria = toDiscard.length > 0 ? toDiscard : undefined;
52997
+ }
52998
+ }
52661
52999
  async function runHardeningPass(ctx) {
52662
53000
  const logger = getSafeLogger();
52663
53001
  const result = { promoted: [], discarded: [] };
@@ -52670,105 +53008,17 @@ async function runHardeningPass(ctx) {
52670
53008
  totalSuggestedACs: storiesWithSuggested.reduce((n, s) => n + (s.suggestedCriteria?.length ?? 0), 0)
52671
53009
  });
52672
53010
  try {
52673
- const allRefined = [];
53011
+ const packageGroups = new Map;
52674
53012
  for (const story of storiesWithSuggested) {
52675
- const criteria = story.suggestedCriteria ?? [];
52676
- const callCtx = {
52677
- runtime: ctx.runtime,
52678
- packageView: ctx.runtime.packages.resolve(ctx.workdir),
52679
- packageDir: ctx.workdir,
52680
- storyId: story.id,
52681
- featureName: ctx.prd.feature,
52682
- agentName: ctx.agentManager.getDefault()
52683
- };
52684
- const refined = await _hardeningDeps.callOp(callCtx, acceptanceRefineOp, {
52685
- criteria,
52686
- codebaseContext: "",
52687
- storyId: story.id,
52688
- testStrategy: ctx.config.acceptance?.testStrategy,
52689
- testFramework: ctx.config.acceptance?.testFramework,
52690
- storyTitle: story.title,
52691
- storyDescription: story.description
52692
- });
52693
- allRefined.push(...refined);
52694
- }
52695
- const language = ctx.config.project?.language;
52696
- const suggestedTestPath = resolveSuggestedPackageFeatureTestPath(ctx.workdir, ctx.prd.feature, ctx.config.acceptance?.suggestedTestPath, language);
52697
- const criteriaList = allRefined.map((c, i) => `AC-${i + 1}: ${c.refined}`).join(`
52698
- `);
52699
- const frameworkOverrideLine = ctx.config.acceptance?.testFramework ? `
52700
- [FRAMEWORK OVERRIDE: Use ${ctx.config.acceptance.testFramework} as the test framework regardless of what you detect.]` : "";
52701
- const genCallCtx = {
52702
- runtime: ctx.runtime,
52703
- packageView: ctx.runtime.packages.resolve(ctx.workdir),
52704
- packageDir: ctx.workdir,
52705
- storyId: storiesWithSuggested[0]?.id,
52706
- featureName: ctx.prd.feature,
52707
- agentName: ctx.agentManager.getDefault()
52708
- };
52709
- const genResult = await _hardeningDeps.callOp(genCallCtx, acceptanceGenerateOp, {
52710
- featureName: ctx.prd.feature,
52711
- criteriaList,
52712
- frameworkOverrideLine,
52713
- targetTestFilePath: suggestedTestPath
52714
- });
52715
- let testCode = genResult.testCode;
52716
- if (!testCode) {
52717
- const skeletonCriteria = allRefined.map((c, i) => ({
52718
- id: `AC-${i + 1}`,
52719
- text: c.refined,
52720
- lineNumber: i + 1
52721
- }));
52722
- testCode = generateSkeletonTests(ctx.prd.feature, skeletonCriteria, ctx.config.acceptance?.testFramework, language);
52723
- logger?.warn("acceptance", "Hardening generate op returned no test code \u2014 using skeleton", {
52724
- storyIds: storiesWithSuggested.map((s) => s.id),
52725
- storiesProcessed: storiesWithSuggested.length
52726
- });
53013
+ const wd = story.workdir ?? "";
53014
+ if (!packageGroups.has(wd))
53015
+ packageGroups.set(wd, []);
53016
+ packageGroups.get(wd)?.push(story);
52727
53017
  }
52728
- await _hardeningDeps.writeFile(suggestedTestPath, testCode);
52729
- const testCmd = buildAcceptanceRunCommand(suggestedTestPath, ctx.config.project?.testFramework, ctx.config.acceptance?.command, ctx.workdir);
52730
- const proc = _hardeningDeps.spawn(testCmd, {
52731
- cwd: ctx.workdir,
52732
- stdout: "pipe",
52733
- stderr: "pipe"
52734
- });
52735
- const [exitCode, stdout, stderr] = await Promise.all([
52736
- proc.exited,
52737
- new Response(proc.stdout).text(),
52738
- new Response(proc.stderr).text()
52739
- ]);
52740
- const output = `${stdout}
52741
- ${stderr}`;
52742
- const failedACs = parseTestFailures(output);
52743
- const failedSet = new Set(failedACs.map((ac) => ac.toUpperCase()));
52744
- const refinedByStory = new Map;
52745
- for (const r of allRefined) {
52746
- const list = refinedByStory.get(r.storyId) ?? [];
52747
- list.push(r);
52748
- refinedByStory.set(r.storyId, list);
52749
- }
52750
- let acIndex = 0;
52751
- for (const story of storiesWithSuggested) {
52752
- const storyRefined = refinedByStory.get(story.id) ?? [];
52753
- const toPromote = [];
52754
- const toDiscard = [];
52755
- for (const refinedCriterion of storyRefined) {
52756
- acIndex++;
52757
- const acId = `AC-${acIndex}`;
52758
- const nonTestable = refinedCriterion.testable === false;
52759
- if (nonTestable || failedSet.has(acId) || exitCode !== 0 && failedACs.length === 0) {
52760
- toDiscard.push(refinedCriterion.original);
52761
- } else {
52762
- toPromote.push(refinedCriterion.original);
52763
- }
52764
- }
52765
- if (toPromote.length > 0) {
52766
- const existingACs = new Set(story.acceptanceCriteria);
52767
- story.acceptanceCriteria = [...story.acceptanceCriteria, ...toPromote.filter((ac) => !existingACs.has(ac))];
52768
- result.promoted.push(...toPromote);
52769
- }
52770
- result.discarded.push(...toDiscard);
52771
- story.suggestedCriteria = toDiscard.length > 0 ? toDiscard : undefined;
53018
+ for (const [wd, groupStories] of packageGroups.entries()) {
53019
+ const packageDir = wd ? path10.join(ctx.workdir, wd) : ctx.workdir;
53020
+ const detectedLang = await _hardeningDeps.detectLanguage(packageDir);
53021
+ await processPackageGroup(ctx, packageDir, groupStories, detectedLang ?? ctx.config.project?.language, result);
52772
53022
  }
52773
53023
  if (result.promoted.length > 0) {
52774
53024
  await _hardeningDeps.savePRD(ctx.prd, ctx.prdPath);
@@ -52793,6 +53043,7 @@ var init_hardening = __esm(() => {
52793
53043
  init_logger2();
52794
53044
  init_operations();
52795
53045
  init_prd();
53046
+ init_detector();
52796
53047
  init_ac_parser();
52797
53048
  init_generator();
52798
53049
  init_test_path();
@@ -52802,7 +53053,8 @@ var init_hardening = __esm(() => {
52802
53053
  spawn: Bun.spawn,
52803
53054
  writeFile: async (p, c) => {
52804
53055
  await Bun.write(p, c);
52805
- }
53056
+ },
53057
+ detectLanguage
52806
53058
  };
52807
53059
  });
52808
53060
 
@@ -53056,7 +53308,7 @@ __export(exports_acceptance_setup, {
53056
53308
  acceptanceSetupStage: () => acceptanceSetupStage,
53057
53309
  _acceptanceSetupDeps: () => _acceptanceSetupDeps
53058
53310
  });
53059
- import path10 from "path";
53311
+ import path11 from "path";
53060
53312
  function computeACFingerprint(criteria) {
53061
53313
  const sorted = [...criteria].sort().join(`
53062
53314
  `);
@@ -53129,7 +53381,7 @@ var init_acceptance_setup = __esm(() => {
53129
53381
  },
53130
53382
  autoCommitIfDirty,
53131
53383
  loadGroupConfig: async (projectDir, relativeWorkdir) => {
53132
- return loadConfigForWorkdir(path10.join(projectDir, ".nax", "config.json"), relativeWorkdir || undefined);
53384
+ return loadConfigForWorkdir(path11.join(projectDir, ".nax", "config.json"), relativeWorkdir || undefined);
53133
53385
  },
53134
53386
  runTest: async (_testPath, _workdir, _cmd) => {
53135
53387
  const cmd = _cmd;
@@ -53173,7 +53425,7 @@ ${stderr}` };
53173
53425
  }
53174
53426
  const language = ctx.config.project?.language;
53175
53427
  const testPathConfig = ctx.config.acceptance.testPath;
53176
- const metaPath = path10.join(ctx.featureDir, "acceptance-meta.json");
53428
+ const metaPath = path11.join(ctx.featureDir, "acceptance-meta.json");
53177
53429
  const allCriteria = ctx.prd.userStories.filter((s) => !s.id.startsWith("US-FIX-") && s.status !== "decomposed").flatMap((s) => s.acceptanceCriteria);
53178
53430
  const featureName = ctx.prd.feature ?? ctx.prd.featureName;
53179
53431
  const groups = await groupStoriesByPackage(ctx.prd, ctx.workdir, featureName, testPathConfig, language);
@@ -53272,7 +53524,7 @@ ${stderr}` };
53272
53524
  text: c.refined,
53273
53525
  lineNumber: i + 1
53274
53526
  }));
53275
- const skeletonCode = generateSkeletonTests(featureName, skeletonCriteria, ctx.config.acceptance.testFramework, language);
53527
+ const skeletonCode = generateSkeletonTests(featureName, skeletonCriteria, ctx.config.acceptance.testFramework, group.language);
53276
53528
  await _acceptanceSetupDeps.writeFile(testPath, skeletonCode);
53277
53529
  getSafeLogger()?.warn("acceptance-setup", "agent did not produce test content; using skeleton", {
53278
53530
  storyId: groupStoryId,
@@ -53288,7 +53540,7 @@ ${stderr}` };
53288
53540
  testable: c.testable,
53289
53541
  storyId: c.storyId
53290
53542
  })), null, 2);
53291
- await _acceptanceSetupDeps.writeFile(path10.join(ctx.featureDir, "acceptance-refined.json"), refinedJsonContent);
53543
+ await _acceptanceSetupDeps.writeFile(path11.join(ctx.featureDir, "acceptance-refined.json"), refinedJsonContent);
53292
53544
  }
53293
53545
  const fingerprint2 = computeACFingerprint(allCriteria);
53294
53546
  await _acceptanceSetupDeps.writeMeta(metaPath, {
@@ -53302,7 +53554,7 @@ ${stderr}` };
53302
53554
  }
53303
53555
  const acceptanceTestPaths = [];
53304
53556
  for (const g of groups) {
53305
- const relativeWorkdir = path10.relative(ctx.projectDir, g.packageDir);
53557
+ const relativeWorkdir = path11.relative(ctx.projectDir, g.packageDir);
53306
53558
  let groupConfig = ctx.config;
53307
53559
  if (relativeWorkdir && relativeWorkdir !== ".") {
53308
53560
  try {
@@ -53871,7 +54123,7 @@ var init_story_context = __esm(() => {
53871
54123
 
53872
54124
  // src/execution/lock.ts
53873
54125
  import { unlink as unlink2 } from "fs/promises";
53874
- import path11 from "path";
54126
+ import path12 from "path";
53875
54127
  function getSafeLogger3() {
53876
54128
  try {
53877
54129
  return getLogger();
@@ -53888,7 +54140,7 @@ function isProcessAlive(pid) {
53888
54140
  }
53889
54141
  }
53890
54142
  async function acquireLock(workdir) {
53891
- const lockPath = path11.join(workdir, "nax.lock");
54143
+ const lockPath = path12.join(workdir, "nax.lock");
53892
54144
  const lockFile = Bun.file(lockPath);
53893
54145
  try {
53894
54146
  const exists = await lockFile.exists();
@@ -53940,7 +54192,7 @@ async function acquireLock(workdir) {
53940
54192
  }
53941
54193
  }
53942
54194
  async function releaseLock(workdir) {
53943
- const lockPath = path11.join(workdir, "nax.lock");
54195
+ const lockPath = path12.join(workdir, "nax.lock");
53944
54196
  try {
53945
54197
  await unlink2(lockPath);
53946
54198
  } catch (error48) {
@@ -55500,6 +55752,16 @@ var init_plan_inputs = __esm(() => {
55500
55752
  });
55501
55753
 
55502
55754
  // src/pipeline/stages/execution-helpers.ts
55755
+ function resolveExecutionAgent(opts) {
55756
+ const { routedAgent, defaultAgent, getAgent } = opts;
55757
+ if (routedAgent !== undefined) {
55758
+ const routed = getAgent(routedAgent);
55759
+ if (routed)
55760
+ return { agentName: routedAgent, agent: routed, degraded: false };
55761
+ return { agentName: defaultAgent, agent: getAgent(defaultAgent), degraded: true };
55762
+ }
55763
+ return { agentName: defaultAgent, agent: getAgent(defaultAgent), degraded: false };
55764
+ }
55503
55765
  function routeTddFailure(failureCategory, isLiteMode, ctx, reviewReason, failureDetail) {
55504
55766
  const buildReason = (category) => {
55505
55767
  const trimmedDetail = failureDetail?.trim();
@@ -55998,6 +56260,7 @@ var init_execution = __esm(() => {
55998
56260
  init_logger2();
55999
56261
  init_git();
56000
56262
  init_execution_helpers();
56263
+ init_execution_helpers();
56001
56264
  RUNTIME_CRASH_CODES = new Set(["CALL_OP_NO_OUTPUT", "CALL_OP_MAX_RETRIES"]);
56002
56265
  executionStage = {
56003
56266
  name: "execution",
@@ -56005,9 +56268,21 @@ var init_execution = __esm(() => {
56005
56268
  async execute(ctx) {
56006
56269
  const logger = getLogger();
56007
56270
  const defaultAgent = ctx.agentManager?.getDefault() ?? "claude";
56008
- const agent = (ctx.agentGetFn ?? _executionDeps.getAgent)(defaultAgent);
56271
+ const resolved = resolveExecutionAgent({
56272
+ routedAgent: ctx.routing.agent,
56273
+ defaultAgent,
56274
+ getAgent: ctx.agentGetFn ?? _executionDeps.getAgent
56275
+ });
56276
+ if (resolved.degraded) {
56277
+ logger.warn("execution", "Routed agent unavailable \u2014 degrading to default agent", {
56278
+ storyId: ctx.story.id,
56279
+ routedAgent: ctx.routing.agent,
56280
+ defaultAgent
56281
+ });
56282
+ }
56283
+ const agent = resolved.agent;
56009
56284
  if (!agent)
56010
- return { action: "fail", reason: `Agent "${defaultAgent}" not found` };
56285
+ return { action: "fail", reason: `Agent "${resolved.agentName}" not found` };
56011
56286
  let effectiveTier = ctx.routing.modelTier;
56012
56287
  if (!_executionDeps.validateAgentForTier(agent, ctx.routing.modelTier)) {
56013
56288
  effectiveTier = agent.capabilities.supportedTiers[0] ?? ctx.routing.modelTier;
@@ -56031,7 +56306,7 @@ var init_execution = __esm(() => {
56031
56306
  runtime: ctx.runtime,
56032
56307
  packageView,
56033
56308
  packageDir: ctx.workdir,
56034
- agentName: ctx.routing.agent ?? defaultAgent,
56309
+ agentName: resolved.agentName,
56035
56310
  storyId: ctx.story.id,
56036
56311
  featureName: ctx.prd.feature,
56037
56312
  story: ctx.story,
@@ -56449,7 +56724,7 @@ function parseQueueFile(content) {
56449
56724
  var init_queue = () => {};
56450
56725
 
56451
56726
  // src/execution/queue-handler.ts
56452
- import path12 from "path";
56727
+ import path13 from "path";
56453
56728
  function getSafeLogger4() {
56454
56729
  try {
56455
56730
  return getLogger();
@@ -56458,8 +56733,8 @@ function getSafeLogger4() {
56458
56733
  }
56459
56734
  }
56460
56735
  async function readQueueFile(workdir) {
56461
- const queuePath = path12.join(workdir, ".queue.txt");
56462
- const processingPath = path12.join(workdir, ".queue.txt.processing");
56736
+ const queuePath = path13.join(workdir, ".queue.txt");
56737
+ const processingPath = path13.join(workdir, ".queue.txt.processing");
56463
56738
  const logger = getSafeLogger4();
56464
56739
  try {
56465
56740
  const file3 = Bun.file(queuePath);
@@ -56484,7 +56759,7 @@ async function readQueueFile(workdir) {
56484
56759
  }
56485
56760
  }
56486
56761
  async function clearQueueFile(workdir) {
56487
- const processingPath = path12.join(workdir, ".queue.txt.processing");
56762
+ const processingPath = path13.join(workdir, ".queue.txt.processing");
56488
56763
  const logger = getSafeLogger4();
56489
56764
  try {
56490
56765
  const file3 = Bun.file(processingPath);
@@ -56562,13 +56837,12 @@ var init_queue_check = __esm(() => {
56562
56837
  // src/pipeline/stages/routing.ts
56563
56838
  var routingStage, _routingDeps;
56564
56839
  var init_routing2 = __esm(() => {
56565
- init_test_runners();
56566
- init_paths3();
56567
- init_greenfield();
56840
+ init_context();
56568
56841
  init_logger2();
56569
56842
  init_prd();
56570
56843
  init_routing();
56571
- init_llm();
56844
+ init_test_runners();
56845
+ init_paths3();
56572
56846
  routingStage = {
56573
56847
  name: "routing",
56574
56848
  enabled: () => true,
@@ -56580,26 +56854,35 @@ var init_routing2 = __esm(() => {
56580
56854
  const decision = await _routingDeps.resolveRouting(ctx.story, ctx.config, ctx.plugins, ctx);
56581
56855
  const TIER_RANK = { fast: 0, balanced: 1, powerful: 2 };
56582
56856
  const derivedTier = decision.modelTier;
56857
+ const profileTier = ctx.story.routing?.profileModelTier;
56858
+ const candidateTier = profileTier ?? derivedTier;
56859
+ const candidateRank = TIER_RANK[candidateTier];
56583
56860
  const previousTier = ctx.story.routing?.modelTier;
56584
56861
  const previousRank = previousTier !== undefined ? TIER_RANK[previousTier] : undefined;
56585
- const derivedRank = TIER_RANK[derivedTier];
56586
- if (previousTier !== undefined && previousRank === undefined) {
56862
+ const hasEscalationRecords = (ctx.story.escalations?.length ?? 0) > 0;
56863
+ if (previousTier !== undefined && previousRank === undefined && !hasEscalationRecords) {
56587
56864
  logger?.warn("routing", "Ignoring unknown previousTier \u2014 not escalating", {
56588
56865
  storyId: ctx.story.id,
56589
56866
  previousTier,
56590
- derivedTier
56867
+ candidateTier
56591
56868
  });
56592
56869
  }
56593
- const isEscalated = previousTier !== undefined && previousRank !== undefined && derivedRank !== undefined && previousRank > derivedRank;
56594
- const modelTier = isEscalated ? previousTier : derivedTier;
56595
- const routing = { ...decision, modelTier, agent: ctx.story.routing?.agent };
56870
+ const isEscalated = previousTier !== undefined && (previousRank !== undefined && candidateRank !== undefined ? previousRank > candidateRank : hasEscalationRecords);
56871
+ const modelTier = isEscalated ? previousTier : candidateTier;
56872
+ const routing = { ...decision, modelTier, agent: ctx.story.routing?.agent ?? decision.agent };
56873
+ const neverEscalated = !hasEscalationRecords;
56874
+ const initialAgent = ctx.story.routing?.initialAgent ?? (neverEscalated ? routing.agent : undefined);
56875
+ const initialProfileId = ctx.story.routing?.initialProfileId ?? (neverEscalated ? ctx.story.routing?.agentProfileId : undefined);
56596
56876
  ctx.story.routing = {
56597
56877
  ...ctx.story.routing ?? {},
56598
56878
  complexity: routing.complexity,
56599
56879
  initialComplexity: ctx.story.routing?.initialComplexity ?? routing.complexity,
56600
56880
  testStrategy: routing.testStrategy,
56601
56881
  reasoning: routing.reasoning ?? "",
56602
- modelTier: routing.modelTier
56882
+ modelTier: routing.modelTier,
56883
+ ...routing.agent !== undefined && { agent: routing.agent },
56884
+ ...initialAgent !== undefined && { initialAgent },
56885
+ ...initialProfileId !== undefined && { initialProfileId }
56603
56886
  };
56604
56887
  if (ctx.prdPath) {
56605
56888
  await _routingDeps.savePRD(ctx.prd, ctx.prdPath);
@@ -56629,13 +56912,13 @@ var init_routing2 = __esm(() => {
56629
56912
  }
56630
56913
  ctx.routing = routing;
56631
56914
  logger.debug("routing", "Task classified", {
56915
+ storyId: ctx.story.id,
56632
56916
  complexity: ctx.routing.complexity,
56633
56917
  modelTier: ctx.routing.modelTier,
56634
- testStrategy: ctx.routing.testStrategy,
56635
- storyId: ctx.story.id
56918
+ testStrategy: ctx.routing.testStrategy
56636
56919
  });
56637
56920
  if (ctx.stories.length === 1) {
56638
- logger.debug("routing", "Routing reasoning", { reasoning: ctx.routing.reasoning, storyId: ctx.story.id });
56921
+ logger.debug("routing", "Routing reasoning", { storyId: ctx.story.id, reasoning: ctx.routing.reasoning });
56639
56922
  }
56640
56923
  return { action: "continue" };
56641
56924
  }
@@ -56707,6 +56990,7 @@ var init_pipeline = __esm(() => {
56707
56990
  init_runner4();
56708
56991
  init_events();
56709
56992
  init_stages();
56993
+ init_execution_helpers();
56710
56994
  init_event_bus();
56711
56995
  });
56712
56996
 
@@ -57113,11 +57397,11 @@ __export(exports_init_context, {
57113
57397
  _initContextDeps: () => _initContextDeps
57114
57398
  });
57115
57399
  import { basename as basename9, join as join52 } from "path";
57116
- async function bunFileExists(path13) {
57117
- return Bun.file(path13).exists();
57400
+ async function bunFileExists(path14) {
57401
+ return Bun.file(path14).exists();
57118
57402
  }
57119
- async function bunMkdirp(path13) {
57120
- const proc = Bun.spawn(["mkdir", "-p", path13]);
57403
+ async function bunMkdirp(path14) {
57404
+ const proc = Bun.spawn(["mkdir", "-p", path14]);
57121
57405
  await proc.exited;
57122
57406
  }
57123
57407
  async function findFiles(dir, maxFiles = 200) {
@@ -57183,8 +57467,8 @@ async function detectEntryPoints(projectRoot) {
57183
57467
  const candidates = ["src/index.ts", "src/main.ts", "main.go", "src/lib.rs"];
57184
57468
  const found = [];
57185
57469
  for (const candidate of candidates) {
57186
- const path13 = join52(projectRoot, candidate);
57187
- if (await bunFileExists(path13)) {
57470
+ const path14 = join52(projectRoot, candidate);
57471
+ if (await bunFileExists(path14)) {
57188
57472
  found.push(candidate);
57189
57473
  }
57190
57474
  }
@@ -57194,8 +57478,8 @@ async function detectConfigFiles(projectRoot) {
57194
57478
  const candidates = ["tsconfig.json", "biome.json", "turbo.json", ".env.example"];
57195
57479
  const found = [];
57196
57480
  for (const candidate of candidates) {
57197
- const path13 = join52(projectRoot, candidate);
57198
- if (await bunFileExists(path13)) {
57481
+ const path14 = join52(projectRoot, candidate);
57482
+ if (await bunFileExists(path14)) {
57199
57483
  found.push(candidate);
57200
57484
  }
57201
57485
  }
@@ -57981,10 +58265,10 @@ var init_setup_analyze = __esm(() => {
57981
58265
  init_workspace();
57982
58266
  CANONICAL_SCRIPTS = ["build", "test", "lint", "type-check", "lint:fix"];
57983
58267
  _analyzeRepoDeps = {
57984
- fileExists: async (path13) => Bun.file(path13).exists(),
57985
- readJson: async (path13) => {
58268
+ fileExists: async (path14) => Bun.file(path14).exists(),
58269
+ readJson: async (path14) => {
57986
58270
  try {
57987
- const f = Bun.file(path13);
58271
+ const f = Bun.file(path14);
57988
58272
  if (!await f.exists())
57989
58273
  return null;
57990
58274
  return JSON.parse(await f.text());
@@ -58039,9 +58323,9 @@ async function fillScripts(workdir, analysis) {
58039
58323
  var TYPE_CHECK_KEY = "type-check", TYPE_CHECK_SCRIPT = "tsc --noEmit -p tsconfig.json", TYPE_CHECK_TURBO_PASSTHROUGH = "turbo run type-check", _fillScriptsDeps;
58040
58324
  var init_setup_fill = __esm(() => {
58041
58325
  _fillScriptsDeps = {
58042
- readJson: async (path13) => {
58326
+ readJson: async (path14) => {
58043
58327
  try {
58044
- const f = Bun.file(path13);
58328
+ const f = Bun.file(path14);
58045
58329
  if (!await f.exists())
58046
58330
  return null;
58047
58331
  return JSON.parse(await f.text());
@@ -58049,8 +58333,8 @@ var init_setup_fill = __esm(() => {
58049
58333
  return null;
58050
58334
  }
58051
58335
  },
58052
- writeFile: async (path13, content) => {
58053
- await Bun.write(path13, content);
58336
+ writeFile: async (path14, content) => {
58337
+ await Bun.write(path14, content);
58054
58338
  }
58055
58339
  };
58056
58340
  });
@@ -58171,10 +58455,10 @@ var init_setup = __esm(() => {
58171
58455
  },
58172
58456
  generateSetupPlan: (ctx, analysis) => generateSetupPlan(ctx, analysis),
58173
58457
  runGate: (workdir, config2) => runSetupGate(workdir, config2),
58174
- fileExists: (path13) => Bun.file(path13).exists(),
58175
- writeFile: (path13, content) => Bun.write(path13, content).then(() => {}),
58176
- mkdir: async (path13) => {
58177
- const proc = Bun.spawn(["mkdir", "-p", path13]);
58458
+ fileExists: (path14) => Bun.file(path14).exists(),
58459
+ writeFile: (path14, content) => Bun.write(path14, content).then(() => {}),
58460
+ mkdir: async (path14) => {
58461
+ const proc = Bun.spawn(["mkdir", "-p", path14]);
58178
58462
  await proc.exited;
58179
58463
  },
58180
58464
  stdout: (msg) => {
@@ -58189,7 +58473,7 @@ var init_setup = __esm(() => {
58189
58473
  });
58190
58474
 
58191
58475
  // src/plugins/builtin/curator/collect.ts
58192
- import * as path13 from "path";
58476
+ import * as path14 from "path";
58193
58477
  function now() {
58194
58478
  return new Date().toISOString();
58195
58479
  }
@@ -58239,7 +58523,7 @@ function tokenCount(story) {
58239
58523
  }
58240
58524
  async function collectFromMetrics(context) {
58241
58525
  const observations = [];
58242
- const metricsPath = path13.join(context.outputDir, "metrics.json");
58526
+ const metricsPath = path14.join(context.outputDir, "metrics.json");
58243
58527
  try {
58244
58528
  const data = await readJsonFile(metricsPath);
58245
58529
  const runs = Array.isArray(data) ? data : [data];
@@ -58289,11 +58573,11 @@ function findingMessage(finding) {
58289
58573
  }
58290
58574
  async function collectFromReviewAudit(context) {
58291
58575
  const observations = [];
58292
- const auditDir = path13.join(context.outputDir, "review-audit");
58576
+ const auditDir = path14.join(context.outputDir, "review-audit");
58293
58577
  try {
58294
58578
  const glob = new Bun.Glob("**/*.json");
58295
58579
  for await (const file3 of glob.scan({ cwd: auditDir, absolute: false })) {
58296
- const fullPath = path13.join(auditDir, file3);
58580
+ const fullPath = path14.join(auditDir, file3);
58297
58581
  try {
58298
58582
  const audit = asRecord3(await readJsonFile(fullPath));
58299
58583
  if (!audit)
@@ -58333,11 +58617,11 @@ async function collectFromReviewAudit(context) {
58333
58617
  }
58334
58618
  async function collectFromContextManifests(context) {
58335
58619
  const observations = [];
58336
- const featuresDir = path13.join(context.workdir, ".nax", "features");
58620
+ const featuresDir = path14.join(context.workdir, ".nax", "features");
58337
58621
  try {
58338
58622
  const glob = new Bun.Glob("*/stories/*/context-manifest-*.json");
58339
58623
  for await (const file3 of glob.scan({ cwd: featuresDir, absolute: false })) {
58340
- const fullPath = path13.join(featuresDir, file3);
58624
+ const fullPath = path14.join(featuresDir, file3);
58341
58625
  try {
58342
58626
  const parts = file3.split("/");
58343
58627
  const featureId = parts[0] ?? context.feature;
@@ -58890,10 +59174,10 @@ function renderProposals(proposals, runId, observationCount) {
58890
59174
 
58891
59175
  // src/plugins/builtin/curator/rollup.ts
58892
59176
  import { appendFile as appendFile3, mkdir as mkdir9, writeFile } from "fs/promises";
58893
- import * as path14 from "path";
59177
+ import * as path15 from "path";
58894
59178
  async function appendToRollup(observations, rollupPath) {
58895
59179
  try {
58896
- const dir = path14.dirname(rollupPath);
59180
+ const dir = path15.dirname(rollupPath);
58897
59181
  await mkdir9(dir, { recursive: true });
58898
59182
  if (observations.length === 0) {
58899
59183
  const f = Bun.file(rollupPath);
@@ -58912,7 +59196,7 @@ var init_rollup = () => {};
58912
59196
 
58913
59197
  // src/plugins/builtin/curator/index.ts
58914
59198
  import { mkdir as mkdir10 } from "fs/promises";
58915
- import * as path15 from "path";
59199
+ import * as path16 from "path";
58916
59200
  function getCuratorEnabled(context) {
58917
59201
  const cfg = context.config;
58918
59202
  if (!cfg)
@@ -58985,7 +59269,7 @@ var init_curator = __esm(() => {
58985
59269
  const observations = await collectObservations(curatorContext);
58986
59270
  if (context.outputDir) {
58987
59271
  const { observationsPath, rollupPath } = resolveCuratorOutputs(curatorContext);
58988
- const runDir = path15.dirname(observationsPath);
59272
+ const runDir = path16.dirname(observationsPath);
58989
59273
  await mkdir10(runDir, { recursive: true });
58990
59274
  await Bun.write(observationsPath, observations.map((o) => JSON.stringify(o)).join(`
58991
59275
  `) + (observations.length > 0 ? `
@@ -58993,7 +59277,7 @@ var init_curator = __esm(() => {
58993
59277
  const thresholds = getCuratorThresholds(context);
58994
59278
  const proposals = runHeuristics(observations, thresholds);
58995
59279
  const markdown = renderProposals(proposals, context.runId, observations.length);
58996
- const proposalsMdPath = path15.join(runDir, "curator-proposals.md");
59280
+ const proposalsMdPath = path16.join(runDir, "curator-proposals.md");
58997
59281
  await Bun.write(proposalsMdPath, markdown);
58998
59282
  await appendToRollup(observations, rollupPath);
58999
59283
  }
@@ -59363,14 +59647,14 @@ var init_validator = __esm(() => {
59363
59647
 
59364
59648
  // src/plugins/loader.ts
59365
59649
  import * as fs from "fs/promises";
59366
- import * as path16 from "path";
59650
+ import * as path17 from "path";
59367
59651
  function getSafeLogger6() {
59368
59652
  return getSafeLogger();
59369
59653
  }
59370
59654
  function extractPluginName(pluginPath) {
59371
- const basename11 = path16.basename(pluginPath);
59655
+ const basename11 = path17.basename(pluginPath);
59372
59656
  if (basename11 === "index.ts" || basename11 === "index.js" || basename11 === "index.mjs") {
59373
- return path16.basename(path16.dirname(pluginPath));
59657
+ return path17.basename(path17.dirname(pluginPath));
59374
59658
  }
59375
59659
  return basename11.replace(/\.(ts|js|mjs)$/, "");
59376
59660
  }
@@ -59456,7 +59740,7 @@ async function discoverPlugins(dir, isTestFileFn) {
59456
59740
  try {
59457
59741
  const entries = await fs.readdir(dir, { withFileTypes: true });
59458
59742
  for (const entry of entries) {
59459
- const fullPath = path16.join(dir, entry.name);
59743
+ const fullPath = path17.join(dir, entry.name);
59460
59744
  if (entry.isFile()) {
59461
59745
  if (isPluginFile(entry.name, isTestFileFn)) {
59462
59746
  discovered.push({ path: fullPath });
@@ -59464,7 +59748,7 @@ async function discoverPlugins(dir, isTestFileFn) {
59464
59748
  } else if (entry.isDirectory()) {
59465
59749
  const indexPaths = ["index.ts", "index.js", "index.mjs"];
59466
59750
  for (const indexFile of indexPaths) {
59467
- const indexPath = path16.join(fullPath, indexFile);
59751
+ const indexPath = path17.join(fullPath, indexFile);
59468
59752
  try {
59469
59753
  await fs.access(indexPath);
59470
59754
  discovered.push({ path: indexPath });
@@ -59489,13 +59773,13 @@ function isPluginFile(filename, isTestFileFn) {
59489
59773
  return !FALLBACK_TEST_FILE_RE.test(filename);
59490
59774
  }
59491
59775
  function resolveModulePath(modulePath, projectRoot) {
59492
- if (path16.isAbsolute(modulePath) || !modulePath.startsWith("./") && !modulePath.startsWith("../")) {
59776
+ if (path17.isAbsolute(modulePath) || !modulePath.startsWith("./") && !modulePath.startsWith("../")) {
59493
59777
  return modulePath;
59494
59778
  }
59495
59779
  if (projectRoot) {
59496
- return path16.resolve(projectRoot, modulePath);
59780
+ return path17.resolve(projectRoot, modulePath);
59497
59781
  }
59498
- return path16.resolve(modulePath);
59782
+ return path17.resolve(modulePath);
59499
59783
  }
59500
59784
  async function loadAndValidatePlugin(initialModulePath, config2, allowedRoots = [], originalPath) {
59501
59785
  let attemptedPath = initialModulePath;
@@ -59811,7 +60095,7 @@ var package_default;
59811
60095
  var init_package = __esm(() => {
59812
60096
  package_default = {
59813
60097
  name: "@nathapp/nax",
59814
- version: "0.69.9",
60098
+ version: "0.70.0-canary.1",
59815
60099
  description: "AI Coding Agent Orchestrator \u2014 loops until done",
59816
60100
  type: "module",
59817
60101
  bin: {
@@ -59906,8 +60190,8 @@ var init_version = __esm(() => {
59906
60190
  NAX_VERSION = package_default.version;
59907
60191
  NAX_COMMIT = (() => {
59908
60192
  try {
59909
- if (/^[0-9a-f]{6,10}$/.test("03eecdb1"))
59910
- return "03eecdb1";
60193
+ if (/^[0-9a-f]{6,10}$/.test("f895b7d3"))
60194
+ return "f895b7d3";
59911
60195
  } catch {}
59912
60196
  try {
59913
60197
  const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
@@ -60293,7 +60577,7 @@ async function readSourceFileContent(filePath, workdir) {
60293
60577
  var MAX_SOURCE_FILES = 5, MAX_FILE_LINES2 = 500;
60294
60578
 
60295
60579
  // src/execution/lifecycle/acceptance-helpers.ts
60296
- import path18 from "path";
60580
+ import path19 from "path";
60297
60581
  function isStubTestFile(content) {
60298
60582
  return isStubTestContent(content);
60299
60583
  }
@@ -60312,7 +60596,7 @@ function isTestLevelFailure(failedACs, totalACs, semanticVerdicts) {
60312
60596
  async function loadSpecContent(featureDir) {
60313
60597
  if (!featureDir)
60314
60598
  return "";
60315
- const specPath = path18.join(featureDir, "spec.md");
60599
+ const specPath = path19.join(featureDir, "spec.md");
60316
60600
  const specFile = Bun.file(specPath);
60317
60601
  return await specFile.exists() ? await specFile.text() : "";
60318
60602
  }
@@ -60332,7 +60616,7 @@ async function loadAcceptanceTestContent2(featureDir, testPaths, configuredTestP
60332
60616
  }
60333
60617
  if (!configuredTestPath)
60334
60618
  return [];
60335
- const resolvedPath = path18.join(featureDir, configuredTestPath);
60619
+ const resolvedPath = path19.join(featureDir, configuredTestPath);
60336
60620
  const testFile = Bun.file(resolvedPath);
60337
60621
  const content = await testFile.exists() ? await testFile.text() : "";
60338
60622
  return [{ content, path: resolvedPath }];
@@ -60349,7 +60633,7 @@ async function regenerateAcceptanceTest(testPath, acceptanceContext) {
60349
60633
  const { unlink: unlink3 } = await import("fs/promises");
60350
60634
  await unlink3(testPath);
60351
60635
  if (acceptanceContext.featureDir) {
60352
- const metaPath = path18.join(acceptanceContext.featureDir, "acceptance-meta.json");
60636
+ const metaPath = path19.join(acceptanceContext.featureDir, "acceptance-meta.json");
60353
60637
  try {
60354
60638
  await unlink3(metaPath);
60355
60639
  } catch {}
@@ -60363,7 +60647,7 @@ async function regenerateAcceptanceTest(testPath, acceptanceContext) {
60363
60647
  const changedFilesRaw = diffOutput.split(`
60364
60648
  `).map((f) => f.trim()).filter((f) => f.length > 0);
60365
60649
  const repoRoot = acceptanceContext.projectDir ?? workdir;
60366
- const packageDir = acceptanceContext.story.workdir && acceptanceContext.projectDir ? path18.join(acceptanceContext.projectDir, acceptanceContext.story.workdir) : undefined;
60650
+ const packageDir = acceptanceContext.story.workdir && acceptanceContext.projectDir ? path19.join(acceptanceContext.projectDir, acceptanceContext.story.workdir) : undefined;
60367
60651
  const ignoreMatchers = acceptanceContext.naxIgnoreIndex?.getMatchers(packageDir) ?? await resolveNaxIgnorePatterns(repoRoot, packageDir);
60368
60652
  const changedFiles = filterNaxInternalPaths(changedFilesRaw, ignoreMatchers);
60369
60653
  const MAX_BYTES = 51200;
@@ -60372,7 +60656,7 @@ async function regenerateAcceptanceTest(testPath, acceptanceContext) {
60372
60656
  for (const file3 of changedFiles) {
60373
60657
  if (totalBytes >= MAX_BYTES)
60374
60658
  break;
60375
- const filePath = path18.join(workdir, file3);
60659
+ const filePath = path19.join(workdir, file3);
60376
60660
  try {
60377
60661
  const fileContent = await _regenerateDeps.readFile(filePath);
60378
60662
  const remaining = MAX_BYTES - totalBytes;
@@ -60831,9 +61115,9 @@ var init_scratch_purge = __esm(() => {
60831
61115
  return [];
60832
61116
  }
60833
61117
  },
60834
- fileExists: (path19) => Bun.file(path19).exists(),
60835
- readFile: (path19) => Bun.file(path19).text(),
60836
- remove: (path19) => rm(path19, { recursive: true, force: true }),
61118
+ fileExists: (path20) => Bun.file(path20).exists(),
61119
+ readFile: (path20) => Bun.file(path20).text(),
61120
+ remove: (path20) => rm(path20, { recursive: true, force: true }),
60837
61121
  move: async (src, dest) => {
60838
61122
  await mkdir12(dirname12(dest), { recursive: true });
60839
61123
  await rename(src, dest);
@@ -62537,17 +62821,12 @@ var init_merge = __esm(() => {
62537
62821
  });
62538
62822
 
62539
62823
  // src/execution/escalation/escalation.ts
62540
- function escalateTier(currentTier, tierOrder) {
62541
- const getName = (t) => t.tier ?? t.name ?? null;
62542
- const currentIndex = tierOrder.findIndex((t) => getName(t) === currentTier);
62543
- if (currentIndex === -1 || currentIndex === tierOrder.length - 1) {
62824
+ function escalateTier(currentRung, tierOrder) {
62825
+ const i = currentRung.agent !== undefined ? tierOrder.findIndex((t) => t.tier === currentRung.tier && t.agent === currentRung.agent) : tierOrder.findIndex((t) => t.tier === currentRung.tier);
62826
+ if (i === -1 || i === tierOrder.length - 1)
62544
62827
  return null;
62545
- }
62546
- const next = tierOrder[currentIndex + 1];
62547
- const nextName = getName(next);
62548
- if (!nextName)
62549
- return null;
62550
- return { tier: nextName, agent: next.agent };
62828
+ const next = tierOrder[i + 1];
62829
+ return { tier: next.tier, agent: next.agent };
62551
62830
  }
62552
62831
  function calculateMaxIterations(tierOrder) {
62553
62832
  return tierOrder.reduce((sum, t) => sum + t.attempts, 0);
@@ -62610,9 +62889,9 @@ var _quoteIntegrityDeps, CONTEXT_LINES = 3;
62610
62889
  var init_quote_integrity = __esm(() => {
62611
62890
  init_logger2();
62612
62891
  _quoteIntegrityDeps = {
62613
- readFile: async (path20) => {
62892
+ readFile: async (path21) => {
62614
62893
  try {
62615
- return await Bun.file(path20).text();
62894
+ return await Bun.file(path21).text();
62616
62895
  } catch {
62617
62896
  return null;
62618
62897
  }
@@ -62767,7 +63046,10 @@ async function handleTierEscalation(ctx) {
62767
63046
  });
62768
63047
  return { outcome: "retry-same", prdDirty: false, prd: ctx.prd };
62769
63048
  }
62770
- const escalationResult = escalateTier(ctx.routing.modelTier, ctx.config.autoMode.escalation.tierOrder);
63049
+ const escalationTierOrder = ctx.config.autoMode.escalation.tierOrder;
63050
+ const hasAgentRungs = escalationTierOrder.some((r) => r.agent !== undefined);
63051
+ const currentRung = hasAgentRungs ? { tier: ctx.routing.modelTier, agent: ctx.story.routing?.agent } : { tier: ctx.routing.modelTier };
63052
+ const escalationResult = escalateTier(currentRung, escalationTierOrder);
62771
63053
  const nextAgent = escalationResult?.agent;
62772
63054
  const escalateWholeBatch = ctx.config.autoMode.escalation.escalateEntireBatch ?? true;
62773
63055
  const storiesToEscalate = ctx.isBatchExecution && escalateWholeBatch ? ctx.storiesToExecute : [ctx.story];
@@ -62875,7 +63157,8 @@ var init_tier_escalation = __esm(() => {
62875
63157
  init_quote_integrity();
62876
63158
  init_tier_outcome();
62877
63159
  _tierEscalationDeps = {
62878
- savePRD
63160
+ savePRD,
63161
+ getSafeLogger
62879
63162
  };
62880
63163
  });
62881
63164
 
@@ -62889,7 +63172,7 @@ var exports_merge_conflict_rectify = {};
62889
63172
  __export(exports_merge_conflict_rectify, {
62890
63173
  rectifyConflictedStory: () => rectifyConflictedStory
62891
63174
  });
62892
- import path20 from "path";
63175
+ import path21 from "path";
62893
63176
  async function closeStaleAcpSession(worktreePath, sessionName) {
62894
63177
  const logger = getSafeLogger();
62895
63178
  try {
@@ -62916,7 +63199,7 @@ async function rectifyConflictedStory(options) {
62916
63199
  await worktreeManager.remove(workdir, storyId);
62917
63200
  } catch {}
62918
63201
  await worktreeManager.create(workdir, storyId);
62919
- const worktreePath = path20.join(workdir, ".nax-wt", storyId);
63202
+ const worktreePath = path21.join(workdir, ".nax-wt", storyId);
62920
63203
  const { formatSessionName: formatSessionName2 } = await Promise.resolve().then(() => (init_naming(), exports_naming));
62921
63204
  const staleSessionName = formatSessionName2({
62922
63205
  workdir: worktreePath,
@@ -63599,7 +63882,7 @@ __export(exports_parallel_batch, {
63599
63882
  runParallelBatch: () => runParallelBatch,
63600
63883
  _parallelBatchDeps: () => _parallelBatchDeps
63601
63884
  });
63602
- import path21 from "path";
63885
+ import path22 from "path";
63603
63886
  async function runParallelBatch(options) {
63604
63887
  const { stories, ctx, prd } = options;
63605
63888
  const { workdir, config: config2, maxConcurrency, pipelineContext, eventEmitter, agentGetFn, hooks, pluginRegistry } = ctx;
@@ -63618,9 +63901,9 @@ async function runParallelBatch(options) {
63618
63901
  });
63619
63902
  throw error48;
63620
63903
  }
63621
- worktreePaths.set(story.id, path21.join(workdir, ".nax-wt", story.id));
63904
+ worktreePaths.set(story.id, path22.join(workdir, ".nax-wt", story.id));
63622
63905
  }
63623
- const rootConfigPath = path21.join(workdir, ".nax", "config.json");
63906
+ const rootConfigPath = path22.join(workdir, ".nax", "config.json");
63624
63907
  const profileOverride = config2.profile && config2.profile !== "default" ? { profile: config2.profile } : undefined;
63625
63908
  const storyEffectiveConfigs = new Map;
63626
63909
  const configResults = await Promise.allSettled(stories.filter((story) => story.workdir).map(async (story) => {
@@ -64537,7 +64820,7 @@ __export(exports_migrate, {
64537
64820
  });
64538
64821
  import { existsSync as existsSync33 } from "fs";
64539
64822
  import { mkdir as mkdir16, readdir as readdir5, rename as rename3 } from "fs/promises";
64540
- import path22 from "path";
64823
+ import path23 from "path";
64541
64824
  async function detectGeneratedContent(naxDir) {
64542
64825
  if (!existsSync33(naxDir))
64543
64826
  return [];
@@ -64550,17 +64833,17 @@ async function detectGeneratedContent(naxDir) {
64550
64833
  }
64551
64834
  for (const entry of entries) {
64552
64835
  if (GENERATED_NAMES.has(entry)) {
64553
- candidates.push({ name: entry, srcPath: path22.join(naxDir, entry) });
64836
+ candidates.push({ name: entry, srcPath: path23.join(naxDir, entry) });
64554
64837
  }
64555
64838
  }
64556
- const featuresDir = path22.join(naxDir, "features");
64839
+ const featuresDir = path23.join(naxDir, "features");
64557
64840
  if (existsSync33(featuresDir)) {
64558
64841
  let featureDirs = [];
64559
64842
  try {
64560
64843
  featureDirs = await readdir5(featuresDir);
64561
64844
  } catch {}
64562
64845
  for (const fid of featureDirs) {
64563
- const featureDir = path22.join(featuresDir, fid);
64846
+ const featureDir = path23.join(featuresDir, fid);
64564
64847
  let subEntries = [];
64565
64848
  try {
64566
64849
  subEntries = await readdir5(featureDir);
@@ -64570,12 +64853,12 @@ async function detectGeneratedContent(naxDir) {
64570
64853
  for (const sub of subEntries) {
64571
64854
  if (GENERATED_FEATURE_SUBNAMES.has(sub)) {
64572
64855
  candidates.push({
64573
- name: path22.join("features", fid, sub),
64574
- srcPath: path22.join(featureDir, sub)
64856
+ name: path23.join("features", fid, sub),
64857
+ srcPath: path23.join(featureDir, sub)
64575
64858
  });
64576
64859
  }
64577
64860
  if (sub === "stories") {
64578
- const storiesDir = path22.join(featureDir, "stories");
64861
+ const storiesDir = path23.join(featureDir, "stories");
64579
64862
  let storyDirs = [];
64580
64863
  try {
64581
64864
  storyDirs = await readdir5(storiesDir);
@@ -64583,7 +64866,7 @@ async function detectGeneratedContent(naxDir) {
64583
64866
  continue;
64584
64867
  }
64585
64868
  for (const sid of storyDirs) {
64586
- const storyDir = path22.join(storiesDir, sid);
64869
+ const storyDir = path23.join(storiesDir, sid);
64587
64870
  let storyEntries = [];
64588
64871
  try {
64589
64872
  storyEntries = await readdir5(storyDir);
@@ -64593,8 +64876,8 @@ async function detectGeneratedContent(naxDir) {
64593
64876
  for (const se of storyEntries) {
64594
64877
  if (se.startsWith("context-manifest-") && se.endsWith(".json")) {
64595
64878
  candidates.push({
64596
- name: path22.join("features", fid, "stories", sid, se),
64597
- srcPath: path22.join(storyDir, se)
64879
+ name: path23.join("features", fid, "stories", sid, se),
64880
+ srcPath: path23.join(storyDir, se)
64598
64881
  });
64599
64882
  }
64600
64883
  }
@@ -64615,15 +64898,15 @@ async function migrateCommand(options) {
64615
64898
  name: options.reclaim
64616
64899
  });
64617
64900
  }
64618
- const src = path22.join(globalConfigDir(), options.reclaim);
64901
+ const src = path23.join(globalConfigDir(), options.reclaim);
64619
64902
  if (!existsSync33(src)) {
64620
64903
  throw new NaxError(`Nothing to reclaim: ~/.nax/${options.reclaim} does not exist`, "MIGRATE_RECLAIM_NOT_FOUND", {
64621
64904
  stage: "migrate",
64622
64905
  name: options.reclaim
64623
64906
  });
64624
64907
  }
64625
- const archiveBase = path22.join(globalConfigDir(), "_archive");
64626
- const archiveDest = path22.join(archiveBase, `${options.reclaim}-${Date.now()}`);
64908
+ const archiveBase = path23.join(globalConfigDir(), "_archive");
64909
+ const archiveDest = path23.join(archiveBase, `${options.reclaim}-${Date.now()}`);
64627
64910
  await mkdir16(archiveBase, { recursive: true });
64628
64911
  await rename3(src, archiveDest);
64629
64912
  logger.info("migrate", `Reclaimed: archived to ${archiveDest}`, { storyId: "_migrate" });
@@ -64660,8 +64943,8 @@ async function migrateCommand(options) {
64660
64943
  logger.info("migrate", `Merged: identity for "${options.merge}" updated`, { storyId: "_migrate" });
64661
64944
  return;
64662
64945
  }
64663
- const naxDir = path22.join(options.workdir, ".nax");
64664
- const configPath = path22.join(naxDir, "config.json");
64946
+ const naxDir = path23.join(options.workdir, ".nax");
64947
+ const configPath = path23.join(naxDir, "config.json");
64665
64948
  if (!existsSync33(configPath)) {
64666
64949
  throw new NaxError("No .nax/config.json found \u2014 run nax init first", "MIGRATE_NO_CONFIG", {
64667
64950
  stage: "migrate",
@@ -64677,7 +64960,7 @@ async function migrateCommand(options) {
64677
64960
  cause: e
64678
64961
  });
64679
64962
  }
64680
- const projectKey = config2.name?.trim() || path22.basename(options.workdir);
64963
+ const projectKey = config2.name?.trim() || path23.basename(options.workdir);
64681
64964
  const destBase = projectOutputDir(projectKey, config2.outputDir);
64682
64965
  const candidates = await detectGeneratedContent(naxDir);
64683
64966
  if (candidates.length === 0) {
@@ -64686,7 +64969,7 @@ async function migrateCommand(options) {
64686
64969
  }
64687
64970
  if (options.dryRun) {
64688
64971
  for (const c of candidates) {
64689
- logger.info("migrate", `[dry-run] Would move: ${c.srcPath} -> ${path22.join(destBase, c.name)}`, {
64972
+ logger.info("migrate", `[dry-run] Would move: ${c.srcPath} -> ${path23.join(destBase, c.name)}`, {
64690
64973
  storyId: "_migrate"
64691
64974
  });
64692
64975
  }
@@ -64695,8 +64978,8 @@ async function migrateCommand(options) {
64695
64978
  await mkdir16(destBase, { recursive: true });
64696
64979
  let moved = 0;
64697
64980
  for (const candidate of candidates) {
64698
- const dest = path22.join(destBase, candidate.name);
64699
- await mkdir16(path22.dirname(dest), { recursive: true });
64981
+ const dest = path23.join(destBase, candidate.name);
64982
+ await mkdir16(path23.dirname(dest), { recursive: true });
64700
64983
  if (existsSync33(dest)) {
64701
64984
  throw new NaxError(`Migration conflict: destination already exists.
64702
64985
  Source: ${candidate.srcPath}
@@ -64726,7 +65009,7 @@ async function migrateCommand(options) {
64726
65009
  moved++;
64727
65010
  logger.info("migrate", `Moved: ${candidate.name}`, { storyId: "_migrate" });
64728
65011
  }
64729
- await Bun.write(path22.join(destBase, ".migrated-from"), JSON.stringify({ from: options.workdir, migratedAt: new Date().toISOString() }, null, 2));
65012
+ await Bun.write(path23.join(destBase, ".migrated-from"), JSON.stringify({ from: options.workdir, migratedAt: new Date().toISOString() }, null, 2));
64730
65013
  logger.info("migrate", `Migration complete: ${moved} entries moved`, {
64731
65014
  storyId: "_migrate",
64732
65015
  destBase
@@ -64843,7 +65126,7 @@ __export(exports_precheck_runner, {
64843
65126
  runPrecheckValidation: () => runPrecheckValidation
64844
65127
  });
64845
65128
  import { mkdirSync as mkdirSync6 } from "fs";
64846
- import path23 from "path";
65129
+ import path24 from "path";
64847
65130
  async function runPrecheckValidation(ctx) {
64848
65131
  const logger = getSafeLogger();
64849
65132
  if (process.env.NAX_PRECHECK !== "1") {
@@ -64858,7 +65141,7 @@ async function runPrecheckValidation(ctx) {
64858
65141
  silent: true
64859
65142
  });
64860
65143
  if (ctx.logFilePath) {
64861
- mkdirSync6(path23.dirname(ctx.logFilePath), { recursive: true });
65144
+ mkdirSync6(path24.dirname(ctx.logFilePath), { recursive: true });
64862
65145
  const precheckLog = {
64863
65146
  type: "precheck",
64864
65147
  timestamp: new Date().toISOString(),
@@ -65155,11 +65438,33 @@ var init_paused_story_prompts = __esm(() => {
65155
65438
  // src/execution/lifecycle/run-setup.ts
65156
65439
  var exports_run_setup = {};
65157
65440
  __export(exports_run_setup, {
65441
+ warnProfileMismatch: () => warnProfileMismatch,
65158
65442
  warnFallbackMisconfiguration: () => warnFallbackMisconfiguration,
65159
65443
  setupRun: () => setupRun,
65160
65444
  _runSetupDeps: () => _runSetupDeps
65161
65445
  });
65162
- import path24 from "path";
65446
+ import path25 from "path";
65447
+ function warnProfileMismatch(prd, config2, logger) {
65448
+ const profiles = config2.routing?.agents?.profiles ?? [];
65449
+ const profileIds = new Set(profiles.map((p) => p.id));
65450
+ if (prd.routingProfile !== undefined) {
65451
+ const current = config2.profile ?? "default";
65452
+ if (prd.routingProfile !== current) {
65453
+ 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 });
65454
+ }
65455
+ }
65456
+ const knownAgents = new Set(Object.keys(config2.models ?? {}));
65457
+ for (const story of prd.userStories) {
65458
+ const profileId = story.routing?.agentProfileId;
65459
+ if (profileId && !profileIds.has(profileId)) {
65460
+ 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 });
65461
+ }
65462
+ const storyAgent = story.routing?.agent;
65463
+ if (storyAgent && !knownAgents.has(storyAgent)) {
65464
+ 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 });
65465
+ }
65466
+ }
65467
+ }
65163
65468
  function warnFallbackMisconfiguration(config2, agentGetFn, logger) {
65164
65469
  if (!agentGetFn)
65165
65470
  return;
@@ -65173,6 +65478,7 @@ function warnFallbackMisconfiguration(config2, agentGetFn, logger) {
65173
65478
  continue;
65174
65479
  if (!agentGetFn(candidate)) {
65175
65480
  logger?.warn("fallback", "Fallback candidate not available \u2014 will be skipped if triggered", {
65481
+ storyId: "_setup",
65176
65482
  primaryAgent,
65177
65483
  candidate
65178
65484
  });
@@ -65258,7 +65564,7 @@ async function setupRun(options) {
65258
65564
  statusWriter.setPrd(prd);
65259
65565
  {
65260
65566
  const { detectGeneratedContent: detectGeneratedContent2, migrateCommand: migrateCommand2 } = await Promise.resolve().then(() => (init_migrate(), exports_migrate));
65261
- const naxDir = path24.join(workdir, ".nax");
65567
+ const naxDir = path25.join(workdir, ".nax");
65262
65568
  const candidates = await detectGeneratedContent2(naxDir).catch(() => []);
65263
65569
  if (candidates.length > 0) {
65264
65570
  logger?.info("setup", "Found generated content under .nax/ \u2014 migrating to output dir", {
@@ -65285,7 +65591,7 @@ async function setupRun(options) {
65285
65591
  remoteUrl = new TextDecoder().decode(gitResult.stdout).trim() || null;
65286
65592
  }
65287
65593
  } catch {}
65288
- const projectKey = config2.name?.trim() || path24.basename(workdir);
65594
+ const projectKey = config2.name?.trim() || path25.basename(workdir);
65289
65595
  await claimProjectIdentity2(projectKey, workdir, remoteUrl).catch((err) => {
65290
65596
  if (err instanceof NaxError && err.code === "RUN_NAME_COLLISION") {
65291
65597
  throw err;
@@ -65340,8 +65646,8 @@ async function setupRun(options) {
65340
65646
  explicit: Object.fromEntries(explicitFields.map((f) => [f, existingProjectConfig[f]])),
65341
65647
  detected: Object.fromEntries(autodetectedFields.map((f) => [f, detectedProfile[f]]))
65342
65648
  });
65343
- const globalPluginsDir = path24.join(globalConfigDir(), "plugins");
65344
- const projectPluginsDir = path24.join(workdir, ".nax", "plugins");
65649
+ const globalPluginsDir = path25.join(globalConfigDir(), "plugins");
65650
+ const projectPluginsDir = path25.join(workdir, ".nax", "plugins");
65345
65651
  const configPlugins = config2.plugins || [];
65346
65652
  const resolvedPatterns = await resolveTestFilePatterns(config2, workdir);
65347
65653
  const isTestFileFn = (filename) => resolvedPatterns.regex.some((re) => re.test(filename));
@@ -65370,6 +65676,7 @@ async function setupRun(options) {
65370
65676
  });
65371
65677
  prd = initResult.prd;
65372
65678
  statusWriter.setPrd(prd);
65679
+ warnProfileMismatch(prd, config2, logger);
65373
65680
  let counts = initResult.storyCounts;
65374
65681
  if (counts.paused > 0 && interactionChain !== null) {
65375
65682
  const { promptForPausedStories: promptForPausedStories2 } = await Promise.resolve().then(() => (init_paused_story_prompts(), exports_paused_story_prompts));
@@ -66832,11 +67139,11 @@ var require_react_reconciler_development = __commonJS((exports, module) => {
66832
67139
  fiber = fiber.next, id--;
66833
67140
  return fiber;
66834
67141
  }
66835
- function copyWithSetImpl(obj, path25, index, value) {
66836
- if (index >= path25.length)
67142
+ function copyWithSetImpl(obj, path26, index, value) {
67143
+ if (index >= path26.length)
66837
67144
  return value;
66838
- var key = path25[index], updated = isArrayImpl(obj) ? obj.slice() : assign2({}, obj);
66839
- updated[key] = copyWithSetImpl(obj[key], path25, index + 1, value);
67145
+ var key = path26[index], updated = isArrayImpl(obj) ? obj.slice() : assign2({}, obj);
67146
+ updated[key] = copyWithSetImpl(obj[key], path26, index + 1, value);
66840
67147
  return updated;
66841
67148
  }
66842
67149
  function copyWithRename(obj, oldPath, newPath) {
@@ -66856,11 +67163,11 @@ var require_react_reconciler_development = __commonJS((exports, module) => {
66856
67163
  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);
66857
67164
  return updated;
66858
67165
  }
66859
- function copyWithDeleteImpl(obj, path25, index) {
66860
- var key = path25[index], updated = isArrayImpl(obj) ? obj.slice() : assign2({}, obj);
66861
- if (index + 1 === path25.length)
67166
+ function copyWithDeleteImpl(obj, path26, index) {
67167
+ var key = path26[index], updated = isArrayImpl(obj) ? obj.slice() : assign2({}, obj);
67168
+ if (index + 1 === path26.length)
66862
67169
  return isArrayImpl(updated) ? updated.splice(key, 1) : delete updated[key], updated;
66863
- updated[key] = copyWithDeleteImpl(obj[key], path25, index + 1);
67170
+ updated[key] = copyWithDeleteImpl(obj[key], path26, index + 1);
66864
67171
  return updated;
66865
67172
  }
66866
67173
  function shouldSuspendImpl() {
@@ -76883,29 +77190,29 @@ Check the top-level render call using <` + componentName2 + ">.");
76883
77190
  var didWarnAboutNestedUpdates = false;
76884
77191
  var didWarnAboutFindNodeInStrictMode = {};
76885
77192
  var overrideHookState = null, overrideHookStateDeletePath = null, overrideHookStateRenamePath = null, overrideProps = null, overridePropsDeletePath = null, overridePropsRenamePath = null, scheduleUpdate = null, scheduleRetry = null, setErrorHandler = null, setSuspenseHandler = null;
76886
- overrideHookState = function(fiber, id, path25, value) {
77193
+ overrideHookState = function(fiber, id, path26, value) {
76887
77194
  id = findHook(fiber, id);
76888
- 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));
77195
+ 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));
76889
77196
  };
76890
- overrideHookStateDeletePath = function(fiber, id, path25) {
77197
+ overrideHookStateDeletePath = function(fiber, id, path26) {
76891
77198
  id = findHook(fiber, id);
76892
- 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));
77199
+ 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));
76893
77200
  };
76894
77201
  overrideHookStateRenamePath = function(fiber, id, oldPath, newPath) {
76895
77202
  id = findHook(fiber, id);
76896
77203
  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));
76897
77204
  };
76898
- overrideProps = function(fiber, path25, value) {
76899
- fiber.pendingProps = copyWithSetImpl(fiber.memoizedProps, path25, 0, value);
77205
+ overrideProps = function(fiber, path26, value) {
77206
+ fiber.pendingProps = copyWithSetImpl(fiber.memoizedProps, path26, 0, value);
76900
77207
  fiber.alternate && (fiber.alternate.pendingProps = fiber.pendingProps);
76901
- path25 = enqueueConcurrentRenderForLane(fiber, 2);
76902
- path25 !== null && scheduleUpdateOnFiber(path25, fiber, 2);
77208
+ path26 = enqueueConcurrentRenderForLane(fiber, 2);
77209
+ path26 !== null && scheduleUpdateOnFiber(path26, fiber, 2);
76903
77210
  };
76904
- overridePropsDeletePath = function(fiber, path25) {
76905
- fiber.pendingProps = copyWithDeleteImpl(fiber.memoizedProps, path25, 0);
77211
+ overridePropsDeletePath = function(fiber, path26) {
77212
+ fiber.pendingProps = copyWithDeleteImpl(fiber.memoizedProps, path26, 0);
76906
77213
  fiber.alternate && (fiber.alternate.pendingProps = fiber.pendingProps);
76907
- path25 = enqueueConcurrentRenderForLane(fiber, 2);
76908
- path25 !== null && scheduleUpdateOnFiber(path25, fiber, 2);
77214
+ path26 = enqueueConcurrentRenderForLane(fiber, 2);
77215
+ path26 !== null && scheduleUpdateOnFiber(path26, fiber, 2);
76909
77216
  };
76910
77217
  overridePropsRenamePath = function(fiber, oldPath, newPath) {
76911
77218
  fiber.pendingProps = copyWithRename(fiber.memoizedProps, oldPath, newPath);
@@ -80960,8 +81267,8 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
80960
81267
  }
80961
81268
  return false;
80962
81269
  }
80963
- function utils_getInObject(object2, path25) {
80964
- return path25.reduce(function(reduced, attr) {
81270
+ function utils_getInObject(object2, path26) {
81271
+ return path26.reduce(function(reduced, attr) {
80965
81272
  if (reduced) {
80966
81273
  if (utils_hasOwnProperty.call(reduced, attr)) {
80967
81274
  return reduced[attr];
@@ -80973,11 +81280,11 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
80973
81280
  return null;
80974
81281
  }, object2);
80975
81282
  }
80976
- function deletePathInObject(object2, path25) {
80977
- var length = path25.length;
80978
- var last2 = path25[length - 1];
81283
+ function deletePathInObject(object2, path26) {
81284
+ var length = path26.length;
81285
+ var last2 = path26[length - 1];
80979
81286
  if (object2 != null) {
80980
- var parent = utils_getInObject(object2, path25.slice(0, length - 1));
81287
+ var parent = utils_getInObject(object2, path26.slice(0, length - 1));
80981
81288
  if (parent) {
80982
81289
  if (src_isArray(parent)) {
80983
81290
  parent.splice(last2, 1);
@@ -81003,11 +81310,11 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81003
81310
  }
81004
81311
  }
81005
81312
  }
81006
- function utils_setInObject(object2, path25, value) {
81007
- var length = path25.length;
81008
- var last2 = path25[length - 1];
81313
+ function utils_setInObject(object2, path26, value) {
81314
+ var length = path26.length;
81315
+ var last2 = path26[length - 1];
81009
81316
  if (object2 != null) {
81010
- var parent = utils_getInObject(object2, path25.slice(0, length - 1));
81317
+ var parent = utils_getInObject(object2, path26.slice(0, length - 1));
81011
81318
  if (parent) {
81012
81319
  parent[last2] = value;
81013
81320
  }
@@ -81538,8 +81845,8 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81538
81845
  unserializable: Symbol("unserializable")
81539
81846
  };
81540
81847
  var LEVEL_THRESHOLD = 2;
81541
- function createDehydrated(type, inspectable, data, cleaned, path25) {
81542
- cleaned.push(path25);
81848
+ function createDehydrated(type, inspectable, data, cleaned, path26) {
81849
+ cleaned.push(path26);
81543
81850
  var dehydrated = {
81544
81851
  inspectable,
81545
81852
  type,
@@ -81557,13 +81864,13 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81557
81864
  }
81558
81865
  return dehydrated;
81559
81866
  }
81560
- function dehydrate(data, cleaned, unserializable, path25, isPathAllowed) {
81867
+ function dehydrate(data, cleaned, unserializable, path26, isPathAllowed) {
81561
81868
  var level = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 0;
81562
81869
  var type = getDataType(data);
81563
81870
  var isPathAllowedCheck;
81564
81871
  switch (type) {
81565
81872
  case "html_element":
81566
- cleaned.push(path25);
81873
+ cleaned.push(path26);
81567
81874
  return {
81568
81875
  inspectable: false,
81569
81876
  preview_short: formatDataForPreview(data, false),
@@ -81572,7 +81879,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81572
81879
  type
81573
81880
  };
81574
81881
  case "function":
81575
- cleaned.push(path25);
81882
+ cleaned.push(path26);
81576
81883
  return {
81577
81884
  inspectable: false,
81578
81885
  preview_short: formatDataForPreview(data, false),
@@ -81581,14 +81888,14 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81581
81888
  type
81582
81889
  };
81583
81890
  case "string":
81584
- isPathAllowedCheck = isPathAllowed(path25);
81891
+ isPathAllowedCheck = isPathAllowed(path26);
81585
81892
  if (isPathAllowedCheck) {
81586
81893
  return data;
81587
81894
  } else {
81588
81895
  return data.length <= 500 ? data : data.slice(0, 500) + "...";
81589
81896
  }
81590
81897
  case "bigint":
81591
- cleaned.push(path25);
81898
+ cleaned.push(path26);
81592
81899
  return {
81593
81900
  inspectable: false,
81594
81901
  preview_short: formatDataForPreview(data, false),
@@ -81597,7 +81904,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81597
81904
  type
81598
81905
  };
81599
81906
  case "symbol":
81600
- cleaned.push(path25);
81907
+ cleaned.push(path26);
81601
81908
  return {
81602
81909
  inspectable: false,
81603
81910
  preview_short: formatDataForPreview(data, false),
@@ -81606,9 +81913,9 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81606
81913
  type
81607
81914
  };
81608
81915
  case "react_element": {
81609
- isPathAllowedCheck = isPathAllowed(path25);
81916
+ isPathAllowedCheck = isPathAllowed(path26);
81610
81917
  if (level >= LEVEL_THRESHOLD && !isPathAllowedCheck) {
81611
- cleaned.push(path25);
81918
+ cleaned.push(path26);
81612
81919
  return {
81613
81920
  inspectable: true,
81614
81921
  preview_short: formatDataForPreview(data, false),
@@ -81625,19 +81932,19 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81625
81932
  preview_long: formatDataForPreview(data, true),
81626
81933
  name: getDisplayNameForReactElement(data) || "Unknown"
81627
81934
  };
81628
- unserializableValue.key = dehydrate(data.key, cleaned, unserializable, path25.concat(["key"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
81935
+ unserializableValue.key = dehydrate(data.key, cleaned, unserializable, path26.concat(["key"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
81629
81936
  if (data.$$typeof === REACT_LEGACY_ELEMENT_TYPE) {
81630
- unserializableValue.ref = dehydrate(data.ref, cleaned, unserializable, path25.concat(["ref"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
81937
+ unserializableValue.ref = dehydrate(data.ref, cleaned, unserializable, path26.concat(["ref"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
81631
81938
  }
81632
- unserializableValue.props = dehydrate(data.props, cleaned, unserializable, path25.concat(["props"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
81633
- unserializable.push(path25);
81939
+ unserializableValue.props = dehydrate(data.props, cleaned, unserializable, path26.concat(["props"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
81940
+ unserializable.push(path26);
81634
81941
  return unserializableValue;
81635
81942
  }
81636
81943
  case "react_lazy": {
81637
- isPathAllowedCheck = isPathAllowed(path25);
81944
+ isPathAllowedCheck = isPathAllowed(path26);
81638
81945
  var payload = data._payload;
81639
81946
  if (level >= LEVEL_THRESHOLD && !isPathAllowedCheck) {
81640
- cleaned.push(path25);
81947
+ cleaned.push(path26);
81641
81948
  var inspectable = payload !== null && hydration_typeof(payload) === "object" && (payload._status === 1 || payload._status === 2 || payload.status === "fulfilled" || payload.status === "rejected");
81642
81949
  return {
81643
81950
  inspectable,
@@ -81654,13 +81961,13 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81654
81961
  preview_long: formatDataForPreview(data, true),
81655
81962
  name: "lazy()"
81656
81963
  };
81657
- _unserializableValue._payload = dehydrate(payload, cleaned, unserializable, path25.concat(["_payload"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
81658
- unserializable.push(path25);
81964
+ _unserializableValue._payload = dehydrate(payload, cleaned, unserializable, path26.concat(["_payload"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
81965
+ unserializable.push(path26);
81659
81966
  return _unserializableValue;
81660
81967
  }
81661
81968
  case "array_buffer":
81662
81969
  case "data_view":
81663
- cleaned.push(path25);
81970
+ cleaned.push(path26);
81664
81971
  return {
81665
81972
  inspectable: false,
81666
81973
  preview_short: formatDataForPreview(data, false),
@@ -81670,21 +81977,21 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81670
81977
  type
81671
81978
  };
81672
81979
  case "array":
81673
- isPathAllowedCheck = isPathAllowed(path25);
81980
+ isPathAllowedCheck = isPathAllowed(path26);
81674
81981
  if (level >= LEVEL_THRESHOLD && !isPathAllowedCheck) {
81675
- return createDehydrated(type, true, data, cleaned, path25);
81982
+ return createDehydrated(type, true, data, cleaned, path26);
81676
81983
  }
81677
81984
  var arr = [];
81678
81985
  for (var i = 0;i < data.length; i++) {
81679
- arr[i] = dehydrateKey(data, i, cleaned, unserializable, path25.concat([i]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
81986
+ arr[i] = dehydrateKey(data, i, cleaned, unserializable, path26.concat([i]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
81680
81987
  }
81681
81988
  return arr;
81682
81989
  case "html_all_collection":
81683
81990
  case "typed_array":
81684
81991
  case "iterator":
81685
- isPathAllowedCheck = isPathAllowed(path25);
81992
+ isPathAllowedCheck = isPathAllowed(path26);
81686
81993
  if (level >= LEVEL_THRESHOLD && !isPathAllowedCheck) {
81687
- return createDehydrated(type, true, data, cleaned, path25);
81994
+ return createDehydrated(type, true, data, cleaned, path26);
81688
81995
  } else {
81689
81996
  var _unserializableValue2 = {
81690
81997
  unserializable: true,
@@ -81696,13 +82003,13 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81696
82003
  name: typeof data.constructor !== "function" || typeof data.constructor.name !== "string" || data.constructor.name === "Object" ? "" : data.constructor.name
81697
82004
  };
81698
82005
  Array.from(data).forEach(function(item, i2) {
81699
- return _unserializableValue2[i2] = dehydrate(item, cleaned, unserializable, path25.concat([i2]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
82006
+ return _unserializableValue2[i2] = dehydrate(item, cleaned, unserializable, path26.concat([i2]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
81700
82007
  });
81701
- unserializable.push(path25);
82008
+ unserializable.push(path26);
81702
82009
  return _unserializableValue2;
81703
82010
  }
81704
82011
  case "opaque_iterator":
81705
- cleaned.push(path25);
82012
+ cleaned.push(path26);
81706
82013
  return {
81707
82014
  inspectable: false,
81708
82015
  preview_short: formatDataForPreview(data, false),
@@ -81711,7 +82018,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81711
82018
  type
81712
82019
  };
81713
82020
  case "date":
81714
- cleaned.push(path25);
82021
+ cleaned.push(path26);
81715
82022
  return {
81716
82023
  inspectable: false,
81717
82024
  preview_short: formatDataForPreview(data, false),
@@ -81720,7 +82027,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81720
82027
  type
81721
82028
  };
81722
82029
  case "regexp":
81723
- cleaned.push(path25);
82030
+ cleaned.push(path26);
81724
82031
  return {
81725
82032
  inspectable: false,
81726
82033
  preview_short: formatDataForPreview(data, false),
@@ -81729,9 +82036,9 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81729
82036
  type
81730
82037
  };
81731
82038
  case "thenable":
81732
- isPathAllowedCheck = isPathAllowed(path25);
82039
+ isPathAllowedCheck = isPathAllowed(path26);
81733
82040
  if (level >= LEVEL_THRESHOLD && !isPathAllowedCheck) {
81734
- cleaned.push(path25);
82041
+ cleaned.push(path26);
81735
82042
  return {
81736
82043
  inspectable: data.status === "fulfilled" || data.status === "rejected",
81737
82044
  preview_short: formatDataForPreview(data, false),
@@ -81752,8 +82059,8 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81752
82059
  preview_long: formatDataForPreview(data, true),
81753
82060
  name: "fulfilled Thenable"
81754
82061
  };
81755
- _unserializableValue3.value = dehydrate(data.value, cleaned, unserializable, path25.concat(["value"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
81756
- unserializable.push(path25);
82062
+ _unserializableValue3.value = dehydrate(data.value, cleaned, unserializable, path26.concat(["value"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
82063
+ unserializable.push(path26);
81757
82064
  return _unserializableValue3;
81758
82065
  }
81759
82066
  case "rejected": {
@@ -81764,12 +82071,12 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81764
82071
  preview_long: formatDataForPreview(data, true),
81765
82072
  name: "rejected Thenable"
81766
82073
  };
81767
- _unserializableValue4.reason = dehydrate(data.reason, cleaned, unserializable, path25.concat(["reason"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
81768
- unserializable.push(path25);
82074
+ _unserializableValue4.reason = dehydrate(data.reason, cleaned, unserializable, path26.concat(["reason"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
82075
+ unserializable.push(path26);
81769
82076
  return _unserializableValue4;
81770
82077
  }
81771
82078
  default:
81772
- cleaned.push(path25);
82079
+ cleaned.push(path26);
81773
82080
  return {
81774
82081
  inspectable: false,
81775
82082
  preview_short: formatDataForPreview(data, false),
@@ -81779,21 +82086,21 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81779
82086
  };
81780
82087
  }
81781
82088
  case "object":
81782
- isPathAllowedCheck = isPathAllowed(path25);
82089
+ isPathAllowedCheck = isPathAllowed(path26);
81783
82090
  if (level >= LEVEL_THRESHOLD && !isPathAllowedCheck) {
81784
- return createDehydrated(type, true, data, cleaned, path25);
82091
+ return createDehydrated(type, true, data, cleaned, path26);
81785
82092
  } else {
81786
82093
  var object2 = {};
81787
82094
  getAllEnumerableKeys(data).forEach(function(key) {
81788
82095
  var name = key.toString();
81789
- object2[name] = dehydrateKey(data, key, cleaned, unserializable, path25.concat([name]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
82096
+ object2[name] = dehydrateKey(data, key, cleaned, unserializable, path26.concat([name]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
81790
82097
  });
81791
82098
  return object2;
81792
82099
  }
81793
82100
  case "class_instance": {
81794
- isPathAllowedCheck = isPathAllowed(path25);
82101
+ isPathAllowedCheck = isPathAllowed(path26);
81795
82102
  if (level >= LEVEL_THRESHOLD && !isPathAllowedCheck) {
81796
- return createDehydrated(type, true, data, cleaned, path25);
82103
+ return createDehydrated(type, true, data, cleaned, path26);
81797
82104
  }
81798
82105
  var value = {
81799
82106
  unserializable: true,
@@ -81805,15 +82112,15 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81805
82112
  };
81806
82113
  getAllEnumerableKeys(data).forEach(function(key) {
81807
82114
  var keyAsString = key.toString();
81808
- value[keyAsString] = dehydrate(data[key], cleaned, unserializable, path25.concat([keyAsString]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
82115
+ value[keyAsString] = dehydrate(data[key], cleaned, unserializable, path26.concat([keyAsString]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
81809
82116
  });
81810
- unserializable.push(path25);
82117
+ unserializable.push(path26);
81811
82118
  return value;
81812
82119
  }
81813
82120
  case "error": {
81814
- isPathAllowedCheck = isPathAllowed(path25);
82121
+ isPathAllowedCheck = isPathAllowed(path26);
81815
82122
  if (level >= LEVEL_THRESHOLD && !isPathAllowedCheck) {
81816
- return createDehydrated(type, true, data, cleaned, path25);
82123
+ return createDehydrated(type, true, data, cleaned, path26);
81817
82124
  }
81818
82125
  var _value = {
81819
82126
  unserializable: true,
@@ -81823,22 +82130,22 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81823
82130
  preview_long: formatDataForPreview(data, true),
81824
82131
  name: data.name
81825
82132
  };
81826
- _value.message = dehydrate(data.message, cleaned, unserializable, path25.concat(["message"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
81827
- _value.stack = dehydrate(data.stack, cleaned, unserializable, path25.concat(["stack"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
82133
+ _value.message = dehydrate(data.message, cleaned, unserializable, path26.concat(["message"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
82134
+ _value.stack = dehydrate(data.stack, cleaned, unserializable, path26.concat(["stack"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
81828
82135
  if ("cause" in data) {
81829
- _value.cause = dehydrate(data.cause, cleaned, unserializable, path25.concat(["cause"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
82136
+ _value.cause = dehydrate(data.cause, cleaned, unserializable, path26.concat(["cause"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
81830
82137
  }
81831
82138
  getAllEnumerableKeys(data).forEach(function(key) {
81832
82139
  var keyAsString = key.toString();
81833
- _value[keyAsString] = dehydrate(data[key], cleaned, unserializable, path25.concat([keyAsString]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
82140
+ _value[keyAsString] = dehydrate(data[key], cleaned, unserializable, path26.concat([keyAsString]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
81834
82141
  });
81835
- unserializable.push(path25);
82142
+ unserializable.push(path26);
81836
82143
  return _value;
81837
82144
  }
81838
82145
  case "infinity":
81839
82146
  case "nan":
81840
82147
  case "undefined":
81841
- cleaned.push(path25);
82148
+ cleaned.push(path26);
81842
82149
  return {
81843
82150
  type
81844
82151
  };
@@ -81846,10 +82153,10 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81846
82153
  return data;
81847
82154
  }
81848
82155
  }
81849
- function dehydrateKey(parent, key, cleaned, unserializable, path25, isPathAllowed) {
82156
+ function dehydrateKey(parent, key, cleaned, unserializable, path26, isPathAllowed) {
81850
82157
  var level = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : 0;
81851
82158
  try {
81852
- return dehydrate(parent[key], cleaned, unserializable, path25, isPathAllowed, level);
82159
+ return dehydrate(parent[key], cleaned, unserializable, path26, isPathAllowed, level);
81853
82160
  } catch (error48) {
81854
82161
  var preview = "";
81855
82162
  if (hydration_typeof(error48) === "object" && error48 !== null && typeof error48.stack === "string") {
@@ -81857,7 +82164,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81857
82164
  } else if (typeof error48 === "string") {
81858
82165
  preview = error48;
81859
82166
  }
81860
- cleaned.push(path25);
82167
+ cleaned.push(path26);
81861
82168
  return {
81862
82169
  inspectable: false,
81863
82170
  preview_short: "[Exception]",
@@ -81867,8 +82174,8 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81867
82174
  };
81868
82175
  }
81869
82176
  }
81870
- function fillInPath(object2, data, path25, value) {
81871
- var target = getInObject(object2, path25);
82177
+ function fillInPath(object2, data, path26, value) {
82178
+ var target = getInObject(object2, path26);
81872
82179
  if (target != null) {
81873
82180
  if (!target[meta3.unserializable]) {
81874
82181
  delete target[meta3.inspectable];
@@ -81883,9 +82190,9 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81883
82190
  }
81884
82191
  if (value !== null && data.unserializable.length > 0) {
81885
82192
  var unserializablePath = data.unserializable[0];
81886
- var isMatch2 = unserializablePath.length === path25.length;
81887
- for (var i = 0;i < path25.length; i++) {
81888
- if (path25[i] !== unserializablePath[i]) {
82193
+ var isMatch2 = unserializablePath.length === path26.length;
82194
+ for (var i = 0;i < path26.length; i++) {
82195
+ if (path26[i] !== unserializablePath[i]) {
81889
82196
  isMatch2 = false;
81890
82197
  break;
81891
82198
  }
@@ -81894,13 +82201,13 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81894
82201
  upgradeUnserializable(value, value);
81895
82202
  }
81896
82203
  }
81897
- setInObject(object2, path25, value);
82204
+ setInObject(object2, path26, value);
81898
82205
  }
81899
82206
  function hydrate(object2, cleaned, unserializable) {
81900
- cleaned.forEach(function(path25) {
81901
- var length = path25.length;
81902
- var last2 = path25[length - 1];
81903
- var parent = getInObject(object2, path25.slice(0, length - 1));
82207
+ cleaned.forEach(function(path26) {
82208
+ var length = path26.length;
82209
+ var last2 = path26[length - 1];
82210
+ var parent = getInObject(object2, path26.slice(0, length - 1));
81904
82211
  if (!parent || !parent.hasOwnProperty(last2)) {
81905
82212
  return;
81906
82213
  }
@@ -81926,10 +82233,10 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
81926
82233
  parent[last2] = replaced;
81927
82234
  }
81928
82235
  });
81929
- unserializable.forEach(function(path25) {
81930
- var length = path25.length;
81931
- var last2 = path25[length - 1];
81932
- var parent = getInObject(object2, path25.slice(0, length - 1));
82236
+ unserializable.forEach(function(path26) {
82237
+ var length = path26.length;
82238
+ var last2 = path26[length - 1];
82239
+ var parent = getInObject(object2, path26.slice(0, length - 1));
81933
82240
  if (!parent || !parent.hasOwnProperty(last2)) {
81934
82241
  return;
81935
82242
  }
@@ -82050,11 +82357,11 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
82050
82357
  return gte2(version2, FIRST_DEVTOOLS_BACKEND_LOCKSTEP_VER);
82051
82358
  }
82052
82359
  function cleanForBridge(data, isPathAllowed) {
82053
- var path25 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
82360
+ var path26 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
82054
82361
  if (data !== null) {
82055
82362
  var cleanedPaths = [];
82056
82363
  var unserializablePaths = [];
82057
- var cleanedData = dehydrate(data, cleanedPaths, unserializablePaths, path25, isPathAllowed);
82364
+ var cleanedData = dehydrate(data, cleanedPaths, unserializablePaths, path26, isPathAllowed);
82058
82365
  return {
82059
82366
  data: cleanedData,
82060
82367
  cleaned: cleanedPaths,
@@ -82064,18 +82371,18 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
82064
82371
  return null;
82065
82372
  }
82066
82373
  }
82067
- function copyWithDelete(obj, path25) {
82374
+ function copyWithDelete(obj, path26) {
82068
82375
  var index = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
82069
- var key = path25[index];
82376
+ var key = path26[index];
82070
82377
  var updated = shared_isArray(obj) ? obj.slice() : utils_objectSpread({}, obj);
82071
- if (index + 1 === path25.length) {
82378
+ if (index + 1 === path26.length) {
82072
82379
  if (shared_isArray(updated)) {
82073
82380
  updated.splice(key, 1);
82074
82381
  } else {
82075
82382
  delete updated[key];
82076
82383
  }
82077
82384
  } else {
82078
- updated[key] = copyWithDelete(obj[key], path25, index + 1);
82385
+ updated[key] = copyWithDelete(obj[key], path26, index + 1);
82079
82386
  }
82080
82387
  return updated;
82081
82388
  }
@@ -82096,14 +82403,14 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
82096
82403
  }
82097
82404
  return updated;
82098
82405
  }
82099
- function copyWithSet(obj, path25, value) {
82406
+ function copyWithSet(obj, path26, value) {
82100
82407
  var index = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
82101
- if (index >= path25.length) {
82408
+ if (index >= path26.length) {
82102
82409
  return value;
82103
82410
  }
82104
- var key = path25[index];
82411
+ var key = path26[index];
82105
82412
  var updated = shared_isArray(obj) ? obj.slice() : utils_objectSpread({}, obj);
82106
- updated[key] = copyWithSet(obj[key], path25, value, index + 1);
82413
+ updated[key] = copyWithSet(obj[key], path26, value, index + 1);
82107
82414
  return updated;
82108
82415
  }
82109
82416
  function getEffectDurations(root) {
@@ -83431,12 +83738,12 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
83431
83738
  }
83432
83739
  });
83433
83740
  bridge_defineProperty(_this, "overrideValueAtPath", function(_ref) {
83434
- var { id, path: path25, rendererID, type, value } = _ref;
83741
+ var { id, path: path26, rendererID, type, value } = _ref;
83435
83742
  switch (type) {
83436
83743
  case "context":
83437
83744
  _this.send("overrideContext", {
83438
83745
  id,
83439
- path: path25,
83746
+ path: path26,
83440
83747
  rendererID,
83441
83748
  wasForwarded: true,
83442
83749
  value
@@ -83445,7 +83752,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
83445
83752
  case "hooks":
83446
83753
  _this.send("overrideHookState", {
83447
83754
  id,
83448
- path: path25,
83755
+ path: path26,
83449
83756
  rendererID,
83450
83757
  wasForwarded: true,
83451
83758
  value
@@ -83454,7 +83761,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
83454
83761
  case "props":
83455
83762
  _this.send("overrideProps", {
83456
83763
  id,
83457
- path: path25,
83764
+ path: path26,
83458
83765
  rendererID,
83459
83766
  wasForwarded: true,
83460
83767
  value
@@ -83463,7 +83770,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
83463
83770
  case "state":
83464
83771
  _this.send("overrideState", {
83465
83772
  id,
83466
- path: path25,
83773
+ path: path26,
83467
83774
  rendererID,
83468
83775
  wasForwarded: true,
83469
83776
  value
@@ -83797,12 +84104,12 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
83797
84104
  }
83798
84105
  });
83799
84106
  agent_defineProperty(_this, "copyElementPath", function(_ref5) {
83800
- var { id, path: path25, rendererID } = _ref5;
84107
+ var { id, path: path26, rendererID } = _ref5;
83801
84108
  var renderer = _this._rendererInterfaces[rendererID];
83802
84109
  if (renderer == null) {
83803
84110
  console.warn('Invalid renderer id "'.concat(rendererID, '" for element "').concat(id, '"'));
83804
84111
  } else {
83805
- var value = renderer.getSerializedElementValueByPath(id, path25);
84112
+ var value = renderer.getSerializedElementValueByPath(id, path26);
83806
84113
  if (value != null) {
83807
84114
  _this._bridge.send("saveToClipboard", value);
83808
84115
  } else {
@@ -83811,12 +84118,12 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
83811
84118
  }
83812
84119
  });
83813
84120
  agent_defineProperty(_this, "deletePath", function(_ref6) {
83814
- var { hookID, id, path: path25, rendererID, type } = _ref6;
84121
+ var { hookID, id, path: path26, rendererID, type } = _ref6;
83815
84122
  var renderer = _this._rendererInterfaces[rendererID];
83816
84123
  if (renderer == null) {
83817
84124
  console.warn('Invalid renderer id "'.concat(rendererID, '" for element "').concat(id, '"'));
83818
84125
  } else {
83819
- renderer.deletePath(type, id, hookID, path25);
84126
+ renderer.deletePath(type, id, hookID, path26);
83820
84127
  }
83821
84128
  });
83822
84129
  agent_defineProperty(_this, "getBackendVersion", function() {
@@ -83853,12 +84160,12 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
83853
84160
  }
83854
84161
  });
83855
84162
  agent_defineProperty(_this, "inspectElement", function(_ref9) {
83856
- var { forceFullData, id, path: path25, rendererID, requestID } = _ref9;
84163
+ var { forceFullData, id, path: path26, rendererID, requestID } = _ref9;
83857
84164
  var renderer = _this._rendererInterfaces[rendererID];
83858
84165
  if (renderer == null) {
83859
84166
  console.warn('Invalid renderer id "'.concat(rendererID, '" for element "').concat(id, '"'));
83860
84167
  } else {
83861
- _this._bridge.send("inspectedElement", renderer.inspectElement(requestID, id, path25, forceFullData));
84168
+ _this._bridge.send("inspectedElement", renderer.inspectElement(requestID, id, path26, forceFullData));
83862
84169
  if (_this._persistedSelectionMatch === null || _this._persistedSelectionMatch.id !== id) {
83863
84170
  _this._persistedSelection = null;
83864
84171
  _this._persistedSelectionMatch = null;
@@ -83892,15 +84199,15 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
83892
84199
  }
83893
84200
  for (var rendererID in _this._rendererInterfaces) {
83894
84201
  var renderer = _this._rendererInterfaces[rendererID];
83895
- var path25 = null;
84202
+ var path26 = null;
83896
84203
  if (suspendedByPathIndex !== null && rendererPath !== null) {
83897
84204
  var suspendedByPathRendererIndex = suspendedByPathIndex - suspendedByOffset;
83898
84205
  var rendererHasRequestedSuspendedByPath = renderer.getElementAttributeByPath(id, ["suspendedBy", suspendedByPathRendererIndex]) !== undefined;
83899
84206
  if (rendererHasRequestedSuspendedByPath) {
83900
- path25 = ["suspendedBy", suspendedByPathRendererIndex].concat(rendererPath);
84207
+ path26 = ["suspendedBy", suspendedByPathRendererIndex].concat(rendererPath);
83901
84208
  }
83902
84209
  }
83903
- var inspectedRootsPayload = renderer.inspectElement(requestID, id, path25, forceFullData);
84210
+ var inspectedRootsPayload = renderer.inspectElement(requestID, id, path26, forceFullData);
83904
84211
  switch (inspectedRootsPayload.type) {
83905
84212
  case "hydrated-path":
83906
84213
  inspectedRootsPayload.path[1] += suspendedByOffset;
@@ -83994,20 +84301,20 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
83994
84301
  }
83995
84302
  });
83996
84303
  agent_defineProperty(_this, "overrideValueAtPath", function(_ref15) {
83997
- var { hookID, id, path: path25, rendererID, type, value } = _ref15;
84304
+ var { hookID, id, path: path26, rendererID, type, value } = _ref15;
83998
84305
  var renderer = _this._rendererInterfaces[rendererID];
83999
84306
  if (renderer == null) {
84000
84307
  console.warn('Invalid renderer id "'.concat(rendererID, '" for element "').concat(id, '"'));
84001
84308
  } else {
84002
- renderer.overrideValueAtPath(type, id, hookID, path25, value);
84309
+ renderer.overrideValueAtPath(type, id, hookID, path26, value);
84003
84310
  }
84004
84311
  });
84005
84312
  agent_defineProperty(_this, "overrideContext", function(_ref16) {
84006
- var { id, path: path25, rendererID, wasForwarded, value } = _ref16;
84313
+ var { id, path: path26, rendererID, wasForwarded, value } = _ref16;
84007
84314
  if (!wasForwarded) {
84008
84315
  _this.overrideValueAtPath({
84009
84316
  id,
84010
- path: path25,
84317
+ path: path26,
84011
84318
  rendererID,
84012
84319
  type: "context",
84013
84320
  value
@@ -84015,11 +84322,11 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
84015
84322
  }
84016
84323
  });
84017
84324
  agent_defineProperty(_this, "overrideHookState", function(_ref17) {
84018
- var { id, hookID, path: path25, rendererID, wasForwarded, value } = _ref17;
84325
+ var { id, hookID, path: path26, rendererID, wasForwarded, value } = _ref17;
84019
84326
  if (!wasForwarded) {
84020
84327
  _this.overrideValueAtPath({
84021
84328
  id,
84022
- path: path25,
84329
+ path: path26,
84023
84330
  rendererID,
84024
84331
  type: "hooks",
84025
84332
  value
@@ -84027,11 +84334,11 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
84027
84334
  }
84028
84335
  });
84029
84336
  agent_defineProperty(_this, "overrideProps", function(_ref18) {
84030
- var { id, path: path25, rendererID, wasForwarded, value } = _ref18;
84337
+ var { id, path: path26, rendererID, wasForwarded, value } = _ref18;
84031
84338
  if (!wasForwarded) {
84032
84339
  _this.overrideValueAtPath({
84033
84340
  id,
84034
- path: path25,
84341
+ path: path26,
84035
84342
  rendererID,
84036
84343
  type: "props",
84037
84344
  value
@@ -84039,11 +84346,11 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
84039
84346
  }
84040
84347
  });
84041
84348
  agent_defineProperty(_this, "overrideState", function(_ref19) {
84042
- var { id, path: path25, rendererID, wasForwarded, value } = _ref19;
84349
+ var { id, path: path26, rendererID, wasForwarded, value } = _ref19;
84043
84350
  if (!wasForwarded) {
84044
84351
  _this.overrideValueAtPath({
84045
84352
  id,
84046
- path: path25,
84353
+ path: path26,
84047
84354
  rendererID,
84048
84355
  type: "state",
84049
84356
  value
@@ -84110,12 +84417,12 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
84110
84417
  _this._bridge.send("stopInspectingHost", selected);
84111
84418
  });
84112
84419
  agent_defineProperty(_this, "storeAsGlobal", function(_ref23) {
84113
- var { count, id, path: path25, rendererID } = _ref23;
84420
+ var { count, id, path: path26, rendererID } = _ref23;
84114
84421
  var renderer = _this._rendererInterfaces[rendererID];
84115
84422
  if (renderer == null) {
84116
84423
  console.warn('Invalid renderer id "'.concat(rendererID, '" for element "').concat(id, '"'));
84117
84424
  } else {
84118
- renderer.storeAsGlobal(id, path25, count);
84425
+ renderer.storeAsGlobal(id, path26, count);
84119
84426
  }
84120
84427
  });
84121
84428
  agent_defineProperty(_this, "updateHookSettings", function(settings) {
@@ -84132,12 +84439,12 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
84132
84439
  var rendererID = +rendererIDString;
84133
84440
  var renderer = _this._rendererInterfaces[rendererID];
84134
84441
  if (_this._lastSelectedRendererID === rendererID) {
84135
- var path25 = renderer.getPathForElement(_this._lastSelectedElementID);
84136
- if (path25 !== null) {
84137
- renderer.setTrackedPath(path25);
84442
+ var path26 = renderer.getPathForElement(_this._lastSelectedElementID);
84443
+ if (path26 !== null) {
84444
+ renderer.setTrackedPath(path26);
84138
84445
  _this._persistedSelection = {
84139
84446
  rendererID,
84140
- path: path25
84447
+ path: path26
84141
84448
  };
84142
84449
  }
84143
84450
  }
@@ -84212,11 +84519,11 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
84212
84519
  var rendererID = _this._lastSelectedRendererID;
84213
84520
  var id = _this._lastSelectedElementID;
84214
84521
  var renderer = _this._rendererInterfaces[rendererID];
84215
- var path25 = renderer != null ? renderer.getPathForElement(id) : null;
84216
- if (path25 !== null) {
84522
+ var path26 = renderer != null ? renderer.getPathForElement(id) : null;
84523
+ if (path26 !== null) {
84217
84524
  storage_sessionStorageSetItem(SESSION_STORAGE_LAST_SELECTION_KEY, JSON.stringify({
84218
84525
  rendererID,
84219
- path: path25
84526
+ path: path26
84220
84527
  }));
84221
84528
  } else {
84222
84529
  storage_sessionStorageRemoveItem(SESSION_STORAGE_LAST_SELECTION_KEY);
@@ -84939,7 +85246,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
84939
85246
  hasElementWithId: function hasElementWithId() {
84940
85247
  return false;
84941
85248
  },
84942
- inspectElement: function inspectElement(requestID, id, path25) {
85249
+ inspectElement: function inspectElement(requestID, id, path26) {
84943
85250
  return {
84944
85251
  id,
84945
85252
  responseID: requestID,
@@ -90209,9 +90516,9 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
90209
90516
  }
90210
90517
  return null;
90211
90518
  }
90212
- function getElementAttributeByPath(id, path25) {
90519
+ function getElementAttributeByPath(id, path26) {
90213
90520
  if (isMostRecentlyInspectedElement(id)) {
90214
- return utils_getInObject(mostRecentlyInspectedElement, path25);
90521
+ return utils_getInObject(mostRecentlyInspectedElement, path26);
90215
90522
  }
90216
90523
  return;
90217
90524
  }
@@ -90914,9 +91221,9 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
90914
91221
  function isMostRecentlyInspectedElementCurrent(id) {
90915
91222
  return isMostRecentlyInspectedElement(id) && !hasElementUpdatedSinceLastInspected;
90916
91223
  }
90917
- function mergeInspectedPaths(path25) {
91224
+ function mergeInspectedPaths(path26) {
90918
91225
  var current = currentlyInspectedPaths;
90919
- path25.forEach(function(key) {
91226
+ path26.forEach(function(key) {
90920
91227
  if (!current[key]) {
90921
91228
  current[key] = {};
90922
91229
  }
@@ -90924,21 +91231,21 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
90924
91231
  });
90925
91232
  }
90926
91233
  function createIsPathAllowed(key, secondaryCategory) {
90927
- return function isPathAllowed(path25) {
91234
+ return function isPathAllowed(path26) {
90928
91235
  switch (secondaryCategory) {
90929
91236
  case "hooks":
90930
- if (path25.length === 1) {
91237
+ if (path26.length === 1) {
90931
91238
  return true;
90932
91239
  }
90933
- if (path25[path25.length - 2] === "hookSource" && path25[path25.length - 1] === "fileName") {
91240
+ if (path26[path26.length - 2] === "hookSource" && path26[path26.length - 1] === "fileName") {
90934
91241
  return true;
90935
91242
  }
90936
- if (path25[path25.length - 1] === "subHooks" || path25[path25.length - 2] === "subHooks") {
91243
+ if (path26[path26.length - 1] === "subHooks" || path26[path26.length - 2] === "subHooks") {
90937
91244
  return true;
90938
91245
  }
90939
91246
  break;
90940
91247
  case "suspendedBy":
90941
- if (path25.length < 5) {
91248
+ if (path26.length < 5) {
90942
91249
  return true;
90943
91250
  }
90944
91251
  break;
@@ -90949,8 +91256,8 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
90949
91256
  if (!current) {
90950
91257
  return false;
90951
91258
  }
90952
- for (var i = 0;i < path25.length; i++) {
90953
- current = current[path25[i]];
91259
+ for (var i = 0;i < path26.length; i++) {
91260
+ current = current[path26[i]];
90954
91261
  if (!current) {
90955
91262
  return false;
90956
91263
  }
@@ -91004,38 +91311,38 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
91004
91311
  break;
91005
91312
  }
91006
91313
  }
91007
- function storeAsGlobal(id, path25, count) {
91314
+ function storeAsGlobal(id, path26, count) {
91008
91315
  if (isMostRecentlyInspectedElement(id)) {
91009
- var value = utils_getInObject(mostRecentlyInspectedElement, path25);
91316
+ var value = utils_getInObject(mostRecentlyInspectedElement, path26);
91010
91317
  var key = "$reactTemp".concat(count);
91011
91318
  window[key] = value;
91012
91319
  console.log(key);
91013
91320
  console.log(value);
91014
91321
  }
91015
91322
  }
91016
- function getSerializedElementValueByPath(id, path25) {
91323
+ function getSerializedElementValueByPath(id, path26) {
91017
91324
  if (isMostRecentlyInspectedElement(id)) {
91018
- var valueToCopy = utils_getInObject(mostRecentlyInspectedElement, path25);
91325
+ var valueToCopy = utils_getInObject(mostRecentlyInspectedElement, path26);
91019
91326
  return serializeToString(valueToCopy);
91020
91327
  }
91021
91328
  }
91022
- function inspectElement(requestID, id, path25, forceFullData) {
91023
- if (path25 !== null) {
91024
- mergeInspectedPaths(path25);
91329
+ function inspectElement(requestID, id, path26, forceFullData) {
91330
+ if (path26 !== null) {
91331
+ mergeInspectedPaths(path26);
91025
91332
  }
91026
91333
  if (isMostRecentlyInspectedElement(id) && !forceFullData) {
91027
91334
  if (!hasElementUpdatedSinceLastInspected) {
91028
- if (path25 !== null) {
91335
+ if (path26 !== null) {
91029
91336
  var secondaryCategory = null;
91030
- if (path25[0] === "hooks" || path25[0] === "suspendedBy") {
91031
- secondaryCategory = path25[0];
91337
+ if (path26[0] === "hooks" || path26[0] === "suspendedBy") {
91338
+ secondaryCategory = path26[0];
91032
91339
  }
91033
91340
  return {
91034
91341
  id,
91035
91342
  responseID: requestID,
91036
91343
  type: "hydrated-path",
91037
- path: path25,
91038
- value: cleanForBridge(utils_getInObject(mostRecentlyInspectedElement, path25), createIsPathAllowed(null, secondaryCategory), path25)
91344
+ path: path26,
91345
+ value: cleanForBridge(utils_getInObject(mostRecentlyInspectedElement, path26), createIsPathAllowed(null, secondaryCategory), path26)
91039
91346
  };
91040
91347
  } else {
91041
91348
  return {
@@ -91231,7 +91538,7 @@ The error thrown in the component is:
91231
91538
  console.groupEnd();
91232
91539
  }
91233
91540
  }
91234
- function deletePath(type, id, hookID, path25) {
91541
+ function deletePath(type, id, hookID, path26) {
91235
91542
  var devtoolsInstance = idToDevToolsInstanceMap.get(id);
91236
91543
  if (devtoolsInstance === undefined) {
91237
91544
  console.warn('Could not find DevToolsInstance with id "'.concat(id, '"'));
@@ -91245,11 +91552,11 @@ The error thrown in the component is:
91245
91552
  var instance2 = fiber.stateNode;
91246
91553
  switch (type) {
91247
91554
  case "context":
91248
- path25 = path25.slice(1);
91555
+ path26 = path26.slice(1);
91249
91556
  switch (fiber.tag) {
91250
91557
  case ClassComponent:
91251
- if (path25.length === 0) {} else {
91252
- deletePathInObject(instance2.context, path25);
91558
+ if (path26.length === 0) {} else {
91559
+ deletePathInObject(instance2.context, path26);
91253
91560
  }
91254
91561
  instance2.forceUpdate();
91255
91562
  break;
@@ -91259,21 +91566,21 @@ The error thrown in the component is:
91259
91566
  break;
91260
91567
  case "hooks":
91261
91568
  if (typeof overrideHookStateDeletePath === "function") {
91262
- overrideHookStateDeletePath(fiber, hookID, path25);
91569
+ overrideHookStateDeletePath(fiber, hookID, path26);
91263
91570
  }
91264
91571
  break;
91265
91572
  case "props":
91266
91573
  if (instance2 === null) {
91267
91574
  if (typeof overridePropsDeletePath === "function") {
91268
- overridePropsDeletePath(fiber, path25);
91575
+ overridePropsDeletePath(fiber, path26);
91269
91576
  }
91270
91577
  } else {
91271
- fiber.pendingProps = copyWithDelete(instance2.props, path25);
91578
+ fiber.pendingProps = copyWithDelete(instance2.props, path26);
91272
91579
  instance2.forceUpdate();
91273
91580
  }
91274
91581
  break;
91275
91582
  case "state":
91276
- deletePathInObject(instance2.state, path25);
91583
+ deletePathInObject(instance2.state, path26);
91277
91584
  instance2.forceUpdate();
91278
91585
  break;
91279
91586
  }
@@ -91328,7 +91635,7 @@ The error thrown in the component is:
91328
91635
  }
91329
91636
  }
91330
91637
  }
91331
- function overrideValueAtPath(type, id, hookID, path25, value) {
91638
+ function overrideValueAtPath(type, id, hookID, path26, value) {
91332
91639
  var devtoolsInstance = idToDevToolsInstanceMap.get(id);
91333
91640
  if (devtoolsInstance === undefined) {
91334
91641
  console.warn('Could not find DevToolsInstance with id "'.concat(id, '"'));
@@ -91342,13 +91649,13 @@ The error thrown in the component is:
91342
91649
  var instance2 = fiber.stateNode;
91343
91650
  switch (type) {
91344
91651
  case "context":
91345
- path25 = path25.slice(1);
91652
+ path26 = path26.slice(1);
91346
91653
  switch (fiber.tag) {
91347
91654
  case ClassComponent:
91348
- if (path25.length === 0) {
91655
+ if (path26.length === 0) {
91349
91656
  instance2.context = value;
91350
91657
  } else {
91351
- utils_setInObject(instance2.context, path25, value);
91658
+ utils_setInObject(instance2.context, path26, value);
91352
91659
  }
91353
91660
  instance2.forceUpdate();
91354
91661
  break;
@@ -91358,18 +91665,18 @@ The error thrown in the component is:
91358
91665
  break;
91359
91666
  case "hooks":
91360
91667
  if (typeof overrideHookState === "function") {
91361
- overrideHookState(fiber, hookID, path25, value);
91668
+ overrideHookState(fiber, hookID, path26, value);
91362
91669
  }
91363
91670
  break;
91364
91671
  case "props":
91365
91672
  switch (fiber.tag) {
91366
91673
  case ClassComponent:
91367
- fiber.pendingProps = copyWithSet(instance2.props, path25, value);
91674
+ fiber.pendingProps = copyWithSet(instance2.props, path26, value);
91368
91675
  instance2.forceUpdate();
91369
91676
  break;
91370
91677
  default:
91371
91678
  if (typeof overrideProps === "function") {
91372
- overrideProps(fiber, path25, value);
91679
+ overrideProps(fiber, path26, value);
91373
91680
  }
91374
91681
  break;
91375
91682
  }
@@ -91377,7 +91684,7 @@ The error thrown in the component is:
91377
91684
  case "state":
91378
91685
  switch (fiber.tag) {
91379
91686
  case ClassComponent:
91380
- utils_setInObject(instance2.state, path25, value);
91687
+ utils_setInObject(instance2.state, path26, value);
91381
91688
  instance2.forceUpdate();
91382
91689
  break;
91383
91690
  }
@@ -91663,14 +91970,14 @@ The error thrown in the component is:
91663
91970
  var trackedPathMatchInstance = null;
91664
91971
  var trackedPathMatchDepth = -1;
91665
91972
  var mightBeOnTrackedPath = false;
91666
- function setTrackedPath(path25) {
91667
- if (path25 === null) {
91973
+ function setTrackedPath(path26) {
91974
+ if (path26 === null) {
91668
91975
  trackedPathMatchFiber = null;
91669
91976
  trackedPathMatchInstance = null;
91670
91977
  trackedPathMatchDepth = -1;
91671
91978
  mightBeOnTrackedPath = false;
91672
91979
  }
91673
- trackedPath = path25;
91980
+ trackedPath = path26;
91674
91981
  }
91675
91982
  function updateTrackedPathStateBeforeMount(fiber, fiberInstance) {
91676
91983
  if (trackedPath === null || !mightBeOnTrackedPath) {
@@ -92434,9 +92741,9 @@ The error thrown in the component is:
92434
92741
  }
92435
92742
  var currentlyInspectedElementID = null;
92436
92743
  var currentlyInspectedPaths = {};
92437
- function mergeInspectedPaths(path25) {
92744
+ function mergeInspectedPaths(path26) {
92438
92745
  var current = currentlyInspectedPaths;
92439
- path25.forEach(function(key) {
92746
+ path26.forEach(function(key) {
92440
92747
  if (!current[key]) {
92441
92748
  current[key] = {};
92442
92749
  }
@@ -92444,13 +92751,13 @@ The error thrown in the component is:
92444
92751
  });
92445
92752
  }
92446
92753
  function createIsPathAllowed(key) {
92447
- return function isPathAllowed(path25) {
92754
+ return function isPathAllowed(path26) {
92448
92755
  var current = currentlyInspectedPaths[key];
92449
92756
  if (!current) {
92450
92757
  return false;
92451
92758
  }
92452
- for (var i = 0;i < path25.length; i++) {
92453
- current = current[path25[i]];
92759
+ for (var i = 0;i < path26.length; i++) {
92760
+ current = current[path26[i]];
92454
92761
  if (!current) {
92455
92762
  return false;
92456
92763
  }
@@ -92500,24 +92807,24 @@ The error thrown in the component is:
92500
92807
  break;
92501
92808
  }
92502
92809
  }
92503
- function storeAsGlobal(id, path25, count) {
92810
+ function storeAsGlobal(id, path26, count) {
92504
92811
  var inspectedElement = inspectElementRaw(id);
92505
92812
  if (inspectedElement !== null) {
92506
- var value = utils_getInObject(inspectedElement, path25);
92813
+ var value = utils_getInObject(inspectedElement, path26);
92507
92814
  var key = "$reactTemp".concat(count);
92508
92815
  window[key] = value;
92509
92816
  console.log(key);
92510
92817
  console.log(value);
92511
92818
  }
92512
92819
  }
92513
- function getSerializedElementValueByPath(id, path25) {
92820
+ function getSerializedElementValueByPath(id, path26) {
92514
92821
  var inspectedElement = inspectElementRaw(id);
92515
92822
  if (inspectedElement !== null) {
92516
- var valueToCopy = utils_getInObject(inspectedElement, path25);
92823
+ var valueToCopy = utils_getInObject(inspectedElement, path26);
92517
92824
  return serializeToString(valueToCopy);
92518
92825
  }
92519
92826
  }
92520
- function inspectElement(requestID, id, path25, forceFullData) {
92827
+ function inspectElement(requestID, id, path26, forceFullData) {
92521
92828
  if (forceFullData || currentlyInspectedElementID !== id) {
92522
92829
  currentlyInspectedElementID = id;
92523
92830
  currentlyInspectedPaths = {};
@@ -92530,8 +92837,8 @@ The error thrown in the component is:
92530
92837
  type: "not-found"
92531
92838
  };
92532
92839
  }
92533
- if (path25 !== null) {
92534
- mergeInspectedPaths(path25);
92840
+ if (path26 !== null) {
92841
+ mergeInspectedPaths(path26);
92535
92842
  }
92536
92843
  updateSelectedElement(id);
92537
92844
  inspectedElement.context = cleanForBridge(inspectedElement.context, createIsPathAllowed("context"));
@@ -92734,10 +93041,10 @@ The error thrown in the component is:
92734
93041
  console.groupEnd();
92735
93042
  }
92736
93043
  }
92737
- function getElementAttributeByPath(id, path25) {
93044
+ function getElementAttributeByPath(id, path26) {
92738
93045
  var inspectedElement = inspectElementRaw(id);
92739
93046
  if (inspectedElement !== null) {
92740
- return utils_getInObject(inspectedElement, path25);
93047
+ return utils_getInObject(inspectedElement, path26);
92741
93048
  }
92742
93049
  return;
92743
93050
  }
@@ -92754,14 +93061,14 @@ The error thrown in the component is:
92754
93061
  }
92755
93062
  return element.type;
92756
93063
  }
92757
- function deletePath(type, id, hookID, path25) {
93064
+ function deletePath(type, id, hookID, path26) {
92758
93065
  var internalInstance = idToInternalInstanceMap.get(id);
92759
93066
  if (internalInstance != null) {
92760
93067
  var publicInstance = internalInstance._instance;
92761
93068
  if (publicInstance != null) {
92762
93069
  switch (type) {
92763
93070
  case "context":
92764
- deletePathInObject(publicInstance.context, path25);
93071
+ deletePathInObject(publicInstance.context, path26);
92765
93072
  forceUpdate(publicInstance);
92766
93073
  break;
92767
93074
  case "hooks":
@@ -92769,12 +93076,12 @@ The error thrown in the component is:
92769
93076
  case "props":
92770
93077
  var element = internalInstance._currentElement;
92771
93078
  internalInstance._currentElement = legacy_renderer_objectSpread(legacy_renderer_objectSpread({}, element), {}, {
92772
- props: copyWithDelete(element.props, path25)
93079
+ props: copyWithDelete(element.props, path26)
92773
93080
  });
92774
93081
  forceUpdate(publicInstance);
92775
93082
  break;
92776
93083
  case "state":
92777
- deletePathInObject(publicInstance.state, path25);
93084
+ deletePathInObject(publicInstance.state, path26);
92778
93085
  forceUpdate(publicInstance);
92779
93086
  break;
92780
93087
  }
@@ -92808,14 +93115,14 @@ The error thrown in the component is:
92808
93115
  }
92809
93116
  }
92810
93117
  }
92811
- function overrideValueAtPath(type, id, hookID, path25, value) {
93118
+ function overrideValueAtPath(type, id, hookID, path26, value) {
92812
93119
  var internalInstance = idToInternalInstanceMap.get(id);
92813
93120
  if (internalInstance != null) {
92814
93121
  var publicInstance = internalInstance._instance;
92815
93122
  if (publicInstance != null) {
92816
93123
  switch (type) {
92817
93124
  case "context":
92818
- utils_setInObject(publicInstance.context, path25, value);
93125
+ utils_setInObject(publicInstance.context, path26, value);
92819
93126
  forceUpdate(publicInstance);
92820
93127
  break;
92821
93128
  case "hooks":
@@ -92823,12 +93130,12 @@ The error thrown in the component is:
92823
93130
  case "props":
92824
93131
  var element = internalInstance._currentElement;
92825
93132
  internalInstance._currentElement = legacy_renderer_objectSpread(legacy_renderer_objectSpread({}, element), {}, {
92826
- props: copyWithSet(element.props, path25, value)
93133
+ props: copyWithSet(element.props, path26, value)
92827
93134
  });
92828
93135
  forceUpdate(publicInstance);
92829
93136
  break;
92830
93137
  case "state":
92831
- utils_setInObject(publicInstance.state, path25, value);
93138
+ utils_setInObject(publicInstance.state, path26, value);
92832
93139
  forceUpdate(publicInstance);
92833
93140
  break;
92834
93141
  }
@@ -92869,7 +93176,7 @@ The error thrown in the component is:
92869
93176
  return [];
92870
93177
  }
92871
93178
  function setTraceUpdatesEnabled(enabled) {}
92872
- function setTrackedPath(path25) {}
93179
+ function setTrackedPath(path26) {}
92873
93180
  function getOwnersList(id) {
92874
93181
  return null;
92875
93182
  }
@@ -96178,10 +96485,10 @@ init_setup();
96178
96485
  // src/cli/plugins.ts
96179
96486
  init_paths();
96180
96487
  init_loader4();
96181
- import * as path17 from "path";
96488
+ import * as path18 from "path";
96182
96489
  async function pluginsListCommand(config2, workdir, overrideGlobalPluginsDir) {
96183
- const globalPluginsDir = overrideGlobalPluginsDir ?? path17.join(globalConfigDir(), "plugins");
96184
- const projectPluginsDir = path17.join(workdir, ".nax", "plugins");
96490
+ const globalPluginsDir = overrideGlobalPluginsDir ?? path18.join(globalConfigDir(), "plugins");
96491
+ const projectPluginsDir = path18.join(workdir, ".nax", "plugins");
96185
96492
  const configPlugins = config2.plugins || [];
96186
96493
  const registry2 = await loadPlugins(globalPluginsDir, projectPluginsDir, configPlugins, workdir, config2.disabledPlugins);
96187
96494
  const plugins = registry2.plugins;
@@ -96231,10 +96538,10 @@ function formatSource(type, sourcePath) {
96231
96538
  return `built-in (${sourcePath})`;
96232
96539
  }
96233
96540
  if (type === "global") {
96234
- return `global (${path17.basename(sourcePath)})`;
96541
+ return `global (${path18.basename(sourcePath)})`;
96235
96542
  }
96236
96543
  if (type === "project") {
96237
- return `project (${path17.basename(sourcePath)})`;
96544
+ return `project (${path18.basename(sourcePath)})`;
96238
96545
  }
96239
96546
  return `config (${sourcePath})`;
96240
96547
  }
@@ -96626,10 +96933,10 @@ function deepDiffConfigs(global2, project, currentPath = []) {
96626
96933
  for (const key of Object.keys(project)) {
96627
96934
  const projectValue = project[key];
96628
96935
  const globalValue = global2[key];
96629
- const path18 = [...currentPath, key];
96630
- const pathStr = path18.join(".");
96936
+ const path19 = [...currentPath, key];
96937
+ const pathStr = path19.join(".");
96631
96938
  if (projectValue !== null && typeof projectValue === "object" && !Array.isArray(projectValue) && globalValue !== null && typeof globalValue === "object" && !Array.isArray(globalValue)) {
96632
- const nestedDiffs = deepDiffConfigs(globalValue, projectValue, path18);
96939
+ const nestedDiffs = deepDiffConfigs(globalValue, projectValue, path19);
96633
96940
  diffs.push(...nestedDiffs);
96634
96941
  } else {
96635
96942
  if (!deepEqual(projectValue, globalValue)) {
@@ -96672,11 +96979,11 @@ init_defaults();
96672
96979
  init_loader();
96673
96980
  import { existsSync as existsSync25 } from "fs";
96674
96981
  import { join as join63 } from "path";
96675
- async function loadConfigFile(path18) {
96676
- if (!existsSync25(path18))
96982
+ async function loadConfigFile(path19) {
96983
+ if (!existsSync25(path19))
96677
96984
  return null;
96678
96985
  try {
96679
- return await Bun.file(path18).json();
96986
+ return await Bun.file(path19).json();
96680
96987
  } catch {
96681
96988
  return null;
96682
96989
  }
@@ -96723,10 +97030,10 @@ async function configCommand(config2, options = {}) {
96723
97030
  console.log(`${"Field".padEnd(40)}${"Project Value".padEnd(20)}Global Value`);
96724
97031
  console.log("\u2500".repeat(80));
96725
97032
  for (const diff2 of diffs) {
96726
- const path18 = diff2.path.padEnd(40);
97033
+ const path19 = diff2.path.padEnd(40);
96727
97034
  const projectVal = formatValueForTable(diff2.projectValue);
96728
97035
  const globalVal = formatValueForTable(diff2.globalValue);
96729
- console.log(`${path18}${projectVal.padEnd(20)}${globalVal}`);
97036
+ console.log(`${path19}${projectVal.padEnd(20)}${globalVal}`);
96730
97037
  const description = FIELD_DESCRIPTIONS[diff2.path];
96731
97038
  if (description) {
96732
97039
  console.log(`${"".padEnd(40)}\u21B3 ${description}`);
@@ -96759,26 +97066,26 @@ function determineConfigSources() {
96759
97066
  project: projectPath && fileExists(projectPath) ? projectPath : null
96760
97067
  };
96761
97068
  }
96762
- function fileExists(path18) {
96763
- return existsSync26(path18);
97069
+ function fileExists(path19) {
97070
+ return existsSync26(path19);
96764
97071
  }
96765
- function displayConfigWithDescriptions(obj, path18, sources, indent = 0) {
97072
+ function displayConfigWithDescriptions(obj, path19, sources, indent = 0) {
96766
97073
  const indentStr = " ".repeat(indent);
96767
- const pathStr = path18.join(".");
97074
+ const pathStr = path19.join(".");
96768
97075
  if (obj === null || obj === undefined || typeof obj !== "object" || Array.isArray(obj)) {
96769
97076
  const description = FIELD_DESCRIPTIONS[pathStr];
96770
97077
  const value = formatValue(obj);
96771
97078
  if (description) {
96772
97079
  console.log(`${indentStr}# ${description}`);
96773
97080
  }
96774
- const key = path18[path18.length - 1] || "";
97081
+ const key = path19[path19.length - 1] || "";
96775
97082
  console.log(`${indentStr}${key}: ${value}`);
96776
97083
  console.log();
96777
97084
  return;
96778
97085
  }
96779
97086
  const entries = Object.entries(obj);
96780
97087
  const objAsRecord = obj;
96781
- const isPromptsSection = path18.join(".") === "prompts";
97088
+ const isPromptsSection = path19.join(".") === "prompts";
96782
97089
  if (isPromptsSection && !objAsRecord.overrides) {
96783
97090
  const description = FIELD_DESCRIPTIONS["prompts.overrides"];
96784
97091
  if (description) {
@@ -96801,7 +97108,7 @@ function displayConfigWithDescriptions(obj, path18, sources, indent = 0) {
96801
97108
  }
96802
97109
  for (let i = 0;i < entries.length; i++) {
96803
97110
  const [key, value] = entries[i];
96804
- const currentPath = [...path18, key];
97111
+ const currentPath = [...path19, key];
96805
97112
  const currentPathStr = currentPath.join(".");
96806
97113
  const description = FIELD_DESCRIPTIONS[currentPathStr];
96807
97114
  if (description) {
@@ -97113,11 +97420,11 @@ init_errors();
97113
97420
  import { mkdir as mkdir11 } from "fs/promises";
97114
97421
  import { basename as basename12, join as join66 } from "path";
97115
97422
  var _rulesCLIDeps = {
97116
- readFile: async (path18) => Bun.file(path18).text(),
97117
- writeFile: async (path18, content) => {
97118
- await Bun.write(path18, content);
97423
+ readFile: async (path19) => Bun.file(path19).text(),
97424
+ writeFile: async (path19, content) => {
97425
+ await Bun.write(path19, content);
97119
97426
  },
97120
- fileExists: async (path18) => Bun.file(path18).exists(),
97427
+ fileExists: async (path19) => Bun.file(path19).exists(),
97121
97428
  globInDir: (dir) => {
97122
97429
  try {
97123
97430
  return [...new Bun.Glob("*.md").scanSync({ cwd: dir })].sort().map((f) => join66(dir, f));
@@ -97125,8 +97432,8 @@ var _rulesCLIDeps = {
97125
97432
  return [];
97126
97433
  }
97127
97434
  },
97128
- mkdir: async (path18) => {
97129
- await mkdir11(path18, { recursive: true });
97435
+ mkdir: async (path19) => {
97436
+ await mkdir11(path19, { recursive: true });
97130
97437
  },
97131
97438
  globCanonicalRuleFiles: (workdir) => {
97132
97439
  try {
@@ -97290,6 +97597,35 @@ async function rulesLintCommand(options) {
97290
97597
  const scopeLabel = roots.length === 1 ? "repo root" : `${roots.length} rule roots`;
97291
97598
  console.log(`[OK] Canonical rules lint passed (${totalRuleFiles} file(s) across ${scopeLabel}).`);
97292
97599
  }
97600
+ // src/cli/resolve-run-profile.ts
97601
+ init_config();
97602
+ init_logger2();
97603
+ async function resolveRunProfileOverride(opts) {
97604
+ if (opts.cliProfile)
97605
+ return opts.cliProfile;
97606
+ if (opts.envProfile)
97607
+ return;
97608
+ const readJson = opts._readJson ?? (async (path19) => {
97609
+ const file3 = Bun.file(path19);
97610
+ if (!await file3.exists())
97611
+ return;
97612
+ return file3.json();
97613
+ });
97614
+ try {
97615
+ const prd = await readJson(opts.prdPath);
97616
+ if (prd && typeof prd.routingProfile === "string" && prd.routingProfile.length > 0) {
97617
+ const name = prd.routingProfile;
97618
+ if (name === "default")
97619
+ return name;
97620
+ const listNames = opts._listProfileNames ?? (async () => (await listProfiles(opts.projectRoot)).map((p) => p.name));
97621
+ const available = await listNames();
97622
+ if (available.includes(name))
97623
+ return name;
97624
+ 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 });
97625
+ }
97626
+ } catch {}
97627
+ return;
97628
+ }
97293
97629
  // src/commands/detect.ts
97294
97630
  init_source();
97295
97631
  init_config();
@@ -97305,14 +97641,14 @@ function resolveEffective(detected, configPatterns) {
97305
97641
  return "detected";
97306
97642
  return "none";
97307
97643
  }
97308
- async function loadRawConfig(path18) {
97309
- const f = Bun.file(path18);
97644
+ async function loadRawConfig(path19) {
97645
+ const f = Bun.file(path19);
97310
97646
  if (!await f.exists())
97311
97647
  return {};
97312
97648
  return JSON.parse(await f.text());
97313
97649
  }
97314
- async function writeRawConfig(path18, data) {
97315
- await Bun.write(path18, `${JSON.stringify(data, null, 2)}
97650
+ async function writeRawConfig(path19, data) {
97651
+ await Bun.write(path19, `${JSON.stringify(data, null, 2)}
97316
97652
  `);
97317
97653
  }
97318
97654
  function deepSet(obj, keyPath, value) {
@@ -98020,7 +98356,7 @@ init_prd();
98020
98356
  init_git();
98021
98357
  init_crash_recovery();
98022
98358
  init_story_context();
98023
- import path19 from "path";
98359
+ import path20 from "path";
98024
98360
  var _runnerCompletionDeps = {
98025
98361
  async runAcceptanceLoop(ctx) {
98026
98362
  const { runAcceptanceLoop: runAcceptanceLoop2 } = await Promise.resolve().then(() => (init_acceptance_loop(), exports_acceptance_loop));
@@ -98051,11 +98387,11 @@ async function runCompletionPhase(options) {
98051
98387
  options.statusWriter.setPostRunPhase("acceptance", { status: "running" });
98052
98388
  pipelineEventBus.emit({ type: "postrun:phase:started", phase: "acceptance" });
98053
98389
  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) => {
98054
- const relativeWorkdir = path19.relative(options.workdir, g.packageDir);
98390
+ const relativeWorkdir = path20.relative(options.workdir, g.packageDir);
98055
98391
  let groupConfig = options.config;
98056
98392
  if (relativeWorkdir && relativeWorkdir !== ".") {
98057
98393
  try {
98058
- groupConfig = await _runnerCompletionDeps.loadConfigForWorkdir(path19.join(options.workdir, ".nax", "config.json"), relativeWorkdir);
98394
+ groupConfig = await _runnerCompletionDeps.loadConfigForWorkdir(path20.join(options.workdir, ".nax", "config.json"), relativeWorkdir);
98059
98395
  } catch (error48) {
98060
98396
  logger?.warn("execution", "Falling back to root config for package acceptance settings", {
98061
98397
  packageDir: g.packageDir,
@@ -103302,8 +103638,8 @@ function Text({ color, backgroundColor, dimColor = false, bold = false, italic =
103302
103638
  }
103303
103639
 
103304
103640
  // node_modules/ink/build/components/ErrorOverview.js
103305
- var cleanupPath = (path25) => {
103306
- return path25?.replace(`file://${cwd()}/`, "");
103641
+ var cleanupPath = (path26) => {
103642
+ return path26?.replace(`file://${cwd()}/`, "");
103307
103643
  };
103308
103644
  var stackUtils = new import_stack_utils.default({
103309
103645
  cwd: cwd(),
@@ -106574,8 +106910,14 @@ program2.command("run").description("Run the orchestration loop for a feature").
106574
106910
  }
106575
106911
  const naxDir = findProjectDir(workdir);
106576
106912
  const cliOverrides = {};
106577
- if (options.profile) {
106578
- cliOverrides.profile = options.profile;
106913
+ const profileOverride = naxDir ? await resolveRunProfileOverride({
106914
+ prdPath: join87(naxDir, "features", options.feature, "prd.json"),
106915
+ projectRoot: workdir,
106916
+ cliProfile: options.profile,
106917
+ envProfile: process.env.NAX_PROFILE
106918
+ }) : options.profile;
106919
+ if (profileOverride) {
106920
+ cliOverrides.profile = profileOverride;
106579
106921
  }
106580
106922
  const config2 = await loadConfig(naxDir ?? undefined, cliOverrides);
106581
106923
  if (!naxDir) {
@@ -107009,8 +107351,8 @@ configProfileCmd.command("current").description("Show the currently active profi
107009
107351
  });
107010
107352
  configProfileCmd.command("create <name>").description("Create a new empty profile").option("-d, --dir <path>", "Project directory", process.cwd()).action(async (name, options) => {
107011
107353
  try {
107012
- const path25 = await profileCreateCommand(name, options.dir);
107013
- console.log(`Created profile at: ${path25}`);
107354
+ const path26 = await profileCreateCommand(name, options.dir);
107355
+ console.log(`Created profile at: ${path26}`);
107014
107356
  } catch (err) {
107015
107357
  console.error(source_default.red(`Error: ${err.message}`));
107016
107358
  process.exit(1);