@wingsbutterfly/dsh-rtk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +52 -0
- package/LICENSE +21 -0
- package/README.md +214 -0
- package/README.zh.md +211 -0
- package/THIRD_PARTY_NOTICES.md +51 -0
- package/docs/assets/how-it-works.svg +47 -0
- package/docs/verification.md +279 -0
- package/lib/command.d.ts +41 -0
- package/lib/command.d.ts.map +1 -0
- package/lib/command.js +137 -0
- package/lib/command.js.map +1 -0
- package/lib/compact/build.d.ts +15 -0
- package/lib/compact/build.d.ts.map +1 -0
- package/lib/compact/build.js +140 -0
- package/lib/compact/build.js.map +1 -0
- package/lib/compact/detect.d.ts +22 -0
- package/lib/compact/detect.d.ts.map +1 -0
- package/lib/compact/detect.js +54 -0
- package/lib/compact/detect.js.map +1 -0
- package/lib/compact/dsh-result.d.ts +49 -0
- package/lib/compact/dsh-result.d.ts.map +1 -0
- package/lib/compact/dsh-result.js +84 -0
- package/lib/compact/dsh-result.js.map +1 -0
- package/lib/compact/git.d.ts +21 -0
- package/lib/compact/git.d.ts.map +1 -0
- package/lib/compact/git.js +197 -0
- package/lib/compact/git.js.map +1 -0
- package/lib/compact/index.d.ts +39 -0
- package/lib/compact/index.d.ts.map +1 -0
- package/lib/compact/index.js +236 -0
- package/lib/compact/index.js.map +1 -0
- package/lib/compact/linter.d.ts +12 -0
- package/lib/compact/linter.d.ts.map +1 -0
- package/lib/compact/linter.js +118 -0
- package/lib/compact/linter.js.map +1 -0
- package/lib/compact/search.d.ts +16 -0
- package/lib/compact/search.d.ts.map +1 -0
- package/lib/compact/search.js +67 -0
- package/lib/compact/search.js.map +1 -0
- package/lib/compact/source.d.ts +22 -0
- package/lib/compact/source.d.ts.map +1 -0
- package/lib/compact/source.js +224 -0
- package/lib/compact/source.js.map +1 -0
- package/lib/compact/test-output.d.ts +12 -0
- package/lib/compact/test-output.d.ts.map +1 -0
- package/lib/compact/test-output.js +168 -0
- package/lib/compact/test-output.js.map +1 -0
- package/lib/compact/text.d.ts +22 -0
- package/lib/compact/text.d.ts.map +1 -0
- package/lib/compact/text.js +87 -0
- package/lib/compact/text.js.map +1 -0
- package/lib/config.d.ts +243 -0
- package/lib/config.d.ts.map +1 -0
- package/lib/config.js +183 -0
- package/lib/config.js.map +1 -0
- package/lib/index.d.ts +46 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +405 -0
- package/lib/index.js.map +1 -0
- package/lib/metrics.d.ts +35 -0
- package/lib/metrics.d.ts.map +1 -0
- package/lib/metrics.js +51 -0
- package/lib/metrics.js.map +1 -0
- package/lib/rtk-executable.d.ts +51 -0
- package/lib/rtk-executable.d.ts.map +1 -0
- package/lib/rtk-executable.js +75 -0
- package/lib/rtk-executable.js.map +1 -0
- package/lib/rtk-rewrite.d.ts +88 -0
- package/lib/rtk-rewrite.d.ts.map +1 -0
- package/lib/rtk-rewrite.js +150 -0
- package/lib/rtk-rewrite.js.map +1 -0
- package/lib/runtime-guard.d.ts +31 -0
- package/lib/runtime-guard.d.ts.map +1 -0
- package/lib/runtime-guard.js +32 -0
- package/lib/runtime-guard.js.map +1 -0
- package/package.json +82 -0
- package/scripts/link-dsh.mjs +135 -0
- package/src/command.ts +174 -0
- package/src/compact/build.ts +154 -0
- package/src/compact/detect.ts +54 -0
- package/src/compact/dsh-result.ts +99 -0
- package/src/compact/git.ts +209 -0
- package/src/compact/index.ts +284 -0
- package/src/compact/linter.ts +126 -0
- package/src/compact/search.ts +73 -0
- package/src/compact/source.ts +244 -0
- package/src/compact/test-output.ts +184 -0
- package/src/compact/text.ts +86 -0
- package/src/config.ts +263 -0
- package/src/index.ts +431 -0
- package/src/metrics.ts +84 -0
- package/src/rtk-executable.ts +117 -0
- package/src/rtk-rewrite.ts +179 -0
- package/src/runtime-guard.ts +44 -0
package/lib/index.js
ADDED
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
import { tmpdir } from 'node:os';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { Config, normalizeConfig } from './config.js';
|
|
4
|
+
import { READ_COMPACTION_BANNER_PREFIX, compactToolResult } from './compact/index.js';
|
|
5
|
+
import { parseBashResult, renderBashResult } from './compact/dsh-result.js';
|
|
6
|
+
import { createMetricsTracker } from './metrics.js';
|
|
7
|
+
import { createRtkCommand } from './command.js';
|
|
8
|
+
import { resolveRtkExecutable, runExecutable } from './rtk-executable.js';
|
|
9
|
+
import { applyRtkHistoryScope, resolveRtkRewrite } from './rtk-rewrite.js';
|
|
10
|
+
import { isStatusStale, shouldRequireRtkAvailability, shouldSkipRewrite } from './runtime-guard.js';
|
|
11
|
+
/** Cordis plugin name used by loader diagnostics. */
|
|
12
|
+
export const name = 'rtk';
|
|
13
|
+
/**
|
|
14
|
+
* The tool runtime is a hard dependency: both halves of this plugin are
|
|
15
|
+
* `tools/*` listeners, and without the registry there is nothing to rewrite or
|
|
16
|
+
* compact.
|
|
17
|
+
*
|
|
18
|
+
* `settings` is declared too, and not because the plugin cannot run without it
|
|
19
|
+
* — it can, entirely from the composition's `config:` block. It is declared
|
|
20
|
+
* because the provider registers *asynchronously*: it reads the settings
|
|
21
|
+
* document first, so a plain `ctx.get('settings')` during `apply` can find
|
|
22
|
+
* nothing and the namespace silently never registers. Observed exactly that in
|
|
23
|
+
* production (`/rtk` reported "settings service unavailable" while a sibling
|
|
24
|
+
* `ctx.get('spillStore')` succeeded). Declaring it makes Cordis park this
|
|
25
|
+
* plugin until the provider appears, then activate it.
|
|
26
|
+
*
|
|
27
|
+
* `commands` and `systemPrompt` stay optional `ctx.get` lookups: they are
|
|
28
|
+
* registered early enough to be present, and a composition without them should
|
|
29
|
+
* still get the optimization.
|
|
30
|
+
*/
|
|
31
|
+
export const inject = ['tools', 'settings'];
|
|
32
|
+
export { Config };
|
|
33
|
+
/** Tools whose `command` argument can be rewritten. */
|
|
34
|
+
const REWRITABLE_TOOLS = new Set(['bash', 'pwsh']);
|
|
35
|
+
/** Path of the rtk history database this plugin scopes rewritten commands to. */
|
|
36
|
+
function rtkHistoryDbPath() {
|
|
37
|
+
return join(tmpdir(), 'dsh-rtk', 'history.db');
|
|
38
|
+
}
|
|
39
|
+
function asRecord(value) {
|
|
40
|
+
return typeof value === 'object' && value !== null ? value : undefined;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Appended once per session when rtk cannot be found.
|
|
44
|
+
*
|
|
45
|
+
* A missing binary is the only failure that silently costs the user the whole
|
|
46
|
+
* feature, so it is worth one short line — but only one, and only for a
|
|
47
|
+
* session that has not been told yet.
|
|
48
|
+
*/
|
|
49
|
+
const MISSING_RTK_NOTICE = '[rtk] rtk not found; rewriting is off — /rtk verify shows install options';
|
|
50
|
+
/** The guidance injected while lossy read compaction is active. */
|
|
51
|
+
const SOURCE_FILTER_TROUBLESHOOTING_NOTE = 'RTK note: if a file edit repeatedly fails because the old text does not match, read compaction may have altered the copy you are editing against. Ask the user to turn off `readCompaction` in the rtk settings, re-read the file, apply the edit, then turn it back on.';
|
|
52
|
+
/** Whether lossy `read` compaction is enabled together with its safeguards. */
|
|
53
|
+
function needsSourceFilterNote(config) {
|
|
54
|
+
const compaction = config.outputCompaction;
|
|
55
|
+
return (config.enabled &&
|
|
56
|
+
compaction.enabled &&
|
|
57
|
+
compaction.readCompaction.enabled &&
|
|
58
|
+
compaction.sourceCodeFilteringEnabled &&
|
|
59
|
+
compaction.sourceCodeFiltering !== 'none' &&
|
|
60
|
+
(compaction.smartTruncate.enabled || compaction.truncate.enabled));
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Register RTK command rewriting and tool-output compaction.
|
|
64
|
+
*
|
|
65
|
+
* Both halves hang off the tool pipeline rather than wrapping a tool:
|
|
66
|
+
*
|
|
67
|
+
* - **Rewriting** rides `tools/execute`. The harness deliberately keeps
|
|
68
|
+
* `tools/pre-execute` from mutating arguments (they are logged and presented
|
|
69
|
+
* before dispatch), so the around-dispatch stage is the only seam where the
|
|
70
|
+
* command that actually runs can differ from the one that was recorded. The
|
|
71
|
+
* replacement is scoped to the call: the original arguments are restored as
|
|
72
|
+
* soon as dispatch returns, so later pipeline stages and the session log see
|
|
73
|
+
* what the model asked for.
|
|
74
|
+
* - **Compaction** rides `tools/post-execute`, which is the stage that may
|
|
75
|
+
* replace result content.
|
|
76
|
+
*
|
|
77
|
+
* @param ctx - the agent-scoped context this row was mounted into.
|
|
78
|
+
* @param rawConfig - the row's `config:` block, already schema-validated.
|
|
79
|
+
*/
|
|
80
|
+
export function apply(ctx, rawConfig) {
|
|
81
|
+
/**
|
|
82
|
+
* Whether the harness bounds oversized results itself.
|
|
83
|
+
*
|
|
84
|
+
* `dsh-spill-policy` writes a full output to disk and keeps a head/tail
|
|
85
|
+
* preview inline, so it truncates *recoverably*. This plugin's own hard
|
|
86
|
+
* truncation is lossy, and it runs first: at 12 000 characters it fires far
|
|
87
|
+
* below spill's threshold (50 000 by default), so spill never sees a large
|
|
88
|
+
* result at all and the reader loses the spill file that would have let them
|
|
89
|
+
* read the rest. When spill is mounted this plugin steps aside; when it is
|
|
90
|
+
* not, the truncation stays as the only bound on a runaway command.
|
|
91
|
+
*/
|
|
92
|
+
const spillHandlesLargeOutput = ctx.get('spillStore') !== undefined;
|
|
93
|
+
/**
|
|
94
|
+
* Apply the spill coordination to a freshly resolved configuration.
|
|
95
|
+
*
|
|
96
|
+
* Gated on an explicit switch rather than on "did the row set truncate?":
|
|
97
|
+
* the loader hands this function a schema-resolved config where every field
|
|
98
|
+
* already carries its default, so an absent key is indistinguishable from an
|
|
99
|
+
* explicit one. `deferToHarnessSpill: false` is how a row keeps its own
|
|
100
|
+
* bound regardless.
|
|
101
|
+
*/
|
|
102
|
+
function coordinate(next) {
|
|
103
|
+
if (spillHandlesLargeOutput && next.outputCompaction.deferToHarnessSpill) {
|
|
104
|
+
next.outputCompaction.truncate.enabled = false;
|
|
105
|
+
}
|
|
106
|
+
return next;
|
|
107
|
+
}
|
|
108
|
+
let config = coordinate(normalizeConfig(rawConfig));
|
|
109
|
+
let runtimeStatus = { rtkAvailable: false };
|
|
110
|
+
const metrics = createMetricsTracker();
|
|
111
|
+
/** Rewrite decisions awaiting their result, keyed by call id, for `suggest` mode. */
|
|
112
|
+
const pendingSuggestions = new Map();
|
|
113
|
+
/** Call ids whose result should carry the one-time "rtk is missing" notice. */
|
|
114
|
+
const missingRtkCalls = new Set();
|
|
115
|
+
/** Sessions already told that rtk is absent, so the notice is emitted once each. */
|
|
116
|
+
const notifiedAgents = new Set();
|
|
117
|
+
// The settings namespace is process-global, so only the first instance of
|
|
118
|
+
// this plugin can own it. A host-plane row and a preset row both mounted, or
|
|
119
|
+
// two presets mounting the same row, would otherwise fail the second mount
|
|
120
|
+
// outright — a configuration convenience must never be the reason a whole
|
|
121
|
+
// preset refuses to activate. The loser follows the winner through the
|
|
122
|
+
// settings event instead.
|
|
123
|
+
const settings = ctx.get('settings');
|
|
124
|
+
let ownedScope;
|
|
125
|
+
// Surfaced by `/rtk show`. A silently swallowed registration failure hides
|
|
126
|
+
// the only runtime-editable configuration path this plugin has, and the
|
|
127
|
+
// failure mode (settings edits simply do nothing) is invisible otherwise.
|
|
128
|
+
let settingsNote;
|
|
129
|
+
if (settings === undefined) {
|
|
130
|
+
settingsNote = 'settings service unavailable — configuration comes from the composition only';
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
try {
|
|
134
|
+
const scope = settings.register('dsh-rtk', Config, { base: rawConfig });
|
|
135
|
+
ownedScope = scope;
|
|
136
|
+
config = coordinate(normalizeConfig(scope.get()));
|
|
137
|
+
scope.watch((next) => {
|
|
138
|
+
config = coordinate(normalizeConfig(next));
|
|
139
|
+
applySourceFilterNote();
|
|
140
|
+
});
|
|
141
|
+
settingsNote = 'the `dsh-rtk` namespace in the harness settings document';
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
settingsNote = `settings namespace unavailable (${error instanceof Error ? error.message : String(error)}) — configuration comes from the composition only`;
|
|
145
|
+
const existing = settings.get('dsh-rtk');
|
|
146
|
+
if (existing !== undefined)
|
|
147
|
+
config = coordinate(normalizeConfig(existing));
|
|
148
|
+
ctx.on('settings/updated', (ns, next) => {
|
|
149
|
+
if (ns !== 'dsh-rtk')
|
|
150
|
+
return;
|
|
151
|
+
config = coordinate(normalizeConfig(next));
|
|
152
|
+
applySourceFilterNote();
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
let disposeNote;
|
|
157
|
+
const systemPrompt = ctx.get('systemPrompt');
|
|
158
|
+
function applySourceFilterNote() {
|
|
159
|
+
if (systemPrompt === undefined)
|
|
160
|
+
return;
|
|
161
|
+
if (needsSourceFilterNote(config)) {
|
|
162
|
+
if (disposeNote !== undefined)
|
|
163
|
+
return;
|
|
164
|
+
disposeNote = systemPrompt.section({ name: 'rtk:read-compaction', order: 1010, text: SOURCE_FILTER_TROUBLESHOOTING_NOTE });
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
disposeNote?.();
|
|
168
|
+
disposeNote = undefined;
|
|
169
|
+
}
|
|
170
|
+
applySourceFilterNote();
|
|
171
|
+
ctx.effect(() => () => {
|
|
172
|
+
disposeNote?.();
|
|
173
|
+
disposeNote = undefined;
|
|
174
|
+
}, 'dsh-rtk.prompt-note');
|
|
175
|
+
async function refreshRuntimeStatus() {
|
|
176
|
+
const resolution = await resolveRtkExecutable({ configured: config.rtkExecutable });
|
|
177
|
+
const probe = await runExecutable(resolution.command, ['--version'], { timeoutMs: 5000 });
|
|
178
|
+
const base = {
|
|
179
|
+
rtkExecutableCommand: resolution.command,
|
|
180
|
+
...(resolution.resolvedPath === undefined ? {} : { rtkExecutablePath: resolution.resolvedPath }),
|
|
181
|
+
rtkExecutableResolver: resolution.resolver,
|
|
182
|
+
...(resolution.warning === undefined ? {} : { rtkExecutableResolutionWarning: resolution.warning }),
|
|
183
|
+
lastCheckedAt: Date.now(),
|
|
184
|
+
};
|
|
185
|
+
runtimeStatus =
|
|
186
|
+
probe.code === 0
|
|
187
|
+
? { rtkAvailable: true, ...base }
|
|
188
|
+
: {
|
|
189
|
+
rtkAvailable: false,
|
|
190
|
+
...base,
|
|
191
|
+
lastError: (probe.stderr || probe.stdout).replace(/\s+/g, ' ').trim() || `exit ${probe.code}`,
|
|
192
|
+
};
|
|
193
|
+
return runtimeStatus;
|
|
194
|
+
}
|
|
195
|
+
async function ensureRuntimeStatusFresh() {
|
|
196
|
+
if (!shouldRequireRtkAvailability(config))
|
|
197
|
+
return;
|
|
198
|
+
if (!isStatusStale(runtimeStatus, Date.now()))
|
|
199
|
+
return;
|
|
200
|
+
try {
|
|
201
|
+
await refreshRuntimeStatus();
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
runtimeStatus = {
|
|
205
|
+
rtkAvailable: false,
|
|
206
|
+
lastCheckedAt: Date.now(),
|
|
207
|
+
lastError: error instanceof Error ? error.message : String(error),
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
// ── command rewriting ────────────────────────────────────────────────────
|
|
212
|
+
ctx.on('tools/execute', async (exec, next) => {
|
|
213
|
+
if (!config.enabled)
|
|
214
|
+
return next();
|
|
215
|
+
if (config.mode !== 'rewrite')
|
|
216
|
+
return next();
|
|
217
|
+
if (!REWRITABLE_TOOLS.has(exec.name))
|
|
218
|
+
return next();
|
|
219
|
+
const args = asRecord(exec.arguments);
|
|
220
|
+
if (args === undefined || typeof args.command !== 'string')
|
|
221
|
+
return next();
|
|
222
|
+
await ensureRuntimeStatusFresh();
|
|
223
|
+
if (shouldSkipRewrite(config, runtimeStatus)) {
|
|
224
|
+
// The guard is standing the rewrite down because rtk is unavailable. Flag
|
|
225
|
+
// this result so post-execute can say so once per session.
|
|
226
|
+
if (config.notifyWhenRtkMissing) {
|
|
227
|
+
if (missingRtkCalls.size > 256)
|
|
228
|
+
missingRtkCalls.clear();
|
|
229
|
+
missingRtkCalls.add(exec.callId);
|
|
230
|
+
}
|
|
231
|
+
return next();
|
|
232
|
+
}
|
|
233
|
+
const decision = await resolveRtkRewrite(args.command, {
|
|
234
|
+
runner: runExecutable,
|
|
235
|
+
executable: runtimeStatus.rtkExecutableCommand ?? config.rtkExecutable,
|
|
236
|
+
timeoutMs: config.rewriteTimeoutMs,
|
|
237
|
+
signal: exec.signal,
|
|
238
|
+
});
|
|
239
|
+
if (!decision.changed)
|
|
240
|
+
return next();
|
|
241
|
+
// `pwsh` is a rewrite target too, and PowerShell has no `export`.
|
|
242
|
+
const shell = exec.name === 'pwsh' ? 'powershell' : 'posix';
|
|
243
|
+
const command = applyRtkHistoryScope(decision.rewrittenCommand, rtkHistoryDbPath(), process.env.RTK_DB_PATH, shell);
|
|
244
|
+
if (config.showRewriteNotifications) {
|
|
245
|
+
// A cancelled call can be finalized on the `final-result` path, which
|
|
246
|
+
// bypasses post-execute and would leave its entry behind. The map is
|
|
247
|
+
// bounded so a notification nobody reads cannot grow without limit.
|
|
248
|
+
if (pendingSuggestions.size > 256)
|
|
249
|
+
pendingSuggestions.clear();
|
|
250
|
+
pendingSuggestions.set(exec.callId, `[rtk] rewrote: ${decision.originalCommand} -> ${decision.rewrittenCommand}`);
|
|
251
|
+
}
|
|
252
|
+
// `arguments` is declared readonly, but the around-dispatch stage is the
|
|
253
|
+
// one place the registry re-reads it before invoking the body. Restoring it
|
|
254
|
+
// in `finally` keeps every later stage — post-execute, content
|
|
255
|
+
// finalization, and the observation in `tools/result` — looking at the call
|
|
256
|
+
// the model actually made.
|
|
257
|
+
const mutable = exec;
|
|
258
|
+
mutable.arguments = { ...args, command };
|
|
259
|
+
try {
|
|
260
|
+
return await next();
|
|
261
|
+
}
|
|
262
|
+
catch (error) {
|
|
263
|
+
pendingSuggestions.delete(exec.callId);
|
|
264
|
+
throw error;
|
|
265
|
+
}
|
|
266
|
+
finally {
|
|
267
|
+
mutable.arguments = args;
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
// ── suggest mode ─────────────────────────────────────────────────────────
|
|
271
|
+
ctx.on('tools/execute', async (exec, next) => {
|
|
272
|
+
if (!config.enabled || config.mode !== 'suggest')
|
|
273
|
+
return next();
|
|
274
|
+
if (!REWRITABLE_TOOLS.has(exec.name))
|
|
275
|
+
return next();
|
|
276
|
+
const args = asRecord(exec.arguments);
|
|
277
|
+
if (args === undefined || typeof args.command !== 'string')
|
|
278
|
+
return next();
|
|
279
|
+
await ensureRuntimeStatusFresh();
|
|
280
|
+
if (shouldSkipRewrite(config, runtimeStatus)) {
|
|
281
|
+
// The guard is standing the rewrite down because rtk is unavailable. Flag
|
|
282
|
+
// this result so post-execute can say so once per session.
|
|
283
|
+
if (config.notifyWhenRtkMissing) {
|
|
284
|
+
if (missingRtkCalls.size > 256)
|
|
285
|
+
missingRtkCalls.clear();
|
|
286
|
+
missingRtkCalls.add(exec.callId);
|
|
287
|
+
}
|
|
288
|
+
return next();
|
|
289
|
+
}
|
|
290
|
+
const decision = await resolveRtkRewrite(args.command, {
|
|
291
|
+
runner: runExecutable,
|
|
292
|
+
executable: runtimeStatus.rtkExecutableCommand ?? config.rtkExecutable,
|
|
293
|
+
timeoutMs: config.rewriteTimeoutMs,
|
|
294
|
+
signal: exec.signal,
|
|
295
|
+
});
|
|
296
|
+
if (decision.changed) {
|
|
297
|
+
if (pendingSuggestions.size > 256)
|
|
298
|
+
pendingSuggestions.clear();
|
|
299
|
+
pendingSuggestions.set(exec.callId, `[rtk] suggestion: ${decision.rewrittenCommand}`);
|
|
300
|
+
}
|
|
301
|
+
try {
|
|
302
|
+
return await next();
|
|
303
|
+
}
|
|
304
|
+
catch (error) {
|
|
305
|
+
pendingSuggestions.delete(exec.callId);
|
|
306
|
+
throw error;
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
// ── output compaction ────────────────────────────────────────────────────
|
|
310
|
+
ctx.on('tools/post-execute', async (exec, result, next) => {
|
|
311
|
+
const decision = await next();
|
|
312
|
+
let notice = pendingSuggestions.get(exec.callId);
|
|
313
|
+
pendingSuggestions.delete(exec.callId);
|
|
314
|
+
if (missingRtkCalls.delete(exec.callId) && config.notifyWhenRtkMissing) {
|
|
315
|
+
const agentKey = exec.agent?.id;
|
|
316
|
+
if (agentKey !== undefined && !notifiedAgents.has(agentKey)) {
|
|
317
|
+
if (notifiedAgents.size > 256)
|
|
318
|
+
notifiedAgents.clear();
|
|
319
|
+
notifiedAgents.add(agentKey);
|
|
320
|
+
notice = MISSING_RTK_NOTICE;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
if (decision.kind !== 'accept')
|
|
324
|
+
return decision;
|
|
325
|
+
if (!config.enabled)
|
|
326
|
+
return decision;
|
|
327
|
+
const source = decision.content ?? result.content;
|
|
328
|
+
if (source.length === 0)
|
|
329
|
+
return decision;
|
|
330
|
+
let content = source;
|
|
331
|
+
try {
|
|
332
|
+
const outcome = compactToolResult({ toolName: exec.name, args: exec.arguments, content: source }, config);
|
|
333
|
+
if (outcome.changed && outcome.content !== undefined) {
|
|
334
|
+
content = outcome.content;
|
|
335
|
+
if (outcome.metadata !== undefined && config.outputCompaction.trackSavings) {
|
|
336
|
+
metrics.track(source.map((block) => block.text ?? '').join('\n'), content.map((block) => block.text ?? '').join('\n'), exec.name, outcome.techniques);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
catch {
|
|
341
|
+
// Compaction is an optimization; a bug in it must not break the tool call.
|
|
342
|
+
return notice === undefined ? decision : { kind: 'accept', content: appendNotice(source, notice) };
|
|
343
|
+
}
|
|
344
|
+
// A sibling listener may have attached contexts for the next request.
|
|
345
|
+
// Rebuilding the decision without them would drop them silently, and the
|
|
346
|
+
// shipped search tool does exactly that when a result was capped.
|
|
347
|
+
const contexts = decision.additionalContexts;
|
|
348
|
+
const rebuild = (blocks) => ({
|
|
349
|
+
kind: 'accept',
|
|
350
|
+
content: blocks,
|
|
351
|
+
...(contexts === undefined ? {} : { additionalContexts: contexts }),
|
|
352
|
+
});
|
|
353
|
+
if (notice === undefined) {
|
|
354
|
+
return content === source ? decision : rebuild([...content]);
|
|
355
|
+
}
|
|
356
|
+
return rebuild(appendNotice(content, notice));
|
|
357
|
+
});
|
|
358
|
+
// ── the /rtk command ─────────────────────────────────────────────────────
|
|
359
|
+
const commands = ctx.get('commands');
|
|
360
|
+
if (commands !== undefined) {
|
|
361
|
+
const command = createRtkCommand({
|
|
362
|
+
getConfig: () => config,
|
|
363
|
+
resetConfig: async () => {
|
|
364
|
+
if (ownedScope === undefined)
|
|
365
|
+
return;
|
|
366
|
+
await ownedScope.replace({});
|
|
367
|
+
config = coordinate(normalizeConfig(settings?.get('dsh-rtk')));
|
|
368
|
+
},
|
|
369
|
+
getRuntimeStatus: () => runtimeStatus,
|
|
370
|
+
refreshRuntimeStatus,
|
|
371
|
+
getMetrics: () => metrics.summary(),
|
|
372
|
+
clearMetrics: () => metrics.clear(),
|
|
373
|
+
configLocation: () => settingsNote,
|
|
374
|
+
});
|
|
375
|
+
ctx.effect(() => commands.register(command), 'dsh-rtk.command');
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Insert a one-line notice into a result, ahead of any trailing status markers.
|
|
380
|
+
*
|
|
381
|
+
* The markers must stay last. The harness parses the final line for the exit
|
|
382
|
+
* status — the model is told to check `[exit code: N]` on every call, and the
|
|
383
|
+
* Web UI derives its exit-status pill from the same line. Appending a notice
|
|
384
|
+
* after them would break both silently, which is exactly what an earlier
|
|
385
|
+
* version of this function did.
|
|
386
|
+
*/
|
|
387
|
+
function appendNotice(content, notice) {
|
|
388
|
+
const blocks = [...content];
|
|
389
|
+
for (let index = blocks.length - 1; index >= 0; index -= 1) {
|
|
390
|
+
const block = blocks[index];
|
|
391
|
+
if (block === undefined || block.type !== 'text')
|
|
392
|
+
continue;
|
|
393
|
+
const parts = parseBashResult(block.text);
|
|
394
|
+
if (parts.empty || parts.markers.length === 0) {
|
|
395
|
+
blocks[index] = { type: 'text', text: `${block.text}\n${notice}` };
|
|
396
|
+
return blocks;
|
|
397
|
+
}
|
|
398
|
+
const stdout = parts.stdout.length > 0 ? `${parts.stdout}\n${notice}` : notice;
|
|
399
|
+
blocks[index] = { type: 'text', text: renderBashResult({ ...parts, stdout }) };
|
|
400
|
+
return blocks;
|
|
401
|
+
}
|
|
402
|
+
return [...blocks, { type: 'text', text: notice }];
|
|
403
|
+
}
|
|
404
|
+
export { READ_COMPACTION_BANNER_PREFIX };
|
|
405
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/lib/metrics.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/** Per-tool savings accumulators for the current session. */
|
|
2
|
+
export interface ToolSavings {
|
|
3
|
+
calls: number;
|
|
4
|
+
originalChars: number;
|
|
5
|
+
compactedChars: number;
|
|
6
|
+
}
|
|
7
|
+
/** One session's compaction savings. */
|
|
8
|
+
export interface MetricsSummary {
|
|
9
|
+
calls: number;
|
|
10
|
+
originalChars: number;
|
|
11
|
+
compactedChars: number;
|
|
12
|
+
savedChars: number;
|
|
13
|
+
savedPercent: number;
|
|
14
|
+
byTool: Record<string, ToolSavings>;
|
|
15
|
+
/** How often each technique fired, across all calls. */
|
|
16
|
+
byTechnique: Record<string, number>;
|
|
17
|
+
}
|
|
18
|
+
/** Accumulates compaction savings; one instance per plugin application. */
|
|
19
|
+
export interface MetricsTracker {
|
|
20
|
+
/** Record one compacted result. A no-op result must not be passed here. */
|
|
21
|
+
track(originalText: string, compactedText: string, tool: string, techniques: readonly string[]): void;
|
|
22
|
+
/** Current totals, recomputed on each call so callers cannot mutate them. */
|
|
23
|
+
summary(): MetricsSummary;
|
|
24
|
+
/** Drop all recorded savings. */
|
|
25
|
+
clear(): void;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Build the session metrics accumulator.
|
|
29
|
+
*
|
|
30
|
+
* Savings are approximate by construction — character counts stand in for
|
|
31
|
+
* tokens — but they are measured on exactly the strings that were swapped, so
|
|
32
|
+
* the ratio is honest even when the absolute number is not.
|
|
33
|
+
*/
|
|
34
|
+
export declare function createMetricsTracker(): MetricsTracker;
|
|
35
|
+
//# sourceMappingURL=metrics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../src/metrics.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAA;IACb,aAAa,EAAE,MAAM,CAAA;IACrB,cAAc,EAAE,MAAM,CAAA;CACvB;AAED,wCAAwC;AACxC,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAA;IACb,aAAa,EAAE,MAAM,CAAA;IACrB,cAAc,EAAE,MAAM,CAAA;IACtB,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;IACnC,wDAAwD;IACxD,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACpC;AAED,2EAA2E;AAC3E,MAAM,WAAW,cAAc;IAC7B,2EAA2E;IAC3E,KAAK,CAAC,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAA;IACrG,6EAA6E;IAC7E,OAAO,IAAI,cAAc,CAAA;IACzB,iCAAiC;IACjC,KAAK,IAAI,IAAI,CAAA;CACd;AAMD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,IAAI,cAAc,CA2CrD"}
|
package/lib/metrics.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
function emptyTotals() {
|
|
2
|
+
return { calls: 0, originalChars: 0, compactedChars: 0 };
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* Build the session metrics accumulator.
|
|
6
|
+
*
|
|
7
|
+
* Savings are approximate by construction — character counts stand in for
|
|
8
|
+
* tokens — but they are measured on exactly the strings that were swapped, so
|
|
9
|
+
* the ratio is honest even when the absolute number is not.
|
|
10
|
+
*/
|
|
11
|
+
export function createMetricsTracker() {
|
|
12
|
+
let calls = 0;
|
|
13
|
+
let originalChars = 0;
|
|
14
|
+
let compactedChars = 0;
|
|
15
|
+
const byTool = new Map();
|
|
16
|
+
const byTechnique = new Map();
|
|
17
|
+
return {
|
|
18
|
+
track(originalText, compactedText, tool, techniques) {
|
|
19
|
+
calls += 1;
|
|
20
|
+
originalChars += originalText.length;
|
|
21
|
+
compactedChars += compactedText.length;
|
|
22
|
+
const totals = byTool.get(tool) ?? emptyTotals();
|
|
23
|
+
totals.calls += 1;
|
|
24
|
+
totals.originalChars += originalText.length;
|
|
25
|
+
totals.compactedChars += compactedText.length;
|
|
26
|
+
byTool.set(tool, totals);
|
|
27
|
+
for (const technique of techniques)
|
|
28
|
+
byTechnique.set(technique, (byTechnique.get(technique) ?? 0) + 1);
|
|
29
|
+
},
|
|
30
|
+
summary() {
|
|
31
|
+
const savedChars = Math.max(0, originalChars - compactedChars);
|
|
32
|
+
return {
|
|
33
|
+
calls,
|
|
34
|
+
originalChars,
|
|
35
|
+
compactedChars,
|
|
36
|
+
savedChars,
|
|
37
|
+
savedPercent: originalChars === 0 ? 0 : Math.round((savedChars / originalChars) * 1000) / 10,
|
|
38
|
+
byTool: Object.fromEntries(byTool),
|
|
39
|
+
byTechnique: Object.fromEntries(byTechnique),
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
clear() {
|
|
43
|
+
calls = 0;
|
|
44
|
+
originalChars = 0;
|
|
45
|
+
compactedChars = 0;
|
|
46
|
+
byTool.clear();
|
|
47
|
+
byTechnique.clear();
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=metrics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.js","sourceRoot":"","sources":["../src/metrics.ts"],"names":[],"mappings":"AA6BA,SAAS,WAAW;IAClB,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,CAAA;AAC1D,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB;IAClC,IAAI,KAAK,GAAG,CAAC,CAAA;IACb,IAAI,aAAa,GAAG,CAAC,CAAA;IACrB,IAAI,cAAc,GAAG,CAAC,CAAA;IACtB,MAAM,MAAM,GAAG,IAAI,GAAG,EAAuB,CAAA;IAC7C,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAA;IAE7C,OAAO;QACL,KAAK,CAAC,YAAY,EAAE,aAAa,EAAE,IAAI,EAAE,UAAU;YACjD,KAAK,IAAI,CAAC,CAAA;YACV,aAAa,IAAI,YAAY,CAAC,MAAM,CAAA;YACpC,cAAc,IAAI,aAAa,CAAC,MAAM,CAAA;YAEtC,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,WAAW,EAAE,CAAA;YAChD,MAAM,CAAC,KAAK,IAAI,CAAC,CAAA;YACjB,MAAM,CAAC,aAAa,IAAI,YAAY,CAAC,MAAM,CAAA;YAC3C,MAAM,CAAC,cAAc,IAAI,aAAa,CAAC,MAAM,CAAA;YAC7C,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;YAExB,KAAK,MAAM,SAAS,IAAI,UAAU;gBAAE,WAAW,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;QACvG,CAAC;QAED,OAAO;YACL,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,aAAa,GAAG,cAAc,CAAC,CAAA;YAC9D,OAAO;gBACL,KAAK;gBACL,aAAa;gBACb,cAAc;gBACd,UAAU;gBACV,YAAY,EAAE,aAAa,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,UAAU,GAAG,aAAa,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE;gBAC5F,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC;gBAClC,WAAW,EAAE,MAAM,CAAC,WAAW,CAAC,WAAW,CAAC;aAC7C,CAAA;QACH,CAAC;QAED,KAAK;YACH,KAAK,GAAG,CAAC,CAAA;YACT,aAAa,GAAG,CAAC,CAAA;YACjB,cAAc,GAAG,CAAC,CAAA;YAClB,MAAM,CAAC,KAAK,EAAE,CAAA;YACd,WAAW,CAAC,KAAK,EAAE,CAAA;QACrB,CAAC;KACF,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/** One settled `rtk` invocation. */
|
|
2
|
+
export interface RtkRunResult {
|
|
3
|
+
code: number;
|
|
4
|
+
stdout: string;
|
|
5
|
+
stderr: string;
|
|
6
|
+
}
|
|
7
|
+
/** How an rtk executable path was discovered. */
|
|
8
|
+
export type RtkResolverName = 'where' | 'which' | 'configured';
|
|
9
|
+
/** The executable this plugin will use, and how sure it is. */
|
|
10
|
+
export interface RtkExecutableResolution {
|
|
11
|
+
command: string;
|
|
12
|
+
resolvedPath?: string;
|
|
13
|
+
resolver: RtkResolverName;
|
|
14
|
+
warning?: string;
|
|
15
|
+
}
|
|
16
|
+
/** Everything the resolver needs; all fields have production defaults. */
|
|
17
|
+
export interface ResolveRtkExecutableOptions {
|
|
18
|
+
/** Configured executable name or path. */
|
|
19
|
+
configured: string;
|
|
20
|
+
/** Command used to look the name up on PATH. */
|
|
21
|
+
resolverCommand?: string;
|
|
22
|
+
timeoutMs?: number;
|
|
23
|
+
platform?: NodeJS.Platform;
|
|
24
|
+
}
|
|
25
|
+
/** Resolver executable name for a platform. */
|
|
26
|
+
export declare function resolverNameFor(platform: NodeJS.Platform): 'where' | 'which';
|
|
27
|
+
/**
|
|
28
|
+
* Invoke one executable and settle with its output.
|
|
29
|
+
*
|
|
30
|
+
* A missing binary or a non-zero exit resolves rather than rejects: every
|
|
31
|
+
* caller here treats "rtk said no" as an ordinary outcome, and rejecting would
|
|
32
|
+
* make each call site wrap the same try/catch. Arguments are passed as an
|
|
33
|
+
* array, so no command string is ever handed to a shell.
|
|
34
|
+
*/
|
|
35
|
+
export declare function runExecutable(command: string, args: readonly string[], options?: {
|
|
36
|
+
timeoutMs?: number;
|
|
37
|
+
signal?: AbortSignal;
|
|
38
|
+
}): Promise<RtkRunResult>;
|
|
39
|
+
/** First non-empty line of resolver output, with surrounding quotes removed. */
|
|
40
|
+
export declare function parseExecutablePath(stdout: string): string | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* Resolve the rtk executable, preferring the configured value.
|
|
43
|
+
*
|
|
44
|
+
* A configured value that is not a bare name is taken as an absolute path and
|
|
45
|
+
* used verbatim — the deployment said where rtk lives, so a PATH probe would
|
|
46
|
+
* only second-guess it. Bare names are looked up so `/rtk verify` can report a
|
|
47
|
+
* real path; a failed lookup is not fatal, because the name may still resolve
|
|
48
|
+
* when the command actually runs.
|
|
49
|
+
*/
|
|
50
|
+
export declare function resolveRtkExecutable(options: ResolveRtkExecutableOptions): Promise<RtkExecutableResolution>;
|
|
51
|
+
//# sourceMappingURL=rtk-executable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rtk-executable.d.ts","sourceRoot":"","sources":["../src/rtk-executable.ts"],"names":[],"mappings":"AAEA,oCAAoC;AACpC,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;CACf;AAED,iDAAiD;AACjD,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,OAAO,GAAG,YAAY,CAAA;AAE9D,+DAA+D;AAC/D,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,EAAE,eAAe,CAAA;IACzB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,0EAA0E;AAC1E,MAAM,WAAW,2BAA2B;IAC1C,0CAA0C;IAC1C,UAAU,EAAE,MAAM,CAAA;IAClB,gDAAgD;IAChD,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAA;CAC3B;AAED,+CAA+C;AAC/C,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,GAAG,OAAO,GAAG,OAAO,CAE5E;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAAO,GACzD,OAAO,CAAC,YAAY,CAAC,CAqBvB;AAED,gFAAgF;AAChF,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAWtE;AAED;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,2BAA2B,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAuBjH"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
/** Resolver executable name for a platform. */
|
|
3
|
+
export function resolverNameFor(platform) {
|
|
4
|
+
return platform === 'win32' ? 'where' : 'which';
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Invoke one executable and settle with its output.
|
|
8
|
+
*
|
|
9
|
+
* A missing binary or a non-zero exit resolves rather than rejects: every
|
|
10
|
+
* caller here treats "rtk said no" as an ordinary outcome, and rejecting would
|
|
11
|
+
* make each call site wrap the same try/catch. Arguments are passed as an
|
|
12
|
+
* array, so no command string is ever handed to a shell.
|
|
13
|
+
*/
|
|
14
|
+
export function runExecutable(command, args, options = {}) {
|
|
15
|
+
return new Promise((resolve) => {
|
|
16
|
+
execFile(command, [...args], {
|
|
17
|
+
timeout: options.timeoutMs ?? 3000,
|
|
18
|
+
maxBuffer: 4 * 1024 * 1024,
|
|
19
|
+
windowsHide: true,
|
|
20
|
+
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
21
|
+
}, (error, stdout, stderr) => {
|
|
22
|
+
if (error === null) {
|
|
23
|
+
resolve({ code: 0, stdout, stderr });
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const code = typeof error.code === 'number' ? error.code : 1;
|
|
27
|
+
resolve({ code, stdout: stdout ?? '', stderr: stderr ?? '' });
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
/** First non-empty line of resolver output, with surrounding quotes removed. */
|
|
32
|
+
export function parseExecutablePath(stdout) {
|
|
33
|
+
for (const line of stdout.split(/\r?\n/)) {
|
|
34
|
+
let candidate = line.trim();
|
|
35
|
+
if (candidate.length >= 2) {
|
|
36
|
+
const first = candidate[0];
|
|
37
|
+
const last = candidate[candidate.length - 1];
|
|
38
|
+
if ((first === '"' && last === '"') || (first === "'" && last === "'"))
|
|
39
|
+
candidate = candidate.slice(1, -1);
|
|
40
|
+
}
|
|
41
|
+
if (candidate)
|
|
42
|
+
return candidate;
|
|
43
|
+
}
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Resolve the rtk executable, preferring the configured value.
|
|
48
|
+
*
|
|
49
|
+
* A configured value that is not a bare name is taken as an absolute path and
|
|
50
|
+
* used verbatim — the deployment said where rtk lives, so a PATH probe would
|
|
51
|
+
* only second-guess it. Bare names are looked up so `/rtk verify` can report a
|
|
52
|
+
* real path; a failed lookup is not fatal, because the name may still resolve
|
|
53
|
+
* when the command actually runs.
|
|
54
|
+
*/
|
|
55
|
+
export async function resolveRtkExecutable(options) {
|
|
56
|
+
const platform = options.platform ?? process.platform;
|
|
57
|
+
const configured = options.configured.trim() || 'rtk';
|
|
58
|
+
const looksLikePath = configured.includes('/') || configured.includes('\\');
|
|
59
|
+
if (looksLikePath) {
|
|
60
|
+
return { command: configured, resolvedPath: configured, resolver: 'configured' };
|
|
61
|
+
}
|
|
62
|
+
const resolver = options.resolverCommand ?? resolverNameFor(platform);
|
|
63
|
+
const result = await runExecutable(resolver, [configured], { timeoutMs: options.timeoutMs ?? 1000 });
|
|
64
|
+
const resolvedPath = parseExecutablePath(result.stdout);
|
|
65
|
+
if (result.code === 0 && resolvedPath !== undefined) {
|
|
66
|
+
return { command: resolvedPath, resolvedPath, resolver: resolver };
|
|
67
|
+
}
|
|
68
|
+
const detail = (result.stderr || result.stdout).replace(/\s+/g, ' ').trim();
|
|
69
|
+
return {
|
|
70
|
+
command: configured,
|
|
71
|
+
resolver: resolver,
|
|
72
|
+
warning: `could not resolve ${configured} via ${resolver}${detail ? `: ${detail}` : ''}`,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=rtk-executable.js.map
|