@nathapp/nax-agent 0.91.6 → 0.91.7-canary.10

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 (79) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/dist/coding-tools/coding-tool-extras.d.ts +52 -0
  3. package/dist/coding-tools/coding-tool-extras.js +56 -0
  4. package/dist/coding-tools/coding-tool-support.d.ts +9 -0
  5. package/dist/coding-tools/coding-tool-support.js +12 -1
  6. package/dist/config/catalog-overrides.d.ts +9 -0
  7. package/dist/index.d.ts +4 -2
  8. package/dist/index.js +2 -1
  9. package/dist/internal/argv-exec.d.ts +6 -0
  10. package/dist/internal/argv-exec.js +158 -63
  11. package/dist/mcp/connect.js +26 -3
  12. package/dist/mcp/types.d.ts +7 -0
  13. package/dist/native/adapter-deps.d.ts +2 -0
  14. package/dist/native/adapter-deps.js +2 -0
  15. package/dist/native/models.js +2 -0
  16. package/dist/native/session/loop-events/types.d.ts +5 -0
  17. package/dist/native/session-adapter.js +19 -5
  18. package/dist/permissions/approval-memory.d.ts +18 -0
  19. package/dist/permissions/approval-memory.js +88 -0
  20. package/dist/permissions/index.d.ts +1 -0
  21. package/dist/permissions/index.js +1 -0
  22. package/dist/permissions/types.d.ts +6 -0
  23. package/dist/runtime/node-runtime.js +5 -0
  24. package/dist/sandbox/claude-settings.d.ts +2 -1
  25. package/dist/sandbox/claude-settings.js +7 -3
  26. package/dist/sandbox/defaults.js +1 -0
  27. package/dist/sandbox/launcher.js +7 -0
  28. package/dist/sandbox/types.d.ts +6 -0
  29. package/dist/session/agent-session-command.d.ts +19 -0
  30. package/dist/session/agent-session-command.js +38 -0
  31. package/dist/session/agent-session-types.d.ts +26 -0
  32. package/dist/session/agent-session.js +86 -1
  33. package/dist/session/native-backend-options.d.ts +37 -2
  34. package/dist/session/native-backend-options.js +39 -3
  35. package/dist/session/native-backend.js +55 -5
  36. package/dist/session/native-posture-rules.d.ts +18 -0
  37. package/dist/session/native-posture-rules.js +33 -0
  38. package/dist/session/session-ask-link.d.ts +6 -0
  39. package/dist/session/session-ask-link.js +5 -0
  40. package/dist/session/session-ask-port.js +4 -0
  41. package/dist/session/session-backend.d.ts +23 -1
  42. package/dist/session/session-interaction.d.ts +2 -0
  43. package/dist/session/session-interaction.js +8 -1
  44. package/dist/session/session-tool-support.d.ts +49 -3
  45. package/dist/session/session-tool-support.js +66 -11
  46. package/dist/session-store/index.d.ts +3 -0
  47. package/dist/session-store/index.js +3 -0
  48. package/dist/session-store/session-lock-guard.d.ts +6 -0
  49. package/dist/session-store/session-lock-guard.js +85 -0
  50. package/dist/session-store/session-lock.d.ts +39 -0
  51. package/dist/session-store/session-lock.js +178 -0
  52. package/dist/session-store/session-meta.d.ts +27 -0
  53. package/dist/session-store/session-meta.js +20 -0
  54. package/dist/session-store/storage.d.ts +39 -0
  55. package/dist/session-store/storage.js +164 -0
  56. package/dist/tools/ask-request.d.ts +18 -0
  57. package/dist/tools/ask-request.js +30 -0
  58. package/dist/tools/bash-background.d.ts +74 -0
  59. package/dist/tools/bash-background.js +151 -0
  60. package/dist/tools/bash.d.ts +11 -0
  61. package/dist/tools/bash.js +77 -17
  62. package/dist/tools/git.js +10 -3
  63. package/dist/tools/policy-match.d.ts +2 -2
  64. package/dist/tools/policy-match.js +9 -6
  65. package/dist/tools/policy-paths-branch.js +4 -1
  66. package/dist/tools/provider-advertise.d.ts +7 -0
  67. package/dist/tools/provider-advertise.js +13 -1
  68. package/dist/tools/provider-types.d.ts +6 -0
  69. package/dist/tools/run-command-exec.js +12 -0
  70. package/dist/tools/run-command-surface.d.ts +28 -0
  71. package/dist/tools/run-command-surface.js +109 -0
  72. package/dist/tools/run-command.d.ts +17 -16
  73. package/dist/tools/run-command.js +48 -68
  74. package/dist/tools/runtime-calltool.d.ts +101 -0
  75. package/dist/tools/runtime-calltool.js +112 -3
  76. package/dist/tools/runtime.d.ts +12 -0
  77. package/dist/tools/runtime.js +36 -18
  78. package/dist/tools/types.d.ts +8 -0
  79. package/package.json +3 -3
package/CHANGELOG.md CHANGED
@@ -4,6 +4,46 @@ All notable changes to `@nathapp/nax-agent` are recorded here. The format follow
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). While the version is `0.x`, a minor
5
5
  release may change the public API.
6
6
 
7
+ ## [0.91.7-canary.10] - 2026-10-30
8
+
9
+ - No changes in this package. Released in lockstep with the other nax packages.
10
+
11
+ ## [0.91.7-canary.9] - 2026-10-30
12
+
13
+ - No changes in this package. Released in lockstep with the other nax packages.
14
+
15
+ ## [0.91.7-canary.8] - 2026-10-29
16
+
17
+ - No changes in this package. Released in lockstep with the other nax packages.
18
+
19
+ ## [0.91.7-canary.7] - 2026-10-29
20
+
21
+ - No changes in this package. Released in lockstep with the other nax packages.
22
+
23
+ ## [0.91.7-canary.6] - 2026-10-28
24
+
25
+ - No changes in this package. Released in lockstep with the other nax packages.
26
+
27
+ ## [0.91.7-canary.5] - 2026-10-27
28
+
29
+ - No changes in this package. Released in lockstep with the other nax packages.
30
+
31
+ ## [0.91.7-canary.4] - 2026-10-27
32
+
33
+ - No changes in this package. Released in lockstep with the other nax packages.
34
+
35
+ ## [0.91.7-canary.3] - 2026-10-27
36
+
37
+ - No changes in this package. Released in lockstep with the other nax packages.
38
+
39
+ ## [0.91.7-canary.2] - 2026-10-26
40
+
41
+ - No changes in this package. Released in lockstep with the other nax packages.
42
+
43
+ ## [0.91.7-canary.1] - 2026-10-24
44
+
45
+ - No changes in this package. Released in lockstep with the other nax packages.
46
+
7
47
  ## [0.91.6] - 2026-10-24
