@deepseek-ai/dsh-terminal-bash 0.1.0-rc.7 → 0.1.0-rc.8

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.i18n.yaml CHANGED
@@ -2,5 +2,5 @@
2
2
  # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
3
  # after editing either side, bring the other along and re-record with:
4
4
  # pnpm run verify-translation-pairing --write packages/terminal/terminal-bash/README.md
5
- README.md: 72f5b57335febe40b36de85e7df9b6df4bf7cb10
6
- README.zh.md: 48c051564130d283717828de35d625d65e825052
5
+ README.md: 2f3f59b1acb88ff9905e78e7fc8d0d9fbcdbf0ba
6
+ README.zh.md: f3daa0a3bc9c160236ad19b35589778d99d48b36
package/README.md CHANGED
@@ -8,6 +8,8 @@ Persistent shell backend for `ctx.terminals` over `ctx.subprocess.spawnTerminal`
8
8
 
9
9
  The plugin injects `pty`, `sandboxPolicy`, and `subprocess`, then registers the configured backend type (`shell`). `danger-full-access` starts the shell directly without requiring a sandbox provider; confined modes require a same-world `ctx.sandbox` and wrap the exact shell argv through it, failing before spawn when none is mounted. At spawn, one `ctx.sandboxPolicy.resolve({ session })` call supplies both the effective mode and the session workspace root; the same root is the default shell cwd when the caller omits one. A change to a different effective mode is rejected before its `sandbox/mode` event commits while that owner has an open PTY or a spawn in progress; the fence is attached to the exact owner and therefore outlives a provider reload that retains existing sessions. Wait for creation to settle and close the sessions before changing modes, so a terminal opened with wider access cannot survive a downgrade.
10
10
 
11
+ `shellDialect` selects the shell stack (`bash` default, `pwsh`): it picks the default `shellPath`/`shellArgs` (bash `--noprofile --norc -i`; pwsh `-NoLogo -NoProfile` through the shared `dsh-pwsh-local` resolver) and the startup contract. The bash dialect installs its prompt through the environment (`PS1` plus an OSC `133;D;`-terminated `PROMPT_COMMAND`). pwsh cannot install a prompt from the environment, so the backend writes a `prompt` function through the session and waits until the controlled prompt is actually visible — looping over follow-up sends because the pwsh banner-to-prompt gap can outlast the silence bound — while its environment drops the bash-only markers and adds `NO_COLOR`. That first send also prefixes the shared `dsh-pwsh-local` encoding preamble, pinning `[Console]::OutputEncoding` and `$OutputEncoding` to UTF-8 before anything runs: the session decode path reads PTY bytes as UTF-8, and an un-pinned console writes its host code page for non-ASCII output. Both dialects emit the same BEL-terminated OSC marker, so the readiness machinery and consumers are dialect-agnostic.
12
+
11
13
  Readiness combines a foreground-verified private bash prompt marker, provider-reported foreground stdin-wait facts, silence fallback, and absolute timeout. A marker is not ready until the printable tail after the latest owned marker exactly equals the controlled `PS1`, including when the OSC marker and prompt are split across data callbacks; echoed input or output following an earlier prompt therefore cannot settle the current send. The controlled `PROMPT_COMMAND` re-asserts that `PS1` before every prompt, so an in-shell prompt override cannot degrade later sends to silence readiness. Prompt and silence evidence collected before the provider write, including while pre-write foreground inspection is pending, is discarded at the write boundary. When bash prints the marker before the terminal provider publishes its return to the foreground process group, polling retains the candidate for `handoffGraceMs` past the ordinary silence bound so a coincident handoff can win. An interactive child that inherits `PROMPT_COMMAND` therefore cannot suppress inferred-idle readiness until the absolute timeout. Unknown foreground state is never a positive exact-idle signal. A foreground group's stdin wait that existed before a send is likewise not post-write readiness: the same group must be observed outside that wait before a later wait can settle the send, while a changed foreground group is new evidence. During unpublished startup, a fallback requires observed output; zero-output silence cannot publish an empty session, and timeout rejects the spawn. Cancellation closes the unpublished shell and rejects with the caller's exact abort reason; `TerminalBackendCleanupError` separately preserves a cleanup failure. The caller's signal is forwarded for terminal allocation and readiness initialization; after publication the handle owns its lifetime. Incomplete terminal-control sequences are bounded by `maxReadBytes` and discarded through their terminator after crossing that limit; malformed UTF-8 terminal output uses replacement characters, and a trailing carriage return is carried across callbacks so split CRLF becomes one newline.
