@dsh-enhanced/lark-channel 0.1.49 → 0.1.53

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.
Files changed (73) hide show
  1. package/README.md +2 -1
  2. package/docs/rsi-setup.md +27 -6
  3. package/docs/setup.md +2 -0
  4. package/lib/launchd-control.d.ts +24 -0
  5. package/lib/launchd-control.d.ts.map +1 -0
  6. package/lib/launchd-control.js +68 -0
  7. package/lib/launchd-control.js.map +1 -0
  8. package/lib/launchd-identity.d.ts +34 -0
  9. package/lib/launchd-identity.d.ts.map +1 -0
  10. package/lib/launchd-identity.js +184 -0
  11. package/lib/launchd-identity.js.map +1 -0
  12. package/lib/launchd-target-lock.d.ts +6 -0
  13. package/lib/launchd-target-lock.d.ts.map +1 -0
  14. package/lib/launchd-target-lock.js +48 -0
  15. package/lib/launchd-target-lock.js.map +1 -0
  16. package/lib/launchd.d.ts +18 -0
  17. package/lib/launchd.d.ts.map +1 -1
  18. package/lib/launchd.js +211 -54
  19. package/lib/launchd.js.map +1 -1
  20. package/lib/rsi-bootstrap-manifest.d.ts.map +1 -1
  21. package/lib/rsi-bootstrap-manifest.js +3 -24
  22. package/lib/rsi-bootstrap-manifest.js.map +1 -1
  23. package/lib/rsi-build.d.ts +10 -1
  24. package/lib/rsi-build.d.ts.map +1 -1
  25. package/lib/rsi-build.js +101 -27
  26. package/lib/rsi-build.js.map +1 -1
  27. package/lib/rsi-creation-build.d.ts +1 -0
  28. package/lib/rsi-creation-build.d.ts.map +1 -1
  29. package/lib/rsi-creation-build.js +60 -30
  30. package/lib/rsi-creation-build.js.map +1 -1
  31. package/lib/rsi-install.d.ts +1 -1
  32. package/lib/rsi-install.d.ts.map +1 -1
  33. package/lib/rsi-install.js.map +1 -1
  34. package/lib/rsi-local-install.d.ts +31 -3
  35. package/lib/rsi-local-install.d.ts.map +1 -1
  36. package/lib/rsi-local-install.js +117 -16
  37. package/lib/rsi-local-install.js.map +1 -1
  38. package/lib/rsi-memory-learning.d.ts +8 -0
  39. package/lib/rsi-memory-learning.d.ts.map +1 -1
  40. package/lib/rsi-memory-learning.js +28 -0
  41. package/lib/rsi-memory-learning.js.map +1 -1
  42. package/lib/rsi-native-install.d.ts +38 -0
  43. package/lib/rsi-native-install.d.ts.map +1 -0
  44. package/lib/rsi-native-install.js +254 -0
  45. package/lib/rsi-native-install.js.map +1 -0
  46. package/lib/rsi-native-launchd.d.ts +7 -0
  47. package/lib/rsi-native-launchd.d.ts.map +1 -0
  48. package/lib/rsi-native-launchd.js +49 -0
  49. package/lib/rsi-native-launchd.js.map +1 -0
  50. package/lib/rsi-native-profile.d.ts +64 -0
  51. package/lib/rsi-native-profile.d.ts.map +1 -0
  52. package/lib/rsi-native-profile.js +283 -0
  53. package/lib/rsi-native-profile.js.map +1 -0
  54. package/lib/rsi-native-runtime-bootstrap.d.ts +35 -0
  55. package/lib/rsi-native-runtime-bootstrap.d.ts.map +1 -0
  56. package/lib/rsi-native-runtime-bootstrap.js +385 -0
  57. package/lib/rsi-native-runtime-bootstrap.js.map +1 -0
  58. package/lib/rsi-plugin-creation.d.ts +2 -1
  59. package/lib/rsi-plugin-creation.d.ts.map +1 -1
  60. package/lib/rsi-plugin-creation.js +16 -6
  61. package/lib/rsi-plugin-creation.js.map +1 -1
  62. package/lib/rsi-setup.d.ts.map +1 -1
  63. package/lib/rsi-setup.js +24 -8
  64. package/lib/rsi-setup.js.map +1 -1
  65. package/lib/rsi-source.d.ts.map +1 -1
  66. package/lib/rsi-source.js +121 -9
  67. package/lib/rsi-source.js.map +1 -1
  68. package/lib/setup.d.ts.map +1 -1
  69. package/lib/setup.js +129 -16
  70. package/lib/setup.js.map +1 -1
  71. package/lib/version.d.ts +1 -1
  72. package/lib/version.js +1 -1
  73. package/package.json +21 -20
package/README.md CHANGED
@@ -160,8 +160,9 @@ dsh-lark-setup --profile web --refresh-agent-policy --allow-agent-tools
160
160
  - 安装阶段的 `dsh-rsi-setup --prepare-source` 执行 Git,在 `$DSH_HOME/rsi-sources/<profile>` 写入私有源码与 bare 发布仓库;npm 来源访问固定官方 GitHub 仓库的精确版本 tag,本地来源只复制已提交内容。支持常用代理与 CA 环境变量,不执行安装脚本;此命令不使用飞书凭据或浏览器,详见 [RSI 配置](docs/rsi-setup.md)。
161
161
  - `dsh-rsi-setup --prepare-local-update` 在 Home 外准备本地上游与现有修复分支合并后的源码和 tarball,使用固定的镜像准备器及离线 bubblewrap 构建,保留原包、源码 refs 与授权。它可联网准备依赖镜像,但候选 build/pack 不带网络、凭据或原 Home;不会停服或激活更新。pre-owner 安装可使用 checkout 维护事务,已有 owner 的完整迁移仍未交付,详见 [RSI 配置](docs/rsi-setup.md)。
