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.
- package/THIRD_PARTY_NOTICES.txt +392 -0
- package/dist/acp/maka-acp-agent.js +8 -2
- package/dist/acp/prompt-content.js +225 -0
- package/dist/acp/session-event-mapper.js +103 -0
- package/dist/acp/session-registry.js +654 -17
- package/dist/acp/stdio-server.js +10 -1
- package/dist/cli-core.js +1 -1
- package/dist/pi-transcript-tools.js +3 -2
- package/dist/pi-transcript.js +12 -2
- package/dist/runtime-host-session-channel.js +63 -9
- package/native/runtime-host-windows-task-launcher/prebuilds/win32-x64/maka-runtime-host-task-launcher.exe +0 -0
- package/node_modules/@maka/core/dist/artifacts.js +6 -0
- package/node_modules/@maka/core/dist/attachments.js +7 -2
- package/node_modules/@maka/core/dist/durable-tool-result-projection.js +3 -1
- package/node_modules/@maka/core/dist/events.js +21 -0
- package/node_modules/@maka/core/dist/goal.js +44 -2
- package/node_modules/@maka/core/dist/permission.js +0 -1
- package/node_modules/@maka/core/dist/runtime-boundary.js +73 -29
- package/node_modules/@maka/core/dist/runtime-event.js +6 -3
- package/node_modules/@maka/core/dist/runtime-handoff.js +10 -2
- package/node_modules/@maka/core/dist/runtime-logical-execution.js +39 -14
- package/node_modules/@maka/core/dist/tool-result-archive-evidence.js +3 -1
- package/node_modules/@maka/core/dist/tool-result-record-schema.js +2 -1
- package/node_modules/@maka/core/dist/unified-diff.js +33 -26
- package/node_modules/@maka/runtime/dist/ai-sdk-compaction.js +49 -178
- package/node_modules/@maka/runtime/dist/ai-sdk-message-projection.js +7 -2
- package/node_modules/@maka/runtime/dist/ai-sdk-turn.js +15 -53
- package/node_modules/@maka/runtime/dist/bash-model-output.js +7 -1
- package/node_modules/@maka/runtime/dist/bash-tail-buffer.js +13 -52
- package/node_modules/@maka/runtime/dist/builtin-tools.js +59 -111
- package/node_modules/@maka/runtime/dist/child-fd-input.js +3 -2
- package/node_modules/@maka/runtime/dist/context-budget-policy.js +1 -11
- package/node_modules/@maka/runtime/dist/context-budget.js +12 -1
- package/node_modules/@maka/runtime/dist/conversation-copy.js +104 -9
- package/node_modules/@maka/runtime/dist/filesystem-executor.js +10 -6
- package/node_modules/@maka/runtime/dist/filesystem-worker/client.js +77 -19
- package/node_modules/@maka/runtime/dist/filesystem-worker/launch-spec.js +66 -55
- package/node_modules/@maka/runtime/dist/filesystem-worker/operations.js +34 -97
- package/node_modules/@maka/runtime/dist/filesystem-worker/protocol.js +25 -10
- package/node_modules/@maka/runtime/dist/filesystem-worker/worker-entry.js +2 -0
- package/node_modules/@maka/runtime/dist/glob-search.js +74 -0
- package/node_modules/@maka/runtime/dist/goal-continuation.js +78 -8
- package/node_modules/@maka/runtime/dist/goal-state.js +7 -0
- package/node_modules/@maka/runtime/dist/grep-search.js +155 -0
- package/node_modules/@maka/runtime/dist/ledger-tool-result-archive-reader.js +84 -94
- package/node_modules/@maka/runtime/dist/model-history.js +25 -3
- package/node_modules/@maka/runtime/dist/pipe-tail-collector.js +6 -9
- package/node_modules/@maka/runtime/dist/read-page.js +231 -0
- package/node_modules/@maka/runtime/dist/request-projection.js +2 -15
- package/node_modules/@maka/runtime/dist/ripgrep-executable.js +62 -0
- package/node_modules/@maka/runtime/dist/ripgrep-guidance.js +81 -0
- package/node_modules/@maka/runtime/dist/runtime-event-read-model.js +187 -20
- package/node_modules/@maka/runtime/dist/runtime-read-model.js +2 -1
- package/node_modules/@maka/runtime/dist/sandbox/linux-profile-path.js +7 -1
- package/node_modules/@maka/runtime/dist/sandbox/linux-sandbox.js +20 -5
- package/node_modules/@maka/runtime/dist/session-manager.js +6 -6
- package/node_modules/@maka/runtime/dist/session-recap.js +9 -5
- package/node_modules/@maka/runtime/dist/shell-exec.js +7 -25
- package/node_modules/@maka/runtime/dist/shell-run-manager.js +1 -1
- package/node_modules/@maka/runtime/dist/shell-run-tool-result.js +1 -1
- package/node_modules/@maka/runtime/dist/shell-tools.js +6 -12
- package/node_modules/@maka/runtime/dist/tool-availability.js +0 -1
- package/node_modules/@maka/runtime/dist/tool-output.js +1 -1
- package/node_modules/@maka/runtime/dist/tool-result-archive-capability.js +24 -36
- package/node_modules/@maka/runtime/dist/tool-result-archive-resource.js +32 -527
- package/node_modules/@maka/runtime/dist/tool-result-archive-transition.js +17 -119
- package/node_modules/@maka/runtime/dist/tool-result-archive.js +7 -25
- package/node_modules/@maka/runtime/dist/tool-runtime.js +7 -5
- package/node_modules/@maka/runtime/dist/workers/filesystem-worker.js +6933 -3681
- package/node_modules/@maka/runtime/dist/workspace-executor.js +20 -24
- package/node_modules/@maka/runtime/package.json +2 -0
- package/node_modules/@maka/runtime-host/dist/client/host-handoff-copy.js +185 -191
- package/node_modules/@maka/runtime-host/dist/client/reconnecting-connection.js +3 -0
- package/node_modules/@maka/runtime-host/dist/protocol/index.js +5 -1
- package/node_modules/@maka/runtime-host/dist/protocol/message.js +2 -2
- package/node_modules/@maka/runtime-host/dist/protocol/operations.js +1 -0
- package/node_modules/@maka/runtime-host/dist/protocol/session-continuity.js +2 -2
- package/node_modules/@maka/runtime-host/dist/protocol/turn.js +10 -2
- package/node_modules/@maka/runtime-host/dist/protocol/workhub-coordination.js +38 -0
- package/node_modules/@maka/runtime-host/dist/server/execution-artifacts.js +2 -8
- package/node_modules/@maka/runtime-host/dist/server/execution-composition.js +2 -0
- package/node_modules/@maka/runtime-host/dist/server/goal-coordinator.js +81 -7
- package/node_modules/@maka/runtime-host/dist/server/hosted-execution-tool-profile.js +13 -13
- package/node_modules/@maka/runtime-host/dist/server/interaction-coordinator.js +65 -0
- package/node_modules/@maka/runtime-host/dist/server/root-turn-coordinator.js +1 -0
- package/node_modules/@maka/runtime-host/dist/server/session-continuity-coordinator.js +5 -2
- package/node_modules/@maka/runtime-host/dist/server/session-transcript-reader.js +88 -72
- package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-action-gate.js +21 -4
- package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-coordinator.js +145 -1
- package/node_modules/@maka/storage/dist/agent-run-store.js +5 -2
- package/node_modules/@maka/storage/dist/execution-stores.js +2 -1
- package/node_modules/@maka/storage/dist/runtime-transcript-query.js +27 -14
- package/node_modules/@maka/storage/dist/sqlite-runtime-store.js +69 -3
- package/node_modules/balanced-match/LICENSE.md +23 -0
- package/node_modules/balanced-match/README.md +57 -0
- package/node_modules/balanced-match/dist/commonjs/index.js +59 -0
- package/node_modules/balanced-match/dist/commonjs/package.json +3 -0
- package/node_modules/balanced-match/dist/esm/index.js +54 -0
- package/node_modules/balanced-match/dist/esm/package.json +3 -0
- package/node_modules/balanced-match/package.json +68 -0
- package/node_modules/brace-expansion/LICENSE +23 -0
- package/node_modules/brace-expansion/README.md +105 -0
- package/node_modules/brace-expansion/dist/commonjs/index.js +289 -0
- package/node_modules/brace-expansion/dist/commonjs/package.json +3 -0
- package/node_modules/brace-expansion/dist/esm/index.js +285 -0
- package/node_modules/brace-expansion/dist/esm/package.json +3 -0
- package/node_modules/brace-expansion/package.json +64 -0
- package/node_modules/glob/LICENSE.md +63 -0
- package/node_modules/glob/README.md +1203 -0
- package/node_modules/glob/dist/commonjs/glob.js +248 -0
- package/node_modules/glob/dist/commonjs/has-magic.js +27 -0
- package/node_modules/glob/dist/commonjs/ignore.js +119 -0
- package/node_modules/glob/dist/commonjs/index.js +68 -0
- package/node_modules/glob/dist/commonjs/index.min.js +4 -0
- package/node_modules/glob/dist/commonjs/package.json +3 -0
- package/node_modules/glob/dist/commonjs/pattern.js +223 -0
- package/node_modules/glob/dist/commonjs/processor.js +301 -0
- package/node_modules/glob/dist/commonjs/walker.js +387 -0
- package/node_modules/glob/dist/esm/glob.js +244 -0
- package/node_modules/glob/dist/esm/has-magic.js +23 -0
- package/node_modules/glob/dist/esm/ignore.js +115 -0
- package/node_modules/glob/dist/esm/index.js +55 -0
- package/node_modules/glob/dist/esm/index.min.js +4 -0
- package/node_modules/glob/dist/esm/package.json +3 -0
- package/node_modules/glob/dist/esm/pattern.js +219 -0
- package/node_modules/glob/dist/esm/processor.js +294 -0
- package/node_modules/glob/dist/esm/walker.js +381 -0
- package/node_modules/glob/package.json +98 -0
- package/node_modules/minimatch/LICENSE.md +55 -0
- package/node_modules/minimatch/README.md +528 -0
- package/node_modules/minimatch/dist/commonjs/assert-valid-pattern.js +14 -0
- package/node_modules/minimatch/dist/commonjs/ast.js +845 -0
- package/node_modules/minimatch/dist/commonjs/brace-expressions.js +150 -0
- package/node_modules/minimatch/dist/commonjs/escape.js +30 -0
- package/node_modules/minimatch/dist/commonjs/index.js +1127 -0
- package/node_modules/minimatch/dist/commonjs/package.json +3 -0
- package/node_modules/minimatch/dist/commonjs/unescape.js +38 -0
- package/node_modules/minimatch/dist/esm/assert-valid-pattern.js +10 -0
- package/node_modules/minimatch/dist/esm/ast.js +841 -0
- package/node_modules/minimatch/dist/esm/brace-expressions.js +146 -0
- package/node_modules/minimatch/dist/esm/escape.js +26 -0
- package/node_modules/minimatch/dist/esm/index.js +1114 -0
- package/node_modules/minimatch/dist/esm/package.json +3 -0
- package/node_modules/minimatch/dist/esm/unescape.js +34 -0
- package/node_modules/minimatch/package.json +73 -0
- package/node_modules/minipass/LICENSE.md +55 -0
- package/node_modules/minipass/README.md +825 -0
- package/node_modules/minipass/dist/commonjs/index.js +1038 -0
- package/node_modules/minipass/dist/commonjs/package.json +3 -0
- package/node_modules/minipass/dist/esm/index.js +1020 -0
- package/node_modules/minipass/dist/esm/package.json +3 -0
- package/node_modules/minipass/package.json +77 -0
- package/node_modules/path-scurry/LICENSE.md +55 -0
- package/node_modules/path-scurry/README.md +636 -0
- package/node_modules/path-scurry/dist/commonjs/index.js +2018 -0
- package/node_modules/path-scurry/dist/commonjs/package.json +3 -0
- package/node_modules/path-scurry/dist/esm/index.js +1983 -0
- package/node_modules/path-scurry/dist/esm/package.json +3 -0
- package/node_modules/path-scurry/node_modules/lru-cache/LICENSE.md +55 -0
- package/node_modules/path-scurry/node_modules/lru-cache/README.md +469 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/diagnostics-channel.js +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.js +1726 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.min.js +2 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/perf.js +10 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/diagnostics-channel-cjs.d.cts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/diagnostics-channel.js +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.js +1726 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.min.js +2 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/diagnostics-channel.js +9 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.js +1726 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.min.js +2 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/perf.js +10 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/package.json +3 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/perf.js +10 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/diagnostics-channel.js +4 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.js +1722 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.min.js +2 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/perf.js +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/diagnostics-channel-esm.d.mts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/diagnostics-channel.js +19 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.js +1722 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.min.js +2 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/diagnostics-channel.js +6 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.js +1722 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.min.js +2 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/perf.js +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/package.json +3 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/perf.js +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/package.json +154 -0
- package/node_modules/path-scurry/package.json +72 -0
- package/package.json +1 -1
- package/node_modules/@maka/runtime/dist/active-tool-result-prune.js +0 -248
- package/node_modules/@maka/runtime/dist/active-tool-result-working-set.js +0 -218
- 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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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
|
|
73
|
-
if (
|
|
74
|
-
|
|
75
|
-
|
|
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
|
-
|
|
102
|
+
source = transition.replacement;
|
|
113
103
|
}
|
|
114
|
-
|
|
115
|
-
|
|
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
|
-
|
|
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
|
-
? {
|
|
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
|
|
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
|
|
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
|
|
51
|
-
const
|
|
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 >
|
|
60
|
-
stderrTruncated: this.stderrChars >
|
|
61
|
-
redacted:
|
|
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
|
-
|
|
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
|
+
}
|