12
14
 
13
15
  Send cancellation marks queued input as canceled before asking the terminal handle to signal the current foreground process group with a real `SIGINT`; if asynchronous pre-write inspection later settles, it cannot execute that input. If a provider write is already in flight, signalling waits for it to settle; a rejected write sends no signal. The canceled send retains its slot until the write and foreground signalling settle, so a successor cannot receive either late bytes or that signal. A provider write or signal that never settles therefore retains the slot indefinitely; closing the session (`terminal_close`) is the recovery. The absolute deadline remains armed while cancellation waits. A signal failure is a terminal transport failure and rejects the active send. Cancellation never emulates interruption by writing `\x03`, so raw-mode programs remain cancellable. Close rejects new public signals, stops readiness polling, and awaits the handle's provider-owned complete-session termination before settling the active send as `session_exit`.
@@ -31,6 +33,7 @@ A standing-policy change appends an owner-rendered superseding runtime-context s
31
33
  ## Known Limitations and Deferred Work
32
34
 
33
35
  - Line-oriented output is normalized; full-screen alternate-buffer interaction is unsupported.
34
- - Exact stdin-wait detection depends on the mounted subprocess provider; providers that cannot prove it use prompt-marker and silence/timeout readiness.
36
+ - Exact stdin-wait detection depends on the mounted subprocess provider; providers that cannot prove it use prompt-marker and silence/timeout readiness. Windows is such a provider: the shell pid is the pseudo foreground group and there is no exact stdin-wait tier, so a marker-less child settles on the silence bound.
37
+ - The pwsh bootstrap writes through `[Console]::` (the UTF-8 encoding pin and the prompt function), which the Windows ACL sandbox's read-only mode (ConstrainedLanguage) may deny. The shell can still settle through the controlled printable prompt and silence tier, but marker readiness is unavailable and non-ASCII output may follow the host code page.
35
38
  - Cleanup guarantees are those of `SubprocessTerminalHandle`; provider-specific gaps belong to that implementation's contract rather than this PTY consumer.
36
39
  - Sessions do not survive harness process exit.
package/README.zh.md CHANGED
@@ -8,6 +8,8 @@
8
8
 
9
9
  该插件注入 `pty`、`sandboxPolicy` 和 `subprocess`,然后注册所配置的后端类型(`shell`)。`danger-full-access` 无需沙箱提供方即可直接启动 shell;受限模式要求同一执行世界中存在 `ctx.sandbox`,并通过它包装确切的 shell argv,未挂载时会在 spawn 前失败。spawn 时,一次 `ctx.sandboxPolicy.resolve({ session })` 调用会同时给出实际模式与会话工作区根目录;调用方省略 cwd 时,同一根目录也是 shell 的默认 cwd。当某个所有者存在开放的 PTY 或正在进行 spawn 时,如果配置变更会得到不同的实际模式,系统会在对应 `sandbox/mode` 事件提交前拒绝该变更。该限制绑定到确切所有者,因此即使提供方重新加载并保留现有会话,它仍然有效。更改模式前,请等待创建完成并关闭会话,避免以更宽权限打开的终端在权限降级后继续存在。
10
10
 
