maka-agent 0.2.0-dev.30.20260912 → 0.2.0-dev.31.20260913

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 (194) hide show
  1. package/THIRD_PARTY_NOTICES.txt +392 -0
  2. package/dist/acp/maka-acp-agent.js +8 -2
  3. package/dist/acp/prompt-content.js +225 -0
  4. package/dist/acp/session-event-mapper.js +103 -0
  5. package/dist/acp/session-registry.js +654 -17
  6. package/dist/acp/stdio-server.js +10 -1
  7. package/dist/cli-core.js +1 -1
  8. package/dist/pi-transcript-tools.js +3 -2
  9. package/dist/pi-transcript.js +12 -2
  10. package/dist/runtime-host-session-channel.js +63 -9
  11. package/native/runtime-host-windows-task-launcher/prebuilds/win32-x64/maka-runtime-host-task-launcher.exe +0 -0
  12. package/node_modules/@maka/core/dist/artifacts.js +6 -0
  13. package/node_modules/@maka/core/dist/attachments.js +7 -2
  14. package/node_modules/@maka/core/dist/durable-tool-result-projection.js +3 -1
  15. package/node_modules/@maka/core/dist/events.js +21 -0
  16. package/node_modules/@maka/core/dist/goal.js +44 -2
  17. package/node_modules/@maka/core/dist/permission.js +0 -1
  18. package/node_modules/@maka/core/dist/runtime-boundary.js +73 -29
  19. package/node_modules/@maka/core/dist/runtime-event.js +6 -3
  20. package/node_modules/@maka/core/dist/runtime-handoff.js +10 -2
  21. package/node_modules/@maka/core/dist/runtime-logical-execution.js +39 -14
  22. package/node_modules/@maka/core/dist/tool-result-archive-evidence.js +3 -1
  23. package/node_modules/@maka/core/dist/tool-result-record-schema.js +2 -1
  24. package/node_modules/@maka/core/dist/unified-diff.js +33 -26
  25. package/node_modules/@maka/runtime/dist/ai-sdk-compaction.js +49 -178
  26. package/node_modules/@maka/runtime/dist/ai-sdk-message-projection.js +7 -2
  27. package/node_modules/@maka/runtime/dist/ai-sdk-turn.js +15 -53
  28. package/node_modules/@maka/runtime/dist/bash-model-output.js +7 -1
  29. package/node_modules/@maka/runtime/dist/bash-tail-buffer.js +13 -52
  30. package/node_modules/@maka/runtime/dist/builtin-tools.js +59 -111
  31. package/node_modules/@maka/runtime/dist/child-fd-input.js +3 -2
  32. package/node_modules/@maka/runtime/dist/context-budget-policy.js +1 -11
  33. package/node_modules/@maka/runtime/dist/context-budget.js +12 -1
  34. package/node_modules/@maka/runtime/dist/conversation-copy.js +104 -9
  35. package/node_modules/@maka/runtime/dist/filesystem-executor.js +10 -6
  36. package/node_modules/@maka/runtime/dist/filesystem-worker/client.js +77 -19
  37. package/node_modules/@maka/runtime/dist/filesystem-worker/launch-spec.js +66 -55
  38. package/node_modules/@maka/runtime/dist/filesystem-worker/operations.js +34 -97
  39. package/node_modules/@maka/runtime/dist/filesystem-worker/protocol.js +25 -10
  40. package/node_modules/@maka/runtime/dist/filesystem-worker/worker-entry.js +2 -0
  41. package/node_modules/@maka/runtime/dist/glob-search.js +74 -0
  42. package/node_modules/@maka/runtime/dist/goal-continuation.js +78 -8
  43. package/node_modules/@maka/runtime/dist/goal-state.js +7 -0
  44. package/node_modules/@maka/runtime/dist/grep-search.js +155 -0
  45. package/node_modules/@maka/runtime/dist/ledger-tool-result-archive-reader.js +84 -94
  46. package/node_modules/@maka/runtime/dist/model-history.js +25 -3
  47. package/node_modules/@maka/runtime/dist/pipe-tail-collector.js +6 -9
  48. package/node_modules/@maka/runtime/dist/read-page.js +231 -0
  49. package/node_modules/@maka/runtime/dist/request-projection.js +2 -15
  50. package/node_modules/@maka/runtime/dist/ripgrep-executable.js +62 -0
  51. package/node_modules/@maka/runtime/dist/ripgrep-guidance.js +81 -0
  52. package/node_modules/@maka/runtime/dist/runtime-event-read-model.js +187 -20
  53. package/node_modules/@maka/runtime/dist/runtime-read-model.js +2 -1
  54. package/node_modules/@maka/runtime/dist/sandbox/linux-profile-path.js +7 -1
  55. package/node_modules/@maka/runtime/dist/sandbox/linux-sandbox.js +20 -5
  56. package/node_modules/@maka/runtime/dist/session-manager.js +6 -6
  57. package/node_modules/@maka/runtime/dist/session-recap.js +9 -5
  58. package/node_modules/@maka/runtime/dist/shell-exec.js +7 -25
  59. package/node_modules/@maka/runtime/dist/shell-run-manager.js +1 -1
  60. package/node_modules/@maka/runtime/dist/shell-run-tool-result.js +1 -1
  61. package/node_modules/@maka/runtime/dist/shell-tools.js +6 -12
  62. package/node_modules/@maka/runtime/dist/tool-availability.js +0 -1
  63. package/node_modules/@maka/runtime/dist/tool-output.js +1 -1
  64. package/node_modules/@maka/runtime/dist/tool-result-archive-capability.js +24 -36
  65. package/node_modules/@maka/runtime/dist/tool-result-archive-resource.js +32 -527
  66. package/node_modules/@maka/runtime/dist/tool-result-archive-transition.js +17 -119
  67. package/node_modules/@maka/runtime/dist/tool-result-archive.js +7 -25
  68. package/node_modules/@maka/runtime/dist/tool-runtime.js +7 -5
  69. package/node_modules/@maka/runtime/dist/workers/filesystem-worker.js +6933 -3681
  70. package/node_modules/@maka/runtime/dist/workspace-executor.js +20 -24
  71. package/node_modules/@maka/runtime/package.json +2 -0
  72. package/node_modules/@maka/runtime-host/dist/client/host-handoff-copy.js +185 -191
  73. package/node_modules/@maka/runtime-host/dist/client/reconnecting-connection.js +3 -0
  74. package/node_modules/@maka/runtime-host/dist/protocol/index.js +5 -1
  75. package/node_modules/@maka/runtime-host/dist/protocol/message.js +2 -2
  76. package/node_modules/@maka/runtime-host/dist/protocol/operations.js +1 -0
  77. package/node_modules/@maka/runtime-host/dist/protocol/session-continuity.js +2 -2
  78. package/node_modules/@maka/runtime-host/dist/protocol/turn.js +10 -2
  79. package/node_modules/@maka/runtime-host/dist/protocol/workhub-coordination.js +38 -0
  80. package/node_modules/@maka/runtime-host/dist/server/execution-artifacts.js +2 -8
  81. package/node_modules/@maka/runtime-host/dist/server/execution-composition.js +2 -0
  82. package/node_modules/@maka/runtime-host/dist/server/goal-coordinator.js +81 -7
  83. package/node_modules/@maka/runtime-host/dist/server/hosted-execution-tool-profile.js +13 -13
  84. package/node_modules/@maka/runtime-host/dist/server/interaction-coordinator.js +65 -0
  85. package/node_modules/@maka/runtime-host/dist/server/root-turn-coordinator.js +1 -0
  86. package/node_modules/@maka/runtime-host/dist/server/session-continuity-coordinator.js +5 -2
  87. package/node_modules/@maka/runtime-host/dist/server/session-transcript-reader.js +88 -72
  88. package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-action-gate.js +21 -4
  89. package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-coordinator.js +145 -1
  90. package/node_modules/@maka/storage/dist/agent-run-store.js +5 -2
  91. package/node_modules/@maka/storage/dist/execution-stores.js +2 -1
  92. package/node_modules/@maka/storage/dist/runtime-transcript-query.js +27 -14
  93. package/node_modules/@maka/storage/dist/sqlite-runtime-store.js +69 -3
  94. package/node_modules/balanced-match/LICENSE.md +23 -0
  95. package/node_modules/balanced-match/README.md +57 -0
  96. package/node_modules/balanced-match/dist/commonjs/index.js +59 -0
  97. package/node_modules/balanced-match/dist/commonjs/package.json +3 -0
  98. package/node_modules/balanced-match/dist/esm/index.js +54 -0
  99. package/node_modules/balanced-match/dist/esm/package.json +3 -0
  100. package/node_modules/balanced-match/package.json +68 -0
  101. package/node_modules/brace-expansion/LICENSE +23 -0
  102. package/node_modules/brace-expansion/README.md +105 -0
  103. package/node_modules/brace-expansion/dist/commonjs/index.js +289 -0
  104. package/node_modules/brace-expansion/dist/commonjs/package.json +3 -0
  105. package/node_modules/brace-expansion/dist/esm/index.js +285 -0
  106. package/node_modules/brace-expansion/dist/esm/package.json +3 -0
  107. package/node_modules/brace-expansion/package.json +64 -0
  108. package/node_modules/glob/LICENSE.md +63 -0
  109. package/node_modules/glob/README.md +1203 -0
  110. package/node_modules/glob/dist/commonjs/glob.js +248 -0
  111. package/node_modules/glob/dist/commonjs/has-magic.js +27 -0
  112. package/node_modules/glob/dist/commonjs/ignore.js +119 -0
  113. package/node_modules/glob/dist/commonjs/index.js +68 -0
  114. package/node_modules/glob/dist/commonjs/index.min.js +4 -0
  115. package/node_modules/glob/dist/commonjs/package.json +3 -0
  116. package/node_modules/glob/dist/commonjs/pattern.js +223 -0
  117. package/node_modules/glob/dist/commonjs/processor.js +301 -0
  118. package/node_modules/glob/dist/commonjs/walker.js +387 -0
  119. package/node_modules/glob/dist/esm/glob.js +244 -0
  120. package/node_modules/glob/dist/esm/has-magic.js +23 -0
  121. package/node_modules/glob/dist/esm/ignore.js +115 -0
  122. package/node_modules/glob/dist/esm/index.js +55 -0
  123. package/node_modules/glob/dist/esm/index.min.js +4 -0
  124. package/node_modules/glob/dist/esm/package.json +3 -0
  125. package/node_modules/glob/dist/esm/pattern.js +219 -0
  126. package/node_modules/glob/dist/esm/processor.js +294 -0
  127. package/node_modules/glob/dist/esm/walker.js +381 -0
  128. package/node_modules/glob/package.json +98 -0
  129. package/node_modules/minimatch/LICENSE.md +55 -0
  130. package/node_modules/minimatch/README.md +528 -0
  131. package/node_modules/minimatch/dist/commonjs/assert-valid-pattern.js +14 -0
  132. package/node_modules/minimatch/dist/commonjs/ast.js +845 -0
  133. package/node_modules/minimatch/dist/commonjs/brace-expressions.js +150 -0
  134. package/node_modules/minimatch/dist/commonjs/escape.js +30 -0
  135. package/node_modules/minimatch/dist/commonjs/index.js +1127 -0
  136. package/node_modules/minimatch/dist/commonjs/package.json +3 -0
  137. package/node_modules/minimatch/dist/commonjs/unescape.js +38 -0
  138. package/node_modules/minimatch/dist/esm/assert-valid-pattern.js +10 -0
  139. package/node_modules/minimatch/dist/esm/ast.js +841 -0
  140. package/node_modules/minimatch/dist/esm/brace-expressions.js +146 -0
  141. package/node_modules/minimatch/dist/esm/escape.js +26 -0
  142. package/node_modules/minimatch/dist/esm/index.js +1114 -0
  143. package/node_modules/minimatch/dist/esm/package.json +3 -0
  144. package/node_modules/minimatch/dist/esm/unescape.js +34 -0
  145. package/node_modules/minimatch/package.json +73 -0
  146. package/node_modules/minipass/LICENSE.md +55 -0
  147. package/node_modules/minipass/README.md +825 -0
  148. package/node_modules/minipass/dist/commonjs/index.js +1038 -0
  149. package/node_modules/minipass/dist/commonjs/package.json +3 -0
  150. package/node_modules/minipass/dist/esm/index.js +1020 -0
  151. package/node_modules/minipass/dist/esm/package.json +3 -0
  152. package/node_modules/minipass/package.json +77 -0
  153. package/node_modules/path-scurry/LICENSE.md +55 -0
  154. package/node_modules/path-scurry/README.md +636 -0
  155. package/node_modules/path-scurry/dist/commonjs/index.js +2018 -0
  156. package/node_modules/path-scurry/dist/commonjs/package.json +3 -0
  157. package/node_modules/path-scurry/dist/esm/index.js +1983 -0
  158. package/node_modules/path-scurry/dist/esm/package.json +3 -0
  159. package/node_modules/path-scurry/node_modules/lru-cache/LICENSE.md +55 -0
  160. package/node_modules/path-scurry/node_modules/lru-cache/README.md +469 -0
  161. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/diagnostics-channel.js +7 -0
  162. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.js +1726 -0
  163. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.min.js +2 -0
  164. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/perf.js +10 -0
  165. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/diagnostics-channel-cjs.d.cts.map +1 -0
  166. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/diagnostics-channel.js +7 -0
  167. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.js +1726 -0
  168. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.min.js +2 -0
  169. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/diagnostics-channel.js +9 -0
  170. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.js +1726 -0
  171. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.min.js +2 -0
  172. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/perf.js +10 -0
  173. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/package.json +3 -0
  174. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/perf.js +10 -0
  175. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/diagnostics-channel.js +4 -0
  176. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.js +1722 -0
  177. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.min.js +2 -0
  178. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/perf.js +7 -0
  179. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/diagnostics-channel-esm.d.mts.map +1 -0
  180. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/diagnostics-channel.js +19 -0
  181. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.js +1722 -0
  182. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.min.js +2 -0
  183. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/diagnostics-channel.js +6 -0
  184. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.js +1722 -0
  185. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.min.js +2 -0
  186. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/perf.js +7 -0
  187. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/package.json +3 -0
  188. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/perf.js +7 -0
  189. package/node_modules/path-scurry/node_modules/lru-cache/package.json +154 -0
  190. package/node_modules/path-scurry/package.json +72 -0
  191. package/package.json +1 -1
  192. package/node_modules/@maka/runtime/dist/active-tool-result-prune.js +0 -248
  193. package/node_modules/@maka/runtime/dist/active-tool-result-working-set.js +0 -218
  194. package/node_modules/@maka/runtime/dist/archive-read-tool.js +0 -115
