dsh-plugin-wsl-env 0.7.5 → 0.8.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 +278 -0
- package/CONTRIBUTING.md +129 -39
- package/README.md +20 -20
- package/docs/ARCHITECTURE.md +6 -3
- package/docs/LIMITATIONS.md +13 -0
- package/docs/README.zh.md +20 -20
- package/lib/agent-confined.d.ts +42 -0
- package/lib/agent-confined.js +25 -41
- package/lib/agent-errors.d.ts +31 -0
- package/lib/agent-errors.js +19 -16
- package/lib/agent-exec.d.ts +159 -0
- package/lib/agent-exec.js +151 -165
- package/lib/agent-protocol.d.ts +192 -0
- package/lib/agent-protocol.js +76 -100
- package/lib/agent-shared.d.ts +27 -0
- package/lib/agent-shared.js +12 -12
- package/lib/agent.d.ts +353 -0
- package/lib/agent.js +536 -552
- package/lib/auto-preset.d.ts +110 -0
- package/lib/auto-preset.js +157 -141
- package/lib/bwrap.d.ts +90 -0
- package/lib/bwrap.js +18 -18
- package/lib/file-reference-wsl.d.ts +160 -0
- package/lib/file-reference-wsl.js +192 -173
- package/lib/fs-decisions.d.ts +107 -0
- package/lib/fs-decisions.js +64 -60
- package/lib/fs-routing.d.ts +182 -0
- package/lib/fs-routing.js +173 -116
- package/lib/fs-substrate.d.ts +258 -0
- package/lib/fs-substrate.js +248 -248
- package/lib/fs.d.ts +10 -0
- package/lib/fs.js +5 -0
- package/lib/fsio-agent.d.ts +307 -0
- package/lib/fsio-agent.js +414 -410
- package/lib/fsio-text.d.ts +115 -0
- package/lib/fsio-text.js +104 -84
- package/lib/git-route.d.ts +100 -0
- package/lib/git-route.js +46 -47
- package/lib/index.d.ts +1003 -0
- package/lib/index.js +1101 -1003
- package/lib/listing.d.ts +114 -0
- package/lib/listing.js +68 -55
- package/lib/paths.d.ts +182 -0
- package/lib/paths.js +134 -109
- package/lib/picker.d.ts +266 -0
- package/lib/picker.js +371 -351
- package/lib/ports.d.ts +44 -0
- package/lib/ports.js +39 -29
- package/lib/preset-choice.d.ts +33 -0
- package/lib/preset-choice.js +15 -7
- package/lib/probe-cache.d.ts +40 -0
- package/lib/probe-cache.js +35 -29
- package/lib/sandbox-core.d.ts +79 -0
- package/lib/sandbox-core.js +71 -88
- package/lib/sandbox.d.ts +48 -0
- package/lib/sandbox.js +4 -4
- package/lib/search-exec.d.ts +96 -0
- package/lib/search-exec.js +52 -79
- package/lib/search-route.d.ts +75 -0
- package/lib/search-route.js +30 -31
- package/lib/shell-env.d.ts +88 -0
- package/lib/shell-env.js +78 -74
- package/lib/shell.d.ts +10 -0
- package/lib/shell.js +5 -0
- package/lib/subprocess.d.ts +313 -0
- package/lib/subprocess.js +267 -262
- package/lib/terminal-activity.d.ts +98 -0
- package/lib/terminal-activity.js +29 -39
- package/lib/terminal-route.d.ts +27 -0
- package/lib/terminal-route.js +16 -8
- package/lib/watcher.d.ts +77 -0
- package/lib/watcher.js +120 -126
- package/lib/workspace-files-route.d.ts +132 -0
- package/lib/workspace-files-route.js +73 -81
- package/lib/workspace-files-wsl.d.ts +257 -0
- package/lib/workspace-files-wsl.js +311 -251
- package/lib/wsl.d.ts +266 -0
- package/lib/wsl.js +144 -155
- package/package.json +68 -20
package/lib/shell-env.js
CHANGED
|
@@ -20,90 +20,94 @@
|
|
|
20
20
|
* directory. A session whose workspace is inside a distro is exactly a session
|
|
21
21
|
* whose shell calls run in that distro — so a host session sees none of these.
|
|
22
22
|
*
|
|
23
|
+
* This is a TypeScript source built to `lib/shell-env.js`; edit THIS file and
|
|
24
|
+
* run `pnpm run build` — the artifact under `lib/` is generated, and `pnpm test`
|
|
25
|
+
* fails when it drifts.
|
|
26
|
+
*
|
|
23
27
|
* @module dsh-plugin-wsl/shell-env
|
|
24
28
|
*/
|
|
25
|
-
|
|
26
29
|
import z from "@deepseek-ai/schemastery";
|
|
27
30
|
import { isAnotherDistrosUnc, isWslUnc } from "./paths.js";
|
|
28
31
|
import { defaultDistro, defaultShell, linuxHomePath } from "./wsl.js";
|
|
29
32
|
import { sharedAgent } from "./agent-shared.js";
|
|
30
33
|
import { listeningPorts } from "./ports.js";
|
|
31
|
-
|
|
32
34
|
export const name = "wsl-shell-env";
|
|
33
|
-
|
|
34
35
|
export const inject = ["shellEnv"];
|
|
35
|
-
|
|
36
36
|
export const Config = z.object({
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
/** Distro these facts describe; empty means this machine's default distro. */
|
|
38
|
+
distro: z.string().default(""),
|
|
39
|
+
/** How often the listening-port snapshot refreshes, in milliseconds. */
|
|
40
|
+
portsRefreshMs: z.number().default(10 * 1000),
|
|
41
41
|
});
|
|
42
|
-
|
|
42
|
+
/**
|
|
43
|
+
* Contribute the WSL environment's facts to the shell-env registry.
|
|
44
|
+
*
|
|
45
|
+
* @param ctx - the cordis context.
|
|
46
|
+
* @param config - the schema-validated plugin config.
|
|
47
|
+
*/
|
|
43
48
|
export async function apply(ctx, config = {}) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
});
|
|
49
|
+
// `resolve` is called synchronously by the registry (`Object.entries` of its
|
|
50
|
+
// result), so every fact has to be resolved up front, not per call.
|
|
51
|
+
const configured = config.distro ?? "";
|
|
52
|
+
const distro = configured.length > 0 ? configured : await defaultDistro();
|
|
53
|
+
// undefined when both probes failed (a cold distro): the fact is then
|
|
54
|
+
// simply absent, which beats presenting the "bash" placeholder as the
|
|
55
|
+
// distro's login shell for this process's lifetime.
|
|
56
|
+
const shell = await defaultShell(distro);
|
|
57
|
+
// The consumer is a shell running INSIDE the distro, so the fact is the POSIX
|
|
58
|
+
// path, not the host-side world path.
|
|
59
|
+
const home = await linuxHomePath(distro);
|
|
60
|
+
const variables = {
|
|
61
|
+
DSH_WSL_DISTRO: {
|
|
62
|
+
description: `Name of the WSL distro this workspace lives in (${distro}).`,
|
|
63
|
+
},
|
|
64
|
+
DSH_WSL_SHELL: {
|
|
65
|
+
description: `Absolute path of the login shell that model shell calls run in inside ${distro}. Commands are executed by this shell, not by bash.`,
|
|
66
|
+
},
|
|
67
|
+
DSH_WSL_HOME: {
|
|
68
|
+
description: `Home directory of the user model shell calls run as inside ${distro}.`,
|
|
69
|
+
},
|
|
70
|
+
DSH_WSL_PORTS: {
|
|
71
|
+
description: `Ports with a listener inside ${distro} (comma-separated, ascending), as of the last snapshot — refreshed every ${Math.round(config.portsRefreshMs / 1000)}s, so a dev server started moments ago may not be listed yet. Empty means none were listening at the last scan.`,
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
// The port snapshot refreshes on a timer and is served synchronously: the
|
|
75
|
+
// registry's resolve is sync by contract, so live reads are impossible —
|
|
76
|
+
// the timer bounds staleness instead (see lib/ports.js).
|
|
77
|
+
let ports = [];
|
|
78
|
+
const refreshPorts = async () => {
|
|
79
|
+
ports = await listeningPorts(sharedAgent(distro), 8000);
|
|
80
|
+
};
|
|
81
|
+
void refreshPorts();
|
|
82
|
+
const portsTimer = setInterval(() => void refreshPorts(), config.portsRefreshMs);
|
|
83
|
+
portsTimer.unref?.();
|
|
84
|
+
const dispose = ctx.shellEnv.register({
|
|
85
|
+
name: "dsh-plugin-wsl-env",
|
|
86
|
+
variables,
|
|
87
|
+
resolve: (execution) => {
|
|
88
|
+
const cwd = execution?.agent?.session?.header?.cwd;
|
|
89
|
+
if (cwd === undefined || !isWslUnc(cwd))
|
|
90
|
+
return {};
|
|
91
|
+
// The facts describe ONE distro. A workspace under another distro's UNC
|
|
92
|
+
// is not that distro — the shell refuses its commands outright (the
|
|
93
|
+
// cross-distro guard) — so the honest resolution is no facts at all,
|
|
94
|
+
// not another distro's home and shell presented as this session's.
|
|
95
|
+
if (isAnotherDistrosUnc(cwd, distro))
|
|
96
|
+
return {};
|
|
97
|
+
const facts = {
|
|
98
|
+
DSH_WSL_DISTRO: distro,
|
|
99
|
+
DSH_WSL_HOME: home,
|
|
100
|
+
DSH_WSL_PORTS: ports.join(","),
|
|
101
|
+
};
|
|
102
|
+
if (shell !== undefined)
|
|
103
|
+
facts.DSH_WSL_SHELL = shell;
|
|
104
|
+
return facts;
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
// Disposing matters: a config hot-reload re-runs apply(), and the registry
|
|
108
|
+
// rejects a second contributor claiming the same keys.
|
|
109
|
+
ctx.effect(() => () => {
|
|
110
|
+
clearInterval(portsTimer);
|
|
111
|
+
dispose();
|
|
112
|
+
});
|
|
109
113
|
}
|
package/lib/shell.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ctx.shell` entrypoint — load as `dsh-plugin-wsl` in a profile patch.
|
|
3
|
+
*
|
|
4
|
+
* This is a TypeScript source built to `lib/shell.js`; edit THIS file and run
|
|
5
|
+
* `pnpm run build` — the artifact under `lib/` is generated, and `pnpm test`
|
|
6
|
+
* fails when it drifts.
|
|
7
|
+
*
|
|
8
|
+
* @module dsh-plugin-wsl/shell
|
|
9
|
+
*/
|
|
10
|
+
export { WslShellExecutor as default, WslShellExecutor } from "./index.js";
|
package/lib/shell.js
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `ctx.shell` entrypoint — load as `dsh-plugin-wsl` in a profile patch.
|
|
3
|
+
*
|
|
4
|
+
* This is a TypeScript source built to `lib/shell.js`; edit THIS file and run
|
|
5
|
+
* `pnpm run build` — the artifact under `lib/` is generated, and `pnpm test`
|
|
6
|
+
* fails when it drifts.
|
|
7
|
+
*
|
|
3
8
|
* @module dsh-plugin-wsl/shell
|
|
4
9
|
*/
|
|
5
10
|
export { WslShellExecutor as default, WslShellExecutor } from "./index.js";
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ctx.subprocess` entrypoint — the WSL execution world behind the GUI's
|
|
3
|
+
* terminal window.
|
|
4
|
+
*
|
|
5
|
+
* ## Why this seam, and not `ctx.terminals`
|
|
6
|
+
*
|
|
7
|
+
* `ctx.terminals` (`@deepseek-ai/dsh-terminal` + `dsh-terminal-bash`) is the
|
|
8
|
+
* *model-facing* persistent-terminal service. The right-hand terminal window is
|
|
9
|
+
* a different subsystem: its host half is
|
|
10
|
+
* `@deepseek-ai/dsh-api-terminal-controller`, mounted once by the Web bundle,
|
|
11
|
+
* and it resolves the execution environment of the Session it serves with
|
|
12
|
+
*
|
|
13
|
+
* execution(agent) {
|
|
14
|
+
* const subprocess = agent.ctx.get("subprocess");
|
|
15
|
+
* const sandboxPolicy = agent.ctx.get("sandboxPolicy");
|
|
16
|
+
* ...
|
|
17
|
+
* }
|
|
18
|
+
*
|
|
19
|
+
* ## Why a preset-scoped provider cannot serve it
|
|
20
|
+
*
|
|
21
|
+
* The obvious design — mount this provider in the `wsl` preset's isolate realm
|
|
22
|
+
* next to `shell` and `fs` — does not work, and the reason is worth recording
|
|
23
|
+
* because it is invisible from the profile YAML:
|
|
24
|
+
*
|
|
25
|
+
* - A preset's isolate realms are created by `dsh-agent-preset-registry`
|
|
26
|
+
* under the registry's **own** context:
|
|
27
|
+
* `createScope(this.owner, key)` → `mountPreset(scope.ctx…)`.
|
|
28
|
+
* - An Agent's context is a **parallel branch** created by the agent loop:
|
|
29
|
+
* `this.scope = createScope(loopCtx, this); this.ctx = this.scope.ctx`,
|
|
30
|
+
* where `loopCtx` is the root-mounted `ctx.agents` service context.
|
|
31
|
+
* `createScope` only wraps a Cordis plugin and tags a scope key; it neither
|
|
32
|
+
* touches `Context.isolate` nor passes through a loader entry, so the
|
|
33
|
+
* agent's isolate map still resolves every service to the root realm.
|
|
34
|
+
*
|
|
35
|
+
* So `agent.ctx.get("subprocess")` always finds the **composition-level**
|
|
36
|
+
* provider, whatever the agent's preset isolates. The shipped registry provides
|
|
37
|
+
* `agentPresets.serviceFor(agent, name)` for exactly this gap, and the terminal
|
|
38
|
+
* controller does not use it. (`shell` and `fs` are unaffected: the model-facing
|
|
39
|
+
* tools live *inside* the preset tree, so their own contexts do resolve the
|
|
40
|
+
* realm.)
|
|
41
|
+
*
|
|
42
|
+
* ## What this provider therefore changes
|
|
43
|
+
*
|
|
44
|
+
* It replaces the shipped `subprocess` row at the composition level and
|
|
45
|
+
* overrides two methods. `spawnTerminal` rewrites a `wsl.exe` launch into a
|
|
46
|
+
* launch that actually names the distro and the Session workspace's Linux
|
|
47
|
+
* directory. `spawn` rewrites one further launch — the file-search tool's
|
|
48
|
+
* packaged ripgrep binary, which a distro workspace's UNC working directory
|
|
49
|
+
* names outright — into the distro's own rg: agent-first, one round trip on
|
|
50
|
+
* the warm resident, with the one-shot `wsl.exe --exec` handle as the
|
|
51
|
+
* documented fallback when the agent is out (`lib/search-route.js` holds the
|
|
52
|
+
* decision, `lib/search-exec.js` the handle). Every other request —
|
|
53
|
+
* including every other `spawn()`, which the command path uses for
|
|
54
|
+
* `wsl.exe -lc <command>` — reaches the shipped implementation untouched.
|
|
55
|
+
*
|
|
56
|
+
* The interpreter, the PTY, output handling and process-tree teardown stay the
|
|
57
|
+
* shipped implementation's, so the blast radius of replacing a root service
|
|
58
|
+
* stays at the two things that were wrong: the directory and distro a terminal
|
|
59
|
+
* starts in, and the filesystem a search walks.
|
|
60
|
+
*
|
|
61
|
+
* ## What the operator must pair it with
|
|
62
|
+
*
|
|
63
|
+
* `terminalEnvironment()` and `resolveExecutable()` are also resolved from the
|
|
64
|
+
* root realm, and neither receives a Session or a directory, so this provider
|
|
65
|
+
* deliberately leaves them alone: rewriting them would change executable lookup
|
|
66
|
+
* for every other root consumer (the pwsh executor, the LSP host, the file
|
|
67
|
+
* search) to make the *shell menu* of one window prettier. The profile instead
|
|
68
|
+
* configures the terminal controller with the single shell profile that matters:
|
|
69
|
+
* `shell: { path: wsl.exe, name: WSL }` and `shellCandidates: []`.
|
|
70
|
+
*
|
|
71
|
+
* Consequence worth stating plainly: the terminal is a property of the
|
|
72
|
+
* composition, not of the Session. A Session whose workspace is a Windows folder
|
|
73
|
+
* gets the same terminal, with that folder mounted at `/mnt/<drive>/…`.
|
|
74
|
+
*
|
|
75
|
+
* This is a TypeScript source built to `lib/subprocess.js`; edit THIS file and
|
|
76
|
+
* run `pnpm run build` — the artifact under `lib/` is generated, and `pnpm test`
|
|
77
|
+
* fails when it drifts.
|
|
78
|
+
*
|
|
79
|
+
* @module dsh-plugin-wsl/subprocess
|
|
80
|
+
*/
|
|
81
|
+
import z from "@deepseek-ai/schemastery";
|
|
82
|
+
import { LocalSubprocessRuntime } from "@deepseek-ai/dsh-subprocess-local";
|
|
83
|
+
import type { Context } from "@deepseek-ai/cordis";
|
|
84
|
+
import type { SubprocessHandle, SubprocessSpawnSpec, SubprocessTerminalHandle, SubprocessTerminalSpawnSpec } from "@deepseek-ai/dsh-subprocess";
|
|
85
|
+
import type { SubprocessTerminalActivity } from "./terminal-activity.js";
|
|
86
|
+
/**
|
|
87
|
+
* The static Config schema's validated output. Every defaulted field is
|
|
88
|
+
* present after validation; `hostCwd` is the volatile accessor the schema
|
|
89
|
+
* builds.
|
|
90
|
+
*/
|
|
91
|
+
export interface WslSubprocessConfig {
|
|
92
|
+
/** Distro name; empty means WSL's own default distro. */
|
|
93
|
+
distro: string;
|
|
94
|
+
/** Path to `wsl.exe`. */
|
|
95
|
+
wslPath: string;
|
|
96
|
+
/** A shell to pin inside the distro, as an absolute Linux path. */
|
|
97
|
+
shell: string;
|
|
98
|
+
/** Login-shell semantics for a pinned shell. */
|
|
99
|
+
loginShell: boolean;
|
|
100
|
+
/** Fallback directory when a launch names none. */
|
|
101
|
+
cwd: string;
|
|
102
|
+
/** Windows directory the `wsl.exe` process itself starts in. */
|
|
103
|
+
hostCwd: {
|
|
104
|
+
get: () => string | undefined;
|
|
105
|
+
};
|
|
106
|
+
/** Extra env names to forward into the distro through WSLENV. */
|
|
107
|
+
forwardEnv: string[];
|
|
108
|
+
/** Whether a session on a Windows folder gets a host shell. */
|
|
109
|
+
hostSessions: boolean;
|
|
110
|
+
/** Whether the controller may reclaim an idle distro terminal. */
|
|
111
|
+
terminalIdleReclaim: boolean;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Subprocess provider that serves a WSL distro as the composition's terminal
|
|
115
|
+
* execution world.
|
|
116
|
+
*
|
|
117
|
+
* Mount it at the profile root in place of the shipped local provider (the
|
|
118
|
+
* profile patch disables the `subprocess` row and inserts this one). It is a
|
|
119
|
+
* subclass rather than a wrapper, so every method it does not override is
|
|
120
|
+
* literally the shipped implementation.
|
|
121
|
+
*/
|
|
122
|
+
export declare class WslSubprocessRuntime extends LocalSubprocessRuntime {
|
|
123
|
+
static Config: z<Schemastery.ObjectS<NoInfer<{
|
|
124
|
+
/** Distro name; empty means WSL's own default distro. */
|
|
125
|
+
distro: z<string, string, "defined">;
|
|
126
|
+
/** Path to `wsl.exe`; overridable for a non-standard install. */
|
|
127
|
+
wslPath: z<string, string, "defined">;
|
|
128
|
+
/**
|
|
129
|
+
* A shell to pin inside the distro, as an absolute Linux path. Empty — the
|
|
130
|
+
* default — leaves the choice to `wsl.exe`, which starts the distro user's
|
|
131
|
+
* login shell exactly as an interactive `wsl.exe` does.
|
|
132
|
+
*/
|
|
133
|
+
shell: z<string, string, "defined">;
|
|
134
|
+
/**
|
|
135
|
+
* Login-shell semantics for a pinned shell. Ignored when no shell is pinned,
|
|
136
|
+
* because then the login shell is the shell.
|
|
137
|
+
*/
|
|
138
|
+
loginShell: z<boolean, boolean, "defined">;
|
|
139
|
+
/** Fallback directory when a launch names none; accepts any coordinate system. */
|
|
140
|
+
cwd: z<string, string, "defined">;
|
|
141
|
+
/** Windows directory the `wsl.exe` process itself starts in. */
|
|
142
|
+
hostCwd: z<string, string, "volatile">;
|
|
143
|
+
/** Extra env names to forward into the distro through WSLENV. */
|
|
144
|
+
forwardEnv: z<string[], string[], "defined">;
|
|
145
|
+
/**
|
|
146
|
+
* Give a session opened on a WINDOWS folder a host shell instead of the
|
|
147
|
+
* distro's shell started at `/mnt/<drive>/…`. WSL-folder sessions always
|
|
148
|
+
* get the distro shell — that is this provider's purpose. `false` restores
|
|
149
|
+
* the composition-owned terminal for every session.
|
|
150
|
+
*/
|
|
151
|
+
hostSessions: z<boolean, boolean, "defined">;
|
|
152
|
+
/**
|
|
153
|
+
* Let the controller reclaim an idle distro terminal. The terminal is
|
|
154
|
+
* marked at launch (`DSH_TERMINAL_ID` through the existing `WSLENV`
|
|
155
|
+
* forwarding) and its handle's `inspectActivity` is replaced with a
|
|
156
|
+
* distro-side observation: the resident agent scans `/proc` for the
|
|
157
|
+
* marker — a shell with live children is busy, a shell without children
|
|
158
|
+
* is idle. The shipped observation can only answer `unknown` for a distro
|
|
159
|
+
* terminal, and `unknown` never accumulates idle, which is why these
|
|
160
|
+
* terminals had to be closed by hand. When the agent is out the
|
|
161
|
+
* observation answers `unknown` (no reclaim) — a probe that cannot answer
|
|
162
|
+
* must not authorize a close. `false` restores that posture.
|
|
163
|
+
*/
|
|
164
|
+
terminalIdleReclaim: z<boolean, boolean, "defined">;
|
|
165
|
+
}>>, Schemastery.ObjectT<NoInfer<{
|
|
166
|
+
/** Distro name; empty means WSL's own default distro. */
|
|
167
|
+
distro: z<string, string, "defined">;
|
|
168
|
+
/** Path to `wsl.exe`; overridable for a non-standard install. */
|
|
169
|
+
wslPath: z<string, string, "defined">;
|
|
170
|
+
/**
|
|
171
|
+
* A shell to pin inside the distro, as an absolute Linux path. Empty — the
|
|
172
|
+
* default — leaves the choice to `wsl.exe`, which starts the distro user's
|
|
173
|
+
* login shell exactly as an interactive `wsl.exe` does.
|
|
174
|
+
*/
|
|
175
|
+
shell: z<string, string, "defined">;
|
|
176
|
+
/**
|
|
177
|
+
* Login-shell semantics for a pinned shell. Ignored when no shell is pinned,
|
|
178
|
+
* because then the login shell is the shell.
|
|
179
|
+
*/
|
|
180
|
+
loginShell: z<boolean, boolean, "defined">;
|
|
181
|
+
/** Fallback directory when a launch names none; accepts any coordinate system. */
|
|
182
|
+
cwd: z<string, string, "defined">;
|
|
183
|
+
/** Windows directory the `wsl.exe` process itself starts in. */
|
|
184
|
+
hostCwd: z<string, string, "volatile">;
|
|
185
|
+
/** Extra env names to forward into the distro through WSLENV. */
|
|
186
|
+
forwardEnv: z<string[], string[], "defined">;
|
|
187
|
+
/**
|
|
188
|
+
* Give a session opened on a WINDOWS folder a host shell instead of the
|
|
189
|
+
* distro's shell started at `/mnt/<drive>/…`. WSL-folder sessions always
|
|
190
|
+
* get the distro shell — that is this provider's purpose. `false` restores
|
|
191
|
+
* the composition-owned terminal for every session.
|
|
192
|
+
*/
|
|
193
|
+
hostSessions: z<boolean, boolean, "defined">;
|
|
194
|
+
/**
|
|
195
|
+
* Let the controller reclaim an idle distro terminal. The terminal is
|
|
196
|
+
* marked at launch (`DSH_TERMINAL_ID` through the existing `WSLENV`
|
|
197
|
+
* forwarding) and its handle's `inspectActivity` is replaced with a
|
|
198
|
+
* distro-side observation: the resident agent scans `/proc` for the
|
|
199
|
+
* marker — a shell with live children is busy, a shell without children
|
|
200
|
+
* is idle. The shipped observation can only answer `unknown` for a distro
|
|
201
|
+
* terminal, and `unknown` never accumulates idle, which is why these
|
|
202
|
+
* terminals had to be closed by hand. When the agent is out the
|
|
203
|
+
* observation answers `unknown` (no reclaim) — a probe that cannot answer
|
|
204
|
+
* must not authorize a close. `false` restores that posture.
|
|
205
|
+
*/
|
|
206
|
+
terminalIdleReclaim: z<boolean, boolean, "defined">;
|
|
207
|
+
}>>, "plain">;
|
|
208
|
+
/** The schema-validated config. */
|
|
209
|
+
config: WslSubprocessConfig;
|
|
210
|
+
/** Cached default distro, resolved once from `wsl.exe -l -q`. */
|
|
211
|
+
resolvedDistro: string;
|
|
212
|
+
/**
|
|
213
|
+
* @param ctx - the cordis context.
|
|
214
|
+
* @param config - the schema-validated config.
|
|
215
|
+
*/
|
|
216
|
+
constructor(ctx: Context, config: WslSubprocessConfig);
|
|
217
|
+
/**
|
|
218
|
+
* The distro a launch uses when the request's directory does not name one,
|
|
219
|
+
* resolving WSL's default on first use.
|
|
220
|
+
*
|
|
221
|
+
* @returns the distro name.
|
|
222
|
+
*/
|
|
223
|
+
distro(): Promise<string>;
|
|
224
|
+
/** Windows directory the `wsl.exe` process is started from. */
|
|
225
|
+
hostCwd(): string;
|
|
226
|
+
/**
|
|
227
|
+
* The distro and Linux directory one terminal request names.
|
|
228
|
+
*
|
|
229
|
+
* The Session workspace the terminal controller passes in is the coordinate
|
|
230
|
+
* the harness already speaks, and it is also the strongest evidence of the
|
|
231
|
+
* intended distro: a UNC path names one outright. Anything else — a Windows
|
|
232
|
+
* drive path or a directory-less request — may legitimately be served by the
|
|
233
|
+
* configured distro.
|
|
234
|
+
*
|
|
235
|
+
* @param cwd - the request's working directory, in any coordinate system.
|
|
236
|
+
* @returns the distro name and its absolute Linux directory.
|
|
237
|
+
*/
|
|
238
|
+
terminalTarget(cwd: string | undefined): Promise<{
|
|
239
|
+
distro: string;
|
|
240
|
+
linuxCwd: string;
|
|
241
|
+
}>;
|
|
242
|
+
/**
|
|
243
|
+
* Open one interactive shell inside the distro over the host's PTY.
|
|
244
|
+
*
|
|
245
|
+
* Only a `wsl.exe` launch is rewritten. Everything else — a shipped host
|
|
246
|
+
* shell, the PTY backend's `bash -i`, any other consumer's terminal — is the
|
|
247
|
+
* shipped implementation's, which is what keeps replacing a root provider
|
|
248
|
+
* safe.
|
|
249
|
+
*
|
|
250
|
+
* The request's remaining arguments are intentionally not forwarded: the
|
|
251
|
+
* controller's shell profile carries only the program, and a second set of
|
|
252
|
+
* `wsl.exe` arguments would fight the distro and `--cd` this method derives
|
|
253
|
+
* from the Session.
|
|
254
|
+
*
|
|
255
|
+
* @param spec - the terminal request from the PTY consumer.
|
|
256
|
+
* @returns the live terminal handle.
|
|
257
|
+
*/
|
|
258
|
+
spawnTerminal(spec: SubprocessTerminalSpawnSpec): Promise<SubprocessTerminalHandle>;
|
|
259
|
+
/**
|
|
260
|
+
* The replacement `inspectActivity` for one distro terminal: ask the
|
|
261
|
+
* resident agent whether the marked shell is at its prompt.
|
|
262
|
+
*
|
|
263
|
+
* The revision increments only when the reported state changes, so the
|
|
264
|
+
* controller's retention accumulates idle across consecutive `idle`
|
|
265
|
+
* observations and restarts the clock on every transition. Any probe
|
|
266
|
+
* failure — the agent out, the distro stopped, a script error — answers
|
|
267
|
+
* `unknown`, which the retention reads as "not idle": the probe that cannot
|
|
268
|
+
* answer never authorizes a close. The first unexpected (non-availability)
|
|
269
|
+
* failure is logged once, so a broken probe is diagnosable without
|
|
270
|
+
* spamming the log every poll.
|
|
271
|
+
*
|
|
272
|
+
* @param distro - the distro the terminal lives in.
|
|
273
|
+
* @param terminalId - the launch's `DSH_TERMINAL_ID` mark.
|
|
274
|
+
* @returns the seam's activity observation.
|
|
275
|
+
*/
|
|
276
|
+
distroActivity(distro: string, terminalId: string): () => Promise<SubprocessTerminalActivity>;
|
|
277
|
+
/**
|
|
278
|
+
* Open one host-side process, rewriting two kinds of launches into the
|
|
279
|
+
* distro: the file-search tool's ripgrep (agent-first, one-shot fallback)
|
|
280
|
+
* and git snapshot commands (one-shot only — snapshot operations are not
|
|
281
|
+
* latency-sensitive, and their stdin relay and collected streams are the
|
|
282
|
+
* shipped handle's). Both decisions are pure coordinate functions
|
|
283
|
+
* (`search-route.js`, `git-route.js`); a spawn neither names (any other
|
|
284
|
+
* program, any drive or relative directory) reaches the shipped
|
|
285
|
+
* implementation verbatim.
|
|
286
|
+
*
|
|
287
|
+
* @param spec - the spawn request.
|
|
288
|
+
* @returns the live search handle.
|
|
289
|
+
*/
|
|
290
|
+
spawn(spec: SubprocessSpawnSpec): SubprocessHandle;
|
|
291
|
+
/**
|
|
292
|
+
* The environment one `wsl.exe` launch forwards: the safe list plus every
|
|
293
|
+
* managed `DSH_*` name, admitted through `WSLENV` and never `PATH` — see the
|
|
294
|
+
* WSLENV note in the recipes.
|
|
295
|
+
*
|
|
296
|
+
* @param spec - the launch request whose env is forwarded.
|
|
297
|
+
* @returns the environment the host launch carries.
|
|
298
|
+
*/
|
|
299
|
+
forwardedEnv(spec: {
|
|
300
|
+
env?: Record<string, string | undefined> | undefined;
|
|
301
|
+
}): Record<string, string> | Record<string, string | undefined> | undefined;
|
|
302
|
+
/**
|
|
303
|
+
* Whether a terminal request is a `wsl.exe` launch.
|
|
304
|
+
*
|
|
305
|
+
* A bare `argv[0]` is judged by its own name, so the shipped program name and
|
|
306
|
+
* an operator-pinned absolute path both match.
|
|
307
|
+
*
|
|
308
|
+
* @param argv - the request's program and arguments.
|
|
309
|
+
* @returns true when this provider owns the launch.
|
|
310
|
+
*/
|
|
311
|
+
launchesDistro(argv?: readonly string[]): boolean;
|
|
312
|
+
}
|
|
313
|
+
export default WslSubprocessRuntime;
|