@nathapp/nax 0.65.5 → 0.66.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 (3) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/nax.js +1671 -1463
  3. package/package.json +1 -1
package/dist/nax.js CHANGED
@@ -3545,119 +3545,6 @@ var init_env = __esm(() => {
3545
3545
  ];
3546
3546
  });
3547
3547
 
3548
- // src/agents/acp/parser.ts
3549
- function createParseState() {
3550
- return {
3551
- text: "",
3552
- tokenUsage: undefined,
3553
- exactCostUsd: undefined,
3554
- stopReason: undefined,
3555
- error: undefined,
3556
- retryable: false
3557
- };
3558
- }
3559
- function parseAcpxJsonLine(line, state) {
3560
- try {
3561
- const event = JSON.parse(line);
3562
- if (event.jsonrpc === "2.0") {
3563
- if (event.method === "session/update" && event.params?.update) {
3564
- const update = event.params.update;
3565
- if (update.sessionUpdate === "agent_message_chunk" && update.content?.type === "text" && typeof update.content.text === "string") {
3566
- const text = update.content.text;
3567
- state.text += text;
3568
- return {
3569
- kind: "message_update",
3570
- deltaBytes: text.length
3571
- };
3572
- }
3573
- if (update.sessionUpdate === "agent_thought_chunk" && update.content?.type === "text" && typeof update.content.text === "string") {
3574
- return {
3575
- kind: "thinking_update",
3576
- deltaBytes: update.content.text.length
3577
- };
3578
- }
3579
- if (update.sessionUpdate === "usage_update") {
3580
- const activity = { kind: "usage_update" };
3581
- if (typeof update.used === "number") {
3582
- activity.outputTokens = update.used;
3583
- }
3584
- if (typeof update.cost?.amount === "number") {
3585
- activity.costUsd = update.cost.amount;
3586
- state.exactCostUsd = update.cost.amount;
3587
- }
3588
- return activity;
3589
- }
3590
- }
3591
- if (event.id !== undefined && event.result && typeof event.result === "object") {
3592
- const result = event.result;
3593
- if (result.stopReason)
3594
- state.stopReason = result.stopReason;
3595
- if (result.stop_reason)
3596
- state.stopReason = result.stop_reason;
3597
- if (result.usage && typeof result.usage === "object") {
3598
- const u = result.usage;
3599
- state.tokenUsage = {
3600
- input_tokens: u.inputTokens ?? u.input_tokens ?? 0,
3601
- output_tokens: u.outputTokens ?? u.output_tokens ?? 0,
3602
- cache_read_input_tokens: u.cachedReadTokens ?? u.cache_read_input_tokens ?? 0,
3603
- cache_creation_input_tokens: u.cachedWriteTokens ?? u.cache_creation_input_tokens ?? 0
3604
- };
3605
- }
3606
- }
3607
- if (event.error && typeof event.error === "object") {
3608
- const err = event.error;
3609
- let errorMsg = typeof err.message === "string" ? err.message : JSON.stringify(event.error);
3610
- if (err.data && typeof err.data === "object") {
3611
- const data = err.data;
3612
- const suffix = [data.acpxCode, data.detailCode].filter(Boolean).join("/");
3613
- if (suffix)
3614
- errorMsg = `${errorMsg} [${suffix}]`;
3615
- if (!state.error && data.retryable === true)
3616
- state.retryable = true;
3617
- }
3618
- if (!state.error)
3619
- state.error = errorMsg;
3620
- }
3621
- return;
3622
- }
3623
- if (event.content && typeof event.content === "string")
3624
- state.text += event.content;
3625
- if (event.text && typeof event.text === "string")
3626
- state.text += event.text;
3627
- if (event.result && typeof event.result === "string")
3628
- state.text = event.result;
3629
- if (event.cumulative_token_usage)
3630
- state.tokenUsage = event.cumulative_token_usage;
3631
- if (event.usage) {
3632
- state.tokenUsage = {
3633
- input_tokens: event.usage.input_tokens ?? event.usage.prompt_tokens ?? 0,
3634
- output_tokens: event.usage.output_tokens ?? event.usage.completion_tokens ?? 0
3635
- };
3636
- }
3637
- if (event.stopReason)
3638
- state.stopReason = event.stopReason;
3639
- if (event.stop_reason)
3640
- state.stopReason = event.stop_reason;
3641
- if (event.error) {
3642
- state.error = typeof event.error === "string" ? event.error : event.error.message ?? JSON.stringify(event.error);
3643
- }
3644
- } catch {
3645
- if (!state.text)
3646
- state.text = line;
3647
- }
3648
- return;
3649
- }
3650
- function finalizeParseState(state) {
3651
- return {
3652
- text: state.text.trim(),
3653
- tokenUsage: state.tokenUsage,
3654
- exactCostUsd: state.exactCostUsd,
3655
- stopReason: state.stopReason,
3656
- error: state.error,
3657
- retryable: state.retryable
3658
- };
3659
- }
3660
-
3661
3548
  // src/agents/acp/spawn-client.ts
3662
3549
  import { randomUUID } from "crypto";
3663
3550
  async function readAndParseLines(stream, state, onActivity) {
@@ -3837,6 +3724,13 @@ class SpawnAcpSession {
3837
3724
  costUsd: activity.costUsd,
3838
3725
  timestamp: now()
3839
3726
  });
3727
+ } else if (activity.kind === "tool_call_update") {
3728
+ emit({
3729
+ ...baseEvent,
3730
+ kind: "agent.tool_call_update",
3731
+ toolName: activity.toolName,
3732
+ timestamp: now()
3733
+ });
3840
3734
  }
3841
3735
  } : undefined;
3842
3736
  const parsePromise = readAndParseLines(proc.stdout, parseState, onActivity).catch(() => {});
@@ -4115,6 +4009,7 @@ function createSpawnAcpClient(cmdStr, cwd, timeoutSeconds, onPidSpawned, promptR
4115
4009
  }
4116
4010
  var ACPX_STREAM_DRAIN_TIMEOUT_MS = 5000, _spawnClientDeps;
