duaer-spec 0.6.3 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/rules/agents-workflow.md +62 -0
- package/.claude/rules/ai-ui-copy.md +9 -0
- package/.claude/rules/duaer-spec.md +51 -0
- package/.cursor/rules/agents-workflow.mdc +6 -3
- package/.cursor/rules/duaer-spec.mdc +7 -4
- package/.cursor/skills/duaer-do/SKILL.md +4 -0
- package/ADOPT.md +4 -0
- package/AGENTS.md +23 -2
- package/CHANGELOG.md +17 -0
- package/CLAUDE.md +26 -0
- package/DUADER.md +11 -5
- package/README.md +3 -1
- package/README.zh-CN.md +12 -1
- package/bin/duaer.mjs +84 -3
- package/docs/agent/branching-and-release.md +12 -0
- package/docs/agent/e2e-test-plan.md +4 -0
- package/package.json +7 -3
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<!-- duaer-spec agent ops (develop+main, feat/fix, .worktree, push opt-in) -->
|
|
2
|
+
|
|
3
|
+
# Agent development workflow
|
|
4
|
+
|
|
5
|
+
Part of **duaer-spec**. Authoritative over Duaer when they conflict.
|
|
6
|
+
|
|
7
|
+
## Required branches
|
|
8
|
+
|
|
9
|
+
| Branch | Role |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `main` | Production / online |
|
|
12
|
+
| `develop` | Day-to-day integration |
|
|
13
|
+
| `feat/<name>` | Feature → merge to `develop` |
|
|
14
|
+
| `fix/<name>` | Bugfix → `develop` (hotfix: from `main` → `main` then `develop`) |
|
|
15
|
+
|
|
16
|
+
Detail: `docs/agent/branching-and-release.md`.
|
|
17
|
+
|
|
18
|
+
## Isolated development (mandatory worktree)
|
|
19
|
+
|
|
20
|
+
Before editing files for a new request:
|
|
21
|
+
|
|
22
|
+
1. Update local **`develop`** (hotfix: **`main`**)
|
|
23
|
+
2. Create `feat/<name>` or `fix/<name>`
|
|
24
|
+
3. Create worktree at **`.worktree/feat-<name>`** or **`.worktree/fix-<name>`**
|
|
25
|
+
(slash → hyphen). Do **not** reuse the Brief folder name
|
|
26
|
+
(`.duaer/specs/<nnn-slug>/`) as the worktree id.
|
|
27
|
+
4. Develop only inside that worktree
|
|
28
|
+
5. Never develop on `main` / `develop` or in the primary checkout
|
|
29
|
+
6. Never reuse another agent's branch/worktree
|
|
30
|
+
7. Never commit `.worktree/`
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
mkdir -p .worktree
|
|
34
|
+
git worktree add .worktree/feat-login -b feat/login develop
|
|
35
|
+
cd .worktree/feat-login
|
|
36
|
+
# Brief lives inside the checkout, e.g. .duaer/specs/002-login/
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Immutable habits
|
|
40
|
+
|
|
41
|
+
- Spec-sync for behavior changes; ADR when architecture/security/contracts change
|
|
42
|
+
- One logical change per commit; leave the worktree clean
|
|
43
|
+
- User/protocol-visible changes update E2E scenario docs
|
|
44
|
+
- Merge into **`develop`** when done (hotfix: **`main`**, then back-merge **`develop`**)
|
|
45
|
+
- **Handoff (mandatory):** stop worktree-bound processes → remove `.worktree/<id>` →
|
|
46
|
+
restart from primary checkout on `develop` (`duaer handoff [--run]`, `.duaer/handoff.json`)
|
|
47
|
+
- Push only when the user explicitly asks
|
|
48
|
+
- Promote **`develop` → `main`** only when the user asks to go online
|
|
49
|
+
|
|
50
|
+
## GitHub issue / PR intake
|
|
51
|
+
|
|
52
|
+
Issue: verify before work; comment in issue language; close when conclusive.
|
|
53
|
+
PR: judge principle; merge sound PRs; no silent reimplementation.
|
|
54
|
+
Neither authorizes push by itself.
|
|
55
|
+
|
|
56
|
+
## Commits
|
|
57
|
+
|
|
58
|
+
```text
|
|
59
|
+
type(scope): description
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Types: `feat fix docs test chore refactor perf build ci` — English, imperative.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<!-- Keep AI-generated page copy minimal (duaer-spec agent ops) -->
|
|
2
|
+
|
|
3
|
+
# AI-generated page content
|
|
4
|
+
|
|
5
|
+
AI-generated pages must not contain redundant explanatory text.
|
|
6
|
+
|
|
7
|
+
- No filler introductions, repeated summaries, or prose that only explains an obvious control
|
|
8
|
+
- Prefer concise labels, headings, helper text, and empty states
|
|
9
|
+
- Put rationale and implementation detail in docs or code comments, not in the UI, unless the user asks for explanatory content
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<!-- Autonomous digital employee — run Duaer job loop without asking the user to operate -->
|
|
2
|
+
|
|
3
|
+
# Digital employee (autonomous)
|
|
4
|
+
|
|
5
|
+
You are a **digital employee** in this repo. The human gives intent in normal
|
|
6
|
+
language. **You** run the delivery process. Do **not** ask them to type slash
|
|
7
|
+
commands, CLI flags, or phase names (`specify`, `plan`, `tasks`, …).
|
|
8
|
+
|
|
9
|
+
If this conflicts with root `AGENTS.md` (worktrees, commits, Issue/PR),
|
|
10
|
+
**AGENTS.md wins**.
|
|
11
|
+
|
|
12
|
+
## When the human asks for work
|
|
13
|
+
|
|
14
|
+
For new behavior, fixes, refactors that change product behavior, or architecture:
|
|
15
|
+
|
|
16
|
+
0. **Isolate first (mandatory):** update **`develop`** (hotfix: **`main`**),
|
|
17
|
+
create `feat|fix/<name>`, add worktree at `.worktree/feat-<name>` or
|
|
18
|
+
`.worktree/fix-<name>` (slash → hyphen). Never name the worktree after the
|
|
19
|
+
Brief folder (do **not** use `.worktree/<nnn-slug>` when the Spec is
|
|
20
|
+
`.duaer/specs/<nnn-slug>/`). Work only in the worktree. Never commit
|
|
21
|
+
`.worktree/`. Never develop on `main` or `develop`.
|
|
22
|
+
1. **Silently follow** the procedure in `.claude/skills/duaer-do/SKILL.md`
|
|
23
|
+
(assign Brief → light tasks → implement → converge → handoff line).
|
|
24
|
+
2. Do **not** wait for `/duaer-do` or any other skill invocation.
|
|
25
|
+
3. Do **not** say “please run `/duaer-specify`” — you do it.
|
|
26
|
+
4. Do **not** dump a methodology tutorial unless they ask how Duaer works.
|
|
27
|
+
5. Merge to **`develop`** when done (hotfix: **`main`**, then back-merge
|
|
28
|
+
**`develop`**). Promote to **`main`** only if the user asks to go online.
|
|
29
|
+
6. **Handoff (mandatory):** stop processes bound to `.worktree/<id>/`, remove
|
|
30
|
+
the worktree, then restart services from the primary checkout on `develop`
|
|
31
|
+
using `.duaer/handoff.json` / `duaer handoff [--run]`. Never leave the user
|
|
32
|
+
on a dead worktree server.
|
|
33
|
+
See `docs/agent/branching-and-release.md`.
|
|
34
|
+
|
|
35
|
+
## Handoff
|
|
36
|
+
|
|
37
|
+
- End with whether the **job** is accepted or still open (one clear line).
|
|
38
|
+
- Do **not** claim “done” / “finished” / “complete” unless `delivery.json` is
|
|
39
|
+
`accepted` and open tasks are clear.
|
|
40
|
+
- Do **not** tell them to run `duaer status` unless they want a machine check;
|
|
41
|
+
you already know the handoff state.
|
|
42
|
+
|
|
43
|
+
## Forbidden
|
|
44
|
+
|
|
45
|
+
- Jump from chat to code with no Brief under `.duaer/specs/`.
|
|
46
|
+
- Making the human operate the workflow.
|
|
47
|
+
|
|
48
|
+
## Optional finer tools (agent-only)
|
|
49
|
+
|
|
50
|
+
Step skills (`duaer-specify`, `duaer-plan`, …) are **your** playbooks when a
|
|
51
|
+
job is large. The human should not need to know they exist.
|
|
@@ -24,7 +24,9 @@ Before editing files for a new request:
|
|
|
24
24
|
|
|
25
25
|
1. Update local **`develop`** (hotfix: **`main`**)
|
|
26
26
|
2. Create `feat/<name>` or `fix/<name>`
|
|
27
|
-
3. Create worktree at **`.worktree
|
|
27
|
+
3. Create worktree at **`.worktree/feat-<name>`** or **`.worktree/fix-<name>`**
|
|
28
|
+
(slash → hyphen). Do **not** reuse the Brief folder name
|
|
29
|
+
(`.duaer/specs/<nnn-slug>/`) as the worktree id.
|
|
28
30
|
4. Develop only inside that worktree
|
|
29
31
|
5. Never develop on `main` / `develop` or in the primary checkout
|
|
30
32
|
6. Never reuse another agent's branch/worktree
|
|
@@ -32,8 +34,9 @@ Before editing files for a new request:
|
|
|
32
34
|
|
|
33
35
|
```bash
|
|
34
36
|
mkdir -p .worktree
|
|
35
|
-
git worktree add .worktree
|
|
36
|
-
cd .worktree
|
|
37
|
+
git worktree add .worktree/feat-login -b feat/login develop
|
|
38
|
+
cd .worktree/feat-login
|
|
39
|
+
# Brief lives inside the checkout, e.g. .duaer/specs/002-login/
|
|
37
40
|
```
|
|
38
41
|
|
|
39
42
|
## Immutable habits
|
|
@@ -17,10 +17,13 @@ If this conflicts with root `AGENTS.md` (worktrees, commits, Issue/PR),
|
|
|
17
17
|
For new behavior, fixes, refactors that change product behavior, or architecture:
|
|
18
18
|
|
|
19
19
|
0. **Isolate first (mandatory):** update **`develop`** (hotfix: **`main`**),
|
|
20
|
-
create `feat|fix/<name>`, add worktree at `.worktree
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
create `feat|fix/<name>`, add worktree at `.worktree/feat-<name>` or
|
|
21
|
+
`.worktree/fix-<name>` (slash → hyphen). Never name the worktree after the
|
|
22
|
+
Brief folder (do **not** use `.worktree/<nnn-slug>` when the Spec is
|
|
23
|
+
`.duaer/specs/<nnn-slug>/`). Work only in the worktree. Never commit
|
|
24
|
+
`.worktree/`. Never develop on `main` or `develop`.
|
|
25
|
+
1. **Silently follow** the procedure in the `duaer-do` skill
|
|
26
|
+
(`.cursor/skills/duaer-do/SKILL.md` or `.claude/skills/duaer-do/SKILL.md`)
|
|
24
27
|
(assign Brief → light tasks → implement → converge → handoff line).
|
|
25
28
|
2. Do **not** wait for `/duaer-do` or any other skill invocation.
|
|
26
29
|
3. Do **not** say “please run `/duaer-specify`” — you do it.
|
|
@@ -32,6 +32,10 @@ Do **not** lecture about methodology. Do **not** ask them to run commands.
|
|
|
32
32
|
- Matching active job (`.duaer/active-job.json` + `spec.md`) → update acceptance if needed.
|
|
33
33
|
- Else create `.duaer/specs/<nnn-slug>/spec.md` and `.duaer/active-job.json`
|
|
34
34
|
(same outcome as specify). Keep small asks short: what / why / acceptance.
|
|
35
|
+
- The Brief path is **not** the worktree path. Isolation uses
|
|
36
|
+
`.worktree/feat-<name>/` (or `fix-…`); the Spec stays under
|
|
37
|
+
`.duaer/specs/<nnn-slug>/` inside that checkout. Never set both names to
|
|
38
|
+
the same `<nnn-slug>`.
|
|
35
39
|
|
|
36
40
|
2. **Break down** — If `tasks.md` missing, write a short checklist from the Spec.
|
|
37
41
|
Skip a heavy plan unless architecture or contracts change.
|
package/ADOPT.md
CHANGED
|
@@ -32,9 +32,13 @@ npx duaer-spec init --here --ops
|
|
|
32
32
|
npx duaer-spec update --method # rare; usually omit
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
+
Works with **Cursor** and **Claude Code** (both hosts installed by default).
|
|
36
|
+
|
|
35
37
|
## What you get
|
|
36
38
|
|
|
37
39
|
- Autonomous job loop (ask → Brief → work → accept)
|
|
40
|
+
- Cursor: `.cursor/rules` + `.cursor/skills`
|
|
41
|
+
- Claude Code: `CLAUDE.md` + `.claude/rules` + `.claude/skills`
|
|
38
42
|
- `.duaer/handoff.json` + `duaer handoff` after worktree remove
|
|
39
43
|
- Agent ops: `main` / `develop` / `feat` / `fix` + `.worktree/`
|
|
40
44
|
|
package/AGENTS.md
CHANGED
|
@@ -147,10 +147,31 @@ Example (normal feature):
|
|
|
147
147
|
git switch develop
|
|
148
148
|
git pull --ff-only
|
|
149
149
|
mkdir -p .worktree
|
|
150
|
-
git worktree add .worktree
|
|
151
|
-
cd .worktree
|
|
150
|
+
git worktree add .worktree/feat-login -b feat/login develop
|
|
151
|
+
cd .worktree/feat-login
|
|
152
152
|
```
|
|
153
153
|
|
|
154
|
+
**Two different folders — do not give them the same name:**
|
|
155
|
+
|
|
156
|
+
| Layer | Path | Role |
|
|
157
|
+
|---|---|---|
|
|
158
|
+
| Worktree | `.worktree/feat-<name>/` | Full git checkout for isolation |
|
|
159
|
+
| Brief | `.duaer/specs/<nnn-slug>/` | Job Spec / tasks / delivery stamp |
|
|
160
|
+
|
|
161
|
+
A worktree is a **complete** repo copy, so Briefs live *inside* it:
|
|
162
|
+
|
|
163
|
+
```text
|
|
164
|
+
.worktree/feat-login/.duaer/specs/002-login/spec.md
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
That is expected. What is **wrong** is reusing the Brief folder name as the
|
|
168
|
+
worktree id (e.g. `.worktree/002-login/.../specs/002-login/`) — it looks like
|
|
169
|
+
double nesting and confuses humans. Always:
|
|
170
|
+
|
|
171
|
+
* Branch: `feat/<name>` or `fix/<name>`
|
|
172
|
+
* Worktree: `.worktree/feat-<name>` or `.worktree/fix-<name>` (slash → hyphen)
|
|
173
|
+
* Brief: `.duaer/specs/<nnn-slug>/` (numbered catalog; may differ from `<name>`)
|
|
174
|
+
|
|
154
175
|
Branch and worktree names must be unique and clearly associated with the request.
|
|
155
176
|
Do **not** place request worktrees outside the repo (for example `../worktrees/`)
|
|
156
177
|
unless the project baseline explicitly overrides this and still keeps them
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.7.0 — 2026-09-15
|
|
4
|
+
|
|
5
|
+
### Claude Code host
|
|
6
|
+
|
|
7
|
+
- `init` / `update` install **both** Cursor and Claude Code surfaces
|
|
8
|
+
- Claude: `CLAUDE.md`, `.claude/rules/*.md`, `.claude/skills/duaer-*` (mirrored)
|
|
9
|
+
- Cursor: `.cursor/rules/*.mdc`, `.cursor/skills/duaer-*` (unchanged)
|
|
10
|
+
|
|
11
|
+
## 0.6.4 — 2026-09-15
|
|
12
|
+
|
|
13
|
+
### Worktree ≠ Brief folder name
|
|
14
|
+
|
|
15
|
+
- Clarify two layers: `.worktree/feat-<name>/` (full checkout) vs
|
|
16
|
+
`.duaer/specs/<nnn-slug>/` (Brief)
|
|
17
|
+
- Forbid naming the worktree after the Brief slug (avoids
|
|
18
|
+
`.worktree/002-x/.../specs/002-x/` double naming)
|
|
19
|
+
|
|
3
20
|
## 0.6.3 — 2026-09-15
|
|
4
21
|
|
|
5
22
|
### Docs: update path in installed 说明
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# CLAUDE.md — duaer-spec
|
|
2
|
+
|
|
3
|
+
This repository uses **duaer-spec**: coding agents are digital employees.
|
|
4
|
+
|
|
5
|
+
**Precedence:** `AGENTS.md` (ops) wins over `DUADER.md` / `.duaer/` (method).
|
|
6
|
+
|
|
7
|
+
## Always on
|
|
8
|
+
|
|
9
|
+
- Follow `.claude/rules/` in this project.
|
|
10
|
+
- For product work, run the job loop in `.claude/skills/duaer-do/SKILL.md`
|
|
11
|
+
without waiting for slash commands.
|
|
12
|
+
- Do not ask the human to operate phases, CLI flags, or skill names.
|
|
13
|
+
|
|
14
|
+
## Layout
|
|
15
|
+
|
|
16
|
+
| Host | Rules | Skills |
|
|
17
|
+
|---|---|---|
|
|
18
|
+
| Claude Code | `.claude/rules/` | `.claude/skills/` |
|
|
19
|
+
| Cursor | `.cursor/rules/` | `.cursor/skills/` |
|
|
20
|
+
|
|
21
|
+
Both are installed by `npx duaer-spec init --here` / `update`.
|
|
22
|
+
|
|
23
|
+
## Branches
|
|
24
|
+
|
|
25
|
+
See `docs/agent/branching-and-release.md` and `AGENTS.md`.
|
|
26
|
+
Worktree: `.worktree/feat-<name>/` — not the same name as `.duaer/specs/<nnn-slug>/`.
|
package/DUADER.md
CHANGED
|
@@ -14,7 +14,7 @@ runs Brief → work → accept. Humans are not the operators of the phase machin
|
|
|
14
14
|
|
|
15
15
|
## Agent procedure (autonomous)
|
|
16
16
|
|
|
17
|
-
Follow `.cursor/skills/
|
|
17
|
+
Follow the `duaer-do` skill (`.cursor/skills/` or `.claude/skills/`) on every product ask — **without**
|
|
18
18
|
waiting for a slash invocation:
|
|
19
19
|
|
|
20
20
|
1. Assign Brief + `active-job.json`
|
|
@@ -34,12 +34,18 @@ Humans need not configure it for everyday use.
|
|
|
34
34
|
## Layout
|
|
35
35
|
|
|
36
36
|
```text
|
|
37
|
-
.
|
|
38
|
-
.duaer/
|
|
39
|
-
.
|
|
40
|
-
.
|
|
37
|
+
.worktree/feat-<name>/ # git isolation (full checkout)
|
|
38
|
+
.duaer/active-job.json
|
|
39
|
+
.duaer/specs/<nnn-slug>/ # Brief (≠ worktree folder name)
|
|
40
|
+
spec.md | tasks.md | delivery.json
|
|
41
|
+
.cursor/rules|skills/ # Cursor host
|
|
42
|
+
.claude/rules|skills/ + CLAUDE.md # Claude Code host
|
|
41
43
|
```
|
|
42
44
|
|
|
45
|
+
Worktree and Brief are different layers. Prefer
|
|
46
|
+
`.worktree/feat-login/.duaer/specs/002-login/` — not
|
|
47
|
+
`.worktree/002-login/.duaer/specs/002-login/`.
|
|
48
|
+
|
|
43
49
|
## Related
|
|
44
50
|
|
|
45
51
|
- Adopt: [`ADOPT.md`](ADOPT.md)
|
package/README.md
CHANGED
|
@@ -19,7 +19,9 @@ npx duaer-spec init --here
|
|
|
19
19
|
npx duaer-spec update
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
Then use Cursor as usual — describe what you want.
|
|
22
|
+
Then use **Cursor** or **Claude Code** as usual — describe what you want.
|
|
23
|
+
|
|
24
|
+
Install writes both `.cursor/` and `.claude/` (plus `CLAUDE.md`).
|
|
23
25
|
|
|
24
26
|
中文说明:[`README.zh-CN.md`](README.zh-CN.md)
|
|
25
27
|
|
package/README.zh-CN.md
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
**Duaer** 把 AI 编程助手变成**数字员工**:你用自然语言提需求,它自己跑 Spec → 实现 → 验收;只有交接干净才算完成。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
你**不用**操作流程。装一次之后,在 **Cursor** 或 **Claude Code** 里说话即可。
|
|
6
|
+
|
|
7
|
+
`init` / `update` 会同时写入 `.cursor/` 与 `.claude/`(以及 `CLAUDE.md`)。
|
|
6
8
|
|
|
7
9
|
## 安装
|
|
8
10
|
|
|
@@ -31,4 +33,13 @@ npx duaer-spec update
|
|
|
31
33
|
|
|
32
34
|
合并后:`duaer handoff [--run]` 在 `develop` 上重启本地服务(命令写在 `.duaer/handoff.json`)。
|
|
33
35
|
|
|
36
|
+
### 目录不要同名套娃
|
|
37
|
+
|
|
38
|
+
Worktree 是整仓副本,Brief 在仓库内的 `.duaer/specs/`:
|
|
39
|
+
|
|
40
|
+
```text
|
|
41
|
+
正确: .worktree/feat-login/.duaer/specs/002-login/spec.md
|
|
42
|
+
错误: .worktree/002-login/.duaer/specs/002-login/spec.md ← worktree 名不要用 specs 目录名
|
|
43
|
+
```
|
|
44
|
+
|
|
34
45
|
英文源:[`README.md`](README.md) · 采纳细节:[`ADOPT.md`](ADOPT.md)
|
package/bin/duaer.mjs
CHANGED
|
@@ -209,6 +209,15 @@ function installMethod(target, opts) {
|
|
|
209
209
|
writeDefaultPolicy(target, opts)
|
|
210
210
|
writeDefaultHandoff(target, opts)
|
|
211
211
|
|
|
212
|
+
installCursorMethod(target, opts)
|
|
213
|
+
installClaudeMethod(target, opts)
|
|
214
|
+
|
|
215
|
+
copyPath(join(PKG_ROOT, 'DUADER.md'), join(target, 'DUADER.md'), opts)
|
|
216
|
+
console.log(' DUADER.md')
|
|
217
|
+
ensureWorktreeGitignore(target)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function installCursorMethod(target, opts) {
|
|
212
221
|
ensureDir(join(target, '.cursor', 'skills'))
|
|
213
222
|
const skillsRoot = join(PKG_ROOT, '.cursor', 'skills')
|
|
214
223
|
for (const name of readdirSync(skillsRoot)) {
|
|
@@ -224,10 +233,62 @@ function installMethod(target, opts) {
|
|
|
224
233
|
opts,
|
|
225
234
|
)
|
|
226
235
|
console.log(' .cursor/rules/duaer-spec.mdc')
|
|
236
|
+
}
|
|
227
237
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
238
|
+
function installClaudeMethod(target, opts) {
|
|
239
|
+
ensureDir(join(target, '.claude', 'skills'))
|
|
240
|
+
const skillsRoot = join(PKG_ROOT, '.cursor', 'skills')
|
|
241
|
+
for (const name of readdirSync(skillsRoot)) {
|
|
242
|
+
if (!name.startsWith('duaer-')) continue
|
|
243
|
+
copyPath(join(skillsRoot, name), join(target, '.claude', 'skills', name), opts)
|
|
244
|
+
}
|
|
245
|
+
console.log(' .claude/skills/duaer-* (mirrored from .cursor/skills)')
|
|
246
|
+
|
|
247
|
+
ensureDir(join(target, '.claude', 'rules'))
|
|
248
|
+
const claudeRule = join(PKG_ROOT, '.claude', 'rules', 'duaer-spec.md')
|
|
249
|
+
if (existsSync(claudeRule)) {
|
|
250
|
+
copyPath(claudeRule, join(target, '.claude', 'rules', 'duaer-spec.md'), opts)
|
|
251
|
+
} else {
|
|
252
|
+
writeIfNeeded(
|
|
253
|
+
join(target, '.claude', 'rules', 'duaer-spec.md'),
|
|
254
|
+
cursorRuleToClaude(
|
|
255
|
+
readFileSync(join(PKG_ROOT, '.cursor', 'rules', 'duaer-spec.mdc'), 'utf8'),
|
|
256
|
+
'.claude',
|
|
257
|
+
),
|
|
258
|
+
opts,
|
|
259
|
+
)
|
|
260
|
+
}
|
|
261
|
+
console.log(' .claude/rules/duaer-spec.md')
|
|
262
|
+
|
|
263
|
+
const claudeMdSrc = join(PKG_ROOT, 'CLAUDE.md')
|
|
264
|
+
if (existsSync(claudeMdSrc)) {
|
|
265
|
+
copyPath(claudeMdSrc, join(target, 'CLAUDE.md'), opts)
|
|
266
|
+
} else {
|
|
267
|
+
writeIfNeeded(join(target, 'CLAUDE.md'), defaultClaudeMd(), opts)
|
|
268
|
+
}
|
|
269
|
+
console.log(' CLAUDE.md')
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function cursorRuleToClaude(mdc, skillHost) {
|
|
273
|
+
let body = mdc.replace(/^---\n[\s\S]*?\n---\n+/, (fm) => {
|
|
274
|
+
const desc = (fm.match(/^description:\s*(.+)$/m) || [])[1]
|
|
275
|
+
return desc ? `<!-- ${desc.trim()} -->\n\n` : ''
|
|
276
|
+
})
|
|
277
|
+
body = body.replaceAll('.cursor/skills/', `${skillHost}/skills/`)
|
|
278
|
+
return body.trimEnd() + '\n'
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function defaultClaudeMd() {
|
|
282
|
+
return `# CLAUDE.md — duaer-spec
|
|
283
|
+
|
|
284
|
+
This project uses **duaer-spec**: coding agents are digital employees.
|
|
285
|
+
|
|
286
|
+
**Precedence:** \`AGENTS.md\` (ops) wins over \`DUADER.md\` / \`.duaer/\` (method).
|
|
287
|
+
|
|
288
|
+
- Follow \`.claude/rules/\`
|
|
289
|
+
- Job loop: \`.claude/skills/duaer-do/SKILL.md\` (no slash commands required)
|
|
290
|
+
- Branches / worktrees: see \`AGENTS.md\` and \`docs/agent/branching-and-release.md\`
|
|
291
|
+
`
|
|
231
292
|
}
|
|
232
293
|
|
|
233
294
|
function ensureWorktreeGitignore(target) {
|
|
@@ -259,6 +320,22 @@ function installOps(target, opts) {
|
|
|
259
320
|
}
|
|
260
321
|
console.log(' .cursor/rules/agents-workflow.mdc, ai-ui-copy.mdc')
|
|
261
322
|
|
|
323
|
+
ensureDir(join(target, '.claude', 'rules'))
|
|
324
|
+
for (const name of ['agents-workflow.md', 'ai-ui-copy.md']) {
|
|
325
|
+
const src = join(PKG_ROOT, '.claude', 'rules', name)
|
|
326
|
+
if (existsSync(src)) {
|
|
327
|
+
copyPath(src, join(target, '.claude', 'rules', name), opts)
|
|
328
|
+
} else {
|
|
329
|
+
const mdc = name.replace(/\.md$/, '.mdc')
|
|
330
|
+
writeIfNeeded(
|
|
331
|
+
join(target, '.claude', 'rules', name),
|
|
332
|
+
cursorRuleToClaude(readFileSync(join(PKG_ROOT, '.cursor', 'rules', mdc), 'utf8'), '.claude'),
|
|
333
|
+
opts,
|
|
334
|
+
)
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
console.log(' .claude/rules/agents-workflow.md, ai-ui-copy.md')
|
|
338
|
+
|
|
262
339
|
ensureDir(join(target, 'docs', 'agent'))
|
|
263
340
|
for (const name of [
|
|
264
341
|
'workflow.md',
|
|
@@ -472,8 +549,12 @@ function checkWorkplace(target) {
|
|
|
472
549
|
['DUADER.md', 'method'],
|
|
473
550
|
['.cursor/rules/duaer-spec.mdc', 'method'],
|
|
474
551
|
['.cursor/skills/duaer-specify/SKILL.md', 'method'],
|
|
552
|
+
['.claude/rules/duaer-spec.md', 'method'],
|
|
553
|
+
['.claude/skills/duaer-do/SKILL.md', 'method'],
|
|
554
|
+
['CLAUDE.md', 'method'],
|
|
475
555
|
['AGENTS.md', 'ops'],
|
|
476
556
|
['.cursor/rules/agents-workflow.mdc', 'ops'],
|
|
557
|
+
['.claude/rules/agents-workflow.md', 'ops'],
|
|
477
558
|
['docs/agent/workflow.md', 'ops'],
|
|
478
559
|
]
|
|
479
560
|
let missing = 0
|
|
@@ -36,6 +36,18 @@ feat/<short-description> # new capability / improvement
|
|
|
36
36
|
fix/<short-description> # defect
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
+
Worktree directory = branch with `/` → `-`:
|
|
40
|
+
|
|
41
|
+
```text
|
|
42
|
+
branch feat/login → .worktree/feat-login
|
|
43
|
+
branch fix/timer → .worktree/fix-timer
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Duaer Brief folders are separate: `.duaer/specs/<nnn-slug>/`. Because a worktree
|
|
47
|
+
is a full checkout, Specs appear as
|
|
48
|
+
`.worktree/feat-login/.duaer/specs/002-login/spec.md`. That nesting is normal.
|
|
49
|
+
Do **not** reuse `<nnn-slug>` as the worktree folder name.
|
|
50
|
+
|
|
39
51
|
Optional types when the project already uses them: `docs/`, `chore/`, `refactor/`,
|
|
40
52
|
`test/`, `ci/` — still branch from `develop`, merge back to `develop` first.
|
|
41
53
|
|
|
@@ -37,6 +37,8 @@ the table for their app.
|
|
|
37
37
|
| E2E-010 | `npx duaer-spec update` refreshes an existing install | manual |
|
|
38
38
|
| E2E-011 | Installed docs (`DUADER.md`, `docs/agent/`) document `update` | manual |
|
|
39
39
|
| E2E-012 | `README.zh-CN.md` covers install, update, branch model | manual |
|
|
40
|
+
| E2E-013 | Worktree id ≠ Brief `<nnn-slug>`; path is `.worktree/feat-…/.duaer/specs/…` | manual |
|
|
41
|
+
| E2E-014 | Init installs Cursor + Claude hosts (`CLAUDE.md`, `.claude/skills`) | manual |
|
|
40
42
|
|
|
41
43
|
## Traceability
|
|
42
44
|
|
|
@@ -54,3 +56,5 @@ the table for their app.
|
|
|
54
56
|
| E2E-010 | `duaer update` | One-line refresh |
|
|
55
57
|
| E2E-011 | DUADER + agent docs | Update path in installed 说明 |
|
|
56
58
|
| E2E-012 | `README.zh-CN.md` | Chinese 说明文档 |
|
|
59
|
+
| E2E-013 | AGENTS / branching naming | Avoid double `<nnn-slug>` |
|
|
60
|
+
| E2E-014 | Claude + Cursor install | Dual host |
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "duaer-spec",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Digital employees
|
|
3
|
+
"version": "0.7.0",
|
|
4
|
+
"description": "Digital employees for Cursor and Claude Code; main/develop/feat/fix",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"duaer": "bin/duaer.mjs",
|
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
"bin",
|
|
12
12
|
".duaer",
|
|
13
13
|
".cursor",
|
|
14
|
+
".claude",
|
|
14
15
|
"AGENTS.md",
|
|
16
|
+
"CLAUDE.md",
|
|
15
17
|
"DUADER.md",
|
|
16
18
|
"ADOPT.md",
|
|
17
19
|
"CHANGELOG.md",
|
|
@@ -43,7 +45,9 @@
|
|
|
43
45
|
"agents",
|
|
44
46
|
"cursor",
|
|
45
47
|
"ai-engineering",
|
|
46
|
-
"controllable-delivery"
|
|
48
|
+
"controllable-delivery",
|
|
49
|
+
"claude",
|
|
50
|
+
"claude-code"
|
|
47
51
|
],
|
|
48
52
|
"license": "MIT",
|
|
49
53
|
"scripts": {
|