一个 opencode 插件,提供 /move-session 斜杠命令,把当前会话搬到另一个项目目录。所有逻辑都在插件进程内直接执行,全程不经过模型。支持 Windows、Linux 和 macOS。
/move-session <目标目录>
/move-session --debug <目标目录>
<目标目录> 支持以下几种写法:
- 绝对路径:
E:\repo\subdir或/Users/me/code/repo - 家目录缩写:
~/Projects/foo - 相对路径:
../sibling - 已知项目的名字:直接写项目目录名即可(不区分大小写),比如
myrepo - 固定短语:
here/current dir/this folder/current directory—— 当前目录home/my home—— 用户主目录- 包含
projects、code、src、dev字样的词 —— 取第一个实际存在的~/Projects、~/projects、~/code、~/src、~/dev
短语是固定的几个,不是自然语言理解;包含这些字样的输入会先按普通路径处理。
opencode 会把每个会话绑定到一个项目上(存在 project_id、directory、path 这几列里)。会话一旦建立,就没有内置的办法把它挪到别的目录——目标目录的会话列表看不到它,因为这几列还指向旧位置。
本插件在 command.execute.before 钩子里完成整个搬家过程:
- 先解析目标路径(纯代码判断,确定性的,不需要模型参与)。
- 在一个事务里重写根会话以及它全部后代 subagent 会话的
project_id、directory、path和workspace_id。 - 如果目标是 git 仓库,就按 opencode 自己的优先级确定项目身份:已有同名 worktree 的 project 行 → origin 远程地址的 sha1 →
.git/opencode缓存 → 根提交哈希,必要时自动注册新的 project 行。跨仓库移动会降级为global,不会把会话硬绑到另一个仓库上;机器上没装 git 时也一样降级,并记一条 warn 日志说明原因。 - 移动结果用 toast 弹出(成功、原地不动、或错误原文);成功时再向会话注入一条
noReply的合成 system-reminder,让下一轮对话知道工作目录变了。最后抛错中止命令管线——用户消息不会入库,模型一次都不会被调用。
所以你只会看到 toast 一闪而过的确认信息,聊天记录里不会留下 /move-session 的痕迹,也不产生需要事后清理的子代理会话。
| 文件 | 作用 |
|---|---|
plugins/move-session.js |
全部核心逻辑:路径解析、git 探测、用 bun:sqlite 直写 opencode.db、toast 与 reminder 注入 |
commands/move-session.md |
一个空壳斜杠命令(模板只有 $ARGUMENTS),作用仅仅是让 /move-session 能注册出来;它的内容会被插件整体替换掉 |
Windows 下运行:
.\install.ps1Linux 和 macOS 下运行:
./install.sh # 可以用 OPENCODE_CONFIG_DIR 指定其他配置目录脚本只负责把上面两个文件复制到 ~/.config/opencode/。如果检测到 opencode-move-session 原版或其 PowerShell 分支的文件,就会显示一条警告。确认旧版可以删除后带 -RemoveLegacy 或 --remove-legacy 参数重新跑一次安装脚本,或者自己手动删掉那些文件。装好后重启 opencode 即可生效。
手动安装就是把仓库里的两个文件复制到 opencode 的配置目录下:
plugins/move-session.js→~/.config/opencode/plugins/(Windows 为%USERPROFILE%\.config\opencode\plugins\)commands/move-session.md→~/.config/opencode/commands/(Windows 为%USERPROFILE%\.config\opencode\commands\)
如果之前装过旧版(session-env.js、move-session-auto-undo.js 或旧的同名命令文件),记得一并删掉,否则同名 /move-session 命令会冲突。
- 会话 ID 直接从钩子参数里拿,不需要靠环境变量注入;数据库用进程内的
bun:sqlite读写(设置了busy_timeout),git 探测通过Bun.spawn调用(找不到 git 时会优雅降级,不会让移动失败)。 session.path按官方公式计算(path.relative(project.directory, dir));Windows 上的全局会话存储的是去掉盘符的相对形式,比如test/testfolder2。/c/Users这种 MSYS 风格盘符前缀的重写只在 Windows 上生效,POSIX 路径不受影响。--debug的诊断信息写入 opencode 日志(service 标识为move-session),不会出现在任何提示文本里。
本项目的思路来自 opencode-move-session(bash 原版)及其 PowerShell 分支:搬家的规则、路径语义完全一致,但把"提示词驱动 LLM 执行脚本"改成了插件内直接执行,因此不再依赖 sqlite3 或 PowerShell,也不会产生子代理会话和待清理的临时文件。去掉LLM调用的原因有如下几点:1. 调用 LLM 可能会产生费用。 2. 有时可能尴尬地发现手头没有可用的 LLM 。 3. LLM 可能不会严格按照skill里写的内容执行,或者理解错skill的内容,产生各种问题。 4. 不受 LLM 的随机因素影响,更加容易调试。 5. 执行速度更快。当然,相应地,这个脚本也失去了用 LLM “智能”地寻找目标路径的功能。
- 本插件直接修改
opencode.db。如果 opencode 未来改了 session/project 的表结构或过滤规则,这里也要跟着调整。 - 已经打开的 opencode 实例可能在内存里缓存旧的项目归属,切换会话或重启后才会看到新位置。
- 依赖 opencode 支持
command.execute.before钩子。 - 无 TUI 挂载时(headless 或
opencode run)看不到 toast,但移动照常完成,结果会写进日志。 - 抛错中止管线在服务端表现为一次失败的
session.command请求,属于预期现象。 - 目标路径不做符号链接解析;如果项目路径里有符号链接,worktree 匹配可能受影响。
删掉这两个文件然后重启 opencode:
~/.config/opencode/plugins/move-session.js
~/.config/opencode/commands/move-session.md