162
162
  - checkout 的 `local-service-upgrade` 使用固定 pnpm,在停服前以无 registry 凭据的私有配置联网验证旧锁文件并预取依赖,失败保留原服务。停服副本的原生安装无网络且禁用安装脚本;新 Node 子进程沿用隔离边界,完整核验安装包文件和依赖闭包。事务会写入独立缓存及 Home 副本、切换 systemd 服务;它不启用 owner scheduler 或扩大授权。用法与恢复见[安装器指南](../../scripts/install/README.md#checkout-内的-pre-owner-冻结源码维护)。
163
+ - macOS 安装使用系统 Perl 的内核 `flock` 串行化同一用户、同名 profile 的 LaunchAgent 操作,使用 `plutil`/`launchctl` 核对服务归属并管理当前用户服务;运行检查核对状态与 PID。同名目标属于另一 DSH_HOME 时拒绝修改,替换失败时尝试恢复旧定义与注册状态。原生学习另串行化 Home 配置,写入私有计划、有限授权、恢复日志和 HMAC observer 密钥。新安装从冻结源码清单和锁文件准备私有 Node、pnpm 及依赖,候选构建和行为检查使用本机 Seatbelt;Host 也是原生 Node。支持范围与失败恢复见[原生 macOS 学习](docs/rsi-setup.md#原生-macos-学习)。
163
164
  - Linux 安装的 `--prepare-build` 还自动准备私有授权运行时和本地发布资源,也可单独执行 `--prepare-authorities`:从同版本已安装 Control Plane 复制官方程序及模块、固定独立 Node,运行副本做版本/模块检查,并生成 14 个独立 Ed25519 身份和本地 registry/catalog。共享契约从 Control Plane 声明的依赖解析,只接受包内依赖边或同一 pnpm 虚拟包目录内的相邻依赖边;祖先或 profile 顶层的同名包不能替代它。目录和密钥仅当前用户可读写;重复执行核验固定内容并保留发布/状态进展。此步骤需要文件写入与子进程权限,不需要网络、浏览器或飞书凭据,不执行 npm lifecycle,不签发 owner grant 或启动 Host。
164
- - `dsh-rsi-setup --prepare-build` 还会执行摘要固定的构建脚本和 Dockerfile,用空 Docker 配置准备联网下载依赖的镜像,保存不可变 image ID 与私有构建回执。随后候选检查使用离线完整仓库 sandbox;安装期间不会读取主机 Docker registry 凭据或启动候选 Host。当前 runtime 支持与资源上限见 [RSI 配置](docs/rsi-setup.md)。
165
+ - Linux 的 `dsh-rsi-setup --prepare-build` 还会执行摘要固定的构建脚本和 Dockerfile,用空 Docker 配置准备联网下载依赖的镜像,保存不可变 image ID 与私有构建回执。随后候选检查使用离线完整仓库 sandbox;安装期间不会读取主机 Docker registry 凭据或启动候选 Host。Mac 则准备受摘要固定的私有 Node、pnpm 与冻结清单依赖,并在候选期用 Seatbelt 离线执行。当前 runtime 支持与资源上限见 [RSI 配置](docs/rsi-setup.md)。
165
166
  - 新 `--install-owner` 从已批准的源码镜像准备独立行为镜像;首次构建允许访问 Debian 包源,使用空 Docker 配置和固定 worker/launcher,不读取 owner 凭据、浏览器或候选期望行为,不运行 npm lifecycle。资源与摘要位于 `$DSH_HOME/rsi-creation-builds/<profile>`,创建验收和采用使用既有独立签名身份及私有 runner 账本;重试验证实际镜像,不重建缺失资源或重置额度。
166
167
  - `requestTimeoutMs`(默认 30 秒)为常规 OpenAPI 请求设置硬 deadline,`imageDownloadTimeoutMs` 独立限制图片下载。SDK 会把可下传的 AbortSignal 交给底层 HTTP;若调用已经被服务端接收后超时,最终消息保留 Delivery 的 `unknown_after_send` 语义,绝不自动重发或假称未发送。
167
168
  - App Secret 不写 Delivery 数据库、工具参数、health、route、日志或异常;Linux protected-file 没有额外静态加密,同 UID、root 和可读备份仍能取得内容。
package/docs/rsi-setup.md CHANGED
@@ -1,4 +1,4 @@
1
- # 日常使用自迭代的双 Host 配置
1
+ # 日常使用自迭代配置
2
2
 
3
3
  `dsh-rsi-setup` 将已配置的 Lark owner 目标 profile 和独立采用协调器接入原生 Automations。目标 Host 从普通任务学习持久事实与经验,并从真实任务反馈形成源码修复,协调器在目标重启期间继续有限交接;目标恢复后重验当前 owner 和反馈,再完成采用。后续任务进入观察与回滚流程。
4
4
 
@@ -6,6 +6,25 @@ Linux `supervised` 新安装在最终模型、TraeX、Lark 配置和 doctor 完
6
6
 
7
7
  开发版 Linux 默认安装(包括 checkout 内 shell 的 auto/`--yes`)选择此完整场景;显式轻量场景、shell 的 `--mode standard`、`--lark skip` 或 `--no-service` 不隐式开启后台学习。必要配置优先从当前可信 owner 和已配置模型自动取得,缺少身份时使用安装向导的首次私聊配对,不把任意首条消息当主人。路径、独立授权身份及有限预算自动生成;没有全部前提仍报告未就绪。裸插件安装保持 fail-closed,旧安装不自动续期、补签或修改 paused 任务。
8
8
 
9
+ ## 原生 macOS 学习
10
+
11
+ macOS x64 / Apple Silicon 的 `supervised` 使用一个原生 Node Host,由当前登录用户的 launchd 管理。普通任务与认证反馈驱动持久记忆学习,以及 owner 命名空间内的新工具创建、独立行为验证和 Cordis 动态采用。候选构建和行为执行使用私有本机 Node 与 Seatbelt,独立 runner 保留有限额度及 unknown 结果;Host、聊天、模型与学习调度也运行在 macOS。此路径没有既有插件源码替换、发布和双 Host 交接授权;已有 Linux 源码修复轨保持原合同。
12
+
13
+ 使用已安装的独立 npm DSH CLI,并确保它是 `PATH` 中选中的 `dsh`。先确认 `/usr/bin/git --version` 可运行(Apple Command Line Tools)。安装器只复制冻结来源提交中的根清单、工作区包清单与锁文件,以固定摘要验证官方 Node 24.22.0 和 pnpm 11.7.0,使用私有无凭据环境执行 `--frozen-lockfile --ignore-scripts` 安装。此准备阶段可联网下载锁定依赖;候选构建和行为执行离线运行。私有运行时的节点、依赖树、来源提交与锁文件由回执固定,复跑核对全部内容,缺失或漂移时停止而不重建已授权的资产。macOS `--docker-path` 明确拒绝;无需 Docker Desktop 或 Docker socket。
14
+
15
+ 本地安装器的默认 `auto` 场景也会选择 supervised;已安装相同源码版本及所需包后,可重试:
16
+
17
+ ```sh
18
+ "$DSH_HOME/profiles/web/node_modules/.bin/dsh-rsi-setup" \
19
+ --install-owner --profile web --dsh-home "$DSH_HOME"
20
+ ```
21
+
22
+ 安装计划、有限授权、信任配置与恢复日志保存在 `rsi-authorities/<profile>/config/native-*.json`,重复执行复用原期限、密钥与额度。配置当前用户服务前先核对 Home/owner/Automation 库存;已存在 active 或 paused 任务且需要启用调度时,仍要求 `--ack-existing-automations`。安装后用 HMAC Unix socket 核对 launchd PID、真实 Loader 配置、学习服务及原生 memory-scan 登记,稳定观察通过才报告 ready。失败恢复本次尝试前的配置和服务;冲突时保留日志供核对,不清理聊天、学习历史或候选记录。
23
+
24
+ 从此前报出 `Linux x64 is required` 的官方 `0.1.49` 安装升级时,macOS 会识别其未使用的源码准备:仅当旧 receipt、干净工作树、初始提交与全部 Git 引用均匹配,且没有授权、构建或运行资源时,才把整个旧目录移入 `rsi-source-archives/<profile>/<UUID>`,再准备请求的新版本或本地来源。已有修改、维护提交或使用迹象会停止迁移,保留原目录;归档后的准备失败会报告归档路径,不删除旧历史。新目录建立后若进程崩溃,仍须人工核对不完整目录与归档,不会自动覆盖。
25
+
26
+ `ready` 证明部署就绪,长期普通任务收益仍按 [RSI 验收合同](../../../docs/rsi-acceptance.md) 验证。Linux 上的模拟平台测试不能替代真实 Mac 验收。
27
+
9
28
  ## 1. 准备源码、构建环境与两个 profile
10
29
 
11
30
  新安装的 `supervised` 场景会自动准备私有源码仓库,并安装下述目标依赖。源码放在 `$DSH_HOME/rsi-sources/<profile>/`:`checkout` 为独立工作树,`release.git` 为本地 bare 发布仓库,`bootstrap.json` 保存来源与初始提交。npm 安装读取本工具版本对应的官方 `v<version>` tag;本地安装只复制 checkout 已提交的 HEAD,保留原工作区的未提交修改。
@@ -37,9 +56,9 @@ Linux 上的新安装还会自动准备授权工具与本地发布资源,无
37
56
 
38
57
  新生成的创建采用授权显式包含 `creationCapabilities.retention.maximumLifetimeMs: 2592000000`(最多 30 天)。首次采用仍要求原创建作业和计划有效期内的新鲜独立证书;采用后可以跨单个作业、计划及证书的截止,在原使用授权和 runner 截止前复用精确版本。默认安装的创建与使用授权仍共用原年度截止,此模式不跨该授权期限。重启保留原采用时间、截止和调用额度,反馈纠正、撤回或 owner 变化仍阻断使用。旧 manifest 缺少此字段时保持证书窗口内的原语义;重跑安装不补签,不向已有账本自动增加此授权。该期限不证明真实任务收益或版本替换回退已经验收。
39
58
 
40
- 安装器从已批准的源码构建镜像准备独立行为镜像,资源保存在 `$DSH_HOME/rsi-creation-builds/<profile>`。临时上下文只含固定受信任 worker/launcher、Dockerfile、清单和锁文件,不复制候选、owner 凭据或期望行为。首次镜像准备可能访问 Debian 包源;运行候选时禁用网络。重复安装核验原始回执、输入摘要、Docker 可执行文件和实际不可变镜像 ID;镜像缺失或输入漂移不会触发重建。验收与调用使用独立私有 runner 账本,额度和 unknown 不因重启重置。该安装配置本身不证明普通任务收益或完整自迭代闭环。
59
+ Linux 安装器从已批准的源码构建镜像准备独立行为镜像,资源保存在 `$DSH_HOME/rsi-creation-builds/<profile>`。临时上下文只含固定受信任 worker/launcher、Dockerfile、清单和锁文件,不复制候选、owner 凭据或期望行为。首次镜像准备可能访问 Debian 包源;运行候选时禁用网络。重复安装核验原始回执、输入摘要、Docker 可执行文件和实际不可变镜像 ID;镜像缺失或输入漂移不会触发重建。macOS 行为 runner 复用上文私有原生运行时。两种平台的验收与调用均使用独立私有 runner 账本,额度和 unknown 不因重启重置。该安装配置本身不证明普通任务收益或完整自迭代闭环。
41
60
 
42
- 新安装还会尝试准备离线构建镜像。当前完整仓库检查沿用已验证的 Linux x64、Docker Server `29.4.1/linux/amd64` 与嵌套 sandbox 配置;不满足这些前置条件时,安装器保留源码并报告 `buildUnavailable`,普通 Agent 安装继续,但不声称源码修复构建已经可用。实际镜像构建失败或已有资源不一致会停止安装。
61
+ Linux 新安装还会尝试准备离线构建镜像。当前完整仓库检查沿用已验证的 Linux x64、Docker Server `29.4.1/linux/amd64` 与嵌套 sandbox 配置;不满足这些前置条件时,安装器保留源码并报告 `buildUnavailable`,普通 Agent 安装继续,但不声称源码修复构建已经可用。macOS 原生准备失败会停止安装,不由 `--optional-build` 掩盖;已有资源不一致也会停止安装。
43
62
 
44
63
  支持的环境可单独运行严格构建准备:
45
64
 
@@ -48,9 +67,9 @@ Linux 上的新安装还会自动准备授权工具与本地发布资源,无
48
67
  --prepare-build --profile web --dsh-home "$HOME/.dsh"
49
68
  ```
50
69
 
51
- 输出中的 `sourceBuild` 可用于 Control Plane manifest。安装器还自动从同一不可变镜像导出原生 Node、pnpm、离线 store 和供应链策略缓存,输出 `releaseBuild` 可直接用于本地发布 adapter 的 `build` 配置;无需手填工具链路径和摘要。资源保存在 `$DSH_HOME/rsi-release-builds/<profile>`,回执固定所有文件内容与模式。导出只创建未启动的容器,复制固定路径后删除容器,不执行其中的源码。发布仍使用本机 `/usr/bin/bwrap` 和 `/usr/bin/tar`;`--optional-build` 在缺少这些前置条件时报告 `releaseBuildUnavailable`,保留已准备的源码验证镜像。实际复制、工具链版本校验或已有回执漂移失败仍会停止安装。配置使用不可变镜像 ID,并将私有回执与 seccomp 保存到 `$DSH_HOME/rsi-builds/<profile>`。重新执行会核对来源、构建输入与本地镜像;不会静默换镜像或重新构建丢失的已登记镜像。Docker 构建脚本、Dockerfile 与 seccomp 必须匹配安装包内登记的摘要,只把 lock、workspace 配置及包清单放入构建上下文;不复制源码、主机包缓存或凭据。首次镜像准备需要网络,随后候选构建离线运行。
70
+ Linux 输出中的 `sourceBuild` 可用于 Control Plane manifest。Linux 安装器还自动从同一不可变镜像导出原生 Node、pnpm、离线 store 和供应链策略缓存,输出 `releaseBuild` 可直接用于本地发布 adapter 的 `build` 配置;无需手填工具链路径和摘要。资源保存在 `$DSH_HOME/rsi-release-builds/<profile>`,回执固定所有文件内容与模式。导出只创建未启动的容器,复制固定路径后删除容器,不执行其中的源码。发布仍使用本机 `/usr/bin/bwrap` 和 `/usr/bin/tar`;`--optional-build` 在缺少这些前置条件时报告 `releaseBuildUnavailable`,保留已准备的源码验证镜像。实际复制、工具链版本校验或已有回执漂移失败仍会停止安装。配置使用不可变镜像 ID,并将私有回执与 seccomp 保存到 `$DSH_HOME/rsi-builds/<profile>`。重新执行会核对来源、构建输入与本地镜像;不会静默换镜像或重新构建丢失的已登记镜像。Docker 构建脚本、Dockerfile 与 seccomp 必须匹配安装包内登记的摘要,只把 lock、workspace 配置及包清单放入构建上下文;不复制源码、主机包缓存或凭据。首次镜像准备需要网络,随后候选构建离线运行。macOS 的 `--prepare-build` 仅输出不含 owner 授权的 runtime/sourceBuild 基础回执;`--install-owner` 编译时才加入绑定安装、owner、期限与额度的 sourceBuild 配置。
52
71
 
53
- 自动配置沿用完整仓库检查的 30 分钟、16 GiB 内存、8 CPU、1024 PID、4 GiB 工作区和 2 GiB 临时目录上限;宿主需提供相应资源。嵌套 sandbox 的系统路径与 seccomp 边界见[构建镜像指南](../../../scripts/isolation/README.md#nested-sandbox-profile)。准备资源只完成安装前置步骤;`--install-owner` 会核对已安装 Host、owner 和最终配置后再应用。
72
+ Linux 自动配置使用完整仓库检查的 30 分钟、16 GiB 内存、8 CPU、1024 PID 和 4 GiB 工作区上限;Linux repository 构建保持 2 GiB 临时目录。宿主需提供相应资源。嵌套 sandbox 的系统路径与 seccomp 边界见[构建镜像指南](../../../scripts/isolation/README.md#nested-sandbox-profile)。macOS 原生构建按固定 60 秒单次、1 MiB 输出、1000 次及 24 小时累计运行限额授予,独立行为 runner 保留各自原有额度。准备资源只完成安装前置步骤;`--install-owner` 会核对已安装 Host、owner 和最终配置后再应用。
54
73
 
55
74
  目标先完成 [Lark 配对](setup.md)与 [supervised 安装](../../../scripts/install/README.md),已有唯一 active owner DM。无需先激活固定 Recovery runbook;缺失的 owner route 在成对配置事务内生成,既有唯一精确路由(包括 `supervised-growth-owner`)沿用原 ID 和 minimum generation。路由冲突或重复会拒绝,不覆盖其他授权。新安装自动补齐目标依赖;旧安装若缺依赖,为目标补装同一构建的 Growth Driver、Goals、Skills、Verifier、Memory Learning 与 Control Plane。Memory 由 Personal Assistant 内嵌提供,不再添加独立 Memory bundle。开发版应使用本地构建的包;仅有相同版本号不能证明含有这些新增 API。
56
75
 
@@ -116,12 +135,14 @@ manifest 是 owner 私有的 JSON(`chmod 600`),路径须 canonical,不
116
135
 
117
136
  ## 自动安装与就绪判断
118
137
 
119
- 正常新装无需手填 manifest。`supervised` 安装完成模型、TraeX、Lark 与 doctor 后,调用当前 profile 内的 `dsh-rsi-setup --install-owner --profile <name> --dsh-home <absolute>`;本地源码安装再传 `--source-repository`。仅 Linux systemd user services 支持此入口。构建前置条件缺失,或旧的本地目录链接使必需包实体位于 profile 外时,返回 `{"mode":"not-ready",...}` 和退出码 3;旧链接在停服、创建协调器和签发授权前被拒绝。其他预检或部署失败也使安装命令非零退出,不显示“安装流程完成”。前序已安装的普通 Agent 与资源保留供修复后重试。
138
+ 正常新装无需手填 manifest。`supervised` 安装完成模型、TraeX、Lark 与 doctor 后,调用当前 profile 内的 `dsh-rsi-setup --install-owner --profile <name> --dsh-home <absolute>`;本地源码安装再传 `--source-repository`。此入口支持 Linux systemd user service 和 macOS 原生 launchd Host。构建前置条件缺失,或旧的本地目录链接使必需包实体位于 profile 外时,返回 `{"mode":"not-ready",...}` 和退出码 3;旧链接在停服、创建协调器和签发授权前被拒绝。其他预检或部署失败也使安装命令非零退出,不显示“安装流程完成”。前序已安装的普通 Agent 与资源保留供修复后重试。
120
139
 
121
140
  本地 supervised 新安装先运行 `--install-local-cohort`:在私有临时 checkout 中按冻结 lockfile 构建,将选定插件、协调器及其内部运行依赖打包到 `$DSH_HOME/rsi-local-cohorts/<profile>/`。bootstrap 构建复用本机 pnpm 缓存;这不是候选代码的隔离构建。冻结源码的 `allowBuilds` 布尔清单随 receipt 保存并在安装前合并,保留已有配置;同一依赖存在相反决定时停止,不自动扩大安装脚本权限。安装通过原生 DSH `plugin list/add` 完成,本地 supervised profile 使用 pnpm `nodeLinker: isolated`,防止 hoisted 布局把同版本 registry peer 混入本地运行依赖。依赖覆盖限定精确父包:运行依赖固定到本批制品;内部 peer 仅在其 provider 已属于当前 profile 的运行依赖闭包时固定到同一制品,不通过 peer 扩大安装集合。目标和协调器分别计算闭包,缺席的可选 peer 不自动安装。仅选定根包成为直接 bundle;每条内部运行依赖、已提供的 peer 和实际安装文件均须匹配制品,同名内部包必须解析到同一真实目录,防止同版本 npm/file 副本产生不同模块状态。重试复用 receipt 并核对原始提交、包选择与摘要,不自动改为新的 HEAD。构建发生在停服前;若后续包安装或文件核验失败,保留固定制品与覆盖配置,Host 保持停机,修复后以相同输入重试。若 pnpm 普通安装保留了缺失、已知文件内容不符或模块目录分裂的包,安装器会重验冻结制品和配置,再强制重装一次并核验结果。协调器的完整包名/版本不会掩盖文件缺失。额外文件、配置冲突及未知状态不会触发此自动修复;重验仍失败时保持停机,不自动删除用户的 profile。
122
141
 
123
142
  既有冻结安装可重跑原 `--install-local-cohort` 命令修复同批 peer 解析;必须保持原 profile、源码路径和 bundle 选择。预检拒绝未知内部 override、改变的固定路径或制品;随后持生命周期锁停服,重新安装原 tarball 并核验,成功后恢复原服务。此修复不更新源码提交、冻结收据或业务状态;不是升级到当前开发 HEAD。
124
143
 
144
+ macOS 本地 cohort 安装沿用冻结制品与安装文件校验,持同一个 Home 生命周期锁和当前用户/profile 的 launchd 目标锁,核对当前 LaunchAgent 的加载身份与 plist 后再停服;仅恢复安装前已注册的同一服务。目标锁与普通安装、CLI 服务操作共用,另一 DSH_HOME 的同名 profile 不能并发替换该服务。安装或校验失败且尚未重启时保持停服;若启动可能已提交而补偿无法证明停机,明确报告 unknown,须核对实际服务后重试。本入口只替换所选 profile 的插件包,不授予源码替换或发布能力。
145
+
125
146
  开发版提供本地更新候选的准备入口:
126
147
 
127
148
  ```sh
package/docs/setup.md CHANGED
@@ -92,6 +92,8 @@ pnpm --filter @dsh-enhanced/lark-channel run onboard --profile web --create-app
92
92
 
93
93
  重复执行会更新同一 account 的受管配置,不会重复添加规则或 handle。首次绑定 owner 默认开放已安装的 Agent 工具能力;已有应用或 owner 配置保留现状,不会因重装重新开启已关闭的工具:
94
94
 
95
+ 向导在交接 Lark owner 前检查同一 DSH Home 的其他 profile 是否使用相同 Delivery 数据库。Electron 管理的 `desktop` profile 不允许通过 `dsh --profile desktop --dump-config` 读取;向导遇到这条明确的 CLI 拒绝时,使用当前 `dsh` CLI 安装的配置组合器只读检查 Desktop 的 bundle、profile 和 Home 覆盖层。发现共享 Lark owner 或启用的 Delivery scheduler,以及 Desktop 配置无法完整读取时,都会停止交接并保留原 profile。
96
+
95
97
  - 不传参数:首次配置默认开放,已有配置保留现状;
96
98
  - `--preserve-agent-tools`:始终保留现有规则,首次配置也不新增通用工具授权;
97
99
  - `--allow-agent-tools`:写入本地 foreground 与精确 Delivery 主体的通用 capability 可达性规则,并保留外部主体工具级 allow/deny;
@@ -0,0 +1,24 @@
1
+ import { inspectDshLaunchAgent } from './launchd.js';
2
+ type ServiceInput = {
3
+ dshHome: string;
4
+ profile: string;
5
+ };
6
+ type ServiceState = Awaited<ReturnType<typeof inspectDshLaunchAgent>>;
7
+ export type LaunchAgentAction = 'registered' | 'running' | 'restart' | 'restart-if-loaded';
8
+ export interface LaunchAgentControlOptions {
9
+ platform?: NodeJS.Platform;
10
+ inspect?: (input: ServiceInput) => Promise<ServiceState>;
11
+ run?: (command: string, args: string[]) => {
12
+ status: number | null;
13
+ stderr?: string;
14
+ };
15
+ lock?: <T>(input: ServiceInput, operation: () => Promise<T>) => Promise<T>;
16
+ wait?: (milliseconds: number) => Promise<void>;
17
+ timeoutMs?: number;
18
+ }
19
+ /** Service-only operations never install a plist or run onboarding. */
20
+ export declare function controlDshLaunchAgent(input: ServiceInput, action: LaunchAgentAction, options?: LaunchAgentControlOptions): Promise<boolean>;
21
+ /** Internal installer dispatch, loaded through the selected Host's resolver. */
22
+ export declare function runLaunchdControl(args: string[]): Promise<void>;
23
+ export {};
24
+ //# sourceMappingURL=launchd-control.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"launchd-control.d.ts","sourceRoot":"","sources":["../src/launchd-control.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AAGpD,KAAK,YAAY,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AACxD,KAAK,YAAY,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC,CAAA;AACrE,MAAM,MAAM,iBAAiB,GAAG,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,mBAAmB,CAAA;AAC1F,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAA;IAC1B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC,YAAY,CAAC,CAAA;IACxD,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK;QAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACrF,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAA;IAC1E,IAAI,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,uEAAuE;AACvE,wBAAsB,qBAAqB,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,iBAAiB,EACxF,OAAO,GAAE,yBAA8B,GAAG,OAAO,CAAC,OAAO,CAAC,CAoC3D;AAED,gFAAgF;AAChF,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAarE"}
@@ -0,0 +1,68 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { isAbsolute } from 'node:path';
3
+ import { setTimeout as delay } from 'node:timers/promises';
4
+ import { inspectDshLaunchAgent } from './launchd.js';
5
+ import { withLaunchAgentTargetLock } from './launchd-target-lock.js';
6
+ /** Service-only operations never install a plist or run onboarding. */
7
+ export async function controlDshLaunchAgent(input, action, options = {}) {
8
+ if ((options.platform ?? process.platform) !== 'darwin')
9
+ throw new Error('launchd service control requires macOS');
10
+ if (!isAbsolute(input.dshHome) || !/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/u.test(input.profile)) {
11
+ throw new Error('invalid launchd service identity');
12
+ }
13
+ const inspect = options.inspect ?? inspectDshLaunchAgent;
14
+ if (action === 'registered' || action === 'running') {
15
+ const state = await inspect(input);
16
+ return state.registered && (action === 'registered' || state.running);
17
+ }
18
+ const run = options.run ?? ((command, args) => spawnSync(command, args, {
19
+ encoding: 'utf8', timeout: 10_000, maxBuffer: 262_144,
20
+ env: { PATH: '/usr/bin:/bin:/usr/sbin:/sbin' }, stdio: ['ignore', 'ignore', 'pipe'],
21
+ }));
22
+ const timeoutMs = options.timeoutMs ?? 30_000;
23
+ if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 60_000)
24
+ throw new Error('invalid launchd restart deadline');
25
+ return (options.lock ?? withLaunchAgentTargetLock)(input, async () => {
26
+ const before = await inspect(input);
27
+ if (!before.registered) {
28
+ if (action === 'restart-if-loaded')
29
+ return false;
30
+ throw new Error('launchd service is not registered for this DSH_HOME');
31
+ }
32
+ const result = run('/bin/launchctl', ['kickstart', '-k', before.target]);
33
+ if (result.status !== 0)
34
+ throw new Error(`launchd restart failed: ${result.stderr?.trim() || `exit ${result.status}`}`);
35
+ const deadline = Date.now() + timeoutMs;
36
+ for (;;) {
37
+ const current = await inspect(input);
38
+ if (current.target !== before.target || current.plistPath !== before.plistPath
39
+ || (current.registered && JSON.stringify(current.identity) !== JSON.stringify(before.identity))) {
40
+ throw new Error('launchd service identity changed during restart');
41
+ }
42
+ if (current.registered && current.running && current.pid !== before.pid)
43
+ return true;
44
+ if (Date.now() >= deadline)
45
+ throw new Error('launchd restart did not produce a new running Host');
46
+ await (options.wait ?? delay)(Math.min(100, deadline - Date.now()));
47
+ }
48
+ });
49
+ }
50
+ /** Internal installer dispatch, loaded through the selected Host's resolver. */
51
+ export async function runLaunchdControl(args) {
52
+ const values = {};
53
+ for (let index = 0; index < args.length; index += 2) {
54
+ const name = args[index], value = args[index + 1];
55
+ if (!name || !['--profile', '--dsh-home', '--action'].includes(name) || values[name] !== undefined
56
+ || !value || value.startsWith('--'))
57
+ throw new Error('invalid launchd service control arguments');
58
+ values[name] = value;
59
+ }
60
+ const action = values['--action'];
61
+ if (!action || !['registered', 'running', 'restart', 'restart-if-loaded'].includes(action)
62
+ || !values['--profile'] || !values['--dsh-home'])
63
+ throw new Error('missing launchd service control arguments');
64
+ const present = await controlDshLaunchAgent({ dshHome: values['--dsh-home'], profile: values['--profile'] }, action);
65
+ if (!present && action !== 'restart-if-loaded')
66
+ process.exitCode = 3;
67
+ }
68
+ //# sourceMappingURL=launchd-control.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"launchd-control.js","sourceRoot":"","sources":["../src/launchd-control.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ export interface NativeLaunchdIdentity {
2
+ dshHome: string;
3
+ profile: string;
4
+ home?: string;
5
+ uid?: number;
6
+ nodePath?: string;
7
+ dshPath?: string;
8
+ dshSha256?: string;
9
+ }
10
+ export interface NativeLaunchdState {
11
+ registered: boolean;
12
+ pid: number;
13
+ }
14
+ export interface NativeLaunchdDetail extends NativeLaunchdState {
15
+ running: boolean;
16
+ state: string | null;
17
+ lastExitCode: string | null;
18
+ }
19
+ export interface NativeLaunchdCommandResult {
20
+ status: number | null;
21
+ stdout: string;
22
+ stderr: string;
23
+ }
24
+ export type NativeLaunchdCommand = (command: string, args: string[]) => NativeLaunchdCommandResult;
25
+ /** A missing job is distinct from a failed launchctl query. Never stop a job
26
+ * belonging to another Home just because its profile label is the same. */
27
+ export declare function inspectNativeLaunchdDetail(input: NativeLaunchdIdentity, command?: NativeLaunchdCommand): NativeLaunchdDetail;
28
+ export declare function inspectNativeLaunchd(input: NativeLaunchdIdentity, command?: NativeLaunchdCommand): NativeLaunchdState;
29
+ /** Validate an existing plist before recording it for rollback. The loaded job
30
+ * is independently checked by inspectNativeLaunchd. */
31
+ export declare function assertNativeLaunchdPlist(bytes: string, input: NativeLaunchdIdentity, command?: NativeLaunchdCommand): void;
32
+ export declare function stopNativeLaunchd(input: NativeLaunchdIdentity, signal: AbortSignal, command?: NativeLaunchdCommand): Promise<void>;
33
+ export declare function startNativeLaunchd(input: NativeLaunchdIdentity, signal: AbortSignal, command?: NativeLaunchdCommand): Promise<void>;
34
+ //# sourceMappingURL=launchd-identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"launchd-identity.d.ts","sourceRoot":"","sources":["../src/launchd-identity.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CACxD;AACD,MAAM,WAAW,kBAAkB;IAAG,UAAU,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE;AACxE,MAAM,WAAW,mBAAoB,SAAQ,kBAAkB;IAC7D,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;CACpE;AACD,MAAM,WAAW,0BAA0B;IAAG,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AACrG,MAAM,MAAM,oBAAoB,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,0BAA0B,CAAA;AA0DlG;2EAC2E;AAC3E,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,qBAAqB,EAAE,OAAO,GAAE,oBAA0B,GAAG,mBAAmB,CAqBjI;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,qBAAqB,EAAE,OAAO,GAAE,oBAA0B,GAAG,kBAAkB,CAG1H;AAED;uDACuD;AACvD,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,qBAAqB,EAClF,OAAO,GAAE,oBAA0B,GAAG,IAAI,CA4B3C;AAED,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,qBAAqB,EAAE,MAAM,EAAE,WAAW,EACvF,OAAO,GAAE,oBAA0B,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBpD;AACD,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,qBAAqB,EAAE,MAAM,EAAE,WAAW,EACxF,OAAO,GAAE,oBAA0B,GAAG,OAAO,CAAC,IAAI,CAAC,CAYpD"}
@@ -0,0 +1,184 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { createHash } from 'node:crypto';
3
+ import { readFileSync, realpathSync } from 'node:fs';
4
+ import { isAbsolute, join } from 'node:path';
5
+ import { setTimeout as delay } from 'node:timers/promises';
6
+ import { launchAgentPaths } from './launchd.js';
7
+ const run = (command, args) => {
8
+ const result = spawnSync(command, args, { encoding: 'utf8', timeout: 10_000, maxBuffer: 262_144,
9
+ env: { PATH: '/usr/bin:/bin:/usr/sbin:/sbin' }, stdio: ['ignore', 'pipe', 'pipe'] });
10
+ return { status: result.status, stdout: result.stdout ?? '', stderr: result.stderr ?? '' };
11
+ };
12
+ function fail(message) { throw new Error(`rsi native launchd: ${message}`); }
13
+ function identity(input) {
14
+ const uid = input.uid ?? process.getuid?.();
15
+ if (!Number.isSafeInteger(uid) || uid === undefined || uid < 1)
16
+ fail('a non-root GUI user is required');
17
+ const paths = launchAgentPaths(input), domain = `gui/${uid}`;
18
+ return { ...paths, domain, target: `${domain}/${paths.label}`, cwd: join(input.dshHome, 'profiles', input.profile) };
19
+ }
20
+ function scalar(text, key, separator = ' = ') {
21
+ const prefix = `${key}${separator}`;
22
+ const matches = text.split('\n').map(line => line.trim()).filter(line => line.startsWith(prefix));
23
+ if (matches.length !== 1)
24
+ return undefined;
25
+ return matches[0].slice(prefix.length);
26
+ }
27
+ function rootScalar(text, target, key) {
28
+ const lines = text.split('\n'), values = [];
29
+ let depth = 0, rootDepth = 0, first = true, wrapped = false;
30
+ for (const line of lines) {
31
+ const value = line.trim();
32
+ if (value === '')
33
+ continue;
34
+ if (first) {
35
+ first = false;
36
+ if (value.endsWith(' = {')) {
37
+ if (value !== `${target} = {`)
38
+ return undefined;
39
+ depth = 1;
40
+ rootDepth = 1;
41
+ wrapped = true;
42
+ continue;
43
+ }
44
+ }
45
+ if (wrapped && depth === 0)
46
+ return undefined;
47
+ if (value === '}') {
48
+ if (depth === 0)
49
+ return undefined;
50
+ depth -= 1;
51
+ continue;
52
+ }
53
+ const prefix = `${key} = `;
54
+ if (depth === rootDepth && value.startsWith(prefix))
55
+ values.push(value.slice(prefix.length));
56
+ if (value.endsWith(' = {'))
57
+ depth += 1;
58
+ }
59
+ return depth === 0 && values.length === 1 ? values[0] : undefined;
60
+ }
61
+ function assertArguments(args, input) {
62
+ if (!input.nodePath || !input.dshPath || !input.dshSha256 || !Array.isArray(args)
63
+ || !args.every(arg => typeof arg === 'string'))
64
+ fail('service executable identity is missing');
65
+ const offset = args[1] === '--disable-warning=ExperimentalWarning' ? 2 : 1;
66
+ const node = args[0], dsh = args[offset];
67
+ if (args.length !== offset + 4 || typeof node !== 'string' || typeof dsh !== 'string' || !isAbsolute(node) || !isAbsolute(dsh)
68
+ || realpathSync(node) !== input.nodePath || realpathSync(dsh) !== input.dshPath
69
+ || args[offset + 1] !== '--profile' || args[offset + 2] !== input.profile || args[offset + 3] !== '--no-open'
70
+ || createHash('sha256').update(readFileSync(input.dshPath)).digest('hex') !== input.dshSha256) {
71
+ fail('service command differs from the selected Node and DSH installation');
72
+ }
73
+ }
74
+ /** A missing job is distinct from a failed launchctl query. Never stop a job
75
+ * belonging to another Home just because its profile label is the same. */
76
+ export function inspectNativeLaunchdDetail(input, command = run) {
77
+ const expected = identity(input), result = command('/bin/launchctl', ['print', expected.target]);
78
+ if (result.status !== 0) {
79
+ if (result.status === 113 && /Could not find service/iu.test(result.stderr)) {
80
+ return { registered: false, pid: 0, running: false, state: null, lastExitCode: null };
81
+ }
82
+ fail('cannot inspect the user service');
83
+ }
84
+ if (scalar(result.stdout, 'path') !== expected.plistPath || scalar(result.stdout, 'working directory') !== expected.cwd
85
+ || scalar(result.stdout, 'DSH_HOME', ' => ') !== input.dshHome)
86
+ fail('loaded service belongs to another installation');
87
+ if (/^\s*(?:NODE_OPTIONS|NODE_PATH|DYLD_[A-Z_]+|LD_PRELOAD|LD_LIBRARY_PATH) =>/mu.test(result.stdout)) {
88
+ fail('loaded service has an unexpected execution environment');
89
+ }
90
+ const argumentsBlock = /^\s*arguments = \{\n([\s\S]*?)^\s*\}/mu.exec(result.stdout);
91
+ assertArguments(argumentsBlock?.[1]?.split('\n').map(line => line.trim()).filter(Boolean), input);
92
+ if (realpathSync(scalar(result.stdout, 'program') ?? '') !== input.nodePath)
93
+ fail('loaded service program differs');
94
+ const raw = scalar(result.stdout, 'pid'), pid = raw === undefined ? 0 : Number(raw);
95
+ if (!Number.isSafeInteger(pid) || pid < 0 || pid === 1)
96
+ fail('invalid service process identity');
97
+ const state = rootScalar(result.stdout, expected.target, 'state') ?? null;
98
+ return { registered: true, pid, running: state === 'running' && pid > 1, state,
99
+ lastExitCode: rootScalar(result.stdout, expected.target, 'last exit code') ?? null };
100
+ }
101
+ export function inspectNativeLaunchd(input, command = run) {
102
+ const { registered, pid } = inspectNativeLaunchdDetail(input, command);
103
+ return { registered, pid };
104
+ }
105
+ /** Validate an existing plist before recording it for rollback. The loaded job
106
+ * is independently checked by inspectNativeLaunchd. */
107
+ export function assertNativeLaunchdPlist(bytes, input, command = run) {
108
+ // plutil receives the already-read bytes via an argument-free stdin call in
109
+ // production; tests may supply a parsed response without executing launchd.
110
+ const result = command === run ? (() => {
111
+ const child = spawnSync('/usr/bin/plutil', ['-convert', 'json', '-o', '-', '--', '-'], { input: bytes, encoding: 'utf8', timeout: 10_000, maxBuffer: 262_144, env: { PATH: '/usr/bin:/bin' } });
112
+ return { status: child.status, stdout: child.stdout ?? '', stderr: child.stderr ?? '' };
113
+ })() : command('/usr/bin/plutil', ['-convert', 'json', '-o', '-', '--', '-']);
114
+ if (result.status !== 0)
115
+ fail('invalid LaunchAgent plist');
116
+ const value = JSON.parse(result.stdout), expected = identity(input);
117
+ const fields = new Set(['Label', 'ProgramArguments', 'EnvironmentVariables', 'WorkingDirectory',
118
+ 'StandardOutPath', 'StandardErrorPath', 'LimitLoadToSessionType', 'ProcessType', 'RunAtLoad',
119
+ 'KeepAlive', 'ThrottleInterval', 'ExitTimeOut', 'Umask']);
120
+ // Program overrides argv[0]; other launchd keys can change the executable's
121
+ // filesystem or inherited authority. Only our generated execution shape is
122
+ // safe to record as a rollback target.
123
+ if (!value || typeof value !== 'object' || Array.isArray(value) || Object.keys(value).some(key => !fields.has(key))
124
+ || !value.EnvironmentVariables || typeof value.EnvironmentVariables !== 'object'
125
+ || Object.keys(value.EnvironmentVariables).sort().join(',') !== 'DSH_HOME,PATH'
126
+ || typeof value.EnvironmentVariables.PATH !== 'string'
127
+ || !value.EnvironmentVariables.PATH.split(':').every((path) => isAbsolute(path) && !/[\p{Cc}]/u.test(path))
128
+ || value.StandardOutPath !== expected.stdoutPath || value.StandardErrorPath !== expected.stderrPath
129
+ || value.LimitLoadToSessionType !== 'Aqua' || value.ProcessType !== 'Background'
130
+ || value.RunAtLoad !== true || value.KeepAlive !== true || value.ThrottleInterval !== 10
131
+ || value.ExitTimeOut !== 30 || value.Umask !== 63)
132
+ fail('plist execution settings differ from the managed LaunchAgent');
133
+ if (value.Label !== expected.label || value.WorkingDirectory !== expected.cwd
134
+ || value.EnvironmentVariables?.DSH_HOME !== input.dshHome)
135
+ fail('plist belongs to another installation');
136
+ assertArguments(value.ProgramArguments, input);
137
+ }
138
+ export async function stopNativeLaunchd(input, signal, command = run) {
139
+ const expected = identity(input);
140
+ const initial = inspectNativeLaunchd(input, command);
141
+ if (!initial.registered)
142
+ return;
143
+ const stopped = command('/bin/launchctl', ['bootout', expected.target]);
144
+ // bootout can report a racing removal, but the job must actually disappear.
145
+ for (let attempt = 0; attempt < 400; attempt++) {
146
+ signal.throwIfAborted();
147
+ if (!inspectNativeLaunchd(input, command).registered) {
148
+ // Registry removal alone is insufficient: launchd may still be waiting
149
+ // for the old process to exit. A reused PID conservatively blocks setup.
150
+ if (initial.pid === 0)
151
+ return;
152
+ try {
153
+ process.kill(initial.pid, 0);
154
+ }
155
+ catch (error) {
156
+ if (error.code === 'ESRCH')
157
+ return;
158
+ throw error;
159
+ }
160
+ }
161
+ if (stopped.status !== 0)
162
+ fail('service did not stop');
163
+ await delay(100, undefined, { signal });
164
+ }
165
+ fail('service remained registered after bootout');
166
+ }
167
+ export async function startNativeLaunchd(input, signal, command = run) {
168
+ const expected = identity(input);
169
+ if (inspectNativeLaunchd(input, command).registered)
170
+ fail('service is still registered before bootstrap');
171
+ if (command('/bin/launchctl', ['enable', expected.target]).status !== 0)
172
+ fail('cannot enable user service');
173
+ for (let attempt = 0; attempt < 3; attempt++) {
174
+ signal.throwIfAborted();
175
+ const result = command('/bin/launchctl', ['bootstrap', expected.domain, expected.plistPath]);
176
+ if (result.status !== 0 && result.status !== 5)
177
+ fail('cannot bootstrap user service');
178
+ if (inspectNativeLaunchd(input, command).registered)
179
+ return;
180
+ await delay(250, undefined, { signal });
181
+ }
182
+ fail('bootstrap did not register the service');
183
+ }
184
+ //# sourceMappingURL=launchd-identity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"launchd-identity.js","sourceRoot":"","sources":["../src/launchd-identity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /** The launchd label is shared by every DSH_HOME for this GUI user. */
2
+ export declare function withLaunchAgentTargetLock<T>(input: {
3
+ profile: string;
4
+ uid?: number;
5
+ }, operation: () => Promise<T>): Promise<T>;
6
+ //# sourceMappingURL=launchd-target-lock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"launchd-target-lock.d.ts","sourceRoot":"","sources":["../src/launchd-target-lock.ts"],"names":[],"mappings":"AAMA,uEAAuE;AACvE,wBAAsB,yBAAyB,CAAC,CAAC,EAC/C,KAAK,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACpE,OAAO,CAAC,CAAC,CAAC,CAuCZ"}
@@ -0,0 +1,48 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { constants, realpathSync } from 'node:fs';
3
+ import { lstat, open } from 'node:fs/promises';
4
+ const profilePattern = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/u;
5
+ /** The launchd label is shared by every DSH_HOME for this GUI user. */
6
+ export async function withLaunchAgentTargetLock(input, operation) {
7
+ const uid = input.uid ?? process.getuid?.();
8
+ if (!profilePattern.test(input.profile) || !Number.isSafeInteger(uid) || uid === undefined || uid < 1) {
9
+ throw new Error('lark-channel setup: invalid launchd target lock identity');
10
+ }
11
+ const temporary = await lstat(realpathSync('/tmp'));
12
+ if (!temporary.isDirectory() || temporary.isSymbolicLink() || temporary.uid !== 0
13
+ || (temporary.mode & 0o7777) !== 0o1777) {
14
+ throw new Error('lark-channel setup: unsafe launchd target lock directory');
15
+ }
16
+ const lockPath = `/tmp/.dsh-enhanced-launchd-${uid}-${input.profile}.lock`;
17
+ let descriptor;
18
+ try {
19
+ descriptor = await open(lockPath, constants.O_RDWR | constants.O_CREAT | constants.O_NOFOLLOW, 0o600);
20
+ const assertIdentity = async () => {
21
+ const [opened, linked] = await Promise.all([descriptor.stat(), lstat(lockPath)]);
22
+ if (!opened.isFile() || !linked.isFile() || linked.isSymbolicLink()
23
+ || opened.uid !== uid || linked.uid !== uid || opened.nlink !== 1 || linked.nlink !== 1
24
+ || (opened.mode & 0o777) !== 0o600 || (linked.mode & 0o777) !== 0o600
25
+ || opened.dev !== linked.dev || opened.ino !== linked.ino) {
26
+ throw new Error(`lark-channel setup: unsafe launchd target lock: ${lockPath}`);
27
+ }
28
+ };
29
+ await assertIdentity();
30
+ const acquired = spawnSync('/usr/bin/perl', ['-MFcntl=:flock', '-MErrno=EAGAIN,EWOULDBLOCK', '-e',
31
+ 'open(F, "<&", 3) or exit 74; flock(F, LOCK_EX|LOCK_NB) or exit(($! == EAGAIN || $! == EWOULDBLOCK) ? 75 : 74);'], {
32
+ encoding: 'utf8', stdio: ['ignore', 'ignore', 'pipe', descriptor.fd],
33
+ env: { PATH: '/usr/bin:/bin', LANG: 'C' }, timeout: 10_000,
34
+ });
35
+ if (acquired.status === 75)
36
+ throw new Error(`lark-channel setup: launchd target is busy: ${lockPath}`);
37
+ if (acquired.status !== 0) {
38
+ const detail = acquired.stderr?.trim().slice(0, 1_000);
39
+ throw new Error(`lark-channel setup: cannot acquire launchd target lock${detail ? `: ${detail}` : ''}`);
40
+ }
41
+ await assertIdentity();
42
+ return await operation();
43
+ }
44
+ finally {
45
+ await descriptor?.close();
46
+ }
47
+ }
48
+ //# sourceMappingURL=launchd-target-lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"launchd-target-lock.js","sourceRoot":"","sources":["../src/launchd-target-lock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACjD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AAE9C,MAAM,cAAc,GAAG,oCAAoC,CAAA;AAE3D,uEAAuE;AACvE,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,KAAwC,EAAE,SAA2B;IAErE,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,IAAI,OAAO,CAAC,MAAM,EAAE,EAAE,CAAA;IAC3C,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;QACtG,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAA;IAC7E,CAAC;IACD,MAAM,SAAS,GAAG,MAAM,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAA;IACnD,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,SAAS,CAAC,cAAc,EAAE,IAAI,SAAS,CAAC,GAAG,KAAK,CAAC;WAC5E,CAAC,SAAS,CAAC,IAAI,GAAG,MAAM,CAAC,KAAK,MAAM,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAA;IAC7E,CAAC;IACD,MAAM,QAAQ,GAAG,8BAA8B,GAAG,IAAI,KAAK,CAAC,OAAO,OAAO,CAAA;IAC1E,IAAI,UAAwD,CAAA;IAC5D,IAAI,CAAC;QACH,UAAU,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,MAAM,GAAG,SAAS,CAAC,OAAO,GAAG,SAAS,CAAC,UAAU,EAAE,KAAK,CAAC,CAAA;QACrG,MAAM,cAAc,GAAG,KAAK,IAAI,EAAE;YAChC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,UAAW,CAAC,IAAI,EAAE,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;YACjF,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,MAAM,CAAC,cAAc,EAAE;mBAC9D,MAAM,CAAC,GAAG,KAAK,GAAG,IAAI,MAAM,CAAC,GAAG,KAAK,GAAG,IAAI,MAAM,CAAC,KAAK,KAAK,CAAC,IAAI,MAAM,CAAC,KAAK,KAAK,CAAC;mBACpF,CAAC,MAAM,CAAC,IAAI,GAAG,KAAK,CAAC,KAAK,KAAK,IAAI,CAAC,MAAM,CAAC,IAAI,GAAG,KAAK,CAAC,KAAK,KAAK;mBAClE,MAAM,CAAC,GAAG,KAAK,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,GAAG,KAAK,MAAM,CAAC,GAAG,EAAE,CAAC;gBAC5D,MAAM,IAAI,KAAK,CAAC,mDAAmD,QAAQ,EAAE,CAAC,CAAA;YAChF,CAAC;QACH,CAAC,CAAA;QACD,MAAM,cAAc,EAAE,CAAA;QACtB,MAAM,QAAQ,GAAG,SAAS,CAAC,eAAe,EAAE,CAAC,gBAAgB,EAAE,4BAA4B,EAAE,IAAI;YAC/F,gHAAgH,CAAC,EAAE;YACnH,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,CAAC;YACpE,GAAG,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,MAAM;SAC3D,CAAC,CAAA;QACF,IAAI,QAAQ,CAAC,MAAM,KAAK,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,+CAA+C,QAAQ,EAAE,CAAC,CAAA;QACtG,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAA;YACtD,MAAM,IAAI,KAAK,CAAC,yDAAyD,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;QACzG,CAAC;QACD,MAAM,cAAc,EAAE,CAAA;QACtB,OAAO,MAAM,SAAS,EAAE,CAAA;IAC1B,CAAC;YAAS,CAAC;QACT,MAAM,UAAU,EAAE,KAAK,EAAE,CAAA;IAC3B,CAAC;AACH,CAAC"}
package/lib/launchd.d.ts CHANGED
@@ -22,6 +22,7 @@ export interface InstalledLaunchAgent extends LaunchAgentPaths {
22
22
  }