8
48
 
9
49
  - No changes in this package. Released in lockstep with the other nax packages.
@@ -9,6 +9,7 @@
9
9
  import type { BashApprovalMode } from "#src/config/bash-approval";
10
10
  import type { QualityCommandSpec } from "#src/internal/command-spec/index";
11
11
  import type { CommandLauncher } from "#src/sandbox/index";
12
+ import type { BackgroundCommandPort } from "#src/tools/bash-background";
12
13
  import { type CodingTool, type DeclaredCommandRunner, type ToolGrant } from "#src/tools/index";
13
14
  export interface DeclaredCommandToolsArgs {
14
15
  readonly declaredCommands: ReadonlyMap<string, QualityCommandSpec>;
@@ -31,5 +32,56 @@ export interface DeclaredCommandToolsArgs {
31
32
  readonly runDeclaredCommand?: DeclaredCommandRunner;
32
33
  /** P4: how Bash and Exec-branch commands run; absent = direct spawn (tests). */
33
34
  readonly launcher?: CommandLauncher;
35
+ /**
36
+ * US-003/US-008: whether this session offers the per-call `unsandboxed`
37
+ * argument — on Bash (`createBashTool`) and on RunCommand's argv branch
38
+ * (`createRunCommandTool`'s `exec` option, US-008). Advertisement only:
39
+ * RunCommand's DECLARED-command branch has no argv to unwrap and refuses the
40
+ * flag by name.
41
+ */
42
+ readonly unsandboxedCommands?: boolean;
43
+ readonly backgroundCommands?: BackgroundCommandPort;
34
44
  }
45
+ /**
46
+ * US-003: `unsandboxedCommands` as a spreadable field — present only when the
47
+ * session opted in, so "off" and "absent" stay one shape all the way down to
48
+ * `createBashTool` and to RunCommand's `exec` option (US-008).
49
+ *
50
+ * A helper rather than an inline `cond ? { field } : {}` spread because
51
+ * `buildDeclaredCommandTools` and `buildCodingToolSupport` both sit at their
52
+ * cognitive-complexity baseline and a ternary inside either one would raise it.
53
+ */
54
+ export declare function unsandboxedToolOptions(args: {
55
+ readonly unsandboxedCommands?: boolean;
56
+ }): {
57
+ readonly unsandboxedCommands?: true;
58
+ };
59
+ /**
60
+ * US-005: the same option as the RUNTIME's field — whether a `Bash`/`Exec`
61
+ * call may run outside the sandbox at all, plus the Bash approval mode that
62
+ * decides how an enabled request is routed.
63
+ *
64
+ * Absent when the session did not opt in, so "off" and "absent" stay one shape
65
+ * all the way to `createCodingToolRuntime` (absent means disabled). A helper
66
+ * for the same reason as `unsandboxedToolOptions`: `buildCodingToolSupport`
67
+ * sits at its cognitive-complexity baseline and a ternary inside it would
68
+ * raise it.
69
+ */
70
+ export declare function unsandboxedRuntimeOption(args: {
71
+ readonly unsandboxedCommands?: boolean;
72
+ readonly askOnUnsandboxed?: boolean;
73
+ readonly bashApproval: BashApprovalMode;
74
+ }): {
75
+ readonly unsandboxed?: {
76
+ readonly enabled: boolean;
77
+ readonly bashApproval: BashApprovalMode;
78
+ readonly alwaysAsk?: boolean;
79
+ };
80
+ };
35
81
  export declare function buildDeclaredCommandTools(args: DeclaredCommandToolsArgs): CodingTool[];
82
+ /** Preserve absence at every session/support forwarding hop. */
83
+ export declare function backgroundToolOptions(args?: {
84
+ readonly backgroundCommands?: BackgroundCommandPort;
85
+ }): {
86
+ readonly backgroundCommands?: BackgroundCommandPort;
87
+ };
@@ -1,4 +1,46 @@
1
+ /**
2
+ * The session-local tools an operation declares: RunCommand (its declared
3
+ * commands and, when `Exec` is declared, its argv branch) and Bash.
4
+ *
5
+ * Extracted from coding-tool-support.ts to keep that file under its 600-line
6
+ * source limit ahead of the P4 sandbox wiring. A pure move: every comment that
7
+ * explains a field below travelled with it.
8
+ */
1
9
  import { createBashTool, createRunCommandTool, } from "#src/tools/index";
10
+ /**
11
+ * US-003: `unsandboxedCommands` as a spreadable field — present only when the
12
+ * session opted in, so "off" and "absent" stay one shape all the way down to
13
+ * `createBashTool` and to RunCommand's `exec` option (US-008).
14
+ *
15
+ * A helper rather than an inline `cond ? { field } : {}` spread because
16
+ * `buildDeclaredCommandTools` and `buildCodingToolSupport` both sit at their
17
+ * cognitive-complexity baseline and a ternary inside either one would raise it.
18
+ */
19
+ export function unsandboxedToolOptions(args) {
20
+ return args.unsandboxedCommands === true ? { unsandboxedCommands: true } : {};
21
+ }
22
+ /**
23
+ * US-005: the same option as the RUNTIME's field — whether a `Bash`/`Exec`
24
+ * call may run outside the sandbox at all, plus the Bash approval mode that
25
+ * decides how an enabled request is routed.
26
+ *
27
+ * Absent when the session did not opt in, so "off" and "absent" stay one shape
28
+ * all the way to `createCodingToolRuntime` (absent means disabled). A helper
29
+ * for the same reason as `unsandboxedToolOptions`: `buildCodingToolSupport`
30
+ * sits at its cognitive-complexity baseline and a ternary inside it would
31
+ * raise it.
32
+ */
33
+ export function unsandboxedRuntimeOption(args) {
34
+ if (args.unsandboxedCommands !== true)
35
+ return {};
36
+ return {
37
+ unsandboxed: {
38
+ enabled: true,
39
+ bashApproval: args.bashApproval,
40
+ ...(args.askOnUnsandboxed === true ? { alwaysAsk: true } : {}),
41
+ },
42
+ };
43
+ }
2
44
  export function buildDeclaredCommandTools(args) {
3
45
  return [
4
46
  ...(args.declaredCommands.size > 0 || args.allowExec
@@ -31,6 +73,10 @@ export function buildDeclaredCommandTools(args) {
31
73
  patterns: args.execGrant?.patterns ?? [],
32
74
  ...(args.packageName !== undefined ? { packageName: args.packageName } : {}),
33
75
  ...(args.launcher !== undefined ? { launcher: args.launcher } : {}),
76
+ // US-008: the same option Bash takes, forwarded to the argv
77
+ // branch's advertisement through the same helper — one
78
+ // shape for "off" and "absent" on both tools.
79
+ ...unsandboxedToolOptions(args),
34
80
  },
35
81
  }
36
82
  : {}),
@@ -49,8 +95,18 @@ export function buildDeclaredCommandTools(args) {
49
95
  bashApproval: args.bashApproval,
50
96
  ...(args.humanApproval === true ? { humanApproval: true } : {}),
51
97
  ...(args.launcher !== undefined ? { launcher: args.launcher } : {}),
98
+ ...unsandboxedToolOptions(args),
99
+ ...bashBackgroundOption(args),
52
100
  }),
53
101
  ]