11
+ `shellDialect` 选择 shell 栈(默认 `bash`,或 `pwsh`):它决定默认的 `shellPath`/`shellArgs`(bash 为 `--noprofile --norc -i`;pwsh 经共享的 `dsh-pwsh-local` 解析器得到 `-NoLogo -NoProfile`)与启动契约。bash 方言通过环境安装提示符(`PS1` 加 OSC `133;D;` 终结的 `PROMPT_COMMAND`)。pwsh 无法从环境安装提示符,因此后端通过会话写入 `prompt` 函数,并等待受控提示符真正可见——因为 pwsh 从横幅到提示符的间隙可能超过静默上限,所以会在后续 send 上循环等待;同时其环境去掉 bash 专属标记并加 `NO_COLOR`。同一条首发送还会带上共享的 `dsh-pwsh-local` 编码前缀,在一切运行之前把 `[Console]::OutputEncoding` 与 `$OutputEncoding` 钉为 UTF-8:会话解码路径按 UTF-8 读取 PTY 字节,未钉住编码的控制台会以宿主代码页输出非 ASCII 内容。两种方言发出相同的 BEL 终结 OSC 标记,因此就绪机制与消费方与方言无关。
12
+
11
13
  就绪检测结合以下机制:由前台状态验证的私有 bash 提示符标记、提供方报告的前台 stdin 等待事实、静默回退和绝对超时。只有最新自有标记之后的可打印尾部与受控 `PS1` 完全相等,标记才算就绪;即使 OSC 标记和提示符被拆到多个数据回调中也一样。因此,较早提示符之后的回显输入或输出无法使当前 send 完成。受控 `PROMPT_COMMAND` 会在每次输出提示符前重新设定该 `PS1`,因此在 shell 内覆盖提示符不会使后续 send 退化到静默就绪。提供方写入前收集的提示符与静默证据,包括写入前前台检查仍在等待时收集的证据,都会在写入边界丢弃。如果 bash 在终端提供方发布其重新取得前台进程组的状态前打印标记,轮询会在普通静默上限之后再保留该候选状态 `handoffGraceMs`,使恰好同时发生的前台交接有机会胜出。因此,继承 `PROMPT_COMMAND` 的交互式子进程无法一直抑制推断空闲就绪直至绝对超时。未知的前台状态绝不会作为精确空闲的正向信号。同样,一次 send 之前就已存在的前台进程组 stdin 等待并不代表写入后就绪:必须先观察到同一进程组脱离该等待,之后再次进入等待才能使该次 send 完成;前台进程组发生变化则构成新的证据。尚未发布的启动过程中,回退路径要求已经观察到输出;零输出静默不能发布空会话,超时则拒绝 spawn。取消操作会关闭尚未发布的 shell,并以调用方提供的确切中止原因拒绝;`TerminalBackendCleanupError` 会单独保留清理失败。调用方的 signal 会转发给终端分配与就绪初始化;发布后,句柄负责其生命周期。未完成的终端控制序列受 `maxReadBytes` 限制;超过上限后,系统会丢弃内容直到其终止符。格式错误的 UTF-8 终端输出使用替换字符;末尾的回车会跨回调保留,使拆分的 CRLF 合并为一个换行。
12
14
 
13
15
  取消发送时,系统会先把排队输入标记为已取消,再要求终端句柄向当前前台进程组发送真正的 `SIGINT`;异步写入前检查即使随后结算,也无法执行该输入。如果提供方写入已在途,信号发送会等待其结算;写入被拒绝时不会发送信号。已取消的 send 会保留其位置,直到写入与前台信号发送都结算,因此后继 send 不会收到延迟字节或该信号。因此,永不结算的提供方写入或信号会无限期保留该位置;恢复手段是关闭会话(`terminal_close`)。取消等待期间,绝对 deadline 仍保持启用。信号发送失败是终端传输失败,会拒绝活跃 send。取消绝不会通过写入 `\x03` 模拟中断,因此,即使程序运行在 raw 模式下,也仍可取消。关闭操作会拒绝新的公开信号、停止就绪轮询,并等待由句柄提供方负责的完整会话终止,然后才把活跃 send 结算为 `session_exit`。
@@ -31,6 +33,7 @@
31
33
  ## 已知限制与暂缓事项
32
34
 
33
35
  - 输出按行规范化;不支持全屏备用缓冲区交互。
