deuk-agent-rule 1.0.12 → 1.0.13
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/CHANGELOG.md +23 -6
- package/README.ko.md +19 -7
- package/README.md +20 -8
- package/bundle/AGENTS.md +10 -1
- package/bundle/rules/multi-ai-workflow.mdc +12 -2
- package/package.json +4 -1
- package/scripts/cli.mjs +76 -2
- package/scripts/merge-logic.mjs +1 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,26 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
All notable changes to this project will be documented in this file.
|
|
4
|
-
|
|
5
|
-
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
-
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [1.0.13] - 2026-03-28
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- **deuk-agent-rule:** `printHandoffTip` missing in CLI (handoff tip after `init`)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- **docs:** README § Handoffs; GitHub About text; npm keywords; CLI survey adds Claude, Windsurf, JetBrains AI Assistant
|
|
18
|
+
- **agents:** optional `.cursor/plans/*.plan.md` mirror for plan-style UI; chat `Path:` line and optional first-line path in handoff files
|
|
19
|
+
- **deuk-agent-rule:** `init` prints a short handoff tip after ensuring `.deuk-agent-handoff/`
|
|
20
|
+
- **deuk-agent-rule:** default `--rules prefix` overwrites existing `deuk-agent-rule-*.mdc` on repeat `init` (package updates without a separate `merge`)
|
|
21
|
+
- **deuk-agent-rule:** `.deuk-agent-rule.config.json` stores interactive choices; later `init` reuses them (`--interactive` to change; `--non-interactive` for CI only)
|
|
22
|
+
|
|
23
|
+
|
|
7
24
|
## [1.0.12] - 2026-03-27
|
|
8
25
|
|
|
9
26
|
|
package/README.ko.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
**English:** [README.md](https://github.com/joygram/DeukAgentRules/blob/master/README.md)
|
|
8
8
|
|
|
9
|
-
Cursor, Copilot, Gemini 등
|
|
9
|
+
Cursor, GitHub Copilot, Gemini / Antigravity, Claude(Cursor·Claude Code), Windsurf, JetBrains AI Assistant 등 코딩 에이전트와 함께 쓸 `AGENTS.md`·`.cursor/rules` 버전 관리형 템플릿. 그 밖에도 프로젝트 규칙을 읽는 유사 도구에 그대로 활용할 수 있습니다. 핸드오프·간결 응답으로 비용·성능을 개선합니다.
|
|
10
10
|
|
|
11
11
|
## 워크스페이스 초기화
|
|
12
12
|
|
|
@@ -15,7 +15,9 @@ npm install deuk-agent-rule
|
|
|
15
15
|
npx deuk-agent-rule init
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
`--non-interactive`
|
|
18
|
+
레포에 **처음** `init` 할 때만(`.deuk-agent-rule.config.json` 없음) **대화형** 질문이 나옵니다. **이후** `npx deuk-agent-rule init` 은 저장된 선택을 쓰고 템플릿만 갱신하므로, 매번 `--non-interactive` 할 필요 없습니다. **CI**에서만 `--non-interactive` 를 쓰면 됩니다. 선택을 바꾸려면 **`--interactive`** 이거나 설정 파일을 지우거나 수정하세요.
|
|
19
|
+
|
|
20
|
+
첫 `init` 예시:
|
|
19
21
|
|
|
20
22
|
```
|
|
21
23
|
$ npx deuk-agent-rule init
|
|
@@ -34,8 +36,11 @@ DeukAgentRules init — let's configure your workspace.
|
|
|
34
36
|
1) Cursor
|
|
35
37
|
2) GitHub Copilot
|
|
36
38
|
3) Gemini / Antigravity
|
|
37
|
-
4)
|
|
38
|
-
5)
|
|
39
|
+
4) Claude (Cursor / Claude Code)
|
|
40
|
+
5) Windsurf
|
|
41
|
+
6) JetBrains AI Assistant
|
|
42
|
+
7) All of the above
|
|
43
|
+
8) Other / skip
|
|
39
44
|
Choices: 1,2
|
|
40
45
|
|
|
41
46
|
Stack : unity
|
|
@@ -57,16 +62,23 @@ npx deuk-agent-rule init --non-interactive
|
|
|
57
62
|
|
|
58
63
|
```bash
|
|
59
64
|
npm update deuk-agent-rule
|
|
60
|
-
npx deuk-agent-rule init
|
|
65
|
+
npx deuk-agent-rule init
|
|
61
66
|
```
|
|
62
67
|
|
|
63
|
-
`AGENTS.md
|
|
68
|
+
**CI·헤드리스**에서만 `init --non-interactive` 를 쓰면 됩니다. 일반 업그레이드에 **`merge`를 따로 돌릴 필요는 없습니다.** 기본 **`init`** 이 번들 **`.cursor/rules`** 를 다시 맞춥니다. `--rules prefix`(기본)일 때 이미 있는 **`deuk-agent-rule-*.mdc`** 는 새 패키지 내용으로 **덮어씁니다.** 접두 없이 둔 로컬 전용 룰 파일은 건드리지 않습니다. `AGENTS.md`는 **마커 안**만 갱신되고 바깥 내용은 유지됩니다.
|
|
69
|
+
|
|
70
|
+
### 핸드오프 (멀티 세션·도구 넘김)
|
|
71
|
+
|
|
72
|
+
`init` 시 **`.deuk-agent-handoff/`** 를 만들고 기본으로 **`.gitignore`** 에 넣습니다. 채팅만이 아니라 **파일로 남겨야 할** 작업 명세는 여기(또는 `DeukAgentRules/handoff/LATEST.md` 관례)에 `AGENTS.md`의 **Handoff format** 절 구조(과제, 수정 파일, 결정, 제약)로 적어 두면, 다음 세션이나 다른 에이전트가 이어 받기 쉽습니다.
|
|
73
|
+
|
|
74
|
+
**플랜 패널**을 쓰는 환경에서는 동일 본문을 **`.cursor/plans/deuk-handoff.plan.md`** 등으로 **선택적으로 복제**해 둘 수 있습니다. 정본과 내용이 어긋나지 않게 맞추고, 에이전트 동작은 번들된 **`multi-ai-workflow.mdc`** 를 참고하세요.
|
|
64
75
|
|
|
65
76
|
### 주요 옵션
|
|
66
77
|
|
|
67
78
|
| 플래그 | 기본값 | 설명 |
|
|
68
79
|
|--------|--------|------|
|
|
69
|
-
| `--non-interactive` | 끔 | 질문
|
|
80
|
+
| `--non-interactive` | 끔 | CI/스크립트: 질문 없음·저장 설정 미사용 |
|
|
81
|
+
| `--interactive` | 끔 | `.deuk-agent-rule.config.json` 이 있어도 질문 다시 |
|
|
70
82
|
| `--cwd <path>` | 현재 디렉터리 | 대상 레포 루트 |
|
|
71
83
|
| `--dry-run` | 끔 | 쓰기 없이 동작만 출력 |
|
|
72
84
|
| `--tag <id>` | `deuk-agent-rule` | 마커 id: `<!-- <id>:begin/end -->` |
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
**한국어:** [README.ko.md](https://github.com/joygram/DeukAgentRules/blob/master/README.ko.md)
|
|
8
8
|
|
|
9
|
-
Versioned templates for `AGENTS.md` and `.cursor/rules` for Cursor, Copilot, Gemini and
|
|
9
|
+
Versioned templates for `AGENTS.md` and `.cursor/rules` for Cursor, GitHub Copilot, Gemini / Antigravity, Claude (via Cursor or Claude Code), Windsurf, JetBrains AI Assistant, and other coding agents that read project rules: shared handoff format, concise execution, stronger cost-efficiency and responsiveness.
|
|
10
10
|
|
|
11
11
|
## Initialize a workspace
|
|
12
12
|
|
|
@@ -15,7 +15,9 @@ npm install deuk-agent-rule
|
|
|
15
15
|
npx deuk-agent-rule init
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
On the **first** `init` in a repo (no `.deuk-agent-rule.config.json`), a short **interactive** setup runs. **Later** `npx deuk-agent-rule init` reuses those choices and only applies template updates — no need for `--non-interactive` unless you are in **CI**. Use **`--interactive`** to change answers, or delete/edit the config file.
|
|
19
|
+
|
|
20
|
+
Running `init` for the first time (example):
|
|
19
21
|
|
|
20
22
|
```
|
|
21
23
|
$ npx deuk-agent-rule init
|
|
@@ -34,12 +36,15 @@ DeukAgentRules init — let's configure your workspace.
|
|
|
34
36
|
1) Cursor
|
|
35
37
|
2) GitHub Copilot
|
|
36
38
|
3) Gemini / Antigravity
|
|
37
|
-
4)
|
|
38
|
-
5)
|
|
39
|
+
4) Claude (Cursor / Claude Code)
|
|
40
|
+
5) Windsurf
|
|
41
|
+
6) JetBrains AI Assistant
|
|
42
|
+
7) All of the above
|
|
43
|
+
8) Other / skip
|
|
39
44
|
Choices: all
|
|
40
45
|
|
|
41
46
|
Stack : web
|
|
42
|
-
Tools : cursor, copilot, gemini, all
|
|
47
|
+
Tools : cursor, copilot, gemini, claude, windsurf, jetbrains, all, other
|
|
43
48
|
|
|
44
49
|
AGENTS.md: injected (inject)
|
|
45
50
|
rule copied: .cursor/rules/deuk-agent-rule-multi-ai-workflow.mdc
|
|
@@ -57,16 +62,23 @@ After a package upgrade:
|
|
|
57
62
|
|
|
58
63
|
```bash
|
|
59
64
|
npm update deuk-agent-rule
|
|
60
|
-
npx deuk-agent-rule init
|
|
65
|
+
npx deuk-agent-rule init
|
|
61
66
|
```
|
|
62
67
|
|
|
63
|
-
Only the **marker region** in `AGENTS.md` is replaced; your text outside stays.
|
|
68
|
+
Use `init --non-interactive` only in **CI** or headless scripts. You do **not** need a separate `merge` for routine upgrades: **`init` refreshes** the bundled `.cursor/rules` files. With default `--rules prefix`, existing **`deuk-agent-rule-*.mdc`** copies are **overwritten** from the new package so template fixes reach your repo. Unprefixed rule files you keep for local overrides are not touched. Only the **marker region** in `AGENTS.md` is replaced; your text outside stays.
|
|
69
|
+
|
|
70
|
+
### Handoffs (multi-session and tool handover)
|
|
71
|
+
|
|
72
|
+
`init` creates **`.deuk-agent-handoff/`** (and adds it to **`.gitignore`** by default) so you can **persist** structured specs beyond a single chat. Use the same sections as in `AGENTS.md` (**Handoff format**): task title, files to modify, decisions, constraints. That lets the next session or another tool pick up where you left off without re-explaining the repo.
|
|
73
|
+
|
|
74
|
+
Optionally, if you use an editor with a **Plans** panel, mirror the same Markdown body under **`.cursor/plans/deuk-handoff.plan.md`** (or `deuk-handoff-<topic>.plan.md`) so it appears there; keep it in sync with the canonical file under `.deuk-agent-handoff/` or `DeukAgentRules/handoff/LATEST.md`. See the bundled **`multi-ai-workflow.mdc`** rule for agent-side details.
|
|
64
75
|
|
|
65
76
|
### Key options
|
|
66
77
|
|
|
67
78
|
| Flag | Default | Description |
|
|
68
79
|
|------|---------|-------------|
|
|
69
|
-
| `--non-interactive` | off |
|
|
80
|
+
| `--non-interactive` | off | CI/scripts: no prompts; no saved-config path |
|
|
81
|
+
| `--interactive` | off | Force the setup questions even if `.deuk-agent-rule.config.json` exists |
|
|
70
82
|
| `--cwd <path>` | current directory | Target repo root |
|
|
71
83
|
| `--dry-run` | off | Print actions without writing |
|
|
72
84
|
| `--tag <id>` | `deuk-agent-rule` | Marker id: `<!-- <id>:begin/end -->` |
|
package/bundle/AGENTS.md
CHANGED
|
@@ -44,6 +44,9 @@ No editor or vendor tool branding in code, docs, README, commits, or published a
|
|
|
44
44
|
- **핸드오프 보관**: 채팅만이 아니라 **남겨야 할** 핸드오프는 **내부 구현 문서**에 아래 **Handoff format**과 같은 제목·절 구조의 Markdown으로 기록한다. `deuk-agent-rule init`은 기본으로 **`.deuk-agent-handoff/`** 를 만들고 `.gitignore`에 넣어 로컬 전용으로 둔다. 이 패키지를 **`DeukAgentRules/`** 폴더로 둔 소비 모노레포에서는 **`DeukAgentRules/handoff/LATEST.md`** 에 두는 관례를 쓸 수 있다(해당 `handoff/`는 소비 레포 `.gitignore`에 넣는다). 본문은 **사용자가 대화에 쓰는 언어**로 쓴다(특정 언어를 요청한 경우는 예외).
|
|
45
45
|
- **핸드오프 선확인**: 구현·수정 등 본격 작업 전에 **보관된 핸드오프**를 확인한다. **반드시 경로 문자열을 규칙에 포함해 읽는다:** 존재하면 **`DeukAgentRules/handoff/LATEST.md`**(소비 레포 루트 기준), 그리고 **`.deuk-agent-handoff/`** 및 프로젝트별 내부 경로. 채팅에 붙여 넣은 핸드오프가 있으면 우선한다(사용자가 파일 기준이라고 하면 예외).
|
|
46
46
|
- **핸드오프 파일 링크**: Markdown 링크 `[텍스트](경로)`·백틱 경로·채팅 안내에서 핸드오프 파일을 가리킬 때 **저장소(또는 워크스페이스) 루트 기준 전체 경로**를 쓴다(예: `DeukAgentRules/handoff/LATEST.md`, `project_i/foo/internal/handoff.md`). **`LATEST.md`처럼 파일명만** 단독으로 쓰지 않는다. 모노레포에서는 접두 경로를 생략하지 않는다.
|
|
47
|
+
- **핸드오프 저장 후 채팅**: 파일로 남긴 뒤 채팅에 **`Path: \`루트기준/전체/경로.md\``** 형태로 **한 줄**을 반드시 넣어 다음 세션이 동일 파일을 연다.
|
|
48
|
+
- **핸드오프 파일 머리줄(선택)**: 파일 첫 줄에 `**Handoff (repo-relative):** \`경로\`` 또는 동일 경로의 HTML 주석을 두어 검색·스캔에 쓸 수 있다.
|
|
49
|
+
- **플랜 UI(선택)**: 플랜 전용 패널에 같은 문서를 띄우려면, 관리 중인 **multi-ai-workflow** 규칙에 적힌 **선택적 미러 경로**(예: `.cursor/plans/*.plan.md`)에 동일 본문을 둘 수 있다. 정본은 `.deuk-agent-handoff/` 또는 `DeukAgentRules/handoff/`를 유지하고 두 곳 내용을 맞출 것.
|
|
47
50
|
|
|
48
51
|
English sections above are canonical for tooling; this block is a short Korean mirror for the same rules.
|
|
49
52
|
|
|
@@ -67,6 +70,12 @@ When handing work between tools or people, use:
|
|
|
67
70
|
|
|
68
71
|
When a handoff should **outlive the chat** — for example the user asks to save it, it is the authoritative spec for a follow-up session or another implementer, or the team keeps structured handoffs in-repo — **write it as a Markdown file** under **internal implementation documentation** (implementation notes, not end-user or marketing docs). Prefer **`.deuk-agent-handoff/`** when no project convention exists; if this package lives in **`DeukAgentRules/`** at the consumer repo root, prefer **`DeukAgentRules/handoff/LATEST.md`** (see the next section). Otherwise use an existing convention such as `<product-or-feature>/internal/*.md` or `docs/internal/*.md`. If the user names a path, use it. Reuse the same section structure as **Handoff format** above. If only an inline paste is needed, skip creating a file unless the user asks to save.
|
|
69
72
|
|
|
73
|
+
**Plan-style UI (optional):** Some editors surface **plan documents** separately from normal Markdown. You may **mirror** the same handoff body into the optional path described in the managed **multi-ai-workflow** rule (e.g. `.cursor/plans/deuk-handoff.plan.md`) while keeping the **canonical** file under **`.deuk-agent-handoff/`** or **`DeukAgentRules/handoff/`**. If both exist, **keep them in sync**.
|
|
74
|
+
|
|
75
|
+
**After saving (chat):** Include **one dedicated line** with the full repo-root-relative path, e.g. `Path: \`.deuk-agent-handoff/LATEST.md\`` — not only a bare filename inside prose.
|
|
76
|
+
|
|
77
|
+
**Optional first line in the file:** e.g. `**Handoff (repo-relative):** \`path/from/root.md\`` or the same in an HTML comment on line 1.
|
|
78
|
+
|
|
70
79
|
**Language:** Write the **body** of persisted handoffs in the **user’s language** — the language they use in the conversation (or their stated preference) — unless they ask for a specific language (for example English-only for an external partner).
|
|
71
80
|
|
|
72
81
|
**Before substantive work:** Before implementation, fixes, or other non-trivial repo changes, **check persisted handoffs** in the locations above (including **`.deuk-agent-handoff/`** and any project-specific internal paths). **If the file `DeukAgentRules/handoff/LATEST.md` exists** (path relative to the **consumer** repository root — i.e. this rules package lives in a top-level folder named `DeukAgentRules`), **read it** before editing code, in addition to other handoff locations. Read documents that match the current task; a **pasted handoff** in the chat takes precedence unless the user says to follow files instead. Skip this scan only when no locations exist, nothing matches, or the user explicitly says to ignore stored handoffs.
|
|
@@ -82,6 +91,6 @@ Add **`DeukAgentRules/handoff/`** to the **consumer** repository’s `.gitignore
|
|
|
82
91
|
|
|
83
92
|
**Agent guidance (canonical path strings):** Rules and `AGENTS.md` in the consumer repo should tell agents to open **`DeukAgentRules/handoff/LATEST.md`** when it exists — not only a pasted chat block — so other tools and sessions can resume from the same clone.
|
|
84
93
|
|
|
85
|
-
**Producing handoffs:** When saving a durable handoff for another agent, write the **Handoff format** body to **`DeukAgentRules/handoff/LATEST.md`** (or a dated file in that folder) and, in chat, include one line
|
|
94
|
+
**Producing handoffs:** When saving a durable handoff for another agent, write the **Handoff format** body to **`DeukAgentRules/handoff/LATEST.md`** (or a dated file in that folder) and, in chat, include **one line** with the full path, e.g. `Path: \`DeukAgentRules/handoff/LATEST.md\`` using **repo-relative paths** (no `file://` URLs).
|
|
86
95
|
|
|
87
96
|
**Handoff links (full path):** Whenever you **link** or **cite** a persisted handoff file — in **Handoff format** sections, chat, or Markdown — use the **full path from the repository root** (for example `DeukAgentRules/handoff/LATEST.md`, `project_i/_ref_data/deuk_define/reports/REF_DATA_DEUK_TRANSITION.md`). Do **not** use a **bare filename** (`LATEST.md` alone) or an ambiguous partial path. In monorepos, include every prefix segment so the path is unique in the workspace. Markdown: put the full path in the link target, e.g. `[handoff](DeukAgentRules/handoff/LATEST.md)` (repo-relative).
|
|
@@ -30,8 +30,18 @@ When the user asks to prepare work for another tool:
|
|
|
30
30
|
1. Output the handoff format with concrete file paths and change descriptions. When linking handoff files (Markdown `[label](path)` or path citations), use the **full path from the repository root** — never a bare filename.
|
|
31
31
|
2. Include any constraints or dependencies.
|
|
32
32
|
3. Do not include editor-specific instructions (token budgets, local rule file paths).
|
|
33
|
-
4. When the handoff must **persist** (user asks to save or document it, or it is the canonical next-step spec), **create or update** a Markdown file under **internal implementation documentation** (see `AGENTS.md`, **Handoff persistence**). Prefer **`DeukAgentRules/handoff/LATEST.md`** when this repo has a top-level **`DeukAgentRules/`** folder; otherwise prefer **`.deuk-agent-handoff/`**; `init` gitignores that directory by default. Use the same handoff template; do not place this in public README/landing unless the project explicitly treats
|
|
34
|
-
5.
|
|
33
|
+
4. When the handoff must **persist** (user asks to save or document it, or it is the canonical next-step spec), **create or update** a Markdown file under **internal implementation documentation** (see `AGENTS.md`, **Handoff persistence**). Prefer **`DeukAgentRules/handoff/LATEST.md`** when this repo has a top-level **`DeukAgentRules/`** folder; otherwise prefer **`.deuk-agent-handoff/`**; `init` gitignores that directory by default. Use the same handoff template; do not place this in public README/landing unless the project explicitly treats this as its internal log. In Markdown links and backtick citations, use the **full path from the repository root** — never a bare filename.
|
|
34
|
+
5. **After writing a persisted handoff**, in chat include **one dedicated line** with the full repo-root-relative path so the next session can open it unambiguously, for example: `Path: \`.deuk-agent-handoff/LATEST.md\`` (same path you used in the file). Repeat the full path in links elsewhere in the same message if helpful.
|
|
35
|
+
6. **Optional first line inside the persisted file** (improves search and skim): `**Handoff (repo-relative):** \`path/from/repo/root.md\`` or the same path in an HTML comment on line 1.
|
|
36
|
+
7. Write persisted handoff **content** in the **user's conversation language** unless they specify another language.
|
|
37
|
+
|
|
38
|
+
## Persisted handoff vs plan UI (optional)
|
|
39
|
+
|
|
40
|
+
Some environments show **plan-style documents** in a separate panel from ordinary Markdown tabs. Behavior varies by product version; when the user wants that experience in **Cursor**, you may **mirror** the same handoff body (Handoff format) under the workspace **`.cursor/plans/`** directory using a **`.plan.md`** suffix, for example `.cursor/plans/deuk-handoff.plan.md` or `.cursor/plans/deuk-handoff-<topic>.plan.md`.
|
|
41
|
+
|
|
42
|
+
- **Canonical copy** remains **`.deuk-agent-handoff/`** or **`DeukAgentRules/handoff/LATEST.md`** (portable, matches `AGENTS.md`). The `.cursor/plans/` file is an **optional duplicate** for UI only.
|
|
43
|
+
- **Single source of truth:** If both exist, keep their **content in sync**; updating one should update the other in the same turn when possible.
|
|
44
|
+
- **Version control:** Treat `.cursor/plans/` like other local-only handoffs unless the team commits plans on purpose — align with `.gitignore` team policy.
|
|
35
45
|
|
|
36
46
|
## Role: Execution
|
|
37
47
|
|
package/package.json
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "deuk-agent-rule",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.13",
|
|
4
4
|
"description": "DeukAgentRules: generic AGENTS.md + .cursor rule templates with init/merge CLI (npm name: deuk-agent-rule).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agents-md",
|
|
7
7
|
"cursor-rules",
|
|
8
8
|
"copilot",
|
|
9
9
|
"gemini",
|
|
10
|
+
"claude",
|
|
11
|
+
"windsurf",
|
|
12
|
+
"jetbrains",
|
|
10
13
|
"handoff",
|
|
11
14
|
"deuk-family",
|
|
12
15
|
"deukpack-ecosystem"
|
package/scripts/cli.mjs
CHANGED
|
@@ -18,6 +18,14 @@ const bundleRoot = join(pkgRoot, "bundle");
|
|
|
18
18
|
const HANDOFF_DIR_NAME = ".deuk-agent-handoff";
|
|
19
19
|
const GITIGNORE_HANDOFF_MARKER = "# deuk-agent-rule: handoff directory (local, not committed by default)";
|
|
20
20
|
|
|
21
|
+
function printHandoffTip() {
|
|
22
|
+
console.log(
|
|
23
|
+
"tip: Persist multi-session specs under " +
|
|
24
|
+
HANDOFF_DIR_NAME +
|
|
25
|
+
"/ (see README § Handoffs). Optional: mirror the same body to .cursor/plans/deuk-handoff.plan.md for the Plans panel.",
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
21
29
|
function ensureHandoffDirAndGitignore(opts) {
|
|
22
30
|
const handoffPath = join(opts.cwd, HANDOFF_DIR_NAME);
|
|
23
31
|
const gitignorePath = join(opts.cwd, ".gitignore");
|
|
@@ -25,6 +33,7 @@ function ensureHandoffDirAndGitignore(opts) {
|
|
|
25
33
|
|
|
26
34
|
if (opts.dryRun) {
|
|
27
35
|
console.log("handoff: would mkdir " + HANDOFF_DIR_NAME + "/ and ensure .gitignore ignores it");
|
|
36
|
+
printHandoffTip();
|
|
28
37
|
return;
|
|
29
38
|
}
|
|
30
39
|
|
|
@@ -40,14 +49,17 @@ function ensureHandoffDirAndGitignore(opts) {
|
|
|
40
49
|
lines.some((t) => t === HANDOFF_DIR_NAME || t === ignoreLine.replace(/\/$/, ""));
|
|
41
50
|
if (already) {
|
|
42
51
|
console.log(".gitignore: already ignores " + HANDOFF_DIR_NAME);
|
|
52
|
+
printHandoffTip();
|
|
43
53
|
return;
|
|
44
54
|
}
|
|
45
55
|
const block = "\n" + GITIGNORE_HANDOFF_MARKER + "\n" + ignoreLine + "\n";
|
|
46
56
|
appendFileSync(gitignorePath, block, "utf8");
|
|
47
57
|
console.log(".gitignore: appended " + ignoreLine.trim());
|
|
58
|
+
printHandoffTip();
|
|
48
59
|
} else {
|
|
49
60
|
writeFileSync(gitignorePath, GITIGNORE_HANDOFF_MARKER + "\n" + ignoreLine + "\n", "utf8");
|
|
50
61
|
console.log(".gitignore: created with " + ignoreLine.trim());
|
|
62
|
+
printHandoffTip();
|
|
51
63
|
}
|
|
52
64
|
}
|
|
53
65
|
|
|
@@ -96,14 +108,56 @@ const STACKS = [
|
|
|
96
108
|
{ label: "Other / skip", value: "other" },
|
|
97
109
|
];
|
|
98
110
|
|
|
111
|
+
/** Survey only today; merge/init does not branch on these yet (future tool-specific templates). */
|
|
99
112
|
const AGENT_TOOLS = [
|
|
100
113
|
{ label: "Cursor", value: "cursor" },
|
|
101
114
|
{ label: "GitHub Copilot", value: "copilot" },
|
|
102
115
|
{ label: "Gemini / Antigravity", value: "gemini" },
|
|
116
|
+
{ label: "Claude (Cursor / Claude Code)", value: "claude" },
|
|
117
|
+
{ label: "Windsurf", value: "windsurf" },
|
|
118
|
+
{ label: "JetBrains AI Assistant", value: "jetbrains" },
|
|
103
119
|
{ label: "All of the above", value: "all" },
|
|
104
120
|
{ label: "Other / skip", value: "other" },
|
|
105
121
|
];
|
|
106
122
|
|
|
123
|
+
/** Written after first interactive init; reused on later inits unless --interactive or schema mismatch. */
|
|
124
|
+
const INIT_CONFIG_VERSION = 1;
|
|
125
|
+
const INIT_CONFIG_FILENAME = ".deuk-agent-rule.config.json";
|
|
126
|
+
|
|
127
|
+
function loadInitConfig(cwd) {
|
|
128
|
+
const p = join(cwd, INIT_CONFIG_FILENAME);
|
|
129
|
+
if (!existsSync(p)) return null;
|
|
130
|
+
try {
|
|
131
|
+
const j = JSON.parse(readFileSync(p, "utf8"));
|
|
132
|
+
if (j.version !== INIT_CONFIG_VERSION) return null;
|
|
133
|
+
const allowedStack = new Set(STACKS.map((s) => s.value));
|
|
134
|
+
if (!allowedStack.has(j.stack)) return null;
|
|
135
|
+
const allowedTools = new Set(AGENT_TOOLS.map((t) => t.value));
|
|
136
|
+
if (!Array.isArray(j.agentTools) || !j.agentTools.every((t) => allowedTools.has(t))) return null;
|
|
137
|
+
if (!["inject", "skip", "overwrite"].includes(j.agentsMode)) return null;
|
|
138
|
+
return {
|
|
139
|
+
stack: j.stack,
|
|
140
|
+
agentTools: j.agentTools,
|
|
141
|
+
agentsMode: j.agentsMode,
|
|
142
|
+
};
|
|
143
|
+
} catch {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function writeInitConfig(cwd, opts) {
|
|
149
|
+
const p = join(cwd, INIT_CONFIG_FILENAME);
|
|
150
|
+
const body = {
|
|
151
|
+
version: INIT_CONFIG_VERSION,
|
|
152
|
+
stack: opts.stack,
|
|
153
|
+
agentTools: opts.agentTools,
|
|
154
|
+
agentsMode: opts.agents ?? "inject",
|
|
155
|
+
updatedAt: new Date().toISOString(),
|
|
156
|
+
};
|
|
157
|
+
writeFileSync(p, JSON.stringify(body, null, 2) + "\n", "utf8");
|
|
158
|
+
console.log("saved: " + INIT_CONFIG_FILENAME);
|
|
159
|
+
}
|
|
160
|
+
|
|
107
161
|
async function runInteractive(opts) {
|
|
108
162
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
109
163
|
try {
|
|
@@ -157,7 +211,8 @@ Usage:
|
|
|
157
211
|
Options:
|
|
158
212
|
--cwd <path> Target repo root (default: current directory)
|
|
159
213
|
--dry-run Print actions; do not write files
|
|
160
|
-
--non-interactive
|
|
214
|
+
--non-interactive CI/scripts: no prompts; use --agents/--rules (no saved config read)
|
|
215
|
+
--interactive Ask questions even if .deuk-agent-rule.config.json exists
|
|
161
216
|
--tag <id> Marker id (default: deuk-agent-rule)
|
|
162
217
|
--agents <mode> inject | skip | overwrite
|
|
163
218
|
--rules <mode> prefix | skip | overwrite
|
|
@@ -166,6 +221,7 @@ Options:
|
|
|
166
221
|
--marker-begin / --marker-end Custom marker strings (both required)
|
|
167
222
|
|
|
168
223
|
init also creates .deuk-agent-handoff/ and appends it to .gitignore (local handoffs).
|
|
224
|
+
After npm update, run init again: deuk-agent-rule-*.mdc rules refresh from the bundle (no separate merge needed).
|
|
169
225
|
|
|
170
226
|
Korean: package README.ko.md
|
|
171
227
|
`,
|
|
@@ -184,6 +240,7 @@ function parseArgs(argv) {
|
|
|
184
240
|
rules: undefined,
|
|
185
241
|
appendIfNoMarkers: false,
|
|
186
242
|
nonInteractive: false,
|
|
243
|
+
interactive: false,
|
|
187
244
|
};
|
|
188
245
|
for (let i = 0; i < argv.length; i++) {
|
|
189
246
|
const a = argv[i];
|
|
@@ -193,6 +250,7 @@ function parseArgs(argv) {
|
|
|
193
250
|
} else if (a === "--dry-run") out.dryRun = true;
|
|
194
251
|
else if (a === "--backup") out.backup = true;
|
|
195
252
|
else if (a === "--non-interactive") out.nonInteractive = true;
|
|
253
|
+
else if (a === "--interactive") out.interactive = true;
|
|
196
254
|
else if (a === "--tag") {
|
|
197
255
|
out.tag = argv[++i];
|
|
198
256
|
if (out.tag == null) throw new Error("--tag requires a value");
|
|
@@ -348,7 +406,23 @@ async function main() {
|
|
|
348
406
|
try {
|
|
349
407
|
if (sub === "init") {
|
|
350
408
|
if (!isNonInteractive(opts)) {
|
|
351
|
-
|
|
409
|
+
const saved = loadInitConfig(opts.cwd);
|
|
410
|
+
if (saved && !opts.interactive) {
|
|
411
|
+
opts.agents = opts.agents !== undefined ? opts.agents : saved.agentsMode;
|
|
412
|
+
opts.stack = saved.stack;
|
|
413
|
+
opts.agentTools = saved.agentTools;
|
|
414
|
+
const stackL = STACKS.find((s) => s.value === saved.stack)?.label || saved.stack;
|
|
415
|
+
console.log("\nDeukAgentRules init — using saved choices from " + INIT_CONFIG_FILENAME);
|
|
416
|
+
console.log(" Stack : " + saved.stack + " (" + stackL + ")");
|
|
417
|
+
console.log(" Tools : " + (saved.agentTools.join(", ") || "none"));
|
|
418
|
+
console.log(" AGENTS: " + opts.agents);
|
|
419
|
+
console.log(" (`--interactive` to change, or edit/delete " + INIT_CONFIG_FILENAME + ")\n");
|
|
420
|
+
} else {
|
|
421
|
+
await runInteractive(opts);
|
|
422
|
+
if (!opts.dryRun) {
|
|
423
|
+
writeInitConfig(opts.cwd, opts);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
352
426
|
}
|
|
353
427
|
runInit(opts);
|
|
354
428
|
} else if (sub === "merge") {
|
package/scripts/merge-logic.mjs
CHANGED
|
@@ -168,15 +168,7 @@ export function applyRules(opts) {
|
|
|
168
168
|
|
|
169
169
|
if (rulesMode === "prefix" && existsSync(destPath)) {
|
|
170
170
|
destPath = join(targetRulesDir, filePrefix + name);
|
|
171
|
-
|
|
172
|
-
actions.push({
|
|
173
|
-
action: "skip",
|
|
174
|
-
src,
|
|
175
|
-
dest: destPath,
|
|
176
|
-
reason: "prefixed target also exists",
|
|
177
|
-
});
|
|
178
|
-
continue;
|
|
179
|
-
}
|
|
171
|
+
// If prefixed file exists (repeat init after npm update), overwrite from bundle — do not skip.
|
|
180
172
|
}
|
|
181
173
|
|
|
182
174
|
if (dryRun) {
|