From 1a74b15ed5b6ce1bfcca23f23ce8d37c50078a82 Mon Sep 17 00:00:00 2001 From: laily Date: Sun, 23 Aug 2026 22:02:06 +0800 Subject: [PATCH] feat: update --- AGENTS.md | 4 +++- skiff/agents.py | 1 + skiff/cli.py | 2 +- skiff/paths.py | 4 +++- skills/deb-publisher/SKILL.md | 19 ++++++++++++++++++- tests/test_select.py | 8 ++++---- 6 files changed, 30 insertions(+), 8 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 56ce32e..adcb399 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -148,7 +148,8 @@ catalog.yaml ←── skiff add / fetch ▼ ▼ ~/.cursor/skills/ project/.agents/skills/ ~/.claude/skills/ project/.claude/skills/ -~/.codex/skills/ project/.skills.yaml +~/.codex/skills/ project/.opencode/skills/ +~/.config/opencode/skills/ project/.skills.yaml ``` ### Skill 三层分类 @@ -176,6 +177,7 @@ catalog.yaml ←── skiff add / fetch | Cursor | `~/.cursor/skills/` | `.agents/skills/` | | Claude Code | `~/.claude/skills/` | `.claude/skills/` | | Codex | `~/.codex/skills/` | `.agents/skills/` | +| OpenCode | `~/.config/opencode/skills/` | `.opencode/skills/` | --- diff --git a/skiff/agents.py b/skiff/agents.py index 121bb15..b3a2a10 100644 --- a/skiff/agents.py +++ b/skiff/agents.py @@ -9,6 +9,7 @@ AGENT_ALIASES: dict[str, str] = { "claude": "claude", "claude-code": "claude", "codex": "codex", + "opencode": "opencode", "*": "*", } diff --git a/skiff/cli.py b/skiff/cli.py index 4417c9c..3b7601e 100644 --- a/skiff/cli.py +++ b/skiff/cli.py @@ -1655,7 +1655,7 @@ def _add_common_flags(parser: argparse.ArgumentParser) -> None: nargs="+", action="append", metavar="AGENT", - help="目标 agent(cursor、claude、claude-code、codex、*)", + help="目标 agent(cursor、claude、claude-code、codex、opencode、*)", ) parser.add_argument( "-g", diff --git a/skiff/paths.py b/skiff/paths.py index f891a20..2c4eaef 100644 --- a/skiff/paths.py +++ b/skiff/paths.py @@ -20,15 +20,17 @@ AGENT_GLOBAL: dict[str, Path] = { "cursor": HOME / ".cursor" / "skills", "claude": HOME / ".claude" / "skills", "codex": HOME / ".codex" / "skills", + "opencode": HOME / ".config" / "opencode" / "skills", } AGENT_PROJECT: dict[str, str] = { "cursor": ".agents/skills", "claude": ".claude/skills", "codex": ".agents/skills", + "opencode": ".opencode/skills", } -ALL_TARGETS = ("cursor", "claude", "codex") +ALL_TARGETS = ("cursor", "claude", "codex", "opencode") def resolve_targets(target: str | None) -> list[str]: diff --git a/skills/deb-publisher/SKILL.md b/skills/deb-publisher/SKILL.md index b522d63..dd8d0a1 100644 --- a/skills/deb-publisher/SKILL.md +++ b/skills/deb-publisher/SKILL.md @@ -39,6 +39,7 @@ rg -n -i --hidden --glob '!.git' \ - `Makefile`、CI 配置、`debian/`、构建脚本和发布文档。 - 版本号、包名、架构、产物目录和仓库名如何传入。 - 发布端点、认证方式以及发布是否由构建目标自动触发。 +- 项目根目录或发布文档是否提供 `.env` 配置;只确认变量名,不打印其值。 - 当前工作树和目标版本是否匹配。 优先复用已有构建入口。上传默认使用本 skill 的 `scripts/upload_deb.sh`,不要把它 @@ -52,12 +53,25 @@ rg -n -i --hidden --glob '!.git' \ 执行上传前确认: - 目标服务和仓库来自项目配置或用户输入,不猜测生产端点。 -- 认证令牌已通过环境变量或密钥系统提供。 +- 认证令牌已通过环境变量、密钥系统或项目 `.env` 提供。 - 目标版本、架构和产物路径能够从构建配置推导。 - 相同版本是否允许覆盖;无法确认且可能覆盖时,先询问用户。 绝不把令牌写入命令输出、文件、提交或最终回复。不要用 `set -x` 执行含凭据的脚本。 +如果项目根目录存在 `.env`,且当前 shell 尚未提供所需变量,上传前必须显式加载 +该文件;上传脚本不会自动读取 `.env`: + +```bash +set -a +. "$PROJECT_ROOT/.env" +set +a +``` + +加载后确认 `DEB_SERVER_URL`、`DEB_REPOSITORY`、`DEB_TOKEN` 已非空;如配置了自定义 +上传路径,也确认 `DEB_UPLOAD_PATH`。不得输出 `.env` 内容、令牌或完整环境变量值。 +当前 shell 中已显式设置的值优先于 `.env`,若需覆盖 `.env`,加载后重新导出显式值。 + ### 3. 构建包 使用项目声明的构建目标,并显式传入版本。例如项目提供 Make 目标时: @@ -105,6 +119,9 @@ DEB_REPOSITORY="$DEB_REPOSITORY" \ /scripts/upload_deb.sh ``` +执行上述命令前,若配置来自项目 `.env`,先按第 2 步加载 `.env`;不要把 `.env` +复制到 skill 或项目之外的临时位置,也不要把 token 作为命令行参数。 + 不要把脚本复制进当前项目,也不要将 token 作为命令行参数。脚本默认请求 `/api/v2/upload/package`,以 multipart 字段 `package`、`token`、 `repository_name` 上传,接受 `200` 和 `201` 为成功。端点路径不同时可设置 diff --git a/tests/test_select.py b/tests/test_select.py index eb03209..5110528 100644 --- a/tests/test_select.py +++ b/tests/test_select.py @@ -78,7 +78,7 @@ class SelectorTests(unittest.TestCase): "ack", "builtin", installed=False, - readonly_status="全局: cursor,claude,codex", + readonly_status="全局: cursor,claude,codex,opencode", ) ] screen = Mock() @@ -101,7 +101,7 @@ class SelectorTests(unittest.TestCase): if call.args[0] == 3 ) self.assertIn("[ ] ack", title) - self.assertIn("全局: cursor,claude,codex", title) + self.assertIn("全局: cursor,claude,codex,opencode", title) self.assertNotIn("初始化", title) def test_selector_renders_description_on_indented_second_line(self) -> None: @@ -370,7 +370,7 @@ class SelectCommandTests(unittest.TestCase): other.mkdir() global_dirs = { target: root / target / "skills" - for target in ("cursor", "claude", "codex") + for target in ("cursor", "claude", "codex", "opencode") } for directory in global_dirs.values(): directory.mkdir(parents=True) @@ -385,7 +385,7 @@ class SelectCommandTests(unittest.TestCase): note = cli._global_installation_note( "ack", expected, - ["cursor", "claude", "codex"], + ["cursor", "claude", "codex", "opencode"], ) self.assertEqual(note, "全局: cursor;全局同名冲突: claude")