54
102
  : []),
55
103
  ];
56
104
  }
105
+ /** Preserve absence at every session/support forwarding hop. */
106
+ export function backgroundToolOptions(args) {
107
+ return args?.backgroundCommands === undefined ? {} : { backgroundCommands: args.backgroundCommands };
108
+ }
109
+ /** Only Bash receives this capability; RunCommand's argv branch stays unchanged. */
110
+ function bashBackgroundOption(args) {
111
+ return args.backgroundCommands === undefined ? {} : { background: args.backgroundCommands };
112
+ }
@@ -14,6 +14,7 @@ import type { BashApprovalMode } from "#src/config/bash-approval";
14
14
  import type { QualityCommandSpec } from "#src/internal/command-spec/index";
15
15
  import type { AskResolver } from "#src/permissions/index";
16
16
  import type { CommandLauncher } from "#src/sandbox/index";
17
+ import type { BackgroundCommandPort } from "#src/tools/bash-background";
17
18
  import { type CodingTool, type CodingToolName, type CodingToolRuntime, type DeclaredCommandRunner, type ProtectedPathsPolicy, type ToolAuditSink, type ToolGrant, type ToolPatternNarrowing, type ToolSurfaceDraft, type ToolSurfaceRecord } from "#src/tools/index";
18
19
  import type { OwnedPathsPolicy } from "#src/tools/owned-paths";
