deuk-agent-rule 1.0.2 → 1.0.5
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/README.ko.md +55 -40
- package/README.md +53 -39
- package/bundle/AGENTS.md +8 -0
- package/bundle/rules/delivery-and-parallel-work.mdc +26 -0
- package/package.json +10 -1
- package/scripts/cli.mjs +131 -4
- package/scripts/sync-oss.mjs +10 -1
package/README.ko.md
CHANGED
|
@@ -1,78 +1,93 @@
|
|
|
1
1
|
# DeukAgentRules (득에이전트룰스)
|
|
2
2
|
|
|
3
|
+
> **Deuk Family**의 핵심 모듈 가운데 하나입니다. 구조화된 규칙으로 AI 에이전트의 협업과 응답을 다듬습니다.
|
|
4
|
+
|
|
3
5
|
**npm 패키지:** `deuk-agent-rule` · **CLI:** `deuk-agent-rule`
|
|
4
6
|
|
|
5
|
-
**English:** [README.md](README.md)
|
|
7
|
+
**English:** [README.md](https://github.com/joygram/DeukAgentRules/blob/master/README.md)
|
|
6
8
|
|
|
7
9
|
Cursor, Copilot, Gemini 등 여러 에이전트·도구를 함께 쓸 때를 위한 `AGENTS.md`·`.cursor/rules` 버전 관리형 템플릿. 핸드오프·간결 응답으로 비용·성능을 개선합니다.
|
|
8
10
|
|
|
9
11
|
## 워크스페이스 초기화
|
|
10
12
|
|
|
11
|
-
설치만으로는 파일이 바뀌지 않습니다. **대상 프로젝트 루트**에서 CLI를 실행하거나 `--cwd`로 경로를 줍니다.
|
|
12
|
-
|
|
13
13
|
```bash
|
|
14
14
|
npm install deuk-agent-rule
|
|
15
15
|
npx deuk-agent-rule init
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
`--non-interactive` 없이 실행하면 짧은 설정 질문이 시작됩니다:
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
```
|
|
21
|
+
$ npx deuk-agent-rule init
|
|
22
|
+
|
|
23
|
+
DeukAgentRules init — let's configure your workspace.
|
|
24
|
+
|
|
25
|
+
? What is your primary tech stack?
|
|
26
|
+
1) Unity / C#
|
|
27
|
+
2) Next.js + C#
|
|
28
|
+
3) Web (React / Vue / general)
|
|
29
|
+
4) Java / Spring Boot
|
|
30
|
+
5) Other / skip
|
|
31
|
+
Choice [1-5]: 1
|
|
32
|
+
|
|
33
|
+
? Which agent tools do you use? (comma-separated numbers, or 'all')
|
|
34
|
+
1) Cursor
|
|
35
|
+
2) GitHub Copilot
|
|
36
|
+
3) Gemini / Antigravity
|
|
37
|
+
4) All of the above
|
|
38
|
+
5) Other / skip
|
|
39
|
+
Choices: 1,2
|
|
40
|
+
|
|
41
|
+
Stack : unity
|
|
42
|
+
Tools : cursor, copilot
|
|
43
|
+
|
|
44
|
+
AGENTS.md: injected (inject)
|
|
45
|
+
rule copied: .cursor/rules/deuk-agent-rule-multi-ai-workflow.mdc
|
|
46
|
+
rule copied: .cursor/rules/deuk-agent-rule-delivery-and-parallel-work.mdc
|
|
47
|
+
rule copied: .cursor/rules/deuk-agent-rule-git-commit.mdc
|
|
48
|
+
```
|
|
23
49
|
|
|
24
|
-
|
|
50
|
+
CI나 스크립트 환경에서 질문 없이 실행:
|
|
25
51
|
|
|
26
52
|
```bash
|
|
27
|
-
|
|
28
|
-
npx deuk-agent-rule init
|
|
53
|
+
npx deuk-agent-rule init --non-interactive
|
|
29
54
|
```
|
|
30
55
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
### `init` 파라미터
|
|
34
|
-
|
|
35
|
-
플래그는 모두 `init` **뒤**에 둡니다. 예: `npx deuk-agent-rule init --cwd ../다른레포 --dry-run`
|
|
36
|
-
|
|
37
|
-
| 플래그 | init 기본값 | 설명 |
|
|
38
|
-
|--------|-------------|------|
|
|
39
|
-
| `--cwd <path>` | 현재 디렉터리 | `AGENTS.md`·`.cursor/rules/`를 쓸 레포 루트. |
|
|
40
|
-
| `--dry-run` | 끔 | 쓰기 없이 할 일만 출력. |
|
|
41
|
-
| `--backup` | 끔 | 덮어쓰기 전 같은 이름에 `.bak` 저장. |
|
|
42
|
-
| `--tag <id>` | `deuk-agent-rule` | `<!-- <id>:begin -->` ~ `<!-- <id>:end -->` 마커 쌍. |
|
|
43
|
-
| `--marker-begin` / `--marker-end` | (`--tag` 권장) | 임의 마커 문자열, **둘 다** 필요. |
|
|
44
|
-
| `--agents <mode>` | `inject` | `inject` — 마커 안만 갱신(마커 없으면 블록 추가). `skip` — `AGENTS.md` 건드리지 않음. `overwrite` — 전체 교체(주의). |
|
|
45
|
-
| `--rules <mode>` | `prefix` | `prefix` — 있으면 `deuk-agent-rule-foo.mdc`로 추가. `skip` — 스킵. `overwrite` — 덮어쓰기. |
|
|
46
|
-
| `--append-if-no-markers` | 끔 | `merge`에서 주로 사용. |
|
|
47
|
-
|
|
48
|
-
예시:
|
|
56
|
+
패키지 업데이트 후:
|
|
49
57
|
|
|
50
58
|
```bash
|
|
51
|
-
|
|
52
|
-
npx deuk-agent-rule init --
|
|
53
|
-
npx deuk-agent-rule init --tag mycompany --rules overwrite
|
|
54
|
-
npx deuk-agent-rule init --agents skip --rules prefix
|
|
55
|
-
npx deuk-agent-rule init --backup
|
|
59
|
+
npm update deuk-agent-rule
|
|
60
|
+
npx deuk-agent-rule init --non-interactive
|
|
56
61
|
```
|
|
57
62
|
|
|
58
|
-
|
|
63
|
+
`AGENTS.md`의 **마커 안**만 갱신되고 바깥 내용은 유지됩니다.
|
|
64
|
+
|
|
65
|
+
### 주요 옵션
|
|
59
66
|
|
|
60
|
-
|
|
61
|
-
|
|
67
|
+
| 플래그 | 기본값 | 설명 |
|
|
68
|
+
|--------|--------|------|
|
|
69
|
+
| `--non-interactive` | 끔 | 질문 생략, 플래그 기본값으로 실행 |
|
|
70
|
+
| `--cwd <path>` | 현재 디렉터리 | 대상 레포 루트 |
|
|
71
|
+
| `--dry-run` | 끔 | 쓰기 없이 동작만 출력 |
|
|
72
|
+
| `--tag <id>` | `deuk-agent-rule` | 마커 id: `<!-- <id>:begin/end -->` |
|
|
73
|
+
| `--agents <mode>` | `inject` | `inject` \| `skip` \| `overwrite` |
|
|
74
|
+
| `--rules <mode>` | `prefix` | `prefix` \| `skip` \| `overwrite` |
|
|
75
|
+
| `--backup` | 끔 | 덮어쓰기 전 `*.bak` 저장 |
|
|
62
76
|
|
|
63
|
-
###
|
|
77
|
+
### 번들 규칙
|
|
64
78
|
|
|
65
79
|
- **`multi-ai-workflow.mdc`** — `alwaysApply: true`
|
|
80
|
+
- **`delivery-and-parallel-work.mdc`** — `alwaysApply: true` (세로 슬라이스·포트폴리오 우선·병렬 소유·리팩터 범위 축소)
|
|
66
81
|
- **`git-commit.mdc`** — `alwaysApply: false`
|
|
67
82
|
|
|
68
83
|
### `merge` (엄격)
|
|
69
84
|
|
|
70
|
-
|
|
85
|
+
옵션 동일. 마커가 없으면 inject 실패(`--append-if-no-markers` 없을 때). 기본 `--rules skip`.
|
|
71
86
|
|
|
72
87
|
### 주의
|
|
73
88
|
|
|
74
|
-
- `alwaysApply: true` 규칙이 겹치면 컨텍스트가
|
|
75
|
-
- `postinstall`에서 `init` 자동 실행은 권장하지
|
|
89
|
+
- `alwaysApply: true` 규칙이 겹치면 컨텍스트가 커질 수 있습니다.
|
|
90
|
+
- `postinstall`에서 `init` 자동 실행은 권장하지 않습니다.
|
|
76
91
|
|
|
77
92
|
## 버전
|
|
78
93
|
|
package/README.md
CHANGED
|
@@ -1,78 +1,92 @@
|
|
|
1
1
|
# DeukAgentRules
|
|
2
2
|
|
|
3
|
+
> **Part of the Deuk Family** — Empowering AI Agents with structured rules.
|
|
4
|
+
|
|
3
5
|
**npm package:** `deuk-agent-rule` · **CLI:** `deuk-agent-rule`
|
|
4
6
|
|
|
5
|
-
**한국어:** [README.ko.md](README.ko.md)
|
|
7
|
+
**한국어:** [README.ko.md](https://github.com/joygram/DeukAgentRules/blob/master/README.ko.md)
|
|
6
8
|
|
|
7
9
|
Versioned templates for `AGENTS.md` and `.cursor/rules` for Cursor, Copilot, Gemini and similar agents: shared handoff format, concise execution, stronger cost-efficiency and responsiveness.
|
|
8
10
|
|
|
9
11
|
## Initialize a workspace
|
|
10
12
|
|
|
11
|
-
Install does nothing until you run the CLI from the **target repository root** (or pass `--cwd`).
|
|
12
|
-
|
|
13
13
|
```bash
|
|
14
14
|
npm install deuk-agent-rule
|
|
15
15
|
npx deuk-agent-rule init
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
Running `init` without `--non-interactive` starts a short setup flow:
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
```
|
|
21
|
+
$ npx deuk-agent-rule init
|
|
22
|
+
|
|
23
|
+
DeukAgentRules init — let's configure your workspace.
|
|
24
|
+
|
|
25
|
+
? What is your primary tech stack?
|
|
26
|
+
1) Unity / C#
|
|
27
|
+
2) Next.js + C#
|
|
28
|
+
3) Web (React / Vue / general)
|
|
29
|
+
4) Java / Spring Boot
|
|
30
|
+
5) Other / skip
|
|
31
|
+
Choice [1-5]: 3
|
|
32
|
+
|
|
33
|
+
? Which agent tools do you use? (comma-separated numbers, or 'all')
|
|
34
|
+
1) Cursor
|
|
35
|
+
2) GitHub Copilot
|
|
36
|
+
3) Gemini / Antigravity
|
|
37
|
+
4) All of the above
|
|
38
|
+
5) Other / skip
|
|
39
|
+
Choices: all
|
|
40
|
+
|
|
41
|
+
Stack : web
|
|
42
|
+
Tools : cursor, copilot, gemini, all
|
|
43
|
+
|
|
44
|
+
AGENTS.md: injected (inject)
|
|
45
|
+
rule copied: .cursor/rules/deuk-agent-rule-multi-ai-workflow.mdc
|
|
46
|
+
rule copied: .cursor/rules/deuk-agent-rule-delivery-and-parallel-work.mdc
|
|
47
|
+
rule copied: .cursor/rules/deuk-agent-rule-git-commit.mdc
|
|
48
|
+
```
|
|
23
49
|
|
|
24
|
-
|
|
50
|
+
To skip questions (CI or scripted use):
|
|
25
51
|
|
|
26
52
|
```bash
|
|
27
|
-
|
|
28
|
-
npx deuk-agent-rule init
|
|
53
|
+
npx deuk-agent-rule init --non-interactive
|
|
29
54
|
```
|
|
30
55
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
### `init` parameters
|
|
34
|
-
|
|
35
|
-
All flags go **after** `init` (e.g. `npx deuk-agent-rule init --cwd ../other-repo --dry-run`).
|
|
36
|
-
|
|
37
|
-
| Flag | Default (init) | Description |
|
|
38
|
-
|------|----------------|-------------|
|
|
39
|
-
| `--cwd <path>` | current directory | Root of the repo to modify (`AGENTS.md`, `.cursor/rules/`). |
|
|
40
|
-
| `--dry-run` | off | Print planned actions; do not write files. |
|
|
41
|
-
| `--backup` | off | Write `*.bak` next to any file that would be overwritten. |
|
|
42
|
-
| `--tag <id>` | `deuk-agent-rule` | HTML comment markers: `<!-- <id>:begin -->` … `<!-- <id>:end -->`. |
|
|
43
|
-
| `--marker-begin <s>` / `--marker-end <s>` | (use `--tag` instead) | Custom marker strings; **both** required if either is set. |
|
|
44
|
-
| `--agents <mode>` | `inject` | `inject` — update only inside markers (or append block if no markers). `skip` — do not change `AGENTS.md`. `overwrite` — replace entire `AGENTS.md` with the bundle (use with care). |
|
|
45
|
-
| `--rules <mode>` | `prefix` | `prefix` — if `foo.mdc` exists, write `deuk-agent-rule-foo.mdc`. `skip` — skip existing names. `overwrite` — replace on clash. |
|
|
46
|
-
| `--append-if-no-markers` | off | Rare for `init` (init already appends when markers are missing). Same flag is mainly for `merge`. |
|
|
47
|
-
|
|
48
|
-
Examples:
|
|
56
|
+
After a package upgrade:
|
|
49
57
|
|
|
50
58
|
```bash
|
|
51
|
-
|
|
52
|
-
npx deuk-agent-rule init --
|
|
53
|
-
npx deuk-agent-rule init --tag mycompany --rules overwrite
|
|
54
|
-
npx deuk-agent-rule init --agents skip --rules prefix
|
|
55
|
-
npx deuk-agent-rule init --backup
|
|
59
|
+
npm update deuk-agent-rule
|
|
60
|
+
npx deuk-agent-rule init --non-interactive
|
|
56
61
|
```
|
|
57
62
|
|
|
58
|
-
|
|
63
|
+
Only the **marker region** in `AGENTS.md` is replaced; your text outside stays.
|
|
64
|
+
|
|
65
|
+
### Key options
|
|
59
66
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
-
|
|
67
|
+
| Flag | Default | Description |
|
|
68
|
+
|------|---------|-------------|
|
|
69
|
+
| `--non-interactive` | off | Skip questions; use flag defaults |
|
|
70
|
+
| `--cwd <path>` | current directory | Target repo root |
|
|
71
|
+
| `--dry-run` | off | Print actions without writing |
|
|
72
|
+
| `--tag <id>` | `deuk-agent-rule` | Marker id: `<!-- <id>:begin/end -->` |
|
|
73
|
+
| `--agents <mode>` | `inject` | `inject` \| `skip` \| `overwrite` |
|
|
74
|
+
| `--rules <mode>` | `prefix` | `prefix` \| `skip` \| `overwrite` |
|
|
75
|
+
| `--backup` | off | Write `*.bak` before overwrite |
|
|
63
76
|
|
|
64
77
|
### Bundled rules
|
|
65
78
|
|
|
66
79
|
- **`multi-ai-workflow.mdc`** — `alwaysApply: true`
|
|
80
|
+
- **`delivery-and-parallel-work.mdc`** — `alwaysApply: true` (vertical slices, portfolio priority, parallel ownership, scoped refactors)
|
|
67
81
|
- **`git-commit.mdc`** — `alwaysApply: false`
|
|
68
82
|
|
|
69
83
|
### `merge` (stricter)
|
|
70
84
|
|
|
71
|
-
Same flags;
|
|
85
|
+
Same flags; `AGENTS.md` inject fails without markers unless `--append-if-no-markers`. Default `--rules skip`.
|
|
72
86
|
|
|
73
87
|
### Caveats
|
|
74
88
|
|
|
75
|
-
- Multiple `alwaysApply: true`
|
|
89
|
+
- Multiple `alwaysApply: true` rules all apply — trim duplicates if context grows too large.
|
|
76
90
|
- Do **not** run `init` from `postinstall` without an explicit team decision.
|
|
77
91
|
|
|
78
92
|
## Versioning
|
package/bundle/AGENTS.md
CHANGED
|
@@ -22,6 +22,13 @@ Senior software engineer. Correctness, minimal diffs, safety.
|
|
|
22
22
|
- **One clear objective** per session or turn when practical; do not expand scope into unrelated refactors.
|
|
23
23
|
- For read-only or exploratory tasks, **summarize** and point to paths instead of pasting large blobs.
|
|
24
24
|
|
|
25
|
+
## Delivery, portfolio, and parallel work
|
|
26
|
+
|
|
27
|
+
- Prefer **one PR or session outcome = one vertical slice**: integrated, buildable, and **demo-able** for that slice unless the user explicitly requests a broad-only refactor.
|
|
28
|
+
- When the user signals **portfolio / demo / ship-now priority**, **narrow** work to visible outcomes first; defer wide cleanups to a separate scoped task unless blocking.
|
|
29
|
+
- Under **parallel branches or shared ownership**, keep edits **small and bounded** on hot shared paths; respect named lane or directory ownership when given; flag high-conflict paths instead of silently expanding scope.
|
|
30
|
+
- **Default to minimal refactor**: satisfy the task with the smallest structural change; split optional large refactors into a follow-up handoff instead of bundling them.
|
|
31
|
+
|
|
25
32
|
## IDE Branding
|
|
26
33
|
|
|
27
34
|
No editor or vendor tool branding in code, docs, README, commits, or published artifacts.
|
|
@@ -33,6 +40,7 @@ No editor or vendor tool branding in code, docs, README, commits, or published a
|
|
|
33
40
|
- **문서**: 사용자에게 보이는 동작·호환·패키징·보안 위주. 내부 절차 전문을 그대로 붙여 넣지 않음.
|
|
34
41
|
- **브랜딩**: 코드·문서·README·커밋·배포물에 에디터·벤더 도구 이름을 넣지 않음.
|
|
35
42
|
- **비용·효율**: 짧고 신호가 큰 답·패치 위주; 불필요한 장문·동일 맥락 반복 지양. 한 번에 목표 하나. 읽기 전용 작업은 요약과 경로 위주.
|
|
43
|
+
- **전달·병렬**: PR/세션 단위는 데모 가능한 세로 슬라이스 우선. 포트폴리오·출시 우선 시 범위 축소. 병렬 갈래·소유 구역 존중, 핫 경로는 최소 변경.
|
|
36
44
|
|
|
37
45
|
English sections above are canonical for tooling; this block is a short Korean mirror for the same rules.
|
|
38
46
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Vertical slices, portfolio priority, parallel-branch ownership, scoped refactors
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Delivery, portfolio, and parallel work
|
|
7
|
+
|
|
8
|
+
## Default shape of work
|
|
9
|
+
|
|
10
|
+
- Prefer **one PR (or one agent session outcome) = one vertically integrated slice**: buildable, runnable, and **demo-able** end-to-end for that slice. Do not treat “wide refactors with no user-visible behavior” as the default unit of delivery unless the user explicitly asks for that.
|
|
11
|
+
- When the user states **portfolio, demo, or ship-this-week priority**, treat that as **scope authority**: narrow the task to what improves the visible outcome first; defer broad cleanups to a follow-up handoff unless they are blocking the slice.
|
|
12
|
+
|
|
13
|
+
## Parallel branches and file ownership
|
|
14
|
+
|
|
15
|
+
- Assume **other branches or developers may be editing the same repo**. Before touching widely shared files (large pages, shared `lib/`, config roots), **minimize blast radius**: prefer a small, well-bounded edit over sweeping moves in the same change set.
|
|
16
|
+
- If the user names an **owner branch, feature lane, or file ownership** (e.g. “UI lane owns `components/`, gameplay owns `lib/game/`”), **stay inside that boundary** unless they explicitly expand it.
|
|
17
|
+
- When parallel work is likely, **call out** touched paths that are high-merge-conflict risk so the user can coordinate; do not silently expand into those files without need.
|
|
18
|
+
|
|
19
|
+
## Refactor discipline
|
|
20
|
+
|
|
21
|
+
- **Shrink refactor scope by default**: extract or adjust only what the current task requires. If a larger refactor is tempting, split it: **(1)** minimal change that satisfies the task, **(2)** optional follow-up task in handoff format.
|
|
22
|
+
- Do not use “while we’re here” to rename, reformat, or reorganize unrelated modules.
|
|
23
|
+
|
|
24
|
+
## Interaction with handoffs
|
|
25
|
+
|
|
26
|
+
- If a handoff or user message defines **Files to modify** and **Constraints**, those win; this rule file **narrows** how you plan and execute within that envelope — it does not override explicit file lists.
|
package/package.json
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "deuk-agent-rule",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "DeukAgentRules: generic AGENTS.md + .cursor rule templates with init/merge CLI (npm name: deuk-agent-rule).",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"agents-md",
|
|
7
|
+
"cursor-rules",
|
|
8
|
+
"copilot",
|
|
9
|
+
"gemini",
|
|
10
|
+
"handoff",
|
|
11
|
+
"deuk-family",
|
|
12
|
+
"deukpack-ecosystem"
|
|
13
|
+
],
|
|
5
14
|
"license": "Apache-2.0",
|
|
6
15
|
"files": [
|
|
7
16
|
"bundle/**/*",
|
package/scripts/cli.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { existsSync } from "fs";
|
|
2
|
+
import { existsSync, readFileSync } from "fs";
|
|
3
|
+
import { createInterface } from "readline";
|
|
3
4
|
import { dirname, join } from "path";
|
|
4
5
|
import { fileURLToPath } from "url";
|
|
5
6
|
import {
|
|
@@ -13,9 +14,122 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
|
13
14
|
const pkgRoot = join(__dirname, "..");
|
|
14
15
|
const bundleRoot = join(pkgRoot, "bundle");
|
|
15
16
|
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
// Interactive prompt helpers (no external deps)
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
|
|
21
|
+
function isNonInteractive(opts) {
|
|
22
|
+
return opts.nonInteractive || process.env.CI || !process.stdin.isTTY;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function ask(rl, question) {
|
|
26
|
+
return new Promise((resolve) => rl.question(question, resolve));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function selectOne(rl, prompt, choices) {
|
|
30
|
+
console.log("\n" + prompt);
|
|
31
|
+
choices.forEach((c, i) => console.log(` ${i + 1}) ${c.label}`));
|
|
32
|
+
while (true) {
|
|
33
|
+
const ans = (await ask(rl, ` Choice [1-${choices.length}]: `)).trim();
|
|
34
|
+
const idx = parseInt(ans, 10) - 1;
|
|
35
|
+
if (idx >= 0 && idx < choices.length) return choices[idx].value;
|
|
36
|
+
console.log(" Please enter a number between 1 and " + choices.length);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function selectMany(rl, prompt, choices) {
|
|
41
|
+
console.log("\n" + prompt + " (comma-separated numbers, or 'all')");
|
|
42
|
+
choices.forEach((c, i) => console.log(` ${i + 1}) ${c.label}`));
|
|
43
|
+
while (true) {
|
|
44
|
+
const ans = (await ask(rl, ` Choices: `)).trim().toLowerCase();
|
|
45
|
+
if (ans === "all" || ans === "") return choices.map((c) => c.value);
|
|
46
|
+
const parts = ans.split(/[,\s]+/).map((s) => parseInt(s, 10) - 1);
|
|
47
|
+
if (parts.every((i) => i >= 0 && i < choices.length)) {
|
|
48
|
+
return parts.map((i) => choices[i].value);
|
|
49
|
+
}
|
|
50
|
+
console.log(" Invalid selection, try again.");
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const STACKS = [
|
|
55
|
+
{ label: "Unity / C#", value: "unity" },
|
|
56
|
+
{ label: "Next.js + C#", value: "nextjs-dotnet" },
|
|
57
|
+
{ label: "Web (React / Vue / general)", value: "web" },
|
|
58
|
+
{ label: "Java / Spring Boot", value: "java" },
|
|
59
|
+
{ label: "Other / skip", value: "other" },
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
const AGENT_TOOLS = [
|
|
63
|
+
{ label: "Cursor", value: "cursor" },
|
|
64
|
+
{ label: "GitHub Copilot", value: "copilot" },
|
|
65
|
+
{ label: "Gemini / Antigravity", value: "gemini" },
|
|
66
|
+
{ label: "All of the above", value: "all" },
|
|
67
|
+
{ label: "Other / skip", value: "other" },
|
|
68
|
+
];
|
|
69
|
+
|
|
70
|
+
async function runInteractive(opts) {
|
|
71
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
72
|
+
try {
|
|
73
|
+
console.log("\nDeukAgentRules init — let's configure your workspace.\n");
|
|
74
|
+
|
|
75
|
+
const stack = await selectOne(rl, "What is your primary tech stack?", STACKS);
|
|
76
|
+
const tools = await selectMany(rl, "Which agent tools do you use?", AGENT_TOOLS);
|
|
77
|
+
|
|
78
|
+
const targetAgents = join(opts.cwd, "AGENTS.md");
|
|
79
|
+
let agentsDefault = "inject";
|
|
80
|
+
if (!existsSync(targetAgents)) {
|
|
81
|
+
agentsDefault = "inject"; // will append markers
|
|
82
|
+
console.log("\n No AGENTS.md found — will create with markers.");
|
|
83
|
+
} else {
|
|
84
|
+
const content = readFileSync(targetAgents, "utf8");
|
|
85
|
+
const hasMarkers = content.includes("deuk-agent-rule:begin");
|
|
86
|
+
if (!hasMarkers) {
|
|
87
|
+
const choice = await selectOne(rl, "AGENTS.md exists but has no markers. How to apply?", [
|
|
88
|
+
{ label: "Append managed block at the end (safe)", value: "inject" },
|
|
89
|
+
{ label: "Overwrite entire AGENTS.md", value: "overwrite" },
|
|
90
|
+
{ label: "Skip AGENTS.md", value: "skip" },
|
|
91
|
+
]);
|
|
92
|
+
agentsDefault = choice;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
opts.agents = opts.agents ?? agentsDefault;
|
|
97
|
+
opts.stack = stack;
|
|
98
|
+
opts.agentTools = tools;
|
|
99
|
+
|
|
100
|
+
console.log("\n Stack : " + stack);
|
|
101
|
+
console.log(" Tools : " + (tools.join(", ") || "none"));
|
|
102
|
+
console.log(" AGENTS: " + opts.agents + "\n");
|
|
103
|
+
} finally {
|
|
104
|
+
rl.close();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
109
|
+
// Help / arg parsing
|
|
110
|
+
// ---------------------------------------------------------------------------
|
|
111
|
+
|
|
16
112
|
function printHelp() {
|
|
17
113
|
console.log(
|
|
18
|
-
|
|
114
|
+
`DeukAgentRules (npm: deuk-agent-rule) — AGENTS.md + .cursor/rules templates
|
|
115
|
+
|
|
116
|
+
Usage:
|
|
117
|
+
npx deuk-agent-rule init [options] # interactive by default
|
|
118
|
+
npx deuk-agent-rule merge [options]
|
|
119
|
+
|
|
120
|
+
Options:
|
|
121
|
+
--cwd <path> Target repo root (default: current directory)
|
|
122
|
+
--dry-run Print actions; do not write files
|
|
123
|
+
--non-interactive Skip questions; use defaults/flags directly
|
|
124
|
+
--tag <id> Marker id (default: deuk-agent-rule)
|
|
125
|
+
--agents <mode> inject | skip | overwrite
|
|
126
|
+
--rules <mode> prefix | skip | overwrite
|
|
127
|
+
--backup Write *.bak before overwrite
|
|
128
|
+
--append-if-no-markers
|
|
129
|
+
--marker-begin / --marker-end Custom marker strings (both required)
|
|
130
|
+
|
|
131
|
+
Korean: package README.ko.md
|
|
132
|
+
`,
|
|
19
133
|
);
|
|
20
134
|
}
|
|
21
135
|
|
|
@@ -30,6 +144,7 @@ function parseArgs(argv) {
|
|
|
30
144
|
agents: undefined,
|
|
31
145
|
rules: undefined,
|
|
32
146
|
appendIfNoMarkers: false,
|
|
147
|
+
nonInteractive: false,
|
|
33
148
|
};
|
|
34
149
|
for (let i = 0; i < argv.length; i++) {
|
|
35
150
|
const a = argv[i];
|
|
@@ -38,6 +153,7 @@ function parseArgs(argv) {
|
|
|
38
153
|
if (!out.cwd) throw new Error("--cwd requires a path");
|
|
39
154
|
} else if (a === "--dry-run") out.dryRun = true;
|
|
40
155
|
else if (a === "--backup") out.backup = true;
|
|
156
|
+
else if (a === "--non-interactive") out.nonInteractive = true;
|
|
41
157
|
else if (a === "--tag") {
|
|
42
158
|
out.tag = argv[++i];
|
|
43
159
|
if (out.tag == null) throw new Error("--tag requires a value");
|
|
@@ -70,6 +186,10 @@ function validateMode(name, v, allowed) {
|
|
|
70
186
|
}
|
|
71
187
|
}
|
|
72
188
|
|
|
189
|
+
// ---------------------------------------------------------------------------
|
|
190
|
+
// init / merge runners
|
|
191
|
+
// ---------------------------------------------------------------------------
|
|
192
|
+
|
|
73
193
|
function runInit(opts) {
|
|
74
194
|
const markers = resolveMarkers({
|
|
75
195
|
tag: opts.tag,
|
|
@@ -150,7 +270,11 @@ function runMerge(opts) {
|
|
|
150
270
|
}
|
|
151
271
|
}
|
|
152
272
|
|
|
153
|
-
|
|
273
|
+
// ---------------------------------------------------------------------------
|
|
274
|
+
// Entry point
|
|
275
|
+
// ---------------------------------------------------------------------------
|
|
276
|
+
|
|
277
|
+
async function main() {
|
|
154
278
|
const argv = process.argv.slice(2);
|
|
155
279
|
const sub = argv[0];
|
|
156
280
|
if (!sub || sub === "-h" || sub === "--help") {
|
|
@@ -175,13 +299,16 @@ function main() {
|
|
|
175
299
|
|
|
176
300
|
if (!existsSync(bundleRoot)) {
|
|
177
301
|
console.error(
|
|
178
|
-
"Missing bundle/ (run from published package or run npm run sync in
|
|
302
|
+
"Missing bundle/ (run from published package or run npm run sync in DeukAgentRules when developing).",
|
|
179
303
|
);
|
|
180
304
|
process.exit(1);
|
|
181
305
|
}
|
|
182
306
|
|
|
183
307
|
try {
|
|
184
308
|
if (sub === "init") {
|
|
309
|
+
if (!isNonInteractive(opts)) {
|
|
310
|
+
await runInteractive(opts);
|
|
311
|
+
}
|
|
185
312
|
runInit(opts);
|
|
186
313
|
} else if (sub === "merge") {
|
|
187
314
|
runMerge(opts);
|
package/scripts/sync-oss.mjs
CHANGED
|
@@ -29,6 +29,9 @@ mkdirSync(join(ossRoot, "scripts"), { recursive: true });
|
|
|
29
29
|
mkdirSync(join(ossRoot, "publish"), { recursive: true });
|
|
30
30
|
|
|
31
31
|
cpSync(join(pkgRoot, "publish"), join(ossRoot, "publish"), { recursive: true, force: true });
|
|
32
|
+
if (existsSync(join(pkgRoot, ".github"))) {
|
|
33
|
+
cpSync(join(pkgRoot, ".github"), join(ossRoot, ".github"), { recursive: true, force: true });
|
|
34
|
+
}
|
|
32
35
|
cpSync(join(pkgRoot, "scripts", "cli.mjs"), join(ossRoot, "scripts", "cli.mjs"), { force: true });
|
|
33
36
|
cpSync(join(pkgRoot, "scripts", "merge-logic.mjs"), join(ossRoot, "scripts", "merge-logic.mjs"), {
|
|
34
37
|
force: true,
|
|
@@ -42,6 +45,12 @@ if (!existsSync(ossPublic)) {
|
|
|
42
45
|
}
|
|
43
46
|
cpSync(join(pkgRoot, "README.md"), join(ossRoot, "README.md"), { force: true });
|
|
44
47
|
cpSync(join(pkgRoot, "README.ko.md"), join(ossRoot, "README.ko.md"), { force: true });
|
|
48
|
+
if (existsSync(join(pkgRoot, "package-lock.json"))) {
|
|
49
|
+
cpSync(join(pkgRoot, "package-lock.json"), join(ossRoot, "package-lock.json"), { force: true });
|
|
50
|
+
}
|
|
51
|
+
if (existsSync(join(pkgRoot, "LICENSE"))) {
|
|
52
|
+
cpSync(join(pkgRoot, "LICENSE"), join(ossRoot, "LICENSE"), { force: true });
|
|
53
|
+
}
|
|
45
54
|
cpSync(join(ossPublic, "RELEASING.md"), join(ossRoot, "RELEASING.md"), { force: true });
|
|
46
55
|
cpSync(join(ossPublic, "RELEASING.ko.md"), join(ossRoot, "RELEASING.ko.md"), { force: true });
|
|
47
56
|
cpSync(join(ossPublic, "GITHUB_DESCRIPTION.md"), join(ossRoot, "GITHUB_DESCRIPTION.md"), {
|
|
@@ -51,7 +60,7 @@ cpSync(join(ossPublic, "GITHUB_DESCRIPTION.md"), join(ossRoot, "GITHUB_DESCRIPTI
|
|
|
51
60
|
const srcPkg = JSON.parse(readFileSync(join(pkgRoot, "package.json"), "utf8"));
|
|
52
61
|
const outPkg = {
|
|
53
62
|
...srcPkg,
|
|
54
|
-
license: "
|
|
63
|
+
license: srcPkg.license || "Apache-2.0",
|
|
55
64
|
repository: {
|
|
56
65
|
type: "git",
|
|
57
66
|
url: gitUrl,
|