@@ -0,0 +1,81 @@
1
+ /*
2
+ * Licensed to the Apache Software Foundation (ASF) under one
3
+ * or more contributor license agreements. See the NOTICE file
4
+ * distributed with this work for additional information
5
+ * regarding copyright ownership. The ASF licenses this file
6
+ * to you under the Apache License, Version 2.0 (the
7
+ * "License"); you may not use this file except in compliance
8
+ * with the License. You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing,
13
+ * software distributed under the License is distributed on an
14
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+ * KIND, either express or implied. See the License for the
16
+ * specific language governing permissions and limitations
17
+ * under the License.
18
+ */
19
+ /**
20
+ * Grep's only engine is ripgrep, and nothing ships it (#5167). These builders
21
+ * keep the missing-ripgrep copy identical on the local executor and the
22
+ * filesystem worker, so the model and the user learn the same fix whichever
23
+ * path ran the search. Both paths look ripgrep up again on the next attempt —
24
+ * the local executor on every call, the worker whenever the copy it knew is
25
+ * missing, gone or replaced — so the recovery is always "install it where the
26
+ * Host runs, then retry", never a restart. The Windows sandbox refusal
27
+ * deliberately stays in the worker: that is a capability limit of the
28
+ * AppContainer, not a missing dependency.
29
+ *
30
+ * The copy reaches the model as tool output, so it names a place without
31
+ * naming the machine. A WSL distribution is an identifier Maka already keeps
32
+ * for its Hosts; a hostname is personal (a default macOS name carries its
33
+ * owner's name) and Maka otherwise shows it only as a device name in Desktop,
34
+ * which already says which Host is active.
35
+ */
36
+ const RIPGREP_INSTALL_URL = 'https://github.com/BurntSushi/ripgrep#installation';
37
+ export function currentRipgrepEnvironment(env = process.env) {
38
+ const distribution = env.WSL_DISTRO_NAME?.trim();
39
+ return distribution ? { kind: 'wsl', name: distribution } : undefined;
40
+ }
41
+ /** The worker receives its environment as a launch argument: its own environment block is scrubbed. */
42
+ export function formatRipgrepEnvironmentArg(environment) {
43
+ return `${environment.kind}:${environment.name}`;
44
+ }
45
+ export function parseRipgrepEnvironmentArg(value) {
46
+ const match = value ? /^wsl:(.+)$/u.exec(value) : null;
47
+ return match ? { kind: 'wsl', name: match[1] } : undefined;
48
+ }
49
+ function installLocation(environment) {
50
+ return environment
51
+ ? `the WSL distribution "${environment.name}"`
52
+ : 'the machine this Maka Host runs on (for a remote Host, that server rather than this computer)';
53
+ }
54
+ function installInstructions(environment, platform) {
55
+ const command = platform === 'darwin'
56
+ ? '`brew install ripgrep`'
57
+ : platform === 'win32'
58
+ ? '`winget install BurntSushi.ripgrep.MSVC`'
59
+ : 'your package manager (for example `apt install ripgrep`)';
60
+ return `Install it on ${installLocation(environment)} with ${command}, or see ${RIPGREP_INSTALL_URL}, then retry.`;
61
+ }
62
+ /** The local executor looks `rg` up on PATH at every call. */
63
+ export function ripgrepMissingOnPathMessage(environment, platform = process.platform) {
64
+ return `Grep requires ripgrep (\`rg\`), and it was not found on PATH. ${installInstructions(environment, platform)}`;
65
+ }
66
+ /** The worker was launched without a usable ripgrep; its next launch looks again. */
67
+ export function ripgrepMissingMessage(environment, platform = process.platform) {
68
+ return `Grep requires ripgrep (\`rg\`), and no usable copy was found. ${installInstructions(environment, platform)}`;
69
+ }
70
+ /** The executable the worker was launched with is gone (e.g. a package upgrade removed it). */
71
+ export function ripgrepVanishedMessage(executable, environment) {
72
+ return `Grep could not start ripgrep at ${executable}; it was moved or removed, for example by a package upgrade. Reinstall it on ${installLocation(environment)} if needed, then retry.`;
73
+ }
74
+ /** Local-executor twin of the worker protocol's `grep_unavailable` error. */
75
+ export class RipgrepUnavailableError extends Error {
76
+ code = 'grep_unavailable';
77
+ constructor(message, options) {
78
+ super(message, options);
79
+ this.name = 'RipgrepUnavailableError';
80
+ }
81
+ }
@@ -25,6 +25,7 @@ import { isPartialRuntimeEvent, isTerminalRuntimeEvent, isTerminalRuntimeEventSt
25
25
  import { decodePersistedToolResultContent } from '@maka/core/tool-result-record-schema';
26
26
  const SETTLED_SANDBOX_BOUNDARY_STATUSES = SANDBOX_BOUNDARY_REQUEST_STATUSES.filter((status) => status !== 'pending');
27
27
  import { isArchivedToolResultPlaceholder } from './tool-result-archive.js';
28
+ import { truncateToolOutput } from './tool-output.js';
28
29
  /**
29
30
  * Whether a diagnostic means the projection may have lost user-visible content.
30
31
  *
@@ -94,7 +95,54 @@ const UNCLAIMED_RUNTIME_EVENT_DIAGNOSTIC_CODES = [
94
95
  export function isUnclaimedRuntimeEventDiagnostic(diagnostic) {
95
96
  return UNCLAIMED_RUNTIME_EVENT_DIAGNOSTIC_CODES.includes(diagnostic.code);
96
97
  }
98
+ /**
99
+ * Keep a completed local terminal result useful but bounded in transcript views.
100
+ * The durable RuntimeEvent remains untouched and the marker names its retained
101
+ * result, so readers can fetch the full output without repeating the command.
102
+ */
103
+ export function projectTranscriptToolResult(event, content) {
104
+ if (content.kind !== 'terminal' ||
105
+ content.output.mode !== 'pipes' ||
106
+ !hasLocalTerminalModelProjection(event)) {
107
+ return content;
108
+ }
109
+ const recoveryHint = `Read ${JSON.stringify({
110
+ path: `maka://runtime/tool-results/${encodeURIComponent(event.id)}`,
111
+ })} for the retained output; follow next to continue.`;
112
+ const options = { maxBytes: 1024, maxLines: 20, direction: 'tail', recoveryHint };
113
+ const stdout = truncateToolOutput(content.output.stdout, options);
114
+ const stderr = truncateToolOutput(content.output.stderr, options);
115
+ if (!stdout.truncated && !stderr.truncated)
116
+ return content;
117
+ return {
118
+ ...content,
119
+ output: {
120
+ ...content.output,
121
+ stdout: stdout.content,
122
+ stderr: stderr.content,
123
+ stdoutTruncated: content.output.stdoutTruncated || stdout.truncated,
124
+ stderrTruncated: content.output.stderrTruncated || stderr.truncated,
125
+ },
126
+ };
127
+ }
128
+ function hasLocalTerminalModelProjection(event) {
129
+ const content = event.content;
130
+ if (content?.kind !== 'function_response' || content.providerExecuted)
131
+ return false;
132
+ const projection = content.modelProjection;
133
+ return (projection?.kind === 'json' &&
134
+ projection.value !== null &&
135
+ typeof projection.value === 'object' &&
136
+ 'kind' in projection.value &&
137
+ projection.value.kind === 'terminal');
138
+ }
97
139
  export function projectRuntimeEventsToStoredMessages(events, options) {
140
+ const projector = createRuntimeEventStoredMessageProjector(options);
141
+ for (const event of events)
142
+ projector.push(event);
143
+ return projector.finish();
144
+ }
145
+ export function createRuntimeEventStoredMessageProjector(options) {
98
146
  const state = {
99
147
  invocations: normalizeInvocations(options.invocations),
100
148
  diagnostics: [],
@@ -102,6 +150,8 @@ export function projectRuntimeEventsToStoredMessages(events, options) {
102
150
  permissionRequestById: new Map(),
103
151
  thinkingByMessageId: new Map(),
104
152
  contentOrderByMessageId: new Map(),
153
+ ...(options.projectToolResult ? { projectToolResult: options.projectToolResult } : {}),
154
+ sourceOrder: -1,
105
155
  };
106
156
  const messages = [];
107
157
  /**
@@ -112,19 +162,48 @@ export function projectRuntimeEventsToStoredMessages(events, options) {
112
162
  * handled are exactly that event's rows. A durable reader numbers its pages
113
163
  * from this, which is why it is recorded here rather than rediscovered.
114
164
  */
115
- const sourceEventIds = [];
116
- let reading;
117
- const attributeEmitted = () => {
118
- while (sourceEventIds.length < messages.length)
119
- sourceEventIds.push(reading.id);
165
+ const messageSources = [];
166
+ const diagnosticSources = [];
167
+ const deferredPermissionAcceptances = [];
168
+ const permissionRequestIds = new Set();
169
+ let nextSourceOrder = 0;
170
+ let finished;
171
+ const attributeEmitted = (event, sourceOrder, firstSourcePosition) => {
172
+ let sourcePosition = firstSourcePosition;
173
+ while (messageSources.length < messages.length) {
174
+ const message = messages[messageSources.length];
175
+ messageSources.push({
176
+ eventId: event.id,
177
+ sourceOrder,
178
+ sourcePosition,
179
+ emittedOrder: messageSources.length,
180
+ });
181
+ sourcePosition += 1;
182
+ options.onMessage?.(message, event.id);
183
+ }
184
+ return sourcePosition;
120
185
  };
121
- for (const event of events) {
122
- attributeEmitted();
123
- reading = event;
186
+ const attributeDiagnostics = (sourceOrder, firstSourcePosition) => {
187
+ let sourcePosition = firstSourcePosition;
188
+ while (diagnosticSources.length < state.diagnostics.length) {
189
+ diagnosticSources.push({
190
+ sourceOrder,
191
+ sourcePosition,
192
+ emittedOrder: diagnosticSources.length,
193
+ });
194
+ sourcePosition += 1;
195
+ }
196
+ return sourcePosition;
197
+ };
198
+ const projectEvent = (event, sourceOrder) => {
199
+ let nextMessagePosition = 0;
200
+ let nextDiagnosticPosition = 0;
201
+ state.sourceOrder = sourceOrder;
124
202
  recordStepContentOrder(event, state);
125
203
  if (isPartialRuntimeEvent(event)) {
126
204
  diagnostic(state, event, 'partial_skipped', 'partial RuntimeEvent skipped');
127
- continue;
205
+ attributeDiagnostics(sourceOrder, nextDiagnosticPosition);
206
+ return;
128
207
  }
129
208
  let projected = false;
130
209
  const content = event.content;
@@ -197,7 +276,17 @@ export function projectRuntimeEventsToStoredMessages(events, options) {
197
276
  projected = true;
198
277
  }
199
278
  if (event.actions?.permissionAnswerAccepted) {
200
- projectCanonicalPermissionOutcome(event, state, messages, options.canonicalPermissionOutcomes);
279
+ nextMessagePosition = attributeEmitted(event, sourceOrder, nextMessagePosition);
280
+ nextDiagnosticPosition = attributeDiagnostics(sourceOrder, nextDiagnosticPosition);
281
+ const requestId = event.actions.permissionAnswerAccepted.requestId;
282
+ permissionRequestIds.add(requestId);
283
+ deferredPermissionAcceptances.push({
284
+ event: permissionAcceptanceProjectionEvent(event),
285
+ ledgerRequest: state.permissionRequestById.get(requestId),
286
+ sourceOrder,
287
+ messagePosition: nextMessagePosition++,
288
+ diagnosticPosition: nextDiagnosticPosition++,
289
+ });
201
290
  projected = true;
202
291
  }
203
292
  if (event.actions?.permissionClosureAccepted) {
@@ -284,14 +373,74 @@ export function projectRuntimeEventsToStoredMessages(events, options) {
284
373
  diagnostic(state, event, 'unsupported_event', 'RuntimeEvent shape is not supported by the legacy read-model projection');
285
374
  }
286
375
  }
287
- }
288
- for (const pendingItems of state.thinkingByMessageId.values()) {
289
- for (const pending of pendingItems) {
290
- diagnostic(state, pending.event, 'unsupported_event', 'thinking content has no assistant text row with a matching message id');
376
+ attributeEmitted(event, sourceOrder, nextMessagePosition);
377
+ attributeDiagnostics(sourceOrder, nextDiagnosticPosition);
378
+ };
379
+ const push = (event) => {
380
+ if (finished)
381
+ throw new Error('RuntimeEvent StoredMessage projector is already finished');
382
+ const sourceOrder = nextSourceOrder++;
383
+ projectEvent(options.active ? settledPresentationEvent(event) : event, sourceOrder);
384
+ };
385
+ const finish = () => {
386
+ if (finished)
387
+ return finished;
388
+ for (const acceptance of deferredPermissionAcceptances) {
389
+ const before = messages.length;
390
+ projectCanonicalPermissionOutcome(acceptance.event, state, messages, options.canonicalPermissionOutcomes, acceptance.ledgerRequest);
391
+ if (messages.length > before) {
392
+ attributeEmitted(acceptance.event, acceptance.sourceOrder, acceptance.messagePosition);
393
+ }
394
+ attributeDiagnostics(acceptance.sourceOrder, acceptance.diagnosticPosition);
291
395
  }
292
- }
293
- attributeEmitted();
294
- return { messages, diagnostics: state.diagnostics, sourceEventIds };
396
+ if (options.active) {
397
+ for (const pendingItems of [...state.thinkingByMessageId.values()]) {
398
+ const pending = pendingItems.at(-1);
399
+ if (pending)
400
+ projectEvent(emptyAssistantText(pending.event), pending.sourceOrder);
401
+ }
402
+ }
403
+ const orderedDiagnostics = state.diagnostics
404
+ .map((diagnostic, index) => ({ diagnostic, source: diagnosticSources[index] }))
405
+ .sort((left, right) => left.source.sourceOrder - right.source.sourceOrder ||
406
+ left.source.sourcePosition - right.source.sourcePosition ||
407
+ left.source.emittedOrder - right.source.emittedOrder);
408
+ state.diagnostics.splice(0, state.diagnostics.length, ...orderedDiagnostics.map(({ diagnostic }) => diagnostic));
409
+ if (!options.active) {
410
+ for (const pendingItems of state.thinkingByMessageId.values()) {
411
+ for (const pending of pendingItems) {
412
+ diagnostic(state, pending.event, 'unsupported_event', 'thinking content has no assistant text row with a matching message id');
413
+ }
414
+ }
415
+ }
416
+ const ordered = messages
417
+ .map((message, index) => ({ message, source: messageSources[index] }))
418
+ .sort((left, right) => left.source.sourceOrder - right.source.sourceOrder ||
419
+ left.source.sourcePosition - right.source.sourcePosition ||
420
+ left.source.emittedOrder - right.source.emittedOrder);
421
+ finished = {
422
+ messages: ordered.map(({ message }) => message),
423
+ diagnostics: state.diagnostics,
424
+ sourceEventIds: ordered.map(({ source }) => source.eventId),
425
+ };
426
+ deferredPermissionAcceptances.length = 0;
427
+ messageSources.length = 0;
428
+ diagnosticSources.length = 0;
429
+ state.invocations.clear();
430
+ state.toolNameByUseId.clear();
431
+ state.permissionRequestById.clear();
432
+ state.thinkingByMessageId.clear();
433
+ state.contentOrderByMessageId.clear();
434
+ state.projectToolResult = undefined;
435
+ return finished;
436
+ };
437
+ return {
438
+ push,
439
+ finish,
440
+ get permissionRequestIds() {
441
+ return [...permissionRequestIds];
442
+ },
443
+ };
295
444
  }
296
445
  /**
297
446
  * A running invocation's events as the transcript should show them right now.
@@ -564,6 +713,7 @@ function projectThinking(event, state, messages) {
564
713
  event,
565
714
  messageId,
566
715
  text: event.content.text,
716
+ sourceOrder: state.sourceOrder,
567
717
  ...(event.content.signature !== undefined ? { signature: event.content.signature } : {}),
568
718
  ...(event.content.providerOptions !== undefined
569
719
  ? { providerOptions: structuredClone(event.content.providerOptions) }
@@ -669,7 +819,7 @@ function projectFunctionResponse(event, state, messages) {
669
819
  }
670
820
  if (event.content.name)
671
821
  state.toolNameByUseId.set(toolUseId, event.content.name);
672
- const resultContent = archivedPlaceholder
822
+ const decodedResult = archivedPlaceholder
673
823
  ? {
674
824
  kind: 'archived_tool_result',
675
825
  status: 'not_loaded',
@@ -687,6 +837,9 @@ function projectFunctionResponse(event, state, messages) {
687
837
  reason: archivedPlaceholder.reason,
688
838
  }
689
839
  : normalizedResult;
840
+ const resultContent = state.projectToolResult
841
+ ? state.projectToolResult(event, decodedResult)
842
+ : decodedResult;
690
843
  messages.push({
691
844
  type: 'tool_result',
692
845
  id: stableMessageId(event, state, 'tool_result'),
@@ -766,11 +919,10 @@ function projectPermissionDecision(event, state, messages) {
766
919
  });
767
920
  return true;
768
921
  }
769
- function projectCanonicalPermissionOutcome(event, state, messages, outcomes) {
922
+ function projectCanonicalPermissionOutcome(event, state, messages, outcomes, ledgerRequest) {
770
923
  const accepted = event.actions?.permissionAnswerAccepted;
771
924
  if (!accepted)
772
925
  return;
773
- const ledgerRequest = state.permissionRequestById.get(accepted.requestId);
774
926
  const canonical = outcomes?.get(accepted.requestId);
775
927
  const toolUseId = event.refs?.toolCallId;
776
928
  if (!canonical || !toolUseId) {
@@ -807,6 +959,21 @@ function projectCanonicalPermissionOutcome(event, state, messages, outcomes) {
807
959
  ...(ledgerRequest?.hint !== undefined ? { hint: ledgerRequest.hint } : {}),
808
960
  });
809
961
  }
962
+ function permissionAcceptanceProjectionEvent(event) {
963
+ return {
964
+ id: event.id,
965
+ sessionId: event.sessionId,
966
+ invocationId: event.invocationId,
967
+ runId: event.runId,
968
+ turnId: event.turnId,
969
+ ts: event.ts,
970
+ partial: event.partial,
971
+ role: event.role,
972
+ author: event.author,
973
+ actions: { permissionAnswerAccepted: event.actions.permissionAnswerAccepted },
974
+ ...(event.refs?.toolCallId ? { refs: { toolCallId: event.refs.toolCallId } } : {}),
975
+ };
976
+ }
810
977
  function projectTokenUsage(event, state, messages) {
811
978
  const usage = event.actions?.tokenUsage;
812
979
  if (!usage)
@@ -18,7 +18,7 @@
18
18
  */
19
19
  import { deriveTurnRecords } from '@maka/core/session';
20
20
  import { isSessionInlineInvocation } from '@maka/core/runtime-invocation';
21
- import { activePresentationRuntimeEvents, classifyRuntimeEventTerminalFact, isHardRuntimeEventReadModelDiagnostic, projectRuntimeEventsToStoredMessages, } from './runtime-event-read-model.js';
21
+ import { activePresentationRuntimeEvents, classifyRuntimeEventTerminalFact, isHardRuntimeEventReadModelDiagnostic, projectRuntimeEventsToStoredMessages, projectTranscriptToolResult, } from './runtime-event-read-model.js';
22
22
  import { buildRuntimeEventModelReplayPlan, } from './model-history.js';
23
23
  const CANONICAL_PERMISSION_READ_CONCURRENCY = 8;
24
24
  export class RuntimeReadModelError extends Error {
@@ -116,6 +116,7 @@ export class RuntimeReadModel {
116
116
  const projected = projectRuntimeEventsToStoredMessages(input.events, {
117
117
  invocations: input.invocations,
118
118
  canonicalPermissionOutcomes: canonicalPermissionRead.outcomes,
119
+ projectToolResult: projectTranscriptToolResult,
119
120
  });
120
121
  const diagnostics = [
121
122
  ...input.diagnostics,
@@ -16,7 +16,7 @@
16
16
  * specific language governing permissions and limitations
17
17
  * under the License.
18
18
  */
19
- import { closeSync, constants, fstatSync, lstatSync, openSync } from 'node:fs';
19
+ import { closeSync, constants, fstatSync, lstatSync, openSync, readlinkSync } from 'node:fs';
20
20
  export function pinExistingLinuxProfilePath(input) {
21
21
  const existing = (() => {
22
22
  try {
@@ -43,6 +43,12 @@ export function pinExistingLinuxProfilePath(input) {
43
43
  closeSync(sourceFd);
44
44
  };
45
45
  try {
46
+ // O_NOFOLLOW only protects the last component. Check the kernel's path for
47
+ // the opened object too, so a replaced ancestor cannot redirect an approved
48
+ // canonical path. Checking the original pathname again would race anew.
49
+ if (process.platform === 'linux' && readlinkSync(`/proc/self/fd/${sourceFd}`) !== input.path) {
50
+ throw new Error(`Approved sandbox path changed before pinning: ${input.path}`);
51
+ }
46
52
  const metadata = fstatSync(sourceFd, { bigint: true });
47
53
  if (metadata.dev !== BigInt(existing.dev) ||
48
54
  metadata.ino !== BigInt(existing.ino) ||
@@ -17,7 +17,7 @@
17
17
  * under the License.
18
18
  */
19
19
  import { posix } from 'node:path';
20
- import { readdirSync } from 'node:fs';
20
+ import { fstatSync, readdirSync } from 'node:fs';
21
21
  import { detectLinuxSandboxCapability, LINUX_BWRAP_REQUIRED_NAMESPACE_ARGS, } from './linux-capability.js';
22
22
  const DEFAULT_READ_ONLY_HOST_PATHS = ['/usr', '/bin', '/sbin', '/lib', '/lib64', '/etc'];
23
23
  export class LinuxBubblewrapBackend {
@@ -59,7 +59,12 @@ export class LinuxBubblewrapBackend {
59
59
  catch (error) {
60
60
  return failure('backend_not_available', `Unable to enumerate protected metadata: ${error instanceof Error ? error.message : String(error)}`, plan.platform, plan.preference);
61
61
  }
62
- const pinnedFdInputs = command.pathContext.pinnedProfilePaths?.map(({ fd, sourceFd, releaseSource }) => ({
62
+ const exactReadableRoots = exactProfileRoots(command.profile, 'read');
63
+ const pinnedFdInputs = command.pathContext.pinnedProfilePaths
64
+ ?.filter((entry) => !(entry.access === 'read' &&
65
+ exactReadableRoots.has(entry.path) &&
66
+ fstatSync(entry.sourceFd).isDirectory()))
67
+ .map(({ fd, sourceFd, releaseSource }) => ({
63
68
  fd,
64
69
  sourceFd,
65
70
  ...(releaseSource ? { releaseSource } : {}),
@@ -159,9 +164,6 @@ function buildBubblewrapArgvWithRoots(input, roots) {
159
164
  if (networkRestricted(command.profile)) {
160
165
  argv.push('--unshare-net', '--seccomp', '3');
161
166
  }
162
- for (const path of DEFAULT_READ_ONLY_HOST_PATHS) {
163
- argv.push('--ro-bind-try', path, path);
164
- }
165
167
  const runtimeWritableRoots = removeNestedRoots((command.pathContext.runtimeWritableRoots ?? []).filter(isUsableRuntimeRoot));
166
168
  const unavailableProfilePaths = new Set(command.pathContext.unavailableProfilePaths ?? []);
167
169
  const pinnedRuntimeWritableRoots = new Map((command.pathContext.pinnedRuntimeWritableRoots ?? []).map((entry) => [entry.path, entry]));
@@ -219,6 +221,17 @@ function buildBubblewrapArgvWithRoots(input, roots) {
219
221
  for (const directory of requiredParentDirectories(mountRoots)) {
220
222
  argv.push('--dir', directory);
221
223
  }
224
+ // Materialize exact directory markers before any host bind. Creating them
225
+ // inside an already-mounted tree could follow concurrently replaced symlinks.
226
+ const exactReadableDirectories = new Set(profileReadableRoots.filter((root) => {
227
+ const pinned = pinnedProfilePaths.get(root);
228
+ return exactReadableRoots.has(root) && pinned && fstatSync(pinned.sourceFd).isDirectory();
229
+ }));
230
+ for (const directory of exactReadableDirectories)
231
+ argv.push('--dir', directory);
232
+ for (const path of DEFAULT_READ_ONLY_HOST_PATHS) {
233
+ argv.push('--ro-bind-try', path, path);
234
+ }
222
235
  for (const directory of extraProgramDirectories) {
223
236
  argv.push('--ro-bind', directory, directory);
224
237
  }
@@ -243,6 +256,8 @@ function buildBubblewrapArgvWithRoots(input, roots) {
243
256
  const pinned = pinnedProfilePaths.get(root);
244
257
  if (exactReadableRoots.has(root) && !pinned)
245
258
  continue;
259
+ if (exactReadableDirectories.has(root))
260
+ continue;
246
261
  argv.push('--ro-bind', pinned ? `/proc/self/fd/${pinned.fd}` : root, root);
247
262
  }
248
263
  for (const root of profileWritableRoots) {
@@ -720,10 +720,10 @@ export class SessionManager {
720
720
  : header.permissionMode;
721
721
  const narrows = narrowsExecutionAuthority(current, permissionMode);
722
722
  if (narrows && this.runtimeKernel.hasActiveRuns(sessionId)) {
723
- throw new Error('当前任务正在运行,等结束后再切换沙箱边界。');
723
+ throw new SessionConfigurationTransitionError('session_busy', 'Execution boundary cannot change while a Turn is running');
724
724
  }
725
725
  if (header.status === 'waiting_for_user') {
726
- throw new Error('当前有沙箱边界请求正在等待确认,处理后再切换。');
726
+ throw new SessionConfigurationTransitionError('session_busy', 'Execution boundary cannot change while an Interaction is pending');
727
727
  }
728
728
  const boundary = await this.commitExecutionBoundaryTransition(sessionId, current, permissionMode, async () => () => this.deps.store.setExecutionBoundaryKind(sessionId, kind, { permissionMode }));
729
729
  return boundary;
@@ -904,18 +904,18 @@ export class SessionManager {
904
904
  throw new PlanConflictError('Linked child Sessions cannot enter Plan mode');
905
905
  }
906
906
  if (this.runtimeKernel.hasActiveRuns(sessionId)) {
907
- throw new Error('当前任务正在运行,等结束后再切换协作模式。');
907
+ throw new SessionConfigurationTransitionError('session_busy', 'Collaboration mode cannot change while a Turn is running');
908
908
  }
909
909
  if (previous.status === 'waiting_for_user') {
910
- throw new Error('当前有工具调用正在等待确认,处理后再切换协作模式。');
910
+ throw new SessionConfigurationTransitionError('session_busy', 'Collaboration mode cannot change while an Interaction is pending');
911
911
  }
912
912
  const planState = await this.requirePlanStore().readState(sessionId);
913
913
  if (mode === 'plan' && planState.activeExecutionId) {
914
- throw new Error('当前计划仍在执行,结束或中断后才能切换到 Plan Mode。');
914
+ throw new SessionConfigurationTransitionError('session_busy', 'An active Plan execution prevents entering Plan mode');
915
915
  }
916
916
  const latestProposal = planState.proposals.find((proposal) => proposal.proposalId === planState.latestProposalId);
917
917
  if (mode === 'agent' && latestProposal?.status === 'pending_approval') {
918
- throw new Error('当前方案正在等待审批,请明确放弃方案后再退出 Plan Mode。');
918
+ throw new SessionConfigurationTransitionError('operation_conflict', 'A pending Plan proposal must be resolved before leaving Plan mode');
919
919
  }
920
920
  const next = await this.deps.store.updateHeader(sessionId, {
921
921
  collaborationMode: mode,
@@ -19,7 +19,7 @@
19
19
  import { runtimeEventHasModelVisibleContent } from '@maka/core/runtime-event';
20
20
  import { resolveSelectedModelContextWindow } from './context-budget-policy.js';
21
21
  import { stableJsonLength } from './context-budget-helpers.js';
22
- import { groupEventsByTurn } from './model-history.js';
22
+ import { groupEventsByTurn, formatTextWithInlineRefs } from './model-history.js';
23
23
  import { HistoryCompactSummarizerError } from './history-compact-error.js';
24
24
  import { fitHistoryCompactMessages } from './history-compact-input-fit.js';
25
25
  const SESSION_RECAP_TOOL_OUTCOME_MAX_CHARS = 600;
@@ -99,10 +99,14 @@ function projectSessionRecapMessages(events) {
99
99
  continue;
100
100
  const content = event.content;
101
101
  if (content?.kind === 'text' && (event.role === 'user' || event.role === 'model')) {
102
- const text = content.text.trim();
103
- if (text.length > 0) {
104
- messages.push({ role: event.role === 'user' ? 'user' : 'assistant', content: text });
105
- }
102
+ // The gate above already decided visibility through the shared
103
+ // predicate, which is satisfied by non-empty text or by the structured
104
+ // carriers — so every event reaching here projects, with its trimmed
105
+ // text and staged refs rendered by the shared inline-ref formatter.
106
+ messages.push({
107
+ role: event.role === 'user' ? 'user' : 'assistant',
108
+ content: formatTextWithInlineRefs({ ...content, text: content.text.trim() }),
109
+ });
106
110
  continue;
107
111
  }
108
112
  if (content?.kind !== 'function_response')
@@ -30,11 +30,11 @@ import { buildShellSpawnPlan, defaultShellPlan } from './shell-detect.js';
30
30
  import { BashTailBuffer } from './bash-tail-buffer.js';
31
31
  import { DEFAULT_PROCESS_TERMINATION_GRACE_MS } from './process-tree-terminator.js';
32
32
  import { DEFAULT_PROCESS_IO_DRAIN_TIMEOUT_MS, manageChildProcessLifecycle, } from './child-process-lifecycle.js';
33
- import { OUTPUT_RECOVERY_HINT } from './tool-output.js';
34
33
  import { buildSpawnStdio, closeChildFdSources, writeChildFdInputs, } from './child-fd-input.js';
35
34
  // Per-stream cap on the output RETAINED for the result (~1MB). This only bounds
36
- // what is kept to return. The tool layer (truncateToolOutput) trims this further
37
- // to the model's budget. Shared so both Bash paths retain identically.
35
+ // what is kept to return. The tool layer preserves this result for durable
36
+ // storage; unified result pruning bounds its model projection.
37
+ // Shared so both Bash paths retain identically.
38
38
  export const BASH_MAX_RETAINED_CHARS = 1024 * 1024;
39
39
  // Per-stream cap on output forwarded LIVE via emitOutput (~1MB). The command is
40
40
  // never killed for size and the full recoverable tail is still RETAINED (above),
@@ -47,20 +47,6 @@ export const BASH_MAX_LIVE_EMIT_CHARS = 1024 * 1024;
47
47
  // not lost — it still feeds the retained tail and the returned result.
48
48
  export const LIVE_OUTPUT_SUPPRESSED_MARKER = '[live output suppressed: too much output to stream live; the command keeps ' +
49
49
  'running and its result still contains the most recent output]';
50
- // Appended to a stream when BashTailBuffer dropped an oversized line that had no
51
- // newline to truncate at (dropped whole for redaction safety). Without it, a
52
- // command whose only output was one giant line would look like it produced
53
- // nothing. Carries no dropped content — just a recoverable notice.
54
- const UNSAFE_DROP_MARKER = '[a single line larger than the output limit was omitted for safety. ' +
55
- OUTPUT_RECOVERY_HINT +
56
- ']';
57
- export function shellTailValueWithUnsafeDropMarker(buf) {
58
- const text = buf.value(); // value() trims first, so the drop flag is current after it
59
- if (!buf.hasDroppedUnsafe())
60
- return text;
61
- // Append (not prepend) so a later tail-keeping truncateToolOutput retains it.
62
- return text ? `${text}\n${UNSAFE_DROP_MARKER}` : UNSAFE_DROP_MARKER;
63
- }
64
50
  /**
65
51
  * Run `command` in a shell, streaming output into a memory-bounded tail. Never
66
52
  * kills the command for producing too much output — it keeps only the last
@@ -213,8 +199,8 @@ function runSpawnedProcessWithBoundedTail(program, args, useShellOption, options
213
199
  return;
214
200
  settled = true;
215
201
  cleanup();
216
- const stdout = shellTailValueWithUnsafeDropMarker(stdoutBuf);
217
- const stderr = shellTailValueWithUnsafeDropMarker(stderrBuf);
202
+ const stdout = stdoutBuf.value();
203
+ const stderr = stderrBuf.value();
218
204
  resolvePromise({
219
205
  exitCode: termination
220
206
  ? termination.timedOut
@@ -223,12 +209,8 @@ function runSpawnedProcessWithBoundedTail(program, args, useShellOption, options
223
209
  : (outcome.exitCode ?? (outcome.signal ? 128 : 1)),
224
210
  stdout,
225
211
  stderr,
226
- stdoutTruncated: outcome.incompleteOutputs.has('stdout') ||
227
- stdoutChars > stdout.length ||
228
- stdoutBuf.hasDroppedUnsafe(),
229
- stderrTruncated: outcome.incompleteOutputs.has('stderr') ||
230
- stderrChars > stderr.length ||
231
- stderrBuf.hasDroppedUnsafe(),
212
+ stdoutTruncated: outcome.incompleteOutputs.has('stdout') || stdoutChars > stdout.length,
213
+ stderrTruncated: outcome.incompleteOutputs.has('stderr') || stderrChars > stderr.length,
232
214
  timedOut: !!termination?.timedOut,
233
215
  aborted: !!termination?.aborted,
234
216
  });
@@ -715,7 +715,7 @@ export class ShellRunProcessManager {
715
715
  sourceToolCallId: input.sourceToolCallId,
716
716
  ...(input.visibility === undefined ? {} : { visibility: input.visibility }),
717
717
  cwd: input.cwd,
718
- command: redactSecrets(input.command),
718
+ command: input.command,
719
719
  status: 'starting',
720
720
  startedAt,
721
721
  updatedAt: startedAt,
@@ -43,7 +43,7 @@ export function terminalContent(record) {
43
43
  status: terminalResultStatus(record.status),
44
44
  ...(record.exitCode !== undefined ? { exitCode: record.exitCode } : {}),
45
45
  ...(record.failureMessage !== undefined ? { failureMessage: record.failureMessage } : {}),
46
- output: projectShellOutputForModel(record.output),
46
+ output: record.output,
47
47
  ...(sandboxDenialForRecord(record) ? { sandboxDenial: sandboxDenialForRecord(record) } : {}),
48
48
  };
49
49
  }