@nathapp/nax 0.58.2 → 0.58.4

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 +177 -128
  2. package/package.json +1 -1
package/dist/nax.js CHANGED
@@ -3483,8 +3483,8 @@ function parseAgentError(stderr) {
3483
3483
  }
3484
3484
 
3485
3485
  // src/agents/acp/prompt-audit.ts
3486
- import { mkdirSync as mkdirSync2 } from "fs";
3487
- import { isAbsolute, join } from "path";
3486
+ import { existsSync as fsExistsSync, mkdirSync as mkdirSync2 } from "fs";
3487
+ import { dirname, isAbsolute, join, resolve, sep } from "path";
3488
3488
  function buildAuditFilename(entry, epochMs) {
3489
3489
  const stage = entry.pipelineStage ?? entry.callType;
3490
3490
  if (entry.callType === "run" && entry.turn !== undefined) {
@@ -3509,13 +3509,30 @@ function buildAuditContent(entry, epochMs) {
3509
3509
  return lines.join(`
3510
3510
  `);
3511
3511
  }
3512
+ function findNaxProjectRoot(startDir) {
3513
+ let dir = resolve(startDir);
3514
+ for (let depth = 0;depth < MAX_NAX_WALK_DEPTH; depth++) {
3515
+ if (_promptAuditDeps.existsSync(join(dir, ".nax", "config.json"))) {
3516
+ return dir;
3517
+ }
3518
+ const parent = dirname(dir);
3519
+ if (parent === dir)
3520
+ break;
3521
+ dir = parent;
3522
+ }
3523
+ return startDir;
3524
+ }
3512
3525
  async function writePromptAudit(entry) {
3513
3526
  try {
3514
3527
  let baseDir;
3515
3528
  if (entry.auditDir) {
3516
3529
  baseDir = isAbsolute(entry.auditDir) ? entry.auditDir : join(entry.workdir, entry.auditDir);
3517
3530
  } else {
3518
- baseDir = join(entry.workdir, ".nax", "prompt-audit");
3531
+ const wtMarker = `${sep}.nax-wt${sep}`;
3532
+ const wtIdx = entry.workdir.indexOf(wtMarker);
3533
+ const strippedWorkdir = wtIdx !== -1 ? entry.workdir.substring(0, wtIdx) : entry.workdir;
3534
+ const projectRoot = findNaxProjectRoot(strippedWorkdir);
3535
+ baseDir = join(projectRoot, ".nax", "prompt-audit");
3519
3536
  }
3520
3537
  const resolvedDir = join(baseDir, entry.featureName ?? "_unknown");
3521
3538
  _promptAuditDeps.mkdirSync(resolvedDir);
@@ -3530,13 +3547,16 @@ async function writePromptAudit(entry) {
3530
3547
  });
3531
3548
  }
3532
3549
  }
3533
- var _promptAuditDeps;
3550
+ var _promptAuditDeps, MAX_NAX_WALK_DEPTH = 10;
3534
3551
  var init_prompt_audit = __esm(() => {
3535
3552
  init_logger2();
3536
3553
  _promptAuditDeps = {
3537
3554
  mkdirSync(path) {
3538
3555
  mkdirSync2(path, { recursive: true });
3539
3556
  },
3557
+ existsSync(path) {
3558
+ return fsExistsSync(path);
3559
+ },
3540
3560
  async writeFile(path, content) {
3541
3561
  await Bun.write(path, content);
3542
3562
  },
@@ -3766,8 +3786,8 @@ class SpawnAcpSession {
3766
3786
  const exitCode = await proc.exited;
3767
3787
  const makeDrain = (ms) => {
3768
3788
  let id;
3769
- const promise = new Promise((resolve) => {
3770
- id = setTimeout(() => resolve(""), ms);
3789
+ const promise = new Promise((resolve2) => {
3790
+ id = setTimeout(() => resolve2(""), ms);
3771
3791
  });
3772
3792
  return { promise, cancel: () => clearTimeout(id) };
3773
3793
  };
@@ -18799,8 +18819,8 @@ async function ensureAcpSession(client, sessionName, agentName, permissionMode)
18799
18819
  async function runSessionPrompt(session, prompt, timeoutMs) {
18800
18820
  const promptPromise = session.prompt(prompt);
18801
18821
  let timeoutId;
18802
- const timeoutPromise = new Promise((resolve) => {
18803
- timeoutId = setTimeout(() => resolve("timeout"), timeoutMs);
18822
+ const timeoutPromise = new Promise((resolve2) => {
18823
+ timeoutId = setTimeout(() => resolve2("timeout"), timeoutMs);
18804
18824
  });
18805
18825
  let winner;
18806
18826
  try {
@@ -18976,12 +18996,14 @@ function extractQuestion(output) {
18976
18996
  }
18977
18997
 
18978
18998
  class AcpAgentAdapter {
18999
+ naxConfig;
18979
19000
  name;
18980
19001
  displayName;
18981
19002
  binary;
18982
19003
  capabilities;
18983
19004
  _unavailableAgents;
18984
- constructor(agentName) {
19005
+ constructor(agentName, naxConfig) {
19006
+ this.naxConfig = naxConfig;
18985
19007
  const entry = resolveRegistryEntry(agentName);
18986
19008
  this.name = agentName;
18987
19009
  this.displayName = entry.displayName;
@@ -19158,12 +19180,13 @@ class AcpAgentAdapter {
19158
19180
  while (turnCount < MAX_TURNS) {
19159
19181
  turnCount++;
19160
19182
  getSafeLogger()?.debug("acp-adapter", `Session turn ${turnCount}/${MAX_TURNS}`, { sessionName });
19161
- if (options.config?.agent?.promptAudit?.enabled) {
19183
+ const _runAuditConfig = options.config;
19184
+ if (_runAuditConfig?.agent?.promptAudit?.enabled) {
19162
19185
  writePromptAudit({
19163
19186
  prompt: currentPrompt,
19164
19187
  sessionName,
19165
19188
  workdir: options.workdir,
19166
- auditDir: options.config.agent.promptAudit.dir,
19189
+ auditDir: _runAuditConfig.agent.promptAudit.dir,
19167
19190
  storyId: options.storyId,
19168
19191
  featureName: options.featureName,
19169
19192
  pipelineStage: options.pipelineStage ?? "run",
@@ -19265,7 +19288,7 @@ class AcpAgentAdapter {
19265
19288
  };
19266
19289
  }
19267
19290
  async complete(prompt, _options) {
19268
- const timeoutMs = _options?.timeoutMs ?? 120000;
19291
+ const timeoutMs = _options?.timeoutMs || 120000;
19269
19292
  const permissionMode = resolvePermissions(_options?.config, "complete").mode;
19270
19293
  const workdir = _options?.workdir;
19271
19294
  const config2 = _options?.config;
@@ -19291,15 +19314,16 @@ class AcpAgentAdapter {
19291
19314
  try {
19292
19315
  const completeSessionName = _options?.sessionName ?? buildSessionName(workdir ?? process.cwd(), _options?.featureName, _options?.storyId, _options?.sessionRole);
19293
19316
  session = await client.createSession({ agentName, permissionMode, sessionName: completeSessionName });
19294
- if (config2?.agent?.promptAudit?.enabled) {
19317
+ const _completeAuditConfig = config2 ?? this.naxConfig;
19318
+ if (_completeAuditConfig?.agent?.promptAudit?.enabled) {
19295
19319
  writePromptAudit({
19296
19320
  prompt,
19297
19321
  sessionName: completeSessionName,
19298
19322
  workdir: workdir ?? process.cwd(),
19299
- auditDir: config2.agent.promptAudit.dir,
19323
+ auditDir: _completeAuditConfig.agent.promptAudit.dir,
19300
19324
  storyId: _options?.storyId,
19301
19325
  featureName: _options?.featureName,
19302
- pipelineStage: "complete",
19326
+ pipelineStage: _options?.pipelineStage ?? "complete",
19303
19327
  callType: "complete"
19304
19328
  });
19305
19329
  }
@@ -19449,9 +19473,9 @@ class AcpAgentAdapter {
19449
19473
  modelTier: options.modelTier ?? "balanced",
19450
19474
  modelDef,
19451
19475
  timeoutSeconds,
19452
- dangerouslySkipPermissions: resolvePermissions(options.config, "plan").skipPermissions,
19476
+ dangerouslySkipPermissions: resolvePermissions(this.naxConfig, "plan").skipPermissions,
19453
19477
  pipelineStage: "plan",
19454
- config: options.config,
19478
+ config: this.naxConfig,
19455
19479
  interactionBridge: options.interactionBridge,
19456
19480
  maxInteractionTurns: options.maxInteractionTurns,
19457
19481
  featureName: options.featureName,
@@ -19478,7 +19502,7 @@ class AcpAgentAdapter {
19478
19502
  const completeResult = await this.complete(prompt, {
19479
19503
  model,
19480
19504
  jsonMode: true,
19481
- config: options.config,
19505
+ config: this.naxConfig,
19482
19506
  workdir: options.workdir,
19483
19507
  featureName: options.featureName,
19484
19508
  storyId: options.storyId,
@@ -19852,8 +19876,8 @@ async function withProcessTimeout(proc, timeoutMs, opts) {
19852
19876
  try {
19853
19877
  const hardDeadlineMs = timeoutMs + graceMs + hardDeadlineBufferMs;
19854
19878
  let hardDeadlineId;
19855
- const hardDeadlinePromise = new Promise((resolve) => {
19856
- hardDeadlineId = setTimeout(() => resolve(-1), hardDeadlineMs);
19879
+ const hardDeadlinePromise = new Promise((resolve2) => {
19880
+ hardDeadlineId = setTimeout(() => resolve2(-1), hardDeadlineMs);
19857
19881
  });
19858
19882
  exitCode = await Promise.race([proc.exited, hardDeadlinePromise]);
19859
19883
  clearTimeout(hardDeadlineId);
@@ -19964,8 +19988,8 @@ async function executeOnce(binary, options, pidRegistry) {
19964
19988
  let stdoutTimeoutId;
19965
19989
  const stdout = await Promise.race([
19966
19990
  new Response(proc.stdout).text(),
19967
- new Promise((resolve) => {
19968
- stdoutTimeoutId = setTimeout(() => resolve(""), 5000);
19991
+ new Promise((resolve2) => {
19992
+ stdoutTimeoutId = setTimeout(() => resolve2(""), 5000);
19969
19993
  })
19970
19994
  ]);
19971
19995
  clearTimeout(stdoutTimeoutId);
@@ -20129,7 +20153,7 @@ ${inputContent}`;
20129
20153
  }
20130
20154
  return cmd;
20131
20155
  }
20132
- async function runPlan(binary, options, pidRegistry, buildAllowedEnv2) {
20156
+ async function runPlan(binary, options, pidRegistry) {
20133
20157
  const { resolveBalancedModelDef: resolveBalancedModelDef2 } = await Promise.resolve().then(() => (init_model_resolution(), exports_model_resolution));
20134
20158
  const cmd = buildPlanCommand(binary, options);
20135
20159
  let modelDef = options.modelDef;
@@ -20139,13 +20163,6 @@ async function runPlan(binary, options, pidRegistry, buildAllowedEnv2) {
20139
20163
  }
20140
20164
  modelDef = resolveBalancedModelDef2(options.config);
20141
20165
  }
20142
- const envOptions = {
20143
- workdir: options.workdir,
20144
- modelDef,
20145
- prompt: "",
20146
- modelTier: options.modelTier || "balanced",
20147
- timeoutSeconds: options.timeoutSeconds ?? 600
20148
- };
20149
20166
  const planTimeoutMs = (options.timeoutSeconds ?? 600) * 1000;
20150
20167
  if (options.interactive) {
20151
20168
  const proc = Bun.spawn(cmd, {
@@ -20153,7 +20170,7 @@ async function runPlan(binary, options, pidRegistry, buildAllowedEnv2) {
20153
20170
  stdin: "inherit",
20154
20171
  stdout: "inherit",
20155
20172
  stderr: "inherit",
20156
- env: buildAllowedEnv2(envOptions)
20173
+ env: buildAllowedEnv()
20157
20174
  });
20158
20175
  await pidRegistry.register(proc.pid);
20159
20176
  let exitCode;
@@ -20179,7 +20196,7 @@ async function runPlan(binary, options, pidRegistry, buildAllowedEnv2) {
20179
20196
  stdin: "ignore",
20180
20197
  stdout: Bun.file(outFile),
20181
20198
  stderr: Bun.file(errFile),
20182
- env: buildAllowedEnv2(envOptions)
20199
+ env: buildAllowedEnv()
20183
20200
  });
20184
20201
  await pidRegistry.register(proc.pid);
20185
20202
  let exitCode;
@@ -20209,6 +20226,7 @@ async function runPlan(binary, options, pidRegistry, buildAllowedEnv2) {
20209
20226
  var init_plan = __esm(() => {
20210
20227
  init_timeout_handler();
20211
20228
  init_logger2();
20229
+ init_env();
20212
20230
  init_model_resolution();
20213
20231
  });
20214
20232
 
@@ -20303,7 +20321,7 @@ class ClaudeCodeAdapter {
20303
20321
  }
20304
20322
  async plan(options) {
20305
20323
  const pidRegistry = this.getPidRegistry(options.workdir);
20306
- return runPlan(this.binary, options, pidRegistry, this.buildAllowedEnv.bind(this));
20324
+ return runPlan(this.binary, options, pidRegistry);
20307
20325
  }
20308
20326
  async decompose(options) {
20309
20327
  const { resolveBalancedModelDef: resolveBalancedModelDef2 } = await Promise.resolve().then(() => (init_model_resolution(), exports_model_resolution));
@@ -20321,13 +20339,7 @@ class ClaudeCodeAdapter {
20321
20339
  cmd.splice(cmd.length - 2, 0, "--dangerously-skip-permissions");
20322
20340
  }
20323
20341
  const pidRegistry = this.getPidRegistry(options.workdir);
20324
- const env2 = this.buildAllowedEnv({
20325
- workdir: options.workdir,
20326
- modelDef,
20327
- prompt: "",
20328
- modelTier: options.modelTier || "balanced",
20329
- timeoutSeconds: 600
20330
- });
20342
+ const env2 = buildAllowedEnv();
20331
20343
  if (options.featureName) {
20332
20344
  env2.NAX_FEATURE_NAME = options.featureName;
20333
20345
  }
@@ -20364,8 +20376,8 @@ class ClaudeCodeAdapter {
20364
20376
  let stdoutTimeoutId;
20365
20377
  const stdout = await Promise.race([
20366
20378
  new Response(proc.stdout).text(),
20367
- new Promise((resolve) => {
20368
- stdoutTimeoutId = setTimeout(() => resolve(""), 5000);
20379
+ new Promise((resolve2) => {
20380
+ stdoutTimeoutId = setTimeout(() => resolve2(""), 5000);
20369
20381
  })
20370
20382
  ]);
20371
20383
  clearTimeout(stdoutTimeoutId);
@@ -20679,7 +20691,7 @@ function createAgentRegistry(config2) {
20679
20691
  if (!known)
20680
20692
  return;
20681
20693
  if (!acpCache.has(name)) {
20682
- acpCache.set(name, new AcpAgentAdapter(name));
20694
+ acpCache.set(name, new AcpAgentAdapter(name, config2));
20683
20695
  logger?.debug("agents", `Created AcpAgentAdapter for ${name}`, { name, protocol });
20684
20696
  }
20685
20697
  return acpCache.get(name);
@@ -20693,7 +20705,7 @@ function createAgentRegistry(config2) {
20693
20705
  async function getInstalledAgents2() {
20694
20706
  const agents = protocol === "acp" ? ALL_AGENTS.map((a) => {
20695
20707
  if (!acpCache.has(a.name)) {
20696
- acpCache.set(a.name, new AcpAgentAdapter(a.name));
20708
+ acpCache.set(a.name, new AcpAgentAdapter(a.name, config2));
20697
20709
  }
20698
20710
  return acpCache.get(a.name);
20699
20711
  }) : ALL_AGENTS;
@@ -20703,7 +20715,7 @@ function createAgentRegistry(config2) {
20703
20715
  async function checkAgentHealth2() {
20704
20716
  const agents = protocol === "acp" ? ALL_AGENTS.map((a) => {
20705
20717
  if (!acpCache.has(a.name)) {
20706
- acpCache.set(a.name, new AcpAgentAdapter(a.name));
20718
+ acpCache.set(a.name, new AcpAgentAdapter(a.name, config2));
20707
20719
  }
20708
20720
  return acpCache.get(a.name);
20709
20721
  }) : ALL_AGENTS;
@@ -20735,9 +20747,9 @@ var init_registry = __esm(() => {
20735
20747
 
20736
20748
  // src/config/path-security.ts
20737
20749
  import { existsSync as existsSync3, lstatSync, realpathSync } from "fs";
20738
- import { basename, isAbsolute as isAbsolute3, normalize, resolve } from "path";
20750
+ import { basename, isAbsolute as isAbsolute3, normalize, resolve as resolve2 } from "path";
20739
20751
  function validateDirectory(dirPath, baseDir) {
20740
- const resolved = resolve(dirPath);
20752
+ const resolved = resolve2(dirPath);
20741
20753
  if (!existsSync3(resolved)) {
20742
20754
  throw new Error(`Directory does not exist: ${dirPath}`);
20743
20755
  }
@@ -20756,7 +20768,7 @@ function validateDirectory(dirPath, baseDir) {
20756
20768
  throw new Error(`Failed to stat path: ${dirPath} (${error48.message})`);
20757
20769
  }
20758
20770
  if (baseDir) {
20759
- const resolvedBase = resolve(baseDir);
20771
+ const resolvedBase = resolve2(baseDir);
20760
20772
  const realBase = existsSync3(resolvedBase) ? realpathSync(resolvedBase) : resolvedBase;
20761
20773
  if (!isWithinDirectory(realPath, realBase)) {
20762
20774
  throw new Error(`Path is outside allowed directory: ${dirPath} (resolved to ${realPath}, base: ${realBase})`);
@@ -20775,14 +20787,14 @@ function isWithinDirectory(targetPath, basePath) {
20775
20787
  return targetWithSlash.startsWith(baseWithSlash) || normalizedTarget === normalizedBase;
20776
20788
  }
20777
20789
  function validateFilePath(filePath, baseDir) {
20778
- const resolved = resolve(filePath);
20790
+ const resolved = resolve2(filePath);
20779
20791
  let realPath;
20780
20792
  try {
20781
20793
  if (!existsSync3(resolved)) {
20782
- const parent = resolve(resolved, "..");
20794
+ const parent = resolve2(resolved, "..");
20783
20795
  if (existsSync3(parent)) {
20784
20796
  const realParent = realpathSync(parent);
20785
- realPath = resolve(realParent, basename(resolved));
20797
+ realPath = resolve2(realParent, basename(resolved));
20786
20798
  } else {
20787
20799
  realPath = resolved;
20788
20800
  }
@@ -20792,7 +20804,7 @@ function validateFilePath(filePath, baseDir) {
20792
20804
  } catch (error48) {
20793
20805
  throw new Error(`Failed to resolve path: ${filePath} (${error48.message})`);
20794
20806
  }
20795
- const resolvedBase = resolve(baseDir);
20807
+ const resolvedBase = resolve2(baseDir);
20796
20808
  const realBase = existsSync3(resolvedBase) ? realpathSync(resolvedBase) : resolvedBase;
20797
20809
  if (!isWithinDirectory(realPath, realBase)) {
20798
20810
  throw new Error(`Path is outside allowed directory: ${filePath} (resolved to ${realPath}, base: ${realBase})`);
@@ -20839,12 +20851,22 @@ var init_json_file = __esm(() => {
20839
20851
 
20840
20852
  // src/config/merge.ts
20841
20853
  function mergePackageConfig(root, packageOverride) {
20842
- const hasAnyMergeableField = packageOverride.execution !== undefined || packageOverride.review !== undefined || packageOverride.acceptance !== undefined || packageOverride.quality !== undefined || packageOverride.context !== undefined || packageOverride.project !== undefined;
20854
+ const hasAnyMergeableField = packageOverride.agent !== undefined || packageOverride.models !== undefined || packageOverride.routing !== undefined || packageOverride.execution !== undefined || packageOverride.review !== undefined || packageOverride.acceptance !== undefined || packageOverride.quality !== undefined || packageOverride.context !== undefined || packageOverride.project !== undefined;
20843
20855
  if (!hasAnyMergeableField) {
20844
20856
  return root;
20845
20857
  }
20846
20858
  return {
20847
20859
  ...root,
20860
+ agent: packageOverride.agent !== undefined ? {
20861
+ ...root.agent,
20862
+ ...packageOverride.agent,
20863
+ promptAudit: {
20864
+ enabled: packageOverride.agent.promptAudit?.enabled ?? root.agent?.promptAudit?.enabled ?? false,
20865
+ ...packageOverride.agent.promptAudit?.dir !== undefined ? { dir: packageOverride.agent.promptAudit.dir } : root.agent?.promptAudit?.dir !== undefined ? { dir: root.agent.promptAudit.dir } : {}
20866
+ }
20867
+ } : root.agent,
20868
+ models: packageOverride.models !== undefined ? { ...root.models, ...packageOverride.models } : root.models,
20869
+ routing: packageOverride.routing !== undefined ? { ...root.routing, ...packageOverride.routing, llm: { ...root.routing?.llm, ...packageOverride.routing.llm } } : root.routing,
20848
20870
  execution: {
20849
20871
  ...root.execution,
20850
20872
  ...packageOverride.execution,
@@ -20986,7 +21008,7 @@ function isPlainObject2(value) {
20986
21008
 
20987
21009
  // src/config/paths.ts
20988
21010
  import { homedir as homedir2 } from "os";
20989
- import { join as join7, resolve as resolve2 } from "path";
21011
+ import { join as join7, resolve as resolve3 } from "path";
20990
21012
  function globalConfigDir() {
20991
21013
  const override = process.env[GLOBAL_CONFIG_DIR_ENV];
20992
21014
  if (override)
@@ -20994,7 +21016,7 @@ function globalConfigDir() {
20994
21016
  return join7(homedir2(), ".nax");
20995
21017
  }
20996
21018
  function projectConfigDir(projectRoot) {
20997
- return join7(resolve2(projectRoot), PROJECT_NAX_DIR);
21019
+ return join7(resolve3(projectRoot), PROJECT_NAX_DIR);
20998
21020
  }
20999
21021
  var GLOBAL_CONFIG_DIR_ENV = "NAX_GLOBAL_CONFIG_DIR", PROJECT_NAX_DIR = ".nax";
21000
21022
  var init_paths = () => {};
@@ -21148,12 +21170,12 @@ var init_profile = __esm(() => {
21148
21170
 
21149
21171
  // src/config/loader.ts
21150
21172
  import { existsSync as existsSync7 } from "fs";
21151
- import { basename as basename2, dirname as dirname2, join as join9, resolve as resolve3 } from "path";
21173
+ import { basename as basename2, dirname as dirname3, join as join9, resolve as resolve4 } from "path";
21152
21174
  function globalConfigPath() {
21153
21175
  return join9(globalConfigDir(), "config.json");
21154
21176
  }
21155
21177
  function findProjectDir(startDir = process.cwd()) {
21156
- let dir = resolve3(startDir);
21178
+ let dir = resolve4(startDir);
21157
21179
  let depth = 0;
21158
21180
  while (depth < MAX_DIRECTORY_DEPTH) {
21159
21181
  const candidate = join9(dir, PROJECT_NAX_DIR);
@@ -21204,7 +21226,7 @@ function applyBatchModeCompat(conf) {
21204
21226
  async function loadConfig(startDir, cliOverrides) {
21205
21227
  let rawConfig = structuredClone(DEFAULT_CONFIG);
21206
21228
  const projDir = startDir ? basename2(startDir) === PROJECT_NAX_DIR ? startDir : findProjectDir(startDir) : findProjectDir();
21207
- const projectRoot = startDir ? basename2(startDir) === PROJECT_NAX_DIR ? dirname2(startDir) : startDir : process.cwd();
21229
+ const projectRoot = startDir ? basename2(startDir) === PROJECT_NAX_DIR ? dirname3(startDir) : startDir : process.cwd();
21208
21230
  const profileName = await resolveProfileName(cliOverrides ?? {}, process.env, projectRoot);
21209
21231
  const globalConfRaw = await loadJsonFile(globalConfigPath(), "config");
21210
21232
  if (globalConfRaw) {
@@ -21247,13 +21269,19 @@ ${errors3.join(`
21247
21269
  }
21248
21270
  async function loadConfigForWorkdir(rootConfigPath, packageDir) {
21249
21271
  const logger = getLogger();
21250
- const rootNaxDir = dirname2(rootConfigPath);
21251
- const rootConfig = await loadConfig(rootNaxDir);
21272
+ const resolvedRootConfigPath = resolve4(rootConfigPath);
21273
+ const rootNaxDir = dirname3(resolvedRootConfigPath);
21274
+ let rootConfigPromise = _rootConfigCache.get(resolvedRootConfigPath);
21275
+ if (!rootConfigPromise) {
21276
+ rootConfigPromise = loadConfig(rootNaxDir);
21277
+ _rootConfigCache.set(resolvedRootConfigPath, rootConfigPromise);
21278
+ }
21279
+ const rootConfig = await rootConfigPromise;
21252
21280
  if (!packageDir) {
21253
21281
  logger.debug("config", "No packageDir \u2014 using root config");
21254
21282
  return rootConfig;
21255
21283
  }
21256
- const repoRoot = dirname2(rootNaxDir);
21284
+ const repoRoot = dirname3(rootNaxDir);
21257
21285
  const packageConfigPath = join9(repoRoot, PROJECT_NAX_DIR, "mono", packageDir, "config.json");
21258
21286
  const packageOverride = await loadJsonFile(packageConfigPath, "config");
21259
21287
  if (!packageOverride) {
@@ -21264,8 +21292,26 @@ async function loadConfigForWorkdir(rootConfigPath, packageDir) {
21264
21292
  return rootConfig;
21265
21293
  }
21266
21294
  logger.debug("config", "Per-package config loaded", { packageConfigPath, packageDir });
21267
- return mergePackageConfig(rootConfig, packageOverride);
21295
+ const { profile: packageProfile, ...packageFields } = packageOverride;
21296
+ let merged = mergePackageConfig(rootConfig, packageFields);
21297
+ if (packageProfile && packageProfile !== "default") {
21298
+ const packageRoot = join9(repoRoot, packageDir);
21299
+ const profileData = await loadProfile(packageProfile, packageRoot);
21300
+ const rawMerged = deepMergeConfig(merged, profileData);
21301
+ rawMerged.profile = packageProfile;
21302
+ const result = NaxConfigSchema.safeParse(rawMerged);
21303
+ if (result.success) {
21304
+ merged = result.data;
21305
+ } else {
21306
+ logger.warn("config", "Per-package profile failed validation \u2014 using merged config without profile", {
21307
+ packageDir,
21308
+ packageProfile
21309
+ });
21310
+ }
21311
+ }
21312
+ return merged;
21268
21313
  }
21314
+ var _rootConfigCache;
21269
21315
  var init_loader = __esm(() => {
21270
21316
  init_logger2();
21271
21317
  init_json_file();
@@ -21273,6 +21319,7 @@ var init_loader = __esm(() => {
21273
21319
  init_paths();
21274
21320
  init_profile();
21275
21321
  init_schema();
21322
+ _rootConfigCache = new Map;
21276
21323
  });
21277
21324
  // src/config/index.ts
21278
21325
  var init_config = __esm(() => {
@@ -22425,22 +22472,21 @@ class AutoInteractionPlugin {
22425
22472
  if (!adapter) {
22426
22473
  throw new Error("Auto plugin requires adapter to be injected via _autoPluginDeps.adapter");
22427
22474
  }
22428
- let modelArg;
22429
- if (this.config.naxConfig) {
22475
+ const naxConfig = this.config.naxConfig ?? DEFAULT_CONFIG;
22476
+ let resolvedModel;
22477
+ try {
22430
22478
  const modelTier = this.config.model ?? "fast";
22431
- const naxConfig = this.config.naxConfig;
22432
- const modelDef = resolveModelForAgent(naxConfig.models, naxConfig.autoMode.defaultAgent, modelTier, naxConfig.autoMode.defaultAgent);
22433
- modelArg = modelDef.model;
22434
- }
22435
- const timeoutMs = this.config.naxConfig ? (this.config.naxConfig.execution?.sessionTimeoutSeconds ?? 600) * 1000 : undefined;
22479
+ resolvedModel = resolveModelForAgent(naxConfig.models, naxConfig.autoMode.defaultAgent, modelTier, naxConfig.autoMode.defaultAgent).model;
22480
+ } catch {}
22481
+ const timeoutMs = (naxConfig.execution?.sessionTimeoutSeconds ?? 600) * 1000;
22436
22482
  const result = await adapter.complete(prompt, {
22437
- ...modelArg && { model: modelArg },
22483
+ ...resolvedModel !== undefined && { model: resolvedModel },
22438
22484
  jsonMode: true,
22439
- ...this.config.naxConfig && { config: this.config.naxConfig },
22485
+ config: naxConfig,
22440
22486
  featureName: request.featureName,
22441
22487
  storyId: request.storyId,
22442
22488
  sessionRole: "auto",
22443
- ...timeoutMs !== undefined && { timeoutMs }
22489
+ timeoutMs
22444
22490
  });
22445
22491
  const output = typeof result === "string" ? result : result.output;
22446
22492
  return this.parseResponse(output);
@@ -22598,9 +22644,9 @@ ${request.summary}
22598
22644
  if (!this.rl) {
22599
22645
  throw new Error("CLI plugin not initialized");
22600
22646
  }
22601
- const timeoutPromise = new Promise((resolve4) => {
22647
+ const timeoutPromise = new Promise((resolve5) => {
22602
22648
  setTimeout(() => {
22603
- resolve4({
22649
+ resolve5({
22604
22650
  requestId: request.id,
22605
22651
  action: "skip",
22606
22652
  respondedBy: "timeout",
@@ -22752,9 +22798,9 @@ ${request.summary}
22752
22798
  if (!this.rl) {
22753
22799
  throw new Error("CLI plugin not initialized");
22754
22800
  }
22755
- return new Promise((resolve4) => {
22801
+ return new Promise((resolve5) => {
22756
22802
  this.rl?.question(prompt, (answer) => {
22757
- resolve4(answer);
22803
+ resolve5(answer);
22758
22804
  });
22759
22805
  });
22760
22806
  }
@@ -23186,7 +23232,7 @@ class WebhookInteractionPlugin {
23186
23232
  this.pendingResponses.delete(requestId);
23187
23233
  return early;
23188
23234
  }
23189
- return new Promise((resolve4) => {
23235
+ return new Promise((resolve5) => {
23190
23236
  const existingCallback = this.receiveCallbacks.get(requestId);
23191
23237
  if (existingCallback) {
23192
23238
  this.clearReceiveTimer(requestId);
@@ -23200,7 +23246,7 @@ class WebhookInteractionPlugin {
23200
23246
  const timer = setTimeout(() => {
23201
23247
  this.clearReceiveTimer(requestId);
23202
23248
  this.receiveCallbacks.delete(requestId);
23203
- resolve4({
23249
+ resolve5({
23204
23250
  requestId,
23205
23251
  action: "skip",
23206
23252
  respondedBy: "timeout",
@@ -23211,7 +23257,7 @@ class WebhookInteractionPlugin {
23211
23257
  this.receiveCallbacks.set(requestId, (response) => {
23212
23258
  this.clearReceiveTimer(requestId);
23213
23259
  this.receiveCallbacks.delete(requestId);
23214
- resolve4(response);
23260
+ resolve5(response);
23215
23261
  });
23216
23262
  });
23217
23263
  }
@@ -24578,8 +24624,9 @@ function getNextStory(prd, currentStoryId, maxRetries) {
24578
24624
  return currentStory;
24579
24625
  }
24580
24626
  }
24627
+ const storyIds = new Set(prd.userStories.map((s) => s.id));
24581
24628
  const completedIds = new Set(prd.userStories.filter((s) => s.passes || s.status === "passed" || s.status === "skipped").map((s) => s.id));
24582
- return prd.userStories.find((s) => !s.passes && s.status !== "passed" && s.status !== "skipped" && s.status !== "blocked" && s.status !== "failed" && s.status !== "paused" && s.status !== "decomposed" && s.dependencies.every((dep) => completedIds.has(dep))) ?? null;
24629
+ return prd.userStories.find((s) => !s.passes && s.status !== "passed" && s.status !== "skipped" && s.status !== "blocked" && s.status !== "failed" && s.status !== "paused" && s.status !== "decomposed" && s.dependencies.every((dep) => !storyIds.has(dep) || completedIds.has(dep))) ?? null;
24583
24630
  }
24584
24631
  function isComplete(prd) {
24585
24632
  return prd.userStories.every((s) => s.passes || s.status === "passed" || s.status === "skipped");
@@ -27379,7 +27426,7 @@ async function runSemanticReview(workdir, storyGitRef, story, semanticConfig, mo
27379
27426
  storyId: story.id,
27380
27427
  stage: "review",
27381
27428
  stageConfig: reviewStageConfig,
27382
- config: naxConfig,
27429
+ config: naxConfig ?? DEFAULT_CONFIG,
27383
27430
  workdir,
27384
27431
  featureName,
27385
27432
  timeoutSeconds: naxConfig?.execution?.sessionTimeoutSeconds
@@ -27482,7 +27529,7 @@ ${formatFindings(debateBlocking)}`,
27482
27529
  timeoutSeconds: semanticConfig.timeoutMs ? Math.ceil(semanticConfig.timeoutMs / 1000) : 3600,
27483
27530
  modelTier: semanticConfig.modelTier,
27484
27531
  modelDef: resolvedModelDef,
27485
- config: naxConfig
27532
+ config: naxConfig ?? DEFAULT_CONFIG
27486
27533
  });
27487
27534
  runOutput = runResult.output;
27488
27535
  runSucceeded = true;
@@ -27497,7 +27544,7 @@ ${formatFindings(debateBlocking)}`,
27497
27544
  workdir,
27498
27545
  timeoutMs: semanticConfig.timeoutMs,
27499
27546
  modelTier: semanticConfig.modelTier,
27500
- config: naxConfig
27547
+ config: naxConfig ?? DEFAULT_CONFIG
27501
27548
  });
27502
27549
  rawResponse = typeof completeResult === "string" ? completeResult : completeResult.output;
27503
27550
  }
@@ -27603,6 +27650,7 @@ ${formatFindings(blockingFindings)}`;
27603
27650
  var _semanticDeps, DIFF_CAP_BYTES = 51200;
27604
27651
  var init_semantic = __esm(() => {
27605
27652
  init_adapter();
27653
+ init_config();
27606
27654
  init_debate();
27607
27655
  init_logger2();
27608
27656
  init_git();
@@ -28626,7 +28674,7 @@ var init_constitution = __esm(() => {
28626
28674
  });
28627
28675
 
28628
28676
  // src/pipeline/stages/constitution.ts
28629
- import { dirname as dirname3 } from "path";
28677
+ import { dirname as dirname4 } from "path";
28630
28678
  var constitutionStage;
28631
28679
  var init_constitution2 = __esm(() => {
28632
28680
  init_constitution();
@@ -28636,7 +28684,7 @@ var init_constitution2 = __esm(() => {
28636
28684
  enabled: (ctx) => ctx.config.constitution.enabled,
28637
28685
  async execute(ctx) {
28638
28686
  const logger = getLogger();
28639
- const ngentDir = ctx.featureDir ? dirname3(dirname3(ctx.featureDir)) : `${ctx.workdir}/nax`;
28687
+ const ngentDir = ctx.featureDir ? dirname4(dirname4(ctx.featureDir)) : `${ctx.workdir}/nax`;
28640
28688
  const result = await loadConstitution(ngentDir, ctx.config.constitution);
28641
28689
  if (result) {
28642
28690
  ctx.constitution = result;
@@ -29498,13 +29546,14 @@ ${pkgContent.trim()}`;
29498
29546
  }
29499
29547
  }
29500
29548
  function getAllReadyStories(prd) {
29549
+ const storyIds = new Set(prd.userStories.map((s) => s.id));
29501
29550
  const completedIds = new Set(prd.userStories.filter((s) => s.passes || s.status === "skipped").map((s) => s.id));
29502
29551
  const logger = getSafeLogger2();
29503
29552
  logger?.debug("routing", "getAllReadyStories: completed set", {
29504
29553
  completedIds: [...completedIds],
29505
29554
  totalStories: prd.userStories.length
29506
29555
  });
29507
- return prd.userStories.filter((s) => !s.passes && s.status !== "skipped" && s.status !== "failed" && s.status !== "paused" && s.status !== "blocked" && s.dependencies.every((dep) => completedIds.has(dep)));
29556
+ return prd.userStories.filter((s) => !s.passes && s.status !== "skipped" && s.status !== "failed" && s.status !== "paused" && s.status !== "blocked" && s.dependencies.every((dep) => !storyIds.has(dep) || completedIds.has(dep)));
29508
29557
  }
29509
29558
  var CONTEXT_MAX_TOKENS = 1e5, CONTEXT_RESERVED_TOKENS = 1e4;
29510
29559
  var init_story_context = __esm(() => {
@@ -29823,10 +29872,10 @@ async function executeWithTimeout(command, timeoutSeconds, env2, options) {
29823
29872
  const timeoutMs = timeoutSeconds * 1000;
29824
29873
  let timedOut = false;
29825
29874
  const timer = { id: undefined };
29826
- const timeoutPromise = new Promise((resolve6) => {
29875
+ const timeoutPromise = new Promise((resolve7) => {
29827
29876
  timer.id = setTimeout(() => {
29828
29877
  timedOut = true;
29829
- resolve6();
29878
+ resolve7();
29830
29879
  }, timeoutMs);
29831
29880
  });
29832
29881
  const processPromise = proc.exited;
@@ -32644,7 +32693,7 @@ async function _defaultRunDebate(storyId, stageConfig, prompt, config2) {
32644
32693
  if (resolved.length === 0) {
32645
32694
  return { output: null, totalCostUsd: 0 };
32646
32695
  }
32647
- const timeoutMs = (config2?.execution?.sessionTimeoutSeconds ?? 600) * 1000;
32696
+ const timeoutMs = (config2.execution?.sessionTimeoutSeconds ?? 600) * 1000;
32648
32697
  const startMs = Date.now();
32649
32698
  const proposalSettled = await Promise.allSettled(resolved.map(({ debater, adapter }) => adapter.complete(prompt, {
32650
32699
  model: debater.model,
@@ -33122,16 +33171,16 @@ class AcceptanceStrategy {
33122
33171
  }, timeoutMs);
33123
33172
  const exitCode = await Promise.race([
33124
33173
  proc.exited,
33125
- new Promise((resolve6) => setTimeout(() => resolve6(124), timeoutMs + 6000))
33174
+ new Promise((resolve7) => setTimeout(() => resolve7(124), timeoutMs + 6000))
33126
33175
  ]);
33127
33176
  clearTimeout(timeoutId);
33128
33177
  const stdout = await Promise.race([
33129
33178
  new Response(proc.stdout).text(),
33130
- new Promise((resolve6) => setTimeout(() => resolve6(""), 3000))
33179
+ new Promise((resolve7) => setTimeout(() => resolve7(""), 3000))
33131
33180
  ]);
33132
33181
  const stderr = await Promise.race([
33133
33182
  new Response(proc.stderr).text(),
33134
- new Promise((resolve6) => setTimeout(() => resolve6(""), 3000))
33183
+ new Promise((resolve7) => setTimeout(() => resolve7(""), 3000))
33135
33184
  ]);
33136
33185
  const durationMs = Date.now() - start;
33137
33186
  if (timedOut || exitCode === 124) {
@@ -34827,12 +34876,12 @@ var init_init_context = __esm(() => {
34827
34876
 
34828
34877
  // src/utils/path-security.ts
34829
34878
  import { realpathSync as realpathSync3 } from "fs";
34830
- import { dirname as dirname4, isAbsolute as isAbsolute5, join as join32, normalize as normalize2, resolve as resolve6 } from "path";
34879
+ import { dirname as dirname5, isAbsolute as isAbsolute5, join as join32, normalize as normalize2, resolve as resolve7 } from "path";
34831
34880
  function safeRealpathForComparison(p) {
34832
34881
  try {
34833
34882
  return realpathSync3(p);
34834
34883
  } catch {
34835
- const parent = dirname4(p);
34884
+ const parent = dirname5(p);
34836
34885
  if (parent === p)
34837
34886
  return normalize2(p);
34838
34887
  const resolvedParent = safeRealpathForComparison(parent);
@@ -34843,7 +34892,7 @@ function validateModulePath(modulePath, allowedRoots) {
34843
34892
  if (!modulePath) {
34844
34893
  return { valid: false, error: "Module path is empty" };
34845
34894
  }
34846
- const resolvedRoots = allowedRoots.map((r) => safeRealpathForComparison(resolve6(r)));
34895
+ const resolvedRoots = allowedRoots.map((r) => safeRealpathForComparison(resolve7(r)));
34847
34896
  if (isAbsolute5(modulePath)) {
34848
34897
  const normalized = normalize2(modulePath);
34849
34898
  const resolved = safeRealpathForComparison(normalized);
@@ -34853,8 +34902,8 @@ function validateModulePath(modulePath, allowedRoots) {
34853
34902
  }
34854
34903
  } else {
34855
34904
  for (let i = 0;i < allowedRoots.length; i++) {
34856
- const originalRoot = resolve6(allowedRoots[i]);
34857
- const absoluteInput = resolve6(join32(originalRoot, modulePath));
34905
+ const originalRoot = resolve7(allowedRoots[i]);
34906
+ const absoluteInput = resolve7(join32(originalRoot, modulePath));
34858
34907
  const resolved = safeRealpathForComparison(absoluteInput);
34859
34908
  const resolvedRoot = resolvedRoots[i];
34860
34909
  if (resolved.startsWith(`${resolvedRoot}/`) || resolved === resolvedRoot) {
@@ -35602,7 +35651,7 @@ var package_default;
35602
35651
  var init_package = __esm(() => {
35603
35652
  package_default = {
35604
35653
  name: "@nathapp/nax",
35605
- version: "0.58.2",
35654
+ version: "0.58.4",
35606
35655
  description: "AI Coding Agent Orchestrator \u2014 loops until done",
35607
35656
  type: "module",
35608
35657
  bin: {
@@ -35682,8 +35731,8 @@ var init_version = __esm(() => {
35682
35731
  NAX_VERSION = package_default.version;
35683
35732
  NAX_COMMIT = (() => {
35684
35733
  try {
35685
- if (/^[0-9a-f]{6,10}$/.test("46191e3a"))
35686
- return "46191e3a";
35734
+ if (/^[0-9a-f]{6,10}$/.test("05836706"))
35735
+ return "05836706";
35687
35736
  } catch {}
35688
35737
  try {
35689
35738
  const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
@@ -39857,7 +39906,7 @@ var init_project = __esm(() => {
39857
39906
 
39858
39907
  // src/execution/status-file.ts
39859
39908
  import { rename, unlink as unlink3 } from "fs/promises";
39860
- import { resolve as resolve8 } from "path";
39909
+ import { resolve as resolve9 } from "path";
39861
39910
  function countProgress(prd) {
39862
39911
  const stories = prd.userStories;
39863
39912
  const passed = stories.filter((s) => s.status === "passed").length;
@@ -39902,7 +39951,7 @@ function buildStatusSnapshot(state) {
39902
39951
  return snapshot;
39903
39952
  }
39904
39953
  async function writeStatusFile(filePath, status) {
39905
- const resolvedPath = resolve8(filePath);
39954
+ const resolvedPath = resolve9(filePath);
39906
39955
  if (filePath.includes("../") || filePath.includes("..\\")) {
39907
39956
  throw new Error("Invalid status file path: path traversal detected");
39908
39957
  }
@@ -40985,14 +41034,14 @@ See https://react.dev/link/invalid-hook-call for tips about how to debug and fix
40985
41034
  prevActScopeDepth !== actScopeDepth - 1 && console.error("You seem to have overlapping act() calls, this is not supported. Be sure to await previous act() calls before making a new one. ");
40986
41035
  actScopeDepth = prevActScopeDepth;
40987
41036
  }
40988
- function recursivelyFlushAsyncActWork(returnValue, resolve9, reject) {
41037
+ function recursivelyFlushAsyncActWork(returnValue, resolve10, reject) {
40989
41038
  var queue = ReactSharedInternals.actQueue;
40990
41039
  if (queue !== null)
40991
41040
  if (queue.length !== 0)
40992
41041
  try {
40993
41042
  flushActQueue(queue);
40994
41043
  enqueueTask(function() {
40995
- return recursivelyFlushAsyncActWork(returnValue, resolve9, reject);
41044
+ return recursivelyFlushAsyncActWork(returnValue, resolve10, reject);
40996
41045
  });
40997
41046
  return;
40998
41047
  } catch (error48) {
@@ -41000,7 +41049,7 @@ See https://react.dev/link/invalid-hook-call for tips about how to debug and fix
41000
41049
  }
41001
41050
  else
41002
41051
  ReactSharedInternals.actQueue = null;
41003
- 0 < ReactSharedInternals.thrownErrors.length ? (queue = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, reject(queue)) : resolve9(returnValue);
41052
+ 0 < ReactSharedInternals.thrownErrors.length ? (queue = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, reject(queue)) : resolve10(returnValue);
41004
41053
  }
41005
41054
  function flushActQueue(queue) {
41006
41055
  if (!isFlushing) {
@@ -41176,14 +41225,14 @@ See https://react.dev/link/invalid-hook-call for tips about how to debug and fix
41176
41225
  didAwaitActCall || didWarnNoAwaitAct || (didWarnNoAwaitAct = true, console.error("You called act(async () => ...) without await. This could lead to unexpected testing behaviour, interleaving multiple act calls and mixing their scopes. You should - await act(async () => ...);"));
41177
41226
  });
41178
41227
  return {
41179
- then: function(resolve9, reject) {
41228
+ then: function(resolve10, reject) {
41180
41229
  didAwaitActCall = true;
41181
41230
  thenable.then(function(returnValue) {
41182
41231
  popActScope(prevActQueue, prevActScopeDepth);
41183
41232
  if (prevActScopeDepth === 0) {
41184
41233
  try {
41185
41234
  flushActQueue(queue), enqueueTask(function() {
41186
- return recursivelyFlushAsyncActWork(returnValue, resolve9, reject);
41235
+ return recursivelyFlushAsyncActWork(returnValue, resolve10, reject);
41187
41236
  });
41188
41237
  } catch (error$0) {
41189
41238
  ReactSharedInternals.thrownErrors.push(error$0);
@@ -41194,7 +41243,7 @@ See https://react.dev/link/invalid-hook-call for tips about how to debug and fix
41194
41243
  reject(_thrownError);
41195
41244
  }
41196
41245
  } else
41197
- resolve9(returnValue);
41246
+ resolve10(returnValue);
41198
41247
  }, function(error48) {
41199
41248
  popActScope(prevActQueue, prevActScopeDepth);
41200
41249
  0 < ReactSharedInternals.thrownErrors.length ? (error48 = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, reject(error48)) : reject(error48);
@@ -41210,11 +41259,11 @@ See https://react.dev/link/invalid-hook-call for tips about how to debug and fix
41210
41259
  if (0 < ReactSharedInternals.thrownErrors.length)
41211
41260
  throw callback = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, callback;
41212
41261
  return {
41213
- then: function(resolve9, reject) {
41262
+ then: function(resolve10, reject) {
41214
41263
  didAwaitActCall = true;
41215
41264
  prevActScopeDepth === 0 ? (ReactSharedInternals.actQueue = queue, enqueueTask(function() {
41216
- return recursivelyFlushAsyncActWork(returnValue$jscomp$0, resolve9, reject);
41217
- })) : resolve9(returnValue$jscomp$0);
41265
+ return recursivelyFlushAsyncActWork(returnValue$jscomp$0, resolve10, reject);
41266
+ })) : resolve10(returnValue$jscomp$0);
41218
41267
  }
41219
41268
  };
41220
41269
  };
@@ -44056,8 +44105,8 @@ It can also happen if the client has a browser extension installed which messes
44056
44105
  currentEntangledActionThenable = {
44057
44106
  status: "pending",
44058
44107
  value: undefined,
44059
- then: function(resolve9) {
44060
- entangledListeners.push(resolve9);
44108
+ then: function(resolve10) {
44109
+ entangledListeners.push(resolve10);
44061
44110
  }
44062
44111
  };
44063
44112
  }
@@ -44081,8 +44130,8 @@ It can also happen if the client has a browser extension installed which messes
44081
44130
  status: "pending",
44082
44131
  value: null,
44083
44132
  reason: null,
44084
- then: function(resolve9) {
44085
- listeners.push(resolve9);
44133
+ then: function(resolve10) {
44134
+ listeners.push(resolve10);
44086
44135
  }
44087
44136
  };
44088
44137
  thenable.then(function() {
@@ -72607,13 +72656,13 @@ function createCliInteractionBridge() {
72607
72656
  process.stdout.write(`
72608
72657
  \uD83E\uDD16 Agent: ${text}
72609
72658
  You: `);
72610
- return new Promise((resolve4) => {
72659
+ return new Promise((resolve5) => {
72611
72660
  const rl = createInterface2({ input: process.stdin, terminal: false });
72612
72661
  rl.once("line", (line) => {
72613
72662
  rl.close();
72614
- resolve4(line.trim());
72663
+ resolve5(line.trim());
72615
72664
  });
72616
- rl.once("close", () => resolve4(""));
72665
+ rl.once("close", () => resolve5(""));
72617
72666
  });
72618
72667
  }
72619
72668
  };
@@ -73118,20 +73167,20 @@ async function displayModelEfficiency(workdir) {
73118
73167
  // src/cli/status-features.ts
73119
73168
  init_source();
73120
73169
  import { existsSync as existsSync15, readdirSync as readdirSync4 } from "fs";
73121
- import { join as join14, resolve as resolve5 } from "path";
73170
+ import { join as join14, resolve as resolve6 } from "path";
73122
73171
 
73123
73172
  // src/commands/common.ts
73124
73173
  init_path_security();
73125
73174
  init_errors();
73126
73175
  import { existsSync as existsSync14, readdirSync as readdirSync3, realpathSync as realpathSync2 } from "fs";
73127
- import { join as join12, resolve as resolve4 } from "path";
73176
+ import { join as join12, resolve as resolve5 } from "path";
73128
73177
  function resolveProject(options = {}) {
73129
73178
  const { dir, feature } = options;
73130
73179
  let projectRoot;
73131
73180
  let naxDir;
73132
73181
  let configPath;
73133
73182
  if (dir) {
73134
- projectRoot = realpathSync2(resolve4(dir));
73183
+ projectRoot = realpathSync2(resolve5(dir));
73135
73184
  naxDir = join12(projectRoot, ".nax");
73136
73185
  if (!existsSync14(naxDir)) {
73137
73186
  throw new NaxError(`Directory does not contain a nax project: ${projectRoot}
@@ -73184,7 +73233,7 @@ No features found in this project.`;
73184
73233
  };
73185
73234
  }
73186
73235
  function findProjectRoot(startDir) {
73187
- let current = resolve4(startDir);
73236
+ let current = resolve5(startDir);
73188
73237
  let depth = 0;
73189
73238
  while (depth < MAX_DIRECTORY_DEPTH) {
73190
73239
  const naxDir = join12(current, ".nax");
@@ -73501,7 +73550,7 @@ async function displayFeatureStatus(options = {}) {
73501
73550
  if (options.feature) {
73502
73551
  let featureDir;
73503
73552
  if (options.dir) {
73504
- featureDir = join14(resolve5(options.dir), ".nax", "features", options.feature);
73553
+ featureDir = join14(resolve6(options.dir), ".nax", "features", options.feature);
73505
73554
  } else {
73506
73555
  const resolved = resolveProject({ feature: options.feature });
73507
73556
  if (!resolved.featureDir) {
@@ -81627,8 +81676,8 @@ class Ink {
81627
81676
  }
81628
81677
  }
81629
81678
  async waitUntilExit() {
81630
- this.exitPromise ||= new Promise((resolve9, reject2) => {
81631
- this.resolveExitPromise = resolve9;
81679
+ this.exitPromise ||= new Promise((resolve10, reject2) => {
81680
+ this.resolveExitPromise = resolve10;
81632
81681
  this.rejectExitPromise = reject2;
81633
81682
  });
81634
81683
  if (!this.beforeExitHandler) {
@@ -83441,7 +83490,7 @@ async function promptForConfirmation(question) {
83441
83490
  if (!process.stdin.isTTY) {
83442
83491
  return true;
83443
83492
  }
83444
- return new Promise((resolve9) => {
83493
+ return new Promise((resolve10) => {
83445
83494
  process.stdout.write(source_default.bold(`${question} [Y/n] `));
83446
83495
  process.stdin.setRawMode(true);
83447
83496
  process.stdin.resume();
@@ -83454,9 +83503,9 @@ async function promptForConfirmation(question) {
83454
83503
  process.stdout.write(`
83455
83504
  `);
83456
83505
  if (answer === "n") {
83457
- resolve9(false);
83506
+ resolve10(false);
83458
83507
  } else {
83459
- resolve9(true);
83508
+ resolve10(true);
83460
83509
  }
83461
83510
  };
83462
83511
  process.stdin.on("data", handler);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nathapp/nax",
3
- "version": "0.58.2",
3
+ "version": "0.58.4",
4
4
  "description": "AI Coding Agent Orchestrator — loops until done",
5
5
  "type": "module",
6
6
  "bin": {