dsh-bash-terminal-ts 0.4.0 → 0.4.2
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.en.md +42 -164
- package/README.md +86 -92
- package/dist/client.core.js +137 -132
- package/dist/client.js +146 -141
- package/lib/client.js +146 -0
- package/lib/index.js +773 -759
- package/lib/terminal.js +427 -273
- package/package.json +29 -78
- package/scripts/build-client.mjs +14 -13
- package/src/client.jsx +136 -0
- package/README.ja.md +0 -196
- package/README.ko.md +0 -194
- package/dsh.plugin.json +0 -22
- package/lib/dsh-types.d.ts +0 -260
- package/lib/dsh-types.js +0 -9
- package/lib/dsh.d.ts +0 -33
- package/lib/dsh.js +0 -29
- package/lib/index.d.ts +0 -201
- package/lib/terminal.d.ts +0 -87
- package/src/client.tsx +0 -161
- package/src/dsh-types.ts +0 -313
- package/src/dsh.ts +0 -68
- package/src/index.ts +0 -952
- package/src/terminal.ts +0 -368
- package/tsconfig.client.json +0 -17
- package/tsconfig.json +0 -23
- package/tsconfig.test.json +0 -11
package/lib/index.d.ts
DELETED
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
import type { BashTerminalContext, ExecAgent, JobsRegistry, JsonSchemaNode, ResolvedPaths, SandboxFacts, SandboxPolicy, ShellId, ToolRunContext } from "./dsh-types.js";
|
|
2
|
-
/** Stable Cordis plugin name. */
|
|
3
|
-
export declare const name = "bash-terminal";
|
|
4
|
-
/** Services required before the tool can register. */
|
|
5
|
-
export declare const inject: string[];
|
|
6
|
-
/** The terminal backends this tool exposes, in catalog order. */
|
|
7
|
-
export declare const SHELLS: readonly ["powershell", "gitbash", "msys2", "wsl"];
|
|
8
|
-
/** The backend used when the caller does not name one. */
|
|
9
|
-
export declare const DEFAULT_SHELL: ShellId;
|
|
10
|
-
/** Settings namespace backing the user-chosen default terminal. */
|
|
11
|
-
export declare const SETTINGS_NAMESPACE = "bash-terminal";
|
|
12
|
-
/** Static shape of the runtime configuration schema. */
|
|
13
|
-
export interface ConfigValues {
|
|
14
|
-
defaultShell: string;
|
|
15
|
-
timeoutMs: number;
|
|
16
|
-
maxTimeoutMs: number;
|
|
17
|
-
pwshPath: string;
|
|
18
|
-
gitBashPath: string;
|
|
19
|
-
msys2Path: string;
|
|
20
|
-
wslPath: string;
|
|
21
|
-
}
|
|
22
|
-
/** Runtime configuration schema. */
|
|
23
|
-
export declare const Config: import("./dsh.js").SchemasterySchema;
|
|
24
|
-
declare function candidateExists(candidate: string): boolean;
|
|
25
|
-
/** Well-known PowerShell install locations plus PATH entries, newest first. */
|
|
26
|
-
export declare function candidatePwshPaths(env?: NodeJS.ProcessEnv): string[];
|
|
27
|
-
/**
|
|
28
|
-
* Git for Windows locations, then PATH bash.exe entries EXCLUDING the
|
|
29
|
-
* System32 launcher (c:\\windows\\system32\\bash.exe is the WSL
|
|
30
|
-
* forwarder, not a Git Bash shell).
|
|
31
|
-
*/
|
|
32
|
-
export declare function candidateGitBashPaths(env?: NodeJS.ProcessEnv): string[];
|
|
33
|
-
/**
|
|
34
|
-
* MSYS2 locations, in preference order: the real `bash.exe` under usr\bin first,
|
|
35
|
-
* then bin\bash.exe, and `msys2.exe` dead last.
|
|
36
|
-
*
|
|
37
|
-
* msys2.exe is NOT a usable backend for piped execution: it is the console-
|
|
38
|
-
* allocating Cygwin launcher, so a spawn with piped stdio returns exit 0 with
|
|
39
|
-
* zero bytes on both stdout and stderr (measured on MSYS2 with bash 5.3.15).
|
|
40
|
-
* Keeping it in the list only as a last-resort fallback preserves the path the
|
|
41
|
-
* config docs reference, but a working bash.exe always wins.
|
|
42
|
-
*
|
|
43
|
-
* MSYS2 uses the same Cygwin/MSYS2 runtime as Git Bash, so it cannot run under
|
|
44
|
-
* the DSH Windows ACL restricted-token sandbox.
|
|
45
|
-
*/
|
|
46
|
-
export declare function candidateMsys2Paths(env?: NodeJS.ProcessEnv): string[];
|
|
47
|
-
export declare function defaultWslPath(env?: NodeJS.ProcessEnv): string;
|
|
48
|
-
/** Executable paths, possibly undefined when a backend is not installed. */
|
|
49
|
-
export type { ResolvedPaths };
|
|
50
|
-
type PathConfig = Partial<Pick<ConfigValues, "pwshPath" | "gitBashPath" | "msys2Path" | "wslPath">>;
|
|
51
|
-
export declare function resolveAllPaths(config?: PathConfig, env?: NodeJS.ProcessEnv): ResolvedPaths;
|
|
52
|
-
export declare function buildArgv(shell: string, command: string, paths: ResolvedPaths, distro?: string): Array<string | undefined>;
|
|
53
|
-
/**
|
|
54
|
-
* Merge the DSH_* environment over the process environment. For WSL, only
|
|
55
|
-
* variables explicitly listed in WSLENV cross the boundary, so every DSH_* key is
|
|
56
|
-
* appended to it (WSLENV is a `:` separated VAR[/flag] list).
|
|
57
|
-
*
|
|
58
|
-
* WSLENV usually already exists for reasons unrelated to us -- Windows Terminal
|
|
59
|
-
* exports e.g. `WT_SESSION:WT_PROFILE_ID:` -- so the list is layered rather than
|
|
60
|
-
* rebuilt, or those entries would be silently dropped from every WSL call.
|
|
61
|
-
* Callers that spawn through a seam which replaces the parent environment
|
|
62
|
-
* wholesale (the PTY path) must pass the inherited value explicitly.
|
|
63
|
-
*
|
|
64
|
-
* @param inheritedWslenv - the WSLENV the child would otherwise inherit.
|
|
65
|
-
*/
|
|
66
|
-
export declare function buildEnv(shell: string, dshEnv?: Record<string, string>, inheritedWslenv?: string | undefined): Record<string, string | undefined>;
|
|
67
|
-
export interface SpawnResolution {
|
|
68
|
-
command: string;
|
|
69
|
-
workdir: string;
|
|
70
|
-
timeoutMs: number;
|
|
71
|
-
stdoutMaxBytes: number;
|
|
72
|
-
stdin?: string;
|
|
73
|
-
}
|
|
74
|
-
declare function spawnSpec(resolved: SpawnResolution, argv: string[], env: Record<string, string | undefined>, signal: AbortSignal): {
|
|
75
|
-
readonly argv: string[];
|
|
76
|
-
readonly cwd: string;
|
|
77
|
-
readonly stdio: {
|
|
78
|
-
readonly stdin: "ignore" | {
|
|
79
|
-
data: string;
|
|
80
|
-
};
|
|
81
|
-
readonly stdout: {
|
|
82
|
-
maxBytes: number;
|
|
83
|
-
spill: {
|
|
84
|
-
maxBytes: number;
|
|
85
|
-
};
|
|
86
|
-
};
|
|
87
|
-
readonly stderr: {
|
|
88
|
-
maxBytes: number;
|
|
89
|
-
spill: {
|
|
90
|
-
maxBytes: number;
|
|
91
|
-
};
|
|
92
|
-
};
|
|
93
|
-
};
|
|
94
|
-
readonly graceMs: 3000;
|
|
95
|
-
readonly signal: AbortSignal;
|
|
96
|
-
readonly env: Record<string, string | undefined>;
|
|
97
|
-
};
|
|
98
|
-
interface StreamOutput {
|
|
99
|
-
text: string;
|
|
100
|
-
truncated: boolean;
|
|
101
|
-
spillPath?: string;
|
|
102
|
-
}
|
|
103
|
-
export interface ForegroundOutcome {
|
|
104
|
-
exitCode: number | null;
|
|
105
|
-
signal: string | null;
|
|
106
|
-
timedOut: boolean;
|
|
107
|
-
aborted: boolean;
|
|
108
|
-
timeoutMs: number;
|
|
109
|
-
stdout: StreamOutput;
|
|
110
|
-
stderr: StreamOutput;
|
|
111
|
-
}
|
|
112
|
-
declare function runForeground(ctx: BashTerminalContext, argv: string[], resolved: SpawnResolution, env: Record<string, string | undefined>, signal: AbortSignal, timeoutMs: number): Promise<ForegroundOutcome>;
|
|
113
|
-
export interface ProcessRead {
|
|
114
|
-
delta: string;
|
|
115
|
-
lossy: boolean;
|
|
116
|
-
stdoutSpillPath?: string;
|
|
117
|
-
stderrSpillPath?: string;
|
|
118
|
-
}
|
|
119
|
-
interface BackgroundProc {
|
|
120
|
-
status: "running" | "killed" | "completed";
|
|
121
|
-
exitCode: number | null;
|
|
122
|
-
signal: string | null;
|
|
123
|
-
done: Promise<void>;
|
|
124
|
-
readOutput(): ProcessRead;
|
|
125
|
-
kill(): boolean;
|
|
126
|
-
}
|
|
127
|
-
declare function startBackground(ctx: BashTerminalContext, argv: string[], resolved: SpawnResolution, env: Record<string, string | undefined>, signal: AbortSignal): BackgroundProc;
|
|
128
|
-
declare function processOutcome(proc: BackgroundProc): {
|
|
129
|
-
status: string;
|
|
130
|
-
detail: string;
|
|
131
|
-
};
|
|
132
|
-
export interface RenderedResult {
|
|
133
|
-
stdout: StreamOutput;
|
|
134
|
-
stderr: StreamOutput;
|
|
135
|
-
exitCode: number | null;
|
|
136
|
-
signal: string | null;
|
|
137
|
-
timedOut: boolean;
|
|
138
|
-
timeoutMs: number;
|
|
139
|
-
}
|
|
140
|
-
export declare function renderResult(result: RenderedResult): string;
|
|
141
|
-
/** Model-facing lead sentence for each backend. The user's default terminal is
|
|
142
|
-
* stated up front so the model never has to guess which syntax applies. */
|
|
143
|
-
export declare const SHELL_DESCRIPTIONS: Record<ShellId, string>;
|
|
144
|
-
/**
|
|
145
|
-
* Render the model-facing tool description for one backend. The backend is
|
|
146
|
-
* whatever the user chose in Settings -> General -> Default terminal; the
|
|
147
|
-
* description names it explicitly so the model writes the right syntax.
|
|
148
|
-
* @param backgroundEnabled - advertise `run_in_background` controls.
|
|
149
|
-
* @param shell - active backend; unknown values fall back to the default.
|
|
150
|
-
*/
|
|
151
|
-
export declare function toolDescription(backgroundEnabled: boolean, shell?: string): string;
|
|
152
|
-
/** The shell tool's arguments after runtime validation. */
|
|
153
|
-
export type ValidatedShellArgs = {
|
|
154
|
-
command: string;
|
|
155
|
-
description: string;
|
|
156
|
-
timeoutMs?: number;
|
|
157
|
-
distro?: string;
|
|
158
|
-
sandbox_permissions?: string;
|
|
159
|
-
justification?: string;
|
|
160
|
-
workdir?: string;
|
|
161
|
-
run_in_background?: boolean;
|
|
162
|
-
stdin?: string;
|
|
163
|
-
};
|
|
164
|
-
export declare function validateArgs(args: Record<string, unknown>): ValidatedShellArgs;
|
|
165
|
-
declare function resolveWorkdir(modelWorkdir: string | undefined, exec: ToolRunContext): string | undefined;
|
|
166
|
-
export interface ForegroundResult {
|
|
167
|
-
kind: "foreground";
|
|
168
|
-
exitCode: number | null;
|
|
169
|
-
signal: string | null;
|
|
170
|
-
timedOut: boolean;
|
|
171
|
-
aborted: boolean;
|
|
172
|
-
timeoutMs: number;
|
|
173
|
-
stdout: StreamOutput;
|
|
174
|
-
stderr: StreamOutput;
|
|
175
|
-
sandbox?: SandboxFacts;
|
|
176
|
-
}
|
|
177
|
-
export interface BackgroundResult {
|
|
178
|
-
kind: "background";
|
|
179
|
-
jobId: string;
|
|
180
|
-
}
|
|
181
|
-
export type ShellToolResult = ForegroundResult | BackgroundResult;
|
|
182
|
-
export declare function apply(ctx: BashTerminalContext, config?: Partial<ConfigValues>): void;
|
|
183
|
-
export declare const internals: {
|
|
184
|
-
candidateExists: typeof candidateExists;
|
|
185
|
-
resolveAllPaths: typeof resolveAllPaths;
|
|
186
|
-
resolveWorkdir: typeof resolveWorkdir;
|
|
187
|
-
renderResult: typeof renderResult;
|
|
188
|
-
processOutcome: typeof processOutcome;
|
|
189
|
-
startBackground: typeof startBackground;
|
|
190
|
-
runForeground: typeof runForeground;
|
|
191
|
-
spawnSpec: typeof spawnSpec;
|
|
192
|
-
buildEnv: typeof buildEnv;
|
|
193
|
-
buildArgv: typeof buildArgv;
|
|
194
|
-
validateArgs: typeof validateArgs;
|
|
195
|
-
toolDescription: typeof toolDescription;
|
|
196
|
-
SHELL_DESCRIPTIONS: Record<ShellId, string>;
|
|
197
|
-
DEFAULT_TIMEOUT_MS: number;
|
|
198
|
-
MAX_TIMEOUT_MS: number;
|
|
199
|
-
DEFAULT_MAX_OUTPUT_BYTES: number;
|
|
200
|
-
};
|
|
201
|
-
export type { ExecAgent, JobsRegistry, JsonSchemaNode, SandboxFacts, SandboxPolicy, ShellId, ToolRunContext };
|
package/lib/terminal.d.ts
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import type { BashTerminalContext, ResolvedPaths, TerminalHandle } from "./dsh-types.js";
|
|
2
|
-
declare const TERMINAL_SIGNALS: readonly ["SIGINT", "SIGTERM", "SIGKILL", "SIGTSTP", "SIGHUP"];
|
|
3
|
-
export type TerminalSignal = (typeof TERMINAL_SIGNALS)[number];
|
|
4
|
-
interface TerminalBufferRead {
|
|
5
|
-
delta: string;
|
|
6
|
-
nextOffset: number;
|
|
7
|
-
}
|
|
8
|
-
interface TerminalBuffer {
|
|
9
|
-
append(chunk: string): void;
|
|
10
|
-
readFrom(offset: number): TerminalBufferRead;
|
|
11
|
-
snapshot(): string;
|
|
12
|
-
}
|
|
13
|
-
/** Interactive-shell argv (no -c: the terminal itself is the session). */
|
|
14
|
-
export declare function terminalArgv(shell: string, paths: ResolvedPaths, distro?: string): Array<string | undefined>;
|
|
15
|
-
interface TerminalSession {
|
|
16
|
-
id: string;
|
|
17
|
-
handle: TerminalHandle;
|
|
18
|
-
buffer: TerminalBuffer;
|
|
19
|
-
shell: string;
|
|
20
|
-
distro?: string;
|
|
21
|
-
closed: boolean;
|
|
22
|
-
}
|
|
23
|
-
export interface TerminalOpenOptions {
|
|
24
|
-
argv: string[];
|
|
25
|
-
shell: string;
|
|
26
|
-
cwd: string;
|
|
27
|
-
env: Record<string, string | undefined>;
|
|
28
|
-
rows: number;
|
|
29
|
-
cols: number;
|
|
30
|
-
distro?: string;
|
|
31
|
-
initial?: string;
|
|
32
|
-
}
|
|
33
|
-
export interface TerminalRegistry {
|
|
34
|
-
open(options: TerminalOpenOptions): Promise<TerminalSession>;
|
|
35
|
-
get(id: string): TerminalSession;
|
|
36
|
-
send(id: string, input: string): Promise<TerminalBufferRead>;
|
|
37
|
-
read(id: string): TerminalBufferRead;
|
|
38
|
-
signal(id: string, sig: string): Promise<TerminalBufferRead>;
|
|
39
|
-
close(id: string): Promise<boolean>;
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Terminal-session registry owned by the plugin fiber: opens PTYs through
|
|
43
|
-
* the official seam, forwards output into a capped buffer, and tears every
|
|
44
|
-
* session down on plugin disposal.
|
|
45
|
-
*/
|
|
46
|
-
export declare function createTerminalRegistry(ctx: BashTerminalContext): TerminalRegistry;
|
|
47
|
-
/** The terminal tool's arguments after runtime validation (discriminated by action). */
|
|
48
|
-
export type ValidatedTerminalArgs = {
|
|
49
|
-
action: "open";
|
|
50
|
-
sessionId?: string;
|
|
51
|
-
command?: string;
|
|
52
|
-
distro?: string;
|
|
53
|
-
workdir?: string;
|
|
54
|
-
} | {
|
|
55
|
-
action: "send";
|
|
56
|
-
sessionId: string;
|
|
57
|
-
input: string;
|
|
58
|
-
} | {
|
|
59
|
-
action: "read";
|
|
60
|
-
sessionId: string;
|
|
61
|
-
} | {
|
|
62
|
-
action: "signal";
|
|
63
|
-
sessionId: string;
|
|
64
|
-
signal: TerminalSignal;
|
|
65
|
-
} | {
|
|
66
|
-
action: "close";
|
|
67
|
-
sessionId: string;
|
|
68
|
-
};
|
|
69
|
-
export declare function validateArgs(args: Record<string, unknown>): asserts args is ValidatedTerminalArgs;
|
|
70
|
-
export interface TerminalOpenResult {
|
|
71
|
-
kind: "open";
|
|
72
|
-
sessionId: string;
|
|
73
|
-
pid: number;
|
|
74
|
-
shell: string;
|
|
75
|
-
output: string;
|
|
76
|
-
}
|
|
77
|
-
export interface TerminalSessionResult {
|
|
78
|
-
kind: "session";
|
|
79
|
-
output: string;
|
|
80
|
-
}
|
|
81
|
-
export interface TerminalClosedResult {
|
|
82
|
-
kind: "closed";
|
|
83
|
-
sessionId: string;
|
|
84
|
-
}
|
|
85
|
-
export type TerminalToolResult = TerminalOpenResult | TerminalSessionResult | TerminalClosedResult;
|
|
86
|
-
export declare function terminalTool(ctx: BashTerminalContext, registry: TerminalRegistry, paths: ResolvedPaths, defaultShell: () => string): import("./dsh-types.js").ToolDefinition;
|
|
87
|
-
export {};
|
package/src/client.tsx
DELETED
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
// dsh-bash-terminal-ts client plugin: a "Default terminal" preference row in the
|
|
2
|
-
// Web UI General settings. The user picks powershell / gitbash / msys2 / wsl;
|
|
3
|
-
// the host shell tool obeys that choice (the model cannot change it).
|
|
4
|
-
//
|
|
5
|
-
// The option list below must stay in lockstep with SHELLS in ./index.ts: every
|
|
6
|
-
// id gets an <option> here and a `shell.<id>` entry in both dictionaries. The
|
|
7
|
-
// shipped bundle cannot import the host module (it pulls node: builtins), so
|
|
8
|
-
// test/client.ts asserts the bundle covers every host shell id instead.
|
|
9
|
-
|
|
10
|
-
import { defineStore } from "@deepseek-ai/dsh-client-store";
|
|
11
|
-
|
|
12
|
-
const SETTINGS_NS = "settings.bash-terminal";
|
|
13
|
-
const SETTINGS_NAMESPACE = "bash-terminal";
|
|
14
|
-
|
|
15
|
-
const zh: Record<string, string> = {
|
|
16
|
-
"shell.title": "默认终端",
|
|
17
|
-
"shell.description": "shell 工具执行命令时使用的终端(由你决定,AI 无法更改)",
|
|
18
|
-
"shell.powershell": "PowerShell",
|
|
19
|
-
"shell.gitbash": "Git Bash",
|
|
20
|
-
"shell.msys2": "MSYS2",
|
|
21
|
-
"shell.wsl": "WSL"
|
|
22
|
-
};
|
|
23
|
-
const en: Record<string, string> = {
|
|
24
|
-
"shell.title": "Default terminal",
|
|
25
|
-
"shell.description": "Terminal used by the shell tool (you control this; the AI cannot change it)",
|
|
26
|
-
"shell.powershell": "PowerShell",
|
|
27
|
-
"shell.gitbash": "Git Bash",
|
|
28
|
-
"shell.msys2": "MSYS2",
|
|
29
|
-
"shell.wsl": "WSL"
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export const inject = ["slots", "locale", "settingsScope"];
|
|
33
|
-
|
|
34
|
-
/** Row state snapshot served through the settings store. */
|
|
35
|
-
interface RowState {
|
|
36
|
-
shell: string;
|
|
37
|
-
revision: number;
|
|
38
|
-
writable: boolean;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
interface ShellPreferenceRowProps {
|
|
42
|
-
t: (key: string) => string;
|
|
43
|
-
useStore: <S>(selector: (state: RowState) => S) => S;
|
|
44
|
-
setShell: (id: string) => void;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function ShellPreferenceRow({ t, useStore, setShell }: ShellPreferenceRowProps) {
|
|
48
|
-
const shell = useStore((s) => s.shell);
|
|
49
|
-
const writable = useStore((s) => s.writable);
|
|
50
|
-
return (
|
|
51
|
-
<div
|
|
52
|
-
style={{
|
|
53
|
-
display: "flex",
|
|
54
|
-
alignItems: "center",
|
|
55
|
-
justifyContent: "space-between",
|
|
56
|
-
gap: 16,
|
|
57
|
-
padding: "12px 0"
|
|
58
|
-
}}
|
|
59
|
-
>
|
|
60
|
-
<div style={{ minWidth: 0 }}>
|
|
61
|
-
<div style={{ fontSize: 14, fontWeight: 500, lineHeight: "22px", color: "var(--dsw-alias-label-primary, inherit)" }}>
|
|
62
|
-
{t("shell.title")}
|
|
63
|
-
</div>
|
|
64
|
-
<div style={{ fontSize: 12, lineHeight: "18px", opacity: 0.65 }}>{t("shell.description")}</div>
|
|
65
|
-
</div>
|
|
66
|
-
<select
|
|
67
|
-
value={shell}
|
|
68
|
-
disabled={!writable}
|
|
69
|
-
onChange={(e) => setShell(e.target.value)}
|
|
70
|
-
style={{
|
|
71
|
-
fontSize: 14,
|
|
72
|
-
padding: "6px 10px",
|
|
73
|
-
borderRadius: 8,
|
|
74
|
-
border: "1px solid var(--dsw-alias-line-strong, #ccc)",
|
|
75
|
-
background: "var(--dsw-alias-bg-layer-2, #fff)",
|
|
76
|
-
color: "var(--dsw-alias-label-primary, inherit)",
|
|
77
|
-
outline: "none",
|
|
78
|
-
cursor: writable ? "pointer" : "not-allowed",
|
|
79
|
-
maxWidth: 180
|
|
80
|
-
}}
|
|
81
|
-
>
|
|
82
|
-
<option value="powershell">{t("shell.powershell")}</option>
|
|
83
|
-
<option value="gitbash">{t("shell.gitbash")}</option>
|
|
84
|
-
<option value="msys2">{t("shell.msys2")}</option>
|
|
85
|
-
<option value="wsl">{t("shell.wsl")}</option>
|
|
86
|
-
</select>
|
|
87
|
-
</div>
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
interface SettingsSnapshot {
|
|
92
|
-
status: string;
|
|
93
|
-
value?: { defaultShell?: string };
|
|
94
|
-
revision: number;
|
|
95
|
-
writable: boolean;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
interface SettingsScopeBinding {
|
|
99
|
-
getSnapshot(): SettingsSnapshot;
|
|
100
|
-
subscribe(fn: () => void): () => void;
|
|
101
|
-
set(field: string, value: string): void;
|
|
102
|
-
unset(): void;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
interface ClientContext {
|
|
106
|
-
effect(fn: () => unknown, name?: string): unknown;
|
|
107
|
-
locale: { register(ns: string, dicts: Record<string, Record<string, string>>): unknown };
|
|
108
|
-
settingsScope: { bind(options: { namespace: string }): SettingsScopeBinding };
|
|
109
|
-
slots: {
|
|
110
|
-
inject(slot: string, fn: () => unknown, name?: string): void;
|
|
111
|
-
register(options: Record<string, unknown>, Component: unknown): Record<string, unknown>;
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
interface RowStoreActions {
|
|
116
|
-
sync(shell?: string, revision?: number, writable?: boolean): void;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
export function apply(ctx: ClientContext): void {
|
|
120
|
-
ctx.effect(() => ctx.locale.register(SETTINGS_NS, { zh, en }), "bash-terminal: settings dictionaries");
|
|
121
|
-
const scope = ctx.settingsScope.bind({ namespace: SETTINGS_NAMESPACE });
|
|
122
|
-
const store = defineStore<RowState, { sync: (draft: RowState, shell?: string, revision?: number, writable?: boolean) => void }>({
|
|
123
|
-
init: (): RowState => ({ shell: "powershell", revision: -1, writable: false }),
|
|
124
|
-
actions: {
|
|
125
|
-
sync: (d, shell, revision, writable) => {
|
|
126
|
-
if (revision !== undefined && revision <= d.revision) return;
|
|
127
|
-
if (shell !== undefined) d.shell = shell;
|
|
128
|
-
if (revision !== undefined) d.revision = revision;
|
|
129
|
-
if (writable !== undefined) d.writable = writable;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
});
|
|
133
|
-
// defineStore() yields a { spec, create } factory; slots.register creates
|
|
134
|
-
// the live store, so we bind the actions in the inject callback and push
|
|
135
|
-
// the initial snapshot there too (mirrors the theme row pattern).
|
|
136
|
-
let bound: RowStoreActions | undefined;
|
|
137
|
-
const push = (snap: SettingsSnapshot): void => {
|
|
138
|
-
bound?.sync(snap.value?.defaultShell, snap.revision, snap.writable);
|
|
139
|
-
};
|
|
140
|
-
ctx.slots.inject(
|
|
141
|
-
"settings.general.item",
|
|
142
|
-
() =>
|
|
143
|
-
ctx.slots.register(
|
|
144
|
-
{
|
|
145
|
-
name: "settings.general.item",
|
|
146
|
-
id: "bash-terminal-shell",
|
|
147
|
-
order: 20,
|
|
148
|
-
store,
|
|
149
|
-
locale: SETTINGS_NS,
|
|
150
|
-
inject: (actions: unknown) => {
|
|
151
|
-
bound = actions as RowStoreActions;
|
|
152
|
-
push(scope.getSnapshot());
|
|
153
|
-
return { setShell: (value: string) => void scope.set("defaultShell", value) };
|
|
154
|
-
}
|
|
155
|
-
},
|
|
156
|
-
ShellPreferenceRow
|
|
157
|
-
),
|
|
158
|
-
"bash-terminal: settings row"
|
|
159
|
-
);
|
|
160
|
-
ctx.effect(() => scope.subscribe(() => push(scope.getSnapshot())), "bash-terminal: settings watch");
|
|
161
|
-
}
|