@nathapp/nax 0.59.3 → 0.60.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 +37 -23
  2. package/package.json +1 -1
package/dist/nax.js CHANGED
@@ -21444,14 +21444,20 @@ function tryParseLLMJson(text) {
21444
21444
  }
21445
21445
 
21446
21446
  // src/debate/resolvers.ts
21447
- function buildProposalsSection(proposals) {
21448
- return proposals.map((p, i) => `### Proposal ${i + 1}
21449
- ${p}`).join(`
21447
+ function buildDebaterLabel(debater) {
21448
+ return debater.persona ? `${debater.agent} (${debater.persona})` : debater.agent;
21449
+ }
21450
+ function buildProposalsSection(proposals, debaters) {
21451
+ return proposals.map((p, i) => {
21452
+ const label = debaters?.[i] ? buildDebaterLabel(debaters[i]) : String(i + 1);
21453
+ return `### Proposal ${label}
21454
+ ${p}`;
21455
+ }).join(`
21450
21456
 
21451
21457
  `);
21452
21458
  }
21453
- function buildSynthesisPrompt(proposals, critiques) {
21454
- const proposalsSection = buildProposalsSection(proposals);
21459
+ function buildSynthesisPrompt(proposals, critiques, debaters) {
21460
+ const proposalsSection = buildProposalsSection(proposals, debaters);
21455
21461
  const critiquesSection = critiques.length > 0 ? `
21456
21462
 
21457
21463
  ## Critiques
@@ -21466,8 +21472,8 @@ ${proposalsSection}${critiquesSection}
21466
21472
 
21467
21473
  Please synthesize these into the best possible unified response, incorporating the strongest elements from each proposal.`;
21468
21474
  }
21469
- function buildJudgePrompt(proposals, critiques) {
21470
- const proposalsSection = buildProposalsSection(proposals);
21475
+ function buildJudgePrompt(proposals, critiques, debaters) {
21476
+ const proposalsSection = buildProposalsSection(proposals, debaters);
21471
21477
  const critiquesSection = critiques.length > 0 ? `
21472
21478
 
21473
21479
  ## Critiques
@@ -21515,7 +21521,7 @@ function majorityResolver(proposals, failOpen) {
21515
21521
  return passCount > failCount ? "passed" : "failed";
21516
21522
  }
21517
21523
  async function synthesisResolver(proposals, critiques, opts) {
21518
- const base = buildSynthesisPrompt(proposals, critiques);
21524
+ const base = buildSynthesisPrompt(proposals, critiques, opts.debaters);
21519
21525
  const prompt = opts.promptSuffix ? `${base}
21520
21526
 
21521
21527
  ${opts.promptSuffix}` : base;
@@ -21527,7 +21533,7 @@ async function judgeResolver(proposals, critiques, resolverConfig, opts) {
21527
21533
  if (!adapter) {
21528
21534
  throw new Error(`[debate] Judge agent '${agentName}' not found`);
21529
21535
  }
21530
- const prompt = buildJudgePrompt(proposals, critiques);
21536
+ const prompt = buildJudgePrompt(proposals, critiques, opts.debaters);
21531
21537
  return adapter.complete(prompt, opts.completeOptions);
21532
21538
  }
21533
21539
  var DEFAULT_FALLBACK_AGENT = "claude";
@@ -21606,7 +21612,7 @@ function resolveModelDefForDebater(debater, tier, config2) {
21606
21612
  return resolveModelForAgent(configModels, debater.agent, "fast", configDefaultAgent);
21607
21613
  }
21608
21614
  }
21609
- async function resolveOutcome(proposalOutputs, critiqueOutputs, stageConfig, config2, storyId, timeoutMs, workdir, featureName, reviewerSession, resolverContext, promptSuffix) {
21615
+ async function resolveOutcome(proposalOutputs, critiqueOutputs, stageConfig, config2, storyId, timeoutMs, workdir, featureName, reviewerSession, resolverContext, promptSuffix, debaters) {
21610
21616
  const resolverConfig = stageConfig.resolver;
21611
21617
  const logger = _debateSessionDeps.getSafeLogger();
21612
21618
  if (reviewerSession && resolverContext) {
@@ -21675,6 +21681,7 @@ async function resolveOutcome(proposalOutputs, critiqueOutputs, stageConfig, con
21675
21681
  const resolverResult = await synthesisResolver(proposalOutputs, critiqueOutputs, {
21676
21682
  adapter,
21677
21683
  promptSuffix,
21684
+ debaters,
21678
21685
  completeOptions: {
21679
21686
  model: resolveDebaterModel({ agent: agentName }, config2),
21680
21687
  config: config2,
@@ -21700,6 +21707,7 @@ async function resolveOutcome(proposalOutputs, critiqueOutputs, stageConfig, con
21700
21707
  const resolverResult = await judgeResolver(proposalOutputs, critiqueOutputs, resolverConfig, {
21701
21708
  getAgent: (name) => _debateSessionDeps.getAgent(name, config2),
21702
21709
  defaultAgentName: RESOLVER_FALLBACK_AGENT,
21710
+ debaters,
21703
21711
  completeOptions: {
21704
21712
  model: resolveDebaterModel({ agent: agentName }, config2),
21705
21713
  config: config2,
@@ -21772,6 +21780,9 @@ function resolvePersonas(debaters, stage, autoPersona) {
21772
21780
  return { ...d, persona: assigned };
21773
21781
  });
21774
21782
  }
21783
+ function buildDebaterLabel2(debater) {
21784
+ return debater.persona ? `${debater.agent} (${debater.persona})` : debater.agent;
21785
+ }
21775
21786
  var PERSONA_FRAGMENTS, PLAN_ROTATION, REVIEW_ROTATION;
21776
21787
  var init_personas = __esm(() => {
21777
21788
  PERSONA_FRAGMENTS = {
@@ -21998,7 +22009,8 @@ async function runStateful(ctx, prompt) {
21998
22009
  });
21999
22010
  const debate = ctx.config?.debate;
22000
22011
  const concurrencyLimit = debate?.maxConcurrentDebaters ?? 2;
22001
- const proposalSettled = await allSettledBounded(resolved.map(({ debater, adapter }, debaterIdx) => () => runStatefulTurn(ctx, adapter, debater, prompt, `debate-${ctx.stage}-${debaterIdx}`, config2.rounds > 1)), concurrencyLimit);
22012
+ const proposalBuilder = new DebatePromptBuilder({ taskContext: prompt, outputFormat: "", stage: ctx.stage }, { debaters: resolved.map((r) => r.debater), sessionMode: "stateful" });
22013
+ const proposalSettled = await allSettledBounded(resolved.map(({ debater, adapter }, debaterIdx) => () => runStatefulTurn(ctx, adapter, debater, proposalBuilder.buildProposalPrompt(debaterIdx), `debate-${ctx.stage}-${debaterIdx}`, config2.rounds > 1)), concurrencyLimit);
22002
22014
  const successfulProposals = proposalSettled.filter((r) => r.status === "fulfilled").map((r) => r.value);
22003
22015
  for (const r of proposalSettled) {
22004
22016
  if (r.status === "fulfilled") {
@@ -22090,9 +22102,9 @@ async function runStateful(ctx, prompt) {
22090
22102
  const proposalOutputs = successfulProposals.map((s) => s.output);
22091
22103
  const fullResolverContext = ctx.resolverContextInput ? {
22092
22104
  ...ctx.resolverContextInput,
22093
- labeledProposals: successfulProposals.map((s) => ({ debater: s.debater.agent, output: s.output }))
22105
+ labeledProposals: successfulProposals.map((s) => ({ debater: buildDebaterLabel2(s.debater), output: s.output }))
22094
22106
  } : undefined;
22095
- const outcome = await resolveOutcome(proposalOutputs, critiqueOutputs, ctx.stageConfig, ctx.config, ctx.storyId, ctx.timeoutSeconds * 1000, ctx.workdir, ctx.featureName, ctx.reviewerSession, fullResolverContext);
22107
+ const outcome = await resolveOutcome(proposalOutputs, critiqueOutputs, ctx.stageConfig, ctx.config, ctx.storyId, ctx.timeoutSeconds * 1000, ctx.workdir, ctx.featureName, ctx.reviewerSession, fullResolverContext, undefined, successfulProposals.map((s) => s.debater));
22096
22108
  totalCostUsd += outcome.resolverCostUsd;
22097
22109
  const proposals = successfulProposals.map((s) => ({
22098
22110
  debater: s.debater,
@@ -22241,9 +22253,9 @@ async function runHybrid(ctx, prompt) {
22241
22253
  const critiqueOutputs = rebuttals.map((r) => r.output);
22242
22254
  const fullResolverContext = ctx.resolverContextInput ? {
22243
22255
  ...ctx.resolverContextInput,
22244
- labeledProposals: successfulProposals.map((s) => ({ debater: s.debater.agent, output: s.output }))
22256
+ labeledProposals: successfulProposals.map((s) => ({ debater: buildDebaterLabel2(s.debater), output: s.output }))
22245
22257
  } : undefined;
22246
- const resolveResult = await resolveOutcome(proposalOutputs, critiqueOutputs, ctx.stageConfig, ctx.config, ctx.storyId, ctx.timeoutSeconds * 1000, ctx.workdir, ctx.featureName, ctx.reviewerSession, fullResolverContext);
22258
+ const resolveResult = await resolveOutcome(proposalOutputs, critiqueOutputs, ctx.stageConfig, ctx.config, ctx.storyId, ctx.timeoutSeconds * 1000, ctx.workdir, ctx.featureName, ctx.reviewerSession, fullResolverContext, undefined, successfulProposals.map((s) => s.debater));
22247
22259
  totalCostUsd += resolveResult.resolverCostUsd;
22248
22260
  return {
22249
22261
  storyId: ctx.storyId,
@@ -22288,7 +22300,8 @@ async function runOneShot(ctx, prompt) {
22288
22300
  });
22289
22301
  const debate = ctx.config?.debate;
22290
22302
  const concurrencyLimit = debate?.maxConcurrentDebaters ?? 2;
22291
- const proposalSettled = await allSettledBounded(resolved.map(({ debater, adapter }, i) => () => runComplete(adapter, prompt, {
22303
+ const proposalBuilder = new DebatePromptBuilder({ taskContext: prompt, outputFormat: "", stage: ctx.stage }, { debaters: resolved.map((r) => r.debater), sessionMode: "one-shot" });
22304
+ const proposalSettled = await allSettledBounded(resolved.map(({ debater, adapter }, i) => () => runComplete(adapter, proposalBuilder.buildProposalPrompt(i), {
22292
22305
  model: resolveDebaterModel(debater, ctx.config),
22293
22306
  featureName: ctx.stage,
22294
22307
  config: ctx.config,
@@ -22393,9 +22406,9 @@ async function runOneShot(ctx, prompt) {
22393
22406
  const proposalOutputs = successful.map((p) => p.output);
22394
22407
  const fullResolverContext = ctx.resolverContextInput ? {
22395
22408
  ...ctx.resolverContextInput,
22396
- labeledProposals: successful.map((p) => ({ debater: p.debater.agent, output: p.output }))
22409
+ labeledProposals: successful.map((p) => ({ debater: buildDebaterLabel2(p.debater), output: p.output }))
22397
22410
  } : undefined;
22398
- const outcome = await resolveOutcome(proposalOutputs, critiqueOutputs, ctx.stageConfig, ctx.config, ctx.storyId, ctx.timeoutMs, ctx.workdir, ctx.featureName, ctx.reviewerSession, fullResolverContext);
22411
+ const outcome = await resolveOutcome(proposalOutputs, critiqueOutputs, ctx.stageConfig, ctx.config, ctx.storyId, ctx.timeoutMs, ctx.workdir, ctx.featureName, ctx.reviewerSession, fullResolverContext, undefined, successful.map((p) => p.debater));
22399
22412
  totalCostUsd += outcome.resolverCostUsd;
22400
22413
  const proposals = successful.map((p) => ({
22401
22414
  debater: p.debater,
@@ -22554,7 +22567,7 @@ Do NOT output the JSON to the conversation. Write the file, then reply with a br
22554
22567
  }
22555
22568
  const resolverTimeoutMs = (ctx.stageConfig.timeoutSeconds ?? 600) * 1000;
22556
22569
  const planSynthesisSuffix = "IMPORTANT: Your response must be a single valid JSON object in PRD format (with project, feature, branchName, userStories array, etc.). Do NOT wrap it in markdown fences. Output raw JSON only.";
22557
- const outcome = await resolveOutcome(proposalOutputs, critiqueOutputs, ctx.stageConfig, ctx.config, ctx.storyId, resolverTimeoutMs, opts.workdir, opts.feature, undefined, undefined, planSynthesisSuffix);
22570
+ const outcome = await resolveOutcome(proposalOutputs, critiqueOutputs, ctx.stageConfig, ctx.config, ctx.storyId, resolverTimeoutMs, opts.workdir, opts.feature, undefined, undefined, planSynthesisSuffix, successful.map((p) => p.debater));
22558
22571
  const winningOutput = outcome.output ?? successful[0].output;
22559
22572
  const proposals = successful.map((p) => ({ debater: p.debater, output: p.output }));
22560
22573
  logger?.info("debate", "debate:result", {
@@ -25782,7 +25795,8 @@ Rules:
25782
25795
  - Every test MUST have real assertions that PASS when the feature is correctly implemented and FAIL when it is broken
25783
25796
  - **Prefer behavioral tests** \u2014 import functions and call them rather than reading source files. For example, to verify "getPostRunActions() returns empty array", import PluginRegistry and call getPostRunActions(), don't grep the source file for the method name.
25784
25797
  - **File output (REQUIRED)**: Write the acceptance test file DIRECTLY to the path shown below. Do NOT output the test code in your response. After writing the file, reply with a brief confirmation.
25785
- - **Path anchor (CRITICAL)**: Write the test file to this exact path: \`${join16(options.workdir, ".nax", "features", options.featureName, resolveAcceptanceTestFile2(options.language, options.config?.acceptance?.testPath))}\`. Import from package sources using relative paths like \`../../../src/...\` (3 levels up from \`.nax/features/<name>/\` to the package root).`;
25798
+ - **Path anchor (CRITICAL)**: Write the test file to this exact path: \`${join16(options.workdir, ".nax", "features", options.featureName, resolveAcceptanceTestFile2(options.language, options.config?.acceptance?.testPath))}\`. Import from package sources using relative paths like \`../../../src/...\` (3 levels up from \`.nax/features/<name>/\` to the package root).
25799
+ - **Process cwd**: When spawning child processes to invoke a CLI or binary, set the working directory to the **package root** (\`join(import.meta.dir, "../../..")\`) as your default \u2014 unless your Step 2 exploration reveals the CLI uses a different working directory convention (e.g. reads config from \`~/.config/\`, or resolves paths relative to a flag value). Always check how the CLI resolves file paths before assuming.`;
25786
25800
  const implementationSection = options.implementationContext && options.implementationContext.length > 0 ? `
25787
25801
 
25788
25802
  ## Implementation (already exists)
@@ -36362,7 +36376,7 @@ var package_default;
36362
36376
  var init_package = __esm(() => {
36363
36377
  package_default = {
36364
36378
  name: "@nathapp/nax",
36365
- version: "0.59.3",
36379
+ version: "0.60.0-canary.1",
36366
36380
  description: "AI Coding Agent Orchestrator \u2014 loops until done",
36367
36381
  type: "module",
36368
36382
  bin: {
@@ -36442,8 +36456,8 @@ var init_version = __esm(() => {
36442
36456
  NAX_VERSION = package_default.version;
36443
36457
  NAX_COMMIT = (() => {
36444
36458
  try {
36445
- if (/^[0-9a-f]{6,10}$/.test("0c763972"))
36446
- return "0c763972";
36459
+ if (/^[0-9a-f]{6,10}$/.test("1de1f9cc"))
36460
+ return "1de1f9cc";
36447
36461
  } catch {}
36448
36462
  try {
36449
36463
  const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nathapp/nax",
3
- "version": "0.59.3",
3
+ "version": "0.60.0-canary.1",
4
4
  "description": "AI Coding Agent Orchestrator — loops until done",
5
5
  "type": "module",
6
6
  "bin": {