feat(runtime): separate enrollment and native service lifecycle - #1128
Open
akazwz wants to merge 12 commits into
Open
feat(runtime): separate enrollment and native service lifecycle#1128akazwz wants to merge 12 commits into
akazwz wants to merge 12 commits into
Conversation
Member
|
实测发现以下问题,建议合并前修复:
|
launchctl bootout returns before launchd finishes tearing the job down, so an immediate bootstrap intermittently fails with "Bootstrap failed: 5: Input/output error" (reproduced ~1 in 20 on macOS 27). Retry bootstrap up to five times with a 300ms gap.
~/.memoh is shared with other Memoh components and --config may point anywhere, so enforce 0700 only on the runtime-owned home directory and rely on the 0600 file mode for the enrollment itself.
Create runtime directories private and keep the enrollment file 0600, but never refuse to run because an existing directory is not 0700.
launchd's ProcessType=Background makes node hang inside dyld on macOS 27 (getpwuid_r never returns), so the agent runs as a standard process. Login Items names a legacy agent after its executable file, so POSIX staging adds a "Memoh Runtime" symlink to cli.mjs and the service launches through it instead of showing "cli.mjs".
launchctl bootout returns before the job is gone, so a status check right after stop or uninstall still reported the service as running.
akazwz
force-pushed
the
feat/issue-1014-runtime-service
branch
from
September 7, 2026 13:01
6bdecfb to
10727a3
Compare
… log The pinned Node executable no longer has to sit in a directory chain that only the user or root can write: Homebrew keeps its Cellar admin-writable and a shared /usr/local belongs to whoever installed it, so service install failed on the most common macOS setup. Only the file itself must be immune to rewriting by other accounts. macOS ACL checks now ignore entries the user granted to themselves. Task Scheduler captures no output, so the Windows definition passes run --log and the process appends its own status lines and errors to logs/runtime.log. A missing pinned Node or program now names the path and the remedy instead of a bare ENOENT, install removes the generations it replaced, uninstall --purge also removes the service definitions, status prints the backend detail, enroll names --replace when the saved file cannot be read, and stop says the service returns at the next login. The enrollment no longer carries runtimeId: the server identifies a runtime by its key alone and the value was never sent. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UV3sQkb4txRRj54H7VuB84
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
改动内容
为 #1014 提供 CLI enrollment 持久化及当前用户的后台服务管理。保存连接、安装程序、启动进程分别由独立命令负责,安装、重启或故障恢复都不会隐式改写凭证或启动其他实例。
memoh-runtime enroll --server https://memoh.example --key "$MEMOH_RUNTIME_KEY" memoh-runtime service install memoh-runtime service startenroll将连接配置原子写入~/.memoh/runtime.json;更换连接或修复损坏配置必须显式传--replace,读不出已有文件时报错会提示这一点。运行中的进程只在下次启动或重启时读取新配置。服务端只靠 key 识别 runtime,配置里不再有runtimeId。run和原有前台连接参数保持只读,不隐式保存连接;--config只指定输入文件。run --log <file>让进程自己追加状态与错误日志,供无法捕获输出的服务管理器使用。service install将 CLI 和 bridge 协议文件复制到独立安装目录,固定 Node 路径,校验服务定义后注册服务并保持停止;成功后删除被替换的旧程序目录。启动不依赖 npm/npx 缓存;重新安装后也需要显式start。start/restart先校验安装和连接配置;restart校验失败不会停止原进程。固定的 Node 或安装程序被删除(例如包管理器升级)时,报错直接给出路径和重装提示。stop/uninstall不解析连接配置或安装记录,文件损坏时仍可清理服务。stop只结束当前进程,注册仍在,下次登录会再次启动;uninstall --purge额外移除安装程序、服务定义和日志,但保留 enrollment。run --log写入~/.memoh/runtime/logs/runtime.log。status报告原生服务状态及后端细节,不代表服务端连接状态。~/.memoh下的目录链拒绝其他账户可写、用户自有符号链接和 reparse point;POSIX 使用私有权限,Windows 使用受保护 ACL,只持久化修改过的 Owner/DACL。固定的 Node 可执行文件只要求本身是其他账户不能改写的普通文件,Homebrew 的 admin 可写 Cellar、他人安装的/usr/local都能通过;macOS ACL 检查忽略用户授予自己的条目。凭证不进入原生服务定义。PSModulePath,避免从 PowerShell 7 经 Node 启动时系统模块加载失败。新增 runtime README 和架构说明,覆盖安装失败后的重试、固定目录、旧 PR 安装的迁移、各平台自启动范围和日志位置。本 PR 不包含 Web 安装命令生成和 Reconnect 界面改造。
验证
38e126aab在 macOS launchd、Ubuntu 24.04 ARM64 systemd、Windows 11 ARM64 Task Scheduler 上完成过原生生命周期与真实 Bot 工具调用的人工验证。最新提交改动了可执行文件信任检查、Windows 任务参数和安装清理,三平台主路径需要重新人工验证。🤖 Generated with Claude Code
https://claude.ai/code/session_01UV3sQkb4txRRj54H7VuB84