23
23
  interface CommandResult {
24
24
  status: number | null;
25
+ stdout?: string | Buffer;
25
26
  stderr?: string | Buffer;
26
27
  }
27
28
  export interface LaunchAgentInstallOptions {
@@ -33,9 +34,26 @@ export interface LaunchAgentInstallOptions {
33
34
  platform?: NodeJS.Platform;
34
35
  run?: (command: string, args: readonly string[]) => CommandResult;
35
36
  wait?: (milliseconds: number) => Promise<void>;
37
+ signal?: AbortSignal;
38
+ }
39
+ export interface DshLaunchAgentInspection {
40
+ target: string;
41
+ plistPath: string;
42
+ registered: boolean;
43
+ pid: number;
44
+ running: boolean;
45
+ identity: {
46
+ nodePath: string;
47
+ dshPath: string;
48
+ dshSha256: string;
49
+ } | null;
36
50
  }
37
51
  export declare function launchAgentPaths(input: LaunchAgentPathsInput): LaunchAgentPaths;
38
52
  export declare function createLaunchAgent(input: LaunchAgentInput): string;
53
+ export declare function inspectDshLaunchAgent(input: {
54
+ dshHome: string;
55
+ profile: string;
56
+ }, options?: Pick<LaunchAgentInstallOptions, 'home' | 'uid' | 'platform' | 'run'>): Promise<DshLaunchAgentInspection>;
39
57
  export declare function installDshLaunchAgent(input: {
40
58
  dshHome: string;
41
59
  profile: string;
@@ -1 +1 @@
1
- {"version":3,"file":"launchd.d.ts","sourceRoot":"","sources":["../src/launchd.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,qBAAqB;IACpC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,gBAAiB,SAAQ,gBAAgB;IACxD,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,gBAAgB,EAAE,MAAM,CAAA;IACxB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,oBAAqB,SAAQ,gBAAgB;IAC5D,MAAM,EAAE,MAAM,CAAA;CACf;AAED,UAAU,aAAa;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;CACzB;AAED,MAAM,WAAW,yBAAyB;IACxC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAA;IAC1B,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,aAAa,CAAA;IACjE,IAAI,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAC/C;AAgBD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,GAAG,gBAAgB,CAW/E;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,CAmDjE;AA+DD,wBAAsB,qBAAqB,CACzC,KAAK,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EAC3C,OAAO,GAAE,yBAA8B,GACtC,OAAO,CAAC,oBAAoB,CAAC,CA6D/B"}
1
+ {"version":3,"file":"launchd.d.ts","sourceRoot":"","sources":["../src/launchd.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,qBAAqB;IACpC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,gBAAiB,SAAQ,gBAAgB;IACxD,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,gBAAgB,EAAE,MAAM,CAAA;IACxB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,oBAAqB,SAAQ,gBAAgB;IAC5D,MAAM,EAAE,MAAM,CAAA;CACf;AAED,UAAU,aAAa;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACxB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;CACzB;AAED,MAAM,WAAW,yBAAyB;IACxC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAA;IAC1B,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,aAAa,CAAA;IACjE,IAAI,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC9C,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,OAAO,CAAA;IACnB,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;CAC1E;AAgBD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,GAAG,gBAAgB,CAW/E;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,CAmDjE;AA8HD,wBAAsB,qBAAqB,CAAC,KAAK,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EACrF,OAAO,GAAE,IAAI,CAAC,yBAAyB,EAAE,MAAM,GAAG,KAAK,GAAG,UAAU,GAAG,KAAK,CAAM,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAUvH;AA8CD,wBAAsB,qBAAqB,CACzC,KAAK,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EAC3C,OAAO,GAAE,yBAA8B,GACtC,OAAO,CAAC,oBAAoB,CAAC,CAiF/B"}