34
- - 精确 stdin 等待检测取决于已挂载的进程管理提供方;无法证明该状态的提供方使用提示符标记和静默/超时就绪机制。
36
+ - 精确 stdin 等待检测取决于已挂载的进程管理提供方;无法证明该状态的提供方使用提示符标记和静默/超时就绪机制。Windows 正是这样的提供方:shell pid 是伪前台进程组,没有精确的 stdin-wait 档,因此无标记的子进程按静默上限结算。
37
+ - pwsh 引导(UTF-8 编码钉与 `prompt` 函数)通过 `[Console]::` 写入,Windows ACL 沙箱的只读模式(ConstrainedLanguage)可能拒绝它。shell 仍可通过受控可打印提示符和静默档结算,但无法使用 marker 就绪,非 ASCII 输出也可能沿用宿主代码页。
35
38
  - 清理保证以 `SubprocessTerminalHandle` 的保证为准;提供方特定的缺口属于该实现的约定,而非这个 PTY 消费方。
36
39
  - harness 进程退出后,会话无法继续存在。
package/lib/index.js CHANGED
@@ -1,18 +1,44 @@
1
1
  import { TerminalBackendCleanupError, TerminalError } from "@deepseek-ai/dsh-terminal";
2
2
  import { effectiveSandboxMode } from "@deepseek-ai/dsh-sandbox-policy";
3
+ import { ENCODING_PREAMBLE, resolvePwshPath } from "@deepseek-ai/dsh-pwsh-local";
3
4
  import z from "@deepseek-ai/schemastery";
4
5
  import { Buffer } from "node:buffer";
5
6
  //#region lib/types/config.js
6
7
  /** Validated configuration for the local PTY backend. */
8
+ /** Bash dialect default executable. */
9
+ const DEFAULT_BASH_SHELL = "/bin/bash";
10
+ /** Bash dialect default arguments (interactive, profile-free). */
11
+ const DEFAULT_BASH_ARGS = [
12
+ "--noprofile",
13
+ "--norc",
14
+ "-i"
15
+ ];
16
+ /** Pwsh dialect default arguments (interactive host, profile-free). */
17
+ const DEFAULT_PWSH_ARGS = ["-NoLogo", "-NoProfile"];
18
+ /**
19
+ * Resolve the effective per-dialect shell specification. Defaulting is this
20
+ * explicit step: an unset or empty `shellPath`/`shellArgs` selects the
21
+ * dialect's defaults, while a non-empty explicit value always wins.
22
+ * (Schemastery materializes an absent optional array as `[]`, so emptiness —
23
+ * not just `undefined` — means "dialect default".)
24
+ * @param config - Schemastery-resolved plugin configuration.
25
+ * @returns the fully resolved configuration.
26
+ */
27
+ function resolveConfig(config) {
28
+ const shellDialect = config.shellDialect ?? "bash";
29
+ return {
30
+ ...config,
31
+ shellDialect,
32
+ shellPath: config.shellPath !== void 0 && config.shellPath.length > 0 ? config.shellPath : shellDialect === "pwsh" ? resolvePwshPath() : DEFAULT_BASH_SHELL,
33
+ shellArgs: config.shellArgs !== void 0 && config.shellArgs.length > 0 ? config.shellArgs : shellDialect === "pwsh" ? DEFAULT_PWSH_ARGS : DEFAULT_BASH_ARGS
34
+ };
35
+ }
7
36
  /** Schemastery config exposed by the plugin. */
8
37
  const Config = z.object({
9
38
  backendType: z.string().default("shell"),
10
- shellPath: z.string().default("/bin/bash"),
11
- shellArgs: z.array(z.string()).default([
12
- "--noprofile",
13
- "--norc",
14
- "-i"
15
- ]),
39
+ shellDialect: z.union(["bash", "pwsh"]).default("bash"),
40
+ shellPath: z.string().required(false),
41
+ shellArgs: z.array(z.string()).required(false),
16
42
  rows: z.number().default(40),
17
43
  cols: z.number().default(160),
18
44
  scrollbackLines: z.number().default(1e4),
@@ -26,7 +52,7 @@ const Config = z.object({
26
52
  disposeGraceMs: z.number().default(3e3)
27
53
  });
28
54
  /**
29
- * Assert every numeric config field is a positive safe integer and bounds compose.
55
+ * Assert every effective numeric config field is a positive safe integer and bounds compose.
30
56
  * @param config - Schemastery-resolved plugin configuration.
31
57
  * @returns Narrows the input to the fully resolved configuration.
32
58
  */
@@ -713,19 +739,33 @@ function ensureSandboxModeFence(ctx, owner) {
713
739
  throw new Error(`cannot change sandbox mode from "${currentMode}" to "${event.data.mode}" while persistent terminal sessions are open or being created; wait for creation to settle and close them first`);
714
740
  }, { global: true });
715
741
  }
