name: project-session-manager description: 使用git工作树和tmux会话管理隔离的开发环境 aliases: [psm]
项目会话管理器(PSM)技能
psm 是这个规范技能入口点的兼容别名。
快速开始: 对于简单的无tmux会话的工作树创建,使用
omc teleport:omc teleport #123 # 为问题/PR创建工作树 omc teleport my-feature # 为特性创建工作树 omc teleport list # 列出工作树详情见下面的Teleport命令。
使用Claude Code自动化隔离开发环境,利用git工作树和tmux会话。支持跨多个任务、项目和仓库的并行工作。
规范斜杠命令:/oh-my-claudecode:project-session-manager(别名:/oh-my-claudecode:psm)。
命令
| 命令 | 描述 | 示例 |
|---|---|---|
review <ref> |
PR审查会话 | /psm review omc#123 |
fix <ref> |
问题修复会话 | /psm fix omc#42 |
feature <proj> <name> |
特性开发 | /psm feature omc add-webhooks |
list [project] |
列出活跃会话 | /psm list |
attach <session> |
附加到会话 | /psm attach omc:pr-123 |
kill <session> |
终止会话 | /psm kill omc:pr-123 |
cleanup |
清理已合并/关闭的 | /psm cleanup |
status |
当前会话信息 | /psm status |
项目引用
支持格式:
- 别名:
omc#123(需要~/.psm/projects.json) - 完整:
owner/repo#123 - URL:
https://github.com/owner/repo/pull/123 - 当前:
#123(使用当前目录的仓库)
配置
项目别名(~/.psm/projects.json)
{
"aliases": {
"omc": {
"repo": "Yeachan-Heo/oh-my-claudecode",
"local": "~/Workspace/oh-my-claudecode",
"default_base": "main"
}
},
"defaults": {
"worktree_root": "~/.psm/worktrees",
"cleanup_after_days": 14
}
}
提供者
PSM支持多个问题跟踪提供者:
| 提供者 | 所需CLI | 引用格式 | 命令 |
|---|---|---|---|
| GitHub(默认) | gh |
owner/repo#123、alias#123、GitHub URLs |
review, fix, feature |
| Jira | jira |
PROJ-123(如果PROJ配置)、alias#123 |
fix, feature |
Jira配置
要使用Jira,添加一个带有 jira_project 和 provider: "jira" 的别名:
{
"aliases": {
"mywork": {
"jira_project": "MYPROJ",
"repo": "mycompany/my-project",
"local": "~/Workspace/my-project",
"default_base": "develop",
"provider": "jira"
}
}
}
重要: repo 字段仍然需要用于克隆git仓库。Jira跟踪问题,但您在git仓库中工作。
对于非GitHub仓库,使用 clone_url 代替:
{
"aliases": {
"private": {
"jira_project": "PRIV",
"clone_url": "git@gitlab.internal:team/repo.git",
"local": "~/Workspace/repo",
"provider": "jira"
}
}
}
Jira引用检测
PSM仅当 PROJ 在您的别名中明确配置为 jira_project 时,才识别 PROJ-123 格式为Jira引用。这可以防止像 FIX-123 这样的分支名产生误报。
Jira示例
# 修复Jira问题(MYPROJ必须配置)
psm fix MYPROJ-123
# 使用别名修复(推荐)
psm fix mywork#123
# 特性开发(与GitHub相同)
psm feature mywork add-webhooks
# 注意:'psm review' 不支持Jira(无PR概念)
# 对Jira问题使用 'psm fix'
Jira CLI设置
安装Jira CLI:
# macOS
brew install ankitpokhrel/jira-cli/jira-cli
# Linux
# 见:https://github.com/ankitpokhrel/jira-cli#installation
# 配置(交互式)
jira init
Jira CLI单独处理认证,与PSM无关。
目录结构
~/.psm/
├── projects.json # 项目别名
├── sessions.json # 活跃会话注册表
└── worktrees/ # 工作树存储
└── <project>/
└── <type>-<id>/
会话命名
| 类型 | Tmux会话 | 工作树目录 |
|---|---|---|
| PR审查 | psm:omc:pr-123 |
~/.psm/worktrees/omc/pr-123 |
| 问题修复 | psm:omc:issue-42 |
~/.psm/worktrees/omc/issue-42 |
| 特性 | psm:omc:feat-auth |
~/.psm/worktrees/omc/feat-auth |
实现协议
当用户调用PSM命令时,遵循此协议:
解析参数
解析 {{ARGUMENTS}} 以确定:
- 子命令:review, fix, feature, list, attach, kill, cleanup, status
- 引用:project#number, URL, 或会话ID
- 选项:–branch, --base, --no-claude, --no-tmux, 等
子命令:review <ref>
目的:创建PR审查会话
步骤:
-
解析引用:
# 读取项目别名 cat ~/.psm/projects.json 2>/dev/null || echo '{"aliases":{}}' # 解析引用格式:alias#num, owner/repo#num, 或 URL # 提取:project_alias, repo (owner/repo), pr_number, local_path -
获取PR信息:
gh pr view <pr_number> --repo <repo> --json number,title,author,headRefName,baseRefName,body,files,url -
确保本地仓库存在:
# 如果本地路径不存在,克隆 if [[ ! -d "$local_path" ]]; then git clone "https://github.com/$repo.git" "$local_path" fi -
创建工作树:
worktree_path="$HOME/.psm/worktrees/$project_alias/pr-$pr_number" # 获取PR分支 cd "$local_path" git fetch origin "pull/$pr_number/head:pr-$pr_number-review" # 创建工作树 git worktree add "$worktree_path" "pr-$pr_number-review" -
创建会话元数据:
cat > "$worktree_path/.psm-session.json" << EOF { "id": "$project_alias:pr-$pr_number", "type": "review", "project": "$project_alias", "ref": "pr-$pr_number", "branch": "<head_branch>", "base": "<base_branch>", "created_at": "$(date -Iseconds)", "tmux_session": "psm:$project_alias:pr-$pr_number", "worktree_path": "$worktree_path", "source_repo": "$local_path", "github": { "pr_number": $pr_number, "pr_title": "<title>", "pr_author": "<author>", "pr_url": "<url>" }, "state": "active" } EOF -
更新会话注册表:
# 添加到 ~/.psm/sessions.json -
创建tmux会话:
tmux new-session -d -s "psm:$project_alias:pr-$pr_number" -c "$worktree_path" -
启动Claude Code(除非 --no-claude):
tmux send-keys -t "psm:$project_alias:pr-$pr_number" "claude" Enter -
输出会话信息:
会话就绪! ID: omc:pr-123 工作树: ~/.psm/worktrees/omc/pr-123 Tmux: psm:omc:pr-123 附加:tmux attach -t psm:omc:pr-123
子命令:fix <ref>
目的:创建问题修复会话
步骤:
-
解析引用(与review相同)
-
获取问题信息:
gh issue view <issue_number> --repo <repo> --json number,title,body,labels,url -
创建特性分支:
cd "$local_path" git fetch origin main branch_name="fix/$issue_number-$(echo "$title" | tr ' ' '-' | tr '[:upper:]' '[:lower:]' | head -c 30)" git checkout -b "$branch_name" origin/main -
创建工作树:
worktree_path="$HOME/.psm/worktrees/$project_alias/issue-$issue_number" git worktree add "$worktree_path" "$branch_name" -
创建会话元数据(类似review,type=“fix”)
-
更新注册表、创建tmux、启动claude(与review相同)
子命令:feature <project> <name>
目的:开始特性开发
步骤:
-
解析项目(从别名或路径)
-
创建特性分支:
cd "$local_path" git fetch origin main branch_name="feature/$feature_name" git checkout -b "$branch_name" origin/main -
创建工作树:
worktree_path="$HOME/.psm/worktrees/$project_alias/feat-$feature_name" git worktree add "$worktree_path" "$branch_name" -
创建会话、tmux、启动claude(相同模式)
子命令:list [project]
目的:列出活跃会话
步骤:
-
读取会话注册表:
cat ~/.psm/sessions.json 2>/dev/null || echo '{"sessions":{}}' -
检查tmux会话:
tmux list-sessions -F "#{session_name}" 2>/dev/null | grep "^psm:" -
检查工作树:
ls -la ~/.psm/worktrees/*/ 2>/dev/null -
格式化输出:
活跃PSM会话: ID | 类型 | 状态 | 工作树 -------------------|---------|----------|--------------------------- omc:pr-123 | 审查 | 活跃 | ~/.psm/worktrees/omc/pr-123 omc:issue-42 | 修复 | 分离 | ~/.psm/worktrees/omc/issue-42
子命令:attach <session>
目的:附加到现有会话
步骤:
-
解析会话ID:
project:type-number -
验证会话存在:
tmux has-session -t "psm:$session_id" 2>/dev/null -
附加:
tmux attach -t "psm:$session_id"
子命令:kill <session>
目的:终止会话并清理
步骤:
-
终止tmux会话:
tmux kill-session -t "psm:$session_id" 2>/dev/null -
移除工作树:
worktree_path=$(jq -r ".sessions[\"$session_id\"].worktree" ~/.psm/sessions.json) source_repo=$(jq -r ".sessions[\"$session_id\"].source_repo" ~/.psm/sessions.json) cd "$source_repo" git worktree remove "$worktree_path" --force -
更新注册表:
# 从sessions.json中移除
子命令:cleanup
目的:清理已合并的PR和已关闭的问题
步骤:
-
读取所有会话
-
对于每个PR会话,检查是否合并:
gh pr view <pr_number> --repo <repo> --json merged,state -
对于每个问题会话,检查是否关闭:
gh issue view <issue_number> --repo <repo> --json closed,state -
清理已合并/关闭的会话:
- 终止tmux会话
- 移除工作树
- 更新注册表
-
报告:
清理完成: 已移除:omc:pr-123(已合并) 已移除:omc:issue-42(已关闭) 保留:omc:feat-auth(活跃)
子命令:status
目的:显示当前会话信息
步骤:
-
检测当前会话,从tmux或cwd:
tmux display-message -p "#{session_name}" 2>/dev/null # 或检查cwd是否在工作树内 -
读取会话元数据:
cat .psm-session.json 2>/dev/null -
显示状态:
当前会话:omc:pr-123 类型:审查 PR:#123 - 添加webhook支持 分支:feature/webhooks 创建时间:2小时前
错误处理
| 错误 | 解决方案 |
|---|---|
| 工作树已存在 | 提供:附加、重新创建或中止 |
| PR未找到 | 验证URL/编号,检查权限 |
| 无tmux | 警告并跳过会话创建 |
| 无gh CLI | 错误并显示安装说明 |
Teleport命令
omc teleport 命令提供完整PSM会话的轻量级替代方案。它创建git工作树而不管理tmux会话——适合快速、隔离的开发。
用法
# 为问题或PR创建工作树
omc teleport #123
omc teleport owner/repo#123
omc teleport https://github.com/owner/repo/issues/42
# 为特性创建工作树
omc teleport my-feature
# 列出现有工作树
omc teleport list
# 移除工作树
omc teleport remove issue/my-repo-123
omc teleport remove --force feat/my-repo-my-feature
选项
| 标志 | 描述 | 默认 |
|---|---|---|
--worktree |
创建工作树(默认,保持兼容性) | true |
--path <path> |
自定义工作树根目录 | ~/Workspace/omc-worktrees/ |
--base <branch> |
创建的基础分支 | main |
--json |
输出为JSON | false |
工作树布局
~/Workspace/omc-worktrees/
├── issue/
│ └── my-repo-123/ # 问题工作树
├── pr/
│ └── my-repo-456/ # PR审查工作树
└── feat/
└── my-repo-my-feature/ # 特性工作树
PSM vs Teleport
| 特性 | PSM | Teleport |
|---|---|---|
| Git工作树 | 是 | 是 |
| Tmux会话 | 是 | 否 |
| Claude Code启动 | 是 | 否 |
| 会话注册表 | 是 | 否 |
| 自动清理 | 是 | 否 |
| 项目别名 | 是 | 否(使用当前仓库) |
使用PSM进行完整管理会话。使用teleport进行快速工作树创建。
要求
必需:
git- 版本控制(支持工作树 v2.5+)jq- JSON解析tmux- 会话管理(可选,但推荐)
可选(按提供者):
gh- GitHub CLI(用于GitHub工作流)jira- Jira CLI(用于Jira工作流)
初始化
首次运行时,创建默认配置:
mkdir -p ~/.psm/worktrees ~/.psm/logs
# 如果不存在,创建默认projects.json
if [[ ! -f ~/.psm/projects.json ]]; then
cat > ~/.psm/projects.json << 'EOF'
{
"aliases": {
"omc": {
"repo": "Yeachan-Heo/oh-my-claudecode",
"local": "~/Workspace/oh-my-claudecode",
"default_base": "main"
}
},
"defaults": {
"worktree_root": "~/.psm/worktrees",
"cleanup_after_days": 14,
"auto_cleanup_merged": true
}
}
EOF
fi
# 如果不存在,创建sessions.json
if [[ ! -f ~/.psm/sessions.json ]]; then
echo '{"version":1,"sessions":{},"stats":{"total_created":0,"total_cleaned":0}}' > ~/.psm/sessions.json
fi