better-dsh 0.3.0-e → 0.3.0-g

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 CHANGED
@@ -47,28 +47,29 @@ dsh runtime package dependencies**: only `@deepseek-ai/cordis` (peer),
47
47
  dependency imports external (`dts: { resolve: false }`): bundled copies
48
48
  would create duplicate type identities in a consumer's program.
49
49
 
50
- ## Native Web defaults
50
+ ## Native Web policies
51
51
 
52
52
  The bundle owns native DSH Web policies as independently toggleable components.
53
53
  `dashr-web-trust` accepts authenticated serving Host/Origin values while retaining
54
- native cookie authentication. `dashr-webserver` inherits the native server and
55
- waits for welcome confirmation before listening; its default address is
56
- `0.0.0.0`, with the native port and CLI override behavior preserved.
54
+ native cookie authentication. The native WebServer and HMR remain in place;
55
+ Better contributes WebTrust, mobile behavior and its password page through the
56
+ public WebServer interfaces. Listener address and port follow native CLI policy.
57
57
  Automatic credential onboarding is disabled; users can still configure models.
58
58
 
59
- `dashr-welcome-notice` reads the current `WELCOME_NOTICE_VERSION` from the Models
60
- client belonging to the actual DSH installation and acknowledges it through the
61
- original General settings namespace before the first HTTP read. No version is
62
- pinned in the plugin. Ordinary version bumps adapt at startup; changed private
63
- symbols or build layouts fail explicitly. Restore native welcome behavior with:
59
+ `dashr-welcome-notice` shadows only the native `welcome-notice` onboarding entry
60
+ at a higher precedence and calls the shell's public completion callback every
61
+ time it mounts, including new chats and explicitly reopened notices. It renders
62
+ no dialog and writes no native acknowledgement state. Disabling the component
63
+ withdraws its client contribution and restores the native welcome item; other
64
+ onboarding steps retain their own behavior.
64
65
 
65
66
  ```yaml
66
67
  - id: dashr-welcome-notice
67
68
  disabled: true
68
69
  ```
69
70
 
70
- The sibling Super Dash pack builds this repository locally and embeds its actual
71
- tarball. Better Dash remains independently installable. `../dev-webmcp` is an
71
+ Super Dash installs Better through the native Plugin Manager as a separate
72
+ bundle. Better Dash remains independently installable. `../dev-webmcp` is an
72
73
  unshipped development-only bundle owned by this repository.
73
74
 
74
75
  ## Install
package/cordis.patch.yml CHANGED
@@ -68,7 +68,7 @@
68
68
  - id: dashr-web-password
69
69
  name: 'better-dsh/web-password'
70
70
 
71
- # Automatically acknowledge the installed Host's current welcome version.
71
+ # Skip native welcome selections through the client's public onboarding slot.
72
72
  # Single-row opt-out: dashr-welcome-notice: disabled.
73
73
  - id: dashr-welcome-notice
74
74
  name: 'better-dsh/welcome-notice'
@@ -101,35 +101,7 @@
101
101
  config:
102
102
  trustedHosts: !!js (process.env.DSH_TRUSTED_HOSTS ?? '').split(/\s+/).filter(Boolean).concat(ctx.webRuntime.trustedHosts)
103
103
 
104
- # Replacement uses the public patch mechanism: disable the native provider,
105
- # then insert a distinct row providing the same native webServer service.
106
- - id: webserver
107
- name: '@deepseek-ai/dsh-host-webserver'
108
- disabled: true
109
- - insert:
110
- - id: dashr-webserver
111
- name: 'better-dsh/webserver'
112
- inject: [webStartup]
113
- config:
114
- host: !!js ctx.webStartup.host ?? '0.0.0.0'
115
- port: !!js ctx.webStartup.port ?? 3080
116
- compression: gzip
117
- compressionLevel: 1
118
- compressionThresholdBytes: 1024
119
-
120
104
  - id: ui-settings-models
121
105
  name: '@deepseek-ai/dsh-client-ui-settings-models'
122
106
  config:
123
107
  credentialOnboarding: false