19
20
  export interface CodingToolSupport {
@@ -142,6 +143,14 @@ export declare function buildCodingToolSupport(args: {
142
143
  commandShadow?: CommandShadow;
143
144
  /** P4: resolved by resolveCodingToolSupport (async); data only here. */
144
145
  launcher?: CommandLauncher;
146
+ /**
147
+ * US-003: whether this session offers Bash's per-call `unsandboxed` argument
148
+ * (the session profile's `allowUnsandboxedCommands`). Advertisement only —
149
+ * the runtime's own reading of the field is a later story.
150
+ */
151
+ unsandboxedCommands?: boolean;
152
+ backgroundCommands?: BackgroundCommandPort;
153
+ askOnUnsandboxed?: boolean;
145
154
  /** US-001: forwarded into ToolRunContext so Bash/Exec can SIGKILL on cancel. */
146
155
  abortSignal?: AbortSignal;
147
156
  /**
@@ -11,7 +11,7 @@
11
11
  import { getSafeLogger, NaxError } from "#src/infra/index";
12
12
  import { advertisedSchemaBytes, BASH_TOOL_NAME, compileToolPolicy, createCodingToolRuntime, createNoOpToolAuditSink, createToolAuditSink, EXEC_TOOL_NAME, } from "#src/tools/index";
13
13
  import { resolveBashSupport } from "./coding-tool-bash.js";
14
- import { buildDeclaredCommandTools } from "./coding-tool-extras.js";
14
+ import { backgroundToolOptions, buildDeclaredCommandTools, unsandboxedRuntimeOption, unsandboxedToolOptions, } from "./coding-tool-extras.js";
15
15
  import { isTempConfined, rawScreenOptionsFor } from "./coding-tool-sandbox.js";
16
16
  export function buildCodingToolSupport(args) {
17
17
  if (args.declared.length === 0)
@@ -119,9 +119,20 @@ export function buildCodingToolSupport(args) {
119
119
  ...(args.stripEnvVars !== undefined ? { stripEnvVars: args.stripEnvVars } : {}),
120
120
  ...(args.shell !== undefined ? { shell: args.shell } : {}),
121
121
  ...(args.launcher !== undefined ? { launcher: args.launcher } : {}),
122
+ ...unsandboxedToolOptions(args),
123
+ ...backgroundToolOptions(args),
122
124
  }),
123
125
  ],
124
126
  ...(args.providerIdByTool !== undefined ? { providerIdByTool: args.providerIdByTool } : {}),
127
+ // US-005: the escape option reaches the RUNTIME too, not just the Bash
128
+ // schema — with the locally resolved mode, so a caller that left
129
+ // `bashApproval` unset cannot enable an escape under a mode it did not
130
+ // choose.
131
+ ...unsandboxedRuntimeOption({
132
+ unsandboxedCommands: args.unsandboxedCommands,
133
+ askOnUnsandboxed: args.askOnUnsandboxed,
134
+ bashApproval,
135
+ }),
125
136
  });
126
137
  const tools = runtime.advertised(advertised);
127
138
  // The fixed per-hop cost of advertising provider tools: their schemas enter
@@ -91,6 +91,11 @@ export interface CatalogModelOverride {
91
91
  * `protocol: "openai-completions"` (nax-ai `assertOverrideModelRouting`).
92
92
  */
93
93
  openRouterRouting?: OpenRouterRouting;
94
+ /**
95
+ * Thinking wire format for an `openai-completions` model (nax#2696).
96
+ * Mirrored from nax-ai's ThinkingFormat; omit to inherit the provider's format.
97
+ */
98
+ thinkingFormat?: "openai" | "qwen" | "qwen-chat-template" | "deepseek" | "zai" | "openrouter";
94
99
  }
95
100
  /** Provider-scoped catalog overrides — maps 1:1 onto nax-ai's `ProviderOverride[]`. */
96
101
  export interface ProviderCatalogOverride {
@@ -100,6 +105,10 @@ export interface ProviderCatalogOverride {
100
105
  * not to `models` individually, despite sitting alongside a model list.
101
106
  */
102
107
  baseUrl?: string;
108
+ /** Environment variable supplying a custom provider's bearer credential. */
109
+ authEnv?: string;
110
+ /** Config/precheck opt-in only; never forwarded to nax-ai or enforced here. */
111
+ allowInsecureHttp?: boolean;
103
112
  /** Provider-wide extra request headers (nax#2019). May carry credentials. */
104
113
  headers?: Record<string, string>;
105
114
  models: CatalogModelOverride[];
package/dist/index.d.ts CHANGED
@@ -24,13 +24,14 @@ export { AuthCancelledError, type AuthEvent, type AuthInteraction, type AuthLink
24
24
  export type { NativeSessionAdapterOptions } from "#src/native/session-adapter";
25
25
  export type { AfterResponsePatch, AfterResponsePayload, AfterToolPatch, AfterToolPayload, BeforeCompactionPatch, BeforeCompactionPayload, BeforeRequestPatch, BeforeRequestPayload, BeforeToolOutcome, BeforeToolPayload, BeforeTurnEndPatch, BeforeTurnEndPayload, BeforeTurnPatch, BeforeTurnPayload, CompleteCallOptions, ExternalHandlerOf, LoopEvent, LoopEventMap, LoopHandlerContext, LoopHandlerEntry, LoopHandlerSet, PatchOf, PayloadOf, TransformContextPatch, TransformContextPayload, } from "#src/native/session/loop-events/types";
26
26
  export { displayToolInput, TOOL_CALL_INPUT_BYTES, TOOL_RESULT_PREVIEW_BYTES, toolResultPreview, } from "#src/native/session/turn-event-emitter";
27
- export { type ApprovalAuditRow, type ApprovalEntry, type ApprovalsFile, type ApprovalsFileRead, type ApprovalsFileState, type ApprovalsTaint, ASK_CANCELLED_REASON, ASK_DENIED_REASON, ASK_NO_CHANNEL_REASON, ASK_PROFILE_REASON, ASK_TIMEOUT_REASON, ASK_UNAVAILABLE_REASON, ASK_UNSHOWABLE_REASON, type AskControl, type AskDecidedBy, type AskDecision, type AskLink, type AskLinkOutcome, type AskRequest, type AskResolver, type AskVerdict, appendApproval, appendApprovalAudit, approvalId, approvalsPath, type BashLexResult, type BashRedirect, type BashSegment, type BashSegmentSeparator, type BashToken, type ClearTaintOutcome, chainAskLinks, clearApprovalsTaint, createApprovalsLink, findApproval, findSecretSpans, headlessAskResolver, isForgeCapable, lexBashCommand, type MaskResult, maskForPrompt, type PrepareApprovalsStoreOptions, parseRuleList, parseToolExpression, prepareApprovalsStore, type RemovalDecision, type RemovalResult, type ResolvedPermissions, readApprovals, readApprovalsFile, readApprovalsFileDetailed, redactForRow, redactRowStrings, removeApprovals, type SecretSpan, taintApprovals, writeApprovalsFile, } from "#src/permissions/index";
27
+ export { type ApprovalAuditRow, type ApprovalEntry, type ApprovalMemoryDecision, type ApprovalMemoryRequest, approvalMemoryApplies, approvalMemoryKey, type ApprovalsFile, type ApprovalsFileRead, type ApprovalsFileState, type ApprovalsTaint, ASK_CANCELLED_REASON, ASK_DENIED_REASON, ASK_NO_CHANNEL_REASON, ASK_PROFILE_REASON, ASK_TIMEOUT_REASON, ASK_UNAVAILABLE_REASON, ASK_UNSHOWABLE_REASON, type AskControl, type AskDecidedBy, type AskDecision, type AskLink, type AskLinkOutcome, type AskRequest, type AskResolver, type AskVerdict, appendApproval, appendApprovalAudit, approvalId, approvalsPath, type BashLexResult, type BashRedirect, type BashSegment, type BashSegmentSeparator, type BashToken, type ClearTaintOutcome, chainAskLinks, clearApprovalsTaint, createApprovalsLink, findApproval, findSecretSpans, headlessAskResolver, isForgeCapable, lexBashCommand, type MaskResult, maskForPrompt, type PrepareApprovalsStoreOptions, parseRuleList, parseToolExpression, prepareApprovalsStore, type RemovalDecision, type RemovalResult, type ResolvedPermissions, readApprovals, readApprovalsFile, readApprovalsFileDetailed, redactForRow, redactRowStrings, removeApprovals, type SecretSpan, taintApprovals, writeApprovalsFile, } from "#src/permissions/index";
28
28
  export { type AgentGlobOptions, type AgentRuntime, type AgentSpawnOptions, type AgentSpawnResult, type AgentSpawnStdin, getAgentRuntime, nodeRuntime, setAgentRuntime, } from "#src/runtime/index";
29
29
  export { buildSandboxPolicy, type CommandLauncher, type CommandLauncherOptions, createCommandLauncher, createSrtBackend, DISABLED_SANDBOX_STATE, SANDBOXED_ENV, defaultTempRoots, denialHintLine, type GitLayout, type LaunchRequest, type LaunchResult, type LaunchSpec, LIKELY_SANDBOX_DENIAL, listCredentialFiles, listGitGuardFiles, listNaxEntries, type ProbeResult, probeSandbox, probeSandboxOnce, quoteArgvForShell, rawBashRefusalReason, resetSandboxBackend, resolveGitLayout, runTempRoots, runTmpRoot, type SandboxBackend, type SandboxBackendName, type SandboxNetworkPolicy, type SandboxPolicy, type SandboxPolicyInput, type SandboxRecord, type SandboxState, type SandboxWrapRequest, type SessionSandbox, sessionSandboxFrom, sandboxBackendFor, sandboxSentence, sessionTmpDir, sessionTmpDirUnder, strayCommonDirTripwire, unsandboxedSentence, warnSandboxUnavailableOnce, } from "#src/sandbox/index";
30
+ export { createSessionStorage, defaultSessionsDir, processAlive, LIST_PAGE_SIZE, LOCK_HEARTBEAT_MS, LOCK_STALE_MS, SESSION_ID_PATTERN, SESSION_META_MODES, type SessionMeta, type SessionMetaMode, type SessionListEntry, type SessionListPage, type SessionLockHolder, type SessionLockHolderState, type SessionStorage, type SessionStorageDeps, } from "#src/session-store/index";
30
31
  export type { AdapterFailure } from "#src/session/adapter-failure";
31
32
  export { createAgentSession, resumeAgentSession } from "#src/session/agent-session";
32
33
  export { AgentSessionError, type AgentSessionErrorCode } from "#src/session/agent-session-errors";
33
- export type { AgentSession, AgentSessionHostPorts, AgentSessionProfile, AnswerReply, AnswerStatus, ApprovalDecidedBy, CostSource, CreateAgentSessionOptions, EmbedderTool, EmbedderToolContext, EmbedderToolResult, SessionEvent, SessionEventBase, SessionEventBody, TurnEndStatus, } from "#src/session/agent-session-types";
34
+ export type { AgentSession, AgentSessionHostPorts, AgentSessionProfile, AnswerReply, AnswerStatus, ApprovalDecidedBy, CostSource, CommandRunResult, CreateAgentSessionOptions, EmbedderTool, EmbedderToolContext, EmbedderToolResult, SessionConfigureInput, SessionEvent, SessionEventBase, SessionEventBody, TurnEndStatus, } from "#src/session/agent-session-types";
34
35
  export type { AgentAwaitingHumanEvent, AgentCallEndedEvent, AgentCallStartedEvent, AgentMessageUpdateEvent, AgentProcessUpdateEvent, AgentStreamEvent, AgentStreamEventBase, AgentThinkingUpdateEvent, AgentToolCallUpdateEvent, AgentUsageUpdateEvent, } from "#src/session/agent-stream-events";
35
36
  export { type AdapterInteraction, type AdapterInteractionResponse, type InteractionHandler, NO_OP_INTERACTION_HANDLER, } from "#src/session/interaction-handler";
36
37
  export { nativeBackend } from "#src/session/native-backend";
@@ -45,3 +46,4 @@ export type { TurnEvent, TurnEventSink } from "#src/session/turn-event";
45
46
  export { adaptProviderTool, advertisedSchemaBytes, applyModelTruncationPolicy, BASH_TIMEOUT_MS, BASH_TOOL_NAME, buildCommitArgvs, buildGitArgv, buildGrepArgv, type CodingTool, type CodingToolName, type CodingToolOutcome, type CodingToolRuntime, classifyExec, compileToolPolicy, createBashTool, createCodingToolRuntime, createNoOpToolAuditSink, createRunCommandTool, createToolAuditSink, cutBufferToByteCap, DEFAULT_BASH_SHELL, DEFAULT_LOG_FORMAT, DEFAULT_LOG_MAX_COUNT, DEFAULT_TOOL_MAX_BYTES, DEFAULT_TOOL_MAX_FILE_BYTES, type DeclaredCommandRequest, type DeclaredCommandResult, type DeclaredCommandRunner, deleteTool, EXEC_TOOL_NAME, type ExecTarget, editTool, expandMcpRuleGrants, expandProviderGrants, flushOpenToolAuditSinks, GIT_ESCAPE_FLAGS, GIT_READ_VERBS, getCodingTool, gitCommitTool, gitExcludePathspecsOf, gitIgnorePatternsOf, gitTool, globTool, grepTool, isKnownManager, listCodingTools, MAX_PROVIDER_DESCRIPTION_BYTES, MAX_PROVIDER_SCHEMA_BYTES, MCP_INSTRUCTIONS_MAX_CHARS_PER_SERVER, MCP_INSTRUCTIONS_MAX_CHARS_TOTAL, MCP_RULE_TOOL, MODEL_MAX_BYTES, MODEL_MAX_LINE_CHARS, MODEL_MAX_LINES, type ModelTruncationOptions, mcpRuleAdmits, type NormalizeInput, type NormalizeResult, namespacedToolName, narrowGrants, normalizeExec, normalizeManagerBinary, type PolicyVerdict, PROVIDER_ID_RE, type ProtectedPathsPolicy, type ProviderGrantEntry, type ProviderKind, type ProviderTool, partitionMcpRules, partitionNaxOwnedPaths, providerAttachesTo, READ_CEILING, RESERVED_TOOL_NAMES, type ReadFileSliceOptions, type ReadFileSliceResult, type RegisteredSink, type ResolvedProviderTools, readFileSlice, readTool, registerBuiltinCodingTools, registerBuiltinTool, registerCodingTool, registerToolAuditSink, renderProviderInstructions, requestCapabilityTool, resolveProviderTools, resolveWithin, SCRATCHPAD_DIR, SPILL_DIR, type SpillRequest, sanitizeProviderTools, scratchpadListTool, scratchpadReadTool, scratchpadWriteTool, spillRelativePath, substituteCommand, substituteCommandSpec, type ToolAuditHeader, type ToolAuditSink, type ToolCallContext, type ToolCallRecord, type ToolGrant, type ToolPatternNarrowing, type ToolPolicy, type ToolPolicyOptions, type ToolProvider, type ToolResult, type ToolRunContext, type ToolScope, type ToolSurfaceDraft, type ToolSurfaceRecord, type TruncateForModelOptions, type TruncationDirection, type TruncationResult, truncateForModel, truncationDirectionFor, unregisterToolAuditSink, validateProviderId, writeSpill, writeTool, } from "#src/tools/index";
46
47
  export { compileArgvPattern, matchesArgvPattern, type CompiledPattern } from "#src/tools/policy-match";
47
48
  export { EMPTY_OWNED_PATHS_POLICY, type OwnedBashCandidate, type OwnedPathsPolicy, } from "#src/tools/owned-paths";
49
+ export type { BackgroundCommandPort, BackgroundCommandHandle, BackgroundCommandSink, BackgroundCommandEnd, ForegroundCommand, } from "#src/tools/bash-background";
package/dist/index.js CHANGED
@@ -19,9 +19,10 @@ export { NaxError } from "#src/infra/nax-error";
19
19
  export { createTerminalAuthInteraction, PLAIN_STYLE, PromptCancelledError, } from "#src/terminal-auth/index";
20
20
  export { AuthCancelledError, ambientShadows, anyAmbientCredential, authImportOutcomeLabel, createFileTranscriptStore, createMemoryTranscriptStore, credentialFilePath, DEFAULT_PI_AUTH_PATH, importPiCredentials, listProviderModels, listStoredProviders, loginProviderIds, MAX_RETAINED_TRANSCRIPTS, NATIVE_AGENT, NativeSessionAdapter, NativeSessionUnsupportedError, nativeComplete, nativeTierProviders, naxCredentialStore, newSessionKey, providersWithoutCredentials, pruneRetainedTranscripts, removeStoredProvider, resolveNativeId, runLogin, servedAuth, } from "#src/native/index";
21
21
  export { displayToolInput, TOOL_CALL_INPUT_BYTES, TOOL_RESULT_PREVIEW_BYTES, toolResultPreview, } from "#src/native/session/turn-event-emitter";
22
- export { ASK_CANCELLED_REASON, ASK_DENIED_REASON, ASK_NO_CHANNEL_REASON, ASK_PROFILE_REASON, ASK_TIMEOUT_REASON, ASK_UNAVAILABLE_REASON, ASK_UNSHOWABLE_REASON, appendApproval, appendApprovalAudit, approvalId, approvalsPath, chainAskLinks, clearApprovalsTaint, createApprovalsLink, findApproval, findSecretSpans, headlessAskResolver, isForgeCapable, lexBashCommand, maskForPrompt, parseRuleList, parseToolExpression, prepareApprovalsStore, readApprovals, readApprovalsFile, readApprovalsFileDetailed, redactForRow, redactRowStrings, removeApprovals, taintApprovals, writeApprovalsFile, } from "#src/permissions/index";
22
+ export { approvalMemoryApplies, approvalMemoryKey, ASK_CANCELLED_REASON, ASK_DENIED_REASON, ASK_NO_CHANNEL_REASON, ASK_PROFILE_REASON, ASK_TIMEOUT_REASON, ASK_UNAVAILABLE_REASON, ASK_UNSHOWABLE_REASON, appendApproval, appendApprovalAudit, approvalId, approvalsPath, chainAskLinks, clearApprovalsTaint, createApprovalsLink, findApproval, findSecretSpans, headlessAskResolver, isForgeCapable, lexBashCommand, maskForPrompt, parseRuleList, parseToolExpression, prepareApprovalsStore, readApprovals, readApprovalsFile, readApprovalsFileDetailed, redactForRow, redactRowStrings, removeApprovals, taintApprovals, writeApprovalsFile, } from "#src/permissions/index";
23
23
  export { getAgentRuntime, nodeRuntime, setAgentRuntime, } from "#src/runtime/index";
24
24
  export { buildSandboxPolicy, createCommandLauncher, createSrtBackend, DISABLED_SANDBOX_STATE, SANDBOXED_ENV, defaultTempRoots, denialHintLine, LIKELY_SANDBOX_DENIAL, listCredentialFiles, listGitGuardFiles, listNaxEntries, probeSandbox, probeSandboxOnce, quoteArgvForShell, rawBashRefusalReason, resetSandboxBackend, resolveGitLayout, runTempRoots, runTmpRoot, sessionSandboxFrom, sandboxBackendFor, sandboxSentence, sessionTmpDir, sessionTmpDirUnder, strayCommonDirTripwire, unsandboxedSentence, warnSandboxUnavailableOnce, } from "#src/sandbox/index";
25
+ export { createSessionStorage, defaultSessionsDir, processAlive, LIST_PAGE_SIZE, LOCK_HEARTBEAT_MS, LOCK_STALE_MS, SESSION_ID_PATTERN, SESSION_META_MODES, } from "#src/session-store/index";
25
26
  export { createAgentSession, resumeAgentSession } from "#src/session/agent-session";
26
27
  export { AgentSessionError } from "#src/session/agent-session-errors";
27
28
  export { NO_OP_INTERACTION_HANDLER, } from "#src/session/interaction-handler";
@@ -18,6 +18,10 @@ export interface RunArgvOptions {
18
18
  * and the result resolves with `aborted: true`. US-001.
19
19
  */
20
20
  readonly signal?: AbortSignal;
21
+ /** Abort to remove only the deadline, without cancelling the command. */
22
+ readonly releaseDeadline?: AbortSignal;
23
+ /** Observes every read chunk before capture; observer exceptions are ignored. */
24
+ readonly onOutput?: (stream: "stdout" | "stderr", chunk: Uint8Array) => void;
21
25
  }
22
26
  export interface ArgvExecResult {
23
27
  readonly exitCode: number;
@@ -45,6 +49,8 @@ export declare const _argvExecDeps: {
45
49
  * stays at the DRAIN_GRACE_MS constant.
46
50
  */
47
51
  drainGraceMs: number;
52
+ /** Per-stream capture cap (STREAM_CAPTURE_BYTES); a test shrinks it to exercise the cut. */
53
+ streamCaptureBytes: number;
48
54
  /**
49
55
  * Injectable timer pair — lets the BUG-13 "hung install" test drive the
50
56
  * timeout off a virtual clock instead of waiting the full 1s schema minimum.
@@ -23,6 +23,15 @@ import { killProcessGroup } from "./process-kill.js";
23
23
  * Injectable for tests; not exposed as user configuration.
24
24
  */
25
25
  export const DRAIN_GRACE_MS = 500;
26
+ /**
27
+ * Most bytes of ONE stream runArgv keeps in memory: its first half and its last half, with the
28
+ * middle replaced by a marker naming how much was dropped. Callers cap what they show far below
29
+ * this (Bash at READ_CEILING, 2 MB), so it bounds the work rather than the answer: before it, a
30
+ * `yes` or a looping test runner was buffered whole for up to the timeout and could exhaust the
31
+ * orchestrator's memory. The stream is still read to EOF, so the child never blocks or takes a
32
+ * SIGPIPE on a full pipe; the tail survives because that is where a failure's error usually is.
33
+ */
34
+ const STREAM_CAPTURE_BYTES = 8_000_000;
26
35
  /** Injectable seam, mirroring _worktreeDependencyDeps. */
27
36
  export const _argvExecDeps = {
28
37
  spawn: runtimeSpawn,
@@ -33,6 +42,8 @@ export const _argvExecDeps = {
33
42
  * stays at the DRAIN_GRACE_MS constant.
34
43
  */
35
44
  drainGraceMs: DRAIN_GRACE_MS,
45
+ /** Per-stream capture cap (STREAM_CAPTURE_BYTES); a test shrinks it to exercise the cut. */
46
+ streamCaptureBytes: STREAM_CAPTURE_BYTES,
36
47
  /**
37
48
  * Injectable timer pair — lets the BUG-13 "hung install" test drive the
38
49
  * timeout off a virtual clock instead of waiting the full 1s schema minimum.
@@ -73,13 +84,12 @@ function buildEnv(options) {
73
84
  * after a process-group kill: a child that ignores the kill cannot pin
74
85
  * runArgv forever on its still-open pipe.
75
86
  */
76
- async function drainToEof(stream, signal) {
87
+ async function drainToEof(stream, signal, onChunk) {
77
88
  const reader = stream.getReader();
78
- const decoder = new TextDecoder();
79
- let text = "";
89
+ const capture = new BoundedCapture(_argvExecDeps.streamCaptureBytes);
80
90
  const onAbort = () => {
81
91
  // Closing the stream forces the in-flight `read()` below to resolve with
82
- // `{done: true}`; any bytes already captured stay in `text`.
92
+ // `{done: true}`; any bytes already captured stay in `capture`.
83
93
  reader.cancel().catch(() => {
84
94
  // Cancelling after the pipe already closed is a no-op race; ignore.
85
95
  });
@@ -90,16 +100,23 @@ async function drainToEof(stream, signal) {
90
100
  const { done, value } = await reader.read();
91
101
  if (done === true)
92
102
  break;
93
- if (value !== undefined)
94
- text += decoder.decode(value, { stream: true });
103
+ if (value !== undefined) {
104
+ try {
105
+ // Copy even Buffer-backed chunks: observers must not mutate captured bytes.
106
+ onChunk?.(Uint8Array.from(value));
107
+ }
108
+ catch {
109
+ // Observers are best-effort: never let one truncate capture or stop draining.
110
+ }
111
+ capture.push(value);
112
+ }
95
113
  }
96
114
  }
97
115
  catch {
98
116
  // Stream cancelled by SIGKILL on the process group; the partial text
99
- // is still in `text`, so resolve with closed=false and let the caller
117
+ // is still in `capture`, so resolve with what it holds and let the caller
100
118
  // decide.
101
119
  }
102
- text += decoder.decode();
103
120
  if (signal !== undefined)
104
121
  signal.removeEventListener("abort", onAbort);
105
122
  try {
@@ -108,7 +125,81 @@ async function drainToEof(stream, signal) {
108
125
  catch {
109
126
  // Already released; nothing to do.
110
127
  }
111
- return { text, closed: true };
128
+ return { text: capture.text(), closed: true };
129
+ }
130
+ /**
131
+ * Keeps the first and the last `maxBytes / 2` bytes of a stream and counts what falls between
132
+ * (STREAM_CAPTURE_BYTES). The head is decoded as it arrives; the tail is kept as bytes, trimmed from
133
+ * the front, and decoded once at the end from a codepoint boundary.
134
+ */
135
+ class BoundedCapture {
136
+ half;
137
+ decoder = new TextDecoder();
138
+ head = "";
139
+ headBytes = 0;
140
+ tail = [];
141
+ tailBytes = 0;
142
+ omitted = 0;
143
+ constructor(maxBytes) {
144
+ this.half = Math.max(1, Math.floor(maxBytes / 2));
145
+ }
146
+ push(chunk) {
147
+ let rest = chunk;
148
+ if (this.headBytes < this.half) {
149
+ const take = Math.min(this.half - this.headBytes, rest.length);
150
+ this.head += this.decoder.decode(rest.subarray(0, take), { stream: true });
151
+ this.headBytes += take;
152
+ rest = rest.subarray(take);
153
+ }
154
+ if (rest.length === 0)
155
+ return;
156
+ this.tail.push(rest);
157
+ this.tailBytes += rest.length;
158
+ while (this.tailBytes > this.half) {
159
+ const first = this.tail[0];
160
+ const excess = this.tailBytes - this.half;
161
+ if (first.length <= excess) {
162
+ this.tail.shift();
163
+ this.tailBytes -= first.length;
164
+ this.omitted += first.length;
165
+ }
166
+ else {
167
+ this.tail[0] = first.subarray(excess);
168
+ this.tailBytes -= excess;
169
+ this.omitted += excess;
170
+ }
171
+ }
172
+ }
173
+ text() {
174
+ const tail = Buffer.concat(this.tail);
175
+ if (this.omitted === 0)
176
+ return this.head + this.decoder.decode(tail);
177
+ // The cut can land inside a codepoint: skip its continuation bytes so the tail opens cleanly.
178
+ let start = 0;
179
+ while (start < tail.length && (tail[start] & 0xc0) === 0x80)
180
+ start += 1;
181
+ const head = this.head + this.decoder.decode();
182
+ const marker = `\n[... ${this.omitted + start} bytes of output omitted ...]\n`;
183
+ return head + marker + new TextDecoder().decode(tail.subarray(start));
184
+ }
185
+ }
186
+ /** The deadline is releasable independently of command cancellation and drain grace. */
187
+ function armDeadline(options, onTimeout) {
188
+ let timerId;
189
+ const release = () => {
190
+ if (timerId !== undefined)
191
+ _argvExecDeps.clearTimeout(timerId);
192
+ timerId = undefined;
193
+ };
194
+ if (options.releaseDeadline?.aborted !== true) {
195
+ // A cancellable timer: releaseDeadline and settlement both clear it mid-flight.
196
+ timerId = _argvExecDeps.setTimeout(onTimeout, options.timeoutMs);
197
+ options.releaseDeadline?.addEventListener("abort", release, { once: true });
198
+ }
199
+ return () => {
200
+ release();
201
+ options.releaseDeadline?.removeEventListener("abort", release);
202
+ };
112
203
  }
113
204
  export async function runArgv(options) {
114
205
  const signal = options.signal;
@@ -145,14 +236,14 @@ export async function runArgv(options) {
145
236
  // BUG-13: unlike every git call (routed through gitWithTimeout), a spawn
146
237
  // with no deadline can block its caller forever on a hung install
147
238
  // (registry/NFS stall).
148
- const timerId = _argvExecDeps.setTimeout(() => {
239
+ const clearDeadline = armDeadline(options, () => {
149
240
  timedOut = true;
150
241
  // MEM-4: proc.kill() reaches only the direct child, orphaning postinstall
151
242
  // grandchildren. killProcessGroup(pid, "SIGKILL") kills the whole group
152
243
  // (negative pid), falling back to the single process on ESRCH.
153
244
  killGroup();
154
245
  stopReaders();
155
- }, options.timeoutMs);
246
+ });
156
247
  // US-001: an abort races the timeout. One listener, removed on every settle
157
248
  // path so a never-aborted signal never leaks a registration (AC10).
158
249
  const onAbort = () => {
@@ -168,57 +259,61 @@ export async function runArgv(options) {
168
259
  // to settle (via reader.cancel()) after we kill the process group. US-001
169
260
  // requires that settlement stay bounded even when a background process
170
261
  // inherits the pipe and ignores the SIGKILL.
171
- const stdoutPromise = drainToEof(proc.stdout, stdoutController.signal);
172
- const stderrPromise = drainToEof(proc.stderr, stderrController.signal);
173
- const exitCode = await proc.exited;
174
- // Post-exit drain grace. After exit, the streams MUST close — they were
175
- // owned by the shell, which is now dead. Background processes that
176
- // inherited the pipe (the `&` case) keep it open: that's the orphan.
177
- const graceMs = _argvExecDeps.drainGraceMs;
178
- // Cleared on every settle path: a successful command whose readers close
179
- // before the grace elapses would otherwise leave a pending timer whose
180
- // callback fires 500ms later and resolves an orphaned promise. Under load
181
- // the leaked registrations accumulate in the timer wheel for nothing.
182
- let graceTimerId;
183
- const gracePromise = new Promise((resolve) => {
184
- graceTimerId = _argvExecDeps.setTimeout(() => resolve("expired"), graceMs);
185
- });
186
- const stdoutSettled = await Promise.race([
187
- stdoutPromise,
188
- gracePromise.then(() => "expired"),
189
- ]);
190
- const stderrSettled = await Promise.race([
191
- stderrPromise,
192
- gracePromise.then(() => "expired"),
193
- ]);
194
- if (graceTimerId !== undefined)
195
- _argvExecDeps.clearTimeout(graceTimerId);
196
- const stdoutClosed = stdoutSettled !== "expired";
197
- const stderrClosed = stderrSettled !== "expired";
198
- if (!stdoutClosed || !stderrClosed) {
199
- orphansKilled = true;
200
- killGroup();
201
- // The OS should close the pipes once the group dies; race that against
202
- // a small post-kill budget. If a holdout somehow ignores SIGKILL or is
203
- // not yet reaped, abort the matching reader controller — that drives
204
- // `reader.cancel()` in drainToEof, which forces the pending `read()` to
205
- // resolve with `done: true` and bounds settlement.
206
- if (!stdoutClosed)
207
- stdoutController.abort();
208
- if (!stderrClosed)
209
- stderrController.abort();
262
+ try {
263
+ const stdoutPromise = drainToEof(proc.stdout, stdoutController.signal, options.onOutput?.bind(undefined, "stdout"));
264
+ const stderrPromise = drainToEof(proc.stderr, stderrController.signal, options.onOutput?.bind(undefined, "stderr"));
265
+ const exitCode = await proc.exited;
266
+ // Post-exit drain grace. After exit, the streams MUST close — they were
267
+ // owned by the shell, which is now dead. Background processes that
268
+ // inherited the pipe (the `&` case) keep it open: that's the orphan.
269
+ const graceMs = _argvExecDeps.drainGraceMs;
270
+ // Cleared on every settle path: a successful command whose readers close
271
+ // before the grace elapses would otherwise leave a pending timer whose
272
+ // callback fires 500ms later and resolves an orphaned promise. Under load
273
+ // the leaked registrations accumulate in the timer wheel for nothing.
274
+ let graceTimerId;
275
+ const gracePromise = new Promise((resolve) => {
276
+ graceTimerId = _argvExecDeps.setTimeout(() => resolve("expired"), graceMs);
277
+ });
278
+ const stdoutSettled = await Promise.race([
279
+ stdoutPromise,
280
+ gracePromise.then(() => "expired"),
281
+ ]);
282
+ const stderrSettled = await Promise.race([
283
+ stderrPromise,
284
+ gracePromise.then(() => "expired"),
285
+ ]);
286
+ if (graceTimerId !== undefined)
287
+ _argvExecDeps.clearTimeout(graceTimerId);
288
+ const stdoutClosed = stdoutSettled !== "expired";
289
+ const stderrClosed = stderrSettled !== "expired";
290
+ if (!stdoutClosed || !stderrClosed) {
291
+ orphansKilled = true;
292
+ killGroup();
293
+ // The OS should close the pipes once the group dies; race that against
294
+ // a small post-kill budget. If a holdout somehow ignores SIGKILL or is
295
+ // not yet reaped, abort the matching reader controller — that drives
296
+ // `reader.cancel()` in drainToEof, which forces the pending `read()` to
297
+ // resolve with `done: true` and bounds settlement.
298
+ if (!stdoutClosed)
299
+ stdoutController.abort();
300
+ if (!stderrClosed)
301
+ stderrController.abort();
302
+ }
303
+ // Always await the readers to harvest whatever they captured.
304
+ const stdoutFinal = stdoutClosed ? stdoutSettled : await stdoutPromise;
305
+ const stderrFinal = stderrClosed ? stderrSettled : await stderrPromise;
306
+ return {
307
+ exitCode,
308
+ stdout: stdoutFinal.text,
309
+ stderr: stderrFinal.text,
310
+ timedOut,
311
+ aborted,
312
+ orphansKilled,
313
+ };
314
+ }
315
+ finally {
316
+ clearDeadline();
317
+ signal?.removeEventListener("abort", onAbort);
210
318
  }
211
- // Always await the readers to harvest whatever they captured.
212
- const stdoutFinal = stdoutClosed ? stdoutSettled : await stdoutPromise;
213
- const stderrFinal = stderrClosed ? stderrSettled : await stderrPromise;
214
- _argvExecDeps.clearTimeout(timerId);
215
- signal?.removeEventListener("abort", onAbort);
216
- return {
217
- exitCode,
218
- stdout: stdoutFinal.text,
219
- stderr: stderrFinal.text,
220
- timedOut,
221
- aborted,
222
- orphansKilled,
223
- };
224
319
  }