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
@@ -23,108 +23,98 @@ import { decodeLedgerTransition, reduceEffectiveModelProjections, } from './mode
23
23
  import { isArchivedToolResultPlaceholder, } from './tool-result-archive.js';
24
24
  import { serializeToolResultProjectionV1 } from './tool-result-archive-encoding.js';
25
25
  import { TOOL_RESULT_ARCHIVE_EVIDENCE_MAX_BYTES, TOOL_RESULT_ARCHIVE_EVIDENCE_MAX_TRANSITIONS, } from '@maka/core/tool-result-archive-evidence';
26
- /**
27
- * Read-only v1 reconstruction. It never calls a live tool projector, reads an
28
- * Artifact, changes history, or authorizes access from a hash alone.
29
- * The evidence port is trusted to return the complete bounded target history.
30
- */
31
- export function createLedgerToolResultArchiveReader(evidence) {
32
- return async (input) => {
33
- const request = { ...input };
34
- if (!isArchivedToolResultPlaceholder(request) ||
35
- !/^[a-f0-9]{64}$/.test(request.bodySha256) ||
36
- !Number.isSafeInteger(request.originalBytes) ||
37
- request.originalBytes < 1) {
38
- return { ok: false, reason: 'corrupt' };
26
+ async function readLedgerArchive(evidence, request) {
27
+ const identity = 'bodySha256' in request ? request : undefined;
28
+ if (identity &&
29
+ (!/^[a-f0-9]{64}$/.test(identity.bodySha256) ||
30
+ !Number.isSafeInteger(identity.originalBytes) ||
31
+ identity.originalBytes < 1))
32
+ return { ok: false, reason: 'corrupt' };
33
+ if (!Number.isSafeInteger(request.maxBytes) ||
34
+ (identity && request.maxBytes < identity.originalBytes))
35
+ return { ok: false, reason: 'too_large' };
36
+ try {
37
+ const loaded = await evidence.read({
38
+ sessionId: request.sessionId,
39
+ runtimeEventId: request.runtimeEventId,
40
+ });
41
+ if (!loaded.ok)
42
+ return {
43
+ ok: false,
44
+ reason: loaded.reason === 'unavailable' ? 'read_failed' : loaded.reason,
45
+ };
46
+ const { event } = loaded;
47
+ const content = event.content;
48
+ if (event.sessionId !== request.sessionId)
49
+ return { ok: false, reason: 'session_mismatch' };
50
+ if (event.id !== request.runtimeEventId ||
51
+ content?.kind !== 'function_response' ||
52
+ (identity && (content.id !== identity.toolCallId || content.name !== identity.toolName)) ||
53
+ content.providerExecuted ||
54
+ !content.modelProjection)
55
+ return { ok: false, reason: 'source_mismatch' };
56
+ let source = decodeDurableToolResultProjection(content.modelProjection);
57
+ const byId = new Map();
58
+ for (const record of loaded.transitions) {
59
+ const transition = decodeLedgerTransition(record, request.sessionId);
60
+ if (!transition ||
61
+ record.sessionId !== request.sessionId ||
62
+ transition.target.runtimeEventId !== event.id)
63
+ return { ok: false, reason: 'corrupt' };
64
+ const previous = byId.get(transition.transitionId);
65
+ if (previous &&
66
+ JSON.stringify({ ...previous, createdAt: 0 }) !==
67
+ JSON.stringify({ ...transition, createdAt: 0 })) {
68
+ return { ok: false, reason: 'corrupt' };
69
+ }
70
+ byId.set(transition.transitionId, transition);
39
71
  }
40
- const maxBytes = request.maxBytes ?? request.originalBytes;
41
- if (!Number.isSafeInteger(maxBytes) || maxBytes < request.originalBytes)
42
- return { ok: false, reason: 'too_large' };
43
- try {
44
- const loaded = await evidence.read({
45
- sessionId: request.sessionId,
46
- runtimeEventId: request.runtimeEventId,
47
- });
48
- if (!loaded.ok)
49
- return {
50
- ok: false,
51
- reason: loaded.reason === 'unavailable' ? 'read_failed' : loaded.reason,
52
- };
53
- const { event } = loaded;
54
- const content = event.content;
55
- if (event.sessionId !== request.sessionId)
56
- return { ok: false, reason: 'session_mismatch' };
57
- if (event.id !== request.runtimeEventId ||
58
- content?.kind !== 'function_response' ||
59
- content.id !== request.toolCallId ||
60
- content.name !== request.toolName ||
61
- content.providerExecuted ||
62
- !content.modelProjection)
63
- return { ok: false, reason: 'source_mismatch' };
64
- let source = decodeDurableToolResultProjection(content.modelProjection);
65
- const byId = new Map();
66
- for (const record of loaded.transitions) {
67
- const transition = decodeLedgerTransition(record, request.sessionId);
68
- if (!transition ||
69
- record.sessionId !== request.sessionId ||
70
- transition.target.runtimeEventId !== event.id)
72
+ const reduction = reduceEffectiveModelProjections([event], [...byId.values()]);
73
+ for (const transition of reduction.applied) {
74
+ const replacement = transition.replacement;
75
+ const placeholder = replacement.kind === 'json' ? replacement.value : undefined;
76
+ if (isArchivedToolResultPlaceholder(placeholder) &&
77
+ ((!identity && transition === reduction.applied.at(-1)) ||
78
+ (placeholder.rewriteVersion === 2 &&
79
+ identity &&
80
+ placeholder.sourceProjectionDigest === identity.sourceProjectionDigest &&
81
+ placeholder.previousTransitionId === identity.previousTransitionId))) {
82
+ if (placeholder.runtimeEventId !== event.id ||
83
+ placeholder.toolCallId !== content.id ||
84
+ placeholder.toolName !== content.name ||
85
+ (identity &&
86
+ (placeholder.bodySha256 !== identity.bodySha256 ||
87
+ placeholder.originalBytes !== identity.originalBytes)))
88
+ return { ok: false, reason: 'source_mismatch' };
89
+ if (placeholder.rewriteVersion === 2 &&
90
+ (placeholder.sourceProjectionDigest !== transition.sourceProjectionDigest ||
91
+ placeholder.previousTransitionId !== transition.previousTransitionId))
71
92
  return { ok: false, reason: 'corrupt' };
72
- const previous = byId.get(transition.transitionId);
73
- if (previous &&
74
- JSON.stringify({ ...previous, createdAt: 0 }) !==
75
- JSON.stringify({ ...transition, createdAt: 0 })) {
93
+ const serializedResult = serializeToolResultProjectionV1(source);
94
+ if (placeholder.originalBytes > request.maxBytes)
95
+ return { ok: false, reason: 'too_large' };
96
+ if (Buffer.byteLength(serializedResult, 'utf8') !== placeholder.originalBytes)
97
+ return { ok: false, reason: 'size_mismatch' };
98
+ if (createHash('sha256').update(serializedResult).digest('hex') !== placeholder.bodySha256)
76
99
  return { ok: false, reason: 'corrupt' };
77
- }
78
- byId.set(transition.transitionId, transition);
79
- }
80
- const reduction = reduceEffectiveModelProjections([event], [...byId.values()]);
81
- for (const transition of reduction.applied) {
82
- const replacement = transition.replacement;
83
- const placeholder = replacement.kind === 'json' ? replacement.value : undefined;
84
- if (isArchivedToolResultPlaceholder(placeholder) &&
85
- ((placeholder.rewriteVersion === 1 &&
86
- request.rewriteVersion === 1 &&
87
- placeholder.artifactId === request.artifactId) ||
88
- (placeholder.rewriteVersion === 2 &&
89
- request.rewriteVersion === 2 &&
90
- placeholder.sourceProjectionDigest === request.sourceProjectionDigest &&
91
- placeholder.previousTransitionId === request.previousTransitionId))) {
92
- if (placeholder.runtimeEventId !== request.runtimeEventId ||
93
- placeholder.toolCallId !== request.toolCallId ||
94
- placeholder.toolName !== request.toolName ||
95
- placeholder.bodySha256 !== request.bodySha256 ||
96
- placeholder.originalBytes !== request.originalBytes ||
97
- placeholder.rewriteVersion !== request.rewriteVersion)
98
- return { ok: false, reason: 'source_mismatch' };
99
- if (placeholder.rewriteVersion === 2 &&
100
- (placeholder.sourceProjectionDigest !== transition.sourceProjectionDigest ||
101
- placeholder.previousTransitionId !== transition.previousTransitionId))
102
- return { ok: false, reason: 'corrupt' };
103
- const serializedResult = serializeToolResultProjectionV1(source);
104
- if (Buffer.byteLength(serializedResult, 'utf8') !== request.originalBytes)
105
- return { ok: false, reason: 'size_mismatch' };
106
- if (createHash('sha256').update(serializedResult).digest('hex') !== request.bodySha256)
107
- return { ok: false, reason: 'corrupt' };
108
- return { ok: true, serializedResult };
109
- }
110
- source = transition.replacement;
100
+ return { ok: true, serializedResult };
111
101
  }
112
- return { ok: false, reason: 'not_found' };
102
+ source = transition.replacement;
113
103
  }
114
- catch {
115
- return { ok: false, reason: 'corrupt' };
104
+ if (!identity && reduction.rejected.length === 0) {
105
+ const serializedResult = serializeToolResultProjectionV1(source);
106
+ if (Buffer.byteLength(serializedResult, 'utf8') > request.maxBytes)
107
+ return { ok: false, reason: 'too_large' };
108
+ return { ok: true, serializedResult };
116
109
  }
117
- };
110
+ return { ok: false, reason: 'not_found' };
111
+ }
112
+ catch {
113
+ return { ok: false, reason: 'corrupt' };
114
+ }
118
115
  }
119
116
  export function createLedgerArchiveResourceReader(evidence) {
120
- const reader = createLedgerToolResultArchiveReader(evidence);
121
- return (input) => reader({
122
- ...input,
123
- kind: 'maka.archived_tool_result',
124
- rewriteVersion: 2,
125
- originalEstimatedTokens: 1,
126
- reason: 'stale_tool_result_pruned_before_compact',
127
- });
117
+ return (input) => readLedgerArchive(evidence, input);
128
118
  }
129
119
  /** Verify reconstructibility before committing a replacement; does not write any payload. */
130
120
  export function createLedgerArchivePreparer(evidence) {
@@ -134,8 +134,30 @@ export function estimateEffectiveToolResultChars(content, sessionId) {
134
134
  export function estimateRuntimeEventChars(event) {
135
135
  let total = 0;
136
136
  const content = event.content;
137
- if (content?.kind === 'text' || content?.kind === 'thinking')
137
+ if (content?.kind === 'text' || content?.kind === 'thinking') {
138
138
  total += content.text.length;
139
+ // Structured carriers are part of the event's weight: a quote- or
140
+ // attachment-only user message must not estimate to zero, or the
141
+ // history-compact gate drops a model-visible event (#4804).
142
+ if (content.kind === 'text') {
143
+ for (const quote of content.quotes ?? []) {
144
+ total += quote.text.length + (quote.label?.length ?? 0);
145
+ }
146
+ for (const attachment of content.attachments ?? []) {
147
+ // Weight the block the projection actually emits, not the display
148
+ // fields: name+mimeType is ~25 chars while the formatted attachment
149
+ // block with its Read guidance runs to hundreds (#4815 review).
150
+ total += formatAttachmentRefs([attachment]).length;
151
+ }
152
+ // Directory references project as one fixed envelope per message; count
153
+ // what it actually emits, or a directory-only message estimates to zero
154
+ // and the history-compact gate drops a model-visible event from the
155
+ // replay successors (#4815 review).
156
+ if (content.directoryReferences?.length) {
157
+ total += formatDirectoryReferences(content.directoryReferences).length;
158
+ }
159
+ }
160
+ }
139
161
  else if (content?.kind === 'function_call')
140
162
  total += content.name.length + stableJsonLength(content.args);
141
163
  else if (content?.kind === 'function_response')
@@ -724,7 +746,7 @@ function formatAttachmentRefs(attachments) {
724
746
  .map((attachment) => {
725
747
  const resourceRef = formatAttachmentResourceRef(attachment.ref);
726
748
  const readArgument = resourceRef
727
- ? { ref: resourceRef }
749
+ ? { path: resourceRef }
728
750
  : attachment.ref.kind === 'workspace_file'
729
751
  ? { path: attachment.ref.relativePath }
730
752
  : attachment.ref.kind === 'external_file'
@@ -737,7 +759,7 @@ function formatAttachmentRefs(attachments) {
737
759
  ...(attachment.kind === 'image'
738
760
  ? [`Markdown image source: ${JSON.stringify(resourceRef)}`]
739
761
  : []),
740
- 'This is a Session resource, not a workspace file. Use the ref above; never use the display name as a path.',
762
+ 'This is a Session resource, not a workspace file. Use the path above; never use the display name as a path.',
741
763
  ].join('\n')
742
764
  : `Read argument: ${JSON.stringify(readArgument)}`
743
765
  : 'The attachment content is unavailable to Read.';
@@ -16,9 +16,8 @@
16
16
  * specific language governing permissions and limitations
17
17
  * under the License.
18
18
  */
19
- import { redactSecrets } from '@maka/core/redaction';
20
19
  import { BashTailBuffer } from './bash-tail-buffer.js';
21
- import { BASH_MAX_RETAINED_CHARS, shellTailValueWithUnsafeDropMarker } from './shell-exec.js';
20
+ import { BASH_MAX_RETAINED_CHARS } from './shell-exec.js';
22
21
  export class PipeTailCollector {
23
22
  stdout;
24
23
  stderr;
@@ -47,18 +46,16 @@ export class PipeTailCollector {
47
46
  return this.generation;
48
47
  }
49
48
  snapshot() {
50
- const stdoutRaw = shellTailValueWithUnsafeDropMarker(this.stdout);
51
- const stderrRaw = shellTailValueWithUnsafeDropMarker(this.stderr);
52
- const stdout = redactSecrets(stdoutRaw);
53
- const stderr = redactSecrets(stderrRaw);
49
+ const stdout = this.stdout.value();
50
+ const stderr = this.stderr.value();
54
51
  return {
55
52
  mode: 'pipes',
56
53
  stdout,
57
54
  stderr,
58
55
  ...(this.latestStream ? { latestStream: this.latestStream } : {}),
59
- stdoutTruncated: this.stdoutChars > stdoutRaw.length || this.stdout.hasDroppedUnsafe(),
60
- stderrTruncated: this.stderrChars > stderrRaw.length || this.stderr.hasDroppedUnsafe(),
61
- redacted: stdout !== stdoutRaw || stderr !== stderrRaw,
56
+ stdoutTruncated: this.stdoutChars > stdout.length,
57
+ stderrTruncated: this.stderrChars > stderr.length,
58
+ redacted: false,
62
59
  };
63
60
  }
64
61
  currentGeneration() {
@@ -0,0 +1,231 @@
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
+ import { createHash } from 'node:crypto';
20
+ import { z } from 'zod';
21
+ export const READ_PAGE_MAX_CHARS = 7_500;
22
+ export const READ_DESCRIPTION = 'Read a file or a Maka resource. Only path is required. By default, read from the beginning and return one bounded page. offset and limit select a line range; offset is zero-based. A large limit cannot bypass the response-size cap. If next is non-null, pass its contents to Read to continue; otherwise the requested range is complete. Use a smaller limit for a short excerpt. A partialLine page continues automatically through next.';
23
+ export const readParameters = z.object({
24
+ path: z
25
+ .string({
26
+ error: 'path is required. Provide a file path or the Maka address returned by a tool.',
27
+ })
28
+ .min(1, 'path cannot be empty. Provide the location to read.')
29
+ .describe('File path relative to the session cwd, an absolute path, or a Maka address returned by a tool.'),
30
+ offset: z
31
+ .number({ error: 'offset must be a non-negative integer. Omit it to start at the beginning.' })
32
+ .int('offset must be an integer. Omit it to start at the beginning.')
33
+ .nonnegative('offset must be non-negative. Omit it to start at the beginning.')
34
+ .optional()
35
+ .describe('Zero-based starting line; defaults to 0. offset 200 starts at line 201. Omit when using a continuation address.'),
36
+ limit: z
37
+ .number({ error: 'limit must be a positive integer. Omit it to read one bounded page.' })
38
+ .int('limit must be an integer. Omit it to read one bounded page.')
39
+ .positive('limit must be positive. Omit it to read one bounded page.')
40
+ .optional()
41
+ .describe('Maximum lines in the requested range. Omit to browse one bounded page at a time. Use next to obtain any remaining content.'),
42
+ });
43
+ export const readPageSchema = z.object({
44
+ content: z.string(),
45
+ offset: z.number().int().nonnegative(),
46
+ returnedLines: z.number().int().nonnegative(),
47
+ totalLines: z.number().int().nonnegative(),
48
+ partialLine: z.literal(true).optional(),
49
+ next: readParameters.nullable(),
50
+ metadata: z.record(z.string(), z.unknown()).optional(),
51
+ });
52
+ export const readContinuationSchema = z
53
+ .object({
54
+ position: z.number().int().nonnegative(),
55
+ digest: z.string().regex(/^[a-f0-9]{32}$/),
56
+ })
57
+ .strict();
58
+ const CONTINUATION_PREFIX = 'maka://read/';
59
+ export function resolveReadInput(input) {
60
+ if (!input.path.startsWith(CONTINUATION_PREFIX))
61
+ return { path: input.path };
62
+ try {
63
+ const url = new URL(input.path);
64
+ const path = Buffer.from(url.pathname.slice(1), 'base64url').toString('utf8');
65
+ const at = url.searchParams.get('at') ?? '';
66
+ const position = Number(at);
67
+ const digest = url.searchParams.get('sha') ?? '';
68
+ if (!path ||
69
+ path.startsWith(CONTINUATION_PREFIX) ||
70
+ !/^\d+$/.test(at) ||
71
+ !Number.isSafeInteger(position) ||
72
+ !/^[a-f0-9]{32}$/.test(digest) ||
73
+ input.offset !== undefined)
74
+ throw new Error();
75
+ return { path, position, digest };
76
+ }
77
+ catch {
78
+ throw new Error('Invalid Read continuation. Copy the complete next object from the preceding result. To start again, use the original path and omit offset and limit.');
79
+ }
80
+ }
81
+ function digestText(content) {
82
+ return createHash('sha256').update(content).digest('hex').slice(0, 32);
83
+ }
84
+ export function readPage(content, input, maxChars = READ_PAGE_MAX_CHARS, continuation) {
85
+ const resolved = continuation ? { path: input.path, ...continuation } : resolveReadInput(input);
86
+ if (resolved.digest && digestText(content) !== resolved.digest) {
87
+ throw new Error('The content changed since the previous page. This continuation cannot be used. Read the original path again to start from the current content.');
88
+ }
89
+ if (resolved.position !== undefined && resolved.position > content.length) {
90
+ throw new Error('Invalid Read continuation position. Copy the complete next object from the preceding result.');
91
+ }
92
+ const starts = [0];
93
+ for (let at = content.indexOf('\n'); at >= 0; at = content.indexOf('\n', at + 1))
94
+ starts.push(at + 1);
95
+ const totalLines = starts.length;
96
+ const lineAt = (position) => {
97
+ let low = 0;
98
+ let high = starts.length - 1;
99
+ while (low < high) {
100
+ const middle = Math.ceil((low + high) / 2);
101
+ if (starts[middle] <= position)
102
+ low = middle;
103
+ else
104
+ high = middle - 1;
105
+ }
106
+ return low;
107
+ };
108
+ const offset = resolved.position === undefined ? (input.offset ?? 0) : lineAt(resolved.position);
109
+ const start = resolved.position ?? starts[Math.min(offset, totalLines)] ?? content.length;
110
+ const lastLine = Math.min(totalLines, offset + (input.limit ?? totalLines));
111
+ const end = lastLine < totalLines ? starts[lastLine] - 1 : content.length;
112
+ let digest = resolved.digest;
113
+ const makePage = (stop) => {
114
+ const complete = stop >= end;
115
+ const nextLine = Math.max(offset, lineAt(stop));
116
+ const boundary = stop === (starts[nextLine + 1] ?? content.length + 1) - 1;
117
+ const partialLine = !complete && !boundary;
118
+ const returnedLines = offset >= totalLines
119
+ ? 0
120
+ : complete
121
+ ? lastLine - offset
122
+ : nextLine - offset + (partialLine ? 0 : 1);
123
+ let next = null;
124
+ if (!complete) {
125
+ const remaining = input.limit === undefined ? undefined : input.limit - returnedLines;
126
+ const position = partialLine ? stop : stop + 1;
127
+ next = {
128
+ path: `${CONTINUATION_PREFIX}${Buffer.from(resolved.path).toString('base64url')}?at=${position}&sha=${(digest ??= digestText(content))}`,
129
+ ...(remaining === undefined ? {} : { limit: remaining }),
130
+ };
131
+ }
132
+ return {
133
+ content: content.slice(start, Math.max(start, stop)),
134
+ offset,
135
+ returnedLines,
136
+ totalLines,
137
+ ...(partialLine || (offset < totalLines && start > starts[offset])
138
+ ? { partialLine: true }
139
+ : {}),
140
+ next,
141
+ };
142
+ };
143
+ if (end - start <= maxChars) {
144
+ const page = makePage(end);
145
+ if (JSON.stringify(page).length <= maxChars)
146
+ return page;
147
+ }
148
+ let low = start;
149
+ let high = Math.min(end, start + maxChars);
150
+ while (low < high) {
151
+ const middle = Math.ceil((low + high) / 2);
152
+ if (JSON.stringify(makePage(middle)).length <= maxChars)
153
+ low = middle;
154
+ else
155
+ high = middle - 1;
156
+ }
157
+ // Never split a UTF-16 surrogate pair between responses.
158
+ if (low > start && /[\uD800-\uDBFF]/.test(content[low - 1]))
159
+ low--;
160
+ if (low <= start)
161
+ throw new Error('The Read address is too long to fit a bounded response. Use a shorter original path.');
162
+ const newline = content.lastIndexOf('\n', low);
163
+ if (newline > start)
164
+ low = newline;
165
+ return makePage(low);
166
+ }
167
+ export function readableToolResult(serialized) {
168
+ try {
169
+ const value = JSON.parse(serialized);
170
+ if (typeof value === 'string')
171
+ return value;
172
+ if (value &&
173
+ typeof value === 'object' &&
174
+ Object.keys(value).length === 2 &&
175
+ 'kind' in value &&
176
+ value.kind === 'text' &&
177
+ 'text' in value &&
178
+ typeof value.text === 'string')
179
+ return value.text;
180
+ if (value &&
181
+ typeof value === 'object' &&
182
+ Object.keys(value).length === 1 &&
183
+ 'content' in value &&
184
+ typeof value.content === 'string')
185
+ return value.content;
186
+ if (value &&
187
+ typeof value === 'object' &&
188
+ 'kind' in value &&
189
+ (value.kind === 'terminal' || value.kind === 'shell_run')) {
190
+ const shell = value;
191
+ let output;
192
+ if (typeof shell.output === 'string')
193
+ output = shell.output;
194
+ if (shell.output && typeof shell.output === 'object') {
195
+ const shellOutput = shell.output;
196
+ output = (shellOutput.mode === 'pty'
197
+ ? [shellOutput.scrollback, shellOutput.screen, shellOutput.lastAlternateScreen]
198
+ : [shellOutput.stdout, shellOutput.stderr])
199
+ .filter((part) => typeof part === 'string' && part.length > 0)
200
+ .join('\n');
201
+ }
202
+ if (typeof shell.failureMessage === 'string' && shell.failureMessage.length > 0)
203
+ return output ? `${output}\n${shell.failureMessage}` : shell.failureMessage;
204
+ if (output !== undefined)
205
+ return output;
206
+ }
207
+ }
208
+ catch {
209
+ /* Plain text projections are already readable. */
210
+ }
211
+ return serialized;
212
+ }
213
+ export function readToolResultPage(serialized, input, maxChars = READ_PAGE_MAX_CHARS) {
214
+ let metadata;
215
+ try {
216
+ const value = JSON.parse(serialized);
217
+ if (value?.kind === 'terminal' || value?.kind === 'shell_run') {
218
+ metadata = Object.fromEntries(Object.entries(value).filter(([key]) => ['kind', 'status', 'exitCode', 'signal', 'revision', 'mode'].includes(key)));
219
+ if (value.output && typeof value.output === 'object')
220
+ for (const key of ['stdoutTruncated', 'stderrTruncated', 'redacted']) {
221
+ if (typeof value.output[key] === 'boolean')
222
+ metadata[key] = value.output[key];
223
+ }
224
+ }
225
+ }
226
+ catch {
227
+ /* Text has no separate execution metadata. */
228
+ }
229
+ const page = readPage(readableToolResult(serialized), input, maxChars - (metadata ? JSON.stringify(metadata).length + 16 : 0));
230
+ return metadata ? { ...page, metadata } : page;
231
+ }
@@ -16,21 +16,8 @@
16
16
  * specific language governing permissions and limitations
17
17
  * under the License.
18
18
  */
19
- /**
20
- * Deterministic request-projection pipeline over ONE provider-visible request.
21
- * Order is a contract: mid-turn capacity compaction runs first among the
22
- * message-shaping hooks so every later mechanism operates on its projection —
23
- * active tool-result pruning re-archives large tool results in the rebuilt
24
- * tail.
25
- *
26
- * Every hook here only SHAPES the projection. The pass/terminate capacity
27
- * verdict is issued once, after the whole pipeline, by the final-request
28
- * estimate owner (buildMidTurnFinalRequestVerdict) over the actual outgoing
29
- * (messages, tools) payload — never by an individual hook over an intermediate
30
- * projection that a later hook could still rescue.
31
- */
32
- export function composeRequestProjection(toolAvailability, midTurnCapacityCompact, activeToolResultPrune) {
33
- const hooks = [toolAvailability, midTurnCapacityCompact, activeToolResultPrune].filter(Boolean);
19
+ export function composeRequestProjection(...stages) {
20
+ const hooks = stages.filter((stage) => stage !== undefined);
34
21
  if (hooks.length === 0)
35
22
  return undefined;
36
23
  return async (context) => {
@@ -0,0 +1,62 @@
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
+ import { constants } from 'node:fs';
20
+ import { access, realpath } from 'node:fs/promises';
21
+ import { delimiter, isAbsolute, join } from 'node:path';
22
+ export function defaultRipgrepCandidates(env, platform = process.platform) {
23
+ const executableName = platform === 'win32' ? 'rg.exe' : 'rg';
24
+ return [
25
+ ...(env.PATH ?? '')
26
+ .split(delimiter)
27
+ .filter(Boolean)
28
+ .map((directory) => join(directory, executableName)),
29
+ ...(platform === 'win32' ? [] : ['/opt/homebrew/bin/rg', '/usr/local/bin/rg', '/usr/bin/rg']),
30
+ // winget adds this directory to PATH only for processes started after the
31
+ // install. A running Host must probe it explicitly for install-and-retry.
32
+ ...(platform === 'win32' && env.LOCALAPPDATA
33
+ ? [join(env.LOCALAPPDATA, 'Microsoft', 'WinGet', 'Links', executableName)]
34
+ : []),
35
+ ];
36
+ }
37
+ export async function* resolveRipgrepCandidates(candidates) {
38
+ const resolved = new Set();
39
+ for (const candidate of candidates) {
40
+ const executable = await resolveExecutable(candidate);
41
+ if (!executable || resolved.has(executable))
42
+ continue;
43
+ resolved.add(executable);
44
+ yield executable;
45
+ }
46
+ }
47
+ export async function resolveRipgrepExecutable(candidates) {
48
+ for await (const executable of resolveRipgrepCandidates(candidates))
49
+ return executable;
50
+ return undefined;
51
+ }
52
+ async function resolveExecutable(candidate) {
53
+ if (!candidate || !isAbsolute(candidate))
54
+ return undefined;
55
+ try {
56
+ await access(candidate, constants.X_OK);
57
+ return await realpath(candidate);
58
+ }
59
+ catch {
60
+ return undefined;
61
+ }
62
+ }