716
- function childEnvironment(spec) {
717
- return {
742
+ function childEnvironment(spec, dialect) {
743
+ const common = {
718
744
  TERM: "dumb",
719
745
  PAGER: "cat",
720
746
  GIT_PAGER: "cat",
721
- PS1: CONTROLLED_PROMPT,
722
- PROMPT_COMMAND: `printf "\\033]133;D;%s\\007" "$?"; PS1='${CONTROLLED_PROMPT}'`,
723
- BASH_SILENCE_DEPRECATION_WARNING: "1",
724
747
  DSH_SHELL: "1",
725
748
  DSH_SESSION_ID: spec.owner.id,
726
749
  DSH_PTY_SESSION_ID: spec.sessionId
727
750
  };
751
+ if (dialect === "pwsh") return {
752
+ ...common,
753
+ NO_COLOR: "1"
754
+ };
755
+ return {
756
+ ...common,
757
+ PS1: CONTROLLED_PROMPT,
758
+ PROMPT_COMMAND: `printf "\\033]133;D;%s\\007" "$?"; PS1='${CONTROLLED_PROMPT}'`,
759
+ BASH_SILENCE_DEPRECATION_WARNING: "1"
760
+ };
728
761
  }
762
+ /**
763
+ * The pwsh prompt function that emits the shared OSC `133;D;` + BEL marker
764
+ * before every prompt, mirroring bash's PROMPT_COMMAND. `[char]27`/`[char]7`
765
+ * build the control bytes at runtime because raw ESC characters in submitted
766
+ * input are unreliable under PSReadLine.
767
+ */
768
+ const PWSH_PROMPT_SETUP = "function prompt { [Console]::Write([char]27 + ']133;D;' + [int]$LASTEXITCODE + [char]7); 'dsh> ' }";
729
769
  function spawnArgv(ctx, config, policy) {
730
770
  const argv = [config.shellPath, ...config.shellArgs];
731
771
  if (policy.mode === "danger-full-access") return argv;
@@ -736,9 +776,33 @@ function spawnArgv(ctx, config, policy) {
736
776
  mode: policy.mode
737
777
  }).argv;
738
778
  }
739
- async function initializeSession(session, signal) {
779
+ async function startupSession(session, dialect, signal) {
780
+ const start = async () => {
781
+ if (dialect === "bash") {
782
+ await session.initialize(signal);
783
+ return;
784
+ }
785
+ let viewport = "";
786
+ for (;;) {
787
+ const first = viewport.length === 0;
788
+ const result = await session.startSend({
789
+ text: first ? ENCODING_PREAMBLE + PWSH_PROMPT_SETUP : "",
790
+ submit: first,
791
+ ...signal !== void 0 ? { signal } : {}
792
+ }).done;
793
+ if (result.waitReason === "session_exit") throw new Error("PTY shell exited during startup");
794
+ if (result.waitReason === "timeout") throw new Error("PTY shell did not reach readiness before startup timeout");
795
+ viewport = result.viewport;
796
+ const scrollback = session.read({
797
+ offset: 0,
798
+ count: 20
799
+ }).text;
800
+ if (viewport.includes("dsh> ") || scrollback.includes("dsh> ")) break;
801
+ }
802
+ session.motd = viewport;
803
+ };
740
804
  if (signal === void 0) {
741
- await session.initialize(signal);
805
+ await start();
742
806
  return;
743
807
  }
744
808
  const aborted = Promise.withResolvers();
@@ -748,7 +812,7 @@ async function initializeSession(session, signal) {
748
812
  signal.addEventListener("abort", onAbort, { once: true });
749
813
  try {
750
814
  signal.throwIfAborted();
751
- await Promise.race([session.initialize(signal), aborted.promise]);
815
+ await Promise.race([start(), aborted.promise]);
752
816
  } finally {
753
817
  signal.removeEventListener("abort", onAbort);
754
818
  }
@@ -776,7 +840,7 @@ var BashTerminalBackend = class {
776
840
  const terminal = await this.spawnTerminal({
777
841
  argv,
778
842
  cwd: spec.cwd ?? policy.workspaceRoot,
779
- env: childEnvironment(spec),
843
+ env: childEnvironment(spec, this.config.shellDialect),
780
844
  rows: this.config.rows,
781
845
  cols: this.config.cols,
782
846
  graceMs: this.config.disposeGraceMs,
@@ -784,7 +848,7 @@ var BashTerminalBackend = class {
784
848
  });
785
849
  const session = this.createSession(terminal, this.config);
786
850
  try {
787
- await initializeSession(session, spec.signal);
851
+ await startupSession(session, this.config.shellDialect, spec.signal);
788
852
  return session;
789
853
  } catch (error) {
790
854
  try {
@@ -798,8 +862,9 @@ var BashTerminalBackend = class {
798
862
  };
799
863
  /** Register the local PTY backend. */
800
864
  function apply(ctx, config) {
801
- validateConfig(config);
802
- ctx.terminals.registerBackend(new BashTerminalBackend(ctx, config));
865
+ const resolved = resolveConfig(config);
866
+ validateConfig(resolved);
867
+ ctx.terminals.registerBackend(new BashTerminalBackend(ctx, resolved));
803
868
  }
804
869
  //#endregion
805
- export { BashTerminalBackend, Config, apply, inject, name };
870
+ export { BashTerminalBackend, Config, PWSH_PROMPT_SETUP, apply, inject, name };
@@ -1,12 +1,16 @@
1
1
  /** Validated configuration for the local PTY backend. */
2
2
  import z from '@deepseek-ai/schemastery';
3
+ /** One supported interactive shell dialect. */
4
+ export type ShellDialect = 'bash' | 'pwsh';
3
5
  /** Public plugin configuration. */
4
6
  export interface Config {
5
7
  /** Backend registry type (default: `shell`). */
6
8
  backendType?: string;
7
- /** Interactive shell executable (default: `/bin/bash`). */
9
+ /** Interactive shell dialect (default: `bash`); selects the argv/env/startup defaults. */
10
+ shellDialect?: ShellDialect;
11
+ /** Interactive shell executable (default per dialect: `/bin/bash`, or the resolved pwsh). */
8
12
  shellPath?: string;
9
- /** Shell arguments (default: `--noprofile --norc -i`). */
13
+ /** Shell arguments (default per dialect: bash `--noprofile --norc -i`, pwsh `-NoLogo -NoProfile`). */
10
14
  shellArgs?: string[];
11
15
  /** Terminal rows. */
12
16
  rows?: number;
@@ -34,12 +38,32 @@ export interface Config {
34
38
  /** Grace before teardown escalates to `SIGKILL`. */
35
39
  disposeGraceMs?: number;
36
40
  }
37
- /** Configuration after Schemastery defaults. */
38
- export type ResolvedConfig = Required<Config>;
41
+ /** Configuration after Schemastery defaults and dialect resolution. */
42
+ export type ResolvedConfig = Omit<Required<Config>, 'shellDialect' | 'shellPath' | 'shellArgs'> & {
43
+ shellDialect: ShellDialect;
44
+ shellPath: string;
45
+ shellArgs: string[];
46
+ };
47
+ /** Bash dialect default executable. */
48
+ export declare const DEFAULT_BASH_SHELL = "/bin/bash";
49
+ /** Bash dialect default arguments (interactive, profile-free). */
50
+ export declare const DEFAULT_BASH_ARGS: string[];
51
+ /** Pwsh dialect default arguments (interactive host, profile-free). */
52
+ export declare const DEFAULT_PWSH_ARGS: string[];
53
+ /**
54
+ * Resolve the effective per-dialect shell specification. Defaulting is this
55
+ * explicit step: an unset or empty `shellPath`/`shellArgs` selects the
56
+ * dialect's defaults, while a non-empty explicit value always wins.
57
+ * (Schemastery materializes an absent optional array as `[]`, so emptiness —
58
+ * not just `undefined` — means "dialect default".)
59
+ * @param config - Schemastery-resolved plugin configuration.
60
+ * @returns the fully resolved configuration.
61
+ */
62
+ export declare function resolveConfig(config: Config): ResolvedConfig;
39
63
  /** Schemastery config exposed by the plugin. */
40
64
  export declare const Config: z<Config>;
41
65
  /**
42
- * Assert every numeric config field is a positive safe integer and bounds compose.
66
+ * Assert every effective numeric config field is a positive safe integer and bounds compose.
43
67
  * @param config - Schemastery-resolved plugin configuration.
44
68
  * @returns Narrows the input to the fully resolved configuration.
45
69
  */
@@ -14,6 +14,13 @@ export type { Config as TerminalLocalConfig } from './config.ts';
14
14
  export declare const name = "terminal-bash";
15
15
  /** Required services: PTY registry, shared confinement policy, and process substrate. */
16
16
  export declare const inject: string[];
17
+ /**
18
+ * The pwsh prompt function that emits the shared OSC `133;D;` + BEL marker
19
+ * before every prompt, mirroring bash's PROMPT_COMMAND. `[char]27`/`[char]7`
20
+ * build the control bytes at runtime because raw ESC characters in submitted
21
+ * input are unreliable under PSReadLine.
22
+ */
23
+ export declare const PWSH_PROMPT_SETUP: string;
17
24
  /** Local shell backend registered under the configured type. */
18
25
  export declare class BashTerminalBackend implements TerminalBackend {
19
26
  private readonly ctx;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-terminal-bash",
3
3
  "description": "Persistent shell PTY backend over the DeepSeek Harness subprocess terminal primitive",
4
- "version": "0.1.0-rc.7",
4
+ "version": "0.1.0-rc.8",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -32,27 +32,28 @@
32
32
  ],
33
33
  "license": "MIT",
34
34
  "peerDependencies": {
35
- "@deepseek-ai/dsh-agent": "^0.1.0-rc.7",
36
- "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7",
37
- "@deepseek-ai/dsh-terminal": "^0.1.0-rc.7",
38
- "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.7",
39
- "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.7",
40
- "@deepseek-ai/dsh-session": "^0.1.0-rc.7",
41
- "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.7",
35
+ "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8",
36
+ "@deepseek-ai/dsh-terminal": "^0.1.0-rc.8",
37
+ "@deepseek-ai/dsh-agent": "^0.1.0-rc.8",
38
+ "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8",
39
+ "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8",
40
+ "@deepseek-ai/dsh-session": "^0.1.0-rc.8",
41
+ "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.8",
42
42
  "@deepseek-ai/cordis": "^4.0.1"
43
43
  },
44
44
  "dependencies": {
45
+ "@deepseek-ai/dsh-pwsh-local": "^0.1.0-rc.8",
45
46
  "@deepseek-ai/schemastery": "^3.18.1"
46
47
  },
47
48
  "devDependencies": {
48
- "@deepseek-ai/dsh-agent": "^0.1.0-rc.7",
49
- "@deepseek-ai/dsh-terminal": "^0.1.0-rc.7",
50
- "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.7",
51
- "@deepseek-ai/dsh-session": "^0.1.0-rc.7",
52
- "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.7",
53
- "@deepseek-ai/dsh-subprocess-local": "^0.1.0-rc.7",
54
- "@deepseek-ai/cordis": "^4.0.1",
55
- "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.7",
56
- "@deepseek-ai/dsh-invariants": "^0.1.0-rc.7"
49
+ "@deepseek-ai/dsh-agent": "^0.1.0-rc.8",
50
+ "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8",
51
+ "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8",
52
+ "@deepseek-ai/dsh-terminal": "^0.1.0-rc.8",
53
+ "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8",
54
+ "@deepseek-ai/dsh-session": "^0.1.0-rc.8",
55
+ "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.8",
56
+ "@deepseek-ai/dsh-subprocess-local": "^0.1.0-rc.8",
57
+ "@deepseek-ai/cordis": "^4.0.1"
57
58
  }
58
59
  }