Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
[![Version](https://img.shields.io/badge/version-6.2.0-brightgreen.svg)](.claude-plugin/marketplace.json)
[![Python](https://img.shields.io/badge/Python-3.10+-blue.svg)](https://www.python.org/)
[![Claude Code](https://img.shields.io/badge/Claude%20Code-Compatible-purple.svg)](https://claude.ai/claude-code)
[![OpenCode](https://img.shields.io/badge/OpenCode-Compatible-success.svg)](https://opencode.ai)
[![Marketplace](https://img.shields.io/badge/Claude%20Code-Marketplace-black.svg)](.claude-plugin/marketplace.json)

<a href="https://trendshift.io/repositories/22487" target="_blank"><img src="https://trendshift.io/api/badge/repositories/22487" alt="lingfengQAQ%2Fwebnovel-writer | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
Expand Down
43 changes: 41 additions & 2 deletions webnovel-writer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,53 @@

## 依赖与安装

通过 Claude Code Marketplace 安装(推荐):
### Claude Code(推荐)

通过 Claude Code Marketplace 安装:

```bash
claude plugin marketplace add lingfengQAQ/webnovel-writer --scope user
claude plugin install webnovel-writer@webnovel-writer-marketplace --scope user
```

Python 依赖:
### OpenCode

本项目同时兼容 [OpenCode](https://opencode.ai)。安装步骤:

1. 将 `skills/`、`agents/`、`scripts/`、`dashboard/`、`references/`、`templates/` 和 `hooks/` 拷贝到本地目录(例如 `~/.opencode/plugins/webnovel-writer/`)。

2. 将 skills 链接到 OpenCode 可发现的位置:
```bash
# 项目级:在书项目根目录下
mkdir -p .opencode/skills
cp -r <plugin_dir>/skills/* .opencode/skills/

# 或全局:
mkdir -p ~/.config/opencode/skills
cp -r <plugin_dir>/skills/* ~/.config/opencode/skills/
```

3. 设置环境变量(在 shell profile 或系统环境变量中):
```bash
# Linux/Mac(添加到 ~/.bashrc 或 ~/.zshrc)
export OPENCODE_PLUGIN_ROOT="/path/to/plugin/dir"
export OPENCODE_PROJECT_DIR="/path/to/your/novel/project"

# Windows(管理员 PowerShell)
setx OPENCODE_PLUGIN_ROOT "D:\\path\\to\\plugin"
setx OPENCODE_PROJECT_DIR "D:\\path\\to\\novel"
```

> **注意**:OpenCode 的配置文件 (`opencode.json`) 不支持设置环境变量。环境变量须通过操作系统或 shell profile 设置。插件自带的 `opencode.json` 仅用于配置技能权限,非必需。

4. Python 依赖:
```bash
python -m pip install -r scripts/requirements.txt
```

> **环境变量说明**:OpenCode 不设置 `CLAUDE_*` 变量。本项目同时识别 `OPENCODE_PLUGIN_ROOT`(等价于 `CLAUDE_PLUGIN_ROOT`)和 `OPENCODE_PROJECT_DIR`(等价于 `CLAUDE_PROJECT_DIR`)。设置其中任一即可,两者都不设置时脚本会尝试从当前目录推断项目根。

### Python 依赖(通用)

```bash
python -m pip install -r scripts/requirements.txt
Expand Down
9 changes: 7 additions & 2 deletions webnovel-writer/hooks/session_start.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,13 @@ def main() -> int:
if _truthy(os.environ.get(DISABLE_ENV)):
return 0

plugin_root = Path(os.environ.get("CLAUDE_PLUGIN_ROOT") or Path(__file__).resolve().parents[1])
workspace_root = os.environ.get("CLAUDE_PROJECT_DIR") or os.getcwd()
# OpenCode compat: check OPENCODE_PLUGIN_ROOT / OPENCODE_PROJECT_DIR as fallback
plugin_root = Path(
os.environ.get("CLAUDE_PLUGIN_ROOT")
or os.environ.get("OPENCODE_PLUGIN_ROOT")
or Path(__file__).resolve().parents[1]
)
workspace_root = os.environ.get("CLAUDE_PROJECT_DIR") or os.environ.get("OPENCODE_PROJECT_DIR") or os.getcwd()
webnovel = plugin_root / "scripts" / "webnovel.py"
if not webnovel.is_file():
return 0
Expand Down
18 changes: 14 additions & 4 deletions webnovel-writer/scripts/project_locator.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@

# Claude Code 常见环境变量(存在时优先作为“工作区根目录”提示)
ENV_CLAUDE_PROJECT_DIR = "CLAUDE_PROJECT_DIR"
ENV_OPENCODE_PROJECT_DIR = "OPENCODE_PROJECT_DIR"
ENV_CLAUDE_HOME = "CLAUDE_HOME"
ENV_WEBNOVEL_CLAUDE_HOME = "WEBNOVEL_CLAUDE_HOME"
ENV_OPENCODE_HOME = "OPENCODE_HOME"


def _find_git_root(cwd: Path) -> Optional[Path]:
Expand Down Expand Up @@ -60,12 +62,20 @@ def _normcase_path_key(p: Path) -> str:


def _get_user_claude_root() -> Path:
raw = os.environ.get(ENV_WEBNOVEL_CLAUDE_HOME) or os.environ.get(ENV_CLAUDE_HOME)
raw = (
os.environ.get(ENV_WEBNOVEL_CLAUDE_HOME)
or os.environ.get(ENV_CLAUDE_HOME)
or os.environ.get(ENV_OPENCODE_HOME)
)
if raw:
try:
return normalize_windows_path(raw).expanduser().resolve()
except Exception:
return normalize_windows_path(raw).expanduser()
for home_dir in (".opencode", ".claude"):
candidate = (Path.home() / home_dir).resolve()
if candidate.is_dir():
return candidate
return (Path.home() / ".claude").resolve()


Expand Down Expand Up @@ -135,7 +145,7 @@ def _resolve_project_root_from_global_registry(
return None

hints: list[Path] = []
env_ws = os.environ.get(ENV_CLAUDE_PROJECT_DIR)
env_ws = os.environ.get(ENV_CLAUDE_PROJECT_DIR) or os.environ.get(ENV_OPENCODE_PROJECT_DIR)
if env_ws:
hints.append(normalize_windows_path(env_ws).expanduser())
if workspace_hint is not None:
Expand Down Expand Up @@ -208,7 +218,7 @@ def update_global_registry_current_project(

ws = workspace_root
if ws is None:
env_ws = os.environ.get(ENV_CLAUDE_PROJECT_DIR)
env_ws = os.environ.get(ENV_CLAUDE_PROJECT_DIR) or os.environ.get(ENV_OPENCODE_PROJECT_DIR)
if env_ws:
ws = normalize_windows_path(env_ws).expanduser()
if ws is None:
Expand Down Expand Up @@ -407,7 +417,7 @@ def resolve_project_root(explicit_project_root: Optional[str] = None, *, cwd: Op
# 用户级 registry fallback(仅在“有上下文提示”时启用,避免误命中)
# - 若 CLAUDE_PROJECT_DIR 存在:认为 Claude Code 提供了工作区上下文
# - 否则仅在 base 位于某个已记录 workspace 内时启用(前缀匹配)
allow_last_used = bool(os.environ.get(ENV_CLAUDE_PROJECT_DIR))
allow_last_used = bool(os.environ.get(ENV_CLAUDE_PROJECT_DIR) or os.environ.get(ENV_OPENCODE_PROJECT_DIR))
reg_root = _resolve_project_root_from_global_registry(
base,
workspace_hint=None,
Expand Down
5 changes: 5 additions & 0 deletions webnovel-writer/scripts/runtime_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
# -*- coding: utf-8 -*-
"""
Runtime compatibility helpers.

OpenCode adaptation notes:
- OpenCode does not set CLAUDE_PLUGIN_ROOT / CLAUDE_PROJECT_DIR.
- Users should set OPENCODE_PLUGIN_ROOT and OPENCODE_PROJECT_DIR.
- Python code checks both, preferring CLAUDE_* when set, falling back to OPENCODE_*.
"""

from __future__ import annotations
Expand Down
4 changes: 3 additions & 1 deletion webnovel-writer/skills/webnovel-dashboard/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ allowed-tools: Bash Read
### Step 1:确认环境与模块目录

```bash
export WORKSPACE_ROOT="${CLAUDE_PROJECT_DIR:-$PWD}"
export WORKSPACE_ROOT="${CLAUDE_PROJECT_DIR:-${OPENCODE_PROJECT_DIR:-$PWD}}"

export CLAUDE_PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-${OPENCODE_PLUGIN_ROOT:-}}"

if [ -z "${CLAUDE_PLUGIN_ROOT}" ] || [ ! -d "${CLAUDE_PLUGIN_ROOT}/dashboard" ]; then
echo "ERROR: 未找到 dashboard 模块: ${CLAUDE_PLUGIN_ROOT}/dashboard" >&2
Expand Down
3 changes: 2 additions & 1 deletion webnovel-writer/skills/webnovel-doctor/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ argument-hint: "[--chapter N] [--deep]"
准备路径:

```bash
export WORKSPACE_ROOT="${CLAUDE_PROJECT_DIR:-$PWD}"
export WORKSPACE_ROOT="${CLAUDE_PROJECT_DIR:-${OPENCODE_PROJECT_DIR:-$PWD}}"
export CLAUDE_PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-${OPENCODE_PLUGIN_ROOT:-}}"
export SCRIPTS_DIR="${CLAUDE_PLUGIN_ROOT:?}/scripts"
```

Expand Down
4 changes: 3 additions & 1 deletion webnovel-writer/skills/webnovel-init/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ argument-hint: "[书名或灵感(可选)]"

环境设置(bash 命令执行前):
```bash
export WORKSPACE_ROOT="${CLAUDE_PROJECT_DIR:-$PWD}"
export WORKSPACE_ROOT="${CLAUDE_PROJECT_DIR:-${OPENCODE_PROJECT_DIR:-$PWD}}"

export CLAUDE_PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-${OPENCODE_PLUGIN_ROOT:-}}"

if [ -z "${CLAUDE_PLUGIN_ROOT}" ] || [ ! -d "${CLAUDE_PLUGIN_ROOT}/scripts" ]; then
echo "ERROR: 未设置 CLAUDE_PLUGIN_ROOT 或缺少目录: ${CLAUDE_PLUGIN_ROOT}/scripts" >&2
Expand Down
3 changes: 2 additions & 1 deletion webnovel-writer/skills/webnovel-learn/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ argument-hint: "[要记住的写作经验]"
- 用统一入口解析项目根,避免写错目录:

```bash
export WORKSPACE_ROOT="${CLAUDE_PROJECT_DIR:-$PWD}"
export WORKSPACE_ROOT="${CLAUDE_PROJECT_DIR:-${OPENCODE_PROJECT_DIR:-$PWD}}"
export CLAUDE_PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-${OPENCODE_PLUGIN_ROOT:-}}"
export SCRIPTS_DIR="${CLAUDE_PLUGIN_ROOT:?}/scripts"
export PROJECT_ROOT="$(python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "${WORKSPACE_ROOT}" where)"
```
Expand Down
3 changes: 2 additions & 1 deletion webnovel-writer/skills/webnovel-plan/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ argument-hint: "[卷号,如 1]"
## 环境准备

```bash
export WORKSPACE_ROOT="${CLAUDE_PROJECT_DIR:-$PWD}"
export WORKSPACE_ROOT="${CLAUDE_PROJECT_DIR:-${OPENCODE_PROJECT_DIR:-$PWD}}"
export CLAUDE_PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-${OPENCODE_PLUGIN_ROOT:-}}"
export SKILL_ROOT="${CLAUDE_PLUGIN_ROOT}/skills/webnovel-plan"
export SCRIPTS_DIR="${CLAUDE_PLUGIN_ROOT}/scripts"
export PROJECT_ROOT="$(python "${SCRIPTS_DIR}/webnovel.py" --project-root "${WORKSPACE_ROOT}" where)"
Expand Down
3 changes: 2 additions & 1 deletion webnovel-writer/skills/webnovel-query/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ argument-hint: "[查询词,如 角色名/伏笔/境界]"
## 项目根保护

```bash
export WORKSPACE_ROOT="${CLAUDE_PROJECT_DIR:-$PWD}"
export WORKSPACE_ROOT="${CLAUDE_PROJECT_DIR:-${OPENCODE_PROJECT_DIR:-$PWD}}"
export CLAUDE_PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-${OPENCODE_PLUGIN_ROOT:-}}"
export SCRIPTS_DIR="${CLAUDE_PLUGIN_ROOT}/scripts"
export SKILL_ROOT="${CLAUDE_PLUGIN_ROOT}/skills/webnovel-query"
export PROJECT_ROOT="$(python "${SCRIPTS_DIR}/webnovel.py" --project-root "${WORKSPACE_ROOT}" where)"
Expand Down
3 changes: 2 additions & 1 deletion webnovel-writer/skills/webnovel-review/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ argument-hint: "[章号或范围,如 5 或 1-5]"
### Step 1:解析项目根

```bash
export WORKSPACE_ROOT="${CLAUDE_PROJECT_DIR:-$PWD}"
export WORKSPACE_ROOT="${CLAUDE_PROJECT_DIR:-${OPENCODE_PROJECT_DIR:-$PWD}}"
export CLAUDE_PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-${OPENCODE_PLUGIN_ROOT:-}}"
export SCRIPTS_DIR="${CLAUDE_PLUGIN_ROOT}/scripts"
export PROJECT_ROOT="$(python "${SCRIPTS_DIR}/webnovel.py" --project-root "${WORKSPACE_ROOT}" where)"
```
Expand Down
3 changes: 2 additions & 1 deletion webnovel-writer/skills/webnovel-write/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ python -X utf8 "${SCRIPTS_DIR}/reference_search.py" --skill write --table {表
### 准备:预检

```bash
export WORKSPACE_ROOT="${CLAUDE_PROJECT_DIR:-$PWD}"
export WORKSPACE_ROOT="${CLAUDE_PROJECT_DIR:-${OPENCODE_PROJECT_DIR:-$PWD}}"
export CLAUDE_PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-${OPENCODE_PLUGIN_ROOT:-}}"
export SCRIPTS_DIR="${CLAUDE_PLUGIN_ROOT:?}/scripts"
export SKILL_ROOT="${CLAUDE_PLUGIN_ROOT:?}/skills/webnovel-write"

Expand Down