@toddzheng024/dscode-bundle 0.7.27 → 0.7.29
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/README.md +1 -1
- package/THIRD_PARTY_NOTICES.md +10 -10
- package/bootstrap.mjs +1 -1
- package/cordis.patch.yml +433 -46
- package/package.json +280 -245
- package/plugins/account/index.mjs +178 -0
- package/plugins/account/state.mjs +123 -0
- package/plugins/auto-review/index.mjs +8 -5
- package/plugins/code-review/index.mjs +1 -1
- package/plugins/computer-use/index.mjs +37 -0
- package/plugins/cordis-config/plain.mjs +31 -0
- package/plugins/dscode/index.mjs +1 -1
- package/plugins/exec/cli.mjs +1 -1
- package/plugins/grok/index.mjs +28 -24
- package/plugins/i18n/messages.mjs +204 -0
- package/plugins/memory/index.mjs +1 -1
- package/plugins/message-source/kind.mjs +20 -0
- package/plugins/openrouter/adapter.mjs +29 -13
- package/plugins/openrouter/index.mjs +31 -28
- package/plugins/session-bridge/communication.mjs +6 -3
- package/plugins/session-bridge/server.mjs +3 -2
- package/plugins/session-bridge/tasks.mjs +3 -1
- package/plugins/session-cards/index.mjs +1 -1
- package/plugins/time-marks/index.mjs +3 -2
- package/plugins/time-marks/marks.mjs +6 -5
- package/plugins/triggers/config.mjs +1 -1
- package/plugins/triggers/tools.mjs +1 -1
- package/plugins/tui-tools/doctor.mjs +1 -1
- package/plugins/tui-tools/index.mjs +16 -4
- package/plugins/ultra/policy.mjs +16 -0
- package/vendor/bash/index.js +455 -186
- package/vendor/bash/types/background.d.ts +38 -7
- package/vendor/bash/types/index.d.ts +20 -4
- package/vendor/bash/types/render.d.ts +28 -9
- package/vendor/command-goal/index.js +3 -1
- package/vendor/deepseek/index.js +1378 -1246
- package/vendor/deepseek/types/adapter.d.ts +16 -155
- package/vendor/deepseek/types/config.d.ts +127 -0
- package/vendor/deepseek/types/defaults.d.ts +24 -0
- package/vendor/deepseek/types/file-store.d.ts +5 -3
- package/vendor/deepseek/types/files-api.d.ts +12 -9
- package/vendor/deepseek/types/image-tokens.d.ts +24 -9
- package/vendor/deepseek/types/images.d.ts +35 -0
- package/vendor/deepseek/types/index.d.ts +10 -94
- package/vendor/deepseek/types/messages-api.d.ts +10 -0
- package/vendor/deepseek/types/model-info.d.ts +16 -0
- package/vendor/deepseek/types/models.d.ts +4 -0
- package/vendor/deepseek/types/replay.d.ts +27 -0
- package/vendor/deepseek/types/request-extensions.d.ts +16 -0
- package/vendor/deepseek/types/request-files.d.ts +49 -0
- package/vendor/deepseek/types/request-pricing.d.ts +32 -20
- package/vendor/deepseek/types/serialize.d.ts +17 -82
- package/vendor/deepseek/types/sse.d.ts +6 -22
- package/vendor/deepseek/types/translate.d.ts +13 -36
- package/vendor/deepseek/types/transport.d.ts +15 -0
- package/vendor/deepseek/types/types.d.ts +106 -167
- package/vendor/deepseek/types/wire-types.d.ts +62 -0
- package/vendor/persistent/index.js +9 -3
- package/vendor/subagent/index.js +11 -8
- package/vendor/subagent/model-selection-settings.js +12 -38
- package/vendor/subagent/types/index.d.ts +4 -3
- package/vendor/subagent/types/model-selection-settings.d.ts +12 -10
- package/vendor/subagent-core/index.js +401 -264
- package/vendor/subagent-core/typert.host.js +103 -113
- package/vendor/subagent-core/typert.remote-client.d.ts +1 -3
- package/vendor/subagent-core/typert.remote-client.js +23 -69
- package/vendor/subagent-core/types/archive-admission.d.ts +16 -0
- package/vendor/subagent-core/types/archive-admission.js +151 -0
- package/vendor/subagent-core/types/assistant-output.d.ts +2 -2
- package/vendor/subagent-core/types/catalog.d.ts +17 -10
- package/vendor/subagent-core/types/catalog.js +12 -6
- package/vendor/subagent-core/types/child-agent.d.ts +8 -5
- package/vendor/subagent-core/types/child-agent.js +11 -5
- package/vendor/subagent-core/types/continuation-activation.d.ts +17 -1
- package/vendor/subagent-core/types/continuation-activation.js +41 -4
- package/vendor/subagent-core/types/continuation-messages.d.ts +1 -1
- package/vendor/subagent-core/types/continuation-messages.js +7 -3
- package/vendor/subagent-core/types/continuation.d.ts +1 -1
- package/vendor/subagent-core/types/continuation.js +2 -2
- package/vendor/subagent-core/types/control-types.d.ts +29 -36
- package/vendor/subagent-core/types/control-types.js +2 -3
- package/vendor/subagent-core/types/control.d.ts +2 -28
- package/vendor/subagent-core/types/control.js +3 -40
- package/vendor/subagent-core/types/index.d.ts +45 -41
- package/vendor/subagent-core/types/index.js +46 -82
- package/vendor/subagent-core/types/internal.d.ts +2 -2
- package/vendor/subagent-core/types/internal.js +2 -2
- package/vendor/subagent-core/types/lifecycle.d.ts +1 -1
- package/vendor/subagent-core/types/lifecycle.js +5 -3
- package/vendor/subagent-core/types/list-children.d.ts +15 -32
- package/vendor/subagent-core/types/list-children.js +45 -49
- package/vendor/subagent-core/types/out-of-process.d.ts +1 -1
- package/vendor/subagent-core/types/projection-types.d.ts +9 -1
- package/vendor/subagent-core/types/projection.d.ts +5 -0
- package/vendor/subagent-core/types/projection.js +10 -4
- package/vendor/subagent-core/types/run-settlement.js +1 -1
- package/vendor/subagent-core/types/types.d.ts +2 -2
- package/vendor/terminal/index.js +94 -30
- package/vendor/tui/lib/index.mjs +2 -1
- package/vendor/tui/lib/kernel-panels.mjs +1 -1
- package/vendor/tui/lib/render/projection.mjs +50 -36
- package/presets/dscode/agent.cordis.yml +0 -321
- package/presets/dscode/preset.yml +0 -3
package/vendor/bash/index.js
CHANGED
|
@@ -1,33 +1,129 @@
|
|
|
1
1
|
// dscode-named-shell-v1
|
|
2
2
|
import z from "@deepseek-ai/schemastery";
|
|
3
|
-
import { isAbsolute,
|
|
3
|
+
import { isAbsolute, sep } from "node:path";
|
|
4
4
|
import { TOOL_ABORTED, defineTool } from "@deepseek-ai/dsh-tools";
|
|
5
5
|
import { HarnessError } from "@deepseek-ai/dsh-llm";
|
|
6
|
-
import { ESCALATION_TARGETS, approveEscalation,
|
|
6
|
+
import { ESCALATION_TARGETS, approveEscalation, escalationHintMarker, sandboxDenialMarker, validateEscalationArgs } from "@deepseek-ai/dsh-sandbox";
|
|
7
7
|
import { DSH_ENV_PREFIX, parseExitStatus } from "@deepseek-ai/dsh-shell";
|
|
8
8
|
//#region lib/types/background.js
|
|
9
9
|
/**
|
|
10
|
-
* Generic-
|
|
10
|
+
* Generic-job adaptation for bash process handles: the terminal outcome the
|
|
11
|
+
* registry records, the pull sources it pumps, and the ring read a foreground
|
|
12
|
+
* call renders when it stops waiting.
|
|
11
13
|
*
|
|
12
14
|
* @module @deepseek-ai/dsh-tool-bash/background
|
|
13
15
|
*/
|
|
14
16
|
/**
|
|
15
|
-
*
|
|
17
|
+
* Sandbox facts worth the terminal detail: a runner that never ran the
|
|
18
|
+
* command, or a denial (with the escalation hint this composition offers).
|
|
19
|
+
* @param sandbox - settled sandbox facts, when this was a confined process.
|
|
20
|
+
* @param escalationModes - escalation targets advertised by this composition.
|
|
21
|
+
* @returns the markers to append, oldest first.
|
|
22
|
+
*/
|
|
23
|
+
function sandboxNotes(sandbox, escalationModes) {
|
|
24
|
+
if (sandbox?.runnerFailed) return [`[sandbox: the sandbox runner itself failed under ${sandbox.mode} mode — the command did not run; this is a sandbox problem, not a command failure]`];
|
|
25
|
+
if (sandbox?.denied) {
|
|
26
|
+
const notes = [sandboxDenialMarker(sandbox.mode)];
|
|
27
|
+
if (escalationModes.length > 0) notes.push(escalationHintMarker("command"));
|
|
28
|
+
return notes;
|
|
29
|
+
}
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Map a settled background process onto the generic job-outcome vocabulary:
|
|
16
34
|
* `killed` stays `killed` (detail: the signal when one is known), everything
|
|
17
35
|
* else is `completed` with the exit code as detail. A nonzero command exit is
|
|
18
|
-
* reported, not failed, exactly like the foreground rendering.
|
|
36
|
+
* reported, not failed, exactly like the foreground rendering. Sandbox facts
|
|
37
|
+
* join the detail, since a job's terminal reason is the one line every
|
|
38
|
+
* reader — the model's status line, the roster row — shows.
|
|
19
39
|
* @param proc - the settled process handle.
|
|
40
|
+
* @param escalationModes - escalation targets advertised by this composition.
|
|
20
41
|
* @returns the outcome for the `ctx.jobs` registration.
|
|
21
42
|
*/
|
|
22
|
-
function processOutcome(proc) {
|
|
23
|
-
|
|
43
|
+
function processOutcome(proc, escalationModes = []) {
|
|
44
|
+
const base = proc.status === "killed" ? {
|
|
24
45
|
status: "killed",
|
|
25
46
|
detail: proc.signal !== null ? `signal: ${proc.signal}` : "killed before exit"
|
|
26
|
-
}
|
|
27
|
-
return {
|
|
47
|
+
} : {
|
|
28
48
|
status: "completed",
|
|
29
49
|
detail: `exit code: ${proc.exitCode ?? 0}`
|
|
30
50
|
};
|
|
51
|
+
const notes = sandboxNotes(proc.sandbox, escalationModes);
|
|
52
|
+
return notes.length === 0 ? base : {
|
|
53
|
+
...base,
|
|
54
|
+
detail: `${base.detail}; ${notes.join(" ")}`
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The process's non-consuming stream readers as registry pull sources. They
|
|
59
|
+
* bind lazily because the process is spawned inside the starter, after the
|
|
60
|
+
* registry admitted the job; a read before the spawn yields nothing, and the
|
|
61
|
+
* pump keeps the model's consuming cursor untouched. A rejected spawn's
|
|
62
|
+
* stderr reader carries the provider's `subprocess failed before reporting an
|
|
63
|
+
* outcome: …` note.
|
|
64
|
+
* @param proc - the started process's observed streams, once the starter has spawned it.
|
|
65
|
+
* @returns one source per stream, stdout first.
|
|
66
|
+
*/
|
|
67
|
+
function processSources(proc) {
|
|
68
|
+
const source = (channel) => ({
|
|
69
|
+
channel,
|
|
70
|
+
read: (fromByte) => {
|
|
71
|
+
const live = proc();
|
|
72
|
+
return live === void 0 ? {
|
|
73
|
+
text: "",
|
|
74
|
+
nextOffset: fromByte,
|
|
75
|
+
lossy: false
|
|
76
|
+
} : live.observed[channel].readFrom(fromByte);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
return [source("stdout"), source("stderr")];
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* The ring chunks of one consuming registry read as the shell tools render a
|
|
83
|
+
* process read: stdout chunks in order, then every stderr chunk in one
|
|
84
|
+
* `[stderr]` section, so the output a foreground call hands over when it
|
|
85
|
+
* stops waiting reads exactly like the `job_output` reads that follow it.
|
|
86
|
+
* @param chunks - the chunks since the model cursor, in offset order.
|
|
87
|
+
* @returns the delta text, possibly empty.
|
|
88
|
+
*/
|
|
89
|
+
function ringDelta(chunks) {
|
|
90
|
+
const out = chunks.filter((chunk) => chunk.channel !== "stderr").map((chunk) => chunk.text).join("");
|
|
91
|
+
const err = chunks.filter((chunk) => chunk.channel === "stderr").map((chunk) => chunk.text).join("");
|
|
92
|
+
const separator = out.length > 0 && !out.endsWith("\n") ? "\n" : "";
|
|
93
|
+
return out + (err.length > 0 ? `${separator}[stderr]\n${err}` : "");
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Adapt asynchronous shell preparation after job admission without exposing a partial process.
|
|
97
|
+
* @param start - starts the process with job-owned cancellation.
|
|
98
|
+
* @param outcome - projects the settled process into the job outcome.
|
|
99
|
+
* @returns synchronous job hooks whose completion includes preparation and process settlement.
|
|
100
|
+
*/
|
|
101
|
+
function processJob(start, outcome) {
|
|
102
|
+
const controller = new AbortController();
|
|
103
|
+
let process;
|
|
104
|
+
return {
|
|
105
|
+
cancel: (reason) => {
|
|
106
|
+
if (controller.signal.aborted) return;
|
|
107
|
+
controller.abort(reason);
|
|
108
|
+
process?.kill();
|
|
109
|
+
},
|
|
110
|
+
done: (async () => {
|
|
111
|
+
try {
|
|
112
|
+
process = await start(controller.signal);
|
|
113
|
+
try {
|
|
114
|
+
if (controller.signal.aborted) process.kill();
|
|
115
|
+
} finally {
|
|
116
|
+
await process.done;
|
|
117
|
+
}
|
|
118
|
+
return outcome(process);
|
|
119
|
+
} catch (error) {
|
|
120
|
+
return {
|
|
121
|
+
status: controller.signal.aborted && process === void 0 ? "killed" : "failed",
|
|
122
|
+
detail: error instanceof Error ? error.message : String(error)
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
})()
|
|
126
|
+
};
|
|
31
127
|
}
|
|
32
128
|
//#endregion
|
|
33
129
|
//#region lib/types/render.js
|
|
@@ -50,7 +146,7 @@ function streamText(output) {
|
|
|
50
146
|
* @param escalationModes - the escalation targets this composition advertises;
|
|
51
147
|
* non-empty adds the same-turn escalation hint after a denial marker
|
|
52
148
|
* (default `[]`: no hint).
|
|
53
|
-
* @returns the model-facing text: output body (or `(no output)`), then any timeout/signal/exit markers, each on its own line.
|
|
149
|
+
* @returns the model-facing text: output body (or `(no output)`), then any timeout/stopped/signal/exit markers, each on its own line.
|
|
54
150
|
*/
|
|
55
151
|
function renderResult(result, escalationModes = []) {
|
|
56
152
|
const out = streamText(result.stdout);
|
|
@@ -67,6 +163,7 @@ function renderResult(result, escalationModes = []) {
|
|
|
67
163
|
if (escalationModes.length > 0) markers.push(escalationHintMarker("command"));
|
|
68
164
|
}
|
|
69
165
|
if (result.timedOut) markers.push(`[timed out after ${result.timeoutMs}ms]`);
|
|
166
|
+
if (result.stopped !== void 0) markers.push(`[stopped: ${result.stopped}]`);
|
|
70
167
|
if (result.signal !== null) markers.push(`[killed by signal: ${result.signal}]`);
|
|
71
168
|
else if (result.exitCode !== 0) markers.push(`[exit code: ${result.exitCode}]`);
|
|
72
169
|
if (markers.length === 0) return body;
|
|
@@ -74,35 +171,50 @@ function renderResult(result, escalationModes = []) {
|
|
|
74
171
|
return body + markers.join("\n");
|
|
75
172
|
}
|
|
76
173
|
/**
|
|
77
|
-
* Shape
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
* @param
|
|
174
|
+
* Shape a foreground call that stopped waiting into the text the model sees:
|
|
175
|
+
* the output captured so far (one consuming registry read taken at that
|
|
176
|
+
* point, so `job_output` continues exactly after it), then the still-running
|
|
177
|
+
* marker and the job hand-off guidance.
|
|
178
|
+
* @param promoted - the promoted result value: the job id, the wait that
|
|
179
|
+
* expired, and the output so far.
|
|
180
|
+
* @returns the model-facing text for a promoted call.
|
|
181
|
+
*/
|
|
182
|
+
function renderPromoted(promoted) {
|
|
183
|
+
return `${promoted.output.length > 0 ? promoted.output.endsWith("\n") ? promoted.output : `${promoted.output}\n` : ""}[still running after ${promoted.timeoutMs}ms; moved to background job ${promoted.jobId}]\nThe command keeps running in the background. You will be notified when it finishes; read newer output with job_output, stop it with job_kill.`;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Shape the one consuming registry read a foreground call embeds in its
|
|
187
|
+
* result when it stops waiting: the output produced so far, plus the
|
|
188
|
+
* dropped-output notice (naming the job's spill files) when the model cursor
|
|
189
|
+
* fell behind the ring, and the sandbox notices. Later `job_output` reads
|
|
190
|
+
* render the same ring through the job tools.
|
|
191
|
+
* @param delta - the read's chunks as rendered text.
|
|
192
|
+
* @param lossy - whether bytes before the delta were evicted unread.
|
|
193
|
+
* @param spillPaths - the complete-stream files the job currently advertises.
|
|
82
194
|
* @param sandbox - settled sandbox facts, when this was a confined process.
|
|
83
195
|
* @param escalationModes - escalation targets advertised by this composition.
|
|
84
196
|
* @returns the delta text with any loss or sandbox notice appended.
|
|
85
197
|
*/
|
|
86
|
-
function
|
|
198
|
+
function renderJobRead(delta, lossy, spillPaths, sandbox, escalationModes = []) {
|
|
87
199
|
const notices = [];
|
|
88
|
-
if (
|
|
89
|
-
const paths = [read.stdoutSpillPath, read.stderrSpillPath].filter((path) => path !== void 0);
|
|
90
|
-
notices.push(`[some output was dropped from memory; full output: ${paths.length > 0 ? paths.join(", ") : "(unavailable)"}]`);
|
|
91
|
-
}
|
|
200
|
+
if (lossy) notices.push(`[some output was dropped from memory; full output: ${spillPaths.length > 0 ? spillPaths.join(", ") : "(unavailable)"}]`);
|
|
92
201
|
if (sandbox?.runnerFailed) notices.push(`[sandbox: the sandbox runner itself failed under ${sandbox.mode} mode — the command did not run; this is a sandbox problem, not a command failure]`);
|
|
93
202
|
else if (sandbox?.denied) {
|
|
94
203
|
notices.push(sandboxDenialMarker(sandbox.mode));
|
|
95
204
|
if (escalationModes.length > 0) notices.push(escalationHintMarker("command"));
|
|
96
205
|
}
|
|
97
|
-
if (notices.length === 0) return
|
|
98
|
-
return `${
|
|
206
|
+
if (notices.length === 0) return delta;
|
|
207
|
+
return `${delta}${delta.length > 0 && !delta.endsWith("\n") ? "\n" : ""}${notices.join("\n")}`;
|
|
99
208
|
}
|
|
100
209
|
//#endregion
|
|
101
210
|
//#region lib/types/index.js
|
|
102
211
|
/**
|
|
103
|
-
* Model-facing Consumer of the `ctx.shell` capability seam.
|
|
104
|
-
*
|
|
105
|
-
*
|
|
212
|
+
* Model-facing Consumer of the `ctx.shell` capability seam. While a job
|
|
213
|
+
* registry is composed, every call registers its process with `ctx.jobs` as
|
|
214
|
+
* it starts: `run_in_background` returns the id at once, and a foreground call
|
|
215
|
+
* waits on its job until the command finishes or the wait times out, at which
|
|
216
|
+
* point it returns the same id. Without a registry the tool is foreground-only
|
|
217
|
+
* and the executor's deadline kills the command.
|
|
106
218
|
*
|
|
107
219
|
* TODO(permissions): deployment policy belongs in `tools/pre-execute` and
|
|
108
220
|
* sandboxing executors; see docs/architecture.md § Where new behavior goes.
|
|
@@ -116,15 +228,21 @@ const inject = [
|
|
|
116
228
|
"shellEnv"
|
|
117
229
|
];
|
|
118
230
|
/** Runtime configuration schema for the bash tool plugin. */
|
|
119
|
-
const Config = z.object({
|
|
120
|
-
|
|
231
|
+
const Config = z.object({
|
|
232
|
+
toolName: z.string().default("bash"),
|
|
233
|
+
enableRunInBackground: z.boolean().default(true),
|
|
234
|
+
promoteOnTimeout: z.boolean().default(true)
|
|
235
|
+
});
|
|
236
|
+
function validateBashArgs(args, effectiveMode) {
|
|
121
237
|
if (args.command.trim().length === 0) throw new Error("invalid command: expected a non-empty string");
|
|
122
238
|
if (args.description.trim().length === 0) throw new Error("invalid description: expected a non-empty string");
|
|
123
239
|
if (args.timeoutMs !== void 0 && (!Number.isFinite(args.timeoutMs) || args.timeoutMs <= 0)) throw new Error(`invalid timeoutMs: expected a positive number, got ${JSON.stringify(args.timeoutMs)}`);
|
|
124
|
-
|
|
240
|
+
if (args.sandbox_permissions !== void 0 && args.sandbox_permissions === effectiveMode) return;
|
|
241
|
+
const justification = args.sandbox_permissions === void 0 && args.justification?.trim() === "" ? void 0 : args.justification;
|
|
242
|
+
validateEscalationArgs(args.sandbox_permissions, justification);
|
|
125
243
|
}
|
|
126
|
-
function bashDescription(backgroundEnabled, escalationModes) {
|
|
127
|
-
const background = backgroundEnabled ? "Set `run_in_background: true` for long-running commands: the call returns a job id immediately; read its output with `job_output` and stop it with `job_kill`." : "Background execution is not available; long-running commands must finish within the timeout.";
|
|
244
|
+
function bashDescription(backgroundEnabled, escalationModes, promoteOnTimeout) {
|
|
245
|
+
const background = backgroundEnabled ? "Set `run_in_background: true` for long-running commands: the call returns a job id immediately; read its output with `job_output` and stop it with `job_kill`." + (promoteOnTimeout ? " A foreground command that reaches its timeout is not killed: it moves to the background the same way, returning its job id and the output so far." : "") : "Background execution is not available; long-running commands must finish within the timeout.";
|
|
128
246
|
const base = `Execute a bash command (\`bash -c\`) and return its stdout/stderr. Each call runs in a fresh shell: no state (cwd, variables, functions) persists between calls — pass \`workdir\` instead of using \`cd\`. Non-zero exits are reported as \`[exit code: N]\`. Current harness environment facts are exposed through managed \`$${DSH_ENV_PREFIX}*\` variables; inspect them when needed. Commands may run under a file sandbox; a blocked file operation is reported as \`[sandbox: file access denied under <mode> mode]\` — a policy denial, not a bug in the command; do not retry another way. Long output is truncated to its tail; the full output is saved to a file whose path is reported when available. ` + background;
|
|
129
247
|
if (escalationModes.length === 0) return base;
|
|
130
248
|
return base + " Attempting a command the sandbox may deny is safe and expected: run it and read the marker rather than assuming the denial. When a command is denied and a wider mode would let it succeed, escalate immediately in the same turn — the one sanctioned exception to a denial: retry the exact same command once with `sandbox_permissions` (the narrowest wider mode that suffices) plus a one-sentence `justification`. Do not detour through chat to ask permission first — the approval prompt raised by that retry is how the user consents. If the session states approval prompts are disabled, there is no exception: a denial is final — do not set `sandbox_permissions`. Never escalate speculatively: ground the request in a real denial — normally the one this command just hit; escalating up front is fine only when this session already denied the same access. A rejected escalation is final for that command — stop and explain, never work around it — but it does not forbid attempting or escalating other commands later.";
|
|
@@ -155,7 +273,9 @@ function presentBashResult(args, result) {
|
|
|
155
273
|
const block = result.content.length === 1 ? result.content[0] : void 0;
|
|
156
274
|
if (block === void 0 || block.type !== "text") return void 0;
|
|
157
275
|
const raw = block.text;
|
|
158
|
-
|
|
276
|
+
const isBackground = typeof args === "object" && args !== null && args.run_in_background === true;
|
|
277
|
+
const isPromoted = result.value?.kind === "promoted";
|
|
278
|
+
if (isBackground || isPromoted || result.isError) return {
|
|
159
279
|
card: "generic",
|
|
160
280
|
content: [{
|
|
161
281
|
type: "text",
|
|
@@ -177,9 +297,9 @@ function presentBashResult(args, result) {
|
|
|
177
297
|
*/
|
|
178
298
|
function resolveWorkdir(modelWorkdir, exec, policyWorkspaceRoot) {
|
|
179
299
|
const headerCwd = exec.agent?.session.header.cwd;
|
|
180
|
-
const sessionCwd = policyWorkspaceRoot ??
|
|
300
|
+
const sessionCwd = policyWorkspaceRoot ?? headerCwd;
|
|
181
301
|
if (modelWorkdir === void 0) return sessionCwd;
|
|
182
|
-
if (sessionCwd !== void 0 && !isAbsolute(modelWorkdir)) return
|
|
302
|
+
if (sessionCwd !== void 0 && !isAbsolute(modelWorkdir)) return `${sessionCwd}${sep}${modelWorkdir}`;
|
|
183
303
|
return modelWorkdir;
|
|
184
304
|
}
|
|
185
305
|
/** Detach the executor DTO from readonly Service Definition types into plain JSON data. */
|
|
@@ -205,6 +325,12 @@ function canonicalBashResult(result) {
|
|
|
205
325
|
} } : {}
|
|
206
326
|
};
|
|
207
327
|
}
|
|
328
|
+
/** The structured abort the foreground paths throw when the caller cancels the call. */
|
|
329
|
+
function toolAborted() {
|
|
330
|
+
const error = new HarnessError("tool call aborted", TOOL_ABORTED);
|
|
331
|
+
error.name = "AbortError";
|
|
332
|
+
return error;
|
|
333
|
+
}
|
|
208
334
|
/** Canonical background-handle properties shared by the bash output union. */
|
|
209
335
|
const BACKGROUND_OUTPUT_PROPERTIES = {
|
|
210
336
|
kind: {
|
|
@@ -219,6 +345,7 @@ const BACKGROUND_OUTPUT_PROPERTIES = {
|
|
|
219
345
|
};
|
|
220
346
|
function apply(ctx, config = {}) {
|
|
221
347
|
const backgroundEnabled = config.enableRunInBackground ?? true;
|
|
348
|
+
const promoteOnTimeout = (config.promoteOnTimeout ?? true) && backgroundEnabled;
|
|
222
349
|
const defaultMode = ctx.shell.sandboxMode;
|
|
223
350
|
const escalationModes = defaultMode === void 0 ? [] : ESCALATION_TARGETS;
|
|
224
351
|
const sandboxPolicy = defaultMode === void 0 ? void 0 : ctx.get("sandboxPolicy");
|
|
@@ -257,193 +384,335 @@ function apply(ctx, config = {}) {
|
|
|
257
384
|
order: ctx.systemPrompt.getSectionOrder("TOOL_BASH"),
|
|
258
385
|
text: `Check the [exit code: N] marker on every ${config.toolName} result; investigate failures before moving on.`
|
|
259
386
|
});
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
387
|
+
/**
|
|
388
|
+
* One registration of the `bash` tool. With a registry, every call
|
|
389
|
+
* registers its process as a job at its start; without one the tool is
|
|
390
|
+
* foreground-only and the executor's deadline kills the command.
|
|
391
|
+
*/
|
|
392
|
+
const bashTool = (jobs) => {
|
|
393
|
+
const background = jobs !== void 0;
|
|
394
|
+
const promote = background && promoteOnTimeout;
|
|
395
|
+
/** Register the command as a job; the process spawns inside the starter, after admission. */
|
|
396
|
+
const startJob = (registry, args, exec, spec) => {
|
|
397
|
+
let proc;
|
|
398
|
+
let stopped;
|
|
399
|
+
return {
|
|
400
|
+
id: registry.start({
|
|
401
|
+
kind: "bash",
|
|
402
|
+
label: args.command,
|
|
403
|
+
...exec.agent ? { owner: exec.agent.id } : {},
|
|
404
|
+
output: processSources(() => proc),
|
|
405
|
+
run: () => {
|
|
406
|
+
const hooks = processJob(async (signal) => {
|
|
407
|
+
proc = await ctx.shell.execute({
|
|
408
|
+
...spec,
|
|
409
|
+
signal
|
|
410
|
+
});
|
|
411
|
+
return proc;
|
|
412
|
+
}, (started) => processOutcome(started, escalationModes));
|
|
413
|
+
return {
|
|
414
|
+
done: hooks.done,
|
|
415
|
+
cancel: (reason) => {
|
|
416
|
+
stopped = reason;
|
|
417
|
+
hooks.cancel(reason);
|
|
418
|
+
}
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
}),
|
|
422
|
+
process: () => proc,
|
|
423
|
+
stopped: () => stopped
|
|
424
|
+
};
|
|
425
|
+
};
|
|
426
|
+
/** Wait on a registered foreground command until it settles or the timeout passes. */
|
|
427
|
+
const waitOnJob = async (registry, attached, exec, spec) => {
|
|
428
|
+
const owner = exec.agent?.id;
|
|
429
|
+
const timeoutMs = spec.timeoutMs;
|
|
430
|
+
/**
|
|
431
|
+
* Stop the job on this call's own account and stay on it until it
|
|
432
|
+
* settles, so the settlement is `awaited` and no completion notice
|
|
433
|
+
* follows a result this call already carries; the record then leaves
|
|
434
|
+
* with the call, as the model never saw the id.
|
|
435
|
+
*/
|
|
436
|
+
const stop = async (reason) => {
|
|
437
|
+
registry.kill(attached.id, owner, reason);
|
|
438
|
+
const settled = await registry.wait(attached.id, timeoutMs, owner);
|
|
439
|
+
if (settled.status !== "running" && settled.status !== "stopping") registry.remove(attached.id, owner);
|
|
440
|
+
return settled;
|
|
441
|
+
};
|
|
442
|
+
let view;
|
|
443
|
+
try {
|
|
444
|
+
view = await registry.wait(attached.id, timeoutMs, owner, exec.signal);
|
|
445
|
+
} catch {
|
|
446
|
+
await stop("tool call aborted");
|
|
447
|
+
throw toolAborted();
|
|
448
|
+
}
|
|
449
|
+
if ((view.status === "running" || view.status === "stopping") && attached.process() === void 0) {
|
|
450
|
+
await stop("timed out during preparation");
|
|
451
|
+
return {
|
|
452
|
+
kind: "foreground",
|
|
453
|
+
exitCode: null,
|
|
454
|
+
signal: null,
|
|
455
|
+
timedOut: true,
|
|
456
|
+
aborted: false,
|
|
457
|
+
timeoutMs,
|
|
458
|
+
stdout: {
|
|
459
|
+
text: "",
|
|
460
|
+
truncated: false
|
|
461
|
+
},
|
|
462
|
+
stderr: {
|
|
463
|
+
text: "",
|
|
464
|
+
truncated: false
|
|
465
|
+
},
|
|
466
|
+
...spec.sandboxPolicy !== void 0 ? { sandbox: {
|
|
467
|
+
mode: spec.sandboxPolicy.mode,
|
|
468
|
+
denied: false
|
|
469
|
+
} } : {}
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
if (view.status === "running" || view.status === "stopping") {
|
|
473
|
+
const read = registry.read(attached.id, owner);
|
|
474
|
+
return {
|
|
475
|
+
kind: "promoted",
|
|
476
|
+
jobId: attached.id,
|
|
477
|
+
timeoutMs,
|
|
478
|
+
output: renderJobRead(ringDelta(read.chunks), read.lossy, read.job.output.spillPaths ?? [], attached.process()?.sandbox, escalationModes)
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
registry.remove(attached.id, owner);
|
|
482
|
+
const process = attached.process();
|
|
483
|
+
if (process === void 0) throw new Error(view.detail);
|
|
484
|
+
const result = await process.result();
|
|
485
|
+
const stopped = attached.stopped();
|
|
486
|
+
return {
|
|
487
|
+
kind: "foreground",
|
|
488
|
+
...canonicalBashResult(result),
|
|
489
|
+
...stopped !== void 0 ? { stopped } : {}
|
|
490
|
+
};
|
|
491
|
+
};
|
|
492
|
+
return defineTool({
|
|
493
|
+
name: config.toolName,
|
|
494
|
+
description: bashDescription(background, escalationModes, promote),
|
|
495
|
+
parameters: {
|
|
496
|
+
command: {
|
|
288
497
|
type: "string",
|
|
289
|
-
|
|
290
|
-
description: "The
|
|
498
|
+
required: true,
|
|
499
|
+
description: "The bash command to execute."
|
|
291
500
|
},
|
|
292
|
-
|
|
501
|
+
description: {
|
|
293
502
|
type: "string",
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
503
|
+
required: true,
|
|
504
|
+
description: "Clear, concise description of what this command does in active voice, 5-10 words (shown in the UI). Examples: \"ls\" → \"List files in current directory\"; \"git status\" → \"Show working tree status\"; \"npm install\" → \"Install package dependencies\"."
|
|
505
|
+
},
|
|
506
|
+
timeoutMs: {
|
|
507
|
+
type: "number",
|
|
508
|
+
description: promote ? "Timeout in milliseconds. The executor applies its configured default and cap; on expiry the command moves to the background as a job instead of being killed." : "Timeout in milliseconds. The executor applies its configured default and cap, and kills the command on expiry."
|
|
509
|
+
},
|
|
510
|
+
workdir: {
|
|
511
|
+
type: "string",
|
|
512
|
+
description: "Working directory for this command. Defaults to the session workspace; a relative path is resolved against it."
|
|
513
|
+
},
|
|
514
|
+
...background ? { run_in_background: {
|
|
515
|
+
type: "boolean",
|
|
516
|
+
description: "Run in the background and return a job id immediately (collect with job_output, stop with job_kill). No timeout applies."
|
|
517
|
+
} } : {},
|
|
518
|
+
...escalationModes.length > 0 ? {
|
|
519
|
+
sandbox_permissions: {
|
|
308
520
|
type: "string",
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
},
|
|
312
|
-
exitCode: {
|
|
313
|
-
required: true,
|
|
314
|
-
oneOf: [{ type: "integer" }, { type: "null" }]
|
|
521
|
+
enum: [...escalationModes],
|
|
522
|
+
description: "The wider sandbox mode this command needs. Only valid as a one-shot retry of a command the sandbox just denied; requires justification and user approval."
|
|
315
523
|
},
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
type: "
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
timeoutMs: {
|
|
329
|
-
type: "number",
|
|
330
|
-
required: true
|
|
524
|
+
justification: {
|
|
525
|
+
type: "string",
|
|
526
|
+
description: "Required with sandbox_permissions: one sentence for the user explaining why this exact command needs the wider access."
|
|
527
|
+
}
|
|
528
|
+
} : {}
|
|
529
|
+
},
|
|
530
|
+
output: {
|
|
531
|
+
schema: { oneOf: [
|
|
532
|
+
{
|
|
533
|
+
type: "object",
|
|
534
|
+
additionalProperties: false,
|
|
535
|
+
properties: BACKGROUND_OUTPUT_PROPERTIES
|
|
331
536
|
},
|
|
332
|
-
|
|
537
|
+
{
|
|
333
538
|
type: "object",
|
|
334
539
|
additionalProperties: false,
|
|
335
|
-
required: true,
|
|
336
540
|
properties: {
|
|
337
|
-
|
|
541
|
+
kind: {
|
|
542
|
+
type: "string",
|
|
543
|
+
required: true,
|
|
544
|
+
const: "promoted"
|
|
545
|
+
},
|
|
546
|
+
jobId: {
|
|
338
547
|
type: "string",
|
|
339
548
|
required: true
|
|
340
549
|
},
|
|
341
|
-
|
|
342
|
-
type: "
|
|
550
|
+
timeoutMs: {
|
|
551
|
+
type: "number",
|
|
343
552
|
required: true
|
|
344
553
|
},
|
|
345
|
-
|
|
554
|
+
output: {
|
|
555
|
+
type: "string",
|
|
556
|
+
required: true
|
|
557
|
+
}
|
|
346
558
|
}
|
|
347
559
|
},
|
|
348
|
-
|
|
560
|
+
{
|
|
349
561
|
type: "object",
|
|
350
562
|
additionalProperties: false,
|
|
351
|
-
required: true,
|
|
352
563
|
properties: {
|
|
353
|
-
|
|
564
|
+
kind: {
|
|
354
565
|
type: "string",
|
|
355
|
-
required: true
|
|
566
|
+
required: true,
|
|
567
|
+
const: "foreground"
|
|
568
|
+
},
|
|
569
|
+
exitCode: {
|
|
570
|
+
required: true,
|
|
571
|
+
oneOf: [{ type: "integer" }, { type: "null" }]
|
|
572
|
+
},
|
|
573
|
+
signal: {
|
|
574
|
+
required: true,
|
|
575
|
+
oneOf: [{ type: "string" }, { type: "null" }]
|
|
356
576
|
},
|
|
357
|
-
|
|
577
|
+
timedOut: {
|
|
358
578
|
type: "boolean",
|
|
359
579
|
required: true
|
|
360
580
|
},
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
},
|
|
364
|
-
sandbox: {
|
|
365
|
-
type: "object",
|
|
366
|
-
additionalProperties: false,
|
|
367
|
-
properties: {
|
|
368
|
-
mode: {
|
|
369
|
-
type: "string",
|
|
581
|
+
aborted: {
|
|
582
|
+
type: "boolean",
|
|
370
583
|
required: true
|
|
371
584
|
},
|
|
372
|
-
|
|
373
|
-
|
|
585
|
+
stopped: { type: "string" },
|
|
586
|
+
timeoutMs: {
|
|
587
|
+
type: "number",
|
|
374
588
|
required: true
|
|
375
589
|
},
|
|
376
|
-
|
|
377
|
-
|
|
590
|
+
stdout: {
|
|
591
|
+
type: "object",
|
|
592
|
+
additionalProperties: false,
|
|
593
|
+
required: true,
|
|
594
|
+
properties: {
|
|
595
|
+
text: {
|
|
596
|
+
type: "string",
|
|
597
|
+
required: true
|
|
598
|
+
},
|
|
599
|
+
truncated: {
|
|
600
|
+
type: "boolean",
|
|
601
|
+
required: true
|
|
602
|
+
},
|
|
603
|
+
spillPath: { type: "string" }
|
|
604
|
+
}
|
|
605
|
+
},
|
|
606
|
+
stderr: {
|
|
607
|
+
type: "object",
|
|
608
|
+
additionalProperties: false,
|
|
609
|
+
required: true,
|
|
610
|
+
properties: {
|
|
611
|
+
text: {
|
|
612
|
+
type: "string",
|
|
613
|
+
required: true
|
|
614
|
+
},
|
|
615
|
+
truncated: {
|
|
616
|
+
type: "boolean",
|
|
617
|
+
required: true
|
|
618
|
+
},
|
|
619
|
+
spillPath: { type: "string" }
|
|
620
|
+
}
|
|
621
|
+
},
|
|
622
|
+
sandbox: {
|
|
623
|
+
type: "object",
|
|
624
|
+
additionalProperties: false,
|
|
625
|
+
properties: {
|
|
626
|
+
mode: {
|
|
627
|
+
type: "string",
|
|
628
|
+
required: true
|
|
629
|
+
},
|
|
630
|
+
denied: {
|
|
631
|
+
type: "boolean",
|
|
632
|
+
required: true
|
|
633
|
+
},
|
|
634
|
+
enforcement: { type: "string" },
|
|
635
|
+
runnerFailed: { type: "boolean" }
|
|
636
|
+
}
|
|
637
|
+
}
|
|
378
638
|
}
|
|
379
639
|
}
|
|
640
|
+
] },
|
|
641
|
+
render: (_args, value) => [{
|
|
642
|
+
type: "text",
|
|
643
|
+
text: value.kind === "background" ? `started background job ${value.jobId}` : value.kind === "promoted" ? renderPromoted(value) : renderResult(value, escalationModes)
|
|
644
|
+
}]
|
|
645
|
+
},
|
|
646
|
+
async execute(args, exec) {
|
|
647
|
+
const standingPolicy = resolveSandboxPolicy(exec);
|
|
648
|
+
validateBashArgs(args, standingPolicy?.mode);
|
|
649
|
+
const approvedMode = args.sandbox_permissions !== void 0 && args.justification !== void 0 ? await approveBashEscalation(args.sandbox_permissions, args.justification, exec, standingPolicy) : void 0;
|
|
650
|
+
const policy = approvedMode === void 0 ? standingPolicy : {
|
|
651
|
+
...standingPolicy,
|
|
652
|
+
mode: approvedMode
|
|
653
|
+
};
|
|
654
|
+
const workdir = resolveWorkdir(args.workdir, exec, standingPolicy?.workspaceRoot);
|
|
655
|
+
const dshEnv = ctx.shellEnv.collect(exec);
|
|
656
|
+
const request = {
|
|
657
|
+
command: args.command,
|
|
658
|
+
...workdir !== void 0 ? { workdir } : {},
|
|
659
|
+
...args.timeoutMs !== void 0 ? { timeoutMs: args.timeoutMs } : {},
|
|
660
|
+
dshEnv,
|
|
661
|
+
...policy !== void 0 ? { sandboxPolicy: policy } : {}
|
|
662
|
+
};
|
|
663
|
+
if (args.run_in_background === true) {
|
|
664
|
+
if (!backgroundEnabled) throw new Error("run_in_background is disabled for this deployment (enableRunInBackground: false)");
|
|
665
|
+
if (jobs === void 0) throw new Error("background jobs unavailable: load @deepseek-ai/dsh-jobs and @deepseek-ai/dsh-tool-jobs");
|
|
666
|
+
if (exec.signal.aborted) throw toolAborted();
|
|
667
|
+
return {
|
|
668
|
+
kind: "background",
|
|
669
|
+
jobId: startJob(jobs, args, exec, ctx.shell.resolve({
|
|
670
|
+
...request,
|
|
671
|
+
onExpiry: "none"
|
|
672
|
+
})).id
|
|
673
|
+
};
|
|
380
674
|
}
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
mode: approvedMode
|
|
394
|
-
};
|
|
395
|
-
const workdir = resolveWorkdir(args.workdir, exec, standingPolicy?.workspaceRoot);
|
|
396
|
-
const dshEnv = ctx.shellEnv.collect(exec);
|
|
397
|
-
const request = {
|
|
398
|
-
command: args.command,
|
|
399
|
-
...workdir !== void 0 ? { workdir } : {},
|
|
400
|
-
...args.timeoutMs !== void 0 ? { timeoutMs: args.timeoutMs } : {},
|
|
401
|
-
dshEnv,
|
|
402
|
-
...policy !== void 0 ? { sandboxPolicy: policy } : {}
|
|
403
|
-
};
|
|
404
|
-
if (args.run_in_background === true) {
|
|
405
|
-
if (!backgroundEnabled) throw new Error("run_in_background is disabled for this deployment (enableRunInBackground: false)");
|
|
406
|
-
const jobs = ctx.get("jobs");
|
|
407
|
-
if (jobs === void 0) throw new Error("background jobs unavailable: load @deepseek-ai/dsh-jobs and @deepseek-ai/dsh-tool-jobs");
|
|
408
|
-
if (exec.signal.aborted) {
|
|
409
|
-
const error = new HarnessError("tool call aborted", TOOL_ABORTED);
|
|
410
|
-
error.name = "AbortError";
|
|
411
|
-
throw error;
|
|
675
|
+
if (jobs !== void 0 && promote) {
|
|
676
|
+
const spec = ctx.shell.resolve({
|
|
677
|
+
...request,
|
|
678
|
+
onExpiry: "none"
|
|
679
|
+
});
|
|
680
|
+
let attached;
|
|
681
|
+
try {
|
|
682
|
+
attached = startJob(jobs, args, exec, spec);
|
|
683
|
+
} catch (error) {
|
|
684
|
+
ctx.logger.warn(`bash: job registration refused, running in the foreground with the timeout kill instead: ${String(error)}`);
|
|
685
|
+
}
|
|
686
|
+
if (attached !== void 0) return waitOnJob(jobs, attached, exec, spec);
|
|
412
687
|
}
|
|
688
|
+
const result = await (await ctx.shell.execute(ctx.shell.resolve({
|
|
689
|
+
...request,
|
|
690
|
+
signal: exec.signal
|
|
691
|
+
}))).result();
|
|
692
|
+
if (result.aborted) throw toolAborted();
|
|
413
693
|
return {
|
|
414
|
-
kind: "
|
|
415
|
-
|
|
416
|
-
kind: "bash",
|
|
417
|
-
label: args.command,
|
|
418
|
-
...exec.agent ? { owner: exec.agent } : {},
|
|
419
|
-
run: () => {
|
|
420
|
-
const proc = ctx.shell.start(ctx.shell.resolve(request));
|
|
421
|
-
return {
|
|
422
|
-
cancel: () => void proc.kill(),
|
|
423
|
-
done: proc.done.then(() => processOutcome(proc)),
|
|
424
|
-
readOutput: () => renderProcessRead(proc.readOutput(), proc.sandbox, escalationModes)
|
|
425
|
-
};
|
|
426
|
-
}
|
|
427
|
-
})
|
|
694
|
+
kind: "foreground",
|
|
695
|
+
...canonicalBashResult(result)
|
|
428
696
|
};
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
697
|
+
},
|
|
698
|
+
presentCall: presentBashCall,
|
|
699
|
+
presentResult: presentBashResult
|
|
700
|
+
});
|
|
701
|
+
};
|
|
702
|
+
if (!backgroundEnabled) {
|
|
703
|
+
ctx.tools.register(bashTool(void 0));
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
706
|
+
let foregroundOnly = ctx.get("jobs") === void 0 ? ctx.tools.register(bashTool(void 0)) : void 0;
|
|
707
|
+
ctx.inject(["jobs"], (jobCtx) => {
|
|
708
|
+
foregroundOnly?.();
|
|
709
|
+
foregroundOnly = void 0;
|
|
710
|
+
const unregister = ctx.tools.register(bashTool(jobCtx.jobs));
|
|
711
|
+
jobCtx.effect(() => () => {
|
|
712
|
+
unregister();
|
|
713
|
+
if (ctx.fiber.state === 2) foregroundOnly = ctx.tools.register(bashTool(void 0));
|
|
714
|
+
});
|
|
715
|
+
});
|
|
447
716
|
}
|
|
448
717
|
//#endregion
|
|
449
718
|
export { Config, apply, inject, name };
|