Files
078f6f5e46 feat: 岛上作答交互卡 + 项目置顶/排序 + 建仓与克隆 (#6)
## 岛上能直接作答 Claude 的交互请求

AskUserQuestion / ExitPlanMode 的 tool_input 里没有 command/path,
RiskClassifier 提不出 summary,风险判定为 normal 直接放行 ——
岛上从来不弹任何东西。这是这次要修的核心 bug。

现在按 toolName 在风险判定**之前**分流,岛上弹可作答的卡:

- 选择题:单题单选点选即答;多题表单逐题作答,多选勾完提交,
  最后合成一条回传。答案借 deny 的 reason 送回模型(PreToolUse
  没有「替用户作答」的通道,这是唯一的口子)。
- 计划审批:显式 allow 压不掉 plan 状态机自己的确认框(实测
  2.1.220),所以「批准」= 放行后替用户在终端框里按 1/2,带重试
  等对话框渲染出来;驳回走 hook deny 有效。
- 进入计划模式(EnterPlanMode)同样接管。
- 终端权限框("Do you want to...")走 Notification hook 弹卡,
  允许=注入 1、拒绝=Esc,复用 TerminalReply 的全套护栏。

超时方向和审批卡**相反**:审批超时必须 deny(唯一的安全刹车),
交互卡超时 allow(不输出决策 = 交还终端原生对话框,用户零损失)。
这条镜像关系有专门的测试钉住。

## 项目列表

- 置顶:岛和主窗口菜单里都能置顶,落盘 pinned.json。
- 排序统一成 置顶 > 正在开发 > 最近提交 > 名字。GitInfo 加
  lastCommitAt(38 个仓库合计约 300ms,后台队列)—— 三十多个项目
  按 yaml 顺序排,找一个要翻半屏。
- 岛上无会话的行点击弹启动菜单,不再直接起 claude(误触成本太高)。
  用原生 NSMenu:SwiftUI Menu 的两种整行方案都翻过车(label 被
  压扁 / 透明盖层收不到点击)。

## 建仓与克隆

- scripts/new-project.sh:目录 + git + GitHub 远程 + 防污染
  settings.json + 注册 projects.yaml,一条命令。app、/new-project
  skill、命令行三个入口共用同一份逻辑。
- scripts/clone-project.sh + 克隆表单:列出账号可见的全部仓库
  (含组织仓,之前 gh repo list 只列个人仓),按 owner 分组筛选,
  多账号可切换(gh 只用活跃账号的凭据,不切就拉不了另一个账号的
  私有仓)。列表按账号分开缓存 + 后台静默刷新。
- 防污染 deny 刻意**不禁** ~/.claude/plans/:plan mode 的计划文件
  写在那里,禁了所有 plan 会话都会报 Error writing file(真踩过)。

## 顺带修掉

add-project.sh 最后一行是 `[ ${#ALIASES[@]} -gt 0 ] && echo ...`,
没有别名时测试为假,整个脚本退出码变成 1 —— 明明写进去了,调用方
却报「注册 projects.yaml 失败」。改成显式 exit 0。

Co-authored-by: wuguangan <anjaihd0206@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-04 17:19:39 +08:00

69 lines
1.7 KiB
Bash
Executable File

#!/bin/bash
# 添加项目到 projects.yaml
# 用法: bash scripts/add-project.sh <name> <path> [aliases...]
#
# 示例:
# bash scripts/add-project.sh acme-erp ~/code/acme-admin acme-admin erp 后台
HUB_DIR="$(cd "$(dirname "$0")/.." && pwd)"
YAML_FILE="$HUB_DIR/projects.yaml"
NAME="$1"
PROJECT_PATH="$2"
shift 2
ALIASES=("$@")
if [ -z "$NAME" ] || [ -z "$PROJECT_PATH" ]; then
echo "用法: add-project.sh <name> <path> [aliases...]"
echo "示例: add-project.sh acme-erp ~/code/acme-admin acme-admin erp"
exit 1
fi
# 展开 ~ 检查路径
EXPANDED_PATH="${PROJECT_PATH/#\~/$HOME}"
if [ ! -d "$EXPANDED_PATH" ]; then
echo "警告: 目录不存在 $PROJECT_PATH(会继续添加)"
fi
# 确保 projects.yaml 存在
if [ ! -f "$YAML_FILE" ]; then
cp "$HUB_DIR/projects.yaml.example" "$YAML_FILE" 2>/dev/null || cat > "$YAML_FILE" << 'EOF'
# 项目清单
projects:
EOF
fi
# 检查是否已存在
if grep -q "name: $NAME" "$YAML_FILE" 2>/dev/null; then
echo "项目 $NAME 已存在于 projects.yaml"
exit 1
fi
# 构建别名字符串
ALIAS_STR=""
if [ ${#ALIASES[@]} -gt 0 ]; then
ALIAS_STR=" aliases: [$(IFS=', '; echo "${ALIASES[*]}")]"
fi
# 追加
cat >> "$YAML_FILE" << EOF
- name: $NAME
${ALIAS_STR:+$ALIAS_STR
} path: $PROJECT_PATH
description: ""
tags: []
EOF
echo "已添加: $NAME → $PROJECT_PATH"
if [ ${#ALIASES[@]} -gt 0 ]; then
echo " 别名: ${ALIASES[*]}"
fi
# 必须显式 exit 0。
# 之前最后一行是 `[ ${#ALIASES[@]} -gt 0 ] && echo ...`:没有别名时这个测试为假,
# 脚本退出码就成了 1 —— 明明写进去了,调用方(clone-project.sh / app)却报
# "注册 projects.yaml 失败"。真踩过。
exit 0