4117
4011
  var init_spawn_client = __esm(() => {
4012
+ init_agents();
4118
4013
  init_logger2();
4119
4014
  init_bun_deps();
4120
4015
  init_env();
@@ -4793,6 +4688,144 @@ var init_adapter = __esm(() => {
4793
4688
  };
4794
4689
  });
4795
4690
 
4691
+ // src/agents/acp/parser.ts
4692
+ function createParseState() {
4693
+ return {
4694
+ text: "",
4695
+ tokenUsage: undefined,
4696
+ exactCostUsd: undefined,
4697
+ stopReason: undefined,
4698
+ error: undefined,
4699
+ retryable: false
4700
+ };
4701
+ }
4702
+ function parseAcpxJsonLine(line, state) {
4703
+ try {
4704
+ const event = JSON.parse(line);
4705
+ if (event.jsonrpc === "2.0") {
4706
+ if (event.method === "session/update" && event.params?.update) {
4707
+ const update = event.params.update;
4708
+ if (update.sessionUpdate === "agent_message_chunk" && update.content?.type === "text" && typeof update.content.text === "string") {
4709
+ const text = update.content.text;
4710
+ state.text += text;
4711
+ return {
4712
+ kind: "message_update",
4713
+ deltaBytes: text.length
4714
+ };
4715
+ }
4716
+ if (update.sessionUpdate === "agent_thought_chunk" && update.content?.type === "text" && typeof update.content.text === "string") {
4717
+ return {
4718
+ kind: "thinking_update",
4719
+ deltaBytes: update.content.text.length
4720
+ };
4721
+ }
4722
+ if (update.sessionUpdate === "usage_update") {
4723
+ const activity = { kind: "usage_update" };
4724
+ if (typeof update.used === "number") {
4725
+ activity.outputTokens = update.used;
4726
+ }
4727
+ if (typeof update.cost?.amount === "number") {
4728
+ activity.costUsd = update.cost.amount;
4729
+ state.exactCostUsd = update.cost.amount;
4730
+ }
4731
+ return activity;
4732
+ }
4733
+ if (update.sessionUpdate === "tool_call" || update.sessionUpdate === "tool_call_update") {
4734
+ return {
4735
+ kind: "tool_call_update",
4736
+ toolName: extractToolName(update)
4737
+ };
4738
+ }
4739
+ }
4740
+ if (event.id !== undefined && event.result && typeof event.result === "object") {
4741
+ const result = event.result;
4742
+ if (result.stopReason)
4743
+ state.stopReason = result.stopReason;
4744
+ if (result.stop_reason)
4745
+ state.stopReason = result.stop_reason;
4746
+ if (result.usage && typeof result.usage === "object") {
4747
+ const u = result.usage;
4748
+ state.tokenUsage = {
4749
+ input_tokens: u.inputTokens ?? u.input_tokens ?? 0,
4750
+ output_tokens: u.outputTokens ?? u.output_tokens ?? 0,
4751
+ cache_read_input_tokens: u.cachedReadTokens ?? u.cache_read_input_tokens ?? 0,
4752
+ cache_creation_input_tokens: u.cachedWriteTokens ?? u.cache_creation_input_tokens ?? 0
4753
+ };
4754
+ }
4755
+ }
4756
+ if (event.error && typeof event.error === "object") {
4757
+ const err = event.error;
4758
+ let errorMsg = typeof err.message === "string" ? err.message : JSON.stringify(event.error);
4759
+ if (err.data && typeof err.data === "object") {
4760
+ const data = err.data;
4761
+ const suffix = [data.acpxCode, data.detailCode].filter(Boolean).join("/");
4762
+ if (suffix)
4763
+ errorMsg = `${errorMsg} [${suffix}]`;
4764
+ if (!state.error && data.retryable === true)
4765
+ state.retryable = true;
4766
+ }
4767
+ if (!state.error)
4768
+ state.error = errorMsg;
4769
+ }
4770
+ return;
4771
+ }
4772
+ if (event.content && typeof event.content === "string")
4773
+ state.text += event.content;
4774
+ if (event.text && typeof event.text === "string")
4775
+ state.text += event.text;
4776
+ if (event.result && typeof event.result === "string")
4777
+ state.text = event.result;
4778
+ if (event.cumulative_token_usage)
4779
+ state.tokenUsage = event.cumulative_token_usage;
4780
+ if (event.usage) {
4781
+ state.tokenUsage = {
4782
+ input_tokens: event.usage.input_tokens ?? event.usage.prompt_tokens ?? 0,
4783
+ output_tokens: event.usage.output_tokens ?? event.usage.completion_tokens ?? 0
4784
+ };
4785
+ }
4786
+ if (event.stopReason)
4787
+ state.stopReason = event.stopReason;
4788
+ if (event.stop_reason)
4789
+ state.stopReason = event.stop_reason;
4790
+ if (event.error) {
4791
+ state.error = typeof event.error === "string" ? event.error : event.error.message ?? JSON.stringify(event.error);
4792
+ }
4793
+ } catch {
4794
+ if (!state.text)
4795
+ state.text = line;
4796
+ }
4797
+ return;
4798
+ }
4799
+ function extractToolName(update) {
4800
+ const directName = update.toolName;
4801
+ if (typeof directName === "string" && directName.trim())
4802
+ return directName;
4803
+ const nestedTool = update.tool;
4804
+ if (nestedTool && typeof nestedTool === "object") {
4805
+ const name = nestedTool.name;
4806
+ if (typeof name === "string" && name.trim())
4807
+ return name;
4808
+ }
4809
+ return;
4810
+ }
4811
+ function finalizeParseState(state) {
4812
+ return {
4813
+ text: state.text.trim(),
4814
+ tokenUsage: state.tokenUsage,
4815
+ exactCostUsd: state.exactCostUsd,
4816
+ stopReason: state.stopReason,
4817
+ error: state.error,
4818
+ retryable: state.retryable
4819
+ };
4820
+ }
4821
+
4822
+ // src/agents/acp/index.ts
4823
+ var init_acp = __esm(() => {
4824
+ init_adapter();
4825
+ init_spawn_client();
4826
+ init_token_mapper();
4827
+ });
4828
+
4796
4829
  // src/agents/registry.ts
4797
4830
  async function getInstalledAgents() {
4798
4831
  return [];
@@ -5235,7 +5268,7 @@ class AgentManager {
5235
5268
  let rateLimitRetry = 0;
5236
5269
  let staleRetryAttempts = 0;
5237
5270
  let currentBundle = request.bundle;
5238
- let currentFailure;
5271
+ let currentHopKind = { kind: "primary" };
5239
5272
  let finalPrompt;
5240
5273
  const _opStartMs = Date.now();
5241
5274
  const _agentChain = [primaryAgent];
@@ -5246,7 +5279,7 @@ class AgentManager {
5246
5279
  let result;
5247
5280
  let updatedBundle = currentBundle;
5248
5281
  if (request.executeHop) {
5249
- const hopOut = await request.executeHop(currentAgent, currentBundle, currentFailure, request.runOptions);
5282
+ const hopOut = await request.executeHop(currentAgent, currentBundle, currentHopKind, request.runOptions);
5250
5283
  result = hopOut.result;
5251
5284
  updatedBundle = hopOut.bundle ?? currentBundle;
5252
5285
  finalPrompt = hopOut.prompt ?? finalPrompt;
@@ -5299,6 +5332,7 @@ class AgentManager {
5299
5332
  attempt: staleRetryAttempts,
5300
5333
  agent: currentAgent
5301
5334
  });
5335
+ currentHopKind = { kind: "stale-retry", attempt: staleRetryAttempts };
5302
5336
  continue;
5303
5337
  }
5304
5338
  const hasBundleForSwap = !!bundleForSwapCheck || isFailStale;
@@ -5364,7 +5398,7 @@ class AgentManager {
5364
5398
  hopsSoFar += 1;
5365
5399
  rateLimitRetry = 0;
5366
5400
  currentBundle = updatedBundle;
5367
- currentFailure = adapterFailure;
5401
+ currentHopKind = { kind: "swap", failure: adapterFailure };
5368
5402
  const hop = {
5369
5403
  storyId: request.runOptions.storyId,
5370
5404
  priorAgent: currentAgent,
@@ -5673,49 +5707,6 @@ function resolveDefaultAgent(config) {
5673
5707
  }
5674
5708
  var FALLBACK_DEFAULT_AGENT = "claude";
5675
5709
 
5676
- // src/agents/index.ts
5677
- var init_agents = __esm(() => {
5678
- init_interaction_handler();
5679
- init_types();
5680
- init_registry();
5681
- init_cost();
5682
- init_version_detection();
5683
- init_manager();
5684
- });
5685
-
5686
- // src/interaction/bridge-builder.ts
5687
- function buildInteractionBridge(chain, context, timeoutMs = DEFAULT_INTERACTION_TIMEOUT_MS) {
5688
- const plugin = chain?.getPrimary();
5689
- if (!plugin)
5690
- return;
5691
- return {
5692
- detectQuestion: async (text) => QUESTION_PATTERNS.some((p) => p.test(text)),
5693
- onQuestionDetected: async (text) => {
5694
- const requestId = `ix-${context.stage}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
5695
- await plugin.send({
5696
- id: requestId,
5697
- type: "input",
5698
- featureName: context.featureName ?? "unknown",
5699
- storyId: context.storyId,
5700
- stage: context.stage,
5701
- summary: text,
5702
- fallback: "continue",
5703
- createdAt: Date.now()
5704
- });
5705
- try {
5706
- const response = await plugin.receive(requestId, timeoutMs);
5707
- return response.value ?? "continue";
5708
- } catch {
5709
- return "continue";
5710
- }
5711
- }
5712
- };
5713
- }
5714
- var QUESTION_PATTERNS, DEFAULT_INTERACTION_TIMEOUT_MS = 120000;
5715
- var init_bridge_builder = __esm(() => {
5716
- QUESTION_PATTERNS = [/\?\s*$/, /\bwhich\b/i, /\bshould i\b/i, /\bunclear\b/i, /\bplease clarify\b/i];
5717
- });
5718
-
5719
5710
  // src/agents/retry/types.ts
5720
5711
  var ParseValidationError;
5721
5712
  var init_types3 = __esm(() => {
@@ -5898,6 +5889,51 @@ var init_retry = __esm(() => {
5898
5889
  init_parse_retry();
5899
5890
  });
5900
5891
 
5892
+ // src/agents/index.ts
5893
+ var init_agents = __esm(() => {
5894
+ init_interaction_handler();
5895
+ init_types();
5896
+ init_acp();
5897
+ init_registry();
5898
+ init_cost();
5899
+ init_version_detection();
5900
+ init_manager();
5901
+ init_retry();
5902
+ });
5903
+
5904
+ // src/interaction/bridge-builder.ts
5905
+ function buildInteractionBridge(chain, context, timeoutMs = DEFAULT_INTERACTION_TIMEOUT_MS) {
5906
+ const plugin = chain?.getPrimary();
5907
+ if (!plugin)
5908
+ return;
5909
+ return {
5910
+ detectQuestion: async (text) => QUESTION_PATTERNS.some((p) => p.test(text)),
5911
+ onQuestionDetected: async (text) => {
5912
+ const requestId = `ix-${context.stage}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
5913
+ await plugin.send({
5914
+ id: requestId,
5915
+ type: "input",
5916
+ featureName: context.featureName ?? "unknown",
5917
+ storyId: context.storyId,
5918
+ stage: context.stage,
5919
+ summary: text,
5920
+ fallback: "continue",
5921
+ createdAt: Date.now()
5922
+ });
5923
+ try {
5924
+ const response = await plugin.receive(requestId, timeoutMs);
5925
+ return response.value ?? "continue";
5926
+ } catch {
5927
+ return "continue";
5928
+ }
5929
+ }
5930
+ };
5931
+ }
5932
+ var QUESTION_PATTERNS, DEFAULT_INTERACTION_TIMEOUT_MS = 120000;
5933
+ var init_bridge_builder = __esm(() => {
5934
+ QUESTION_PATTERNS = [/\?\s*$/, /\bwhich\b/i, /\bshould i\b/i, /\bunclear\b/i, /\bplease clarify\b/i];
5935
+ });
5936
+
5901
5937
  // src/config/schema-types.ts
5902
5938
  function isBuiltinModelTier(value) {
5903
5939
  return value === "fast" || value === "balanced" || value === "powerful";
@@ -20219,8 +20255,8 @@ var init_schemas_execution = __esm(() => {
20219
20255
  // src/config/schemas-infra.ts
20220
20256
  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;
20221
20257
  var init_schemas_infra = __esm(() => {
20258
+ init_config();
20222
20259
  init_zod();
20223
- init_schemas_model();
20224
20260
  PlanConfigSchema = exports_external.object({
20225
20261
  model: ConfiguredModelSchema,
20226
20262
  outputPath: exports_external.string().min(1, "plan.outputPath must be non-empty"),
@@ -20323,7 +20359,8 @@ var init_schemas_infra = __esm(() => {
20323
20359
  enabled: true,
20324
20360
  mode: "warn-then-cancel",
20325
20361
  idleTimeoutSeconds: 900,
20326
- activityKinds: ["message_update", "thinking_update", "usage_update"],
20362
+ toolCallOnlyIdleTimeoutSeconds: 1800,
20363
+ activityKinds: ["message_update", "thinking_update", "usage_update", "tool_call_update"],
20327
20364
  cancelGraceSeconds: 10,
20328
20365
  maxRetryAttempts: 3
20329
20366
  };
@@ -20331,7 +20368,8 @@ var init_schemas_infra = __esm(() => {
20331
20368
  enabled: exports_external.boolean().default(true),
20332
20369
  mode: exports_external.enum(["off", "observe", "warn-then-cancel", "cancel"]).default("warn-then-cancel"),
20333
20370
  idleTimeoutSeconds: exports_external.number().nonnegative().default(900),
20334
- activityKinds: exports_external.array(exports_external.enum(["message_update", "thinking_update", "usage_update"])).default(["message_update", "thinking_update", "usage_update"]),
20371
+ toolCallOnlyIdleTimeoutSeconds: exports_external.number().nonnegative().default(1800),
20372
+ activityKinds: exports_external.array(exports_external.enum(["message_update", "thinking_update", "usage_update", "tool_call_update"])).default(["message_update", "thinking_update", "usage_update", "tool_call_update"]),
20335
20373
  cancelGraceSeconds: exports_external.number().nonnegative().default(10),
20336
20374
  maxRetryAttempts: exports_external.number().int().nonnegative().default(3)
20337
20375
  }).refine((config2) => config2.mode === "off" || config2.idleTimeoutSeconds > 0, {
@@ -21610,6 +21648,7 @@ function createConfigLoader(config2) {
21610
21648
  // src/config/index.ts
21611
21649
  var init_config = __esm(() => {
21612
21650
  init_schema();
21651
+ init_schemas_model();
21613
21652
  init_loader();
21614
21653
  init_path_security();
21615
21654
  init_paths();
@@ -24160,7 +24199,7 @@ async function hasCommitsForStory(workdir, storyId, maxCommits = 20) {
24160
24199
  }
24161
24200
  }
24162
24201
  function detectMergeConflict(output) {
24163
- return output.includes("CONFLICT") || output.includes("conflict");
24202
+ return output.includes("<<<<<<<") || output.includes(">>>>>>>") || /\bCONFLICT\s*\(/.test(output) || output.includes("Merge conflict in");
24164
24203
  }
24165
24204
  async function autoCommitIfDirty(workdir, stage, role, storyId) {
24166
24205
  const logger = _gitDeps.getSafeLogger();
@@ -28249,6 +28288,7 @@ var init_context = __esm(() => {
28249
28288
  init_feature_context_filter();
28250
28289
  init_feature_context();
28251
28290
  init_builder();
28291
+ init_engine();
28252
28292
  init_test_scanner();
28253
28293
  init_auto_detect();
28254
28294
  });
@@ -29873,7 +29913,10 @@ Worked example:
29873
29913
 
29874
29914
  **Convention / coding-standard violations almost always belong as \`"info"\`** unless an AC specifically names the convention or the symbol it concerns.
29875
29915
 
29876
- If you cannot find an AC that names the **specific symbol** in your finding, downgrade to \`"info"\`. A finding dropped by the validator is worse than one correctly classified as advisory.`;
29916
+ **Scope constraints are not Acceptance Criteria:**
29917
+ The story description may contain a "Scope" section with "In:" and "Out:" bullets. These are implementation guidelines, not ACs. A finding about code changed outside the stated scope (e.g., a file listed under "Out:") cannot cite a scope constraint as its \`acQuote\`/\`acIndex\` because scope text is not in the numbered AC list. Emit scope-violation findings as \`"warning"\` \u2014 never \`"error"\`. Never use \`acIndex: 0\`; \`acIndex\` is 1-based (first AC bullet = 1).
29918
+
29919
+ If you cannot find an AC that names the **specific symbol** in your finding, downgrade to \`"info"\` or \`"warning"\`. A finding dropped by the validator is worse than one correctly classified as advisory.`;
29877
29920
  var init_adversarial_review_builder = () => {};
29878
29921
 
29879
29922
  // src/prompts/builders/acceptance-builder-helpers.ts
@@ -31352,12 +31395,12 @@ function buildHopCallback(ctx, sessionId, _initialOptions) {
31352
31395
  hopBodyInput
31353
31396
  } = ctx;
31354
31397
  const stage = pipelineStage ?? "run";
31355
- return async (agentName, hopBundle, failure, resolvedRunOptions) => {
31398
+ return async (agentName, hopBundle, hopKind, resolvedRunOptions) => {
31356
31399
  const logger = getLogger();
31357
31400
  let workingBundle = hopBundle;
31358
31401
  let prompt = resolvedRunOptions.prompt;
31359
- if (failure && hopBundle) {
31360
- workingBundle = _buildHopCallbackDeps.rebuildForAgent(hopBundle, agentName, failure, story.id);
31402
+ if (hopKind.kind === "swap" && hopBundle) {
31403
+ workingBundle = _buildHopCallbackDeps.rebuildForAgent(hopBundle, agentName, hopKind.failure, story.id);
31361
31404
  if (projectDir && featureName && workingBundle.manifest.rebuildInfo) {
31362
31405
  try {
31363
31406
  await _buildHopCallbackDeps.writeRebuildManifest(projectDir, featureName, story.id, {
@@ -31381,8 +31424,8 @@ function buildHopCallback(ctx, sessionId, _initialOptions) {
31381
31424
  }
31382
31425
  prompt = RectifierPromptBuilder.swapHandoff(resolvedRunOptions.prompt, workingBundle.pushMarkdown);
31383
31426
  }
31384
- if (failure && sessionId) {
31385
- sessionManager.handoff?.(sessionId, agentName, failure.outcome);
31427
+ if (hopKind.kind === "swap" && sessionId) {
31428
+ sessionManager.handoff?.(sessionId, agentName, hopKind.failure.outcome);
31386
31429
  }
31387
31430
  const contextToolRuntime = workingBundle ? _buildHopCallbackDeps.createContextToolRuntime({
31388
31431
  bundle: workingBundle,
@@ -31399,19 +31442,44 @@ function buildHopCallback(ctx, sessionId, _initialOptions) {
31399
31442
  role: resolvedRunOptions.sessionRole ?? "implementer",
31400
31443
  pipelineStage: stage
31401
31444
  });
31402
- const modelDef = failure === undefined ? resolvedRunOptions.modelDef ?? resolveModelForAgent(config2.models, agentName, effectiveTier, defaultAgent) : resolveModelForAgent(config2.models, agentName, effectiveTier, defaultAgent);
31403
- const timeoutSeconds = resolvedRunOptions.timeoutSeconds ?? config2.execution.sessionTimeoutSeconds;
31404
- const handle = await sessionManager.openSession(sessionName, {
31405
- agentName,
31406
- role: resolvedRunOptions.sessionRole ?? "implementer",
31407
- workdir,
31408
- pipelineStage: stage,
31409
- modelDef,
31410
- timeoutSeconds,
31411
- featureName,
31412
- storyId: story.id,
31413
- signal: resolvedRunOptions.abortSignal
31414
- });
31445
+ let handle;
31446
+ if (hopKind.kind === "stale-retry") {
31447
+ const cached2 = sessionManager.getLiveHandle(sessionName);
31448
+ if (cached2 && cached2.agentName === agentName) {
31449
+ handle = cached2;
31450
+ } else {
31451
+ logger.warn("execution", "Stale-retry: live handle missing, re-opening session", {
31452
+ storyId: story.id,
31453
+ sessionName,
31454
+ attempt: hopKind.attempt
31455
+ });
31456
+ const modelDef = resolvedRunOptions.modelDef ?? resolveModelForAgent(config2.models, agentName, effectiveTier, defaultAgent);
31457
+ handle = await sessionManager.openSession(sessionName, {
31458
+ agentName,
31459
+ role: resolvedRunOptions.sessionRole ?? "implementer",
31460
+ workdir,
31461
+ pipelineStage: stage,
31462
+ modelDef,
31463
+ timeoutSeconds: resolvedRunOptions.timeoutSeconds ?? config2.execution.sessionTimeoutSeconds,
31464
+ featureName,
31465
+ storyId: story.id,
31466
+ signal: resolvedRunOptions.abortSignal
31467
+ });
31468
+ }
31469
+ } else {
31470
+ const modelDef = hopKind.kind === "primary" ? resolvedRunOptions.modelDef ?? resolveModelForAgent(config2.models, agentName, effectiveTier, defaultAgent) : resolveModelForAgent(config2.models, agentName, effectiveTier, defaultAgent);
31471
+ handle = await sessionManager.openSession(sessionName, {
31472
+ agentName,
31473
+ role: resolvedRunOptions.sessionRole ?? "implementer",
31474
+ workdir,
31475
+ pipelineStage: stage,
31476
+ modelDef,
31477
+ timeoutSeconds: resolvedRunOptions.timeoutSeconds ?? config2.execution.sessionTimeoutSeconds,
31478
+ featureName,
31479
+ storyId: story.id,
31480
+ signal: resolvedRunOptions.abortSignal
31481
+ });
31482
+ }
31415
31483
  try {
31416
31484
  const send = (turnPrompt) => agentManager.runAsSession(agentName, handle, turnPrompt, {
31417
31485
  storyId: story.id,
@@ -31447,7 +31515,9 @@ function buildHopCallback(ctx, sessionId, _initialOptions) {
31447
31515
  prompt
31448
31516
  };
31449
31517
  } finally {
31450
- await sessionManager.closeSession(handle);
31518
+ if (hopKind.kind !== "stale-retry") {
31519
+ await sessionManager.closeSession(handle);
31520
+ }
31451
31521
  }
31452
31522
  };
31453
31523
  }
@@ -39524,224 +39594,783 @@ var init_agent_stream_events = __esm(() => {
39524
39594
  init_logger2();
39525
39595
  });
39526
39596
 
39527
- // src/agents/factory.ts
39528
- function createAgentManager(config2, opts) {
39529
- return new AgentManager(config2, undefined, opts);
39597
+ // src/runtime/middleware/cancellation.ts
39598
+ function cancellationMiddleware() {
39599
+ return {
39600
+ name: "cancellation",
39601
+ async before(ctx) {
39602
+ if (ctx.signal?.aborted) {
39603
+ throw new NaxError("Agent call cancelled before start", "AGENT_CANCELLED", {
39604
+ stage: ctx.stage ?? "run",
39605
+ agentName: ctx.agentName
39606
+ });
39607
+ }
39608
+ }
39609
+ };
39530
39610
  }
39531
- var init_factory = __esm(() => {
39532
- init_manager();
39611
+ var init_cancellation = __esm(() => {
39612
+ init_errors();
39533
39613
  });
39534
39614
 
39535
- // src/execution/pid-registry.ts
39536
- import { existsSync as existsSync9 } from "fs";
39537
- import { appendFile as appendFile2 } from "fs/promises";
39615
+ // src/runtime/middleware/logging.ts
39616
+ function attachLoggingSubscriber(bus, runId) {
39617
+ const offDispatch = bus.onDispatch((event) => {
39618
+ getSafeLogger()?.info("middleware", "Agent call complete", {
39619
+ storyId: event.storyId,
39620
+ runId,
39621
+ agentName: event.agentName,
39622
+ kind: event.kind,
39623
+ stage: event.stage,
39624
+ durationMs: event.durationMs
39625
+ });
39626
+ });
39627
+ const offError = bus.onDispatchError((event) => {
39628
+ getSafeLogger()?.warn("middleware", "Agent call failed", {
39629
+ storyId: event.storyId,
39630
+ runId,
39631
+ agentName: event.agentName,
39632
+ stage: event.stage,
39633
+ durationMs: event.durationMs,
39634
+ error: event.errorMessage
39635
+ });
39636
+ });
39637
+ return () => {
39638
+ offDispatch();
39639
+ offError();
39640
+ };
39641
+ }
39642
+ var init_logging2 = __esm(() => {
39643
+ init_logger2();
39644
+ });
39538
39645
 
39539
- class PidRegistry {
39540
- workdir;
39541
- pidsFilePath;
39542
- pids = new Set;
39543
- frozen = false;
39544
- constructor(workdir, _platform) {
39545
- this.workdir = workdir;
39546
- this.pidsFilePath = `${workdir}/${PID_REGISTRY_FILE}`;
39547
- }
39548
- freeze() {
39549
- if (this.frozen)
39550
- return;
39551
- this.frozen = true;
39552
- getSafeLogger()?.debug("pid-registry", "Registry frozen \u2014 new registrations blocked");
39553
- }
39554
- isFrozen() {
39555
- return this.frozen;
39556
- }
39557
- async register(pid) {
39558
- const logger = getSafeLogger();
39559
- if (this.frozen) {
39560
- logger?.warn("pid-registry", `Registration blocked (registry frozen) PID ${pid}`, { pid });
39561
- return;
39562
- }
39563
- this.pids.add(pid);
39564
- const entry = {
39565
- pid,
39566
- spawnedAt: new Date().toISOString(),
39567
- workdir: this.workdir
39568
- };
39569
- try {
39570
- const line = `${JSON.stringify(entry)}
39571
- `;
39572
- await appendFile2(this.pidsFilePath, line);
39573
- logger?.debug("pid-registry", `Registered PID ${pid}`, { pid });
39574
- } catch (err) {
39575
- logger?.warn("pid-registry", `Failed to write PID ${pid} to registry`, {
39576
- error: err.message
39577
- });
39578
- }
39579
- }
39580
- async unregister(pid) {
39581
- const logger = getSafeLogger();
39582
- this.pids.delete(pid);
39583
- try {
39584
- await this.writePidsFile();
39585
- logger?.debug("pid-registry", `Unregistered PID ${pid}`, { pid });
39586
- } catch (err) {
39587
- logger?.warn("pid-registry", `Failed to unregister PID ${pid}`, {
39588
- error: err.message
39589
- });
39590
- }
39591
- }
39592
- async killAll() {
39593
- const logger = getSafeLogger();
39594
- const pids = Array.from(this.pids);
39595
- if (pids.length === 0) {
39596
- logger?.debug("pid-registry", "No PIDs to kill");
39597
- return;
39598
- }
39599
- logger?.info("pid-registry", `Killing ${pids.length} registered processes`, { pids });
39600
- const killPromises = pids.map((pid) => this.killPid(pid));
39601
- await Promise.allSettled(killPromises);
39602
- try {
39603
- await Bun.write(this.pidsFilePath, "");
39604
- this.pids.clear();
39605
- logger?.info("pid-registry", "All registered PIDs killed and registry cleared");
39606
- } catch (err) {
39607
- logger?.warn("pid-registry", "Failed to clear registry file", {
39608
- error: err.message
39609
- });
39610
- }
39611
- }
39612
- async cleanupStale() {
39613
- const logger = getSafeLogger();
39614
- if (!existsSync9(this.pidsFilePath)) {
39615
- logger?.debug("pid-registry", "No stale PIDs file found");
39616
- return;
39617
- }
39618
- try {
39619
- const content = await Bun.file(this.pidsFilePath).text();
39620
- const lines = content.split(`
39621
- `).filter((line) => line.trim()).map((line) => {
39622
- try {
39623
- return JSON.parse(line);
39624
- } catch {
39625
- return null;
39646
+ // src/runtime/middleware/agent-stream-logging.ts
39647
+ function attachAgentStreamLogging(bus, runId) {
39648
+ const activeCalls = new Map;
39649
+ return bus.onAgentStream((event) => {
39650
+ switch (event.kind) {
39651
+ case "agent.call_started": {
39652
+ const now = event.timestamp;
39653
+ activeCalls.set(event.callId, {
39654
+ callId: event.callId,
39655
+ agentName: event.agentName,
39656
+ storyId: event.storyId,
39657
+ stage: event.stage,
39658
+ startedAt: now,
39659
+ lastActivityAt: now,
39660
+ messageUpdates: 0,
39661
+ thinkingUpdates: 0,
39662
+ usageUpdates: 0,
39663
+ toolCallUpdates: 0
39664
+ });
39665
+ getSafeLogger()?.info("agent-stream", "Agent call started", {
39666
+ storyId: event.storyId,
39667
+ runId,
39668
+ callId: event.callId,
39669
+ agentName: event.agentName,
39670
+ stage: event.stage,
39671
+ model: event.model,
39672
+ timeoutSeconds: event.timeoutSeconds
39673
+ });
39674
+ break;
39675
+ }
39676
+ case "agent.message_update": {
39677
+ const state = activeCalls.get(event.callId);
39678
+ if (state) {
39679
+ state.messageUpdates++;
39680
+ state.lastActivityAt = event.timestamp;
39626
39681
  }
39627
- }).filter((entry) => entry !== null);
39628
- if (lines.length === 0) {
39629
- logger?.debug("pid-registry", "No stale PIDs to cleanup");
39630
- await Bun.write(this.pidsFilePath, "");
39631
- return;
39682
+ break;
39632
39683
  }
39633
- const stalePids = lines.map((entry) => entry.pid);
39634
- logger?.info("pid-registry", `Found ${stalePids.length} stale PID entries from previous run; clearing file without signaling (PIDs likely recycled)`, { pids: stalePids });
39635
- await Bun.write(this.pidsFilePath, "");
39636
- logger?.info("pid-registry", "Stale PIDs file cleared");
39637
- } catch (err) {
39638
- logger?.warn("pid-registry", "Failed to cleanup stale PIDs", {
39639
- error: err.message
39640
- });
39641
- }
39642
- }
39643
- async killPid(pid) {
39644
- const logger = getSafeLogger();
39645
- if (!Number.isInteger(pid) || pid <= 1) {
39646
- logger?.warn("pid-registry", `Refusing to signal non-positive or reserved PID ${pid}`, { pid });
39647
- return;
39648
- }
39649
- try {
39650
- const checkProc = Bun.spawn(["kill", "-0", String(pid)], {
39651
- stdout: "pipe",
39652
- stderr: "pipe"
39653
- });
39654
- const checkCode = await checkProc.exited;
39655
- if (checkCode !== 0) {
39656
- logger?.debug("pid-registry", `PID ${pid} not found (already exited)`, { pid });
39657
- return;
39684
+ case "agent.thinking_update": {
39685
+ const state = activeCalls.get(event.callId);
39686
+ if (state) {
39687
+ state.thinkingUpdates++;
39688
+ state.lastActivityAt = event.timestamp;
39689
+ }
39690
+ break;
39658
39691
  }
39659
- const killProc = Bun.spawn(["kill", "-TERM", String(pid)], {
39660
- stdout: "pipe",
39661
- stderr: "pipe"
39662
- });
39663
- const killCode = await killProc.exited;
39664
- if (killCode === 0) {
39665
- logger?.debug("pid-registry", `Killed PID ${pid}`, { pid });
39666
- } else {
39667
- const stderr = await new Response(killProc.stderr).text();
39668
- logger?.warn("pid-registry", `Failed to kill PID ${pid}`, {
39669
- pid,
39670
- exitCode: killCode,
39671
- stderr: stderr.trim()
39672
- });
39692
+ case "agent.usage_update": {
39693
+ const state = activeCalls.get(event.callId);
39694
+ if (state) {
39695
+ state.usageUpdates++;
39696
+ state.lastActivityAt = event.timestamp;
39697
+ }
39698
+ break;
39699
+ }
39700
+ case "agent.tool_call_update": {
39701
+ const state = activeCalls.get(event.callId);
39702
+ if (state) {
39703
+ state.toolCallUpdates++;
39704
+ state.lastActivityAt = event.timestamp;
39705
+ }
39706
+ break;
39707
+ }
39708
+ case "agent.process_update":
39709
+ break;
39710
+ case "agent.call_ended": {
39711
+ const state = activeCalls.get(event.callId);
39712
+ if (state) {
39713
+ const idleMs = event.timestamp - state.lastActivityAt;
39714
+ getSafeLogger()?.info("agent-stream", "Agent call ended", {
39715
+ storyId: state.storyId,
39716
+ runId,
39717
+ callId: state.callId,
39718
+ agentName: state.agentName,
39719
+ stage: state.stage,
39720
+ messageUpdates: state.messageUpdates,
39721
+ thinkingUpdates: state.thinkingUpdates,
39722
+ usageUpdates: state.usageUpdates,
39723
+ toolCallUpdates: state.toolCallUpdates,
39724
+ lastActivityAt: state.lastActivityAt,
39725
+ idleMs,
39726
+ status: event.status
39727
+ });
39728
+ activeCalls.delete(event.callId);
39729
+ }
39730
+ break;
39673
39731
  }
39674
- } catch (err) {
39675
- logger?.warn("pid-registry", `Error killing PID ${pid}`, {
39676
- pid,
39677
- error: err.message
39678
- });
39679
39732
  }
39680
- }
39681
- async writePidsFile() {
39682
- const entries = Array.from(this.pids).map((pid) => ({
39683
- pid,
39684
- spawnedAt: new Date().toISOString(),
39685
- workdir: this.workdir
39686
- }));
39687
- const content = entries.map((entry) => JSON.stringify(entry)).join(`
39688
- `);
39689
- await Bun.write(this.pidsFilePath, content ? `${content}
39690
- ` : "");
39691
- }
39692
- getPids() {
39693
- return Array.from(this.pids);
39694
- }
39733
+ });
39695
39734
  }
39696
- var PID_REGISTRY_FILE = ".nax-pids";
39697
- var init_pid_registry = __esm(() => {
39735
+ var init_agent_stream_logging = __esm(() => {
39698
39736
  init_logger2();
39699
39737
  });
39700
39738
 
39701
- // src/session/manager-deps.ts
39702
- import { randomUUID as randomUUID3 } from "crypto";
39703
- import { mkdir as mkdir5 } from "fs/promises";
39704
- import { isAbsolute as isAbsolute9, join as join27, relative as relative10, sep } from "path";
39705
- function resolveProjectDirFromScratchDir(scratchDir) {
39706
- const marker = `${sep}.nax${sep}features${sep}`;
39707
- const markerIdx = scratchDir.lastIndexOf(marker);
39708
- if (markerIdx > 0)
39709
- return scratchDir.slice(0, markerIdx);
39710
- const posixIdx = scratchDir.lastIndexOf("/.nax/features/");
39711
- if (posixIdx > 0)
39712
- return scratchDir.slice(0, posixIdx);
39713
- return;
39714
- }
39715
- function toProjectRelativePath(projectDir, pathValue) {
39716
- const relativePath = isAbsolute9(pathValue) ? relative10(projectDir, pathValue) : pathValue;
39717
- return relativePath === "" ? "." : relativePath;
39739
+ // src/runtime/middleware/cost.ts
39740
+ function attachCostSubscriber(bus, aggregator, runId) {
39741
+ const offDispatch = bus.onDispatch((event) => {
39742
+ const tu = event.tokenUsage;
39743
+ const exactCostUsd = event.exactCostUsd;
39744
+ const estimatedCostUsd = event.estimatedCostUsd ?? exactCostUsd ?? 0;
39745
+ if (!tu && exactCostUsd == null && estimatedCostUsd === 0)
39746
+ return;
39747
+ const costUsd = exactCostUsd ?? estimatedCostUsd;
39748
+ const confidence = exactCostUsd != null ? "exact" : "estimated";
39749
+ const costEvent = {
39750
+ ts: event.timestamp,
39751
+ runId,
39752
+ agentName: event.agentName,
39753
+ model: "unknown",
39754
+ stage: event.stage,
39755
+ storyId: event.storyId,
39756
+ tokens: tu ? {
39757
+ input: tu.inputTokens ?? 0,
39758
+ output: tu.outputTokens ?? 0,
39759
+ cacheRead: tu.cacheReadInputTokens,
39760
+ cacheWrite: tu.cacheCreationInputTokens
39761
+ } : { input: 0, output: 0 },
39762
+ estimatedCostUsd,
39763
+ exactCostUsd,
39764
+ costUsd,
39765
+ confidence,
39766
+ durationMs: event.durationMs
39767
+ };
39768
+ aggregator.record(costEvent);
39769
+ });
39770
+ const offError = bus.onDispatchError((event) => {
39771
+ const errorEvent = {
39772
+ ts: event.timestamp,
39773
+ runId,
39774
+ agentName: event.agentName,
39775
+ stage: event.stage,
39776
+ storyId: event.storyId,
39777
+ errorCode: event.errorCode,
39778
+ durationMs: event.durationMs
39779
+ };
39780
+ aggregator.recordError(errorEvent);
39781
+ });
39782
+ const offCompleted = bus.onOperationCompleted((event) => {
39783
+ const summary = {
39784
+ runId,
39785
+ operation: event.operation,
39786
+ hopCount: event.hopCount,
39787
+ fallbackTriggered: event.fallbackTriggered,
39788
+ totalCostUsd: event.totalCostUsd,
39789
+ totalElapsedMs: event.totalElapsedMs,
39790
+ finalStatus: event.finalStatus
39791
+ };
39792
+ aggregator.recordOperationSummary(summary);
39793
+ });
39794
+ return () => {
39795
+ offDispatch();
39796
+ offError();
39797
+ offCompleted();
39798
+ };
39718
39799
  }
39719
- var _sessionManagerDeps;
39720
- var init_manager_deps = __esm(() => {
39721
- _sessionManagerDeps = {
39722
- now: () => new Date().toISOString(),
39723
- nowMs: () => Date.now(),
39724
- uuid: () => randomUUID3(),
39725
- sessionScratchDir: (projectDir, featureName, sessionId) => join27(projectDir, ".nax", "features", featureName, "sessions", sessionId),
39726
- writeDescriptor: async (scratchDir, descriptor, projectDir) => {
39727
- await mkdir5(scratchDir, { recursive: true });
39728
- const { handle: _handle, ...persistable } = descriptor;
39729
- const derivedProjectDir = projectDir ?? resolveProjectDirFromScratchDir(scratchDir);
39730
- if (derivedProjectDir) {
39731
- persistable.workdir = toProjectRelativePath(derivedProjectDir, persistable.workdir);
39732
- if (persistable.scratchDir) {
39733
- persistable.scratchDir = toProjectRelativePath(derivedProjectDir, persistable.scratchDir);
39734
- }
39800
+
39801
+ // src/runtime/middleware/audit.ts
39802
+ function attachAuditSubscriber(bus, auditor, runId) {
39803
+ const offDispatch = bus.onDispatch((event) => {
39804
+ const entry = {
39805
+ ts: event.timestamp,
39806
+ runId,
39807
+ agentName: event.agentName,
39808
+ stage: event.stage,
39809
+ storyId: event.storyId,
39810
+ permissionProfile: event.resolvedPermissions.mode,
39811
+ prompt: event.prompt,
39812
+ response: event.response,
39813
+ durationMs: event.durationMs,
39814
+ callType: event.kind === "session-turn" ? "run" : "complete",
39815
+ workdir: event.workdir,
39816
+ projectDir: event.projectDir,
39817
+ featureName: event.featureName,
39818
+ sessionName: event.sessionName,
39819
+ ...event.kind === "session-turn" && {
39820
+ sessionId: event.protocolIds.sessionId ?? null,
39821
+ recordId: event.protocolIds.recordId ?? null,
39822
+ turn: event.turn
39735
39823
  }
39736
- await Bun.write(join27(scratchDir, "descriptor.json"), JSON.stringify(persistable, null, 2));
39737
- }
39824
+ };
39825
+ auditor.record(entry);
39826
+ });
39827
+ const offError = bus.onDispatchError((event) => {
39828
+ const entry = {
39829
+ ts: event.timestamp,
39830
+ runId,
39831
+ agentName: event.agentName,
39832
+ stage: event.stage,
39833
+ storyId: event.storyId,
39834
+ errorCode: event.errorCode,
39835
+ errorMessage: event.errorMessage,
39836
+ durationMs: event.durationMs,
39837
+ callType: event.origin === "completeAs" ? "complete" : "run",
39838
+ permissionProfile: event.resolvedPermissions.mode,
39839
+ prompt: event.prompt
39840
+ };
39841
+ auditor.recordError(entry);
39842
+ });
39843
+ return () => {
39844
+ offDispatch();
39845
+ offError();
39738
39846
  };
39739
- });
39847
+ }
39740
39848
 
39741
- // src/session/manager-run.ts
39742
- async function runTrackedSession(state, id, runner, request) {
39743
- const startedAt = Date.now();
39744
- const pre = state.sessions.get(id);
39849
+ // src/runtime/middleware/review-audit.ts
39850
+ function reviewerFromRole(role) {
39851
+ if (role === "reviewer-semantic")
39852
+ return "semantic";
39853
+ if (role === "reviewer-adversarial")
39854
+ return "adversarial";
39855
+ return null;
39856
+ }
39857
+ function attachReviewAuditSubscriber(bus, auditor, runId) {
39858
+ const offDispatch = bus.onDispatch((event) => {
39859
+ if (event.kind !== "session-turn")
39860
+ return;
39861
+ const reviewer = reviewerFromRole(event.sessionRole);
39862
+ if (!reviewer)
39863
+ return;
39864
+ auditor.recordDispatch({
39865
+ runId,
39866
+ reviewer,
39867
+ sessionName: event.sessionName,
39868
+ sessionId: event.protocolIds.sessionId ?? null,
39869
+ recordId: event.protocolIds.recordId ?? null,
39870
+ workdir: event.workdir,
39871
+ projectDir: event.projectDir,
39872
+ agentName: event.agentName,
39873
+ storyId: event.storyId,
39874
+ featureName: event.featureName
39875
+ });
39876
+ });
39877
+ const offDecision = bus.onReviewDecision((event) => {
39878
+ auditor.recordDecision({
39879
+ runId: event.runId,
39880
+ reviewer: event.reviewer,
39881
+ sessionName: event.sessionName,
39882
+ sessionId: event.sessionId,
39883
+ recordId: event.recordId,
39884
+ workdir: event.workdir,
39885
+ projectDir: event.projectDir,
39886
+ outputDir: event.outputDir,
39887
+ agentName: event.agentName,
39888
+ storyId: event.storyId,
39889
+ featureName: event.featureName,
39890
+ parsed: event.parsed,
39891
+ looksLikeFail: event.looksLikeFail,
39892
+ failOpen: event.failOpen,
39893
+ passed: event.passed,
39894
+ blockingThreshold: event.blockingThreshold,
39895
+ result: event.result,
39896
+ advisoryFindings: event.advisoryFindings
39897
+ });
39898
+ });
39899
+ return () => {
39900
+ offDispatch();
39901
+ offDecision();
39902
+ };
39903
+ }
39904
+
39905
+ // src/runtime/middleware/idle-watchdog.ts
39906
+ function scheduleTickIfNeeded(tickRef, tick, intervalMs) {
39907
+ if (tickRef.handle !== null)
39908
+ return;
39909
+ tickRef.handle = setTimeout(tick, intervalMs);
39910
+ }
39911
+ function handleObserveTimeout(state, reason, idleDurationMs, nonToolCallIdleMs) {
39912
+ if (state.warnedForCurrentIdlePeriod)
39913
+ return;
39914
+ state.warnedForCurrentIdlePeriod = true;
39915
+ getSafeLogger()?.warn("idle-watchdog", reason === "tool_call_only_idle_timeout_exceeded" ? "Tool-call-only idle timeout exceeded" : "Idle timeout exceeded", {
39916
+ storyId: state.storyId,
39917
+ key: reason,
39918
+ callId: state.callId,
39919
+ mode: "observe",
39920
+ idleDurationMs,
39921
+ nonToolCallIdleMs,
39922
+ toolCallUpdates: state.toolCallUpdates
39923
+ });
39924
+ }
39925
+ async function handleCancelTimeout(state, reason, controllerRegistry, maxRetryAttempts, activeStates) {
39926
+ if (state.cancelAttempts >= maxRetryAttempts) {
39927
+ getSafeLogger()?.error("idle-watchdog", "Max retry attempts exceeded", {
39928
+ storyId: state.storyId,
39929
+ key: "max_retry_attempts_exceeded",
39930
+ callId: state.callId,
39931
+ cancelAttempts: state.cancelAttempts
39932
+ });
39933
+ activeStates.delete(state.callId);
39934
+ return;
39935
+ }
39936
+ state.cancelAttempts++;
39937
+ state.lastActivityAt = Date.now();
39938
+ getSafeLogger()?.warn("idle-watchdog", reason === "tool_call_only_idle_timeout_exceeded" ? "Canceling tool-call-only idle call" : "Canceling idle call", {
39939
+ storyId: state.storyId,
39940
+ key: reason,
39941
+ callId: state.callId,
39942
+ mode: "cancel",
39943
+ action: "cancel",
39944
+ toolCallUpdates: state.toolCallUpdates
39945
+ });
39946
+ const cancel = controllerRegistry.get(state.callId);
39947
+ if (cancel)
39948
+ await cancel().catch(() => {});
39949
+ }
39950
+ function handleWarnThenCancelTimeout(state, reason, controllerRegistry, maxRetryAttempts, idleTimeoutMs, toolCallOnlyTimeoutMs, graceMs, activeStates) {
39951
+ if (state.cancelAttempts >= maxRetryAttempts) {
39952
+ getSafeLogger()?.error("idle-watchdog", "Max retry attempts exceeded", {
39953
+ storyId: state.storyId,
39954
+ key: "max_retry_attempts_exceeded",
39955
+ callId: state.callId,
39956
+ cancelAttempts: state.cancelAttempts
39957
+ });
39958
+ activeStates.delete(state.callId);
39959
+ return;
39960
+ }
39961
+ getSafeLogger()?.warn("idle-watchdog", reason === "tool_call_only_idle_timeout_exceeded" ? "Tool-call-only idle timeout exceeded, entering grace period" : "Idle timeout exceeded, entering grace period", {
39962
+ storyId: state.storyId,
39963
+ key: reason,
39964
+ callId: state.callId,
39965
+ mode: "warn-then-cancel",
39966
+ gracePeriodMs: graceMs,
39967
+ toolCallUpdates: state.toolCallUpdates
39968
+ });
39969
+ state.inGracePeriod = true;
39970
+ state.graceReason = reason;
39971
+ state.graceTimer = setTimeout(async () => {
39972
+ if (!activeStates.has(state.callId))
39973
+ return;
39974
+ state.inGracePeriod = false;
39975
+ state.graceTimer = undefined;
39976
+ state.graceReason = undefined;
39977
+ const currentReason = getTimeoutReason(state, Date.now(), idleTimeoutMs, toolCallOnlyTimeoutMs);
39978
+ if (currentReason !== reason)
39979
+ return;
39980
+ state.cancelAttempts++;
39981
+ state.lastActivityAt = Date.now();
39982
+ const cancel = controllerRegistry.get(state.callId);
39983
+ if (cancel)
39984
+ await cancel().catch(() => {});
39985
+ }, graceMs);
39986
+ }
39987
+ function clearGrace(state) {
39988
+ if (state.inGracePeriod && state.graceTimer !== undefined) {
39989
+ clearTimeout(state.graceTimer);
39990
+ state.graceTimer = undefined;
39991
+ state.inGracePeriod = false;
39992
+ state.graceReason = undefined;
39993
+ }
39994
+ }
39995
+ function resetActivity(state, newTimestamp, options) {
39996
+ state.lastActivityAt = newTimestamp;
39997
+ state.warnedForCurrentIdlePeriod = false;
39998
+ if (options.clearGrace)
39999
+ clearGrace(state);
40000
+ }
40001
+ function getTimeoutReason(state, now, idleTimeoutMs, toolCallOnlyTimeoutMs) {
40002
+ if (now - state.lastActivityAt >= idleTimeoutMs)
40003
+ return "idle_timeout_exceeded";
40004
+ if (toolCallOnlyTimeoutMs > idleTimeoutMs && now - state.lastNonToolCallActivityAt >= toolCallOnlyTimeoutMs) {
40005
+ return "tool_call_only_idle_timeout_exceeded";
40006
+ }
40007
+ return;
40008
+ }
40009
+ function attachAgentIdleWatchdog(agentStreamEvents, controllerRegistry, config2) {
40010
+ const watchdogConfig = config2.agent?.idleWatchdog;
40011
+ if (!watchdogConfig?.enabled || watchdogConfig.mode === "off" || watchdogConfig.mode === undefined) {
40012
+ return agentStreamEvents.onAgentStream(() => {});
40013
+ }
40014
+ const mode = watchdogConfig.mode;
40015
+ const idleTimeoutMs = (watchdogConfig.idleTimeoutSeconds ?? 30) * 1000;
40016
+ const toolCallOnlyTimeoutMs = (watchdogConfig.toolCallOnlyIdleTimeoutSeconds ?? 0) * 1000;
40017
+ const graceMs = (watchdogConfig.cancelGraceSeconds ?? 5) * 1000;
40018
+ const maxRetryAttempts = watchdogConfig.maxRetryAttempts ?? 3;
40019
+ const activityKinds = new Set(watchdogConfig.activityKinds ?? ["message_update", "thinking_update", "usage_update", "tool_call_update"]);
40020
+ const tickIntervalMs = Math.max(1, Math.ceil(idleTimeoutMs / 4));
40021
+ const activeStates = new Map;
40022
+ const tickRef = { handle: null };
40023
+ function tick() {
40024
+ tickRef.handle = null;
40025
+ const now = Date.now();
40026
+ for (const [, state] of activeStates) {
40027
+ if (state.inGracePeriod)
40028
+ continue;
40029
+ const idleDurationMs = now - state.lastActivityAt;
40030
+ const nonToolCallIdleMs = now - state.lastNonToolCallActivityAt;
40031
+ const reason = getTimeoutReason(state, now, idleTimeoutMs, toolCallOnlyTimeoutMs);
40032
+ if (!reason)
40033
+ continue;
40034
+ if (mode === "observe")
40035
+ handleObserveTimeout(state, reason, idleDurationMs, nonToolCallIdleMs);
40036
+ else if (mode === "cancel") {
40037
+ handleCancelTimeout(state, reason, controllerRegistry, maxRetryAttempts, activeStates);
40038
+ } else if (mode === "warn-then-cancel") {
40039
+ handleWarnThenCancelTimeout(state, reason, controllerRegistry, maxRetryAttempts, idleTimeoutMs, toolCallOnlyTimeoutMs, graceMs, activeStates);
40040
+ }
40041
+ }
40042
+ if (activeStates.size > 0)
40043
+ scheduleTickIfNeeded(tickRef, tick, tickIntervalMs);
40044
+ }
40045
+ const unsubscribe = agentStreamEvents.onAgentStream((event) => {
40046
+ switch (event.kind) {
40047
+ case "agent.call_started": {
40048
+ const now = Date.now();
40049
+ activeStates.set(event.callId, {
40050
+ callId: event.callId,
40051
+ agentName: event.agentName,
40052
+ sessionName: event.sessionName,
40053
+ storyId: event.storyId,
40054
+ stage: event.stage,
40055
+ pid: event.pid,
40056
+ startedAt: now,
40057
+ lastActivityAt: now,
40058
+ lastNonToolCallActivityAt: now,
40059
+ messageUpdates: 0,
40060
+ thinkingUpdates: 0,
40061
+ usageUpdates: 0,
40062
+ toolCallUpdates: 0,
40063
+ cancelAttempts: 0,
40064
+ inGracePeriod: false,
40065
+ warnedForCurrentIdlePeriod: false
40066
+ });
40067
+ getSafeLogger()?.debug("idle-watchdog", "Watchdog tracking call", {
40068
+ storyId: event.storyId,
40069
+ callId: event.callId,
40070
+ mode,
40071
+ idleTimeoutMs,
40072
+ toolCallOnlyTimeoutMs
40073
+ });
40074
+ scheduleTickIfNeeded(tickRef, tick, tickIntervalMs);
40075
+ break;
40076
+ }
40077
+ case "agent.message_update": {
40078
+ const state = activeStates.get(event.callId);
40079
+ if (state && activityKinds.has("message_update")) {
40080
+ state.messageUpdates++;
40081
+ state.lastNonToolCallActivityAt = event.timestamp;
40082
+ resetActivity(state, event.timestamp, { clearGrace: true });
40083
+ }
40084
+ break;
40085
+ }
40086
+ case "agent.thinking_update": {
40087
+ const state = activeStates.get(event.callId);
40088
+ if (state && activityKinds.has("thinking_update")) {
40089
+ state.thinkingUpdates++;
40090
+ state.lastNonToolCallActivityAt = event.timestamp;
40091
+ resetActivity(state, event.timestamp, { clearGrace: true });
40092
+ }
40093
+ break;
40094
+ }
40095
+ case "agent.usage_update": {
40096
+ const state = activeStates.get(event.callId);
40097
+ if (state && activityKinds.has("usage_update")) {
40098
+ state.usageUpdates++;
40099
+ state.lastNonToolCallActivityAt = event.timestamp;
40100
+ resetActivity(state, event.timestamp, { clearGrace: true });
40101
+ }
40102
+ break;
40103
+ }
40104
+ case "agent.tool_call_update": {
40105
+ const state = activeStates.get(event.callId);
40106
+ if (state && activityKinds.has("tool_call_update")) {
40107
+ state.toolCallUpdates++;
40108
+ resetActivity(state, event.timestamp, {
40109
+ clearGrace: state.graceReason === "idle_timeout_exceeded"
40110
+ });
40111
+ }
40112
+ break;
40113
+ }
40114
+ case "agent.process_update":
40115
+ break;
40116
+ case "agent.call_ended": {
40117
+ const state = activeStates.get(event.callId);
40118
+ if (state) {
40119
+ if (state.graceTimer !== undefined)
40120
+ clearTimeout(state.graceTimer);
40121
+ activeStates.delete(event.callId);
40122
+ }
40123
+ if (activeStates.size === 0 && tickRef.handle !== null) {
40124
+ clearTimeout(tickRef.handle);
40125
+ tickRef.handle = null;
40126
+ }
40127
+ break;
40128
+ }
40129
+ }
40130
+ });
40131
+ return () => {
40132
+ unsubscribe();
40133
+ for (const state of activeStates.values()) {
40134
+ if (state.graceTimer !== undefined)
40135
+ clearTimeout(state.graceTimer);
40136
+ }
40137
+ activeStates.clear();
40138
+ if (tickRef.handle !== null) {
40139
+ clearTimeout(tickRef.handle);
40140
+ tickRef.handle = null;
40141
+ }
40142
+ };
40143
+ }
40144
+ var init_idle_watchdog = __esm(() => {
40145
+ init_logger2();
40146
+ });
40147
+
40148
+ // src/runtime/middleware/index.ts
40149
+ var init_middleware = __esm(() => {
40150
+ init_cancellation();
40151
+ init_logging2();
40152
+ init_agent_stream_logging();
40153
+ init_idle_watchdog();
40154
+ });
40155
+
40156
+ // src/agents/factory.ts
40157
+ function createAgentManager(config2, opts) {
40158
+ return new AgentManager(config2, undefined, opts);
40159
+ }
40160
+ var init_factory = __esm(() => {
40161
+ init_manager();
40162
+ });
40163
+
40164
+ // src/execution/pid-registry.ts
40165
+ import { existsSync as existsSync9 } from "fs";
40166
+ import { appendFile as appendFile2 } from "fs/promises";
40167
+
40168
+ class PidRegistry {
40169
+ workdir;
40170
+ pidsFilePath;
40171
+ pids = new Set;
40172
+ frozen = false;
40173
+ constructor(workdir, _platform) {
40174
+ this.workdir = workdir;
40175
+ this.pidsFilePath = `${workdir}/${PID_REGISTRY_FILE}`;
40176
+ }
40177
+ freeze() {
40178
+ if (this.frozen)
40179
+ return;
40180
+ this.frozen = true;
40181
+ getSafeLogger()?.debug("pid-registry", "Registry frozen \u2014 new registrations blocked");
40182
+ }
40183
+ isFrozen() {
40184
+ return this.frozen;
40185
+ }
40186
+ async register(pid) {
40187
+ const logger = getSafeLogger();
40188
+ if (this.frozen) {
40189
+ logger?.warn("pid-registry", `Registration blocked (registry frozen) PID ${pid}`, { pid });
40190
+ return;
40191
+ }
40192
+ this.pids.add(pid);
40193
+ const entry = {
40194
+ pid,
40195
+ spawnedAt: new Date().toISOString(),
40196
+ workdir: this.workdir
40197
+ };
40198
+ try {
40199
+ const line = `${JSON.stringify(entry)}
40200
+ `;
40201
+ await appendFile2(this.pidsFilePath, line);
40202
+ logger?.debug("pid-registry", `Registered PID ${pid}`, { pid });
40203
+ } catch (err) {
40204
+ logger?.warn("pid-registry", `Failed to write PID ${pid} to registry`, {
40205
+ error: err.message
40206
+ });
40207
+ }
40208
+ }
40209
+ async unregister(pid) {
40210
+ const logger = getSafeLogger();
40211
+ this.pids.delete(pid);
40212
+ try {
40213
+ await this.writePidsFile();
40214
+ logger?.debug("pid-registry", `Unregistered PID ${pid}`, { pid });
40215
+ } catch (err) {
40216
+ logger?.warn("pid-registry", `Failed to unregister PID ${pid}`, {
40217
+ error: err.message
40218
+ });
40219
+ }
40220
+ }
40221
+ async killAll() {
40222
+ const logger = getSafeLogger();
40223
+ const pids = Array.from(this.pids);
40224
+ if (pids.length === 0) {
40225
+ logger?.debug("pid-registry", "No PIDs to kill");
40226
+ return;
40227
+ }
40228
+ logger?.info("pid-registry", `Killing ${pids.length} registered processes`, { pids });
40229
+ const killPromises = pids.map((pid) => this.killPid(pid));
40230
+ await Promise.allSettled(killPromises);
40231
+ try {
40232
+ await Bun.write(this.pidsFilePath, "");
40233
+ this.pids.clear();
40234
+ logger?.info("pid-registry", "All registered PIDs killed and registry cleared");
40235
+ } catch (err) {
40236
+ logger?.warn("pid-registry", "Failed to clear registry file", {
40237
+ error: err.message
40238
+ });
40239
+ }
40240
+ }
40241
+ async cleanupStale() {
40242
+ const logger = getSafeLogger();
40243
+ if (!existsSync9(this.pidsFilePath)) {
40244
+ logger?.debug("pid-registry", "No stale PIDs file found");
40245
+ return;
40246
+ }
40247
+ try {
40248
+ const content = await Bun.file(this.pidsFilePath).text();
40249
+ const lines = content.split(`
40250
+ `).filter((line) => line.trim()).map((line) => {
40251
+ try {
40252
+ return JSON.parse(line);
40253
+ } catch {
40254
+ return null;
40255
+ }
40256
+ }).filter((entry) => entry !== null);
40257
+ if (lines.length === 0) {
40258
+ logger?.debug("pid-registry", "No stale PIDs to cleanup");
40259
+ await Bun.write(this.pidsFilePath, "");
40260
+ return;
40261
+ }
40262
+ const stalePids = lines.map((entry) => entry.pid);
40263
+ logger?.info("pid-registry", `Found ${stalePids.length} stale PID entries from previous run; clearing file without signaling (PIDs likely recycled)`, { pids: stalePids });
40264
+ await Bun.write(this.pidsFilePath, "");
40265
+ logger?.info("pid-registry", "Stale PIDs file cleared");
40266
+ } catch (err) {
40267
+ logger?.warn("pid-registry", "Failed to cleanup stale PIDs", {
40268
+ error: err.message
40269
+ });
40270
+ }
40271
+ }
40272
+ async killPid(pid) {
40273
+ const logger = getSafeLogger();
40274
+ if (!Number.isInteger(pid) || pid <= 1) {
40275
+ logger?.warn("pid-registry", `Refusing to signal non-positive or reserved PID ${pid}`, { pid });
40276
+ return;
40277
+ }
40278
+ try {
40279
+ const checkProc = Bun.spawn(["kill", "-0", String(pid)], {
40280
+ stdout: "pipe",
40281
+ stderr: "pipe"
40282
+ });
40283
+ const checkCode = await checkProc.exited;
40284
+ if (checkCode !== 0) {
40285
+ logger?.debug("pid-registry", `PID ${pid} not found (already exited)`, { pid });
40286
+ return;
40287
+ }
40288
+ const killProc = Bun.spawn(["kill", "-TERM", String(pid)], {
40289
+ stdout: "pipe",
40290
+ stderr: "pipe"
40291
+ });
40292
+ const killCode = await killProc.exited;
40293
+ if (killCode === 0) {
40294
+ logger?.debug("pid-registry", `Killed PID ${pid}`, { pid });
40295
+ } else {
40296
+ const stderr = await new Response(killProc.stderr).text();
40297
+ logger?.warn("pid-registry", `Failed to kill PID ${pid}`, {
40298
+ pid,
40299
+ exitCode: killCode,
40300
+ stderr: stderr.trim()
40301
+ });
40302
+ }
40303
+ } catch (err) {
40304
+ logger?.warn("pid-registry", `Error killing PID ${pid}`, {
40305
+ pid,
40306
+ error: err.message
40307
+ });
40308
+ }
40309
+ }
40310
+ async writePidsFile() {
40311
+ const entries = Array.from(this.pids).map((pid) => ({
40312
+ pid,
40313
+ spawnedAt: new Date().toISOString(),
40314
+ workdir: this.workdir
40315
+ }));
40316
+ const content = entries.map((entry) => JSON.stringify(entry)).join(`
40317
+ `);
40318
+ await Bun.write(this.pidsFilePath, content ? `${content}
40319
+ ` : "");
40320
+ }
40321
+ getPids() {
40322
+ return Array.from(this.pids);
40323
+ }
40324
+ }
40325
+ var PID_REGISTRY_FILE = ".nax-pids";
40326
+ var init_pid_registry = __esm(() => {
40327
+ init_logger2();
40328
+ });
40329
+
40330
+ // src/session/manager-deps.ts
40331
+ import { randomUUID as randomUUID3 } from "crypto";
40332
+ import { mkdir as mkdir5 } from "fs/promises";
40333
+ import { isAbsolute as isAbsolute9, join as join27, relative as relative10, sep } from "path";
40334
+ function resolveProjectDirFromScratchDir(scratchDir) {
40335
+ const marker = `${sep}.nax${sep}features${sep}`;
40336
+ const markerIdx = scratchDir.lastIndexOf(marker);
40337
+ if (markerIdx > 0)
40338
+ return scratchDir.slice(0, markerIdx);
40339
+ const posixIdx = scratchDir.lastIndexOf("/.nax/features/");
40340
+ if (posixIdx > 0)
40341
+ return scratchDir.slice(0, posixIdx);
40342
+ return;
40343
+ }
40344
+ function toProjectRelativePath(projectDir, pathValue) {
40345
+ const relativePath = isAbsolute9(pathValue) ? relative10(projectDir, pathValue) : pathValue;
40346
+ return relativePath === "" ? "." : relativePath;
40347
+ }
40348
+ var _sessionManagerDeps;
40349
+ var init_manager_deps = __esm(() => {
40350
+ _sessionManagerDeps = {
40351
+ now: () => new Date().toISOString(),
40352
+ nowMs: () => Date.now(),
40353
+ uuid: () => randomUUID3(),
40354
+ sessionScratchDir: (projectDir, featureName, sessionId) => join27(projectDir, ".nax", "features", featureName, "sessions", sessionId),
40355
+ writeDescriptor: async (scratchDir, descriptor, projectDir) => {
40356
+ await mkdir5(scratchDir, { recursive: true });
40357
+ const { handle: _handle, ...persistable } = descriptor;
40358
+ const derivedProjectDir = projectDir ?? resolveProjectDirFromScratchDir(scratchDir);
40359
+ if (derivedProjectDir) {
40360
+ persistable.workdir = toProjectRelativePath(derivedProjectDir, persistable.workdir);
40361
+ if (persistable.scratchDir) {
40362
+ persistable.scratchDir = toProjectRelativePath(derivedProjectDir, persistable.scratchDir);
40363
+ }
40364
+ }
40365
+ await Bun.write(join27(scratchDir, "descriptor.json"), JSON.stringify(persistable, null, 2));
40366
+ }
40367
+ };
40368
+ });
40369
+
40370
+ // src/session/manager-run.ts
40371
+ async function runTrackedSession(state, id, runner, request) {
40372
+ const startedAt = Date.now();
40373
+ const pre = state.sessions.get(id);
39745
40374
  if (!pre) {
39746
40375
  throw new NaxError(`Session "${id}" not found in registry`, "SESSION_NOT_FOUND", {
39747
40376
  stage: "session",
@@ -40053,838 +40682,331 @@ class SessionManager {
40053
40682
  });
40054
40683
  }
40055
40684
  const allowed = SESSION_TRANSITIONS[session.state];
40056
- if (!allowed.includes(to)) {
40057
- throw new NaxError(`Invalid session transition: ${session.state} \u2192 ${to} (session ${id})`, "SESSION_INVALID_TRANSITION", { stage: "session", sessionId: id, from: session.state, to, allowed });
40058
- }
40059
- const now = _sessionManagerDeps.now();
40060
- const updated = {
40061
- ...session,
40062
- state: to,
40063
- lastActivityAt: now
40064
- };
40065
- if (options?.protocolIds) {
40066
- updated.protocolIds = options.protocolIds;
40067
- }
40068
- if (options?.completedStage) {
40069
- updated.completedStages = [...session.completedStages, options.completedStage];
40070
- }
40071
- this._sessions.set(id, updated);
40072
- this._persistDescriptor(updated);
40073
- getLogger().debug("session", "Session transitioned", {
40074
- storyId: session.storyId,
40075
- sessionId: id,
40076
- from: session.state,
40077
- to
40078
- });
40079
- return { ...updated };
40080
- }
40081
- bindHandle(id, handle, protocolIds) {
40082
- const session = this._sessions.get(id);
40083
- if (!session) {
40084
- throw new NaxError(`Session "${id}" not found in registry`, "SESSION_NOT_FOUND", {
40085
- stage: "session",
40086
- sessionId: id
40087
- });
40088
- }
40089
- const updated = {
40090
- ...session,
40091
- handle,
40092
- protocolIds,
40093
- lastActivityAt: _sessionManagerDeps.now()
40094
- };
40095
- this._sessions.set(id, updated);
40096
- this._persistDescriptor(updated);
40097
- getLogger().debug("session", "Session handle bound", {
40098
- storyId: session.storyId,
40099
- sessionId: id,
40100
- handle
40101
- });
40102
- return { ...updated };
40103
- }
40104
- handoff(id, newAgent, reason) {
40105
- const session = this._sessions.get(id);
40106
- if (!session) {
40107
- throw new NaxError(`Session "${id}" not found in registry`, "SESSION_NOT_FOUND", {
40108
- stage: "session",
40109
- sessionId: id
40110
- });
40111
- }
40112
- const updated = {
40113
- ...session,
40114
- agent: newAgent,
40115
- lastActivityAt: _sessionManagerDeps.now()
40116
- };
40117
- this._sessions.set(id, updated);
40118
- this._persistDescriptor(updated);
40119
- getLogger().info("session", "Session handed off to fallback agent", {
40120
- storyId: session.storyId,
40121
- sessionId: id,
40122
- fromAgent: session.agent,
40123
- toAgent: newAgent,
40124
- ...reason && { reason }
40125
- });
40126
- return { ...updated };
40127
- }
40128
- resume(storyId, role) {
40129
- const terminal = ["COMPLETED", "FAILED"];
40130
- for (const session of this._sessions.values()) {
40131
- if (session.storyId === storyId && session.role === role && !terminal.includes(session.state)) {
40132
- getLogger().debug("session", "Session resumed", {
40133
- storyId,
40134
- sessionId: session.id,
40135
- role,
40136
- state: session.state
40137
- });
40138
- return { ...session };
40139
- }
40140
- }
40141
- return null;
40142
- }
40143
- closeStory(storyId) {
40144
- const terminal = ["COMPLETED", "FAILED"];
40145
- const closed = [];
40146
- const now = _sessionManagerDeps.now();
40147
- for (const [id, session] of this._sessions.entries()) {
40148
- if (session.storyId !== storyId)
40149
- continue;
40150
- if (terminal.includes(session.state))
40151
- continue;
40152
- const updated = { ...session, state: "COMPLETED", lastActivityAt: now };
40153
- this._sessions.set(id, updated);
40154
- this._persistDescriptor(updated);
40155
- closed.push({ ...updated });
40156
- getLogger().debug("session", "Session closed by closeStory", {
40157
- storyId,
40158
- sessionId: id,
40159
- priorState: session.state
40160
- });
40161
- }
40162
- return closed;
40163
- }
40164
- getForStory(storyId) {
40165
- return Array.from(this._sessions.values()).filter((s) => s.storyId === storyId).map((s) => ({ ...s }));
40166
- }
40167
- listActive() {
40168
- const terminal = ["COMPLETED", "FAILED"];
40169
- return Array.from(this._sessions.values()).filter((s) => !terminal.includes(s.state)).map((s) => ({ ...s }));
40170
- }
40171
- _findByName(name) {
40172
- for (const session of this._sessions.values()) {
40173
- if (session.handle === name)
40174
- return session;
40175
- }
40176
- return;
40177
- }
40178
- descriptor(name) {
40179
- const session = this._findByName(name);
40180
- return session ? { ...session } : null;
40181
- }
40182
- nameFor(req) {
40183
- return formatSessionName(req);
40184
- }
40185
- async openSession(name, opts) {
40186
- const liveHandle = this._liveHandles.get(name);
40187
- if (liveHandle && liveHandle.agentName === opts.agentName) {
40188
- const liveDesc = this._findByName(name);
40189
- if (!liveDesc || liveDesc.state !== "COMPLETED" && liveDesc.state !== "FAILED") {
40190
- return liveHandle;
40191
- }
40192
- this._liveHandles.delete(name);
40193
- }
40194
- const adapter = this._getAdapter(opts.agentName);
40195
- if (!adapter) {
40196
- throw new NaxError(`SessionManager.openSession: no adapter found for agent "${opts.agentName}"`, "ADAPTER_NOT_FOUND", { stage: "session", agentName: opts.agentName });
40197
- }
40198
- const resolvedPermissions = resolvePermissions(this._config, opts.pipelineStage);
40199
- const existingDescriptor = this._findByName(name);
40200
- const resume = existingDescriptor !== undefined;
40201
- const handle = await adapter.openSession(name, {
40202
- agentName: opts.agentName,
40203
- workdir: opts.workdir,
40204
- resolvedPermissions,
40205
- modelDef: opts.modelDef,
40206
- timeoutSeconds: opts.timeoutSeconds,
40207
- onPidSpawned: this._pidRegistry ? (pid) => this._pidRegistry?.register(pid) : undefined,
40208
- onPidExited: this._pidRegistry ? (pid) => this._pidRegistry?.unregister(pid) : undefined,
40209
- onSessionEstablished: opts.onSessionEstablished,
40210
- signal: opts.signal,
40211
- resume,
40212
- onActiveCall: this._buildOnActiveCall(name),
40213
- onStreamActivity: this._onStreamActivity
40214
- });
40215
- this._liveHandles.set(name, handle);
40216
- const protocolIds = handle.protocolIds ?? NULL_PROTOCOL_IDS;
40217
- if (!existingDescriptor) {
40218
- const created = this.create({
40219
- role: opts.role ?? "main",
40220
- agent: opts.agentName,
40221
- workdir: opts.workdir,
40222
- featureName: opts.featureName,
40223
- storyId: opts.storyId,
40224
- handle: name
40225
- });
40226
- this.transition(created.id, "RUNNING", { protocolIds });
40227
- } else if (existingDescriptor.state === "CREATED") {
40228
- this.transition(existingDescriptor.id, "RUNNING", { protocolIds });
40229
- } else if (existingDescriptor.state === "COMPLETED" || existingDescriptor.state === "FAILED") {
40230
- this._cancelledSessions.delete(name);
40231
- const updated = {
40232
- ...existingDescriptor,
40233
- state: "RUNNING",
40234
- protocolIds,
40235
- lastActivityAt: _sessionManagerDeps.now()
40236
- };
40237
- this._sessions.set(existingDescriptor.id, updated);
40238
- this._persistDescriptor(updated);
40239
- } else {
40240
- getLogger().warn("session", "openSession called on already-RUNNING session", {
40241
- storyId: opts.storyId,
40242
- sessionName: name
40243
- });
40244
- }
40245
- getLogger().debug("session", "Session opened via SessionManager", {
40246
- storyId: opts.storyId,
40247
- sessionName: name,
40248
- agentName: opts.agentName,
40249
- resume
40250
- });
40251
- return handle;
40252
- }
40253
- async closeSession(handle) {
40254
- const desc = this._findByName(handle.id);
40255
- const adapter = this._getAdapter(handle.agentName);
40256
- this._liveHandles.delete(handle.id);
40257
- if (adapter) {
40258
- try {
40259
- await adapter.closeSession(handle);
40260
- } catch (err) {
40261
- getLogger().warn("session", "adapter.closeSession failed (swallowed)", {
40262
- storyId: desc?.storyId,
40263
- sessionName: handle.id,
40264
- error: err instanceof Error ? err.message : String(err)
40265
- });
40266
- }
40267
- }
40268
- if (desc && desc.state === "RUNNING") {
40269
- this.transition(desc.id, "COMPLETED");
40270
- }
40271
- this._busySessions.delete(handle.id);
40272
- this._cancelledSessions.delete(handle.id);
40273
- }
40274
- async sendPrompt(handle, prompt, opts) {
40275
- if (this._cancelledSessions.has(handle.id)) {
40276
- throw new NaxError(`Session "${handle.id}" was cancelled \u2014 close it and open a new session to continue`, "SESSION_CANCELLED", { stage: "session", sessionName: handle.id });
40277
- }
40278
- if (this._busySessions.has(handle.id)) {
40279
- throw new NaxError(`Session "${handle.id}" is already processing a prompt (single-flight invariant)`, "SESSION_BUSY", { stage: "session", sessionName: handle.id });
40280
- }
40281
- const terminalDesc = this._findByName(handle.id);
40282
- if (terminalDesc && (terminalDesc.state === "COMPLETED" || terminalDesc.state === "FAILED")) {
40283
- throw new NaxError(`Session "${handle.id}" is in terminal state ${terminalDesc.state} \u2014 call openSession first to resume`, "SESSION_TERMINAL_STATE", { stage: "session", sessionName: handle.id, state: terminalDesc.state });
40284
- }
40285
- const adapter = this._getAdapter(handle.agentName);
40286
- if (!adapter) {
40287
- throw new NaxError(`SessionManager.sendPrompt: no adapter found for agent "${handle.agentName}"`, "ADAPTER_NOT_FOUND", { stage: "session", agentName: handle.agentName });
40288
- }
40289
- this._busySessions.add(handle.id);
40290
- try {
40291
- const result = await adapter.sendTurn(handle, prompt, {
40292
- interactionHandler: opts?.interactionHandler ?? NO_OP_INTERACTION_HANDLER,
40293
- signal: opts?.signal,
40294
- maxTurns: opts?.maxTurns
40295
- });
40296
- return { ...result, protocolIds: result.protocolIds ?? handle.protocolIds };
40297
- } catch (err) {
40298
- if (err instanceof SessionTurnError && err.cancelled) {
40299
- const wasWatchdog = (this._watchdogCancelledCallsBySession.get(handle.id)?.size ?? 0) > 0;
40300
- if (wasWatchdog) {
40301
- throw new SessionFailureError("idle watchdog cancelled session \u2014 no stream activity", {
40302
- category: "availability",
40303
- outcome: "fail-stale",
40304
- retriable: true,
40305
- message: "idle watchdog cancelled session \u2014 no stream activity"
40306
- });
40307
- }
40308
- }
40309
- if (opts?.signal?.aborted || err instanceof Error && err.name === "AbortError") {
40310
- this._cancelledSessions.add(handle.id);
40311
- const desc = this._findByName(handle.id);
40312
- if (desc && desc.state === "RUNNING") {
40313
- this.transition(desc.id, "FAILED");
40314
- }
40315
- }
40316
- throw err;
40317
- } finally {
40318
- this._clearWatchdogCancelledCalls(handle.id);
40319
- this._busySessions.delete(handle.id);
40320
- }
40321
- }
40322
- async runInSession(idOrName, promptOrFnOrRunner, optsOrRequest, _legacyOptions) {
40323
- if (typeof promptOrFnOrRunner === "object" && promptOrFnOrRunner !== null && "run" in promptOrFnOrRunner && typeof promptOrFnOrRunner.run === "function") {
40324
- return this._runTrackedSession(idOrName, promptOrFnOrRunner, optsOrRequest);
40325
- }
40326
- const opts = optsOrRequest;
40327
- const handle = await this.openSession(idOrName, opts);
40328
- try {
40329
- if (typeof promptOrFnOrRunner === "string") {
40330
- return await this.sendPrompt(handle, promptOrFnOrRunner, {
40331
- interactionHandler: opts.interactionHandler,
40332
- signal: opts.signal,
40333
- maxTurns: opts.maxTurns
40334
- });
40335
- }
40336
- return await promptOrFnOrRunner(handle);
40337
- } finally {
40338
- await this.closeSession(handle);
40339
- }
40340
- }
40341
- async _runTrackedSession(id, runner, request) {
40342
- return runTrackedSession({
40343
- sessions: this._sessions,
40344
- transition: (sid, to, opts) => this.transition(sid, to, opts),
40345
- bindHandle: (sid, handle, protocolIds) => this.bindHandle(sid, handle, protocolIds),
40346
- handoff: (sid, agent, reason) => this.handoff(sid, agent, reason),
40347
- persistDescriptor: (desc) => this._persistDescriptor(desc),
40348
- dispatchEvents: this._dispatchEvents,
40349
- defaultAgent: this._defaultAgent,
40350
- nameFor: (req) => this.nameFor(req)
40351
- }, id, runner, request);
40352
- }
40353
- sweepOrphans(ttlMs = DEFAULT_ORPHAN_TTL_MS) {
40354
- return sweepOrphansImpl(this._sessions, ttlMs);
40355
- }
40356
- }
40357
- var NULL_PROTOCOL_IDS;
40358
- var init_manager2 = __esm(() => {
40359
- init_types();
40360
- init_errors();
40361
- init_logger2();
40362
- init_dispatch_events();
40363
- init_no_op_interaction_handler();
40364
- init_manager_deps();
40365
- init_manager_run();
40366
- init_manager_sweep();
40367
- init_naming();
40368
- init_types7();
40369
- init_manager_deps();
40370
- NULL_PROTOCOL_IDS = { recordId: null, sessionId: null };
40371
- });
40372
-
40373
- // src/session/index.ts
40374
- var init_session = __esm(() => {
40375
- init_manager2();
40376
- init_naming();
40377
- init_types7();
40378
- });
40379
-
40380
- // src/runtime/middleware/cancellation.ts
40381
- function cancellationMiddleware() {
40382
- return {
40383
- name: "cancellation",
40384
- async before(ctx) {
40385
- if (ctx.signal?.aborted) {
40386
- throw new NaxError("Agent call cancelled before start", "AGENT_CANCELLED", {
40387
- stage: ctx.stage ?? "run",
40388
- agentName: ctx.agentName
40389
- });
40390
- }
40391
- }
40392
- };
40393
- }
40394
- var init_cancellation = __esm(() => {
40395
- init_errors();
40396
- });
40397
-
40398
- // src/runtime/middleware/logging.ts
40399
- function attachLoggingSubscriber(bus, runId) {
40400
- const offDispatch = bus.onDispatch((event) => {
40401
- getSafeLogger()?.info("middleware", "Agent call complete", {
40402
- storyId: event.storyId,
40403
- runId,
40404
- agentName: event.agentName,
40405
- kind: event.kind,
40406
- stage: event.stage,
40407
- durationMs: event.durationMs
40408
- });
40409
- });
40410
- const offError = bus.onDispatchError((event) => {
40411
- getSafeLogger()?.warn("middleware", "Agent call failed", {
40412
- storyId: event.storyId,
40413
- runId,
40414
- agentName: event.agentName,
40415
- stage: event.stage,
40416
- durationMs: event.durationMs,
40417
- error: event.errorMessage
40418
- });
40419
- });
40420
- return () => {
40421
- offDispatch();
40422
- offError();
40423
- };
40424
- }
40425
- var init_logging2 = __esm(() => {
40426
- init_logger2();
40427
- });
40428
-
40429
- // src/runtime/middleware/agent-stream-logging.ts
40430
- function attachAgentStreamLogging(bus, runId) {
40431
- const activeCalls = new Map;
40432
- return bus.onAgentStream((event) => {
40433
- switch (event.kind) {
40434
- case "agent.call_started": {
40435
- const now = event.timestamp;
40436
- activeCalls.set(event.callId, {
40437
- callId: event.callId,
40438
- agentName: event.agentName,
40439
- storyId: event.storyId,
40440
- stage: event.stage,
40441
- startedAt: now,
40442
- lastActivityAt: now,
40443
- messageUpdates: 0,
40444
- thinkingUpdates: 0,
40445
- usageUpdates: 0
40446
- });
40447
- getSafeLogger()?.info("agent-stream", "Agent call started", {
40448
- storyId: event.storyId,
40449
- runId,
40450
- callId: event.callId,
40451
- agentName: event.agentName,
40452
- stage: event.stage,
40453
- model: event.model,
40454
- timeoutSeconds: event.timeoutSeconds
40455
- });
40456
- break;
40457
- }
40458
- case "agent.message_update": {
40459
- const state = activeCalls.get(event.callId);
40460
- if (state) {
40461
- state.messageUpdates++;
40462
- state.lastActivityAt = event.timestamp;
40463
- }
40464
- break;
40465
- }
40466
- case "agent.thinking_update": {
40467
- const state = activeCalls.get(event.callId);
40468
- if (state) {
40469
- state.thinkingUpdates++;
40470
- state.lastActivityAt = event.timestamp;
40471
- }
40472
- break;
40473
- }
40474
- case "agent.usage_update": {
40475
- const state = activeCalls.get(event.callId);
40476
- if (state) {
40477
- state.usageUpdates++;
40478
- state.lastActivityAt = event.timestamp;
40479
- }
40480
- break;
40481
- }
40482
- case "agent.process_update":
40483
- break;
40484
- case "agent.call_ended": {
40485
- const state = activeCalls.get(event.callId);
40486
- if (state) {
40487
- const idleMs = event.timestamp - state.lastActivityAt;
40488
- getSafeLogger()?.info("agent-stream", "Agent call ended", {
40489
- storyId: state.storyId,
40490
- runId,
40491
- callId: state.callId,
40492
- agentName: state.agentName,
40493
- stage: state.stage,
40494
- messageUpdates: state.messageUpdates,
40495
- thinkingUpdates: state.thinkingUpdates,
40496
- usageUpdates: state.usageUpdates,
40497
- lastActivityAt: state.lastActivityAt,
40498
- idleMs,
40499
- status: event.status
40500
- });
40501
- activeCalls.delete(event.callId);
40502
- }
40503
- break;
40504
- }
40505
- }
40506
- });
40507
- }
40508
- var init_agent_stream_logging = __esm(() => {
40509
- init_logger2();
40510
- });
40511
-
40512
- // src/runtime/middleware/cost.ts
40513
- function attachCostSubscriber(bus, aggregator, runId) {
40514
- const offDispatch = bus.onDispatch((event) => {
40515
- const tu = event.tokenUsage;
40516
- const exactCostUsd = event.exactCostUsd;
40517
- const estimatedCostUsd = event.estimatedCostUsd ?? exactCostUsd ?? 0;
40518
- if (!tu && exactCostUsd == null && estimatedCostUsd === 0)
40519
- return;
40520
- const costUsd = exactCostUsd ?? estimatedCostUsd;
40521
- const confidence = exactCostUsd != null ? "exact" : "estimated";
40522
- const costEvent = {
40523
- ts: event.timestamp,
40524
- runId,
40525
- agentName: event.agentName,
40526
- model: "unknown",
40527
- stage: event.stage,
40528
- storyId: event.storyId,
40529
- tokens: tu ? {
40530
- input: tu.inputTokens ?? 0,
40531
- output: tu.outputTokens ?? 0,
40532
- cacheRead: tu.cacheReadInputTokens,
40533
- cacheWrite: tu.cacheCreationInputTokens
40534
- } : { input: 0, output: 0 },
40535
- estimatedCostUsd,
40536
- exactCostUsd,
40537
- costUsd,
40538
- confidence,
40539
- durationMs: event.durationMs
40540
- };
40541
- aggregator.record(costEvent);
40542
- });
40543
- const offError = bus.onDispatchError((event) => {
40544
- const errorEvent = {
40545
- ts: event.timestamp,
40546
- runId,
40547
- agentName: event.agentName,
40548
- stage: event.stage,
40549
- storyId: event.storyId,
40550
- errorCode: event.errorCode,
40551
- durationMs: event.durationMs
40552
- };
40553
- aggregator.recordError(errorEvent);
40554
- });
40555
- const offCompleted = bus.onOperationCompleted((event) => {
40556
- const summary = {
40557
- runId,
40558
- operation: event.operation,
40559
- hopCount: event.hopCount,
40560
- fallbackTriggered: event.fallbackTriggered,
40561
- totalCostUsd: event.totalCostUsd,
40562
- totalElapsedMs: event.totalElapsedMs,
40563
- finalStatus: event.finalStatus
40564
- };
40565
- aggregator.recordOperationSummary(summary);
40566
- });
40567
- return () => {
40568
- offDispatch();
40569
- offError();
40570
- offCompleted();
40571
- };
40572
- }
40573
-
40574
- // src/runtime/middleware/audit.ts
40575
- function attachAuditSubscriber(bus, auditor, runId) {
40576
- const offDispatch = bus.onDispatch((event) => {
40577
- const entry = {
40578
- ts: event.timestamp,
40579
- runId,
40580
- agentName: event.agentName,
40581
- stage: event.stage,
40582
- storyId: event.storyId,
40583
- permissionProfile: event.resolvedPermissions.mode,
40584
- prompt: event.prompt,
40585
- response: event.response,
40586
- durationMs: event.durationMs,
40587
- callType: event.kind === "session-turn" ? "run" : "complete",
40588
- workdir: event.workdir,
40589
- projectDir: event.projectDir,
40590
- featureName: event.featureName,
40591
- sessionName: event.sessionName,
40592
- ...event.kind === "session-turn" && {
40593
- sessionId: event.protocolIds.sessionId ?? null,
40594
- recordId: event.protocolIds.recordId ?? null,
40595
- turn: event.turn
40596
- }
40597
- };
40598
- auditor.record(entry);
40599
- });
40600
- const offError = bus.onDispatchError((event) => {
40601
- const entry = {
40602
- ts: event.timestamp,
40603
- runId,
40604
- agentName: event.agentName,
40605
- stage: event.stage,
40606
- storyId: event.storyId,
40607
- errorCode: event.errorCode,
40608
- errorMessage: event.errorMessage,
40609
- durationMs: event.durationMs,
40610
- callType: event.origin === "completeAs" ? "complete" : "run",
40611
- permissionProfile: event.resolvedPermissions.mode,
40612
- prompt: event.prompt
40613
- };
40614
- auditor.recordError(entry);
40615
- });
40616
- return () => {
40617
- offDispatch();
40618
- offError();
40619
- };
40620
- }
40621
-
40622
- // src/runtime/middleware/review-audit.ts
40623
- function reviewerFromRole(role) {
40624
- if (role === "reviewer-semantic")
40625
- return "semantic";
40626
- if (role === "reviewer-adversarial")
40627
- return "adversarial";
40628
- return null;
40629
- }
40630
- function attachReviewAuditSubscriber(bus, auditor, runId) {
40631
- const offDispatch = bus.onDispatch((event) => {
40632
- if (event.kind !== "session-turn")
40633
- return;
40634
- const reviewer = reviewerFromRole(event.sessionRole);
40635
- if (!reviewer)
40636
- return;
40637
- auditor.recordDispatch({
40638
- runId,
40639
- reviewer,
40640
- sessionName: event.sessionName,
40641
- sessionId: event.protocolIds.sessionId ?? null,
40642
- recordId: event.protocolIds.recordId ?? null,
40643
- workdir: event.workdir,
40644
- projectDir: event.projectDir,
40645
- agentName: event.agentName,
40646
- storyId: event.storyId,
40647
- featureName: event.featureName
40648
- });
40649
- });
40650
- const offDecision = bus.onReviewDecision((event) => {
40651
- auditor.recordDecision({
40652
- runId: event.runId,
40653
- reviewer: event.reviewer,
40654
- sessionName: event.sessionName,
40655
- sessionId: event.sessionId,
40656
- recordId: event.recordId,
40657
- workdir: event.workdir,
40658
- projectDir: event.projectDir,
40659
- outputDir: event.outputDir,
40660
- agentName: event.agentName,
40661
- storyId: event.storyId,
40662
- featureName: event.featureName,
40663
- parsed: event.parsed,
40664
- looksLikeFail: event.looksLikeFail,
40665
- failOpen: event.failOpen,
40666
- passed: event.passed,
40667
- blockingThreshold: event.blockingThreshold,
40668
- result: event.result,
40669
- advisoryFindings: event.advisoryFindings
40670
- });
40671
- });
40672
- return () => {
40673
- offDispatch();
40674
- offDecision();
40675
- };
40676
- }
40677
-
40678
- // src/runtime/middleware/idle-watchdog.ts
40679
- function scheduleTickIfNeeded(tickRef, tick, intervalMs) {
40680
- if (tickRef.handle !== null)
40681
- return;
40682
- tickRef.handle = setTimeout(tick, intervalMs);
40683
- }
40684
- function handleObserveTimeout(state, idleDurationMs) {
40685
- if (state.warnedForCurrentIdlePeriod)
40686
- return;
40687
- state.warnedForCurrentIdlePeriod = true;
40688
- getSafeLogger()?.warn("idle-watchdog", "Idle timeout exceeded", {
40689
- storyId: state.storyId,
40690
- key: "idle_timeout_exceeded",
40691
- callId: state.callId,
40692
- mode: "observe",
40693
- idleDurationMs
40694
- });
40695
- }
40696
- async function handleCancelTimeout(state, controllerRegistry, maxRetryAttempts, activeStates) {
40697
- if (state.cancelAttempts >= maxRetryAttempts) {
40698
- getSafeLogger()?.error("idle-watchdog", "Max retry attempts exceeded", {
40699
- storyId: state.storyId,
40700
- key: "max_retry_attempts_exceeded",
40701
- callId: state.callId,
40702
- cancelAttempts: state.cancelAttempts
40685
+ if (!allowed.includes(to)) {
40686
+ throw new NaxError(`Invalid session transition: ${session.state} \u2192 ${to} (session ${id})`, "SESSION_INVALID_TRANSITION", { stage: "session", sessionId: id, from: session.state, to, allowed });
40687
+ }
40688
+ const now = _sessionManagerDeps.now();
40689
+ const updated = {
40690
+ ...session,
40691
+ state: to,
40692
+ lastActivityAt: now
40693
+ };
40694
+ if (options?.protocolIds) {
40695
+ updated.protocolIds = options.protocolIds;
40696
+ }
40697
+ if (options?.completedStage) {
40698
+ updated.completedStages = [...session.completedStages, options.completedStage];
40699
+ }
40700
+ this._sessions.set(id, updated);
40701
+ this._persistDescriptor(updated);
40702
+ getLogger().debug("session", "Session transitioned", {
40703
+ storyId: session.storyId,
40704
+ sessionId: id,
40705
+ from: session.state,
40706
+ to
40703
40707
  });
40704
- activeStates.delete(state.callId);
40705
- return;
40708
+ return { ...updated };
40706
40709
  }
40707
- state.cancelAttempts++;
40708
- state.lastActivityAt = Date.now();
40709
- getSafeLogger()?.warn("idle-watchdog", "Canceling idle call", {
40710
- storyId: state.storyId,
40711
- key: "idle_timeout_exceeded",
40712
- callId: state.callId,
40713
- mode: "cancel",
40714
- action: "cancel"
40715
- });
40716
- const cancel = controllerRegistry.get(state.callId);
40717
- if (cancel)
40718
- await cancel().catch(() => {});
40719
- }
40720
- function handleWarnThenCancelTimeout(state, controllerRegistry, maxRetryAttempts, idleTimeoutMs, graceMs, activeStates) {
40721
- if (state.cancelAttempts >= maxRetryAttempts) {
40722
- getSafeLogger()?.error("idle-watchdog", "Max retry attempts exceeded", {
40723
- storyId: state.storyId,
40724
- key: "max_retry_attempts_exceeded",
40725
- callId: state.callId,
40726
- cancelAttempts: state.cancelAttempts
40710
+ bindHandle(id, handle, protocolIds) {
40711
+ const session = this._sessions.get(id);
40712
+ if (!session) {
40713
+ throw new NaxError(`Session "${id}" not found in registry`, "SESSION_NOT_FOUND", {
40714
+ stage: "session",
40715
+ sessionId: id
40716
+ });
40717
+ }
40718
+ const updated = {
40719
+ ...session,
40720
+ handle,
40721
+ protocolIds,
40722
+ lastActivityAt: _sessionManagerDeps.now()
40723
+ };
40724
+ this._sessions.set(id, updated);
40725
+ this._persistDescriptor(updated);
40726
+ getLogger().debug("session", "Session handle bound", {
40727
+ storyId: session.storyId,
40728
+ sessionId: id,
40729
+ handle
40727
40730
  });
40728
- activeStates.delete(state.callId);
40729
- return;
40731
+ return { ...updated };
40730
40732
  }
40731
- getSafeLogger()?.warn("idle-watchdog", "Idle timeout exceeded, entering grace period", {
40732
- storyId: state.storyId,
40733
- key: "idle_timeout_exceeded",
40734
- callId: state.callId,
40735
- mode: "warn-then-cancel",
40736
- gracePeriodMs: graceMs
40737
- });
40738
- state.inGracePeriod = true;
40739
- state.graceTimer = setTimeout(async () => {
40740
- if (!activeStates.has(state.callId))
40741
- return;
40742
- state.inGracePeriod = false;
40743
- state.graceTimer = undefined;
40744
- if (Date.now() - state.lastActivityAt < idleTimeoutMs)
40745
- return;
40746
- state.cancelAttempts++;
40747
- state.lastActivityAt = Date.now();
40748
- const cancel = controllerRegistry.get(state.callId);
40749
- if (cancel)
40750
- await cancel().catch(() => {});
40751
- }, graceMs);
40752
- }
40753
- function resetActivity(state, newTimestamp) {
40754
- state.lastActivityAt = newTimestamp;
40755
- state.warnedForCurrentIdlePeriod = false;
40756
- if (state.inGracePeriod && state.graceTimer !== undefined) {
40757
- clearTimeout(state.graceTimer);
40758
- state.graceTimer = undefined;
40759
- state.inGracePeriod = false;
40733
+ handoff(id, newAgent, reason) {
40734
+ const session = this._sessions.get(id);
40735
+ if (!session) {
40736
+ throw new NaxError(`Session "${id}" not found in registry`, "SESSION_NOT_FOUND", {
40737
+ stage: "session",
40738
+ sessionId: id
40739
+ });
40740
+ }
40741
+ const updated = {
40742
+ ...session,
40743
+ agent: newAgent,
40744
+ lastActivityAt: _sessionManagerDeps.now()
40745
+ };
40746
+ this._sessions.set(id, updated);
40747
+ this._persistDescriptor(updated);
40748
+ getLogger().info("session", "Session handed off to fallback agent", {
40749
+ storyId: session.storyId,
40750
+ sessionId: id,
40751
+ fromAgent: session.agent,
40752
+ toAgent: newAgent,
40753
+ ...reason && { reason }
40754
+ });
40755
+ return { ...updated };
40760
40756
  }
40761
- }
40762
- function attachAgentIdleWatchdog(agentStreamEvents, controllerRegistry, config2) {
40763
- const watchdogConfig = config2.agent?.idleWatchdog;
40764
- if (!watchdogConfig?.enabled || watchdogConfig.mode === "off" || watchdogConfig.mode === undefined) {
40765
- return agentStreamEvents.onAgentStream(() => {});
40757
+ resume(storyId, role) {
40758
+ const terminal = ["COMPLETED", "FAILED"];
40759
+ for (const session of this._sessions.values()) {
40760
+ if (session.storyId === storyId && session.role === role && !terminal.includes(session.state)) {
40761
+ getLogger().debug("session", "Session resumed", {
40762
+ storyId,
40763
+ sessionId: session.id,
40764
+ role,
40765
+ state: session.state
40766
+ });
40767
+ return { ...session };
40768
+ }
40769
+ }
40770
+ return null;
40766
40771
  }
40767
- const mode = watchdogConfig.mode;
40768
- const idleTimeoutMs = (watchdogConfig.idleTimeoutSeconds ?? 30) * 1000;
40769
- const graceMs = (watchdogConfig.cancelGraceSeconds ?? 5) * 1000;
40770
- const maxRetryAttempts = watchdogConfig.maxRetryAttempts ?? 3;
40771
- const activityKinds = new Set(watchdogConfig.activityKinds ?? ["message_update", "thinking_update", "usage_update"]);
40772
- const tickIntervalMs = Math.max(1, Math.ceil(idleTimeoutMs / 4));
40773
- const activeStates = new Map;
40774
- const tickRef = { handle: null };
40775
- function tick() {
40776
- tickRef.handle = null;
40777
- const now = Date.now();
40778
- for (const [, state] of activeStates) {
40779
- if (state.inGracePeriod)
40772
+ closeStory(storyId) {
40773
+ const terminal = ["COMPLETED", "FAILED"];
40774
+ const closed = [];
40775
+ const now = _sessionManagerDeps.now();
40776
+ for (const [id, session] of this._sessions.entries()) {
40777
+ if (session.storyId !== storyId)
40780
40778
  continue;
40781
- const idleDurationMs = now - state.lastActivityAt;
40782
- if (idleDurationMs < idleTimeoutMs)
40779
+ if (terminal.includes(session.state))
40783
40780
  continue;
40784
- if (mode === "observe")
40785
- handleObserveTimeout(state, idleDurationMs);
40786
- else if (mode === "cancel")
40787
- handleCancelTimeout(state, controllerRegistry, maxRetryAttempts, activeStates);
40788
- else if (mode === "warn-then-cancel") {
40789
- handleWarnThenCancelTimeout(state, controllerRegistry, maxRetryAttempts, idleTimeoutMs, graceMs, activeStates);
40781
+ const updated = { ...session, state: "COMPLETED", lastActivityAt: now };
40782
+ this._sessions.set(id, updated);
40783
+ this._persistDescriptor(updated);
40784
+ closed.push({ ...updated });
40785
+ getLogger().debug("session", "Session closed by closeStory", {
40786
+ storyId,
40787
+ sessionId: id,
40788
+ priorState: session.state
40789
+ });
40790
+ }
40791
+ return closed;
40792
+ }
40793
+ getForStory(storyId) {
40794
+ return Array.from(this._sessions.values()).filter((s) => s.storyId === storyId).map((s) => ({ ...s }));
40795
+ }
40796
+ listActive() {
40797
+ const terminal = ["COMPLETED", "FAILED"];
40798
+ return Array.from(this._sessions.values()).filter((s) => !terminal.includes(s.state)).map((s) => ({ ...s }));
40799
+ }
40800
+ _findByName(name) {
40801
+ for (const session of this._sessions.values()) {
40802
+ if (session.handle === name)
40803
+ return session;
40804
+ }
40805
+ return;
40806
+ }
40807
+ descriptor(name) {
40808
+ const session = this._findByName(name);
40809
+ return session ? { ...session } : null;
40810
+ }
40811
+ nameFor(req) {
40812
+ return formatSessionName(req);
40813
+ }
40814
+ getLiveHandle(name) {
40815
+ return this._liveHandles.get(name);
40816
+ }
40817
+ async openSession(name, opts) {
40818
+ const liveHandle = this._liveHandles.get(name);
40819
+ if (liveHandle && liveHandle.agentName === opts.agentName) {
40820
+ const liveDesc = this._findByName(name);
40821
+ if (!liveDesc || liveDesc.state !== "COMPLETED" && liveDesc.state !== "FAILED") {
40822
+ return liveHandle;
40790
40823
  }
40824
+ this._liveHandles.delete(name);
40791
40825
  }
40792
- if (activeStates.size > 0)
40793
- scheduleTickIfNeeded(tickRef, tick, tickIntervalMs);
40826
+ const adapter = this._getAdapter(opts.agentName);
40827
+ if (!adapter) {
40828
+ throw new NaxError(`SessionManager.openSession: no adapter found for agent "${opts.agentName}"`, "ADAPTER_NOT_FOUND", { stage: "session", agentName: opts.agentName });
40829
+ }
40830
+ const resolvedPermissions = resolvePermissions(this._config, opts.pipelineStage);
40831
+ const existingDescriptor = this._findByName(name);
40832
+ const resume = existingDescriptor !== undefined;
40833
+ const handle = await adapter.openSession(name, {
40834
+ agentName: opts.agentName,
40835
+ workdir: opts.workdir,
40836
+ resolvedPermissions,
40837
+ modelDef: opts.modelDef,
40838
+ timeoutSeconds: opts.timeoutSeconds,
40839
+ onPidSpawned: this._pidRegistry ? (pid) => this._pidRegistry?.register(pid) : undefined,
40840
+ onPidExited: this._pidRegistry ? (pid) => this._pidRegistry?.unregister(pid) : undefined,
40841
+ onSessionEstablished: opts.onSessionEstablished,
40842
+ signal: opts.signal,
40843
+ resume,
40844
+ onActiveCall: this._buildOnActiveCall(name),
40845
+ onStreamActivity: this._onStreamActivity
40846
+ });
40847
+ this._liveHandles.set(name, handle);
40848
+ const protocolIds = handle.protocolIds ?? NULL_PROTOCOL_IDS;
40849
+ if (!existingDescriptor) {
40850
+ const created = this.create({
40851
+ role: opts.role ?? "main",
40852
+ agent: opts.agentName,
40853
+ workdir: opts.workdir,
40854
+ featureName: opts.featureName,
40855
+ storyId: opts.storyId,
40856
+ handle: name
40857
+ });
40858
+ this.transition(created.id, "RUNNING", { protocolIds });
40859
+ } else if (existingDescriptor.state === "CREATED") {
40860
+ this.transition(existingDescriptor.id, "RUNNING", { protocolIds });
40861
+ } else if (existingDescriptor.state === "COMPLETED" || existingDescriptor.state === "FAILED") {
40862
+ this._cancelledSessions.delete(name);
40863
+ const updated = {
40864
+ ...existingDescriptor,
40865
+ state: "RUNNING",
40866
+ protocolIds,
40867
+ lastActivityAt: _sessionManagerDeps.now()
40868
+ };
40869
+ this._sessions.set(existingDescriptor.id, updated);
40870
+ this._persistDescriptor(updated);
40871
+ } else {
40872
+ getLogger().warn("session", "openSession called on already-RUNNING session", {
40873
+ storyId: opts.storyId,
40874
+ sessionName: name
40875
+ });
40876
+ }
40877
+ getLogger().debug("session", "Session opened via SessionManager", {
40878
+ storyId: opts.storyId,
40879
+ sessionName: name,
40880
+ agentName: opts.agentName,
40881
+ resume
40882
+ });
40883
+ return handle;
40794
40884
  }
40795
- const unsubscribe = agentStreamEvents.onAgentStream((event) => {
40796
- switch (event.kind) {
40797
- case "agent.call_started": {
40798
- const now = Date.now();
40799
- activeStates.set(event.callId, {
40800
- callId: event.callId,
40801
- agentName: event.agentName,
40802
- sessionName: event.sessionName,
40803
- storyId: event.storyId,
40804
- stage: event.stage,
40805
- pid: event.pid,
40806
- startedAt: now,
40807
- lastActivityAt: now,
40808
- messageUpdates: 0,
40809
- thinkingUpdates: 0,
40810
- usageUpdates: 0,
40811
- cancelAttempts: 0,
40812
- inGracePeriod: false,
40813
- warnedForCurrentIdlePeriod: false
40814
- });
40815
- getSafeLogger()?.debug("idle-watchdog", "Watchdog tracking call", {
40816
- storyId: event.storyId,
40817
- callId: event.callId,
40818
- mode,
40819
- idleTimeoutMs
40885
+ async closeSession(handle) {
40886
+ const desc = this._findByName(handle.id);
40887
+ const adapter = this._getAdapter(handle.agentName);
40888
+ this._liveHandles.delete(handle.id);
40889
+ if (adapter) {
40890
+ try {
40891
+ await adapter.closeSession(handle);
40892
+ } catch (err) {
40893
+ getLogger().warn("session", "adapter.closeSession failed (swallowed)", {
40894
+ storyId: desc?.storyId,
40895
+ sessionName: handle.id,
40896
+ error: err instanceof Error ? err.message : String(err)
40820
40897
  });
40821
- scheduleTickIfNeeded(tickRef, tick, tickIntervalMs);
40822
- break;
40823
- }
40824
- case "agent.message_update": {
40825
- const state = activeStates.get(event.callId);
40826
- if (state && activityKinds.has("message_update")) {
40827
- state.messageUpdates++;
40828
- resetActivity(state, event.timestamp);
40829
- }
40830
- break;
40831
- }
40832
- case "agent.thinking_update": {
40833
- const state = activeStates.get(event.callId);
40834
- if (state && activityKinds.has("thinking_update")) {
40835
- state.thinkingUpdates++;
40836
- resetActivity(state, event.timestamp);
40837
- }
40838
- break;
40839
40898
  }
40840
- case "agent.usage_update": {
40841
- const state = activeStates.get(event.callId);
40842
- if (state && activityKinds.has("usage_update")) {
40843
- state.usageUpdates++;
40844
- resetActivity(state, event.timestamp);
40899
+ }
40900
+ if (desc && desc.state === "RUNNING") {
40901
+ this.transition(desc.id, "COMPLETED");
40902
+ }
40903
+ this._busySessions.delete(handle.id);
40904
+ this._cancelledSessions.delete(handle.id);
40905
+ }
40906
+ async sendPrompt(handle, prompt, opts) {
40907
+ if (this._cancelledSessions.has(handle.id)) {
40908
+ throw new NaxError(`Session "${handle.id}" was cancelled \u2014 close it and open a new session to continue`, "SESSION_CANCELLED", { stage: "session", sessionName: handle.id });
40909
+ }
40910
+ if (this._busySessions.has(handle.id)) {
40911
+ throw new NaxError(`Session "${handle.id}" is already processing a prompt (single-flight invariant)`, "SESSION_BUSY", { stage: "session", sessionName: handle.id });
40912
+ }
40913
+ const terminalDesc = this._findByName(handle.id);
40914
+ if (terminalDesc && (terminalDesc.state === "COMPLETED" || terminalDesc.state === "FAILED")) {
40915
+ throw new NaxError(`Session "${handle.id}" is in terminal state ${terminalDesc.state} \u2014 call openSession first to resume`, "SESSION_TERMINAL_STATE", { stage: "session", sessionName: handle.id, state: terminalDesc.state });
40916
+ }
40917
+ const adapter = this._getAdapter(handle.agentName);
40918
+ if (!adapter) {
40919
+ throw new NaxError(`SessionManager.sendPrompt: no adapter found for agent "${handle.agentName}"`, "ADAPTER_NOT_FOUND", { stage: "session", agentName: handle.agentName });
40920
+ }
40921
+ this._busySessions.add(handle.id);
40922
+ try {
40923
+ const result = await adapter.sendTurn(handle, prompt, {
40924
+ interactionHandler: opts?.interactionHandler ?? NO_OP_INTERACTION_HANDLER,
40925
+ signal: opts?.signal,
40926
+ maxTurns: opts?.maxTurns
40927
+ });
40928
+ return { ...result, protocolIds: result.protocolIds ?? handle.protocolIds };
40929
+ } catch (err) {
40930
+ if (err instanceof SessionTurnError && err.cancelled) {
40931
+ const wasWatchdog = (this._watchdogCancelledCallsBySession.get(handle.id)?.size ?? 0) > 0;
40932
+ if (wasWatchdog) {
40933
+ throw new SessionFailureError("idle watchdog cancelled session \u2014 no stream activity", {
40934
+ category: "availability",
40935
+ outcome: "fail-stale",
40936
+ retriable: true,
40937
+ message: "idle watchdog cancelled session \u2014 no stream activity"
40938
+ });
40845
40939
  }
40846
- break;
40847
40940
  }
40848
- case "agent.process_update":
40849
- break;
40850
- case "agent.call_ended": {
40851
- const state = activeStates.get(event.callId);
40852
- if (state) {
40853
- if (state.graceTimer !== undefined)
40854
- clearTimeout(state.graceTimer);
40855
- activeStates.delete(event.callId);
40856
- }
40857
- if (activeStates.size === 0 && tickRef.handle !== null) {
40858
- clearTimeout(tickRef.handle);
40859
- tickRef.handle = null;
40941
+ if (opts?.signal?.aborted || err instanceof Error && err.name === "AbortError") {
40942
+ this._cancelledSessions.add(handle.id);
40943
+ const desc = this._findByName(handle.id);
40944
+ if (desc && desc.state === "RUNNING") {
40945
+ this.transition(desc.id, "FAILED");
40860
40946
  }
40861
- break;
40862
40947
  }
40948
+ throw err;
40949
+ } finally {
40950
+ this._clearWatchdogCancelledCalls(handle.id);
40951
+ this._busySessions.delete(handle.id);
40863
40952
  }
40864
- });
40865
- return () => {
40866
- unsubscribe();
40867
- for (const state of activeStates.values()) {
40868
- if (state.graceTimer !== undefined)
40869
- clearTimeout(state.graceTimer);
40953
+ }
40954
+ async runInSession(idOrName, promptOrFnOrRunner, optsOrRequest, _legacyOptions) {
40955
+ if (typeof promptOrFnOrRunner === "object" && promptOrFnOrRunner !== null && "run" in promptOrFnOrRunner && typeof promptOrFnOrRunner.run === "function") {
40956
+ return this._runTrackedSession(idOrName, promptOrFnOrRunner, optsOrRequest);
40870
40957
  }
40871
- activeStates.clear();
40872
- if (tickRef.handle !== null) {
40873
- clearTimeout(tickRef.handle);
40874
- tickRef.handle = null;
40958
+ const opts = optsOrRequest;
40959
+ const handle = await this.openSession(idOrName, opts);
40960
+ try {
40961
+ if (typeof promptOrFnOrRunner === "string") {
40962
+ return await this.sendPrompt(handle, promptOrFnOrRunner, {
40963
+ interactionHandler: opts.interactionHandler,
40964
+ signal: opts.signal,
40965
+ maxTurns: opts.maxTurns
40966
+ });
40967
+ }
40968
+ return await promptOrFnOrRunner(handle);
40969
+ } finally {
40970
+ await this.closeSession(handle);
40875
40971
  }
40876
- };
40972
+ }
40973
+ async _runTrackedSession(id, runner, request) {
40974
+ return runTrackedSession({
40975
+ sessions: this._sessions,
40976
+ transition: (sid, to, opts) => this.transition(sid, to, opts),
40977
+ bindHandle: (sid, handle, protocolIds) => this.bindHandle(sid, handle, protocolIds),
40978
+ handoff: (sid, agent, reason) => this.handoff(sid, agent, reason),
40979
+ persistDescriptor: (desc) => this._persistDescriptor(desc),
40980
+ dispatchEvents: this._dispatchEvents,
40981
+ defaultAgent: this._defaultAgent,
40982
+ nameFor: (req) => this.nameFor(req)
40983
+ }, id, runner, request);
40984
+ }
40985
+ sweepOrphans(ttlMs = DEFAULT_ORPHAN_TTL_MS) {
40986
+ return sweepOrphansImpl(this._sessions, ttlMs);
40987
+ }
40877
40988
  }
40878
- var init_idle_watchdog = __esm(() => {
40989
+ var NULL_PROTOCOL_IDS;
40990
+ var init_manager2 = __esm(() => {
40991
+ init_types();
40992
+ init_errors();
40879
40993
  init_logger2();
40994
+ init_dispatch_events();
40995
+ init_no_op_interaction_handler();
40996
+ init_manager_deps();
40997
+ init_manager_run();
40998
+ init_manager_sweep();
40999
+ init_naming();
41000
+ init_types7();
41001
+ init_manager_deps();
41002
+ NULL_PROTOCOL_IDS = { recordId: null, sessionId: null };
40880
41003
  });
40881
41004
 
40882
- // src/runtime/middleware/index.ts
40883
- var init_middleware = __esm(() => {
40884
- init_cancellation();
40885
- init_logging2();
40886
- init_agent_stream_logging();
40887
- init_idle_watchdog();
41005
+ // src/session/index.ts
41006
+ var init_session = __esm(() => {
41007
+ init_manager2();
41008
+ init_naming();
41009
+ init_types7();
40888
41010
  });
40889
41011
 
40890
41012
  // src/runtime/session-run-hop.ts
@@ -40981,6 +41103,8 @@ __export(exports_runtime, {
40981
41103
  createNoOpPromptAuditor: () => createNoOpPromptAuditor,
40982
41104
  createNoOpCostAggregator: () => createNoOpCostAggregator,
40983
41105
  claimProjectIdentity: () => claimProjectIdentity,
41106
+ attachAgentStreamLogging: () => attachAgentStreamLogging,
41107
+ attachAgentIdleWatchdog: () => attachAgentIdleWatchdog,
40984
41108
  _reviewAuditDeps: () => _reviewAuditDeps,
40985
41109
  _promptAuditorDeps: () => _promptAuditorDeps,
40986
41110
  _costAggDeps: () => _costAggDeps,
@@ -41118,6 +41242,7 @@ var init_runtime = __esm(() => {
41118
41242
  init_paths2();
41119
41243
  init_dispatch_events();
41120
41244
  init_agent_stream_events();
41245
+ init_middleware();
41121
41246
  init_factory();
41122
41247
  init_manager();
41123
41248
  init_config();
@@ -43304,12 +43429,6 @@ class PipelineEventEmitter {
43304
43429
  }
43305
43430
  var init_events = () => {};
43306
43431
 
43307
- // src/pipeline/index.ts
43308
- var init_pipeline = __esm(() => {
43309
- init_runner3();
43310
- init_events();
43311
- });
43312
-
43313
43432
  // src/utils/log-test-output.ts
43314
43433
  function logTestOutput(logger, stage, output, opts = {}) {
43315
43434
  if (!logger || !output)
@@ -43532,6 +43651,7 @@ var init_acceptance2 = __esm(() => {
43532
43651
  ];
43533
43652
  const allFailedACs = [];
43534
43653
  const allFindings = [];
43654
+ const failedPackages = [];
43535
43655
  const allOutputParts = [];
43536
43656
  let anyError = false;
43537
43657
  let errorExitCode = 0;
@@ -43586,6 +43706,7 @@ ${stderr}`;
43586
43706
  errorExitCode = exitCode;
43587
43707
  allFailedACs.push("AC-ERROR");
43588
43708
  allFindings.push(acSentinelToFinding("AC-ERROR", output));
43709
+ failedPackages.push({ testPath, packageDir, testFramework, commandOverride });
43589
43710
  continue;
43590
43711
  }
43591
43712
  for (const acId of actualFailures) {
@@ -43595,6 +43716,7 @@ ${stderr}`;
43595
43716
  }
43596
43717
  }
43597
43718
  if (actualFailures.length > 0) {
43719
+ failedPackages.push({ testPath, packageDir, testFramework, commandOverride });
43598
43720
  logger.error("acceptance", "Acceptance tests failed", {
43599
43721
  storyId: ctx.story.id,
43600
43722
  failedACs: actualFailures,
@@ -43648,7 +43770,8 @@ ${stderr}`;
43648
43770
  ctx.acceptanceFailures = {
43649
43771
  failedACs: allFailedACs,
43650
43772
  findings: allFindings,
43651
- testOutput: combinedOutput
43773
+ testOutput: combinedOutput,
43774
+ failedPackages
43652
43775
  };
43653
43776
  logger.info("acceptance", "verdict", {
43654
43777
  storyId: ctx.story.id,
@@ -45306,6 +45429,9 @@ var init_dialogue = __esm(() => {
45306
45429
  function normalizeWs(s) {
45307
45430
  return s.replace(/\s+/g, " ").trim();
45308
45431
  }
45432
+ function stripMarkdownInline(s) {
45433
+ return s.replace(/`/g, "").replace(/\*\*/g, "").replace(/\*/g, "");
45434
+ }
45309
45435
  function extractLocusKeywords(finding) {
45310
45436
  const keywords = [];
45311
45437
  if (finding.file) {
@@ -45335,8 +45461,8 @@ function validateAcQuote(finding, acceptanceCriteria) {
45335
45461
  if (typeof acIndex !== "number" || acIndex < 1 || acIndex > acceptanceCriteria.length) {
45336
45462
  return { valid: false, code: "ac_index_out_of_range" };
45337
45463
  }
45338
- const acText = normalizeWs(acceptanceCriteria[acIndex - 1]);
45339
- const normalizedQuote = normalizeWs(acQuote);
45464
+ const acText = normalizeWs(stripMarkdownInline(acceptanceCriteria[acIndex - 1]));
45465
+ const normalizedQuote = normalizeWs(stripMarkdownInline(acQuote));
45340
45466
  if (!acText.toLowerCase().includes(normalizedQuote.toLowerCase())) {
45341
45467
  return { valid: false, code: "ac_quote_not_substring" };
45342
45468
  }
@@ -50632,8 +50758,8 @@ Category: ${outcome.failureCategory ?? "unknown"}`,
50632
50758
  contextToolRunCounter: ctx.contextToolRunCounter,
50633
50759
  pipelineStage: "run"
50634
50760
  }, ctx.sessionId, baseRunOptions) : undefined;
50635
- const executeHop = hopCallback ? async (agentName, hopBundle, failure, resolvedRunOptions) => {
50636
- const hop = await hopCallback(agentName, hopBundle, failure, resolvedRunOptions);
50761
+ const executeHop = hopCallback ? async (agentName, hopBundle, hopKind, resolvedRunOptions) => {
50762
+ const hop = await hopCallback(agentName, hopBundle, hopKind, resolvedRunOptions);
50637
50763
  finalBundle = hop.bundle ?? finalBundle;
50638
50764
  finalPrompt = hop.prompt;
50639
50765
  return hop;
@@ -52322,7 +52448,8 @@ __export(exports_stages, {
52322
52448
  constitutionStage: () => constitutionStage,
52323
52449
  completionStage: () => completionStage,
52324
52450
  autofixStage: () => autofixStage,
52325
- acceptanceStage: () => acceptanceStage
52451
+ acceptanceStage: () => acceptanceStage,
52452
+ _executionDeps: () => _executionDeps
52326
52453
  });
52327
52454
  var defaultPipeline, postRunPipeline, preRunPipeline;
52328
52455
  var init_stages = __esm(() => {
@@ -52374,6 +52501,13 @@ var init_stages = __esm(() => {
52374
52501
  preRunPipeline = [acceptanceSetupStage];
52375
52502
  });
52376
52503
 
52504
+ // src/pipeline/index.ts
52505
+ var init_pipeline = __esm(() => {
52506
+ init_runner3();
52507
+ init_events();
52508
+ init_stages();
52509
+ });
52510
+
52377
52511
  // src/cli/prompts-shared.ts
52378
52512
  function buildFrontmatter(story, ctx, role) {
52379
52513
  const lines = [];
@@ -55183,7 +55317,7 @@ var package_default;
55183
55317
  var init_package = __esm(() => {
55184
55318
  package_default = {
55185
55319
  name: "@nathapp/nax",
55186
- version: "0.65.5",
55320
+ version: "0.66.0",
55187
55321
  description: "AI Coding Agent Orchestrator \u2014 loops until done",
55188
55322
  type: "module",
55189
55323
  bin: {
@@ -55272,8 +55406,8 @@ var init_version = __esm(() => {
55272
55406
  NAX_VERSION = package_default.version;
55273
55407
  NAX_COMMIT = (() => {
55274
55408
  try {
55275
- if (/^[0-9a-f]{6,10}$/.test("a329264b"))
55276
- return "a329264b";
55409
+ if (/^[0-9a-f]{6,10}$/.test("fee8f22f"))
55410
+ return "fee8f22f";
55277
55411
  } catch {}
55278
55412
  try {
55279
55413
  const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
@@ -55611,6 +55745,11 @@ var init_crash_recovery = __esm(() => {
55611
55745
  init_crash_heartbeat();
55612
55746
  });
55613
55747
 
55748
+ // src/acceptance/fix-generator.ts
55749
+ var init_fix_generator = __esm(() => {
55750
+ init_test_path();
55751
+ });
55752
+
55614
55753
  // src/acceptance/content-loader.ts
55615
55754
  async function loadAcceptanceTestContent(pathsOrFallback) {
55616
55755
  if (!pathsOrFallback)
@@ -55632,6 +55771,15 @@ async function loadAcceptanceTestContent(pathsOrFallback) {
55632
55771
  return [];
55633
55772
  }
55634
55773
 
55774
+ // src/acceptance/index.ts
55775
+ var init_acceptance4 = __esm(() => {
55776
+ init_refinement();
55777
+ init_generator();
55778
+ init_fix_generator();
55779
+ init_semantic_verdict();
55780
+ init_test_path();
55781
+ });
55782
+
55635
55783
  // src/acceptance/fix-diagnosis.ts
55636
55784
  function parseImportStatements(content) {
55637
55785
  const importRegex = /import\s+(?:{[^}]+}|[^;]+)\s+from\s+["']([^"']+)["']/g;
@@ -55876,6 +56024,7 @@ var exports_acceptance_loop = {};
55876
56024
  __export(exports_acceptance_loop, {
55877
56025
  runAcceptanceLoop: () => runAcceptanceLoop,
55878
56026
  runAcceptanceFixCycle: () => runAcceptanceFixCycle,
56027
+ resolveAcceptanceFixTarget: () => resolveAcceptanceFixTarget,
55879
56028
  regenerateAcceptanceTest: () => regenerateAcceptanceTest,
55880
56029
  loadSpecContent: () => loadSpecContent,
55881
56030
  loadAcceptanceTestContent: () => loadAcceptanceTestContent2,
@@ -55886,6 +56035,15 @@ __export(exports_acceptance_loop, {
55886
56035
  _acceptanceLoopDeps: () => _acceptanceLoopDeps,
55887
56036
  _acceptanceFixCycleDeps: () => _acceptanceFixCycleDeps
55888
56037
  });
56038
+ function resolveAcceptanceFixTarget(acceptanceTestPaths, failedPackages, config2) {
56039
+ const failedPackage = failedPackages?.[0];
56040
+ const matchedEntry = failedPackage ? acceptanceTestPaths?.find((entry) => entry.testPath === failedPackage.testPath || entry.packageDir === failedPackage.packageDir) : undefined;
56041
+ const selectedPathEntry = matchedEntry ?? acceptanceTestPaths?.[0];
56042
+ return {
56043
+ acceptanceTestPath: failedPackage?.testPath ?? selectedPathEntry?.testPath ?? "",
56044
+ testCommand: failedPackage?.commandOverride ?? matchedEntry?.commandOverride ?? config2.acceptance.command ?? config2.quality?.commands?.test
56045
+ };
56046
+ }
55889
56047
  function convertFailuresToFindings(failedACs, testOutput) {
55890
56048
  return failedACs.map((ac) => {
55891
56049
  if (ac === "AC-HOOK" || ac === "AC-ERROR") {
@@ -55956,7 +56114,12 @@ async function runAcceptanceTestsOnce(ctx, prd) {
55956
56114
  const failures = acceptanceContext.acceptanceFailures;
55957
56115
  if (!failures || failures.failedACs.length === 0)
55958
56116
  return { passed: true, failedACs: [], testOutput: "" };
55959
- return { passed: false, failedACs: failures.failedACs, testOutput: failures.testOutput };
56117
+ return {
56118
+ passed: false,
56119
+ failedACs: failures.failedACs,
56120
+ testOutput: failures.testOutput,
56121
+ failedPackages: failures.failedPackages
56122
+ };
55960
56123
  }
55961
56124
  async function runAcceptanceFixCycle(ctx, prd, initialFailures, diagnosis, acceptanceTestPath, testCommand) {
55962
56125
  const runtime = ctx.runtime;
@@ -56093,10 +56256,11 @@ async function runAcceptanceLoop(ctx) {
56093
56256
  logger?.error("acceptance", "Runtime not found for diagnosis", { storyId: firstStory?.id });
56094
56257
  return buildResult(false, prd, totalCost, iterations, storiesCompleted, prdDirty, failures.failedACs, acceptanceRetries);
56095
56258
  }
56259
+ const { acceptanceTestPath, testCommand } = resolveAcceptanceFixTarget(ctx.acceptanceTestPaths, failures.failedPackages, ctx.config);
56096
56260
  const testEntries = ctx.acceptanceTestPaths ? await loadAcceptanceTestContent(ctx.acceptanceTestPaths.map((p) => p.testPath)) : [];
56097
- const testFileContent = testEntries[0]?.content ?? "";
56098
- const acceptanceTestPath = testEntries[0]?.testPath ?? ctx.acceptanceTestPaths?.[0]?.testPath ?? "";
56099
- const testCommand = ctx.config.quality?.commands?.test;
56261
+ const effectiveAcceptanceTestPath = acceptanceTestPath || testEntries[0]?.testPath || "";
56262
+ const selectedTestEntry = testEntries.find((entry) => entry.testPath === effectiveAcceptanceTestPath);
56263
+ const testFileContent = selectedTestEntry?.content ?? testEntries[0]?.content ?? "";
56100
56264
  const strategy = ctx.config.acceptance.fix?.strategy ?? "diagnose-first";
56101
56265
  const diagnosis = await resolveAcceptanceDiagnosis({
56102
56266
  ctx,
@@ -56107,7 +56271,7 @@ async function runAcceptanceLoop(ctx) {
56107
56271
  diagnosisOpts: {
56108
56272
  testOutput: failures.testOutput,
56109
56273
  testFileContent,
56110
- acceptanceTestPath,
56274
+ acceptanceTestPath: effectiveAcceptanceTestPath,
56111
56275
  workdir: ctx.workdir,
56112
56276
  storyId: firstStory?.id
56113
56277
  }
@@ -56118,7 +56282,7 @@ async function runAcceptanceLoop(ctx) {
56118
56282
  confidence: diagnosis.confidence,
56119
56283
  attempt: acceptanceRetries
56120
56284
  });
56121
- const cycleResult = await runAcceptanceFixCycle(ctx, prd, failures, diagnosis, acceptanceTestPath, testCommand);
56285
+ const cycleResult = await runAcceptanceFixCycle(ctx, prd, failures, diagnosis, effectiveAcceptanceTestPath, testCommand);
56122
56286
  totalCost += cycleResult.costUsd ?? 0;
56123
56287
  const success2 = cycleResult.exitReason === "resolved" || cycleResult.finalFindings.length === 0;
56124
56288
  return buildResult(success2, prd, totalCost, iterations, storiesCompleted, prdDirty, success2 ? undefined : cycleResult.finalFindings.map((f) => f.message), acceptanceRetries + cycleResult.iterations.length);
@@ -56127,8 +56291,7 @@ async function runAcceptanceLoop(ctx) {
56127
56291
  }
56128
56292
  var _acceptanceLoopDeps, _acceptanceFixCycleDeps, MAX_STUB_REGENS = 2;
56129
56293
  var init_acceptance_loop = __esm(() => {
56130
- init_semantic_verdict();
56131
- init_test_path();
56294
+ init_acceptance4();
56132
56295
  init_findings();
56133
56296
  init_hooks();
56134
56297
  init_logger2();
@@ -57932,9 +58095,9 @@ var _quoteIntegrityDeps, CONTEXT_LINES = 3;
57932
58095
  var init_quote_integrity = __esm(() => {
57933
58096
  init_logger2();
57934
58097
  _quoteIntegrityDeps = {
57935
- readFile: async (path20) => {
58098
+ readFile: async (path21) => {
57936
58099
  try {
57937
- return await Bun.file(path20).text();
58100
+ return await Bun.file(path21).text();
57938
58101
  } catch {
57939
58102
  return null;
57940
58103
  }
@@ -58199,7 +58362,7 @@ var exports_merge_conflict_rectify = {};
58199
58362
  __export(exports_merge_conflict_rectify, {
58200
58363
  rectifyConflictedStory: () => rectifyConflictedStory
58201
58364
  });
58202
- import path20 from "path";
58365
+ import path21 from "path";
58203
58366
  async function closeStaleAcpSession(worktreePath, sessionName) {
58204
58367
  const logger = getSafeLogger();
58205
58368
  try {
@@ -58226,7 +58389,7 @@ async function rectifyConflictedStory(options) {
58226
58389
  await worktreeManager.remove(workdir, storyId);
58227
58390
  } catch {}
58228
58391
  await worktreeManager.create(workdir, storyId);
58229
- const worktreePath = path20.join(workdir, ".nax-wt", storyId);
58392
+ const worktreePath = path21.join(workdir, ".nax-wt", storyId);
58230
58393
  const { formatSessionName: formatSessionName2 } = await Promise.resolve().then(() => (init_naming(), exports_naming));
58231
58394
  const staleSessionName = formatSessionName2({
58232
58395
  workdir: worktreePath,
@@ -58899,7 +59062,7 @@ __export(exports_parallel_batch, {
58899
59062
  runParallelBatch: () => runParallelBatch,
58900
59063
  _parallelBatchDeps: () => _parallelBatchDeps
58901
59064
  });
58902
- import path21 from "path";
59065
+ import path22 from "path";
58903
59066
  async function runParallelBatch(options) {
58904
59067
  const { stories, ctx, prd } = options;
58905
59068
  const { workdir, config: config2, maxConcurrency, pipelineContext, eventEmitter, agentGetFn, hooks, pluginRegistry } = ctx;
@@ -58918,9 +59081,9 @@ async function runParallelBatch(options) {
58918
59081
  });
58919
59082
  throw error48;
58920
59083
  }
58921
- worktreePaths.set(story.id, path21.join(workdir, ".nax-wt", story.id));
59084
+ worktreePaths.set(story.id, path22.join(workdir, ".nax-wt", story.id));
58922
59085
  }
58923
- const rootConfigPath = path21.join(workdir, ".nax", "config.json");
59086
+ const rootConfigPath = path22.join(workdir, ".nax", "config.json");
58924
59087
  const profileOverride = config2.profile && config2.profile !== "default" ? { profile: config2.profile } : undefined;
58925
59088
  const storyEffectiveConfigs = new Map;
58926
59089
  await Promise.all(stories.filter((story) => story.workdir).map(async (story) => {
@@ -59779,7 +59942,7 @@ __export(exports_migrate, {
59779
59942
  });
59780
59943
  import { existsSync as existsSync35 } from "fs";
59781
59944
  import { mkdir as mkdir17, readdir as readdir6, rename as rename3 } from "fs/promises";
59782
- import path22 from "path";
59945
+ import path23 from "path";
59783
59946
  async function detectGeneratedContent(naxDir) {
59784
59947
  if (!existsSync35(naxDir))
59785
59948
  return [];
@@ -59792,17 +59955,17 @@ async function detectGeneratedContent(naxDir) {
59792
59955
  }
59793
59956
  for (const entry of entries) {
59794
59957
  if (GENERATED_NAMES.has(entry)) {
59795
- candidates.push({ name: entry, srcPath: path22.join(naxDir, entry) });
59958
+ candidates.push({ name: entry, srcPath: path23.join(naxDir, entry) });
59796
59959
  }
59797
59960
  }
59798
- const featuresDir = path22.join(naxDir, "features");
59961
+ const featuresDir = path23.join(naxDir, "features");
59799
59962
  if (existsSync35(featuresDir)) {
59800
59963
  let featureDirs = [];
59801
59964
  try {
59802
59965
  featureDirs = await readdir6(featuresDir);
59803
59966
  } catch {}
59804
59967
  for (const fid of featureDirs) {
59805
- const featureDir = path22.join(featuresDir, fid);
59968
+ const featureDir = path23.join(featuresDir, fid);
59806
59969
  let subEntries = [];
59807
59970
  try {
59808
59971
  subEntries = await readdir6(featureDir);
@@ -59812,12 +59975,12 @@ async function detectGeneratedContent(naxDir) {
59812
59975
  for (const sub of subEntries) {
59813
59976
  if (GENERATED_FEATURE_SUBNAMES.has(sub)) {
59814
59977
  candidates.push({
59815
- name: path22.join("features", fid, sub),
59816
- srcPath: path22.join(featureDir, sub)
59978
+ name: path23.join("features", fid, sub),
59979
+ srcPath: path23.join(featureDir, sub)
59817
59980
  });
59818
59981
  }
59819
59982
  if (sub === "stories") {
59820
- const storiesDir = path22.join(featureDir, "stories");
59983
+ const storiesDir = path23.join(featureDir, "stories");
59821
59984
  let storyDirs = [];
59822
59985
  try {
59823
59986
  storyDirs = await readdir6(storiesDir);
@@ -59825,7 +59988,7 @@ async function detectGeneratedContent(naxDir) {
59825
59988
  continue;
59826
59989
  }
59827
59990
  for (const sid of storyDirs) {
59828
- const storyDir = path22.join(storiesDir, sid);
59991
+ const storyDir = path23.join(storiesDir, sid);
59829
59992
  let storyEntries = [];
59830
59993
  try {
59831
59994
  storyEntries = await readdir6(storyDir);
@@ -59835,8 +59998,8 @@ async function detectGeneratedContent(naxDir) {
59835
59998
  for (const se of storyEntries) {
59836
59999
  if (se.startsWith("context-manifest-") && se.endsWith(".json")) {
59837
60000
  candidates.push({
59838
- name: path22.join("features", fid, "stories", sid, se),
59839
- srcPath: path22.join(storyDir, se)
60001
+ name: path23.join("features", fid, "stories", sid, se),
60002
+ srcPath: path23.join(storyDir, se)
59840
60003
  });
59841
60004
  }
59842
60005
  }
@@ -59857,15 +60020,15 @@ async function migrateCommand(options) {
59857
60020
  name: options.reclaim
59858
60021
  });
59859
60022
  }
59860
- const src = path22.join(globalConfigDir(), options.reclaim);
60023
+ const src = path23.join(globalConfigDir(), options.reclaim);
59861
60024
  if (!existsSync35(src)) {
59862
60025
  throw new NaxError(`Nothing to reclaim: ~/.nax/${options.reclaim} does not exist`, "MIGRATE_RECLAIM_NOT_FOUND", {
59863
60026
  stage: "migrate",
59864
60027
  name: options.reclaim
59865
60028
  });
59866
60029
  }
59867
- const archiveBase = path22.join(globalConfigDir(), "_archive");
59868
- const archiveDest = path22.join(archiveBase, `${options.reclaim}-${Date.now()}`);
60030
+ const archiveBase = path23.join(globalConfigDir(), "_archive");
60031
+ const archiveDest = path23.join(archiveBase, `${options.reclaim}-${Date.now()}`);
59869
60032
  await mkdir17(archiveBase, { recursive: true });
59870
60033
  await rename3(src, archiveDest);
59871
60034
  logger.info("migrate", `Reclaimed: archived to ${archiveDest}`, { storyId: "_migrate" });
@@ -59902,8 +60065,8 @@ async function migrateCommand(options) {
59902
60065
  logger.info("migrate", `Merged: identity for "${options.merge}" updated`, { storyId: "_migrate" });
59903
60066
  return;
59904
60067
  }
59905
- const naxDir = path22.join(options.workdir, ".nax");
59906
- const configPath = path22.join(naxDir, "config.json");
60068
+ const naxDir = path23.join(options.workdir, ".nax");
60069
+ const configPath = path23.join(naxDir, "config.json");
59907
60070
  if (!existsSync35(configPath)) {
59908
60071
  throw new NaxError("No .nax/config.json found \u2014 run nax init first", "MIGRATE_NO_CONFIG", {
59909
60072
  stage: "migrate",
@@ -59919,7 +60082,7 @@ async function migrateCommand(options) {
59919
60082
  cause: e
59920
60083
  });
59921
60084
  }
59922
- const projectKey = config2.name?.trim() || path22.basename(options.workdir);
60085
+ const projectKey = config2.name?.trim() || path23.basename(options.workdir);
59923
60086
  const destBase = projectOutputDir(projectKey, config2.outputDir);
59924
60087
  const candidates = await detectGeneratedContent(naxDir);
59925
60088
  if (candidates.length === 0) {
@@ -59928,7 +60091,7 @@ async function migrateCommand(options) {
59928
60091
  }
59929
60092
  if (options.dryRun) {
59930
60093
  for (const c of candidates) {
59931
- logger.info("migrate", `[dry-run] Would move: ${c.srcPath} -> ${path22.join(destBase, c.name)}`, {
60094
+ logger.info("migrate", `[dry-run] Would move: ${c.srcPath} -> ${path23.join(destBase, c.name)}`, {
59932
60095
  storyId: "_migrate"
59933
60096
  });
59934
60097
  }
@@ -59937,8 +60100,8 @@ async function migrateCommand(options) {
59937
60100
  await mkdir17(destBase, { recursive: true });
59938
60101
  let moved = 0;
59939
60102
  for (const candidate of candidates) {
59940
- const dest = path22.join(destBase, candidate.name);
59941
- await mkdir17(path22.dirname(dest), { recursive: true });
60103
+ const dest = path23.join(destBase, candidate.name);
60104
+ await mkdir17(path23.dirname(dest), { recursive: true });
59942
60105
  if (existsSync35(dest)) {
59943
60106
  throw new NaxError(`Migration conflict: destination already exists.
59944
60107
  Source: ${candidate.srcPath}
@@ -59968,7 +60131,7 @@ async function migrateCommand(options) {
59968
60131
  moved++;
59969
60132
  logger.info("migrate", `Moved: ${candidate.name}`, { storyId: "_migrate" });
59970
60133
  }
59971
- await Bun.write(path22.join(destBase, ".migrated-from"), JSON.stringify({ from: options.workdir, migratedAt: new Date().toISOString() }, null, 2));
60134
+ await Bun.write(path23.join(destBase, ".migrated-from"), JSON.stringify({ from: options.workdir, migratedAt: new Date().toISOString() }, null, 2));
59972
60135
  logger.info("migrate", `Migration complete: ${moved} entries moved`, {
59973
60136
  storyId: "_migrate",
59974
60137
  destBase
@@ -60085,7 +60248,7 @@ __export(exports_precheck_runner, {
60085
60248
  runPrecheckValidation: () => runPrecheckValidation
60086
60249
  });
60087
60250
  import { mkdirSync as mkdirSync6 } from "fs";
60088
- import path23 from "path";
60251
+ import path24 from "path";
60089
60252
  async function runPrecheckValidation(ctx) {
60090
60253
  const logger = getSafeLogger();
60091
60254
  if (process.env.NAX_PRECHECK !== "1") {
@@ -60100,7 +60263,7 @@ async function runPrecheckValidation(ctx) {
60100
60263
  silent: true
60101
60264
  });
60102
60265
  if (ctx.logFilePath) {
60103
- mkdirSync6(path23.dirname(ctx.logFilePath), { recursive: true });
60266
+ mkdirSync6(path24.dirname(ctx.logFilePath), { recursive: true });
60104
60267
  const precheckLog = {
60105
60268
  type: "precheck",
60106
60269
  timestamp: new Date().toISOString(),
@@ -60401,7 +60564,7 @@ __export(exports_run_setup, {
60401
60564
  setupRun: () => setupRun,
60402
60565
  _runSetupDeps: () => _runSetupDeps
60403
60566
  });
60404
- import path24 from "path";
60567
+ import path25 from "path";
60405
60568
  function warnFallbackMisconfiguration(config2, agentGetFn, logger) {
60406
60569
  if (!agentGetFn)
60407
60570
  return;
@@ -60488,7 +60651,7 @@ async function setupRun(options) {
60488
60651
  statusWriter.setPrd(prd);
60489
60652
  {
60490
60653
  const { detectGeneratedContent: detectGeneratedContent2, migrateCommand: migrateCommand2 } = await Promise.resolve().then(() => (init_migrate(), exports_migrate));
60491
- const naxDir = path24.join(workdir, ".nax");
60654
+ const naxDir = path25.join(workdir, ".nax");
60492
60655
  const candidates = await detectGeneratedContent2(naxDir).catch(() => []);
60493
60656
  if (candidates.length > 0) {
60494
60657
  logger?.info("setup", "Found generated content under .nax/ \u2014 migrating to output dir", {
@@ -60515,7 +60678,7 @@ async function setupRun(options) {
60515
60678
  remoteUrl = new TextDecoder().decode(gitResult.stdout).trim() || null;
60516
60679
  }
60517
60680
  } catch {}
60518
- const projectKey = config2.name?.trim() || path24.basename(workdir);
60681
+ const projectKey = config2.name?.trim() || path25.basename(workdir);
60519
60682
  await claimProjectIdentity2(projectKey, workdir, remoteUrl).catch((err) => {
60520
60683
  if (err instanceof NaxError && err.code === "RUN_NAME_COLLISION") {
60521
60684
  throw err;
@@ -60570,8 +60733,8 @@ async function setupRun(options) {
60570
60733
  explicit: Object.fromEntries(explicitFields.map((f) => [f, existingProjectConfig[f]])),
60571
60734
  detected: Object.fromEntries(autodetectedFields.map((f) => [f, detectedProfile[f]]))
60572
60735
  });
60573
- const globalPluginsDir = path24.join(globalConfigDir(), "plugins");
60574
- const projectPluginsDir = path24.join(workdir, ".nax", "plugins");
60736
+ const globalPluginsDir = path25.join(globalConfigDir(), "plugins");
60737
+ const projectPluginsDir = path25.join(workdir, ".nax", "plugins");
60575
60738
  const configPlugins = config2.plugins || [];
60576
60739
  const resolvedPatterns = await resolveTestFilePatterns(config2, workdir);
60577
60740
  const isTestFileFn = (filename) => resolvedPatterns.regex.some((re) => re.test(filename));
@@ -62062,11 +62225,11 @@ var require_react_reconciler_development = __commonJS((exports, module) => {
62062
62225
  fiber = fiber.next, id--;
62063
62226
  return fiber;
62064
62227
  }
62065
- function copyWithSetImpl(obj, path25, index, value) {
62066
- if (index >= path25.length)
62228
+ function copyWithSetImpl(obj, path26, index, value) {
62229
+ if (index >= path26.length)
62067
62230
  return value;
62068
- var key = path25[index], updated = isArrayImpl(obj) ? obj.slice() : assign2({}, obj);
62069
- updated[key] = copyWithSetImpl(obj[key], path25, index + 1, value);
62231
+ var key = path26[index], updated = isArrayImpl(obj) ? obj.slice() : assign2({}, obj);
62232
+ updated[key] = copyWithSetImpl(obj[key], path26, index + 1, value);
62070
62233
  return updated;
62071
62234
  }
62072
62235
  function copyWithRename(obj, oldPath, newPath) {
@@ -62086,11 +62249,11 @@ var require_react_reconciler_development = __commonJS((exports, module) => {
62086
62249
  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);
62087
62250
  return updated;
62088
62251
  }
62089
- function copyWithDeleteImpl(obj, path25, index) {
62090
- var key = path25[index], updated = isArrayImpl(obj) ? obj.slice() : assign2({}, obj);
62091
- if (index + 1 === path25.length)
62252
+ function copyWithDeleteImpl(obj, path26, index) {
62253
+ var key = path26[index], updated = isArrayImpl(obj) ? obj.slice() : assign2({}, obj);
62254
+ if (index + 1 === path26.length)
62092
62255
  return isArrayImpl(updated) ? updated.splice(key, 1) : delete updated[key], updated;
62093
- updated[key] = copyWithDeleteImpl(obj[key], path25, index + 1);
62256
+ updated[key] = copyWithDeleteImpl(obj[key], path26, index + 1);
62094
62257
  return updated;
62095
62258
  }
62096
62259
  function shouldSuspendImpl() {
@@ -72113,29 +72276,29 @@ Check the top-level render call using <` + componentName2 + ">.");
72113
72276
  var didWarnAboutNestedUpdates = false;
72114
72277
  var didWarnAboutFindNodeInStrictMode = {};
72115
72278
  var overrideHookState = null, overrideHookStateDeletePath = null, overrideHookStateRenamePath = null, overrideProps = null, overridePropsDeletePath = null, overridePropsRenamePath = null, scheduleUpdate = null, scheduleRetry = null, setErrorHandler = null, setSuspenseHandler = null;
72116
- overrideHookState = function(fiber, id, path25, value) {
72279
+ overrideHookState = function(fiber, id, path26, value) {
72117
72280
  id = findHook(fiber, id);
72118
- 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));
72281
+ 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));
72119
72282
  };
72120
- overrideHookStateDeletePath = function(fiber, id, path25) {
72283
+ overrideHookStateDeletePath = function(fiber, id, path26) {
72121
72284
  id = findHook(fiber, id);
72122
- 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));
72285
+ 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));
72123
72286
  };
72124
72287
  overrideHookStateRenamePath = function(fiber, id, oldPath, newPath) {
72125
72288
  id = findHook(fiber, id);
72126
72289
  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));
72127
72290
  };
72128
- overrideProps = function(fiber, path25, value) {
72129
- fiber.pendingProps = copyWithSetImpl(fiber.memoizedProps, path25, 0, value);
72291
+ overrideProps = function(fiber, path26, value) {
72292
+ fiber.pendingProps = copyWithSetImpl(fiber.memoizedProps, path26, 0, value);
72130
72293
  fiber.alternate && (fiber.alternate.pendingProps = fiber.pendingProps);
72131
- path25 = enqueueConcurrentRenderForLane(fiber, 2);
72132
- path25 !== null && scheduleUpdateOnFiber(path25, fiber, 2);
72294
+ path26 = enqueueConcurrentRenderForLane(fiber, 2);
72295
+ path26 !== null && scheduleUpdateOnFiber(path26, fiber, 2);
72133
72296
  };
72134
- overridePropsDeletePath = function(fiber, path25) {
72135
- fiber.pendingProps = copyWithDeleteImpl(fiber.memoizedProps, path25, 0);
72297
+ overridePropsDeletePath = function(fiber, path26) {
72298
+ fiber.pendingProps = copyWithDeleteImpl(fiber.memoizedProps, path26, 0);
72136
72299
  fiber.alternate && (fiber.alternate.pendingProps = fiber.pendingProps);
72137
- path25 = enqueueConcurrentRenderForLane(fiber, 2);
72138
- path25 !== null && scheduleUpdateOnFiber(path25, fiber, 2);
72300
+ path26 = enqueueConcurrentRenderForLane(fiber, 2);
72301
+ path26 !== null && scheduleUpdateOnFiber(path26, fiber, 2);
72139
72302
  };
72140
72303
  overridePropsRenamePath = function(fiber, oldPath, newPath) {
72141
72304
  fiber.pendingProps = copyWithRename(fiber.memoizedProps, oldPath, newPath);
@@ -76190,8 +76353,8 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
76190
76353
  }
76191
76354
  return false;
76192
76355
  }
76193
- function utils_getInObject(object2, path25) {
76194
- return path25.reduce(function(reduced, attr) {
76356
+ function utils_getInObject(object2, path26) {
76357
+ return path26.reduce(function(reduced, attr) {
76195
76358
  if (reduced) {
76196
76359
  if (utils_hasOwnProperty.call(reduced, attr)) {
76197
76360
  return reduced[attr];
@@ -76203,11 +76366,11 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
76203
76366
  return null;
76204
76367
  }, object2);
76205
76368
  }
76206
- function deletePathInObject(object2, path25) {
76207
- var length = path25.length;
76208
- var last2 = path25[length - 1];
76369
+ function deletePathInObject(object2, path26) {
76370
+ var length = path26.length;
76371
+ var last2 = path26[length - 1];
76209
76372
  if (object2 != null) {
76210
- var parent = utils_getInObject(object2, path25.slice(0, length - 1));
76373
+ var parent = utils_getInObject(object2, path26.slice(0, length - 1));
76211
76374
  if (parent) {
76212
76375
  if (src_isArray(parent)) {
76213
76376
  parent.splice(last2, 1);
@@ -76233,11 +76396,11 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
76233
76396
  }
76234
76397
  }
76235
76398
  }
76236
- function utils_setInObject(object2, path25, value) {
76237
- var length = path25.length;
76238
- var last2 = path25[length - 1];
76399
+ function utils_setInObject(object2, path26, value) {
76400
+ var length = path26.length;
76401
+ var last2 = path26[length - 1];
76239
76402
  if (object2 != null) {
76240
- var parent = utils_getInObject(object2, path25.slice(0, length - 1));
76403
+ var parent = utils_getInObject(object2, path26.slice(0, length - 1));
76241
76404
  if (parent) {
76242
76405
  parent[last2] = value;
76243
76406
  }
@@ -76768,8 +76931,8 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
76768
76931
  unserializable: Symbol("unserializable")
76769
76932
  };
76770
76933
  var LEVEL_THRESHOLD = 2;
76771
- function createDehydrated(type, inspectable, data, cleaned, path25) {
76772
- cleaned.push(path25);
76934
+ function createDehydrated(type, inspectable, data, cleaned, path26) {
76935
+ cleaned.push(path26);
76773
76936
  var dehydrated = {
76774
76937
  inspectable,
76775
76938
  type,
@@ -76787,13 +76950,13 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
76787
76950
  }
76788
76951
  return dehydrated;
76789
76952
  }
76790
- function dehydrate(data, cleaned, unserializable, path25, isPathAllowed) {
76953
+ function dehydrate(data, cleaned, unserializable, path26, isPathAllowed) {
76791
76954
  var level = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 0;
76792
76955
  var type = getDataType(data);
76793
76956
  var isPathAllowedCheck;
76794
76957
  switch (type) {
76795
76958
  case "html_element":
76796
- cleaned.push(path25);
76959
+ cleaned.push(path26);
76797
76960
  return {
76798
76961
  inspectable: false,
76799
76962
  preview_short: formatDataForPreview(data, false),
@@ -76802,7 +76965,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
76802
76965
  type
76803
76966
  };
76804
76967
  case "function":
76805
- cleaned.push(path25);
76968
+ cleaned.push(path26);
76806
76969
  return {
76807
76970
  inspectable: false,
76808
76971
  preview_short: formatDataForPreview(data, false),
@@ -76811,14 +76974,14 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
76811
76974
  type
76812
76975
  };
76813
76976
  case "string":
76814
- isPathAllowedCheck = isPathAllowed(path25);
76977
+ isPathAllowedCheck = isPathAllowed(path26);
76815
76978
  if (isPathAllowedCheck) {
76816
76979
  return data;
76817
76980
  } else {
76818
76981
  return data.length <= 500 ? data : data.slice(0, 500) + "...";
76819
76982
  }
76820
76983
  case "bigint":
76821
- cleaned.push(path25);
76984
+ cleaned.push(path26);
76822
76985
  return {
76823
76986
  inspectable: false,
76824
76987
  preview_short: formatDataForPreview(data, false),
@@ -76827,7 +76990,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
76827
76990
  type
76828
76991
  };
76829
76992
  case "symbol":
76830
- cleaned.push(path25);
76993
+ cleaned.push(path26);
76831
76994
  return {
76832
76995
  inspectable: false,
76833
76996
  preview_short: formatDataForPreview(data, false),
@@ -76836,9 +76999,9 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
76836
76999
  type
76837
77000
  };
76838
77001
  case "react_element": {
76839
- isPathAllowedCheck = isPathAllowed(path25);
77002
+ isPathAllowedCheck = isPathAllowed(path26);
76840
77003
  if (level >= LEVEL_THRESHOLD && !isPathAllowedCheck) {
76841
- cleaned.push(path25);
77004
+ cleaned.push(path26);
76842
77005
  return {
76843
77006
  inspectable: true,
76844
77007
  preview_short: formatDataForPreview(data, false),
@@ -76855,19 +77018,19 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
76855
77018
  preview_long: formatDataForPreview(data, true),
76856
77019
  name: getDisplayNameForReactElement(data) || "Unknown"
76857
77020
  };
76858
- unserializableValue.key = dehydrate(data.key, cleaned, unserializable, path25.concat(["key"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
77021
+ unserializableValue.key = dehydrate(data.key, cleaned, unserializable, path26.concat(["key"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
76859
77022
  if (data.$$typeof === REACT_LEGACY_ELEMENT_TYPE) {
76860
- unserializableValue.ref = dehydrate(data.ref, cleaned, unserializable, path25.concat(["ref"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
77023
+ unserializableValue.ref = dehydrate(data.ref, cleaned, unserializable, path26.concat(["ref"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
76861
77024
  }
76862
- unserializableValue.props = dehydrate(data.props, cleaned, unserializable, path25.concat(["props"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
76863
- unserializable.push(path25);
77025
+ unserializableValue.props = dehydrate(data.props, cleaned, unserializable, path26.concat(["props"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
77026
+ unserializable.push(path26);
76864
77027
  return unserializableValue;
76865
77028
  }
76866
77029
  case "react_lazy": {
76867
- isPathAllowedCheck = isPathAllowed(path25);
77030
+ isPathAllowedCheck = isPathAllowed(path26);
76868
77031
  var payload = data._payload;
76869
77032
  if (level >= LEVEL_THRESHOLD && !isPathAllowedCheck) {
76870
- cleaned.push(path25);
77033
+ cleaned.push(path26);
76871
77034
  var inspectable = payload !== null && hydration_typeof(payload) === "object" && (payload._status === 1 || payload._status === 2 || payload.status === "fulfilled" || payload.status === "rejected");
76872
77035
  return {
76873
77036
  inspectable,
@@ -76884,13 +77047,13 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
76884
77047
  preview_long: formatDataForPreview(data, true),
76885
77048
  name: "lazy()"
76886
77049
  };
76887
- _unserializableValue._payload = dehydrate(payload, cleaned, unserializable, path25.concat(["_payload"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
76888
- unserializable.push(path25);
77050
+ _unserializableValue._payload = dehydrate(payload, cleaned, unserializable, path26.concat(["_payload"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
77051
+ unserializable.push(path26);
76889
77052
  return _unserializableValue;
76890
77053
  }
76891
77054
  case "array_buffer":
76892
77055
  case "data_view":
76893
- cleaned.push(path25);
77056
+ cleaned.push(path26);
76894
77057
  return {
76895
77058
  inspectable: false,
76896
77059
  preview_short: formatDataForPreview(data, false),
@@ -76900,21 +77063,21 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
76900
77063
  type
76901
77064
  };
76902
77065
  case "array":
76903
- isPathAllowedCheck = isPathAllowed(path25);
77066
+ isPathAllowedCheck = isPathAllowed(path26);
76904
77067
  if (level >= LEVEL_THRESHOLD && !isPathAllowedCheck) {
76905
- return createDehydrated(type, true, data, cleaned, path25);
77068
+ return createDehydrated(type, true, data, cleaned, path26);
76906
77069
  }
76907
77070
  var arr = [];
76908
77071
  for (var i = 0;i < data.length; i++) {
76909
- arr[i] = dehydrateKey(data, i, cleaned, unserializable, path25.concat([i]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
77072
+ arr[i] = dehydrateKey(data, i, cleaned, unserializable, path26.concat([i]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
76910
77073
  }
76911
77074
  return arr;
76912
77075
  case "html_all_collection":
76913
77076
  case "typed_array":
76914
77077
  case "iterator":
76915
- isPathAllowedCheck = isPathAllowed(path25);
77078
+ isPathAllowedCheck = isPathAllowed(path26);
76916
77079
  if (level >= LEVEL_THRESHOLD && !isPathAllowedCheck) {
76917
- return createDehydrated(type, true, data, cleaned, path25);
77080
+ return createDehydrated(type, true, data, cleaned, path26);
76918
77081
  } else {
76919
77082
  var _unserializableValue2 = {
76920
77083
  unserializable: true,
@@ -76926,13 +77089,13 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
76926
77089
  name: typeof data.constructor !== "function" || typeof data.constructor.name !== "string" || data.constructor.name === "Object" ? "" : data.constructor.name
76927
77090
  };
76928
77091
  Array.from(data).forEach(function(item, i2) {
76929
- return _unserializableValue2[i2] = dehydrate(item, cleaned, unserializable, path25.concat([i2]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
77092
+ return _unserializableValue2[i2] = dehydrate(item, cleaned, unserializable, path26.concat([i2]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
76930
77093
  });
76931
- unserializable.push(path25);
77094
+ unserializable.push(path26);
76932
77095
  return _unserializableValue2;
76933
77096
  }
76934
77097
  case "opaque_iterator":
76935
- cleaned.push(path25);
77098
+ cleaned.push(path26);
76936
77099
  return {
76937
77100
  inspectable: false,
76938
77101
  preview_short: formatDataForPreview(data, false),
@@ -76941,7 +77104,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
76941
77104
  type
76942
77105
  };
76943
77106
  case "date":
76944
- cleaned.push(path25);
77107
+ cleaned.push(path26);
76945
77108
  return {
76946
77109
  inspectable: false,
76947
77110
  preview_short: formatDataForPreview(data, false),
@@ -76950,7 +77113,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
76950
77113
  type
76951
77114
  };
76952
77115
  case "regexp":
76953
- cleaned.push(path25);
77116
+ cleaned.push(path26);
76954
77117
  return {
76955
77118
  inspectable: false,
76956
77119
  preview_short: formatDataForPreview(data, false),
@@ -76959,9 +77122,9 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
76959
77122
  type
76960
77123
  };
76961
77124
  case "thenable":
76962
- isPathAllowedCheck = isPathAllowed(path25);
77125
+ isPathAllowedCheck = isPathAllowed(path26);
76963
77126
  if (level >= LEVEL_THRESHOLD && !isPathAllowedCheck) {
76964
- cleaned.push(path25);
77127
+ cleaned.push(path26);
76965
77128
  return {
76966
77129
  inspectable: data.status === "fulfilled" || data.status === "rejected",
76967
77130
  preview_short: formatDataForPreview(data, false),
@@ -76982,8 +77145,8 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
76982
77145
  preview_long: formatDataForPreview(data, true),
76983
77146
  name: "fulfilled Thenable"
76984
77147
  };
76985
- _unserializableValue3.value = dehydrate(data.value, cleaned, unserializable, path25.concat(["value"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
76986
- unserializable.push(path25);
77148
+ _unserializableValue3.value = dehydrate(data.value, cleaned, unserializable, path26.concat(["value"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
77149
+ unserializable.push(path26);
76987
77150
  return _unserializableValue3;
76988
77151
  }
76989
77152
  case "rejected": {
@@ -76994,12 +77157,12 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
76994
77157
  preview_long: formatDataForPreview(data, true),
76995
77158
  name: "rejected Thenable"
76996
77159
  };
76997
- _unserializableValue4.reason = dehydrate(data.reason, cleaned, unserializable, path25.concat(["reason"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
76998
- unserializable.push(path25);
77160
+ _unserializableValue4.reason = dehydrate(data.reason, cleaned, unserializable, path26.concat(["reason"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
77161
+ unserializable.push(path26);
76999
77162
  return _unserializableValue4;
77000
77163
  }
77001
77164
  default:
77002
- cleaned.push(path25);
77165
+ cleaned.push(path26);
77003
77166
  return {
77004
77167
  inspectable: false,
77005
77168
  preview_short: formatDataForPreview(data, false),
@@ -77009,21 +77172,21 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
77009
77172
  };
77010
77173
  }
77011
77174
  case "object":
77012
- isPathAllowedCheck = isPathAllowed(path25);
77175
+ isPathAllowedCheck = isPathAllowed(path26);
77013
77176
  if (level >= LEVEL_THRESHOLD && !isPathAllowedCheck) {
77014
- return createDehydrated(type, true, data, cleaned, path25);
77177
+ return createDehydrated(type, true, data, cleaned, path26);
77015
77178
  } else {
77016
77179
  var object2 = {};
77017
77180
  getAllEnumerableKeys(data).forEach(function(key) {
77018
77181
  var name = key.toString();
77019
- object2[name] = dehydrateKey(data, key, cleaned, unserializable, path25.concat([name]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
77182
+ object2[name] = dehydrateKey(data, key, cleaned, unserializable, path26.concat([name]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
77020
77183
  });
77021
77184
  return object2;
77022
77185
  }
77023
77186
  case "class_instance": {
77024
- isPathAllowedCheck = isPathAllowed(path25);
77187
+ isPathAllowedCheck = isPathAllowed(path26);
77025
77188
  if (level >= LEVEL_THRESHOLD && !isPathAllowedCheck) {
77026
- return createDehydrated(type, true, data, cleaned, path25);
77189
+ return createDehydrated(type, true, data, cleaned, path26);
77027
77190
  }
77028
77191
  var value = {
77029
77192
  unserializable: true,
@@ -77035,15 +77198,15 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
77035
77198
  };
77036
77199
  getAllEnumerableKeys(data).forEach(function(key) {
77037
77200
  var keyAsString = key.toString();
77038
- value[keyAsString] = dehydrate(data[key], cleaned, unserializable, path25.concat([keyAsString]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
77201
+ value[keyAsString] = dehydrate(data[key], cleaned, unserializable, path26.concat([keyAsString]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
77039
77202
  });
77040
- unserializable.push(path25);
77203
+ unserializable.push(path26);
77041
77204
  return value;
77042
77205
  }
77043
77206
  case "error": {
77044
- isPathAllowedCheck = isPathAllowed(path25);
77207
+ isPathAllowedCheck = isPathAllowed(path26);
77045
77208
  if (level >= LEVEL_THRESHOLD && !isPathAllowedCheck) {
77046
- return createDehydrated(type, true, data, cleaned, path25);
77209
+ return createDehydrated(type, true, data, cleaned, path26);
77047
77210
  }
77048
77211
  var _value = {
77049
77212
  unserializable: true,
@@ -77053,22 +77216,22 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
77053
77216
  preview_long: formatDataForPreview(data, true),
77054
77217
  name: data.name
77055
77218
  };
77056
- _value.message = dehydrate(data.message, cleaned, unserializable, path25.concat(["message"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
77057
- _value.stack = dehydrate(data.stack, cleaned, unserializable, path25.concat(["stack"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
77219
+ _value.message = dehydrate(data.message, cleaned, unserializable, path26.concat(["message"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
77220
+ _value.stack = dehydrate(data.stack, cleaned, unserializable, path26.concat(["stack"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
77058
77221
  if ("cause" in data) {
77059
- _value.cause = dehydrate(data.cause, cleaned, unserializable, path25.concat(["cause"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
77222
+ _value.cause = dehydrate(data.cause, cleaned, unserializable, path26.concat(["cause"]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
77060
77223
  }
77061
77224
  getAllEnumerableKeys(data).forEach(function(key) {
77062
77225
  var keyAsString = key.toString();
77063
- _value[keyAsString] = dehydrate(data[key], cleaned, unserializable, path25.concat([keyAsString]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
77226
+ _value[keyAsString] = dehydrate(data[key], cleaned, unserializable, path26.concat([keyAsString]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1);
77064
77227
  });
77065
- unserializable.push(path25);
77228
+ unserializable.push(path26);
77066
77229
  return _value;
77067
77230
  }
77068
77231
  case "infinity":
77069
77232
  case "nan":
77070
77233
  case "undefined":
77071
- cleaned.push(path25);
77234
+ cleaned.push(path26);
77072
77235
  return {
77073
77236
  type
77074
77237
  };
@@ -77076,10 +77239,10 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
77076
77239
  return data;
77077
77240
  }
77078
77241
  }
77079
- function dehydrateKey(parent, key, cleaned, unserializable, path25, isPathAllowed) {
77242
+ function dehydrateKey(parent, key, cleaned, unserializable, path26, isPathAllowed) {
77080
77243
  var level = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : 0;
77081
77244
  try {
77082
- return dehydrate(parent[key], cleaned, unserializable, path25, isPathAllowed, level);
77245
+ return dehydrate(parent[key], cleaned, unserializable, path26, isPathAllowed, level);
77083
77246
  } catch (error48) {
77084
77247
  var preview = "";
77085
77248
  if (hydration_typeof(error48) === "object" && error48 !== null && typeof error48.stack === "string") {
@@ -77087,7 +77250,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
77087
77250
  } else if (typeof error48 === "string") {
77088
77251
  preview = error48;
77089
77252
  }
77090
- cleaned.push(path25);
77253
+ cleaned.push(path26);
77091
77254
  return {
77092
77255
  inspectable: false,
77093
77256
  preview_short: "[Exception]",
@@ -77097,8 +77260,8 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
77097
77260
  };
77098
77261
  }
77099
77262
  }
77100
- function fillInPath(object2, data, path25, value) {
77101
- var target = getInObject(object2, path25);
77263
+ function fillInPath(object2, data, path26, value) {
77264
+ var target = getInObject(object2, path26);
77102
77265
  if (target != null) {
77103
77266
  if (!target[meta3.unserializable]) {
77104
77267
  delete target[meta3.inspectable];
@@ -77113,9 +77276,9 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
77113
77276
  }
77114
77277
  if (value !== null && data.unserializable.length > 0) {
77115
77278
  var unserializablePath = data.unserializable[0];
77116
- var isMatch2 = unserializablePath.length === path25.length;
77117
- for (var i = 0;i < path25.length; i++) {
77118
- if (path25[i] !== unserializablePath[i]) {
77279
+ var isMatch2 = unserializablePath.length === path26.length;
77280
+ for (var i = 0;i < path26.length; i++) {
77281
+ if (path26[i] !== unserializablePath[i]) {
77119
77282
  isMatch2 = false;
77120
77283
  break;
77121
77284
  }
@@ -77124,13 +77287,13 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
77124
77287
  upgradeUnserializable(value, value);
77125
77288
  }
77126
77289
  }
77127
- setInObject(object2, path25, value);
77290
+ setInObject(object2, path26, value);
77128
77291
  }
77129
77292
  function hydrate(object2, cleaned, unserializable) {
77130
- cleaned.forEach(function(path25) {
77131
- var length = path25.length;
77132
- var last2 = path25[length - 1];
77133
- var parent = getInObject(object2, path25.slice(0, length - 1));
77293
+ cleaned.forEach(function(path26) {
77294
+ var length = path26.length;
77295
+ var last2 = path26[length - 1];
77296
+ var parent = getInObject(object2, path26.slice(0, length - 1));
77134
77297
  if (!parent || !parent.hasOwnProperty(last2)) {
77135
77298
  return;
77136
77299
  }
@@ -77156,10 +77319,10 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
77156
77319
  parent[last2] = replaced;
77157
77320
  }
77158
77321
  });
77159
- unserializable.forEach(function(path25) {
77160
- var length = path25.length;
77161
- var last2 = path25[length - 1];
77162
- var parent = getInObject(object2, path25.slice(0, length - 1));
77322
+ unserializable.forEach(function(path26) {
77323
+ var length = path26.length;
77324
+ var last2 = path26[length - 1];
77325
+ var parent = getInObject(object2, path26.slice(0, length - 1));
77163
77326
  if (!parent || !parent.hasOwnProperty(last2)) {
77164
77327
  return;
77165
77328
  }
@@ -77280,11 +77443,11 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
77280
77443
  return gte2(version2, FIRST_DEVTOOLS_BACKEND_LOCKSTEP_VER);
77281
77444
  }
77282
77445
  function cleanForBridge(data, isPathAllowed) {
77283
- var path25 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
77446
+ var path26 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
77284
77447
  if (data !== null) {
77285
77448
  var cleanedPaths = [];
77286
77449
  var unserializablePaths = [];
77287
- var cleanedData = dehydrate(data, cleanedPaths, unserializablePaths, path25, isPathAllowed);
77450
+ var cleanedData = dehydrate(data, cleanedPaths, unserializablePaths, path26, isPathAllowed);
77288
77451
  return {
77289
77452
  data: cleanedData,
77290
77453
  cleaned: cleanedPaths,
@@ -77294,18 +77457,18 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
77294
77457
  return null;
77295
77458
  }
77296
77459
  }
77297
- function copyWithDelete(obj, path25) {
77460
+ function copyWithDelete(obj, path26) {
77298
77461
  var index = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
77299
- var key = path25[index];
77462
+ var key = path26[index];
77300
77463
  var updated = shared_isArray(obj) ? obj.slice() : utils_objectSpread({}, obj);
77301
- if (index + 1 === path25.length) {
77464
+ if (index + 1 === path26.length) {
77302
77465
  if (shared_isArray(updated)) {
77303
77466
  updated.splice(key, 1);
77304
77467
  } else {
77305
77468
  delete updated[key];
77306
77469
  }
77307
77470
  } else {
77308
- updated[key] = copyWithDelete(obj[key], path25, index + 1);
77471
+ updated[key] = copyWithDelete(obj[key], path26, index + 1);
77309
77472
  }
77310
77473
  return updated;
77311
77474
  }
@@ -77326,14 +77489,14 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
77326
77489
  }
77327
77490
  return updated;
77328
77491
  }
77329
- function copyWithSet(obj, path25, value) {
77492
+ function copyWithSet(obj, path26, value) {
77330
77493
  var index = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
77331
- if (index >= path25.length) {
77494
+ if (index >= path26.length) {
77332
77495
  return value;
77333
77496
  }
77334
- var key = path25[index];
77497
+ var key = path26[index];
77335
77498
  var updated = shared_isArray(obj) ? obj.slice() : utils_objectSpread({}, obj);
77336
- updated[key] = copyWithSet(obj[key], path25, value, index + 1);
77499
+ updated[key] = copyWithSet(obj[key], path26, value, index + 1);
77337
77500
  return updated;
77338
77501
  }
77339
77502
  function getEffectDurations(root) {
@@ -78661,12 +78824,12 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
78661
78824
  }
78662
78825
  });
78663
78826
  bridge_defineProperty(_this, "overrideValueAtPath", function(_ref) {
78664
- var { id, path: path25, rendererID, type, value } = _ref;
78827
+ var { id, path: path26, rendererID, type, value } = _ref;
78665
78828
  switch (type) {
78666
78829
  case "context":
78667
78830
  _this.send("overrideContext", {
78668
78831
  id,
78669
- path: path25,
78832
+ path: path26,
78670
78833
  rendererID,
78671
78834
  wasForwarded: true,
78672
78835
  value
@@ -78675,7 +78838,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
78675
78838
  case "hooks":
78676
78839
  _this.send("overrideHookState", {
78677
78840
  id,
78678
- path: path25,
78841
+ path: path26,
78679
78842
  rendererID,
78680
78843
  wasForwarded: true,
78681
78844
  value
@@ -78684,7 +78847,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
78684
78847
  case "props":
78685
78848
  _this.send("overrideProps", {
78686
78849
  id,
78687
- path: path25,
78850
+ path: path26,
78688
78851
  rendererID,
78689
78852
  wasForwarded: true,
78690
78853
  value
@@ -78693,7 +78856,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
78693
78856
  case "state":
78694
78857
  _this.send("overrideState", {
78695
78858
  id,
78696
- path: path25,
78859
+ path: path26,
78697
78860
  rendererID,
78698
78861
  wasForwarded: true,
78699
78862
  value
@@ -79027,12 +79190,12 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
79027
79190
  }
79028
79191
  });
79029
79192
  agent_defineProperty(_this, "copyElementPath", function(_ref5) {
79030
- var { id, path: path25, rendererID } = _ref5;
79193
+ var { id, path: path26, rendererID } = _ref5;
79031
79194
  var renderer = _this._rendererInterfaces[rendererID];
79032
79195
  if (renderer == null) {
79033
79196
  console.warn('Invalid renderer id "'.concat(rendererID, '" for element "').concat(id, '"'));
79034
79197
  } else {
79035
- var value = renderer.getSerializedElementValueByPath(id, path25);
79198
+ var value = renderer.getSerializedElementValueByPath(id, path26);
79036
79199
  if (value != null) {
79037
79200
  _this._bridge.send("saveToClipboard", value);
79038
79201
  } else {
@@ -79041,12 +79204,12 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
79041
79204
  }
79042
79205
  });
79043
79206
  agent_defineProperty(_this, "deletePath", function(_ref6) {
79044
- var { hookID, id, path: path25, rendererID, type } = _ref6;
79207
+ var { hookID, id, path: path26, rendererID, type } = _ref6;
79045
79208
  var renderer = _this._rendererInterfaces[rendererID];
79046
79209
  if (renderer == null) {
79047
79210
  console.warn('Invalid renderer id "'.concat(rendererID, '" for element "').concat(id, '"'));
79048
79211
  } else {
79049
- renderer.deletePath(type, id, hookID, path25);
79212
+ renderer.deletePath(type, id, hookID, path26);
79050
79213
  }
79051
79214
  });
79052
79215
  agent_defineProperty(_this, "getBackendVersion", function() {
@@ -79083,12 +79246,12 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
79083
79246
  }
79084
79247
  });
79085
79248
  agent_defineProperty(_this, "inspectElement", function(_ref9) {
79086
- var { forceFullData, id, path: path25, rendererID, requestID } = _ref9;
79249
+ var { forceFullData, id, path: path26, rendererID, requestID } = _ref9;
79087
79250
  var renderer = _this._rendererInterfaces[rendererID];
79088
79251
  if (renderer == null) {
79089
79252
  console.warn('Invalid renderer id "'.concat(rendererID, '" for element "').concat(id, '"'));
79090
79253
  } else {
79091
- _this._bridge.send("inspectedElement", renderer.inspectElement(requestID, id, path25, forceFullData));
79254
+ _this._bridge.send("inspectedElement", renderer.inspectElement(requestID, id, path26, forceFullData));
79092
79255
  if (_this._persistedSelectionMatch === null || _this._persistedSelectionMatch.id !== id) {
79093
79256
  _this._persistedSelection = null;
79094
79257
  _this._persistedSelectionMatch = null;
@@ -79122,15 +79285,15 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
79122
79285
  }
79123
79286
  for (var rendererID in _this._rendererInterfaces) {
79124
79287
  var renderer = _this._rendererInterfaces[rendererID];
79125
- var path25 = null;
79288
+ var path26 = null;
79126
79289
  if (suspendedByPathIndex !== null && rendererPath !== null) {
79127
79290
  var suspendedByPathRendererIndex = suspendedByPathIndex - suspendedByOffset;
79128
79291
  var rendererHasRequestedSuspendedByPath = renderer.getElementAttributeByPath(id, ["suspendedBy", suspendedByPathRendererIndex]) !== undefined;
79129
79292
  if (rendererHasRequestedSuspendedByPath) {
79130
- path25 = ["suspendedBy", suspendedByPathRendererIndex].concat(rendererPath);
79293
+ path26 = ["suspendedBy", suspendedByPathRendererIndex].concat(rendererPath);
79131
79294
  }
79132
79295
  }
79133
- var inspectedRootsPayload = renderer.inspectElement(requestID, id, path25, forceFullData);
79296
+ var inspectedRootsPayload = renderer.inspectElement(requestID, id, path26, forceFullData);
79134
79297
  switch (inspectedRootsPayload.type) {
79135
79298
  case "hydrated-path":
79136
79299
  inspectedRootsPayload.path[1] += suspendedByOffset;
@@ -79224,20 +79387,20 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
79224
79387
  }
79225
79388
  });
79226
79389
  agent_defineProperty(_this, "overrideValueAtPath", function(_ref15) {
79227
- var { hookID, id, path: path25, rendererID, type, value } = _ref15;
79390
+ var { hookID, id, path: path26, rendererID, type, value } = _ref15;
79228
79391
  var renderer = _this._rendererInterfaces[rendererID];
79229
79392
  if (renderer == null) {
79230
79393
  console.warn('Invalid renderer id "'.concat(rendererID, '" for element "').concat(id, '"'));
79231
79394
  } else {
79232
- renderer.overrideValueAtPath(type, id, hookID, path25, value);
79395
+ renderer.overrideValueAtPath(type, id, hookID, path26, value);
79233
79396
  }
79234
79397
  });
79235
79398
  agent_defineProperty(_this, "overrideContext", function(_ref16) {
79236
- var { id, path: path25, rendererID, wasForwarded, value } = _ref16;
79399
+ var { id, path: path26, rendererID, wasForwarded, value } = _ref16;
79237
79400
  if (!wasForwarded) {
79238
79401
  _this.overrideValueAtPath({
79239
79402
  id,
79240
- path: path25,
79403
+ path: path26,
79241
79404
  rendererID,
79242
79405
  type: "context",
79243
79406
  value
@@ -79245,11 +79408,11 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
79245
79408
  }
79246
79409
  });
79247
79410
  agent_defineProperty(_this, "overrideHookState", function(_ref17) {
79248
- var { id, hookID, path: path25, rendererID, wasForwarded, value } = _ref17;
79411
+ var { id, hookID, path: path26, rendererID, wasForwarded, value } = _ref17;
79249
79412
  if (!wasForwarded) {
79250
79413
  _this.overrideValueAtPath({
79251
79414
  id,
79252
- path: path25,
79415
+ path: path26,
79253
79416
  rendererID,
79254
79417
  type: "hooks",
79255
79418
  value
@@ -79257,11 +79420,11 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
79257
79420
  }
79258
79421
  });
79259
79422
  agent_defineProperty(_this, "overrideProps", function(_ref18) {
79260
- var { id, path: path25, rendererID, wasForwarded, value } = _ref18;
79423
+ var { id, path: path26, rendererID, wasForwarded, value } = _ref18;
79261
79424
  if (!wasForwarded) {
79262
79425
  _this.overrideValueAtPath({
79263
79426
  id,
79264
- path: path25,
79427
+ path: path26,
79265
79428
  rendererID,
79266
79429
  type: "props",
79267
79430
  value
@@ -79269,11 +79432,11 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
79269
79432
  }
79270
79433
  });
79271
79434
  agent_defineProperty(_this, "overrideState", function(_ref19) {
79272
- var { id, path: path25, rendererID, wasForwarded, value } = _ref19;
79435
+ var { id, path: path26, rendererID, wasForwarded, value } = _ref19;
79273
79436
  if (!wasForwarded) {
79274
79437
  _this.overrideValueAtPath({
79275
79438
  id,
79276
- path: path25,
79439
+ path: path26,
79277
79440
  rendererID,
79278
79441
  type: "state",
79279
79442
  value
@@ -79340,12 +79503,12 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
79340
79503
  _this._bridge.send("stopInspectingHost", selected);
79341
79504
  });
79342
79505
  agent_defineProperty(_this, "storeAsGlobal", function(_ref23) {
79343
- var { count, id, path: path25, rendererID } = _ref23;
79506
+ var { count, id, path: path26, rendererID } = _ref23;
79344
79507
  var renderer = _this._rendererInterfaces[rendererID];
79345
79508
  if (renderer == null) {
79346
79509
  console.warn('Invalid renderer id "'.concat(rendererID, '" for element "').concat(id, '"'));
79347
79510
  } else {
79348
- renderer.storeAsGlobal(id, path25, count);
79511
+ renderer.storeAsGlobal(id, path26, count);
79349
79512
  }
79350
79513
  });
79351
79514
  agent_defineProperty(_this, "updateHookSettings", function(settings) {
@@ -79362,12 +79525,12 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
79362
79525
  var rendererID = +rendererIDString;
79363
79526
  var renderer = _this._rendererInterfaces[rendererID];
79364
79527
  if (_this._lastSelectedRendererID === rendererID) {
79365
- var path25 = renderer.getPathForElement(_this._lastSelectedElementID);
79366
- if (path25 !== null) {
79367
- renderer.setTrackedPath(path25);
79528
+ var path26 = renderer.getPathForElement(_this._lastSelectedElementID);
79529
+ if (path26 !== null) {
79530
+ renderer.setTrackedPath(path26);
79368
79531
  _this._persistedSelection = {
79369
79532
  rendererID,
79370
- path: path25
79533
+ path: path26
79371
79534
  };
79372
79535
  }
79373
79536
  }
@@ -79442,11 +79605,11 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
79442
79605
  var rendererID = _this._lastSelectedRendererID;
79443
79606
  var id = _this._lastSelectedElementID;
79444
79607
  var renderer = _this._rendererInterfaces[rendererID];
79445
- var path25 = renderer != null ? renderer.getPathForElement(id) : null;
79446
- if (path25 !== null) {
79608
+ var path26 = renderer != null ? renderer.getPathForElement(id) : null;
79609
+ if (path26 !== null) {
79447
79610
  storage_sessionStorageSetItem(SESSION_STORAGE_LAST_SELECTION_KEY, JSON.stringify({
79448
79611
  rendererID,
79449
- path: path25
79612
+ path: path26
79450
79613
  }));
79451
79614
  } else {
79452
79615
  storage_sessionStorageRemoveItem(SESSION_STORAGE_LAST_SELECTION_KEY);
@@ -80169,7 +80332,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
80169
80332
  hasElementWithId: function hasElementWithId() {
80170
80333
  return false;
80171
80334
  },
80172
- inspectElement: function inspectElement(requestID, id, path25) {
80335
+ inspectElement: function inspectElement(requestID, id, path26) {
80173
80336
  return {
80174
80337
  id,
80175
80338
  responseID: requestID,
@@ -85439,9 +85602,9 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
85439
85602
  }
85440
85603
  return null;
85441
85604
  }
85442
- function getElementAttributeByPath(id, path25) {
85605
+ function getElementAttributeByPath(id, path26) {
85443
85606
  if (isMostRecentlyInspectedElement(id)) {
85444
- return utils_getInObject(mostRecentlyInspectedElement, path25);
85607
+ return utils_getInObject(mostRecentlyInspectedElement, path26);
85445
85608
  }
85446
85609
  return;
85447
85610
  }
@@ -86144,9 +86307,9 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
86144
86307
  function isMostRecentlyInspectedElementCurrent(id) {
86145
86308
  return isMostRecentlyInspectedElement(id) && !hasElementUpdatedSinceLastInspected;
86146
86309
  }
86147
- function mergeInspectedPaths(path25) {
86310
+ function mergeInspectedPaths(path26) {
86148
86311
  var current = currentlyInspectedPaths;
86149
- path25.forEach(function(key) {
86312
+ path26.forEach(function(key) {
86150
86313
  if (!current[key]) {
86151
86314
  current[key] = {};
86152
86315
  }
@@ -86154,21 +86317,21 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
86154
86317
  });
86155
86318
  }
86156
86319
  function createIsPathAllowed(key, secondaryCategory) {
86157
- return function isPathAllowed(path25) {
86320
+ return function isPathAllowed(path26) {
86158
86321
  switch (secondaryCategory) {
86159
86322
  case "hooks":
86160
- if (path25.length === 1) {
86323
+ if (path26.length === 1) {
86161
86324
  return true;
86162
86325
  }
86163
- if (path25[path25.length - 2] === "hookSource" && path25[path25.length - 1] === "fileName") {
86326
+ if (path26[path26.length - 2] === "hookSource" && path26[path26.length - 1] === "fileName") {
86164
86327
  return true;
86165
86328
  }
86166
- if (path25[path25.length - 1] === "subHooks" || path25[path25.length - 2] === "subHooks") {
86329
+ if (path26[path26.length - 1] === "subHooks" || path26[path26.length - 2] === "subHooks") {
86167
86330
  return true;
86168
86331
  }
86169
86332
  break;
86170
86333
  case "suspendedBy":
86171
- if (path25.length < 5) {
86334
+ if (path26.length < 5) {
86172
86335
  return true;
86173
86336
  }
86174
86337
  break;
@@ -86179,8 +86342,8 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
86179
86342
  if (!current) {
86180
86343
  return false;
86181
86344
  }
86182
- for (var i = 0;i < path25.length; i++) {
86183
- current = current[path25[i]];
86345
+ for (var i = 0;i < path26.length; i++) {
86346
+ current = current[path26[i]];
86184
86347
  if (!current) {
86185
86348
  return false;
86186
86349
  }
@@ -86234,38 +86397,38 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
86234
86397
  break;
86235
86398
  }
86236
86399
  }
86237
- function storeAsGlobal(id, path25, count) {
86400
+ function storeAsGlobal(id, path26, count) {
86238
86401
  if (isMostRecentlyInspectedElement(id)) {
86239
- var value = utils_getInObject(mostRecentlyInspectedElement, path25);
86402
+ var value = utils_getInObject(mostRecentlyInspectedElement, path26);
86240
86403
  var key = "$reactTemp".concat(count);
86241
86404
  window[key] = value;
86242
86405
  console.log(key);
86243
86406
  console.log(value);
86244
86407
  }
86245
86408
  }
86246
- function getSerializedElementValueByPath(id, path25) {
86409
+ function getSerializedElementValueByPath(id, path26) {
86247
86410
  if (isMostRecentlyInspectedElement(id)) {
86248
- var valueToCopy = utils_getInObject(mostRecentlyInspectedElement, path25);
86411
+ var valueToCopy = utils_getInObject(mostRecentlyInspectedElement, path26);
86249
86412
  return serializeToString(valueToCopy);
86250
86413
  }
86251
86414
  }
86252
- function inspectElement(requestID, id, path25, forceFullData) {
86253
- if (path25 !== null) {
86254
- mergeInspectedPaths(path25);
86415
+ function inspectElement(requestID, id, path26, forceFullData) {
86416
+ if (path26 !== null) {
86417
+ mergeInspectedPaths(path26);
86255
86418
  }
86256
86419
  if (isMostRecentlyInspectedElement(id) && !forceFullData) {
86257
86420
  if (!hasElementUpdatedSinceLastInspected) {
86258
- if (path25 !== null) {
86421
+ if (path26 !== null) {
86259
86422
  var secondaryCategory = null;
86260
- if (path25[0] === "hooks" || path25[0] === "suspendedBy") {
86261
- secondaryCategory = path25[0];
86423
+ if (path26[0] === "hooks" || path26[0] === "suspendedBy") {
86424
+ secondaryCategory = path26[0];
86262
86425
  }
86263
86426
  return {
86264
86427
  id,
86265
86428
  responseID: requestID,
86266
86429
  type: "hydrated-path",
86267
- path: path25,
86268
- value: cleanForBridge(utils_getInObject(mostRecentlyInspectedElement, path25), createIsPathAllowed(null, secondaryCategory), path25)
86430
+ path: path26,
86431
+ value: cleanForBridge(utils_getInObject(mostRecentlyInspectedElement, path26), createIsPathAllowed(null, secondaryCategory), path26)
86269
86432
  };
86270
86433
  } else {
86271
86434
  return {
@@ -86461,7 +86624,7 @@ The error thrown in the component is:
86461
86624
  console.groupEnd();
86462
86625
  }
86463
86626
  }
86464
- function deletePath(type, id, hookID, path25) {
86627
+ function deletePath(type, id, hookID, path26) {
86465
86628
  var devtoolsInstance = idToDevToolsInstanceMap.get(id);
86466
86629
  if (devtoolsInstance === undefined) {
86467
86630
  console.warn('Could not find DevToolsInstance with id "'.concat(id, '"'));
@@ -86475,11 +86638,11 @@ The error thrown in the component is:
86475
86638
  var instance2 = fiber.stateNode;
86476
86639
  switch (type) {
86477
86640
  case "context":
86478
- path25 = path25.slice(1);
86641
+ path26 = path26.slice(1);
86479
86642
  switch (fiber.tag) {
86480
86643
  case ClassComponent:
86481
- if (path25.length === 0) {} else {
86482
- deletePathInObject(instance2.context, path25);
86644
+ if (path26.length === 0) {} else {
86645
+ deletePathInObject(instance2.context, path26);
86483
86646
  }
86484
86647
  instance2.forceUpdate();
86485
86648
  break;
@@ -86489,21 +86652,21 @@ The error thrown in the component is:
86489
86652
  break;
86490
86653
  case "hooks":
86491
86654
  if (typeof overrideHookStateDeletePath === "function") {
86492
- overrideHookStateDeletePath(fiber, hookID, path25);
86655
+ overrideHookStateDeletePath(fiber, hookID, path26);
86493
86656
  }
86494
86657
  break;
86495
86658
  case "props":
86496
86659
  if (instance2 === null) {
86497
86660
  if (typeof overridePropsDeletePath === "function") {
86498
- overridePropsDeletePath(fiber, path25);
86661
+ overridePropsDeletePath(fiber, path26);
86499
86662
  }
86500
86663
  } else {
86501
- fiber.pendingProps = copyWithDelete(instance2.props, path25);
86664
+ fiber.pendingProps = copyWithDelete(instance2.props, path26);
86502
86665
  instance2.forceUpdate();
86503
86666
  }
86504
86667
  break;
86505
86668
  case "state":
86506
- deletePathInObject(instance2.state, path25);
86669
+ deletePathInObject(instance2.state, path26);
86507
86670
  instance2.forceUpdate();
86508
86671
  break;
86509
86672
  }
@@ -86558,7 +86721,7 @@ The error thrown in the component is:
86558
86721
  }
86559
86722
  }
86560
86723
  }
86561
- function overrideValueAtPath(type, id, hookID, path25, value) {
86724
+ function overrideValueAtPath(type, id, hookID, path26, value) {
86562
86725
  var devtoolsInstance = idToDevToolsInstanceMap.get(id);
86563
86726
  if (devtoolsInstance === undefined) {
86564
86727
  console.warn('Could not find DevToolsInstance with id "'.concat(id, '"'));
@@ -86572,13 +86735,13 @@ The error thrown in the component is:
86572
86735
  var instance2 = fiber.stateNode;
86573
86736
  switch (type) {
86574
86737
  case "context":
86575
- path25 = path25.slice(1);
86738
+ path26 = path26.slice(1);
86576
86739
  switch (fiber.tag) {
86577
86740
  case ClassComponent:
86578
- if (path25.length === 0) {
86741
+ if (path26.length === 0) {
86579
86742
  instance2.context = value;
86580
86743
  } else {
86581
- utils_setInObject(instance2.context, path25, value);
86744
+ utils_setInObject(instance2.context, path26, value);
86582
86745
  }
86583
86746
  instance2.forceUpdate();
86584
86747
  break;
@@ -86588,18 +86751,18 @@ The error thrown in the component is:
86588
86751
  break;
86589
86752
  case "hooks":
86590
86753
  if (typeof overrideHookState === "function") {
86591
- overrideHookState(fiber, hookID, path25, value);
86754
+ overrideHookState(fiber, hookID, path26, value);
86592
86755
  }
86593
86756
  break;
86594
86757
  case "props":
86595
86758
  switch (fiber.tag) {
86596
86759
  case ClassComponent:
86597
- fiber.pendingProps = copyWithSet(instance2.props, path25, value);
86760
+ fiber.pendingProps = copyWithSet(instance2.props, path26, value);
86598
86761
  instance2.forceUpdate();
86599
86762
  break;
86600
86763
  default:
86601
86764
  if (typeof overrideProps === "function") {
86602
- overrideProps(fiber, path25, value);
86765
+ overrideProps(fiber, path26, value);
86603
86766
  }
86604
86767
  break;
86605
86768
  }
@@ -86607,7 +86770,7 @@ The error thrown in the component is:
86607
86770
  case "state":
86608
86771
  switch (fiber.tag) {
86609
86772
  case ClassComponent:
86610
- utils_setInObject(instance2.state, path25, value);
86773
+ utils_setInObject(instance2.state, path26, value);
86611
86774
  instance2.forceUpdate();
86612
86775
  break;
86613
86776
  }
@@ -86893,14 +87056,14 @@ The error thrown in the component is:
86893
87056
  var trackedPathMatchInstance = null;
86894
87057
  var trackedPathMatchDepth = -1;
86895
87058
  var mightBeOnTrackedPath = false;
86896
- function setTrackedPath(path25) {
86897
- if (path25 === null) {
87059
+ function setTrackedPath(path26) {
87060
+ if (path26 === null) {
86898
87061
  trackedPathMatchFiber = null;
86899
87062
  trackedPathMatchInstance = null;
86900
87063
  trackedPathMatchDepth = -1;
86901
87064
  mightBeOnTrackedPath = false;
86902
87065
  }
86903
- trackedPath = path25;
87066
+ trackedPath = path26;
86904
87067
  }
86905
87068
  function updateTrackedPathStateBeforeMount(fiber, fiberInstance) {
86906
87069
  if (trackedPath === null || !mightBeOnTrackedPath) {
@@ -87664,9 +87827,9 @@ The error thrown in the component is:
87664
87827
  }
87665
87828
  var currentlyInspectedElementID = null;
87666
87829
  var currentlyInspectedPaths = {};
87667
- function mergeInspectedPaths(path25) {
87830
+ function mergeInspectedPaths(path26) {
87668
87831
  var current = currentlyInspectedPaths;
87669
- path25.forEach(function(key) {
87832
+ path26.forEach(function(key) {
87670
87833
  if (!current[key]) {
87671
87834
  current[key] = {};
87672
87835
  }
@@ -87674,13 +87837,13 @@ The error thrown in the component is:
87674
87837
  });
87675
87838
  }
87676
87839
  function createIsPathAllowed(key) {
87677
- return function isPathAllowed(path25) {
87840
+ return function isPathAllowed(path26) {
87678
87841
  var current = currentlyInspectedPaths[key];
87679
87842
  if (!current) {
87680
87843
  return false;
87681
87844
  }
87682
- for (var i = 0;i < path25.length; i++) {
87683
- current = current[path25[i]];
87845
+ for (var i = 0;i < path26.length; i++) {
87846
+ current = current[path26[i]];
87684
87847
  if (!current) {
87685
87848
  return false;
87686
87849
  }
@@ -87730,24 +87893,24 @@ The error thrown in the component is:
87730
87893
  break;
87731
87894
  }
87732
87895
  }
87733
- function storeAsGlobal(id, path25, count) {
87896
+ function storeAsGlobal(id, path26, count) {
87734
87897
  var inspectedElement = inspectElementRaw(id);
87735
87898
  if (inspectedElement !== null) {
87736
- var value = utils_getInObject(inspectedElement, path25);
87899
+ var value = utils_getInObject(inspectedElement, path26);
87737
87900
  var key = "$reactTemp".concat(count);
87738
87901
  window[key] = value;
87739
87902
  console.log(key);
87740
87903
  console.log(value);
87741
87904
  }
87742
87905
  }
87743
- function getSerializedElementValueByPath(id, path25) {
87906
+ function getSerializedElementValueByPath(id, path26) {
87744
87907
  var inspectedElement = inspectElementRaw(id);
87745
87908
  if (inspectedElement !== null) {
87746
- var valueToCopy = utils_getInObject(inspectedElement, path25);
87909
+ var valueToCopy = utils_getInObject(inspectedElement, path26);
87747
87910
  return serializeToString(valueToCopy);
87748
87911
  }
87749
87912
  }
87750
- function inspectElement(requestID, id, path25, forceFullData) {
87913
+ function inspectElement(requestID, id, path26, forceFullData) {
87751
87914
  if (forceFullData || currentlyInspectedElementID !== id) {
87752
87915
  currentlyInspectedElementID = id;
87753
87916
  currentlyInspectedPaths = {};
@@ -87760,8 +87923,8 @@ The error thrown in the component is:
87760
87923
  type: "not-found"
87761
87924
  };
87762
87925
  }
87763
- if (path25 !== null) {
87764
- mergeInspectedPaths(path25);
87926
+ if (path26 !== null) {
87927
+ mergeInspectedPaths(path26);
87765
87928
  }
87766
87929
  updateSelectedElement(id);
87767
87930
  inspectedElement.context = cleanForBridge(inspectedElement.context, createIsPathAllowed("context"));
@@ -87964,10 +88127,10 @@ The error thrown in the component is:
87964
88127
  console.groupEnd();
87965
88128
  }
87966
88129
  }
87967
- function getElementAttributeByPath(id, path25) {
88130
+ function getElementAttributeByPath(id, path26) {
87968
88131
  var inspectedElement = inspectElementRaw(id);
87969
88132
  if (inspectedElement !== null) {
87970
- return utils_getInObject(inspectedElement, path25);
88133
+ return utils_getInObject(inspectedElement, path26);
87971
88134
  }
87972
88135
  return;
87973
88136
  }
@@ -87984,14 +88147,14 @@ The error thrown in the component is:
87984
88147
  }
87985
88148
  return element.type;
87986
88149
  }
87987
- function deletePath(type, id, hookID, path25) {
88150
+ function deletePath(type, id, hookID, path26) {
87988
88151
  var internalInstance = idToInternalInstanceMap.get(id);
87989
88152
  if (internalInstance != null) {
87990
88153
  var publicInstance = internalInstance._instance;
87991
88154
  if (publicInstance != null) {
87992
88155
  switch (type) {
87993
88156
  case "context":
87994
- deletePathInObject(publicInstance.context, path25);
88157
+ deletePathInObject(publicInstance.context, path26);
87995
88158
  forceUpdate(publicInstance);
87996
88159
  break;
87997
88160
  case "hooks":
@@ -87999,12 +88162,12 @@ The error thrown in the component is:
87999
88162
  case "props":
88000
88163
  var element = internalInstance._currentElement;
88001
88164
  internalInstance._currentElement = legacy_renderer_objectSpread(legacy_renderer_objectSpread({}, element), {}, {
88002
- props: copyWithDelete(element.props, path25)
88165
+ props: copyWithDelete(element.props, path26)
88003
88166
  });
88004
88167
  forceUpdate(publicInstance);
88005
88168
  break;
88006
88169
  case "state":
88007
- deletePathInObject(publicInstance.state, path25);
88170
+ deletePathInObject(publicInstance.state, path26);
88008
88171
  forceUpdate(publicInstance);
88009
88172
  break;
88010
88173
  }
@@ -88038,14 +88201,14 @@ The error thrown in the component is:
88038
88201
  }
88039
88202
  }
88040
88203
  }
88041
- function overrideValueAtPath(type, id, hookID, path25, value) {
88204
+ function overrideValueAtPath(type, id, hookID, path26, value) {
88042
88205
  var internalInstance = idToInternalInstanceMap.get(id);
88043
88206
  if (internalInstance != null) {
88044
88207
  var publicInstance = internalInstance._instance;
88045
88208
  if (publicInstance != null) {
88046
88209
  switch (type) {
88047
88210
  case "context":
88048
- utils_setInObject(publicInstance.context, path25, value);
88211
+ utils_setInObject(publicInstance.context, path26, value);
88049
88212
  forceUpdate(publicInstance);
88050
88213
  break;
88051
88214
  case "hooks":
@@ -88053,12 +88216,12 @@ The error thrown in the component is:
88053
88216
  case "props":
88054
88217
  var element = internalInstance._currentElement;
88055
88218
  internalInstance._currentElement = legacy_renderer_objectSpread(legacy_renderer_objectSpread({}, element), {}, {
88056
- props: copyWithSet(element.props, path25, value)
88219
+ props: copyWithSet(element.props, path26, value)
88057
88220
  });
88058
88221
  forceUpdate(publicInstance);
88059
88222
  break;
88060
88223
  case "state":
88061
- utils_setInObject(publicInstance.state, path25, value);
88224
+ utils_setInObject(publicInstance.state, path26, value);
88062
88225
  forceUpdate(publicInstance);
88063
88226
  break;
88064
88227
  }
@@ -88099,7 +88262,7 @@ The error thrown in the component is:
88099
88262
  return [];
88100
88263
  }
88101
88264
  function setTraceUpdatesEnabled(enabled) {}
88102
- function setTrackedPath(path25) {}
88265
+ function setTrackedPath(path26) {}
88103
88266
  function getOwnersList(id) {
88104
88267
  return null;
88105
88268
  }
@@ -94963,11 +95126,23 @@ init_version();
94963
95126
  init_crash_recovery();
94964
95127
 
94965
95128
  // src/execution/runner-completion.ts
94966
- init_test_path();
95129
+ init_acceptance4();
95130
+ init_config();
94967
95131
  init_hooks();
94968
95132
  init_logger2();
94969
95133
  init_prd();
95134
+ import path20 from "path";
95135
+
95136
+ // src/review/index.ts
95137
+ init_semantic_helpers();
95138
+ init_adversarial();
95139
+ init_categorization();
95140
+ init_diff_utils();
95141
+ init_finding_projection();
94970
95142
  init_orchestrator2();
95143
+ init_runner4();
95144
+
95145
+ // src/execution/runner-completion.ts
94971
95146
  init_git();
94972
95147
  init_crash_recovery();
94973
95148
  init_story_context();
@@ -94979,7 +95154,8 @@ var _runnerCompletionDeps = {
94979
95154
  async handleRunCompletion(opts) {
94980
95155
  const { handleRunCompletion: handleRunCompletion2 } = await Promise.resolve().then(() => (init_run_completion(), exports_run_completion));
94981
95156
  return handleRunCompletion2(opts);
94982
- }
95157
+ },
95158
+ loadConfigForWorkdir
94983
95159
  };
94984
95160
  async function runCompletionPhase(options) {
94985
95161
  const logger = getSafeLogger();
@@ -94998,7 +95174,27 @@ async function runCompletionPhase(options) {
94998
95174
  logger?.info("execution", "Acceptance already passed \u2014 skipping acceptance phase");
94999
95175
  } else if (options.config.acceptance.enabled && isComplete(options.prd)) {
95000
95176
  options.statusWriter.setPostRunPhase("acceptance", { status: "running" });
95001
- const acceptanceTestPaths = options.featureDir ? groupStoriesByPackage(options.prd, options.workdir, options.feature, options.config.acceptance.testPath, options.config.project?.language).map((g) => ({ testPath: g.testPath, packageDir: g.packageDir })) : undefined;
95177
+ const acceptanceTestPaths = options.featureDir ? await Promise.all(groupStoriesByPackage(options.prd, options.workdir, options.feature, options.config.acceptance.testPath, options.config.project?.language).map(async (g) => {
95178
+ const relativeWorkdir = path20.relative(options.workdir, g.packageDir);
95179
+ let groupConfig = options.config;
95180
+ if (relativeWorkdir && relativeWorkdir !== ".") {
95181
+ try {
95182
+ groupConfig = await _runnerCompletionDeps.loadConfigForWorkdir(path20.join(options.workdir, ".nax", "config.json"), relativeWorkdir);
95183
+ } catch (error48) {
95184
+ logger?.warn("execution", "Falling back to root config for package acceptance settings", {
95185
+ packageDir: g.packageDir,
95186
+ relativeWorkdir,
95187
+ error: errorMessage(error48)
95188
+ });
95189
+ }
95190
+ }
95191
+ return {
95192
+ testPath: g.testPath,
95193
+ packageDir: g.packageDir,
95194
+ testFramework: groupConfig.project?.testFramework,
95195
+ commandOverride: groupConfig.acceptance.command
95196
+ };
95197
+ })) : undefined;
95002
95198
  const acceptanceResult = await _runnerCompletionDeps.runAcceptanceLoop({
95003
95199
  config: options.config,
95004
95200
  prd: options.prd,
@@ -100201,8 +100397,8 @@ function Text({ color, backgroundColor, dimColor = false, bold = false, italic =
100201
100397
  }
100202
100398
 
100203
100399
  // node_modules/ink/build/components/ErrorOverview.js
100204
- var cleanupPath = (path25) => {
100205
- return path25?.replace(`file://${cwd()}/`, "");
100400
+ var cleanupPath = (path26) => {
100401
+ return path26?.replace(`file://${cwd()}/`, "");
100206
100402
  };
100207
100403
  var stackUtils = new import_stack_utils.default({
100208
100404
  cwd: cwd(),
@@ -102319,6 +102515,7 @@ function useAgentStreamEvents(bus) {
102319
102515
  messageUpdates: 0,
102320
102516
  thinkingUpdates: 0,
102321
102517
  usageUpdates: 0,
102518
+ toolCallUpdates: 0,
102322
102519
  status: "active"
102323
102520
  });
102324
102521
  break;
@@ -102356,6 +102553,17 @@ function useAgentStreamEvents(bus) {
102356
102553
  }
102357
102554
  break;
102358
102555
  }
102556
+ case "agent.tool_call_update": {
102557
+ const state = next.get(event.callId);
102558
+ if (state) {
102559
+ next.set(event.callId, {
102560
+ ...state,
102561
+ toolCallUpdates: state.toolCallUpdates + 1,
102562
+ lastActivityAt: event.timestamp
102563
+ });
102564
+ }
102565
+ break;
102566
+ }
102359
102567
  case "agent.call_ended": {
102360
102568
  const state = next.get(event.callId);
102361
102569
  if (state) {
@@ -103540,8 +103748,8 @@ configProfileCmd.command("current").description("Show the currently active profi
103540
103748
  });
103541
103749
  configProfileCmd.command("create <name>").description("Create a new empty profile").option("-d, --dir <path>", "Project directory", process.cwd()).action(async (name, options) => {
103542
103750
  try {
103543
- const path25 = await profileCreateCommand(name, options.dir);
103544
- console.log(`Created profile at: ${path25}`);
103751
+ const path26 = await profileCreateCommand(name, options.dir);
103752
+ console.log(`Created profile at: ${path26}`);
103545
103753
  } catch (err) {
103546
103754
  console.error(source_default.red(`Error: ${err.message}`));
103547
103755
  process.exit(1);