124
-
125
- # Native watcher/queue with scoped transaction context across listener replacement.
126
- # Distinct row preserves whole-bundle disablement in the native manager.
127
- - id: hmr
128
- name: '@deepseek-ai/dsh-hmr'
129
- disabled: true
130
- - insert:
131
- - id: dashr-hmr
132
- name: 'better-dsh/hmr'
133
- disabled: !!js "!ctx.get('profileContext')"
134
- config:
135
- root: []
@@ -0,0 +1,40 @@
1
+ # ADR 0015 — Independent bundles and Agent-owned remote tools
2
+
3
+ Status: accepted design (2026-10-10); consumer acceptance tracked separately.
4
+
5
+ ## Context
6
+
7
+ The October 9 user decision supersedes ADR 0014's npm dependency architecture. Better Dash and Super Dash are independent native DSH bundles at synchronized versions. Their independent disable/uninstall choices must remain meaningful.
8
+
9
+ ## Decision
10
+
11
+ - Super has no Better npm dependency, optional dependency or peer edge. The native Plugin Manager companion operation requests `better-dsh@<installed Super version>`, then `latest`, then the bare name. Existing installation and user choices are preserved; Super upgrade does not reinstall a removed companion. The same native operation serves Settings explicit installation.
12
+ - `better-dsh/src/remote/` is the sole editable enhanced-remote source. The build generates Super's self-contained `remote/` ESM/declarations and source SHA-256 provenance, exposed by `super-dsh/remote`. This narrow exception carries neither the Better bundle, client, other tools nor a runtime dependency on Better. Host modules remain external optional peers and single-instance.
13
+ - Both remote rows default on. Official Agent creation events allow the first enabled row to own registration for that Agent instance. A loser does not retry. Winner unload cleans its Agent resources; it does not trigger automatic hot takeover. New Agent creation and cold resume can compete again.
14
+ - Hub is optional and independent of native remote registration. Hub-body authenticated executors do not depend on the model-facing remote row. No machine availability poller or second background job registry is introduced.
15
+
16
+ ## Consequences and verification
17
+
18
+ Pack validation covers exports, generated closure/provenance, host externalization, and absence of Better payload/dependency edges. Consumer acceptance must additionally exercise Super's worker while Better is absent, independent Plugin Manager transitions, actual tools and model-visible recovery guidance. Source tests or mounted plugin rows are not substitutes.
19
+
20
+ See [the feature specification](../specs/remote-tool-enhancement/spec.md), [delivery guide §8](../07-cordis-dsh-dev-test-guides.md#8-better-dash-双构建与原生-companion-交付2026-10-09-再修订), and the dated acceptance report. ADR 0014 and its historical reports are preserved as evidence of the former design.
21
+
22
+
23
+ ### 2026-10-10 consumer worker delivery correction
24
+
25
+ The generated Super `remote/` contains exactly `plugin.js`, `plugin.d.ts`, private `file-worker.js`, and `provenance.json`. The worker leaf is built solely from canonical `better-dsh/src/remote/file-worker.ts`, has Node-builtins-only imports, and is hashed/checked with the closure. It has no public package export, host peer imports, duplicated host modules, source loader or Better dependency. The public plugin contract remains unchanged. The existing owned child-process/group cleanup remains the receiver boundary; no worker-thread lifecycle replacement. This narrow extra generated leaf fixes actual installed receiver resolution, not a general guarantee that host plugins import outside their host resolver.
26
+
27
+ ### Receiving ownership and two-remote byte route (Rulings22–25)
28
+
29
+ SSH and canonical Docker/Incus oneshots share the portable receiving gate/control/work owner, preserving official jobs and Agent/plugin ownership. Container helpers additionally self-enable unprivileged child-subreaping before work to reap only their own/adopted descendants. Actual receiving helper/group cleanup precedes settlement; unavailable final transport drain is diagnosed honestly. Prerequisites and three-startup cost are explicit in the tool Surface.
30
+
31
+ Ruling25 supersedes the original two-remote source -R/private-master/sshd-FD/pidfd design after actual default dev3 source failed its permission requirement. A task-owned portable Python loopback proxy, inside the existing receiving helper/group/lease, carries bounded binary frames over authenticated SSH work stdio to an origin TCP bridge into the destination -L tunnel. A real full-route @RSYNCD greeting precedes business admission. No source Linux /proc, pidfd, privileged sshd access or source forwarding permission is required; native find, native rsync and the existing portable Bash/Python/fcntl/shared-monotonic prerequisites remain. No origin Python, credentials on peers, copy fallback, lease increase or second registry. Five-byte type/length frames cap data at64KiB and Python queues at256KiB; one active connection, real backpressure and half-close, prior reader/socket close before next OPEN. Ordinary two-remote transfer measures12 SSH startups: source preflight+inspection clock/work3, relay source/destination preflight2, destination clock/daemon+tunnel2, source proxy clock/owner/work3, native source rsync clock/work2. Fault recovery adds only task-owned authenticated cleanup reconnects, never transfer retries. Same real helper/listener/group/metadata/tunnel/socket cleanup barrier; receiving progress remains an explicit assumption. Historical M permission failure remains in the acceptance report; current default-dev3-source source test passes, installed next-artifact proof is separate.
32
+
33
+
34
+ ### CLI binary receiving ownership (consumer correction, Ruling26)
35
+
36
+ Actual N native SSH copy cancellation settled while the remote import process and its unnamed staging file remained live under a finite work-channel EOF hold. CLI export/import/digest now reuse the canonical portable receiving owner, with raw binary work streams and the same counted lease, admission gate and authenticated recovery. Cancellation/failure waits for receiving helper/group/temp cleanup before local transport teardown/settlement. Normal success must completely drain the binary stream; the oneshot text lane's 2500ms incomplete-output rule does not apply. Archive validation, selected manifest digests, merge/no-delete behavior and canonical SSH identity/ProxyJump are unchanged. Local and Hub file lanes are unchanged.
37
+
38
+ This intentionally replaces the former Python-only minimum for CLI peers: Bash4.1+, Python3.7+ (macOS3.10+), Unix fcntl.flock/shared non-adjustable cross-process monotonic clock, mktemp/mv/rm/sleep; Linux containers also need stdlib ctypes and permitted unprivileged PR_SET_CHILD_SUBREAPER. No rsync or origin Python requirement, auto-install, second registry, fallback, peer polling or increased lease. Minimal Python-only peers no longer support this CLI lane; use a supported peer or authenticated Hub.
39
+
40
+ Each remote export/import/digest costs three native transport starts: clock, independent owner/control, literal binary work. Thus verified local→CLI or CLI→local costs six; CLI→CLI twelve. verify:false skips digest operations, reducing counts to three/three/six. Local/Hub operations do not contribute CLI starts. Fault recovery may add same-identity authenticated cleanup starts and may remain pending until genuine cleanup observation is possible. Artifact O must re-prove installed cancellation and complete binary integrity; N failures remain historical evidence.
@@ -0,0 +1,52 @@
1
+ # Remote tools
2
+
3
+ Better Dash and Super Dash each provide the native `remote` tool and REPL route. The first enabled provider owns each Agent; unloading it does not hot-transfer ownership. Start a new Agent or cold-resume after changing providers. Super works without Better; Hub transport is optional. See [ADR 0015](adr/0015-independent-bundles-agent-remote.md).
4
+
5
+ ## Choose a call
6
+
7
+ | Goal | Input |
8
+ | --- | --- |
9
+ | List locally known targets without dialing | `{}` |
10
+ | Probe one target | `{target:"ssh:alias"}` |
11
+ | Register an Agent-local SSH identity | `{target:"byossh:build",ssh:{host:"host",user:"user",key:"/origin/key"}}` |
12
+ | Stateless command and stdin | `{target:"byossh:build",cmd:"cat",stdin:"hello"}` |
13
+ | Stream a local script to fixed `bash -s` | `{target:"ssh:alias",script:"/absolute/script.sh"}` |
14
+ | Persistent shell | `{target:"ssh:alias",mode:"pty",cmd:"cd /tmp; export CHECK=ready"}` |
15
+ | Official background job | `{target:"ssh:alias",cmd:"long-command",run_in_background:true}` |
16
+ | Binary file/tree copy | `{action:"copy",src:"/absolute/source",dst:"ssh:alias:/absolute/destination",verify:true,mkdir:true}` |
17
+ | Preview native SSH delta sync | `{action:"rsync",src:"/absolute/source/",dst:"ssh:alias:/existing/destination/",dryRun:true,delete:false}` |
18
+
19
+ `script` cannot combine with cmd/stdin/spawn/PTY. Direct local command execution is not provided; use native local shell tools. Background jobs are oneshot-only, require the official jobs service/controller, and are read/killed with `job_output`/`job_kill`; they have no default foreground timeout. An explicit timeout still applies. SSH keys/config stay on the origin; BYO identities are not persisted across new/cold Agents. PTY backlog recovery and live probes are not part of this release.
20
+
21
+ Native/PTY output retains at most 4,000,000 UTF-16 units per stream; Hub oneshot retains 4 MiB bytes. Normal returned tails are smaller. Read `outputStats` units and dropped/returned counters rather than treating character counts as bytes. Discarded output is not recoverable after restart.
22
+
23
+ ## File safety and prerequisites
24
+
25
+ Copy supports local, SSH/byossh, Docker, Incus and authenticated Hub binary transports, not arbitrary BYO-PTY shells. CLI endpoints require the receiving-owner prerequisites below; Hub uses native Node. Copy fully stages on the origin before delivery, merges directories without deleting extras, and verifies SHA-256 over transferred entries only. `verify:false` skips the independent verification claim. Successful staging is removed; failure receipts identify retained diagnostic payload. Unsafe archive paths/types and symlink escapes (including preserved destination ancestors) are rejected.
26
+
27
+ Rsync is SSH-only (one endpoint may be local), with no copy fallback. Dry-run is the default; deletion is opt-in. The origin needs Bash/native rsync. SSH peers need Bash ≥4.1, Python ≥3.7 (macOS ≥3.10), Unix `fcntl.flock`, and a shared non-adjustable cross-process monotonic clock. Nothing auto-installs prerequisites. Two-remote source additionally needs native `find`. Its task-owned Python loopback proxy uses authenticated SSH stdio and an origin bridge into the destination `-L` tunnel; no source remote-forwarding permission, Linux `/proc`, pidfd or privileged sshd access is required. The full route must produce a real rsync greeting before transfer; no origin Python prerequisite is added. A normal two-remote operation uses 12 SSH startups (prerequisite/inspection, destination daemon+tunnel, source proxy owner/work and native sender); ambiguous admission can add authenticated cleanup reconnects, never transfer retries.
28
+
29
+ Two-remote relay uses an existing non-symlink destination directory; unsupported file/new/ambiguous paths and source symlinks are refused before transfer. Ordinary local↔SSH legs retain native path/link semantics. Native rsync stats/itemized changes report real delta behavior. Cancellation/disposal waits for owned cleanup. A startup channel lost before receipt may require restored authenticated connectivity to observe cleanup; recovery never restarts the transfer. Ordinary receiver progress is required, not a hard-real-time guarantee on a frozen host.
30
+
31
+ Hub addresses use `hub:<machine-id>` only when the optional provider is present; paired remote machines never mean self. Hub errors do not fall back to SSH. The runtime tool description carries the detailed current call and recovery contract.
32
+
33
+ ### Owned SSH command requirements
34
+
35
+ Foreground/background SSH and BYO-SSH oneshots, including scripts and literal stdin, use the same portable receiving owner. Remote requirements are Bash 4.1+, Python 3.7+ (macOS 3.10+ for the shared cross-process monotonic epoch), Unix `fcntl.flock`, and `mktemp`, `mv`, `rm`, `sleep`. Ordinary commands do **not** require rsync. No origin Python or Linux/pidfd requirement is added; PTY/BYO-PTY is unchanged.
36
+
37
+ Each oneshot uses three SSH startups: clock-only prerequisite, receiving control owner, and the work channel with untouched stdin/stdout/stderr. Native connection identity, port, key and ProxyJump stay canonical; agent forwarding and reusable multiplexing are disabled for these owned connections. Cleanup waits for the receiving helper and work process group, not merely local SSH exit. The existing 8-second receiving lease, counted 2-second renewals and 3.5-second ordinary-scheduling cleanup allowance also cover the gate. Ambiguous lost startup needs an authenticated same-identity observer; restore connectivity if cleanup observation remains pending. This assumes a progressing receiver, not hard real-time scheduling.
38
+
39
+ After cleanup proof the separate work stream gets up to 2500ms for final drain. If unavailable, the result explicitly diagnoses potentially incomplete output; counters only count received data. A successful normal completion drains the full work stream. No new registry, availability poller or job completion notifier is introduced.
40
+
41
+ ### Container oneshot ownership
42
+
43
+ Docker/Incus oneshots require the same Bash/Python/fcntl/shared-monotonic/core-utility receiver prerequisites and three native exec startups. Linux containers also require Python stdlib ctypes and permitted unprivileged PR_SET_CHILD_SUBREAPER; the helper reaps only its own/adopted descendants before settlement, including ordinary non-reaping PID1 containers. Nothing installs or changes images, privileges or configuration. PTY is unchanged.
44
+
45
+
46
+ ### CLI binary receiving ownership (consumer correction, Ruling26)
47
+
48
+ Actual N native SSH copy cancellation settled while the remote import process and its unnamed staging file remained live under a finite work-channel EOF hold. CLI export/import/digest now reuse the canonical portable receiving owner, with raw binary work streams and the same counted lease, admission gate and authenticated recovery. Cancellation/failure waits for receiving helper/group/temp cleanup before local transport teardown/settlement. Normal success must completely drain the binary stream; the oneshot text lane's 2500ms incomplete-output rule does not apply. Archive validation, selected manifest digests, merge/no-delete behavior and canonical SSH identity/ProxyJump are unchanged. Local and Hub file lanes are unchanged.
49
+
50
+ This intentionally replaces the former Python-only minimum for CLI peers: Bash4.1+, Python3.7+ (macOS3.10+), Unix fcntl.flock/shared non-adjustable cross-process monotonic clock, mktemp/mv/rm/sleep; Linux containers also need stdlib ctypes and permitted unprivileged PR_SET_CHILD_SUBREAPER. No rsync or origin Python requirement, auto-install, second registry, fallback, peer polling or increased lease. Minimal Python-only peers no longer support this CLI lane; use a supported peer or authenticated Hub.
51
+
52
+ Each remote export/import/digest costs three native transport starts: clock, independent owner/control, literal binary work. Thus verified local→CLI or CLI→local costs six; CLI→CLI twelve. verify:false skips digest operations, reducing counts to three/three/six. Local/Hub operations do not contribute CLI starts. Fault recovery may add same-identity authenticated cleanup starts and may remain pending until genuine cleanup observation is possible. Artifact O must re-prove installed cancellation and complete binary integrity; N failures remain historical evidence.
@@ -0,0 +1,203 @@
1
+ # Remote 工具 enhancement — 交付、生命周期与传输规格
2
+
3
+ - 日期:2026-10-10(Asia/Hong_Kong)
4
+ - 状态:2026-10-10 user 已审阅并明确授权执行;Task0–7 已独立审阅通过;Task8 完整双包消费者验收进行中,L 实装暴露的 worker/SSH cleanup 缺陷已进入修复验证。用户亲验与发布尚未放行。
5
+ - 输入:[2026-10-09 方向稿](../../10_plans/2026-10-09-remote-tool-optimization-directions.md)及 2026-10-10 会话裁决。
6
+ - 执行计划:[2026-10-10-remote-tool-enhancement.md](../../superpowers/plans/2026-10-10-remote-tool-enhancement.md)。本规格优先于方向稿的冲突条款。
7
+
8
+ ## 1. 目标与本轮范围
9
+
10
+ 为 Agent 提供省步骤、减少转义和连接错误的 remote 便利层。一个 `remote` 工具覆盖 SSH、Docker、Incus、BYO-PTY,以及 Super 在场时的 Hub machine。Super 和 Better 分别可独立交付,不因另一包关闭或卸载丢失自身代码。
11
+
12
+ 本轮实现 P0/P1:
13
+
14
+ 1. Better 单一源码、Super 构建副本;两条插件行默认开启,Agent 实例级一次注册竞争。
15
+ 2. 可选 Hub 接入、动态 machine 清单;无远端机器时 Hub 清单为空,不执行本机。
16
+ 3. oneshot `script` 文件载体与 Hub oneshot stdin parity。
17
+ 4. 取消 Hub 模型工具缺省/显式本机执行入口,保留执行服务端与本地文件端点。
18
+ 5. BYO-SSH 注册、复用及连接参数;BYO-PTY 保持既有语义。
19
+ 6. oneshot 后台作业复用 DSH 原生 jobs 的 identity、pull-delta、完成通知及取消。
20
+ 7. `copy` 跨受支持端点的二进制传输、校验与暂存清理。
21
+ 8. `rsync` 仅 SSH;两个远端经发起机的 SSH 隧道中继,身份不下放。
22
+ 9. 真实双包交付和模型 Surface 验收。
23
+
24
+ 后续范围,不在本轮实现:P2 PTY 已完成命令的 backlog/offset 续读;P3 运行中 probe。取消:3.5M 提醒、一次性 `ssh://` target、`cmd[]` fan-out、push stdout、非 SSH/混合 transport rsync、BYO-WebSocket/Docker/Incus、命令黑名单、额外文件管理工具、inline cmd 扩容。
25
+
26
+ ## 2. 包归属与交付
27
+
28
+ - 唯一可编辑源码:`better-dsh/src/remote/`。
29
+ - Super 构建时从该源码生成独立 remote 交付闭包,导出 `super-dsh/remote`。不复制 Better 整包、客户端、REPL、文档或其他工具;不建立 Super→Better 的 npm dependency/optional/peer 边。
30
+ - 生成目录及 provenance manifest 不手改;构建必须检查源码哈希与输出闭包,防止旧副本或跨包裸 import。
31
+ - Better 行保留 `id: dashr-remote`、`name: better-dsh/remote`;Super 新行 `id: superd-remote`、`name: super-dsh/remote`。两个 YAML id 不相同,两行默认开,模型工具名相同:`remote`。
32
+ - 不在 Super YAML 中禁用 Better remote,不写安装时脚本化的 profile enable/disable;已存在的用户开关选择保留。
33
+ - Super 的 companion 原生安装流程不改变;remote 是“Super 不携带 Better 文件”契约的窄范围自有源码复用例外,而不是恢复整包捆绑。
34
+ - 宿主模块继续 optional peer、真实类型和单实例契约;私有 schema 真实构建输入在生成闭包内解决,消费者不解析 Better 的 `#schemastery`。
35
+ - 根、Better、Super 同步版本;实现轮经 `npm run version:release -- <同步字母版本>` 和双 tarball 通道,不发布 registry。
36
+
37
+ ## 3. Agent 实例级注册
38
+
39
+ ### 3.1 上游事实
40
+
41
+ 当前上游 `tools.register()` 同步插入 scoped registry,同 scope 同名立即抛错,不是先收集后统一去重。`agent/created` 是 setup 完成后、首轮工作放行前的 serial lifecycle 事件。preset revision/generation 被多个 Agent 复用,不能假设每个 session 重跑 preset 插件。
42
+
43
+ 证据位置:
44
+
45
+ - `upstream/deepseek-harness/packages/core/tools/src/index.ts:1063`。
46
+ - `upstream/deepseek-harness/packages/core/scope/src/store.ts:43`。
47
+ - `upstream/deepseek-harness/packages/core/agent/src/runtime-types.ts:250`。
48
+ - `upstream/deepseek-harness/packages/preset/agent-preset-registry/src/index.ts:104`。
49
+ - `upstream/deepseek-harness/packages/api/session-controller/src/agent.ts:185`。
50
+
51
+ ### 3.2 行为
52
+
53
+ - host 插件行只安装生命周期监听器,不在全局工具作用域注册 `remote`。
54
+ - 每次 `agent/created`,两份行各自在该 Agent 的真实 scope 尝试注册工具。先成功者供该 Agent 使用,后者只跳过该实例。
55
+ - 不自行判断 new/cold resume,不存 session 启动类型、不记录“已退出/待命”状态;官方创建事件本身给出尝试时机。必要改动仅为把现有 host 全局注册移到此事件的 scoped 注册,并局部处理同名冲突。
56
+ - 不保证 Super 优先,不按 UI/YAML 展示顺序推断赢家。两份相同源码均可接入 Hub,赢家不影响能力集合。
57
+ - 只处理实际的 `remote` 重名冲突,其他 schema、生命周期、服务异常继续抛出;不吞掉所有错误。
58
+ - 重名跳过不写 `disabled`,不让 host 行变成失败状态,也不使 Agent 创建失败。
59
+ - 注册、driver、PTY、BYO-SSH label 及 jobs 同时归该 Agent scope 和来源插件行所有:任一 owner 退出都撤注册并清理资源;不能仅依附 Agent 而留下已卸载包的执行闭包。
60
+ - 不轮询、不设接管队列、不在空位出现时重试。已存活 Agent 中途卸载赢家,当前实例不自动补位。
61
+ - new session 和 cold resume 创建新 Agent 时重新尝试;hot continuation、重开页面、给存活会话发消息不重试。
62
+ - 首轮插件热安装不追溯给既有 Agent 补注册,Surface 提示新建会话或 cold resume;普通 disable→enable 若该插件本身支持恢复,须记录实际窗口,不承诺热接管。
63
+ - foreign runtime 的既有 Hub 注入面与 native `remote` 不混淆:本轮不宣称所有 foreign agent 直接拥有 DSH scoped remote 工具。
64
+
65
+ ## 4. 可选 Hub 能力
66
+
67
+ Better 不 import Super 包。共享 remote 定义 owned structural contract;Super 在官方 Cordis scope 提供 `superdRemoteTransport`,remote 用 `ctx.get()` 在能力消费时可选取得。absence 不形成硬 inject 等待,不修改宿主。
68
+
69
+ - provider 在场 → 工具描述与 roster 说明 `hub:<machineId>`;机器目录可为空。机器变化只改变 roster,不增删 target 字段。
70
+ - provider 不在场 → SSH/Docker/Incus/BYO 继续可用,Hub target 返回有恢复提示的 unavailable 错误,不静默改走 SSH。
71
+ - provider 的出现/消失通过官方服务通知更新模型 Surface;不检查 npm 包目录,不轮询各机器可达性。
72
+ - roster 来自 pairing 表中的远端 m4,排除 self;执行时检查 unknown machine、`execEnabled` 与连接错误,保留原始原因。
73
+ - 远端执行服务端和文件 transport 随 Hub 本体提供,不依附模型侧 remote 行。关闭某台机器的工具行不应拆掉别人访问它的服务端。
74
+ - PTY 沿用现有 pairing cookie、auth/Host/Origin fence 与 WS executor。oneshot 沿用既有 authenticated RPC,不声称现有 HTTP exec 已改为 WS。
75
+ - 文件独立使用 binary WS lane;文本 PTY 不作为二进制文件通道。
76
+ - 对端旧版本无文件 lane 时明确 unsupported;不以 base64 手搓冒充新增能力。
77
+
78
+ ## 5. 执行入口
79
+
80
+ ### 5.1 script 与 stdin
81
+
82
+ `{ target, script: "/abs/local/script.sh", mode: "oneshot" }`:从工具所在运行时读文件,原文作为 `bash -s` 的 stdin。文件不要求能在目标机直接访问,不把源码拼入 argv。
83
+
84
+ - `script`、`cmd`、`stdin` 的选择:script 与 cmd 互斥,script 与 stdin 互斥;stdin+cmd 沿用现有模式。
85
+ - script 首轮仅 oneshot,BYO-PTY 或 mode pty 请求在读文件/拨号前拒绝。
86
+ - 本地路径必须绝对、无 NUL;文件读取失败在连接/执行前报告。
87
+ - 不做 script 自带业务 stdin 的第二通道;需要数据时用文件/参数,或用 cmd+stdin。
88
+ - 保留 Hub inline cmd 4096 字符上限;script 固定命令短于上限,正文走 stdin。
89
+ - Hub API、wire sender、legacy Hub tool exec Surface 同步支持 string stdin;PTY 不把 legacy stdin 支持悄悄扩成 script 模式。
90
+
91
+ ### 5.2 local
92
+
93
+ - Hub 模型工具 exec 不再缺省本机;未传 machine 返回“请选择远端”提示,显式 self 默认也拒绝。
94
+ - `localExec` 配置默认 false,可作为显式兼容入口,但不替正常消费者加入测试专用业务守卫。
95
+ - 接收对端请求的本地 oneshot/PTY executor 保留;copy 的本地文件端点及读取 script 保留。
96
+
97
+ ### 5.3 输出
98
+
99
+ - native/PTy 现有 4,000,000 UTF-16 code units 与 Hub oneshot 4MiB byte ring 是不同单位,回执必须真实说明;本轮不配置化,不凭文案把两者说成同一精确 4MB。
100
+ - 保留约 30k 返回尾窗;统计总输出、保留量、已丢头部,超限明确标注。修复 native oneshot 现有收头却被上层当作尾窗的偏差。
101
+ - 单次 dispatch 重新计数;达到上限不要求重启 PTY,重启不能找回已丢数据。
102
+ - 不新增 3.5M 预警、输出预测或 push 监控。
103
+
104
+ ## 6. BYO-SSH
105
+
106
+ 调用形态:`{target:"byossh:label", ssh:{host,user?,port?,key?,proxyJump?}, cmd}`;首次注册连接,随后只用 target 复用。使用 `ssh` 字段而非复用现有 string `spawn`,避免破坏 BYO-PTY schema。
107
+
108
+ - label 归 Agent 实例;不改 `~/.ssh/config`,不持久化凭据,不接受 inline 私钥内容;key 是发起机已有文件路径。
109
+ - 首次可登记后执行或仅登记;复用相同参数幂等,不同参数给出冲突与换 label 提示。
110
+ - host、user、port、key、proxyJump 通过参数数组、受控 config 文件或官方 SSH options 编排,不能拼出第二层任意 shell。
111
+ - 所有执行、copy、rsync 和中继复用同一已解析 SSH connection spec,不能 rsync 又退回只读系统 alias。
112
+ - roster 区分 SSH config 与 byossh labels,不导出密钥、cookie 或完整凭据。
113
+
114
+ ## 7. oneshot jobs
115
+
116
+ `{target, cmd|script, run_in_background:true}` → 原生 jobId;读取/取消使用 DSH `job_output` / `job_kill`,完成由宿主通知。PTY mode 明确拒绝此选项。
117
+
118
+ - 使用官方 `ctx.jobs.start`、owner、JobHooks、output source/pump;不自建第二份 job registry、poller 或通知渠道。
119
+ - 子进程/远端任务在 job admission 后启动;启动被拒不能留下已经运行的进程。
120
+ - job 输出必须运行中真实增量可读,不能等 command 完成后才一次 append 全量。
121
+ - done 等到进程、远端任务及资源释放后结算;cancel 终止真实本地组/远端 job,不只把本地 Promise 标为取消。
122
+ - provider 需要对 Hub oneshot 提供 job-owned start/read/cancel/done 协议;仅 abort HTTP fetch 不视为远端取消。
123
+ - jobs service 不在场时同步 exec 仍可用,background 请求 fail-loud 并说明缺失的官方能力。
124
+ - 前台 timeout 保持现有上限;background 无前台等待截止但受 owner cancellation 和 job kill 管理。
125
+
126
+ ## 8. 文件操作
127
+
128
+ ### 8.1 寻址及能力边界
129
+
130
+ `{action:"copy", src, dst, verify:true, mkdir:true}` 与 `{action:"rsync", src, dst, delete:false, excludes:[], dryRun:true, preserve:true}`。
131
+
132
+ 端点使用 `[target:]绝对路径`;例如 `/tmp/a`、`ssh:dev3:/data/a`、`byossh:review:/data/a`、`docker:build:/data/a`、`hub:skc8:/data/a`。按最后一个 `:/` 边界解析 target/path,避免把 transport 前缀冒充 host。裸 label 的兼容解析复用 remote roster 规则,不另建命名系统。
133
+
134
+ - copy 首轮支持文件与目录的 local、SSH/byossh、Docker、Incus、Hub 端点;每条腿使用实际 binary stream,保持精确路径与明确的内容/目录语义。
135
+ - byop 是任意交互 shell,不保证 binary I/O 或 filesystem;copy/rsync 不承诺可用,拒绝并建议用显式 transport target。
136
+ - rm/mv/mkdir/chmod/stat 不增加 action;mkdir 仅 copy 的建父目录选项。
137
+ - 校验使用 SHA-256;目录使用排序、长度编码的相对路径/条目类型/内容 manifest,明确 symlink 不跟随,避免文件名含空白/换行破坏回执。
138
+ - 覆盖默认允许普通文件,目录合并无删除;不得悄悄把 copy 变为 rsync delete。路径/type 不兼容返回错误。
139
+
140
+ ### 8.2 copy 中转
141
+
142
+ 任意两远端通过工具所在发起机中转,各腿使用其已有 target 通道,不向其中一端复制另一端连接身份。中转采用任务级 `.scratch` 暂存,先收完整载体,再向目标发送;不宣称提供源到目标流式复制、delta 或断点恢复。
143
+
144
+ - 二进制 lane 需要 backpressure、传输错误/关闭、显式完成帧、有限 metadata/frame buffer 和 cancellation。
145
+ - tar/archive 或等价 carrier 在解包前验证成员路径,不接受绝对成员、`..` 出界或借 symlink 写出目标目录。
146
+ - `verify:true` 返回独立源/目标 hash 或 manifest digest、条目/字节统计、校验结果;数据端失败不能给成功回执。
147
+ - 中转任务成功后清理 owned 暂存;失败保留可诊断载体,回执给出位置和原因。保留不意味着自动重试。
148
+ - 远端临时进程、监听/临时接收文件必须取消/结束清理,不能因为“失败保留诊断”而留后台服务。
149
+ - `verify:false` 不显示已校验;successful transfer 也清理中转载体,不无限堆垃圾。
150
+
151
+ ### 8.3 SSH-only rsync
152
+
153
+ - 支持 local↔SSH,以及 SSH↔SSH;目标连接来自系统 SSH config 或 byossh 注册。
154
+ - 两个 remote 参数不能直接传给普通 rsync;工具负责变成原生 rsync 可接受的一端本地视角。
155
+ - remote↔remote 通过发起机建 SSH 隧道中继;一种实现为目标端短命 loopback rsync daemon + 发起机 local forward + 源端 reverse forward。rsync delta 算法仍为原生实现。
156
+ - 两端 identity 仅由发起机 SSH 进程使用;禁止复制 private key、导出登录凭据、ssh-agent forwarding 或修改远端 SSH config。
157
+ - daemon 仅绑定 loopback、模块限定目标目录,以当前登录用户启动;不安装永久 daemon,不公开监听。SSH 禁止 forwarding 时返回原始拒绝。
158
+ - `dryRun` 默认 true、`delete` 默认 false;`excludes`、preserve、trailing slash 内容语义通过参数表达。真正传输显式 dryRun false。
159
+ - 预检两端 rsync 和所需 SSH forwarding;缺失不静默 fallback copy,更不能对 delete/excludes 回报假成功。
160
+ - 捕获 rsync 原始退出码与 itemized changes,保持 stderr;非零不标成成功。
161
+ - 无论成功、失败、cancel 都清理 tunnel、短命 daemon 与本任务临时 config;复用 transport 不等于关掉用户既有 SSH 会话。
162
+
163
+ ## 9. 验收和完成定义
164
+
165
+ 代码、传统测试、打包成功只说明阶段进度,不等于产品验收。
166
+
167
+ 1. scoped 真实 Cordis/Agent fixture:双包仅一个 remote;Agent 创建不失败;非重名异常不被吞;不同 Agent 互不争抢;赢家卸载当前实例不补位;new/cold resume 可恢复;hot continuation 不假装恢复;退出清理。
168
+ 2. 单包 Better tarball:无 Super import/安装,SSH/Docker/Incus/BYO 按已有能力工作;jobs 缺失错误真实。
169
+ 3. Super tarball:禁用/卸载 Better 后 remote 仍可用;两包启用顺序相反都可用;Hub 存在但 machine 清单空的 Surface 正确;关闭模型工具行不拆 Hub executor。
170
+ 4. 4999 完整 launcher:安装双 tarball、真实模型 roster/script/stdin/PTY/后台任务/job_output/job_kill/copy/rsync 与错误恢复;工具 catalog 和 REPL 路由属于验收。
171
+ 5. dev3 同版本实际安装:配对但无 SSH 的 Hub PTY 与 binary copy;dev3↔另一 SSH 目标经发起机中继,远端无对方 key/config;第二次改少量内容证明真实 rsync delta;cancel/异常证明无残留。
172
+ 6. 记录上游实际 checkout、目标宿主版本、同步版本、tarball SHA-256、安装步骤、模型可见 Surface 和失败证据至 `docs/test-reports/`。
173
+ 7. Web 测试线保持运行,报告真实访问 URL,供 user 亲验。
174
+ 8. 不触碰生产 home/3080/3081/Caddy,不修改上游,不 npm publish、不 commit/tag/push 定版。发布需要本次单独放行。
175
+
176
+ ## 10. 书面确认边界
177
+
178
+ 本稿实现上述会话裁决,没有把 P2/P3、非 SSH rsync 或热接管重新塞入首轮。字段 `ssh`、端点解析、copy 的 BYO-PTY 不支持回执是保持已有接口并使交付可实现的具体化;user 可在书面规格审阅时修订。收到书面审阅后,按执行计划进入实现,不再为已批准的 routine 实现步骤重复请求授权。
179
+
180
+
181
+ ### 2026-10-10 consumer worker delivery correction
182
+
183
+ The generated Super `remote/` contains exactly `plugin.js`, `plugin.d.ts`, private `file-worker.js`, and `provenance.json`. The worker leaf is built solely from canonical `better-dsh/src/remote/file-worker.ts`, has Node-builtins-only imports, and is hashed/checked with the closure. It has no public package export, host peer imports, duplicated host modules, source loader or Better dependency. The public plugin contract remains unchanged. The existing owned child-process/group cleanup remains the receiver boundary; no worker-thread lifecycle replacement. This narrow extra generated leaf fixes actual installed receiver resolution, not a general guarantee that host plugins import outside their host resolver.
184
+
185
+ ### Task8 delivery correction: owned SSH oneshots (Ruling22)
186
+
187
+ Real consumer job-kill exposed local-only SSH termination. Foreground/background/script/stdin SSH oneshots therefore reuse the portable receiving sideband owner, preserving native literal stdio and connection normalization. Remote Bash4.1+, Python3.7+ (macOS3.10+), shared non-adjustable cross-process monotonic clock, Unix fcntl.flock and mktemp/mv/rm/sleep are required. Ordinary commands never require rsync; origin needs no Python, and this path needs no Linux/pidfd. Three SSH startups (clock, control, work), with authenticated same-identity cleanup reconnect after ambiguous startup; existing lease/bounds remain. Receiver helper/group cleanup precedes settlement, followed by up to2500ms work-stream drain; unavailable drain explicitly marks incomplete received output without fabricated counters. PTY/BYOPTY and rsync-specific restrictions remain unchanged. No second jobs registry or availability polling.
188
+
189
+
190
+ ### Task8 container oneshot ownership correction (Rulings23–24)
191
+
192
+ Actual installed Docker/Incus native job cancellation reported killed while receiving children remained live. Canonical oneshot foreground/background/script/stdin therefore share the SSH portable receiving gate/control/work barrier through native container exec argv, not local CLI termination. Each command requires three native exec startups (clock, owner, literal-stdio work), remote Bash4.1+, Python3.7+, Unix fcntl.flock/shared non-adjustable cross-process monotonic clock, mktemp/mv/rm/sleep. Linux containers additionally require stdlib ctypes and permitted unprivileged PR_SET_CHILD_SUBREAPER before business admission; the work helper reaps only its own/adopted children and stays alive until its work group is absent. This supports ordinary non-reaping PID1 containers without forcing --init, privilege/capability, image/config mutation, rsync, pidfd or origin Python. PTY/BYOPTY stay unchanged; SSH portable prerequisites are not broadened. The same eight-second counted lease, gate recovery, actual cleanup barrier and 2500ms honest final-output drain apply, with no enlarged grace, second job registry or availability polling. Consumer iteration N must prove real native killed status together with owned process/group/helper/state absence; M failures remain historical evidence.
193
+
194
+ Ruling25 supersedes the original two-remote source -R/private-master/sshd-FD/pidfd design after actual default dev3 source failed its permission requirement. A task-owned portable Python loopback proxy, inside the existing receiving helper/group/lease, carries bounded binary frames over authenticated SSH work stdio to an origin TCP bridge into the destination -L tunnel. A real full-route @RSYNCD greeting precedes business admission. No source Linux /proc, pidfd, privileged sshd access or source forwarding permission is required; native find, native rsync and the existing portable Bash/Python/fcntl/shared-monotonic prerequisites remain. No origin Python, credentials on peers, copy fallback, lease increase or second registry. Five-byte type/length frames cap data at64KiB and Python queues at256KiB; one active connection, real backpressure and half-close, prior reader/socket close before next OPEN. Ordinary two-remote transfer measures12 SSH startups: source preflight+inspection clock/work3, relay source/destination preflight2, destination clock/daemon+tunnel2, source proxy clock/owner/work3, native source rsync clock/work2. Fault recovery adds only task-owned authenticated cleanup reconnects, never transfer retries. Same real helper/listener/group/metadata/tunnel/socket cleanup barrier; receiving progress remains an explicit assumption. Historical M permission failure remains in the acceptance report; current default-dev3-source source test passes, installed next-artifact proof is separate.
195
+
196
+
197
+ ### CLI binary receiving ownership (consumer correction, Ruling26)
198
+
199
+ Actual N native SSH copy cancellation settled while the remote import process and its unnamed staging file remained live under a finite work-channel EOF hold. CLI export/import/digest now reuse the canonical portable receiving owner, with raw binary work streams and the same counted lease, admission gate and authenticated recovery. Cancellation/failure waits for receiving helper/group/temp cleanup before local transport teardown/settlement. Normal success must completely drain the binary stream; the oneshot text lane's 2500ms incomplete-output rule does not apply. Archive validation, selected manifest digests, merge/no-delete behavior and canonical SSH identity/ProxyJump are unchanged. Local and Hub file lanes are unchanged.
200
+
201
+ This intentionally replaces the former Python-only minimum for CLI peers: Bash4.1+, Python3.7+ (macOS3.10+), Unix fcntl.flock/shared non-adjustable cross-process monotonic clock, mktemp/mv/rm/sleep; Linux containers also need stdlib ctypes and permitted unprivileged PR_SET_CHILD_SUBREAPER. No rsync or origin Python requirement, auto-install, second registry, fallback, peer polling or increased lease. Minimal Python-only peers no longer support this CLI lane; use a supported peer or authenticated Hub.
202
+
203
+ Each remote export/import/digest costs three native transport starts: clock, independent owner/control, literal binary work. Thus verified local→CLI or CLI→local costs six; CLI→CLI twelve. verify:false skips digest operations, reducing counts to three/three/six. Local/Hub operations do not contribute CLI starts. Fault recovery may add same-identity authenticated cleanup starts and may remain pending until genuine cleanup observation is possible. Artifact O must re-prove installed cancellation and complete binary integrity; N failures remain historical evidence.
@@ -1,4 +1,4 @@
1
- import { b as ChromeReleaseChannel } from "./main-CKFNYpqT.js";
1
+ import { b as ChromeReleaseChannel } from "./main-CBC7_uE-.js";
2
2
 
3
3
  //#region node_modules/puppeteer-core/lib/puppeteer/node/LaunchOptions.js
4
4
  /**
@@ -0,0 +1,4 @@
1
+ import "./main-CBC7_uE-.js";
2
+ import { t as convertPuppeteerChannelToBrowsersChannel } from "./LaunchOptions-CLEBmZeM.js";
3
+
4
+ export { convertPuppeteerChannelToBrowsersChannel };
@@ -1,6 +1,6 @@
1
1
  import { n as __require } from "./chunk-DQxbwPpZ.js";
2
2
  import { A as stringToTypedArray, G as first, H as delayWhen, K as firstValueFrom, L as combineLatest, M as assert, Q as map, S as timeout, St as debug, Tt as environment, V as defer, W as filter, at as race, b as isString, bt as TouchError, c as evaluationString, d as fromEmitterEvent, g as isDate, gt as ProtocolError, h as getSourceUrlComment, ht as ConnectionClosedError, i as SOURCE_URL_REGEX, k as stringToBase64, lt as switchMap, m as getSourcePuppeteerURLIfAvailable, o as debugCatchError, ot as raceWith, q as from, r as PuppeteerURL, rt as of, s as debugError, u as fromAbortSignal, v as isPlainObject, vt as TargetCloseError, x as parsePDFOptions, xt as UnsupportedOperation, y as isRegExp, yt as TimeoutError } from "./util-BHL_dfV_.js";
3
- import { $n as Deferred, $t as scriptInjector, Bt as throwIfDetached, Ct as WebWorkerEvent, Dn as DeviceRequestPrompt, Dt as normalizeHeaderValue, Fn as Browser, Hn as DisposableStack, Ht as bindIsolatedHandle, In as WEB_PERMISSION_TO_PROTOCOL_PERMISSION, It as Dialog, Jn as CallbackRegistry, Kn as disposeSymbol, Ln as CDPSession, Lt as Accessibility, Mn as invokeAtMostOnceForArguments, Mt as InterceptResolutionAction, Nn as throwIfDisposed, Nt as STATUS_TEXTS, On as BrowserContext, Ot as SecurityDetails, Pt as handleError, Rt as Frame, St as WebWorker, Ut as JSHandle, Vt as ElementHandle, Zn as isErrorLike, _t as Mouse, an as stringifyFunction, cn as Tracing, dt as ConsoleMessage, en as ARIAQueryHandler, fn as Coverage, gt as Keyboard, ht as TargetType, in as interpolateFunction, jn as inertIfDisposed, jt as HTTPRequest, kn as bubble, kt as HTTPResponse, mn as Page, mt as Target, nn as LazyArg, on as AsyncIterableUtil, sn as FileChooser, un as EmulationManager, vt as MouseButton, wt as Realm, yt as Touchscreen, zn as EventEmitter } from "./index-browser-Bp3vxHC3.js";
3
+ import { $n as Deferred, $t as scriptInjector, Bt as throwIfDetached, Ct as WebWorkerEvent, Dn as DeviceRequestPrompt, Dt as normalizeHeaderValue, Fn as Browser, Hn as DisposableStack, Ht as bindIsolatedHandle, In as WEB_PERMISSION_TO_PROTOCOL_PERMISSION, It as Dialog, Jn as CallbackRegistry, Kn as disposeSymbol, Ln as CDPSession, Lt as Accessibility, Mn as invokeAtMostOnceForArguments, Mt as InterceptResolutionAction, Nn as throwIfDisposed, Nt as STATUS_TEXTS, On as BrowserContext, Ot as SecurityDetails, Pt as handleError, Rt as Frame, St as WebWorker, Ut as JSHandle, Vt as ElementHandle, Zn as isErrorLike, _t as Mouse, an as stringifyFunction, cn as Tracing, dt as ConsoleMessage, en as ARIAQueryHandler, fn as Coverage, gt as Keyboard, ht as TargetType, in as interpolateFunction, jn as inertIfDisposed, jt as HTTPRequest, kn as bubble, kt as HTTPResponse, mn as Page, mt as Target, nn as LazyArg, on as AsyncIterableUtil, sn as FileChooser, un as EmulationManager, vt as MouseButton, wt as Realm, yt as Touchscreen, zn as EventEmitter } from "./index-browser-pHtsz007.js";
4
4
  import "./BrowserWebSocketTransport-wm99h94r.js";
5
5
 
6
6
  //#region node_modules/mitt/dist/mitt.mjs
@@ -650,6 +650,28 @@ function setupCompactionRow(ctx) {
650
650
  })), "compaction-tuning: served settings row");
651
651
  }
652
652
 
653
+ //#endregion
654
+ //#region src/welcome-notice/client/index.ts
655
+ /** Complete each newly selected notice without persisting native acknowledgement state. */
656
+ function SkipWelcomeNotice({ complete }) {
657
+ const completed = (0, react.useRef)(false);
658
+ (0, react.useEffect)(() => {
659
+ if (completed.current) return;
660
+ completed.current = true;
661
+ complete();
662
+ }, [complete]);
663
+ return null;
664
+ }
665
+ /** A package client can outlive this independently toggleable Host component. */
666
+ function setupWelcomeNotice(ctx) {
667
+ ctx.effect(() => ctx.configForms.whileServed(["dashr-welcome-notice"], () => ctx.slots.inject("settings.onboarding", () => ctx.slots.register({
668
+ name: "settings.onboarding",
669
+ id: "welcome-notice",
670
+ priority: -1,
671
+ order: -100
672
+ }, SkipWelcomeNotice))), "welcome notice: served skip policy");
673
+ }
674
+
653
675
  //#endregion
654
676
  //#region src/failover/client/index.ts
655
677
  /** Required services (cordis fiber inject). */
@@ -672,6 +694,7 @@ function apply(ctx) {
672
694
  }), "llm-failover: dictionaries");
