@nathapp/nax 0.81.0-canary.2 → 0.81.0

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 +115 -223
  2. package/package.json +3 -1
package/dist/nax.js CHANGED
@@ -17148,8 +17148,7 @@ var init_schemas_infra = __esm(() => {
17148
17148
  agents: AgentRoutingConfigSchema.default({ enabled: true, strategy: "off", profiles: [] })
17149
17149
  });
17150
17150
  OptimizerConfigSchema = exports_external.object({
17151
- enabled: exports_external.boolean(),
17152
- strategy: exports_external.enum(["rule-based", "llm", "noop"]).optional()
17151
+ enabled: exports_external.boolean()
17153
17152
  });
17154
17153
  PluginConfigEntrySchema = exports_external.object({
17155
17154
  module: exports_external.string().min(1, "plugin.module must be non-empty"),
@@ -18840,6 +18839,21 @@ function _applyRemovedRoutingKeysShim(conf, warn = defaultConfigWarn) {
18840
18839
  }
18841
18840
  return newRouting === routing ? conf : { ...conf, routing: newRouting };
18842
18841
  }
18842
+ function _applyRemovedOptimizerKeysShim(conf, warn = defaultConfigWarn) {
18843
+ const optimizer = conf.optimizer;
18844
+ if (!optimizer || typeof optimizer !== "object")
18845
+ return conf;
18846
+ const REMOVED_OPTIMIZER_KEYS = ["strategy", "strategies"];
18847
+ let newOptimizer = optimizer;
18848
+ for (const key of REMOVED_OPTIMIZER_KEYS) {
18849
+ if (key in newOptimizer) {
18850
+ warn(`optimizer.${key} was removed along with the rule-based optimizer and has no effect. Remove it from your config; set optimizer.enabled and provide a plugin optimizer instead.`);
18851
+ const { [key]: _removed, ...rest } = newOptimizer;
18852
+ newOptimizer = rest;
18853
+ }
18854
+ }
18855
+ return newOptimizer === optimizer ? conf : { ...conf, optimizer: newOptimizer };
18856
+ }
18843
18857
  function _applyRemovedWorktreeInheritShim(conf, warn = defaultConfigWarn) {
18844
18858
  const execution = conf.execution;
18845
18859
  const worktreeDependencies = execution?.worktreeDependencies;
@@ -18968,7 +18982,17 @@ function _applyFinishAutoFlowShim(conf, warn = defaultConfigWarn) {
18968
18982
  function applyConfigCompatShims(conf, logger, dedupe) {
18969
18983
  const log = dedupe.wrapLogger(logger);
18970
18984
  const warn = dedupe.warn;
18971
- return _applyFinishAutoFlowShim(_applyRemovedWorktreeInheritShim(_applyLegacyReviewExecutionShim(_applyRemovedRoutingKeysShim(applyRoutingRetryDeprecationWarning(applyBatchModeCompat(applyRemovedStrategyCompat(migrateLegacyReviewModelKey(migrateLegacyTestPattern(conf, log), log), warn), warn), warn), warn), warn), warn), warn);
18985
+ let out = migrateLegacyTestPattern(conf, log);
18986
+ out = migrateLegacyReviewModelKey(out, log);
18987
+ out = applyRemovedStrategyCompat(out, warn);
18988
+ out = applyBatchModeCompat(out, warn);
18989
+ out = applyRoutingRetryDeprecationWarning(out, warn);
18990
+ out = _applyRemovedRoutingKeysShim(out, warn);
18991
+ out = _applyLegacyReviewExecutionShim(out, warn);
18992
+ out = _applyRemovedWorktreeInheritShim(out, warn);
18993
+ out = _applyFinishAutoFlowShim(out, warn);
18994
+ out = _applyRemovedOptimizerKeysShim(out, warn);
18995
+ return out;
18972
18996
  }
18973
18997
  var SECURITY_SENSITIVE_KEY_PATHS, REMOVED_FINISH_KEYS;
18974
18998
  var init_compat_shims = __esm(() => {
@@ -29969,186 +29993,20 @@ class NoopOptimizer {
29969
29993
  }
29970
29994
  var init_noop_optimizer = () => {};
29971
29995
 
29972
- // src/optimizer/rule-based.optimizer.ts
29973
- class RuleBasedOptimizer {
29974
- name = "rule-based";
29975
- async optimize(input) {
29976
- const originalTokens = estimateTokens2(input.prompt);
29977
- const appliedRules = [];
29978
- let optimized = input.prompt;
29979
- const config2 = {
29980
- ...DEFAULT_CONFIG2,
29981
- ...input.config.optimizer?.strategies?.["rule-based"]
29982
- };
29983
- if (config2.stripWhitespace) {
29984
- const before = optimized;
29985
- optimized = this.stripWhitespace(optimized);
29986
- if (optimized !== before) {
29987
- appliedRules.push("stripWhitespace");
29988
- }
29989
- }
29990
- if (config2.compactCriteria) {
29991
- const before = optimized;
29992
- optimized = this.compactCriteria(optimized);
29993
- if (optimized !== before) {
29994
- appliedRules.push("compactCriteria");
29995
- }
29996
- }
29997
- if (config2.deduplicateContext && input.contextMarkdown) {
29998
- const before = optimized;
29999
- optimized = this.deduplicateContext(optimized, input.contextMarkdown);
30000
- if (optimized !== before) {
30001
- appliedRules.push("deduplicateContext");
30002
- }
30003
- }
30004
- if (config2.maxPromptTokens) {
30005
- const currentTokens = estimateTokens2(optimized);
30006
- if (currentTokens > config2.maxPromptTokens) {
30007
- optimized = this.trimToMaxTokens(optimized, config2.maxPromptTokens);
30008
- appliedRules.push("maxPromptTokens");
30009
- }
30010
- }
30011
- const optimizedTokens = estimateTokens2(optimized);
30012
- const savings = originalTokens > 0 ? (originalTokens - optimizedTokens) / originalTokens : 0;
30013
- return {
30014
- prompt: optimized,
30015
- originalTokens,
30016
- optimizedTokens,
30017
- savings,
30018
- appliedRules
30019
- };
30020
- }
30021
- stripWhitespace(prompt) {
30022
- return prompt.split(`
30023
- `).map((line) => line.trimEnd()).join(`
30024
- `).replace(/\n{3,}/g, `
30025
-
30026
- `);
30027
- }
30028
- compactCriteria(prompt) {
30029
- return prompt.replace(/The user should be able to /gi, "").replace(/The system must /gi, "").replace(/The system should /gi, "").replace(/When the /gi, "").replace(/When a /gi, "").replace(/it should validate all fields/gi, "validate all fields").replace(/display an error message/gi, "show error").replace(/error message/gi, "error");
30030
- }
30031
- deduplicateContext(prompt, contextMarkdown) {
30032
- const contextSectionMatch = prompt.match(/# Context\n([\s\S]*?)(?=\n#|$)/i);
30033
- if (!contextSectionMatch) {
30034
- return prompt;
30035
- }
30036
- const contextSection = contextSectionMatch[1];
30037
- const contextLines = contextSection.split(`
30038
- `);
30039
- const dedupedLines = contextLines.filter((line) => {
30040
- const trimmed = line.trim();
30041
- if (!trimmed)
30042
- return true;
30043
- return !contextMarkdown.includes(trimmed);
30044
- });
30045
- if (dedupedLines.length < contextLines.length) {
30046
- const newContextSection = dedupedLines.join(`
30047
- `);
30048
- return prompt.replace(contextSectionMatch[0], `# Context
30049
- ${newContextSection}`);
30050
- }
30051
- return prompt;
30052
- }
30053
- trimToMaxTokens(prompt, maxTokens) {
30054
- const currentTokens = estimateTokens2(prompt);
30055
- if (currentTokens <= maxTokens) {
30056
- return prompt;
30057
- }
30058
- const sections = this.extractSections(prompt);
30059
- const targetChars = maxTokens * 4;
30060
- const trimmedMessage = `
30061
- ... (context trimmed)`;
30062
- let result = "";
30063
- let remainingChars = targetChars;
30064
- if (sections.task) {
30065
- result += sections.task;
30066
- remainingChars -= sections.task.length;
30067
- }
30068
- if (sections.acceptanceCriteria) {
30069
- result += sections.acceptanceCriteria;
30070
- remainingChars -= sections.acceptanceCriteria.length;
30071
- }
30072
- const trimmable = sections.context ?? sections.other;
30073
- if (trimmable && remainingChars > 0) {
30074
- const reserveForMessage = trimmable.length > remainingChars ? trimmedMessage.length : 0;
30075
- const maxContextChars = Math.max(0, remainingChars - reserveForMessage);
30076
- const trimmedContext = trimmable.substring(0, maxContextChars);
30077
- result += trimmedContext;
30078
- if (trimmedContext.length < trimmable.length) {
30079
- result += trimmedMessage;
30080
- }
30081
- }
30082
- return result.trim() ? result : prompt;
30083
- }
30084
- extractSections(prompt) {
30085
- const sections = {};
30086
- const taskMatch = prompt.match(/# Task\n([\s\S]*?)(?=\n#|$)/i);
30087
- if (taskMatch) {
30088
- sections.task = taskMatch[0];
30089
- }
30090
- const contextMatch = prompt.match(/# Context\n([\s\S]*?)(?=\n#|$)/i);
30091
- if (contextMatch) {
30092
- sections.context = contextMatch[0];
30093
- }
30094
- const acMatch = prompt.match(/# Acceptance Criteria\n([\s\S]*?)(?=\n#|$)/i);
30095
- if (acMatch) {
30096
- sections.acceptanceCriteria = acMatch[0];
30097
- }
30098
- let other = prompt;
30099
- if (sections.task) {
30100
- other = other.replace(sections.task, "");
30101
- }
30102
- if (sections.context) {
30103
- other = other.replace(sections.context, "");
30104
- }
30105
- if (sections.acceptanceCriteria) {
30106
- other = other.replace(sections.acceptanceCriteria, "");
30107
- }
30108
- if (other.trim()) {
30109
- sections.other = other;
30110
- }
30111
- return sections;
30112
- }
30113
- }
30114
- var DEFAULT_CONFIG2;
30115
- var init_rule_based_optimizer = __esm(() => {
30116
- DEFAULT_CONFIG2 = {
30117
- stripWhitespace: true,
30118
- compactCriteria: true,
30119
- deduplicateContext: true,
30120
- maxPromptTokens: 8000
30121
- };
30122
- });
30123
-
30124
29996
  // src/optimizer/index.ts
30125
29997
  function resolveOptimizer(config2, pluginRegistry) {
30126
29998
  if (!config2.optimizer?.enabled) {
30127
29999
  return new NoopOptimizer;
30128
30000
  }
30129
- if (pluginRegistry) {
30130
- const pluginOptimizers = pluginRegistry.getOptimizers();
30131
- if (pluginOptimizers.length > 0) {
30132
- return pluginOptimizers[0];
30133
- }
30134
- }
30135
- const strategy = config2.optimizer.strategy ?? "noop";
30136
- switch (strategy) {
30137
- case "rule-based":
30138
- return new RuleBasedOptimizer;
30139
- case "noop":
30140
- return new NoopOptimizer;
30141
- default:
30142
- getSafeLogger()?.warn("optimizer", `Unknown optimizer strategy '${strategy}', using noop`);
30143
- return new NoopOptimizer;
30001
+ const pluginOptimizers = pluginRegistry?.getOptimizers() ?? [];
30002
+ if (pluginOptimizers.length > 0) {
30003
+ return pluginOptimizers[0];
30144
30004
  }
30005
+ return new NoopOptimizer;
30145
30006
  }
30146
30007
  var init_optimizer = __esm(() => {
30147
30008
  init_noop_optimizer();
30148
- init_rule_based_optimizer();
30149
- init_logger2();
30150
30009
  init_noop_optimizer();
30151
- init_rule_based_optimizer();
30152
30010
  });
30153
30011
 
30154
30012
  // src/context/fragments/store.ts
@@ -50783,7 +50641,7 @@ var package_default;
50783
50641
  var init_package = __esm(() => {
50784
50642
  package_default = {
50785
50643
  name: "@nathapp/nax",
50786
- version: "0.81.0-canary.2",
50644
+ version: "0.81.0",
50787
50645
  description: "AI Coding Agent Orchestrator \u2014 loops until done",
50788
50646
  type: "module",
50789
50647
  bin: {
@@ -50825,6 +50683,8 @@ var init_package = __esm(() => {
50825
50683
  "test:e2e": "timeout -k 5s 180s bun test test/e2e/ --timeout=60000",
50826
50684
  "test:coverage": "bun run scripts/check-coverage.ts",
50827
50685
  "test:coverage:report": "bun run scripts/check-coverage.ts --report",
50686
+ "test:coverage:update": "bun run scripts/check-coverage.ts --update-baseline",
50687
+ "test:coverage:list": "bun run scripts/check-coverage.ts --list",
50828
50688
  "report:test-overlap": "bun run scripts/report-test-overlap.ts",
50829
50689
  "report:dead-tests": "bun run scripts/report-dead-tests.ts",
50830
50690
  "check:test-mocks": "bun scripts/check-inline-test-mocks.ts --strict",
@@ -50898,8 +50758,8 @@ var init_version = __esm(() => {
50898
50758
  NAX_VERSION = package_default.version;
50899
50759
  NAX_COMMIT = (() => {
50900
50760
  try {
50901
- if (/^[0-9a-f]{6,10}$/.test("6e101254"))
50902
- return "6e101254";
50761
+ if (/^[0-9a-f]{6,10}$/.test("a2cc47be"))
50762
+ return "a2cc47be";
50903
50763
  } catch {}
50904
50764
  try {
50905
50765
  const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
@@ -62316,7 +62176,7 @@ async function checkGitignoreCoversNax(workdir) {
62316
62176
  "**/.nax-acceptance*",
62317
62177
  "**/_nax_acceptance_test.py",
62318
62178
  "**/_nax_suggested_test.py",
62319
- `**/${PROJECT_FEATURES_DIR}/*/`
62179
+ `${PROJECT_FEATURES_DIR}/*/fragments/`
62320
62180
  ];
62321
62181
  const missing = patterns.filter((pattern) => !content.includes(pattern));
62322
62182
  const passed = missing.length === 0;
@@ -66110,7 +65970,7 @@ async function acquireLock(workdir) {
66110
65970
  }
66111
65971
  const tombstonePath = `${lockPath}.stale.${process.pid}.${Date.now()}`;
66112
65972
  try {
66113
- await rename2(lockPath, tombstonePath);
65973
+ await _lockDeps.rename(lockPath, tombstonePath);
66114
65974
  } catch (renameError) {
66115
65975
  if (renameError.code === "ENOENT") {
66116
65976
  return false;
@@ -66175,8 +66035,12 @@ async function releaseLock(workdir) {
66175
66035
  }
66176
66036
  }
66177
66037
  }
66038
+ var _lockDeps;
66178
66039
  var init_lock = __esm(() => {
66179
66040
  init_logger2();
66041
+ _lockDeps = {
66042
+ rename: rename2
66043
+ };
66180
66044
  });
66181
66045
 
66182
66046
  // src/execution/helpers.ts
@@ -75746,7 +75610,7 @@ ${missing.join(`
75746
75610
  `);
75747
75611
  return { created: false, added: [...missing] };
75748
75612
  }
75749
- var NAX_GITIGNORE_ENTRIES, NAX_NAXIGNORE_ENTRIES, NAX_NAXIGNORE_HEADER = `# nax - paths excluded from context, review
75613
+ var FEATURE_RUN_ARTIFACTS, NAX_GITIGNORE_ENTRIES, NAX_NAXIGNORE_ENTRIES, NAX_NAXIGNORE_HEADER = `# nax - paths excluded from context, review
75750
75614
  # and verification scanning.
75751
75615
  # gitignore syntax. Also honoured per-package.
75752
75616
 
@@ -75759,24 +75623,32 @@ var NAX_GITIGNORE_ENTRIES, NAX_NAXIGNORE_ENTRIES, NAX_NAXIGNORE_HEADER = `# nax
75759
75623
  `;
75760
75624
  var init_gitignore = __esm(() => {
75761
75625
  init_config();
75626
+ FEATURE_RUN_ARTIFACTS = [
75627
+ "runs/",
75628
+ "plan/",
75629
+ "sessions/",
75630
+ "stories/",
75631
+ "fragments/",
75632
+ "interactions/",
75633
+ "semantic-verdicts/",
75634
+ "status.json",
75635
+ "checkpoint.jsonl",
75636
+ "progress.txt",
75637
+ "acp-sessions.json",
75638
+ "acceptance-refined.json",
75639
+ "*.bak"
75640
+ ].map((artifact) => `**/${PROJECT_FEATURES_DIR}/*/${artifact}`);
75762
75641
  NAX_GITIGNORE_ENTRIES = [
75763
75642
  ".nax-verifier-verdict.json",
75764
75643
  "nax.lock",
75765
75644
  ".nax/**/runs/",
75766
75645
  ".nax/metrics.json",
75767
- `${PROJECT_FEATURES_DIR}/*/status.json`,
75768
- `${PROJECT_FEATURES_DIR}/*/plan/`,
75769
- `${PROJECT_FEATURES_DIR}/*/fragments/`,
75770
- `${PROJECT_FEATURES_DIR}/*/acp-sessions.json`,
75771
- `${PROJECT_FEATURES_DIR}/*/interactions/`,
75772
- `${PROJECT_FEATURES_DIR}/*/progress.txt`,
75773
- `${PROJECT_FEATURES_DIR}/*/acceptance-refined.json`,
75646
+ ...FEATURE_RUN_ARTIFACTS,
75774
75647
  ".nax-pids",
75775
75648
  ".nax-wt/",
75776
75649
  "**/.nax-acceptance*",
75777
75650
  "**/_nax_acceptance_test.py",
75778
75651
  "**/_nax_suggested_test.py",
75779
- `**/${PROJECT_FEATURES_DIR}/*/`,
75780
75652
  ".nax/prompt-audit/",
75781
75653
  ".nax/finish-audit/",
75782
75654
  ".nax/mutation-journal/"
@@ -83758,6 +83630,7 @@ __export(exports_execution, {
83758
83630
  _postRunDeps: () => _postRunDeps,
83759
83631
  _pidRegistryDeps: () => _pidRegistryDeps,
83760
83632
  _newPackageSetupDeps: () => _newPackageSetupDeps,
83633
+ _lockDeps: () => _lockDeps,
83761
83634
  StoryOrchestratorBuilder: () => StoryOrchestratorBuilder,
83762
83635
  StatusWriter: () => StatusWriter,
83763
83636
  STRICT_VERDICT_PHASE_NAMES: () => STRICT_VERDICT_PHASE_NAMES,
@@ -85179,8 +85052,7 @@ var init_config_descriptions = __esm(() => {
85179
85052
  "context.autoDetect.maxFiles": "Max files to auto-detect",
85180
85053
  "context.autoDetect.traceImports": "Trace imports to find related files",
85181
85054
  optimizer: "Prompt optimizer configuration",
85182
- "optimizer.enabled": "Enable prompt optimizer",
85183
- "optimizer.strategy": "Optimization strategy: rule-based | llm | noop",
85055
+ "optimizer.enabled": "Enable prompt optimizer (pass-through unless a plugin provides one)",
85184
85056
  plugins: "Plugin configurations",
85185
85057
  hooks: "Hooks configuration",
85186
85058
  "hooks.skipGlobal": "Skip loading global hooks",
@@ -117609,6 +117481,7 @@ import { join as join106 } from "path";
117609
117481
  // src/commands/logs-formatter.ts
117610
117482
  init_source();
117611
117483
  init_formatter();
117484
+ init_bun_deps();
117612
117485
  import { readdirSync as readdirSync8 } from "fs";
117613
117486
  import { join as join105 } from "path";
117614
117487
 
@@ -117795,13 +117668,57 @@ async function displayLogs(filePath, options) {
117795
117668
  }
117796
117669
  }
117797
117670
  }
117798
- async function followLogs(filePath, options) {
117671
+ async function defaultReadRange(filePath, start) {
117672
+ return Bun.file(filePath).slice(start).text();
117673
+ }
117674
+ async function defaultSize(filePath) {
117675
+ return (await Bun.file(filePath).stat()).size;
117676
+ }
117677
+ var DEFAULT_FOLLOW_LOGS_DEPS = {
117678
+ emit: (line) => console.log(line),
117679
+ sleep: (ms, signal) => cancellableDelay(ms, signal),
117680
+ readRange: defaultReadRange,
117681
+ size: defaultSize
117682
+ };
117683
+ async function followLogs(filePath, options, opts) {
117684
+ const deps = { ...DEFAULT_FOLLOW_LOGS_DEPS, ...opts?._deps };
117685
+ const signal = opts?.signal;
117799
117686
  const mode = options.json ? "json" : "normal";
117800
- const file3 = Bun.file(filePath);
117801
- const content = await file3.text();
117802
- const lines = content.trim().split(`
117687
+ if (signal?.aborted)
117688
+ return "cancelled";
117689
+ let lastOffset = await consumeRange(filePath, 0, deps, options, mode);
117690
+ while (true) {
117691
+ if (signal?.aborted)
117692
+ return "cancelled";
117693
+ try {
117694
+ await deps.sleep(500, signal);
117695
+ } catch (err) {
117696
+ if (signal?.aborted)
117697
+ return "cancelled";
117698
+ throw err;
117699
+ }
117700
+ let currentSize;
117701
+ try {
117702
+ currentSize = await deps.size(filePath);
117703
+ } catch {
117704
+ return "cancelled";
117705
+ }
117706
+ if (currentSize > lastOffset) {
117707
+ lastOffset = await consumeRange(filePath, lastOffset, deps, options, mode);
117708
+ } else if (currentSize < lastOffset) {
117709
+ lastOffset = currentSize;
117710
+ }
117711
+ }
117712
+ }
117713
+ async function consumeRange(filePath, start, deps, options, mode) {
117714
+ const chunk = await deps.readRange(filePath, start);
117715
+ if (!chunk)
117716
+ return start;
117717
+ const lastNewline = chunk.lastIndexOf(`
117803
117718
  `);
117804
- for (const line of lines) {
117719
+ const complete = lastNewline === -1 ? "" : chunk.slice(0, lastNewline + 1);
117720
+ for (const line of complete.split(`
117721
+ `)) {
117805
117722
  if (!line.trim())
117806
117723
  continue;
117807
117724
  try {
@@ -117811,36 +117728,11 @@ async function followLogs(filePath, options) {
117811
117728
  }
117812
117729
  const formatted = formatLogEntry(entry, { mode, useColor: true });
117813
117730
  if (formatted.shouldDisplay && formatted.output) {
117814
- console.log(formatted.output);
117731
+ deps.emit(formatted.output);
117815
117732
  }
117816
117733
  } catch {}
117817
117734
  }
117818
- let lastSize = (await Bun.file(filePath).stat()).size;
117819
- while (true) {
117820
- await Bun.sleep(500);
117821
- const currentSize = (await Bun.file(filePath).stat()).size;
117822
- if (currentSize > lastSize) {
117823
- const newFile = Bun.file(filePath);
117824
- const newContent = await newFile.text();
117825
- const newLines = newContent.slice(lastSize).trim().split(`
117826
- `);
117827
- for (const line of newLines) {
117828
- if (!line.trim())
117829
- continue;
117830
- try {
117831
- const entry = JSON.parse(line);
117832
- if (!shouldDisplayEntry(entry, options)) {
117833
- continue;
117834
- }
117835
- const formatted = formatLogEntry(entry, { mode, useColor: true });
117836
- if (formatted.shouldDisplay && formatted.output) {
117837
- console.log(formatted.output);
117838
- }
117839
- } catch {}
117840
- }
117841
- lastSize = currentSize;
117842
- }
117843
- }
117735
+ return start + Buffer.byteLength(complete, "utf8");
117844
117736
  }
117845
117737
  function shouldDisplayEntry(entry, options) {
117846
117738
  if (options.story && entry.storyId !== options.story) {
@@ -117864,7 +117756,7 @@ async function logsCommand(options) {
117864
117756
  return;
117865
117757
  }
117866
117758
  if (options.follow) {
117867
- await followLogs(runFile2, options);
117759
+ await followLogs(runFile2, options, { signal: options.signal });
117868
117760
  } else {
117869
117761
  await displayLogs(runFile2, options);
117870
117762
  }
@@ -117887,7 +117779,7 @@ async function logsCommand(options) {
117887
117779
  throw new Error("No runs found for this feature");
117888
117780
  }
117889
117781
  if (options.follow) {
117890
- await followLogs(runFile, options);
117782
+ await followLogs(runFile, options, { signal: options.signal });
117891
117783
  return;
117892
117784
  }
117893
117785
  await displayLogs(runFile, options);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nathapp/nax",
3
- "version": "0.81.0-canary.2",
3
+ "version": "0.81.0",
4
4
  "description": "AI Coding Agent Orchestrator — loops until done",
5
5
  "type": "module",
6
6
  "bin": {
@@ -42,6 +42,8 @@
42
42
  "test:e2e": "timeout -k 5s 180s bun test test/e2e/ --timeout=60000",
43
43
  "test:coverage": "bun run scripts/check-coverage.ts",
44
44
  "test:coverage:report": "bun run scripts/check-coverage.ts --report",
45
+ "test:coverage:update": "bun run scripts/check-coverage.ts --update-baseline",
46
+ "test:coverage:list": "bun run scripts/check-coverage.ts --list",
45
47
  "report:test-overlap": "bun run scripts/report-test-overlap.ts",
46
48
  "report:dead-tests": "bun run scripts/report-dead-tests.ts",
47
49
  "check:test-mocks": "bun scripts/check-inline-test-mocks.ts --strict",