@agentsmd/core 0.0.0-stage → 0.2.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/LICENSE +21 -0
- package/README.md +12 -2
- package/dist/agents-md.d.ts +30 -0
- package/dist/agents-md.d.ts.map +1 -0
- package/dist/agents-md.js +197 -0
- package/dist/agents-md.js.map +1 -0
- package/dist/check.d.ts +20 -0
- package/dist/check.d.ts.map +1 -0
- package/dist/check.js +67 -0
- package/dist/check.js.map +1 -0
- package/dist/errors.d.ts +7 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +10 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/install-entry-files.d.ts +19 -0
- package/dist/install-entry-files.d.ts.map +1 -0
- package/dist/install-entry-files.js +64 -0
- package/dist/install-entry-files.js.map +1 -0
- package/dist/install.d.ts +19 -0
- package/dist/install.d.ts.map +1 -0
- package/dist/install.js +33 -0
- package/dist/install.js.map +1 -0
- package/dist/markdown-sections.d.ts +20 -0
- package/dist/markdown-sections.d.ts.map +1 -0
- package/dist/markdown-sections.js +58 -0
- package/dist/markdown-sections.js.map +1 -0
- package/dist/markdown-table.d.ts +12 -0
- package/dist/markdown-table.d.ts.map +1 -0
- package/dist/markdown-table.js +46 -0
- package/dist/markdown-table.js.map +1 -0
- package/dist/parse-doc-map.d.ts +9 -0
- package/dist/parse-doc-map.d.ts.map +1 -0
- package/dist/parse-doc-map.js +73 -0
- package/dist/parse-doc-map.js.map +1 -0
- package/dist/pre-commit-hook.d.ts +8 -0
- package/dist/pre-commit-hook.d.ts.map +1 -0
- package/dist/pre-commit-hook.js +25 -0
- package/dist/pre-commit-hook.js.map +1 -0
- package/dist/preset.d.ts +33 -0
- package/dist/preset.d.ts.map +1 -0
- package/dist/preset.js +2 -0
- package/dist/preset.js.map +1 -0
- package/dist/resolve-link.d.ts +11 -0
- package/dist/resolve-link.d.ts.map +1 -0
- package/dist/resolve-link.js +21 -0
- package/dist/resolve-link.js.map +1 -0
- package/dist/rules/broken-link.d.ts +11 -0
- package/dist/rules/broken-link.d.ts.map +1 -0
- package/dist/rules/broken-link.js +26 -0
- package/dist/rules/broken-link.js.map +1 -0
- package/dist/rules/claude-import.d.ts +13 -0
- package/dist/rules/claude-import.d.ts.map +1 -0
- package/dist/rules/claude-import.js +46 -0
- package/dist/rules/claude-import.js.map +1 -0
- package/dist/rules/unlisted-doc.d.ts +12 -0
- package/dist/rules/unlisted-doc.d.ts.map +1 -0
- package/dist/rules/unlisted-doc.js +27 -0
- package/dist/rules/unlisted-doc.js.map +1 -0
- package/dist/types.d.ts +25 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +38 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 이태경
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @agentsmd/core
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[`@agentsmd/cli`](https://www.npmjs.com/package/@agentsmd/cli)의 검사 로직과 프리셋 설치 로직입니다.
|
|
4
|
+
CLI 없이 코드에서 검사하고 싶을 때 씁니다.
|
|
5
|
+
|
|
6
|
+
```ts
|
|
7
|
+
import { checkRepository } from "@agentsmd/core";
|
|
8
|
+
|
|
9
|
+
const findings = await checkRepository({ root: process.cwd() });
|
|
10
|
+
// [{ ruleId: 'broken-link', file: 'AGENTS.md', line: 12, message: '링크 대상이 없습니다: docs/api.md' }]
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
검사 규칙은 [docs/rules.md](https://github.com/xoruddl/agentsmd-kit/blob/main/docs/rules.md)를 참고하세요.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Preset } from "./preset.js";
|
|
2
|
+
/** Claude Code가 AGENTS.md를 읽도록 불러오기만 하는 CLAUDE.md. 규칙이 두 곳으로 갈라지지 않게 한다. */
|
|
3
|
+
export declare const CLAUDE_MD = "@AGENTS.md\n\n<!-- \uADDC\uCE59\uC740 \uC774 \uD30C\uC77C\uC5D0 \uC4F0\uC9C0 \uC54A\uB294\uB2E4. AGENTS.md \uC640 docs/ \uC5D0\uB9CC \uC791\uC131\uD55C\uB2E4. -->\n";
|
|
4
|
+
/** 합치면서 새로 넣은 항목. */
|
|
5
|
+
export interface AgentsMdAdditions {
|
|
6
|
+
/** 문서 지도에 넣은 문서 경로. */
|
|
7
|
+
readonly docs: readonly string[];
|
|
8
|
+
readonly rules: readonly string[];
|
|
9
|
+
readonly verify: readonly string[];
|
|
10
|
+
}
|
|
11
|
+
export interface MergedAgentsMd {
|
|
12
|
+
readonly content: string;
|
|
13
|
+
readonly added: AgentsMdAdditions;
|
|
14
|
+
}
|
|
15
|
+
/** 고른 프리셋들의 문서·규칙·검증 명령으로 새 AGENTS.md를 만든다. */
|
|
16
|
+
export declare function renderAgentsMd(presets: readonly Preset[]): string;
|
|
17
|
+
/**
|
|
18
|
+
* 이미 있는 AGENTS.md에 프리셋의 문서·규칙·검증 명령 가운데 빠진 것만 넣는다.
|
|
19
|
+
*
|
|
20
|
+
* 프리셋을 나눠 설치해도 지도에서 문서가 빠지지 않게 하려는 것이다. 설치 순서와 상관없이 같은 항목이 모이고,
|
|
21
|
+
* 같은 프리셋을 다시 합치면 아무것도 바뀌지 않는다. 사람이 고쳐 둔 줄은 지우거나 바꾸지 않는다.
|
|
22
|
+
*
|
|
23
|
+
* - 문서: 이미 링크된 문서는 건너뛰고, `## 문서 지도` 표 끝에 행을 더한다. 표 정렬은 다시 맞춘다.
|
|
24
|
+
* - 규칙: 같은 문장이 없으면 `## 핵심 규칙` 목록 끝에 이어 붙인다.
|
|
25
|
+
* - 검증: 같은 명령 줄이 없으면 `## 검증` 코드 블록에 더한다.
|
|
26
|
+
*
|
|
27
|
+
* 절이나 표, 목록이 없으면 새로 만든다.
|
|
28
|
+
*/
|
|
29
|
+
export declare function mergeAgentsMd(existing: string, presets: readonly Preset[]): MergedAgentsMd;
|
|
30
|
+
//# sourceMappingURL=agents-md.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agents-md.d.ts","sourceRoot":"","sources":["../src/agents-md.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAe,MAAM,EAAE,MAAM,aAAa,CAAC;AAGvD,4EAA4E;AAC5E,eAAO,MAAM,SAAS,yKAGrB,CAAC;AAyBF,qBAAqB;AACrB,MAAM,WAAW,iBAAiB;IAChC,uBAAuB;IACvB,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,iBAAiB,CAAC;CACnC;AAED,+CAA+C;AAC/C,wBAAgB,cAAc,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAEjE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,cAAc,CA2B1F"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { findSection, insertSection, lastContentLine } from "./markdown-sections.js";
|
|
2
|
+
import { formatTable, parseTableRow } from "./markdown-table.js";
|
|
3
|
+
import { parseDocMap } from "./parse-doc-map.js";
|
|
4
|
+
import { resolveLink } from "./resolve-link.js";
|
|
5
|
+
/** Claude Code가 AGENTS.md를 읽도록 불러오기만 하는 CLAUDE.md. 규칙이 두 곳으로 갈라지지 않게 한다. */
|
|
6
|
+
export const CLAUDE_MD = `@AGENTS.md
|
|
7
|
+
|
|
8
|
+
<!-- 규칙은 이 파일에 쓰지 않는다. AGENTS.md 와 docs/ 에만 작성한다. -->
|
|
9
|
+
`;
|
|
10
|
+
/** 프리셋이 아무것도 넣지 않은 AGENTS.md. 여기에 프리셋을 합치면 새 지도가 된다. */
|
|
11
|
+
const SKELETON = `# AGENTS.md
|
|
12
|
+
|
|
13
|
+
에이전트 작업 지침의 진입점. 작업 전 이 파일을 읽고, 작업 종류에 맞는 문서를 연다.
|
|
14
|
+
|
|
15
|
+
## 지침 관리
|
|
16
|
+
|
|
17
|
+
- 지침 추가·변경 요청은 메모리에 저장하지 않는다. 이 파일이나 \`docs/\` 에 반영한다.
|
|
18
|
+
- 새 문서를 만들면 위 문서 지도에 한 줄 추가한다.
|
|
19
|
+
- 문서 수정도 코드와 같은 커밋 규칙을 따른다.
|
|
20
|
+
`;
|
|
21
|
+
const DOCS = "문서 지도";
|
|
22
|
+
const RULES = "핵심 규칙";
|
|
23
|
+
const VERIFY = "검증";
|
|
24
|
+
/** 절을 새로 만들 때 이 순서를 지킨다. */
|
|
25
|
+
const SECTION_ORDER = [DOCS, RULES, VERIFY, "지침 관리"];
|
|
26
|
+
const RULES_INTRO = "문서를 다 읽지 못했더라도 아래는 반드시 지킨다.";
|
|
27
|
+
const VERIFY_INTRO = "작업을 마치기 전에 실행하고 결과를 그대로 보고한다. 실패를 숨기지 않는다.";
|
|
28
|
+
const LIST_ITEM = /^(\d+)\.\s+(.*)$|^[-*]\s+(.*)$/;
|
|
29
|
+
const FENCE = /^\s{0,3}(`{3,}|~{3,})/;
|
|
30
|
+
/** 고른 프리셋들의 문서·규칙·검증 명령으로 새 AGENTS.md를 만든다. */
|
|
31
|
+
export function renderAgentsMd(presets) {
|
|
32
|
+
return mergeAgentsMd(SKELETON, presets).content;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 이미 있는 AGENTS.md에 프리셋의 문서·규칙·검증 명령 가운데 빠진 것만 넣는다.
|
|
36
|
+
*
|
|
37
|
+
* 프리셋을 나눠 설치해도 지도에서 문서가 빠지지 않게 하려는 것이다. 설치 순서와 상관없이 같은 항목이 모이고,
|
|
38
|
+
* 같은 프리셋을 다시 합치면 아무것도 바뀌지 않는다. 사람이 고쳐 둔 줄은 지우거나 바꾸지 않는다.
|
|
39
|
+
*
|
|
40
|
+
* - 문서: 이미 링크된 문서는 건너뛰고, `## 문서 지도` 표 끝에 행을 더한다. 표 정렬은 다시 맞춘다.
|
|
41
|
+
* - 규칙: 같은 문장이 없으면 `## 핵심 규칙` 목록 끝에 이어 붙인다.
|
|
42
|
+
* - 검증: 같은 명령 줄이 없으면 `## 검증` 코드 블록에 더한다.
|
|
43
|
+
*
|
|
44
|
+
* 절이나 표, 목록이 없으면 새로 만든다.
|
|
45
|
+
*/
|
|
46
|
+
export function mergeAgentsMd(existing, presets) {
|
|
47
|
+
let lines = existing.split(/\r?\n/);
|
|
48
|
+
const linked = new Set(parseDocMap("AGENTS.md", existing).links.flatMap((link) => resolveLink("AGENTS.md", link.target) ?? []));
|
|
49
|
+
const docs = uniqueByPath(presets.flatMap((preset) => preset.docs ?? [])).filter((doc) => !linked.has(doc.path));
|
|
50
|
+
lines = addDocs(lines, docs);
|
|
51
|
+
const rules = missingItems(listItems(lines), presets.flatMap((preset) => preset.rules ?? []));
|
|
52
|
+
lines = addRules(lines, rules);
|
|
53
|
+
const verify = missingItems(codeBlockLines(lines), presets.flatMap((preset) => (preset.verify === undefined ? [] : [preset.verify])));
|
|
54
|
+
lines = addVerify(lines, verify);
|
|
55
|
+
const content = `${lines.join("\n").replace(/\s+$/, "")}\n`;
|
|
56
|
+
return { content, added: { docs: docs.map((doc) => doc.path), rules, verify } };
|
|
57
|
+
}
|
|
58
|
+
function addDocs(lines, docs) {
|
|
59
|
+
if (docs.length === 0) {
|
|
60
|
+
return lines;
|
|
61
|
+
}
|
|
62
|
+
const newRows = docs.map((doc) => [`[${doc.path}](${doc.path})`, doc.when]);
|
|
63
|
+
const section = findSection(lines, DOCS);
|
|
64
|
+
if (section === undefined) {
|
|
65
|
+
return insertSection(lines, DOCS, docsTable(newRows), later(DOCS));
|
|
66
|
+
}
|
|
67
|
+
const tableStart = findIndexIn(lines, section.start + 1, section.end, isTableLine);
|
|
68
|
+
if (tableStart === undefined) {
|
|
69
|
+
const at = lastContentLine(lines, section) + 1;
|
|
70
|
+
return splice(lines, at, 0, ["", ...docsTable(newRows)]);
|
|
71
|
+
}
|
|
72
|
+
const tableEnd = findIndexIn(lines, tableStart, section.end, (line) => !isTableLine(line)) ?? section.end;
|
|
73
|
+
const [header = [], , ...rows] = lines.slice(tableStart, tableEnd).map(parseTableRow);
|
|
74
|
+
const table = formatTable(header, [...rows, ...newRows]).split("\n");
|
|
75
|
+
return splice(lines, tableStart, tableEnd - tableStart, table);
|
|
76
|
+
}
|
|
77
|
+
function addRules(lines, rules) {
|
|
78
|
+
if (rules.length === 0) {
|
|
79
|
+
return lines;
|
|
80
|
+
}
|
|
81
|
+
const section = findSection(lines, RULES);
|
|
82
|
+
if (section === undefined) {
|
|
83
|
+
return insertSection(lines, RULES, [RULES_INTRO, "", ...numbered(rules, 1)], later(RULES));
|
|
84
|
+
}
|
|
85
|
+
const lastItem = findLastIndexIn(lines, section.start + 1, section.end, (line) => LIST_ITEM.test(line));
|
|
86
|
+
if (lastItem === undefined) {
|
|
87
|
+
const at = lastContentLine(lines, section) + 1;
|
|
88
|
+
return splice(lines, at, 0, ["", ...numbered(rules, 1)]);
|
|
89
|
+
}
|
|
90
|
+
// 목록의 마지막 항목이 여러 줄이면 들여쓴 이어지는 줄 뒤에 넣는다.
|
|
91
|
+
let at = lastItem + 1;
|
|
92
|
+
while (at < section.end && /^\s+\S/.test(lines[at] ?? "")) {
|
|
93
|
+
at++;
|
|
94
|
+
}
|
|
95
|
+
const number = /^(\d+)\./.exec(lines[lastItem] ?? "")?.[1];
|
|
96
|
+
const items = number === undefined ? rules.map((rule) => `- ${rule}`) : numbered(rules, Number(number) + 1);
|
|
97
|
+
return splice(lines, at, 0, items);
|
|
98
|
+
}
|
|
99
|
+
function addVerify(lines, commands) {
|
|
100
|
+
if (commands.length === 0) {
|
|
101
|
+
return lines;
|
|
102
|
+
}
|
|
103
|
+
const block = ["```bash", ...commands, "```"];
|
|
104
|
+
const section = findSection(lines, VERIFY);
|
|
105
|
+
if (section === undefined) {
|
|
106
|
+
return insertSection(lines, VERIFY, [VERIFY_INTRO, "", ...block], later(VERIFY));
|
|
107
|
+
}
|
|
108
|
+
const open = findIndexIn(lines, section.start + 1, section.end, (line) => FENCE.test(line));
|
|
109
|
+
const close = open === undefined
|
|
110
|
+
? undefined
|
|
111
|
+
: findIndexIn(lines, open + 1, section.end, (line) => FENCE.test(line));
|
|
112
|
+
if (close === undefined) {
|
|
113
|
+
const at = lastContentLine(lines, section) + 1;
|
|
114
|
+
return splice(lines, at, 0, ["", ...block]);
|
|
115
|
+
}
|
|
116
|
+
return splice(lines, close, 0, [...commands]);
|
|
117
|
+
}
|
|
118
|
+
function docsTable(rows) {
|
|
119
|
+
return formatTable(["문서", "읽는 시점"], rows).split("\n");
|
|
120
|
+
}
|
|
121
|
+
function numbered(items, from) {
|
|
122
|
+
return items.map((item, index) => `${String(from + index)}. ${item}`);
|
|
123
|
+
}
|
|
124
|
+
/** `## 핵심 규칙` 목록의 항목 문장. 번호·글머리표는 뗀다. */
|
|
125
|
+
function listItems(lines) {
|
|
126
|
+
const section = findSection(lines, RULES);
|
|
127
|
+
if (section === undefined) {
|
|
128
|
+
return [];
|
|
129
|
+
}
|
|
130
|
+
return lines.slice(section.start + 1, section.end).flatMap((line) => {
|
|
131
|
+
const match = LIST_ITEM.exec(line);
|
|
132
|
+
const text = match?.[2] ?? match?.[3];
|
|
133
|
+
return text === undefined ? [] : [text.trim()];
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
/** `## 검증` 절의 코드 블록 안 줄. */
|
|
137
|
+
function codeBlockLines(lines) {
|
|
138
|
+
const section = findSection(lines, VERIFY);
|
|
139
|
+
if (section === undefined) {
|
|
140
|
+
return [];
|
|
141
|
+
}
|
|
142
|
+
let inFence = false;
|
|
143
|
+
return lines.slice(section.start + 1, section.end).flatMap((line) => {
|
|
144
|
+
if (FENCE.test(line)) {
|
|
145
|
+
inFence = !inFence;
|
|
146
|
+
return [];
|
|
147
|
+
}
|
|
148
|
+
return inFence ? [line.trim()] : [];
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
/** 이미 있는 항목과 같은 것, 앞에서 이미 나온 것을 뺀다. */
|
|
152
|
+
function missingItems(existing, candidates) {
|
|
153
|
+
const seen = new Set(existing);
|
|
154
|
+
return candidates.filter((item) => {
|
|
155
|
+
if (seen.has(item.trim())) {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
seen.add(item.trim());
|
|
159
|
+
return true;
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
function uniqueByPath(entries) {
|
|
163
|
+
const seen = new Set();
|
|
164
|
+
return entries.filter((entry) => {
|
|
165
|
+
if (seen.has(entry.path)) {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
seen.add(entry.path);
|
|
169
|
+
return true;
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
function later(title) {
|
|
173
|
+
return SECTION_ORDER.slice(SECTION_ORDER.indexOf(title) + 1);
|
|
174
|
+
}
|
|
175
|
+
function isTableLine(line) {
|
|
176
|
+
return line.trimStart().startsWith("|");
|
|
177
|
+
}
|
|
178
|
+
function findIndexIn(lines, from, to, test) {
|
|
179
|
+
for (let index = from; index < to; index++) {
|
|
180
|
+
if (test(lines[index] ?? "")) {
|
|
181
|
+
return index;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return undefined;
|
|
185
|
+
}
|
|
186
|
+
function findLastIndexIn(lines, from, to, test) {
|
|
187
|
+
for (let index = to - 1; index >= from; index--) {
|
|
188
|
+
if (test(lines[index] ?? "")) {
|
|
189
|
+
return index;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return undefined;
|
|
193
|
+
}
|
|
194
|
+
function splice(lines, start, deleteCount, items) {
|
|
195
|
+
return [...lines.slice(0, start), ...items, ...lines.slice(start + deleteCount)];
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=agents-md.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agents-md.js","sourceRoot":"","sources":["../src/agents-md.ts"],"names":[],"mappings":"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"}
|
package/dist/check.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Finding } from "./types.js";
|
|
2
|
+
export interface CheckOptions {
|
|
3
|
+
/** 검사할 저장소의 루트 디렉터리. */
|
|
4
|
+
readonly root: string;
|
|
5
|
+
/** 문서 지도 파일. 루트 기준 상대 경로. 기본값 `AGENTS.md` */
|
|
6
|
+
readonly agentsFile?: string;
|
|
7
|
+
/** 지도에 모두 올라 있어야 하는 문서 디렉터리. 루트 기준 상대 경로. 기본값 `docs` */
|
|
8
|
+
readonly docsDir?: string;
|
|
9
|
+
/** Claude Code용 지침 파일. 루트 기준 상대 경로. 기본값 `CLAUDE.md` */
|
|
10
|
+
readonly claudeFile?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* 저장소의 AI 작업 지침을 검사하고, 찾은 문제를 파일·줄 순서로 돌려준다.
|
|
14
|
+
*
|
|
15
|
+
* 규칙들은 파일 시스템을 모르는 순수 함수이고, 파일을 읽는 일은 이 함수가 모두 맡는다.
|
|
16
|
+
*
|
|
17
|
+
* @throws {DocMapNotFoundError} 문서 지도 파일이 없을 때
|
|
18
|
+
*/
|
|
19
|
+
export declare function checkRepository(options: CheckOptions): Promise<Finding[]>;
|
|
20
|
+
//# sourceMappingURL=check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../src/check.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,MAAM,WAAW,YAAY;IAC3B,wBAAwB;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,6CAA6C;IAC7C,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,wDAAwD;IACxD,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,uDAAuD;IACvD,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAgB/E"}
|
package/dist/check.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { readFile, readdir } from "node:fs/promises";
|
|
3
|
+
import { join, posix, sep } from "node:path";
|
|
4
|
+
import { DocMapNotFoundError } from "./errors.js";
|
|
5
|
+
import { parseDocMap } from "./parse-doc-map.js";
|
|
6
|
+
import { findBrokenLinks } from "./rules/broken-link.js";
|
|
7
|
+
import { findMissingClaudeImport } from "./rules/claude-import.js";
|
|
8
|
+
import { findUnlistedDocs } from "./rules/unlisted-doc.js";
|
|
9
|
+
/**
|
|
10
|
+
* 저장소의 AI 작업 지침을 검사하고, 찾은 문제를 파일·줄 순서로 돌려준다.
|
|
11
|
+
*
|
|
12
|
+
* 규칙들은 파일 시스템을 모르는 순수 함수이고, 파일을 읽는 일은 이 함수가 모두 맡는다.
|
|
13
|
+
*
|
|
14
|
+
* @throws {DocMapNotFoundError} 문서 지도 파일이 없을 때
|
|
15
|
+
*/
|
|
16
|
+
export async function checkRepository(options) {
|
|
17
|
+
const { root, agentsFile = "AGENTS.md", docsDir = "docs", claudeFile = "CLAUDE.md" } = options;
|
|
18
|
+
const agentsContent = await readOptional(join(root, agentsFile));
|
|
19
|
+
if (agentsContent === undefined) {
|
|
20
|
+
throw new DocMapNotFoundError(agentsFile);
|
|
21
|
+
}
|
|
22
|
+
const map = parseDocMap(agentsFile, agentsContent);
|
|
23
|
+
const exists = (repoPath) => existsSync(join(root, repoPath));
|
|
24
|
+
const findings = [
|
|
25
|
+
...findBrokenLinks(map, exists),
|
|
26
|
+
...findUnlistedDocs([map], await listMarkdownFiles(root, docsDir)),
|
|
27
|
+
...findMissingClaudeImport(claudeFile, await readOptional(join(root, claudeFile)), agentsFile),
|
|
28
|
+
];
|
|
29
|
+
return findings.sort(byLocation);
|
|
30
|
+
}
|
|
31
|
+
async function readOptional(path) {
|
|
32
|
+
try {
|
|
33
|
+
return await readFile(path, "utf8");
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
if (isNotFound(error)) {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
throw error;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/** 문서 디렉터리 아래의 .md 파일을 루트 기준 posix 경로로 모은다. 디렉터리가 없으면 빈 목록이다. */
|
|
43
|
+
async function listMarkdownFiles(root, docsDir) {
|
|
44
|
+
try {
|
|
45
|
+
const entries = await readdir(join(root, docsDir), { recursive: true, withFileTypes: true });
|
|
46
|
+
return entries
|
|
47
|
+
.filter((entry) => entry.isFile() && entry.name.endsWith(".md"))
|
|
48
|
+
.map((entry) => toRepoPath(root, join(entry.parentPath, entry.name)))
|
|
49
|
+
.sort();
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
if (isNotFound(error)) {
|
|
53
|
+
return [];
|
|
54
|
+
}
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function toRepoPath(root, absolutePath) {
|
|
59
|
+
return posix.normalize(absolutePath.slice(join(root, sep).length).split(sep).join("/"));
|
|
60
|
+
}
|
|
61
|
+
function isNotFound(error) {
|
|
62
|
+
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
63
|
+
}
|
|
64
|
+
function byLocation(a, b) {
|
|
65
|
+
return a.file.localeCompare(b.file) || (a.line ?? 0) - (b.line ?? 0);
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.js","sourceRoot":"","sources":["../src/check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAc3D;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAAqB;IACzD,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,WAAW,EAAE,OAAO,GAAG,MAAM,EAAE,UAAU,GAAG,WAAW,EAAE,GAAG,OAAO,CAAC;IAE/F,MAAM,aAAa,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC;IACjE,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;QAChC,MAAM,IAAI,mBAAmB,CAAC,UAAU,CAAC,CAAC;IAC5C,CAAC;IACD,MAAM,GAAG,GAAG,WAAW,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;IACnD,MAAM,MAAM,GAAG,CAAC,QAAgB,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;IAEtE,MAAM,QAAQ,GAAG;QACf,GAAG,eAAe,CAAC,GAAG,EAAE,MAAM,CAAC;QAC/B,GAAG,gBAAgB,CAAC,CAAC,GAAG,CAAC,EAAE,MAAM,iBAAiB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAClE,GAAG,uBAAuB,CAAC,UAAU,EAAE,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,EAAE,UAAU,CAAC;KAC/F,CAAC;IACF,OAAO,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;AACnC,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,IAAY;IACtC,IAAI,CAAC;QACH,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACtC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YACtB,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,iEAAiE;AACjE,KAAK,UAAU,iBAAiB,CAAC,IAAY,EAAE,OAAe;IAC5D,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7F,OAAO,OAAO;aACX,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;aAC/D,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;aACpE,IAAI,EAAE,CAAC;IACZ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YACtB,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,IAAY,EAAE,YAAoB;IACpD,OAAO,KAAK,CAAC,SAAS,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1F,CAAC;AAED,SAAS,UAAU,CAAC,KAAc;IAChC,OAAO,KAAK,YAAY,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC;AAC9E,CAAC;AAED,SAAS,UAAU,CAAC,CAAU,EAAE,CAAU;IACxC,OAAO,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC;AACvE,CAAC"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,qBAAa,mBAAoB,SAAQ,KAAK;IAGhC,QAAQ,CAAC,IAAI,EAAE,MAAM;IAFjC,SAAkB,IAAI,yBAAyB;gBAE1B,IAAI,EAAE,MAAM;CAGlC"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** 검사의 출발점인 문서 지도 파일이 없을 때. 규칙 위반이 아니라 검사를 시작할 수 없는 상황이다. */
|
|
2
|
+
export class DocMapNotFoundError extends Error {
|
|
3
|
+
path;
|
|
4
|
+
name = "DocMapNotFoundError";
|
|
5
|
+
constructor(path) {
|
|
6
|
+
super(`문서 지도를 찾을 수 없습니다: ${path}`);
|
|
7
|
+
this.path = path;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAGvB;IAFH,IAAI,GAAG,qBAAqB,CAAC;IAE/C,YAAqB,IAAY;QAC/B,KAAK,CAAC,qBAAqB,IAAI,EAAE,CAAC,CAAC;QADhB,SAAI,GAAJ,IAAI,CAAQ;IAEjC,CAAC;CACF"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { CLAUDE_MD, mergeAgentsMd, renderAgentsMd } from "./agents-md.js";
|
|
2
|
+
export type { AgentsMdAdditions, MergedAgentsMd } from "./agents-md.js";
|
|
3
|
+
export { checkRepository } from "./check.js";
|
|
4
|
+
export type { CheckOptions } from "./check.js";
|
|
5
|
+
export { DocMapNotFoundError } from "./errors.js";
|
|
6
|
+
export { installEntryFiles } from "./install-entry-files.js";
|
|
7
|
+
export type { EntryFilesResult } from "./install-entry-files.js";
|
|
8
|
+
export { installPreset } from "./install.js";
|
|
9
|
+
export type { InstallOptions, InstallResult } from "./install.js";
|
|
10
|
+
export { PRE_COMMIT_HOOK } from "./pre-commit-hook.js";
|
|
11
|
+
export type { DocMapEntry, Preset } from "./preset.js";
|
|
12
|
+
export type { DocLink, DocMap, Finding, RuleId } from "./types.js";
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC1E,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACxE,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,YAAY,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,YAAY,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACvD,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { CLAUDE_MD, mergeAgentsMd, renderAgentsMd } from "./agents-md.js";
|
|
2
|
+
export { checkRepository } from "./check.js";
|
|
3
|
+
export { DocMapNotFoundError } from "./errors.js";
|
|
4
|
+
export { installEntryFiles } from "./install-entry-files.js";
|
|
5
|
+
export { installPreset } from "./install.js";
|
|
6
|
+
export { PRE_COMMIT_HOOK } from "./pre-commit-hook.js";
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAE1E,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type AgentsMdAdditions } from "./agents-md.js";
|
|
2
|
+
import type { InstallOptions, InstallResult } from "./install.js";
|
|
3
|
+
import type { Preset } from "./preset.js";
|
|
4
|
+
export interface EntryFilesResult extends InstallResult {
|
|
5
|
+
/** 이미 있던 AGENTS.md에 합쳤으면 새로 넣은 항목. 새로 만들었거나 덮어썼으면 undefined. */
|
|
6
|
+
readonly merged: AgentsMdAdditions | undefined;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* 여러 프리셋이 함께 쓰는 파일을 고른 프리셋에 맞게 만들어 설치한다.
|
|
10
|
+
*
|
|
11
|
+
* - `AGENTS.md`: 고른 프리셋들의 문서 지도를 합친 것
|
|
12
|
+
* - `CLAUDE.md`: `AGENTS.md`를 불러오기만 한다
|
|
13
|
+
* - `<hooksPath>/pre-commit`: 훅이 있는 프리셋을 골랐을 때만. 각 프리셋의 `pre-commit.d/` 검사를 실행한다
|
|
14
|
+
*
|
|
15
|
+
* `AGENTS.md`가 이미 있으면 빠진 문서·규칙·검증 명령만 합친다. 프리셋을 나눠 설치해도 지도에서 빠지지 않게 하려는 것이다.
|
|
16
|
+
* 나머지 파일은 프리셋 파일과 같은 규칙으로, 이미 있으면 건너뛴다. `force`면 모두 새로 쓴다.
|
|
17
|
+
*/
|
|
18
|
+
export declare function installEntryFiles(presets: readonly Preset[], targetDir: string, options?: InstallOptions): Promise<EntryFilesResult>;
|
|
19
|
+
//# sourceMappingURL=install-entry-files.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-entry-files.d.ts","sourceRoot":"","sources":["../src/install-entry-files.ts"],"names":[],"mappings":"AAGA,OAAO,EAA4C,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAClG,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAU1C,MAAM,WAAW,gBAAiB,SAAQ,aAAa;IACrD,gEAAgE;IAChE,QAAQ,CAAC,MAAM,EAAE,iBAAiB,GAAG,SAAS,CAAC;CAChD;AAED;;;;;;;;;GASG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,gBAAgB,CAAC,CAwB3B"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { chmod, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { CLAUDE_MD, mergeAgentsMd, renderAgentsMd } from "./agents-md.js";
|
|
5
|
+
import { PRE_COMMIT_HOOK } from "./pre-commit-hook.js";
|
|
6
|
+
const AGENTS_MD = "AGENTS.md";
|
|
7
|
+
/**
|
|
8
|
+
* 여러 프리셋이 함께 쓰는 파일을 고른 프리셋에 맞게 만들어 설치한다.
|
|
9
|
+
*
|
|
10
|
+
* - `AGENTS.md`: 고른 프리셋들의 문서 지도를 합친 것
|
|
11
|
+
* - `CLAUDE.md`: `AGENTS.md`를 불러오기만 한다
|
|
12
|
+
* - `<hooksPath>/pre-commit`: 훅이 있는 프리셋을 골랐을 때만. 각 프리셋의 `pre-commit.d/` 검사를 실행한다
|
|
13
|
+
*
|
|
14
|
+
* `AGENTS.md`가 이미 있으면 빠진 문서·규칙·검증 명령만 합친다. 프리셋을 나눠 설치해도 지도에서 빠지지 않게 하려는 것이다.
|
|
15
|
+
* 나머지 파일은 프리셋 파일과 같은 규칙으로, 이미 있으면 건너뛴다. `force`면 모두 새로 쓴다.
|
|
16
|
+
*/
|
|
17
|
+
export async function installEntryFiles(presets, targetDir, options = {}) {
|
|
18
|
+
const force = options.force === true;
|
|
19
|
+
const written = [];
|
|
20
|
+
const skipped = [];
|
|
21
|
+
const merged = force ? undefined : await mergeExistingAgentsMd(presets, targetDir);
|
|
22
|
+
for (const file of entryFiles(presets)) {
|
|
23
|
+
const destination = join(targetDir, file.path);
|
|
24
|
+
if (file.path === AGENTS_MD && merged !== undefined) {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
if (!force && existsSync(destination)) {
|
|
28
|
+
skipped.push(file.path);
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
await mkdir(dirname(destination), { recursive: true });
|
|
32
|
+
await writeFile(destination, file.content);
|
|
33
|
+
if (file.executable) {
|
|
34
|
+
await chmod(destination, 0o755);
|
|
35
|
+
}
|
|
36
|
+
written.push(file.path);
|
|
37
|
+
}
|
|
38
|
+
return { written, skipped, merged };
|
|
39
|
+
}
|
|
40
|
+
/** 이미 있는 AGENTS.md에 빠진 항목을 합친다. 파일이 없으면 undefined, 넣을 것이 없으면 파일을 건드리지 않는다. */
|
|
41
|
+
async function mergeExistingAgentsMd(presets, targetDir) {
|
|
42
|
+
const path = join(targetDir, AGENTS_MD);
|
|
43
|
+
if (!existsSync(path)) {
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
const existing = await readFile(path, "utf8");
|
|
47
|
+
const { content, added } = mergeAgentsMd(existing, presets);
|
|
48
|
+
if (content !== existing) {
|
|
49
|
+
await writeFile(path, content);
|
|
50
|
+
}
|
|
51
|
+
return added;
|
|
52
|
+
}
|
|
53
|
+
function entryFiles(presets) {
|
|
54
|
+
const files = [
|
|
55
|
+
{ path: AGENTS_MD, content: renderAgentsMd(presets), executable: false },
|
|
56
|
+
{ path: "CLAUDE.md", content: CLAUDE_MD, executable: false },
|
|
57
|
+
];
|
|
58
|
+
const hooksPath = presets.find((preset) => preset.hooksPath !== undefined)?.hooksPath;
|
|
59
|
+
if (hooksPath !== undefined) {
|
|
60
|
+
files.push({ path: `${hooksPath}/pre-commit`, content: PRE_COMMIT_HOOK, executable: true });
|
|
61
|
+
}
|
|
62
|
+
return files;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=install-entry-files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-entry-files.js","sourceRoot":"","sources":["../src/install-entry-files.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Preset } from "./preset.js";
|
|
2
|
+
export interface InstallOptions {
|
|
3
|
+
/** 이미 있는 파일도 덮어쓴다. 기본값 false. */
|
|
4
|
+
readonly force?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export interface InstallResult {
|
|
7
|
+
/** 새로 만들었거나 덮어쓴 파일. 대상 디렉터리 기준 posix 경로. */
|
|
8
|
+
readonly written: readonly string[];
|
|
9
|
+
/** 이미 있어서 건드리지 않은 파일. 대상 디렉터리 기준 posix 경로. */
|
|
10
|
+
readonly skipped: readonly string[];
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* 프리셋 파일을 대상 디렉터리에 복사한다.
|
|
14
|
+
*
|
|
15
|
+
* 기존 저장소에 적용할 때 사람이 다듬어 둔 지침을 지우지 않도록, 기본으로는 이미 있는 파일을 건너뛴다.
|
|
16
|
+
* 파일 권한도 함께 복사되므로 Git 훅의 실행 권한이 유지된다.
|
|
17
|
+
*/
|
|
18
|
+
export declare function installPreset(preset: Preset, targetDir: string, options?: InstallOptions): Promise<InstallResult>;
|
|
19
|
+
//# sourceMappingURL=install.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,WAAW,cAAc;IAC7B,iCAAiC;IACjC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAC5B,4CAA4C;IAC5C,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,8CAA8C;IAC9C,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,aAAa,CAAC,CAgBxB"}
|
package/dist/install.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { copyFile, mkdir, readdir } from "node:fs/promises";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { dirname, join, relative, sep } from "node:path";
|
|
4
|
+
/**
|
|
5
|
+
* 프리셋 파일을 대상 디렉터리에 복사한다.
|
|
6
|
+
*
|
|
7
|
+
* 기존 저장소에 적용할 때 사람이 다듬어 둔 지침을 지우지 않도록, 기본으로는 이미 있는 파일을 건너뛴다.
|
|
8
|
+
* 파일 권한도 함께 복사되므로 Git 훅의 실행 권한이 유지된다.
|
|
9
|
+
*/
|
|
10
|
+
export async function installPreset(preset, targetDir, options = {}) {
|
|
11
|
+
const written = [];
|
|
12
|
+
const skipped = [];
|
|
13
|
+
for (const file of await listFiles(preset.filesDir)) {
|
|
14
|
+
const destination = join(targetDir, file);
|
|
15
|
+
if (options.force !== true && existsSync(destination)) {
|
|
16
|
+
skipped.push(file);
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
await mkdir(dirname(destination), { recursive: true });
|
|
20
|
+
await copyFile(join(preset.filesDir, file), destination);
|
|
21
|
+
written.push(file);
|
|
22
|
+
}
|
|
23
|
+
return { written, skipped };
|
|
24
|
+
}
|
|
25
|
+
/** 디렉터리 아래 모든 파일을 posix 상대 경로로, 정렬해서 돌려준다. */
|
|
26
|
+
async function listFiles(dir) {
|
|
27
|
+
const entries = await readdir(dir, { recursive: true, withFileTypes: true });
|
|
28
|
+
return entries
|
|
29
|
+
.filter((entry) => entry.isFile())
|
|
30
|
+
.map((entry) => relative(dir, join(entry.parentPath, entry.name)).split(sep).join("/"))
|
|
31
|
+
.sort();
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=install.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAezD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAAc,EACd,SAAiB,EACjB,UAA0B,EAAE;IAE5B,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,KAAK,MAAM,IAAI,IAAI,MAAM,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;QACpD,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QAC1C,IAAI,OAAO,CAAC,KAAK,KAAK,IAAI,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YACtD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACnB,SAAS;QACX,CAAC;QACD,MAAM,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACvD,MAAM,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,WAAW,CAAC,CAAC;QACzD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrB,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAC9B,CAAC;AAED,8CAA8C;AAC9C,KAAK,UAAU,SAAS,CAAC,GAAW;IAClC,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7E,OAAO,OAAO;SACX,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;SACjC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;SACtF,IAAI,EAAE,CAAC;AACZ,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** `## 제목` 절의 줄 범위. `start`는 제목 줄, `end`는 다음 제목 줄(없으면 줄 수)이다. */
|
|
2
|
+
export interface Section {
|
|
3
|
+
readonly start: number;
|
|
4
|
+
readonly end: number;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* `## 제목` 절을 찾는다. 절은 다음 `#`·`##` 제목 앞에서 끝난다.
|
|
8
|
+
* 코드 블록 안의 `##` 줄은 제목으로 보지 않는다.
|
|
9
|
+
*/
|
|
10
|
+
export declare function findSection(lines: readonly string[], title: string): Section | undefined;
|
|
11
|
+
/** 절 안에서 마지막으로 내용이 있는 줄. 절이 제목뿐이면 제목 줄이다. */
|
|
12
|
+
export declare function lastContentLine(lines: readonly string[], section: Section): number;
|
|
13
|
+
/**
|
|
14
|
+
* 새 `## 제목` 절을 넣는다.
|
|
15
|
+
*
|
|
16
|
+
* `before`에 적힌 절 가운데 문서에 있는 첫 번째 절 앞에 넣고, 하나도 없으면 문서 끝에 붙인다.
|
|
17
|
+
* 절 사이에는 빈 줄 하나를 둔다.
|
|
18
|
+
*/
|
|
19
|
+
export declare function insertSection(lines: readonly string[], title: string, body: readonly string[], before: readonly string[]): string[];
|
|
20
|
+
//# sourceMappingURL=markdown-sections.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-sections.d.ts","sourceRoot":"","sources":["../src/markdown-sections.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAKD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAexF;AAED,6CAA6C;AAC7C,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,CAOlF;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,MAAM,EAAE,SAAS,MAAM,EAAE,GACxB,MAAM,EAAE,CAWV"}
|