673
695
  setupMobileLayout(ctx);
674
696
  setupCompactionRow(ctx);
697
+ setupWelcomeNotice(ctx);
675
698
  ctx.effect(() => ctx.configForms.whileServed([FAILOVER_SETTINGS_ENTRY], () => ctx.slots.inject("settings.general.item", function* () {
676
699
  yield ctx.slots.register({
677
700
  name: "settings.general.item",
@@ -20792,7 +20792,7 @@ async function _connectToBiDiBrowser(connectionTransport, url, options) {
20792
20792
  const { bidiConnection, cdpConnection, closeCallback } = await getBiDiConnection(connectionTransport, url, options);
20793
20793
  return await (await import(
20794
20794
  /* webpackIgnore: true */
20795
- "./bidi-CwtLGgcA.js"
20795
+ "./bidi-Bs8owg1e.js"
20796
20796
  )).BidiBrowser.create({
20797
20797
  connection: bidiConnection,
20798
20798
  cdpConnection,
@@ -20815,7 +20815,7 @@ async function _connectToBiDiBrowser(connectionTransport, url, options) {
20815
20815
  async function getBiDiConnection(connectionTransport, url, options) {
20816
20816
  const BiDi = await import(
20817
20817
  /* webpackIgnore: true */
20818
- "./bidi-CwtLGgcA.js"
20818
+ "./bidi-Bs8owg1e.js"
20819
20819
  );
20820
20820
  const { slowMo = 0, protocolTimeout, idGenerator = createIncrementalIdGenerator() } = options;
20821
20821
  const pureBidiConnection = new BiDi.BidiConnection(url, connectionTransport, idGenerator, slowMo, protocolTimeout);
@@ -20887,10 +20887,10 @@ async function getConnectionTransport(options) {
20887
20887
  endpointUrl: connectionURL
20888
20888
  };
20889
20889
  } else if (options.channel && isNode) {
20890
- const { detectBrowserPlatform, resolveDefaultUserDataDir, Browser: Browser$1 } = await import("./main-BXwPLuYr.js");
20890
+ const { detectBrowserPlatform, resolveDefaultUserDataDir, Browser: Browser$1 } = await import("./main-RqgDOjH9.js");
20891
20891
  const platform = detectBrowserPlatform();
20892
20892
  if (!platform) throw new Error("Could not detect required browser platform");
20893
- const { convertPuppeteerChannelToBrowsersChannel } = await import("./LaunchOptions-3peHoOAx.js");
20893
+ const { convertPuppeteerChannelToBrowsersChannel } = await import("./LaunchOptions-CjYFNZFS.js");
20894
20894
  const { join } = await import("node:path");
20895
20895
  const portPath = join(resolveDefaultUserDataDir(Browser$1.CHROME, platform, convertPuppeteerChannelToBrowsersChannel(options.channel)), "DevToolsActivePort");
20896
20896
  try {
@@ -1,12 +1,14 @@
1
1
  import { createHash } from "node:crypto";
2
- import fs, { accessSync, constants, existsSync, readFileSync } from "node:fs";
2
+ import fs, { accessSync, constants, createReadStream, createWriteStream, existsSync, readFileSync } from "node:fs";
3
3
  import path from "node:path";
4
4
  import childProcess, { execFile, execSync, spawn, spawnSync } from "node:child_process";
5
5
  import os from "node:os";
6
6
  import readline from "node:readline";
7
7
  import { URL as URL$1, urlToHttpOptions } from "node:url";
8
8
  import { debuglog, promisify } from "node:util";
9
- import { mkdir, readdir, unlink } from "node:fs/promises";
9
+ import { mkdir, readdir, symlink, unlink } from "node:fs/promises";
10
+ import { pipeline } from "node:stream/promises";
11
+ import { Writable } from "node:stream";
10
12
  import { EventEmitter } from "node:events";
11
13
  import * as http from "node:http";
12
14
  import * as https from "node:https";
@@ -1,3 +1,3 @@
1
- import { _ as Browser, a as TimeoutError, b as ChromeReleaseChannel, c as computeSystemExecutablePath, d as InstalledBrowser, f as detectBrowserPlatform, g as resolveDefaultUserDataDir, h as resolveBuildId, i as Process, l as launch, m as getVersionComparator, n as uninstall, o as WEBDRIVER_BIDI_WEBSOCKET_ENDPOINT_REGEX, p as createProfile, r as CDP_WEBSOCKET_ENDPOINT_REGEX, s as computeExecutablePath, t as getInstalledBrowsers, u as Cache, v as BrowserPlatform, y as BrowserTag } from "./main-CKFNYpqT.js";
1
+ import { _ as Browser, a as TimeoutError, b as ChromeReleaseChannel, c as computeSystemExecutablePath, d as InstalledBrowser, f as detectBrowserPlatform, g as resolveDefaultUserDataDir, h as resolveBuildId, i as Process, l as launch, m as getVersionComparator, n as uninstall, o as WEBDRIVER_BIDI_WEBSOCKET_ENDPOINT_REGEX, p as createProfile, r as CDP_WEBSOCKET_ENDPOINT_REGEX, s as computeExecutablePath, t as getInstalledBrowsers, u as Cache, v as BrowserPlatform, y as BrowserTag } from "./main-CBC7_uE-.js";
2
2
 
3
3
  export { Browser, BrowserPlatform, BrowserTag, CDP_WEBSOCKET_ENDPOINT_REGEX, Cache, ChromeReleaseChannel, InstalledBrowser, Process, TimeoutError, WEBDRIVER_BIDI_WEBSOCKET_ENDPOINT_REGEX, computeExecutablePath, computeSystemExecutablePath, createProfile, detectBrowserPlatform, getInstalledBrowsers, getVersionComparator, launch, resolveBuildId, resolveDefaultUserDataDir, uninstall };
@@ -1,5 +1,5 @@
1
1
  import { t as Schema } from "../index-DTDXUe6m.js";
2
- import { r as MobileConfig } from "../web-trust-C_Y6o8Z2.js";
2
+ import { r as MobileConfig } from "../web-trust-RwK0P74B.js";
3
3
  import { Context } from "@deepseek-ai/cordis";
4
4
 
5
5
  //#region src/mobile/plugin.d.ts
@@ -1,8 +1,8 @@
1
- import { _ as Browser$1, a as TimeoutError$1, c as computeSystemExecutablePath, f as detectBrowserPlatform, h as resolveBuildId, l as launch$1, n as uninstall, o as WEBDRIVER_BIDI_WEBSOCKET_ENDPOINT_REGEX, p as createProfile, r as CDP_WEBSOCKET_ENDPOINT_REGEX, s as computeExecutablePath, t as getInstalledBrowsers } from "./main-CKFNYpqT.js";
1
+ import { _ as Browser$1, a as TimeoutError$1, c as computeSystemExecutablePath, f as detectBrowserPlatform, h as resolveBuildId, l as launch$1, n as uninstall, o as WEBDRIVER_BIDI_WEBSOCKET_ENDPOINT_REGEX, p as createProfile, r as CDP_WEBSOCKET_ENDPOINT_REGEX, s as computeExecutablePath, t as getInstalledBrowsers } from "./main-CBC7_uE-.js";
2
2
  import { C as unitToPixels, Ct as getCapturedLogs, E as paperFormats, F as bufferCount, J as fromEvent, K as firstValueFrom, M as assert, Q as map, S as timeout, St as debug, T as withSourcePuppeteerURLIfNone, Tt as environment, W as filter, Z as lastValueFrom, _ as isNumber, _t as PuppeteerError, a as UTILITY_WORLD_NAME, at as race, b as isString, bt as TouchError, c as evaluationString, d as fromEmitterEvent, dt as takeUntil, f as getReadableAsTypedArray, ft as tap, g as isDate, gt as ProtocolError, h as getSourceUrlComment, ht as ConnectionClosedError, i as SOURCE_URL_REGEX, l as filterAsync, m as getSourcePuppeteerURLIfAvailable, mt as timer, n as NETWORK_IDLE_TIME, o as debugCatchError, p as getReadableFromProtocolStream, q as from, r as PuppeteerURL, s as debugError, t as DEFAULT_VIEWPORT, u as fromAbortSignal, v as isPlainObject, vt as TargetCloseError, w as validateDialogType, wt as setLogCapture, x as parsePDFOptions, xt as UnsupportedOperation, y as isRegExp, yt as TimeoutError, z as concatMap } from "./util-BHL_dfV_.js";
3
- import { $ as pageBindingInitString, $n as Deferred, $t as scriptInjector, A as NetworkManager, An as guarded, At as DEFAULT_INTERCEPT_RESOLUTION_PRIORITY, B as MAIN_WORLD, Bn as AsyncDisposableStack, Bt as throwIfDetached, C as WebMCPToolCall, Cn as NodeLocator, Ct as WebWorkerEvent, D as CdpTouchscreen, Dn as DeviceRequestPrompt, Dt as normalizeHeaderValue, E as CdpTouchHandle, En as TimeoutSettings, Et as WaitTask, F as CdpFrame, Fn as Browser, Ft as headersArray, G as CdpJSHandle, Gn as asyncDisposeSymbol, Gt as XPathQueryHandler, H as FrameManagerEvent, Hn as DisposableStack, Ht as bindIsolatedHandle, I as referrerPolicyToProtocol, In as WEB_PERMISSION_TO_PROTOCOL_PERMISSION, It as Dialog, J as addPageBinding, Jn as CallbackRegistry, Jt as PQueryHandler, K as releaseObject, Kn as disposeSymbol, Kt as TextQueryHandler, L as LifecycleWatcher, Ln as CDPSession, Lt as Accessibility, M as CdpHTTPResponse, Mt as InterceptResolutionAction, N as CdpHTTPRequest, Nt as STATUS_TEXTS, O as _keyDefinitions, On as BrowserContext, Ot as SecurityDetails, P as FrameTree, Pn as Mutex, Pt as handleError, Q as createEvaluationError, Qn as rewriteError, Qt as ScriptInjector, R as IsolatedWorld, Rn as CDPSessionEvent, Rt as Frame, S as WebMCPTool, Sn as MappedLocator, St as WebWorker, T as CdpMouse, Tn as RaceLocator, Tt as TaskManager, U as ExecutionContext, Un as DisposableStackPolyfill, Ut as JSHandle, V as PUPPETEER_WORLD, Vn as AsyncDisposableStackPolyfill, Vt as ElementHandle, W as CdpElementHandle, Wn as SuppressedError, Wt as getQueryHandlerAndSelector, X as createClientError, Xn as isErrnoException, Xt as CustomQueryHandlerRegistry, Y as convertConsoleMessageLevel, Yn as createProtocolErrorMessage, Yt as PierceQueryHandler, Z as createConsoleMessage, Zn as isErrorLike, Zt as customQueryHandlers, _ as CdpBrowserContext, _n as DelegatedLocator, _t as Mouse, a as KnownDevices, at as CdpPreloadScript, b as convertSameSiteFromPuppeteerToCdp, bn as Locator, bt as createIncrementalIdGenerator, c as _connectToCdpBrowser, cn as Tracing, ct as isTargetClosedError, d as CdpTarget, dn as CSSCoverage, dt as ConsoleMessage, en as ARIAQueryHandler, et as valueFromJSHandle, f as DevToolsTarget, fn as Coverage, ft as CdpBluetoothEmulation, g as WorkerTarget, gn as supportedMetrics, gt as Keyboard, h as PageTarget, hn as setDefaultScreenshotOptions, ht as TargetType, i as assertSupportedUrlRestrictions, it as CdpDeviceRequestPromptManager, j as NetworkEventManager, jt as HTTPRequest, k as FrameManager, kt as HTTPResponse, l as CdpBrowser, ln as EmulatedState, lt as CdpCDPSession, m as OtherTarget, mn as Page, mt as Target, n as TaskQueue, nn as LazyArg, nt as valueFromRemoteObjectReference, o as PredefinedNetworkConditions, on as AsyncIterableUtil, ot as CdpDialog, p as InitializationStatus, pn as JSCoverage, pt as Binding, q as CDP_BINDING_PREFIX, qn as Callback, qt as parsePSelectors, r as Puppeteer, rn as transposeIterableHandle, rt as CdpDeviceRequestPrompt, s as ExtensionTransport, sn as FileChooser, st as Connection, t as PUPPETEER_REVISIONS, tn as QueryHandler, tt as valueFromPrimitiveRemoteObject, u as TargetManager, un as EmulationManager, ut as NetworkManagerEvent, v as CdpPage, vn as FilteredLocator, vt as MouseButton, w as CdpKeyboard, wn as RETRY_DELAY, wt as Realm, x as WebMCP, xn as LocatorEvent, xt as Extension, y as convertCookiesPartitionKeyFromPuppeteerToCdp, yn as FunctionLocator, yt as Touchscreen, z as CdpWebWorker, zn as EventEmitter, zt as FrameEvent } from "./index-browser-Bp3vxHC3.js";
3
+ import { $ as pageBindingInitString, $n as Deferred, $t as scriptInjector, A as NetworkManager, An as guarded, At as DEFAULT_INTERCEPT_RESOLUTION_PRIORITY, B as MAIN_WORLD, Bn as AsyncDisposableStack, Bt as throwIfDetached, C as WebMCPToolCall, Cn as NodeLocator, Ct as WebWorkerEvent, D as CdpTouchscreen, Dn as DeviceRequestPrompt, Dt as normalizeHeaderValue, E as CdpTouchHandle, En as TimeoutSettings, Et as WaitTask, F as CdpFrame, Fn as Browser, Ft as headersArray, G as CdpJSHandle, Gn as asyncDisposeSymbol, Gt as XPathQueryHandler, H as FrameManagerEvent, Hn as DisposableStack, Ht as bindIsolatedHandle, I as referrerPolicyToProtocol, In as WEB_PERMISSION_TO_PROTOCOL_PERMISSION, It as Dialog, J as addPageBinding, Jn as CallbackRegistry, Jt as PQueryHandler, K as releaseObject, Kn as disposeSymbol, Kt as TextQueryHandler, L as LifecycleWatcher, Ln as CDPSession, Lt as Accessibility, M as CdpHTTPResponse, Mt as InterceptResolutionAction, N as CdpHTTPRequest, Nt as STATUS_TEXTS, O as _keyDefinitions, On as BrowserContext, Ot as SecurityDetails, P as FrameTree, Pn as Mutex, Pt as handleError, Q as createEvaluationError, Qn as rewriteError, Qt as ScriptInjector, R as IsolatedWorld, Rn as CDPSessionEvent, Rt as Frame, S as WebMCPTool, Sn as MappedLocator, St as WebWorker, T as CdpMouse, Tn as RaceLocator, Tt as TaskManager, U as ExecutionContext, Un as DisposableStackPolyfill, Ut as JSHandle, V as PUPPETEER_WORLD, Vn as AsyncDisposableStackPolyfill, Vt as ElementHandle, W as CdpElementHandle, Wn as SuppressedError, Wt as getQueryHandlerAndSelector, X as createClientError, Xn as isErrnoException, Xt as CustomQueryHandlerRegistry, Y as convertConsoleMessageLevel, Yn as createProtocolErrorMessage, Yt as PierceQueryHandler, Z as createConsoleMessage, Zn as isErrorLike, Zt as customQueryHandlers, _ as CdpBrowserContext, _n as DelegatedLocator, _t as Mouse, a as KnownDevices, at as CdpPreloadScript, b as convertSameSiteFromPuppeteerToCdp, bn as Locator, bt as createIncrementalIdGenerator, c as _connectToCdpBrowser, cn as Tracing, ct as isTargetClosedError, d as CdpTarget, dn as CSSCoverage, dt as ConsoleMessage, en as ARIAQueryHandler, et as valueFromJSHandle, f as DevToolsTarget, fn as Coverage, ft as CdpBluetoothEmulation, g as WorkerTarget, gn as supportedMetrics, gt as Keyboard, h as PageTarget, hn as setDefaultScreenshotOptions, ht as TargetType, i as assertSupportedUrlRestrictions, it as CdpDeviceRequestPromptManager, j as NetworkEventManager, jt as HTTPRequest, k as FrameManager, kt as HTTPResponse, l as CdpBrowser, ln as EmulatedState, lt as CdpCDPSession, m as OtherTarget, mn as Page, mt as Target, n as TaskQueue, nn as LazyArg, nt as valueFromRemoteObjectReference, o as PredefinedNetworkConditions, on as AsyncIterableUtil, ot as CdpDialog, p as InitializationStatus, pn as JSCoverage, pt as Binding, q as CDP_BINDING_PREFIX, qn as Callback, qt as parsePSelectors, r as Puppeteer, rn as transposeIterableHandle, rt as CdpDeviceRequestPrompt, s as ExtensionTransport, sn as FileChooser, st as Connection, t as PUPPETEER_REVISIONS, tn as QueryHandler, tt as valueFromPrimitiveRemoteObject, u as TargetManager, un as EmulationManager, ut as NetworkManagerEvent, v as CdpPage, vn as FilteredLocator, vt as MouseButton, w as CdpKeyboard, wn as RETRY_DELAY, wt as Realm, x as WebMCP, xn as LocatorEvent, xt as Extension, y as convertCookiesPartitionKeyFromPuppeteerToCdp, yn as FunctionLocator, yt as Touchscreen, z as CdpWebWorker, zn as EventEmitter, zt as FrameEvent } from "./index-browser-pHtsz007.js";
4
4
  import { t as BrowserWebSocketTransport } from "./BrowserWebSocketTransport-wm99h94r.js";
5
- import { t as convertPuppeteerChannelToBrowsersChannel } from "./LaunchOptions-DXdeJis3.js";
5
+ import { t as convertPuppeteerChannelToBrowsersChannel } from "./LaunchOptions-CLEBmZeM.js";
6
6
  import { t as NodeWebSocketTransport } from "./NodeWebSocketTransport-D9ysYGLM.js";
7
7
  import fs, { existsSync } from "node:fs";
8
8
  import path, { dirname, join } from "node:path";
@@ -240,7 +240,7 @@ var BrowserLauncher = class {
240
240
  const bidiOnly = process.env["PUPPETEER_WEBDRIVER_BIDI_ONLY"] === "true";
241
241
  const BiDi = await import(
242
242
  /* webpackIgnore: true */
243
- "./bidi-CwtLGgcA.js"
243
+ "./bidi-Bs8owg1e.js"
244
244
  );
245
245
  const bidiConnection = await BiDi.connectBidiOverCdp(cdpConnection);
246
246
  return await BiDi.BidiBrowser.create({
@@ -262,7 +262,7 @@ var BrowserLauncher = class {
262
262
  const transport = await NodeWebSocketTransport.create(browserWSEndpoint);
263
263
  const BiDi = await import(
264
264
  /* webpackIgnore: true */
265
- "./bidi-CwtLGgcA.js"
265
+ "./bidi-Bs8owg1e.js"
266
266
  );
267
267
  const bidiConnection = new BiDi.BidiConnection(browserWSEndpoint, transport, opts.idGenerator, opts.slowMo, opts.protocolTimeout);
268
268
  return await BiDi.BidiBrowser.create({