@01b/team-kb 0.2.8 → 0.3.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/README.md +180 -0
- package/dist/index.js +227 -6
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
- package/templates/kb-structure/kb-health.yml +22 -17
- package/templates/kb-structure/kb-rules.md +7 -8
- package/templates/kb-structure/pre-commit +6 -2
package/README.md
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# @01b/team-kb
|
|
2
|
+
|
|
3
|
+
CLI tool for building and wiring a Team Knowledge Base (KB) so that LLMs (Claude, Gemini, Codex) can automatically leverage shared team knowledge.
|
|
4
|
+
|
|
5
|
+
## Why
|
|
6
|
+
|
|
7
|
+
- LLM sessions reset every time. Domain knowledge explained yesterday is forgotten today.
|
|
8
|
+
- Knowledge stays siloed — what one developer teaches Claude, another's Gemini doesn't know.
|
|
9
|
+
- LLMs ignore team coding conventions because they don't know they exist.
|
|
10
|
+
|
|
11
|
+
**@01b/team-kb** solves this by creating a shared, git-based knowledge base that automatically loads into any LLM tool across your team.
|
|
12
|
+
|
|
13
|
+
**How is this different from RAG?** RAG searches documents when you ask. team-kb pre-loads knowledge into every LLM session — your LLM already knows your domain before you ask anything. [Learn more](docs/vs-rag.md)
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
npm install -g @01b/team-kb
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Commands
|
|
22
|
+
|
|
23
|
+
### `kb init`
|
|
24
|
+
|
|
25
|
+
Create a new KB repository. Run once per team.
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
mkdir ~/team-kb && cd ~/team-kb
|
|
29
|
+
kb init
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Generates:
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
team-kb/
|
|
36
|
+
├── ai-context/ # Auto-loaded by LLMs
|
|
37
|
+
│ ├── kb-rules.md # Search, record, and reference rules
|
|
38
|
+
│ └── team-focus.md # Team intro and focus areas
|
|
39
|
+
├── rules/ # Verified business rules
|
|
40
|
+
├── analysis/ # Code analysis results
|
|
41
|
+
├── decisions/ # Decision records
|
|
42
|
+
├── troubleshoot/ # Incident responses
|
|
43
|
+
├── drafts/ # Unverified drafts
|
|
44
|
+
├── archive/ # Inactive notes
|
|
45
|
+
├── templates/ # Note templates
|
|
46
|
+
├── .kb/
|
|
47
|
+
│ ├── hooks/pre-commit # Frontmatter validation + index rebuild
|
|
48
|
+
│ └── scripts/ # rebuild-index.sh
|
|
49
|
+
├── .github/workflows/ # CI health checks
|
|
50
|
+
└── kb-index.json # Search index (auto-generated)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### `kb join <url>`
|
|
54
|
+
|
|
55
|
+
Join an existing KB. Run once per team member.
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
kb join https://github.com/your-org/team-kb.git
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
This will:
|
|
62
|
+
- `git clone` the KB repository
|
|
63
|
+
- Install the pre-commit hook
|
|
64
|
+
- Save the KB path to local config
|
|
65
|
+
|
|
66
|
+
### `kb wire <tool>`
|
|
67
|
+
|
|
68
|
+
Wire a project to the KB. Run once per project per tool.
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
cd ~/repos/my-project
|
|
72
|
+
kb wire claude # Claude Code
|
|
73
|
+
kb wire gemini # Gemini CLI
|
|
74
|
+
kb wire codex # Codex CLI
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
#### Claude
|
|
78
|
+
|
|
79
|
+
Creates symlinks in `.claude/rules/` pointing to KB files. Claude Code auto-scans this directory, so KB rules and knowledge are loaded automatically every session.
|
|
80
|
+
|
|
81
|
+
#### Gemini
|
|
82
|
+
|
|
83
|
+
Creates `GEMINI.md` with `@import` chain via `.gemini/kb-context/` symlink. Gemini loads `GEMINI.md` as a foundational mandate, which imports KB rules and knowledge through the symlink.
|
|
84
|
+
|
|
85
|
+
#### Codex
|
|
86
|
+
|
|
87
|
+
Creates `AGENTS.md` with a directive to read `.codex/kb-directive.md`. Codex reads `AGENTS.md` on session start and follows the instruction to load KB content via tool calls.
|
|
88
|
+
|
|
89
|
+
### How wiring works
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
Claude: .claude/rules/ ── auto-scan ──→ symlinks ──→ KB ai-context/
|
|
93
|
+
Gemini: GEMINI.md ──@import──→ kb-import.md ──@import──→ kb-context/ (symlink) ──→ KB ai-context/
|
|
94
|
+
Codex: AGENTS.md ──directive──→ kb-directive.md ──tool call──→ KB ai-context/
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**Tracked vs local-only**: Tracked files (git commit) contain only KB entry points. Files with absolute paths are local-only (`.gitignore`) to prevent path conflicts between team members.
|
|
98
|
+
|
|
99
|
+
### `kb index`
|
|
100
|
+
|
|
101
|
+
Rebuild the KB search index. Uses Node.js for safe JSON serialization (replaces the legacy bash script).
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
kb index # Rebuild kb-index.json
|
|
105
|
+
kb index --check # Validate frontmatter without rebuilding
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Runs automatically via the pre-commit hook on every commit.
|
|
109
|
+
|
|
110
|
+
### `kb query <keywords>`
|
|
111
|
+
|
|
112
|
+
Search the KB from the command line. Designed for LLM tool calls — one command returns matching notes.
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
kb query "coupon discount" # OR matching, top 5, tldr + first 30 lines
|
|
116
|
+
kb query "coupon" --repo my-service # Prioritize notes tagged with repo/my-service
|
|
117
|
+
kb query "redis" --brief # Show tldr only (note list)
|
|
118
|
+
kb query "cache" --full # Show full note content
|
|
119
|
+
kb query "coupon" --limit 3 # Top 3 results only
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
LLMs use this automatically via the rules in `ai-context/kb-rules.md`.
|
|
123
|
+
|
|
124
|
+
## Recording Knowledge
|
|
125
|
+
|
|
126
|
+
While working with an LLM, when you discover new domain knowledge:
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
"Record this to KB"
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
The LLM will:
|
|
133
|
+
1. Determine the appropriate folder based on content type
|
|
134
|
+
2. Create a note with proper frontmatter (tags, tldr, created, updated)
|
|
135
|
+
3. The pre-commit hook automatically rebuilds the search index on commit
|
|
136
|
+
|
|
137
|
+
### Tag namespaces
|
|
138
|
+
|
|
139
|
+
Tags use `/` as a namespace separator (Obsidian-compatible):
|
|
140
|
+
|
|
141
|
+
```yaml
|
|
142
|
+
tags: [repo/my-service, domain/coupon, tech/redis]
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Folder guide
|
|
146
|
+
|
|
147
|
+
| Folder | Purpose |
|
|
148
|
+
|--------|---------|
|
|
149
|
+
| `rules/` | Team-verified business rules |
|
|
150
|
+
| `analysis/` | Code analysis results |
|
|
151
|
+
| `decisions/` | Decision records |
|
|
152
|
+
| `troubleshoot/` | Incident response records |
|
|
153
|
+
| `drafts/` | Unverified drafts |
|
|
154
|
+
|
|
155
|
+
## KB Search Rules
|
|
156
|
+
|
|
157
|
+
Defined in `ai-context/kb-rules.md` and auto-loaded into every LLM session:
|
|
158
|
+
|
|
159
|
+
- **KB first** — For domain knowledge questions, check KB before searching code
|
|
160
|
+
- **Code is truth** — KB is a guide, code is the source of truth. Lightly verify against code when answering about code behavior
|
|
161
|
+
- **Mismatch handling** — If KB and code disagree, answer based on code + report the mismatch + suggest KB update
|
|
162
|
+
- **Efficient search** — LLMs use `kb query` for fast single-command KB search
|
|
163
|
+
|
|
164
|
+
## Trust Hierarchy
|
|
165
|
+
|
|
166
|
+
| Folder | Trust level |
|
|
167
|
+
|--------|-------------|
|
|
168
|
+
| `global/` | Highest — org-wide rules |
|
|
169
|
+
| `rules/`, `decisions/` | Team-verified |
|
|
170
|
+
| `analysis/`, `troubleshoot/` | Generally reliable — lightly verify |
|
|
171
|
+
| `drafts/` | Unverified — must verify |
|
|
172
|
+
| `archive/` | Inactive — may be outdated |
|
|
173
|
+
|
|
174
|
+
## Works with Obsidian
|
|
175
|
+
|
|
176
|
+
The KB is a plain folder of markdown files with YAML frontmatter — Obsidian reads it natively as a vault. Tags use `/` separator, which Obsidian renders as a navigable tree in the tag panel. Obsidian CLI (v1.12+) can also be used to search and manage KB notes from the terminal.
|
|
177
|
+
|
|
178
|
+
## License
|
|
179
|
+
|
|
180
|
+
MIT
|
package/dist/index.js
CHANGED
|
@@ -168,9 +168,15 @@ async function initCommand() {
|
|
|
168
168
|
await initRepo(resolvedPath, remoteUrl || void 0);
|
|
169
169
|
log.step("git init" + (remoteUrl ? ` + remote: ${remoteUrl}` : ""));
|
|
170
170
|
const gitHookDest = path2.join(resolvedPath, ".git", "hooks", "pre-commit");
|
|
171
|
-
await fs3.
|
|
172
|
-
|
|
173
|
-
|
|
171
|
+
await fs3.remove(gitHookDest);
|
|
172
|
+
try {
|
|
173
|
+
await fs3.symlink(preCommitDest, gitHookDest);
|
|
174
|
+
log.step("pre-commit hook \uC124\uCE58 (symlink \u2192 .kb/hooks/)");
|
|
175
|
+
} catch {
|
|
176
|
+
await fs3.copy(preCommitDest, gitHookDest);
|
|
177
|
+
await fs3.chmod(gitHookDest, 493);
|
|
178
|
+
log.step("pre-commit hook \uC124\uCE58 (\uBCF5\uC0AC \u2014 symlink \uC2E4\uD328)");
|
|
179
|
+
}
|
|
174
180
|
await saveKbPath(resolvedPath);
|
|
175
181
|
const git = (await import("simple-git")).default(resolvedPath);
|
|
176
182
|
await git.add(".");
|
|
@@ -205,9 +211,15 @@ async function joinCommand(remoteUrl) {
|
|
|
205
211
|
const hookSrc = path3.join(resolvedPath, ".kb", "hooks", "pre-commit");
|
|
206
212
|
const hookDest = path3.join(resolvedPath, ".git", "hooks", "pre-commit");
|
|
207
213
|
if (fs4.existsSync(hookSrc)) {
|
|
208
|
-
await fs4.
|
|
209
|
-
|
|
210
|
-
|
|
214
|
+
await fs4.remove(hookDest);
|
|
215
|
+
try {
|
|
216
|
+
await fs4.symlink(hookSrc, hookDest);
|
|
217
|
+
log.step("pre-commit hook \uC124\uCE58 (symlink \u2192 .kb/hooks/)");
|
|
218
|
+
} catch {
|
|
219
|
+
await fs4.copy(hookSrc, hookDest);
|
|
220
|
+
await fs4.chmod(hookDest, 493);
|
|
221
|
+
log.step("pre-commit hook \uC124\uCE58 (\uBCF5\uC0AC \u2014 symlink \uC2E4\uD328)");
|
|
222
|
+
}
|
|
211
223
|
} else {
|
|
212
224
|
log.warn("pre-commit hook \uC6D0\uBCF8\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 (.kb/hooks/pre-commit)");
|
|
213
225
|
}
|
|
@@ -658,6 +670,213 @@ async function uninstallCommand() {
|
|
|
658
670
|
log.info("npm uninstall -g kb-cli \uB85C CLI \uC790\uCCB4\uB3C4 \uC81C\uAC70\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.");
|
|
659
671
|
}
|
|
660
672
|
|
|
673
|
+
// src/commands/index-cmd.ts
|
|
674
|
+
import fs12 from "fs-extra";
|
|
675
|
+
import path11 from "path";
|
|
676
|
+
import matter from "gray-matter";
|
|
677
|
+
var EXCLUDE_DIRS = [".kb", "templates", "99-personal", "00-inbox", ".github"];
|
|
678
|
+
var EXCLUDE_FILES = ["README.md"];
|
|
679
|
+
function shouldInclude(filePath) {
|
|
680
|
+
for (const dir of EXCLUDE_DIRS) {
|
|
681
|
+
if (filePath.startsWith(`./${dir}/`) || filePath.startsWith(`${dir}/`)) {
|
|
682
|
+
return false;
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
for (const file of EXCLUDE_FILES) {
|
|
686
|
+
if (path11.basename(filePath) === file) return false;
|
|
687
|
+
}
|
|
688
|
+
return filePath.endsWith(".md");
|
|
689
|
+
}
|
|
690
|
+
async function collectMarkdownFiles(dir) {
|
|
691
|
+
const results = [];
|
|
692
|
+
const entries = await fs12.readdir(dir, { withFileTypes: true });
|
|
693
|
+
for (const entry of entries) {
|
|
694
|
+
const rel = path11.relative(dir, path11.join(dir, entry.name));
|
|
695
|
+
if (entry.isDirectory()) {
|
|
696
|
+
if (EXCLUDE_DIRS.includes(entry.name) || entry.name.startsWith(".")) continue;
|
|
697
|
+
const sub = await collectMarkdownFiles(path11.join(dir, entry.name));
|
|
698
|
+
results.push(...sub);
|
|
699
|
+
} else if (entry.isFile() && shouldInclude(`./${rel}`)) {
|
|
700
|
+
results.push(path11.join(dir, entry.name));
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
return results;
|
|
704
|
+
}
|
|
705
|
+
function parseFrontmatter(filePath) {
|
|
706
|
+
try {
|
|
707
|
+
const content = fs12.readFileSync(filePath, "utf-8");
|
|
708
|
+
const { data } = matter(content);
|
|
709
|
+
let tags = [];
|
|
710
|
+
if (Array.isArray(data.tags)) {
|
|
711
|
+
tags = data.tags.map(String);
|
|
712
|
+
} else if (typeof data.tags === "string") {
|
|
713
|
+
tags = data.tags.replace(/^\[|\]$/g, "").split(",").map((t) => t.trim()).filter(Boolean);
|
|
714
|
+
}
|
|
715
|
+
const tldr = typeof data.tldr === "string" ? data.tldr : "";
|
|
716
|
+
const updated = typeof data.updated === "string" ? data.updated : data.updated instanceof Date ? data.updated.toISOString().split("T")[0] : "unknown";
|
|
717
|
+
return { path: "", tags, tldr, updated };
|
|
718
|
+
} catch {
|
|
719
|
+
return null;
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
async function indexCommand(options) {
|
|
723
|
+
const kbPath = getKbPath();
|
|
724
|
+
if (!kbPath) {
|
|
725
|
+
log.error("KB \uACBD\uB85C\uAC00 \uC124\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. kb init \uB610\uB294 kb join\uC744 \uBA3C\uC800 \uC2E4\uD589\uD558\uC138\uC694.");
|
|
726
|
+
process.exit(1);
|
|
727
|
+
}
|
|
728
|
+
if (!fs12.existsSync(kbPath)) {
|
|
729
|
+
log.error(`KB \uB514\uB809\uD1A0\uB9AC\uAC00 \uC874\uC7AC\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: ${kbPath}`);
|
|
730
|
+
process.exit(1);
|
|
731
|
+
}
|
|
732
|
+
const files = await collectMarkdownFiles(kbPath);
|
|
733
|
+
const entries = [];
|
|
734
|
+
let errors = 0;
|
|
735
|
+
for (const filePath of files) {
|
|
736
|
+
const rel = "./" + path11.relative(kbPath, filePath);
|
|
737
|
+
const entry = parseFrontmatter(filePath);
|
|
738
|
+
if (!entry) {
|
|
739
|
+
log.warn(`\uD30C\uC2F1 \uC2E4\uD328: ${rel}`);
|
|
740
|
+
errors++;
|
|
741
|
+
continue;
|
|
742
|
+
}
|
|
743
|
+
if (!entry.tldr) {
|
|
744
|
+
log.warn(`tldr \uD544\uB4DC \uC5C6\uC74C: ${rel}`);
|
|
745
|
+
errors++;
|
|
746
|
+
}
|
|
747
|
+
if (entry.tags.length === 0) {
|
|
748
|
+
log.warn(`tags \uD544\uB4DC \uC5C6\uC74C: ${rel}`);
|
|
749
|
+
errors++;
|
|
750
|
+
}
|
|
751
|
+
entry.path = rel;
|
|
752
|
+
entries.push(entry);
|
|
753
|
+
}
|
|
754
|
+
if (options.check) {
|
|
755
|
+
if (errors > 0) {
|
|
756
|
+
log.error(`\uAC80\uC99D \uC2E4\uD328: ${errors}\uAC1C \uBB38\uC81C \uBC1C\uACAC`);
|
|
757
|
+
process.exit(1);
|
|
758
|
+
}
|
|
759
|
+
log.success(`\uAC80\uC99D \uD1B5\uACFC: ${entries.length}\uAC1C \uB178\uD2B8`);
|
|
760
|
+
return;
|
|
761
|
+
}
|
|
762
|
+
const indexJson = JSON.stringify(entries, null, 2);
|
|
763
|
+
const sharedIndex = path11.join(kbPath, "kb-index.json");
|
|
764
|
+
await fs12.writeFile(sharedIndex, indexJson + "\n", "utf-8");
|
|
765
|
+
const localIndex = path11.join(kbPath, ".kb-index.local.json");
|
|
766
|
+
await fs12.writeFile(localIndex, indexJson + "\n", "utf-8");
|
|
767
|
+
log.success(`\uC778\uB371\uC2A4 \uC0DD\uC131 \uC644\uB8CC: ${entries.length}\uAC1C \uB178\uD2B8`);
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
// src/commands/query.ts
|
|
771
|
+
import fs13 from "fs-extra";
|
|
772
|
+
import path12 from "path";
|
|
773
|
+
import pc2 from "picocolors";
|
|
774
|
+
var TRUST_LEVELS = {
|
|
775
|
+
global: "highest",
|
|
776
|
+
rules: "verified",
|
|
777
|
+
decisions: "verified",
|
|
778
|
+
analysis: "reliable",
|
|
779
|
+
troubleshoot: "reliable",
|
|
780
|
+
drafts: "unverified",
|
|
781
|
+
archive: "inactive"
|
|
782
|
+
};
|
|
783
|
+
function getTrustLevel(notePath) {
|
|
784
|
+
const folder = notePath.replace(/^\.\//, "").split("/")[0];
|
|
785
|
+
return TRUST_LEVELS[folder] || "unknown";
|
|
786
|
+
}
|
|
787
|
+
function scoreEntry(entry, keywords, repo) {
|
|
788
|
+
let score = 0;
|
|
789
|
+
const lowerKeywords = keywords.map((k) => k.toLowerCase());
|
|
790
|
+
for (const kw of lowerKeywords) {
|
|
791
|
+
for (const tag of entry.tags) {
|
|
792
|
+
if (tag.toLowerCase().includes(kw)) score += 10;
|
|
793
|
+
}
|
|
794
|
+
if (entry.tldr.toLowerCase().includes(kw)) score += 5;
|
|
795
|
+
if (entry.path.toLowerCase().includes(kw)) score += 3;
|
|
796
|
+
}
|
|
797
|
+
if (repo) {
|
|
798
|
+
const repoLower = repo.toLowerCase();
|
|
799
|
+
for (const tag of entry.tags) {
|
|
800
|
+
if (tag.toLowerCase().includes(`repo/${repoLower}`)) score += 20;
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
return score;
|
|
804
|
+
}
|
|
805
|
+
function loadIndex(kbPath) {
|
|
806
|
+
const entries = [];
|
|
807
|
+
const sharedPath = path12.join(kbPath, "kb-index.json");
|
|
808
|
+
const localPath = path12.join(kbPath, ".kb-index.local.json");
|
|
809
|
+
for (const indexPath of [sharedPath, localPath]) {
|
|
810
|
+
if (fs13.existsSync(indexPath)) {
|
|
811
|
+
try {
|
|
812
|
+
const data = fs13.readJsonSync(indexPath);
|
|
813
|
+
if (Array.isArray(data)) entries.push(...data);
|
|
814
|
+
} catch {
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
const seen = /* @__PURE__ */ new Set();
|
|
819
|
+
return entries.filter((e) => {
|
|
820
|
+
if (seen.has(e.path)) return false;
|
|
821
|
+
seen.add(e.path);
|
|
822
|
+
return true;
|
|
823
|
+
});
|
|
824
|
+
}
|
|
825
|
+
var DEFAULT_LIMIT = 5;
|
|
826
|
+
var DEFAULT_LINES_PER_NOTE = 30;
|
|
827
|
+
async function queryCommand(keywords, options) {
|
|
828
|
+
const kbPath = getKbPath();
|
|
829
|
+
if (!kbPath) {
|
|
830
|
+
log.error("KB \uACBD\uB85C\uAC00 \uC124\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. kb init \uB610\uB294 kb join\uC744 \uBA3C\uC800 \uC2E4\uD589\uD558\uC138\uC694.");
|
|
831
|
+
process.exit(1);
|
|
832
|
+
}
|
|
833
|
+
const kwList = keywords.split(/\s+/).map((k) => k.trim()).filter(Boolean);
|
|
834
|
+
if (kwList.length === 0) {
|
|
835
|
+
log.error("\uAC80\uC0C9 \uD0A4\uC6CC\uB4DC\uB97C \uC785\uB825\uD558\uC138\uC694.");
|
|
836
|
+
process.exit(1);
|
|
837
|
+
}
|
|
838
|
+
const entries = loadIndex(kbPath);
|
|
839
|
+
if (entries.length === 0) {
|
|
840
|
+
log.warn("\uC778\uB371\uC2A4\uAC00 \uBE44\uC5B4\uC788\uC2B5\uB2C8\uB2E4. kb index\uB97C \uC2E4\uD589\uD558\uC138\uC694.");
|
|
841
|
+
return;
|
|
842
|
+
}
|
|
843
|
+
const scored = entries.map((e) => ({ ...e, score: scoreEntry(e, kwList, options.repo) })).filter((e) => e.score > 0).sort((a, b) => b.score - a.score);
|
|
844
|
+
const limit = options.limit ? parseInt(options.limit, 10) : DEFAULT_LIMIT;
|
|
845
|
+
const top = scored.slice(0, limit);
|
|
846
|
+
if (top.length === 0) {
|
|
847
|
+
console.log("\uAC80\uC0C9 \uACB0\uACFC \uC5C6\uC74C");
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
850
|
+
console.log(`${pc2.blue(`[${scored.length}\uAC1C \uB9E4\uCE6D, \uC0C1\uC704 ${top.length}\uAC1C \uD45C\uC2DC]`)}
|
|
851
|
+
`);
|
|
852
|
+
for (const entry of top) {
|
|
853
|
+
const trust = getTrustLevel(entry.path);
|
|
854
|
+
const header = `${pc2.green("##")} ${entry.path} ${pc2.gray(`[${trust}]`)}`;
|
|
855
|
+
console.log(header);
|
|
856
|
+
console.log(`${pc2.gray("tags:")} ${entry.tags.join(", ")}`);
|
|
857
|
+
console.log(`${pc2.gray("tldr:")} ${entry.tldr}`);
|
|
858
|
+
if (!options.brief) {
|
|
859
|
+
const fullPath = path12.join(kbPath, entry.path.replace(/^\.\//, ""));
|
|
860
|
+
if (fs13.existsSync(fullPath)) {
|
|
861
|
+
const content = fs13.readFileSync(fullPath, "utf-8");
|
|
862
|
+
const body = content.replace(/^---[\s\S]*?---\s*/, "").trim();
|
|
863
|
+
if (body) {
|
|
864
|
+
const lines = body.split("\n");
|
|
865
|
+
const maxLines = options.full ? lines.length : DEFAULT_LINES_PER_NOTE;
|
|
866
|
+
const display = lines.slice(0, maxLines).join("\n");
|
|
867
|
+
console.log();
|
|
868
|
+
console.log(display);
|
|
869
|
+
if (!options.full && lines.length > maxLines) {
|
|
870
|
+
console.log(pc2.gray(`
|
|
871
|
+
... (${lines.length - maxLines}\uC904 \uB354)`));
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
console.log();
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
|
|
661
880
|
// src/index.ts
|
|
662
881
|
var require2 = createRequire(import.meta.url);
|
|
663
882
|
var { version } = require2("../package.json");
|
|
@@ -668,5 +887,7 @@ program.command("join").description("\uAE30\uC874 KB\uC5D0 \uD569\uB958 (\uD300\
|
|
|
668
887
|
program.command("wire").description("\uD504\uB85C\uC81D\uD2B8\uC5D0 LLM \uB3C4\uAD6C \uC5F0\uACB0").argument("<tool>", "claude | gemini | codex").action(wireCommand);
|
|
669
888
|
program.command("doctor").description("KB \uD658\uACBD \uBB34\uACB0\uC131 \uAC80\uC99D").action(doctorCommand);
|
|
670
889
|
program.command("uninstall").description("KB wiring \uC81C\uAC70 + \uC124\uC815 \uC815\uB9AC").action(uninstallCommand);
|
|
890
|
+
program.command("index").description("KB \uC778\uB371\uC2A4 \uC7AC\uC0DD\uC131 (Node.js \uAE30\uBC18)").option("--check", "\uC778\uB371\uC2A4 \uC0DD\uC131 \uC5C6\uC774 frontmatter \uAC80\uC99D\uB9CC \uC218\uD589").action(indexCommand);
|
|
891
|
+
program.command("query").description("KB \uAC80\uC0C9 (\uD0A4\uC6CC\uB4DC OR \uB9E4\uCE6D)").argument("<keywords>", "\uAC80\uC0C9 \uD0A4\uC6CC\uB4DC (\uACF5\uBC31\uC73C\uB85C \uAD6C\uBD84, OR \uB9E4\uCE6D)").option("-l, --limit <n>", "\uACB0\uACFC \uC218 \uC81C\uD55C", "5").option("-b, --brief", "tldr\uB9CC \uD45C\uC2DC").option("-f, --full", "\uB178\uD2B8 \uC804\uCCB4 \uB0B4\uC6A9 \uD45C\uC2DC").option("-r, --repo <name>", "\uD2B9\uC815 repo \uC6B0\uC120 \uC815\uB82C").action(queryCommand);
|
|
671
892
|
program.parse();
|
|
672
893
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/commands/init.ts","../src/utils/log.ts","../src/utils/template.ts","../src/utils/config.ts","../src/utils/git.ts","../src/commands/join.ts","../src/commands/wire.ts","../src/commands/wire-claude.ts","../src/utils/symlink.ts","../src/utils/gitignore.ts","../src/commands/wire-gemini.ts","../src/commands/wire-codex.ts","../src/commands/doctor.ts","../src/commands/uninstall.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { createRequire } from \"node:module\";\nimport { initCommand } from \"./commands/init.js\";\nimport { joinCommand } from \"./commands/join.js\";\nimport { wireCommand } from \"./commands/wire.js\";\nimport { doctorCommand } from \"./commands/doctor.js\";\nimport { uninstallCommand } from \"./commands/uninstall.js\";\n\nconst require = createRequire(import.meta.url);\nconst { version } = require(\"../package.json\");\n\nconst program = new Command();\n\nprogram\n .name(\"kb\")\n .description(\"Team Knowledge Base harness CLI\")\n .version(version);\n\nprogram\n .command(\"init\")\n .description(\"KB 최초 생성 (팀 리드)\")\n .action(initCommand);\n\nprogram\n .command(\"join\")\n .description(\"기존 KB에 합류 (팀원)\")\n .argument(\"<remote-url>\", \"Git remote URL\")\n .action(joinCommand);\n\nprogram\n .command(\"wire\")\n .description(\"프로젝트에 LLM 도구 연결\")\n .argument(\"<tool>\", \"claude | gemini | codex\")\n .action(wireCommand);\n\nprogram\n .command(\"doctor\")\n .description(\"KB 환경 무결성 검증\")\n .action(doctorCommand);\n\nprogram\n .command(\"uninstall\")\n .description(\"KB wiring 제거 + 설정 정리\")\n .action(uninstallCommand);\n\nprogram.parse();\n","import { input } from \"@inquirer/prompts\";\nimport fs from \"fs-extra\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { log } from \"../utils/log.js\";\nimport { renderTemplate } from \"../utils/template.js\";\nimport { saveKbPath } from \"../utils/config.js\";\nimport { initRepo } from \"../utils/git.js\";\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\nconst TEMPLATES_DIR = path.join(__dirname, \"..\", \"templates\", \"kb-structure\");\n\nconst KB_DIRS = [\n \"global\",\n \"rules\",\n \"analysis\",\n \"decisions\",\n \"troubleshoot\",\n \"drafts\",\n \"areas\",\n \"templates\",\n \"ai-context\",\n \"archive\",\n \"00-inbox\",\n \"99-personal\",\n \".kb/hooks\",\n \".kb/scripts\",\n \".kb/setup\",\n \".github/workflows\",\n];\n\nexport async function initCommand(): Promise<void> {\n log.info(\"KB 최초 생성을 시작합니다.\");\n\n const defaultPath = path.join(process.env.HOME || \"~\", \"team-kb\");\n const kbPath = await input({\n message: \"KB 경로\",\n default: defaultPath,\n });\n const resolvedPath = kbPath.startsWith(\"~\")\n ? kbPath.replace(\"~\", process.env.HOME || \"\")\n : path.resolve(kbPath);\n\n if (fs.existsSync(resolvedPath) && fs.readdirSync(resolvedPath).length > 0) {\n log.error(`${resolvedPath} 가 이미 존재하고 비어있지 않습니다.`);\n return;\n }\n\n const remoteUrl = await input({\n message: \"Git remote URL (없으면 엔터)\",\n default: \"\",\n });\n\n const today = new Date().toISOString().split(\"T\")[0];\n const vars = { date: today };\n\n // 1. Create directory structure\n log.info(\"폴더 구조 생성 중...\");\n for (const dir of KB_DIRS) {\n await fs.ensureDir(path.join(resolvedPath, dir));\n }\n log.success(\"폴더 구조 생성 완료\");\n\n // 2. Copy .gitignore\n const gitignoreSrc = path.join(TEMPLATES_DIR, \"gitignore\");\n await fs.copy(gitignoreSrc, path.join(resolvedPath, \".gitignore\"));\n log.step(\".gitignore 생성\");\n\n // 3. Copy and render note templates\n const noteTemplatesDir = path.join(TEMPLATES_DIR, \"note-templates\");\n const noteTemplates = await fs.readdir(noteTemplatesDir);\n for (const file of noteTemplates) {\n const content = await fs.readFile(path.join(noteTemplatesDir, file), \"utf-8\");\n const rendered = renderTemplate(content, vars);\n await fs.writeFile(path.join(resolvedPath, \"templates\", file), rendered);\n }\n log.step(\"노트 템플릿 생성\");\n\n // 4. Copy pre-commit hook\n const preCommitSrc = path.join(TEMPLATES_DIR, \"pre-commit\");\n const preCommitDest = path.join(resolvedPath, \".kb\", \"hooks\", \"pre-commit\");\n await fs.copy(preCommitSrc, preCommitDest);\n await fs.chmod(preCommitDest, 0o755);\n log.step(\"pre-commit hook 생성\");\n\n // 5. Copy rebuild-index.sh\n const rebuildSrc = path.join(TEMPLATES_DIR, \"rebuild-index.sh\");\n const rebuildDest = path.join(resolvedPath, \".kb\", \"scripts\", \"rebuild-index.sh\");\n await fs.copy(rebuildSrc, rebuildDest);\n await fs.chmod(rebuildDest, 0o755);\n log.step(\"rebuild-index.sh 생성\");\n\n // 6. Copy GitHub Actions workflows\n const healthSrc = path.join(TEMPLATES_DIR, \"kb-health.yml\");\n const coverageSrc = path.join(TEMPLATES_DIR, \"kb-coverage.yml\");\n await fs.copy(healthSrc, path.join(resolvedPath, \".github\", \"workflows\", \"kb-health.yml\"));\n await fs.copy(coverageSrc, path.join(resolvedPath, \".github\", \"workflows\", \"kb-coverage.yml\"));\n log.step(\"GitHub Actions 워크플로우 생성\");\n\n // 7. Create kb-index.json (empty)\n await fs.writeJson(path.join(resolvedPath, \"kb-index.json\"), []);\n log.step(\"kb-index.json 초기화 (빈 배열)\");\n\n // 8. Create ai-context files\n const kbRulesSrc = path.join(TEMPLATES_DIR, \"kb-rules.md\");\n const kbRulesContent = await fs.readFile(kbRulesSrc, \"utf-8\");\n await fs.writeFile(\n path.join(resolvedPath, \"ai-context\", \"kb-rules.md\"),\n renderTemplate(kbRulesContent, vars),\n );\n\n const teamFocusSrc = path.join(TEMPLATES_DIR, \"team-focus.md\");\n const teamFocusContent = await fs.readFile(teamFocusSrc, \"utf-8\");\n await fs.writeFile(\n path.join(resolvedPath, \"ai-context\", \"team-focus.md\"),\n renderTemplate(teamFocusContent, vars),\n );\n log.step(\"ai-context/ 파일 생성 (kb-rules.md, team-focus.md)\");\n\n // 9. Git init + remote\n await initRepo(resolvedPath, remoteUrl || undefined);\n log.step(\"git init\" + (remoteUrl ? ` + remote: ${remoteUrl}` : \"\"));\n\n // 10. Install pre-commit hook\n const gitHookDest = path.join(resolvedPath, \".git\", \"hooks\", \"pre-commit\");\n await fs.copy(preCommitDest, gitHookDest);\n await fs.chmod(gitHookDest, 0o755);\n log.step(\"pre-commit hook 설치 (.git/hooks/)\");\n\n // 11. Save config\n await saveKbPath(resolvedPath);\n\n // 12. Initial commit\n const git = (await import(\"simple-git\")).default(resolvedPath);\n await git.add(\".\");\n await git.commit(\"init: KB 구조 생성\");\n log.step(\"초기 커밋 완료\");\n\n log.success(`KB 생성 완료: ${resolvedPath}`);\n log.info(\"다음 단계:\");\n log.step(\"ai-context/ 오버뷰 초안 작성\");\n log.step(\"git push\");\n log.step(\"팀원에게 kb join 안내\");\n}\n","import pc from \"picocolors\";\n\nexport const log = {\n info: (msg: string) => console.log(pc.blue(\"ℹ\") + \" \" + msg),\n success: (msg: string) => console.log(pc.green(\"✔\") + \" \" + msg),\n warn: (msg: string) => console.log(pc.yellow(\"⚠\") + \" \" + msg),\n error: (msg: string) => console.error(pc.red(\"✖\") + \" \" + msg),\n step: (msg: string) => console.log(pc.gray(\" →\") + \" \" + msg),\n};\n","/**\n * Simple template variable replacement.\n * Replaces {{VAR_NAME}} with provided values.\n */\nexport function renderTemplate(\n template: string,\n vars: Record<string, string>,\n): string {\n let result = template;\n for (const [key, value] of Object.entries(vars)) {\n result = result.replaceAll(`{{${key}}}`, value);\n }\n return result;\n}\n","import fs from \"fs-extra\";\nimport path from \"node:path\";\nimport { log } from \"./log.js\";\n\nconst CONFIG_DIR = path.join(\n process.env.HOME || \"~\",\n \".config\",\n \"kb-cli\",\n);\nconst CONFIG_PATH = path.join(CONFIG_DIR, \"config.json\");\n\ninterface KbConfig {\n kbPath: string;\n}\n\n/**\n * Read KB path from config file.\n */\nexport function getKbPath(): string | undefined {\n try {\n if (fs.existsSync(CONFIG_PATH)) {\n const config: KbConfig = fs.readJsonSync(CONFIG_PATH);\n return config.kbPath;\n }\n } catch {\n // ignore parse errors\n }\n return undefined;\n}\n\n/**\n * Save KB path to config file.\n */\nexport async function saveKbPath(kbPath: string): Promise<void> {\n await fs.ensureDir(CONFIG_DIR);\n await fs.writeJson(CONFIG_PATH, { kbPath }, { spaces: 2 });\n log.step(`설정 저장: ${CONFIG_PATH}`);\n}\n\n/**\n * Remove config file.\n */\nexport async function removeConfig(): Promise<boolean> {\n if (fs.existsSync(CONFIG_PATH)) {\n await fs.remove(CONFIG_PATH);\n return true;\n }\n return false;\n}\n\nexport { CONFIG_PATH };\n","import simpleGit, { type SimpleGit } from \"simple-git\";\nimport fs from \"fs-extra\";\n\nexport function getGit(cwd?: string): SimpleGit {\n return simpleGit(cwd);\n}\n\nexport async function isGitRepo(dir: string): Promise<boolean> {\n try {\n const git = getGit(dir);\n return await git.checkIsRepo();\n } catch {\n return false;\n }\n}\n\nexport async function initRepo(\n dir: string,\n remote?: string,\n): Promise<void> {\n const git = getGit(dir);\n await git.init();\n if (remote) {\n await git.addRemote(\"origin\", remote);\n }\n}\n\nexport async function cloneRepo(\n url: string,\n dir: string,\n): Promise<void> {\n await fs.ensureDir(dir);\n const git = simpleGit();\n await git.clone(url, dir);\n}\n","import { input } from \"@inquirer/prompts\";\nimport fs from \"fs-extra\";\nimport path from \"node:path\";\nimport { log } from \"../utils/log.js\";\nimport { saveKbPath } from \"../utils/config.js\";\nimport { cloneRepo } from \"../utils/git.js\";\n\nexport async function joinCommand(remoteUrl: string): Promise<void> {\n log.info(\"기존 KB에 합류합니다.\");\n\n const defaultPath = path.join(process.env.HOME || \"~\", \"team-kb\");\n const kbPath = await input({\n message: \"로컬 경로\",\n default: defaultPath,\n });\n const resolvedPath = kbPath.startsWith(\"~\")\n ? kbPath.replace(\"~\", process.env.HOME || \"\")\n : path.resolve(kbPath);\n\n if (fs.existsSync(resolvedPath) && fs.readdirSync(resolvedPath).length > 0) {\n log.error(`${resolvedPath} 가 이미 존재하고 비어있지 않습니다.`);\n return;\n }\n\n // 1. Clone\n log.info(\"git clone 중...\");\n await cloneRepo(remoteUrl, resolvedPath);\n log.success(\"clone 완료\");\n\n // 2. Install pre-commit hook\n const hookSrc = path.join(resolvedPath, \".kb\", \"hooks\", \"pre-commit\");\n const hookDest = path.join(resolvedPath, \".git\", \"hooks\", \"pre-commit\");\n if (fs.existsSync(hookSrc)) {\n await fs.copy(hookSrc, hookDest);\n await fs.chmod(hookDest, 0o755);\n log.step(\"pre-commit hook 설치\");\n } else {\n log.warn(\"pre-commit hook 원본이 없습니다 (.kb/hooks/pre-commit)\");\n }\n\n // 3. Save config\n await saveKbPath(resolvedPath);\n\n log.success(`KB 합류 완료: ${resolvedPath}`);\n log.info(\"다음 단계:\");\n log.step(\"cd ~/repos/{project} && kb wire claude (또는 gemini / codex)\");\n}\n","import { input } from \"@inquirer/prompts\";\nimport { log } from \"../utils/log.js\";\nimport { getKbPath } from \"../utils/config.js\";\nimport { wireClaude } from \"./wire-claude.js\";\nimport { wireGemini } from \"./wire-gemini.js\";\nimport { wireCodex } from \"./wire-codex.js\";\n\nexport interface WireContext {\n /** Absolute path to the KB repo */\n kbPath: string;\n /** Current project root (cwd) */\n projectRoot: string;\n /** Current repo name (e.g., \"coupon-api\") */\n repoName: string;\n}\n\nasync function collectWireContext(): Promise<WireContext | null> {\n // Resolve KB path\n let kbPath = getKbPath();\n if (!kbPath) {\n kbPath = await input({\n message: \"KB 경로를 찾을 수 없습니다. KB 절대 경로를 입력하세요\",\n });\n }\n\n if (!kbPath) {\n log.error(\"KB 경로가 필요합니다. kb init 또는 kb join을 먼저 실행하세요.\");\n return null;\n }\n\n const projectRoot = process.cwd();\n const repoName =\n projectRoot.split(\"/\").pop() || \"unknown\";\n\n return { kbPath, projectRoot, repoName };\n}\n\nexport async function wireCommand(tool: string): Promise<void> {\n const validTools = [\"claude\", \"gemini\", \"codex\"];\n if (!validTools.includes(tool)) {\n log.error(`지원하지 않는 도구: ${tool}. (claude, gemini, codex 중 선택)`);\n return;\n }\n\n log.info(`프로젝트에 ${tool} 연결을 시작합니다.`);\n\n const ctx = await collectWireContext();\n if (!ctx) return;\n\n switch (tool) {\n case \"claude\":\n await wireClaude(ctx);\n break;\n case \"gemini\":\n await wireGemini(ctx);\n break;\n case \"codex\":\n await wireCodex(ctx);\n break;\n }\n}\n","import fs from \"fs-extra\";\nimport path from \"node:path\";\nimport { log } from \"../utils/log.js\";\nimport { createSymlink } from \"../utils/symlink.js\";\nimport { ensureGitignorePatterns } from \"../utils/gitignore.js\";\nimport type { WireContext } from \"./wire.js\";\n\nfunction buildKbLocationContent(ctx: WireContext): string {\n return `## KB 절대 경로\nLLM은 파일 접근 및 쉘 스크립트 실행 시 반드시 아래의 절대 경로를 그대로 사용할 것.\n- KB 루트: ${ctx.kbPath}\n- 전체 인덱스: ${ctx.kbPath}/kb-index.json\n- 로컬 인덱스: ${ctx.kbPath}/.kb-index.local.json\n- 로컬 인덱스 재생성 스크립트: ${ctx.kbPath}/.kb/scripts/rebuild-index.sh\n`;\n}\n\nexport async function wireClaude(ctx: WireContext): Promise<void> {\n const rulesDir = path.join(ctx.projectRoot, \".claude\", \"rules\");\n await fs.ensureDir(rulesDir);\n\n // 1. Symlinks to KB ai-context files\n const aiContextDir = path.join(ctx.kbPath, \"ai-context\");\n const symlinkTargets = [\n { name: \"kb-rules.md\", target: path.join(aiContextDir, \"kb-rules.md\") },\n { name: \"team-focus.md\", target: path.join(aiContextDir, \"team-focus.md\") },\n ];\n\n // Also symlink any *-overview.md files\n if (fs.existsSync(aiContextDir)) {\n const files = await fs.readdir(aiContextDir);\n for (const file of files) {\n if (file.endsWith(\"-overview.md\")) {\n symlinkTargets.push({\n name: file,\n target: path.join(aiContextDir, file),\n });\n }\n }\n }\n\n for (const { name, target } of symlinkTargets) {\n await createSymlink(target, path.join(rulesDir, name));\n }\n\n // 3. kb-location.md — explicit paths (local-only)\n const locationPath = path.join(rulesDir, \"kb-location.md\");\n await fs.writeFile(locationPath, buildKbLocationContent(ctx));\n log.step(\"kb-location.md 생성 (KB 절대 경로)\");\n\n // 3. .claude/settings.json\n const settingsPath = path.join(ctx.projectRoot, \".claude\", \"settings.json\");\n if (!fs.existsSync(settingsPath)) {\n await fs.writeJson(settingsPath, {}, { spaces: 2 });\n log.step(\".claude/settings.json 생성\");\n }\n\n // 4. Update .gitignore\n await ensureGitignorePatterns(ctx.projectRoot, [\n \".claude/rules/\",\n ]);\n\n log.success(\"Claude Code 연결 완료\");\n}\n","import fs from \"fs-extra\";\nimport path from \"node:path\";\nimport { log } from \"./log.js\";\n\n/**\n * Create a symlink. If target doesn't exist, warn but still create.\n */\nexport async function createSymlink(\n target: string,\n linkPath: string,\n): Promise<void> {\n await fs.ensureDir(path.dirname(linkPath));\n\n if (fs.existsSync(linkPath)) {\n const stat = await fs.lstat(linkPath);\n if (stat.isSymbolicLink()) {\n const existing = await fs.readlink(linkPath);\n if (existing === target) {\n log.step(`symlink 이미 존재: ${path.basename(linkPath)}`);\n return;\n }\n await fs.remove(linkPath);\n } else {\n log.warn(`${linkPath} 이 일반 파일로 존재. symlink로 교체합니다.`);\n await fs.remove(linkPath);\n }\n }\n\n if (!fs.existsSync(target)) {\n log.warn(`symlink 대상 파일 없음: ${target} (나중에 생성 필요)`);\n }\n\n await fs.symlink(target, linkPath);\n log.step(`symlink 생성: ${path.basename(linkPath)} → ${target}`);\n}\n","import fs from \"fs-extra\";\nimport path from \"node:path\";\nimport { log } from \"./log.js\";\n\n/**\n * Ensure patterns exist in a .gitignore file.\n * Creates the file if it doesn't exist. Skips patterns already present.\n */\nexport async function ensureGitignorePatterns(\n dir: string,\n patterns: string[],\n): Promise<void> {\n const gitignorePath = path.join(dir, \".gitignore\");\n\n let content = \"\";\n if (fs.existsSync(gitignorePath)) {\n content = await fs.readFile(gitignorePath, \"utf-8\");\n }\n\n const lines = content.split(\"\\n\");\n const toAdd: string[] = [];\n\n for (const pattern of patterns) {\n const trimmed = pattern.trim();\n if (!lines.some((line) => line.trim() === trimmed)) {\n toAdd.push(trimmed);\n }\n }\n\n if (toAdd.length === 0) {\n return;\n }\n\n const separator = content.length > 0 && !content.endsWith(\"\\n\") ? \"\\n\" : \"\";\n const section =\n separator +\n \"\\n# KB wiring (local-only)\\n\" +\n toAdd.join(\"\\n\") +\n \"\\n\";\n\n await fs.appendFile(gitignorePath, section);\n log.step(`.gitignore에 ${toAdd.length}개 패턴 추가`);\n}\n","import fs from \"fs-extra\";\nimport path from \"node:path\";\nimport { log } from \"../utils/log.js\";\nimport { createSymlink } from \"../utils/symlink.js\";\nimport { ensureGitignorePatterns } from \"../utils/gitignore.js\";\nimport type { WireContext } from \"./wire.js\";\n\nfunction buildGeminiMd(): string {\n return \"도메인 지식 질문은 코드 탐색 전에 반드시 KB를 먼저 확인할 것.\\n\\n@.gemini/kb-import.md\\n\";\n}\n\nfunction buildKbImportMd(ctx: WireContext): string {\n let content = `## KB 절대 경로\nLLM은 파일 접근 및 쉘 스크립트 실행 시 반드시 아래의 절대 경로를 그대로 사용할 것.\n- KB 루트: ${ctx.kbPath}\n- 전체 인덱스: ${ctx.kbPath}/kb-index.json\n- 로컬 인덱스: ${ctx.kbPath}/.kb-index.local.json\n- 로컬 인덱스 재생성 스크립트: ${ctx.kbPath}/.kb/scripts/rebuild-index.sh\n\n`;\n\n // @import via symlink (relative to this file's location)\n content += \"@kb-context/kb-rules.md\\n\";\n content += \"@kb-context/team-focus.md\\n\";\n\n // Also import any *-overview.md files\n const aiContext = path.join(ctx.kbPath, \"ai-context\");\n if (fs.existsSync(aiContext)) {\n const files = fs.readdirSync(aiContext);\n for (const file of files) {\n if (file.endsWith(\"-overview.md\")) {\n content += `@kb-context/${file}\\n`;\n }\n }\n }\n\n return content;\n}\n\nexport async function wireGemini(ctx: WireContext): Promise<void> {\n const geminiDir = path.join(ctx.projectRoot, \".gemini\");\n await fs.ensureDir(geminiDir);\n\n // 1. GEMINI.md (tracked — @import only)\n const geminiMdPath = path.join(ctx.projectRoot, \"GEMINI.md\");\n const importLine = buildGeminiMd();\n if (fs.existsSync(geminiMdPath)) {\n const existing = await fs.readFile(geminiMdPath, \"utf-8\");\n if (!existing.includes(\"@.gemini/kb-import.md\")) {\n const updated = importLine + \"\\n\" + existing;\n await fs.writeFile(geminiMdPath, updated);\n log.step(\"GEMINI.md에 KB @import 추가\");\n } else {\n log.step(\"GEMINI.md에 KB @import 이미 존재 — 스킵\");\n }\n } else {\n await fs.writeFile(geminiMdPath, importLine);\n log.step(\"GEMINI.md 생성\");\n }\n\n // 2. .gemini/kb-context symlink → KB ai-context/\n const aiContextDir = path.join(ctx.kbPath, \"ai-context\");\n const kbContextLink = path.join(geminiDir, \"kb-context\");\n await createSymlink(aiContextDir, kbContextLink);\n\n // 3. .gemini/kb-import.md (local-only — paths + @import via symlink)\n const importPath = path.join(geminiDir, \"kb-import.md\");\n await fs.writeFile(importPath, buildKbImportMd(ctx));\n log.step(\".gemini/kb-import.md 생성 (KB 경로 + @import)\");\n\n // 4. .gemini/settings.json\n const settingsPath = path.join(geminiDir, \"settings.json\");\n if (!fs.existsSync(settingsPath)) {\n await fs.writeJson(settingsPath, {}, { spaces: 2 });\n log.step(\".gemini/settings.json 생성\");\n }\n\n // 5. Update .gitignore\n await ensureGitignorePatterns(ctx.projectRoot, [\n \".gemini/kb-import.md\",\n \".gemini/kb-context\",\n ]);\n\n log.success(\"Gemini CLI 연결 완료\");\n}\n","import fs from \"fs-extra\";\nimport path from \"node:path\";\nimport { log } from \"../utils/log.js\";\nimport { ensureGitignorePatterns } from \"../utils/gitignore.js\";\nimport type { WireContext } from \"./wire.js\";\n\nfunction buildAgentsMd(): string {\n return \"# Knowledge Base\\n- 도메인 지식 질문은 코드 탐색 전에 반드시 KB를 먼저 확인할 것\\n- 세션 시작 시 반드시 .codex/kb-directive.md 파일을 먼저 읽고 그 안의 경로 지시를 따를 것\\n\";\n}\n\nfunction buildDirectiveMd(ctx: WireContext): string {\n const aiContext = path.join(ctx.kbPath, \"ai-context\");\n\n return `## KB 작동 지시\n- 세션 시작 시 반드시 ${aiContext}/kb-rules.md 를 먼저 읽을 것\n\n## KB 절대 경로\nLLM은 파일 접근 및 쉘 스크립트 실행 시 반드시 아래의 절대 경로를 그대로 사용할 것.\n- KB 루트: ${ctx.kbPath}\n- 전체 인덱스: ${ctx.kbPath}/kb-index.json\n- 로컬 인덱스: ${ctx.kbPath}/.kb-index.local.json\n- 로컬 인덱스 재생성 스크립트: ${ctx.kbPath}/.kb/scripts/rebuild-index.sh\n`;\n}\n\nexport async function wireCodex(ctx: WireContext): Promise<void> {\n const codexDir = path.join(ctx.projectRoot, \".codex\");\n await fs.ensureDir(codexDir);\n\n // 1. AGENTS.md (tracked — KB directive reference only)\n const agentsMdPath = path.join(ctx.projectRoot, \"AGENTS.md\");\n const kbDirective = buildAgentsMd();\n if (fs.existsSync(agentsMdPath)) {\n const existing = await fs.readFile(agentsMdPath, \"utf-8\");\n if (!existing.includes(\"# Knowledge Base\")) {\n await fs.appendFile(agentsMdPath, \"\\n\" + kbDirective);\n log.step(\"AGENTS.md에 KB 지시문 추가\");\n } else {\n log.step(\"AGENTS.md에 KB 지시문 이미 존재 — 스킵\");\n }\n } else {\n await fs.writeFile(agentsMdPath, kbDirective);\n log.step(\"AGENTS.md 생성\");\n }\n\n // 2. .codex/kb-directive.md (local-only — absolute paths)\n const directivePath = path.join(codexDir, \"kb-directive.md\");\n await fs.writeFile(directivePath, buildDirectiveMd(ctx));\n log.step(\".codex/kb-directive.md 생성 (KB 경로 + 지시)\");\n\n // 3. Update .gitignore\n await ensureGitignorePatterns(ctx.projectRoot, [\n \".codex/kb-directive.md\",\n ]);\n\n log.success(\"Codex CLI 연결 완료\");\n}\n","import fs from \"fs-extra\";\nimport path from \"node:path\";\nimport { log } from \"../utils/log.js\";\nimport { getKbPath, CONFIG_PATH } from \"../utils/config.js\";\n\ninterface CheckResult {\n name: string;\n ok: boolean;\n detail: string;\n}\n\nexport async function doctorCommand(): Promise<void> {\n log.info(\"KB 환경 진단을 시작합니다.\\n\");\n const results: CheckResult[] = [];\n\n // 1. KB config\n const kbPath = getKbPath();\n results.push({\n name: `설정 파일 (${CONFIG_PATH})`,\n ok: !!kbPath,\n detail: kbPath || \"미설정. kb init 또는 kb join을 먼저 실행하세요.\",\n });\n\n if (!kbPath) {\n printResults(results);\n return;\n }\n\n // 2. KB directory exists and is accessible\n const kbExists = fs.existsSync(kbPath);\n results.push({\n name: \"KB 디렉토리 접근\",\n ok: kbExists,\n detail: kbExists ? kbPath : `${kbPath} 경로가 존재하지 않습니다.`,\n });\n\n if (!kbExists) {\n printResults(results);\n return;\n }\n\n // 3. ai-context/kb-rules.md exists\n const kbRulesPath = path.join(kbPath, \"ai-context\", \"kb-rules.md\");\n const kbRulesExists = fs.existsSync(kbRulesPath);\n results.push({\n name: \"ai-context/kb-rules.md\",\n ok: kbRulesExists,\n detail: kbRulesExists ? \"존재\" : \"없음. ai-context/ 초기 파일을 작성하세요.\",\n });\n\n // 4. kb-index.json exists\n const indexPath = path.join(kbPath, \"kb-index.json\");\n const indexExists = fs.existsSync(indexPath);\n results.push({\n name: \"kb-index.json\",\n ok: indexExists,\n detail: indexExists ? \"존재\" : \"없음. git push 후 CI가 생성합니다.\",\n });\n\n // 5. pre-commit hook installed\n const hookPath = path.join(kbPath, \".git\", \"hooks\", \"pre-commit\");\n const hookExists = fs.existsSync(hookPath);\n results.push({\n name: \"pre-commit hook\",\n ok: hookExists,\n detail: hookExists ? \"설치됨\" : \"미설치. kb join을 다시 실행하세요.\",\n });\n\n // 6. Check project wiring (if in a project directory)\n const cwd = process.cwd();\n if (cwd !== kbPath) {\n // Claude\n const claudeRulesDir = path.join(cwd, \".claude\", \"rules\");\n if (fs.existsSync(claudeRulesDir)) {\n const kbRulesLink = path.join(claudeRulesDir, \"kb-rules.md\");\n if (fs.existsSync(kbRulesLink)) {\n const stat = await fs.lstat(kbRulesLink);\n if (stat.isSymbolicLink()) {\n const target = await fs.readlink(kbRulesLink);\n const targetValid = fs.existsSync(target);\n results.push({\n name: \"Claude symlink (kb-rules.md)\",\n ok: targetValid,\n detail: targetValid ? `→ ${target}` : `깨진 symlink → ${target}`,\n });\n }\n }\n\n const locationFile = path.join(claudeRulesDir, \"kb-location.md\");\n results.push({\n name: \"Claude kb-location.md\",\n ok: fs.existsSync(locationFile),\n detail: fs.existsSync(locationFile) ? \"존재\" : \"없음. kb wire claude를 실행하세요.\",\n });\n }\n\n // Gemini\n const geminiImport = path.join(cwd, \".gemini\", \"kb-import.md\");\n if (fs.existsSync(path.join(cwd, \"GEMINI.md\"))) {\n results.push({\n name: \"Gemini kb-import.md\",\n ok: fs.existsSync(geminiImport),\n detail: fs.existsSync(geminiImport) ? \"존재\" : \"없음. kb wire gemini를 실행하세요.\",\n });\n }\n\n // Codex\n const codexDirective = path.join(cwd, \".codex\", \"kb-directive.md\");\n if (fs.existsSync(path.join(cwd, \"AGENTS.md\"))) {\n results.push({\n name: \"Codex kb-directive.md\",\n ok: fs.existsSync(codexDirective),\n detail: fs.existsSync(codexDirective) ? \"존재\" : \"없음. kb wire codex를 실행하세요.\",\n });\n }\n }\n\n printResults(results);\n}\n\nfunction printResults(results: CheckResult[]): void {\n let allOk = true;\n for (const r of results) {\n if (r.ok) {\n log.success(`${r.name}: ${r.detail}`);\n } else {\n log.error(`${r.name}: ${r.detail}`);\n allOk = false;\n }\n }\n\n console.log();\n if (allOk) {\n log.success(\"모든 검증 통과\");\n } else {\n log.warn(\"일부 항목에 문제가 있습니다. 위 메시지를 확인하세요.\");\n }\n}\n","import { confirm } from \"@inquirer/prompts\";\nimport fs from \"fs-extra\";\nimport path from \"node:path\";\nimport { log } from \"../utils/log.js\";\nimport { getKbPath, removeConfig, CONFIG_PATH } from \"../utils/config.js\";\n\nexport async function uninstallCommand(): Promise<void> {\n log.info(\"KB wiring 제거를 시작합니다.\\n\");\n\n const cwd = process.cwd();\n let removed = 0;\n\n // 1. Remove Claude wiring (local-only files only)\n const claudeRulesDir = path.join(cwd, \".claude\", \"rules\");\n if (fs.existsSync(claudeRulesDir)) {\n // Remove symlinks (KB-related only)\n const files = await fs.readdir(claudeRulesDir);\n for (const file of files) {\n const filePath = path.join(claudeRulesDir, file);\n const stat = await fs.lstat(filePath);\n if (stat.isSymbolicLink()) {\n await fs.remove(filePath);\n log.step(`symlink 삭제: .claude/rules/${file}`);\n removed++;\n }\n }\n\n // Remove kb-location.md\n const locationPath = path.join(claudeRulesDir, \"kb-location.md\");\n if (fs.existsSync(locationPath)) {\n await fs.remove(locationPath);\n log.step(\"삭제: .claude/rules/kb-location.md\");\n removed++;\n }\n }\n\n // 2. Remove Gemini wiring (local-only file only)\n const geminiImport = path.join(cwd, \".gemini\", \"kb-import.md\");\n if (fs.existsSync(geminiImport)) {\n await fs.remove(geminiImport);\n log.step(\"삭제: .gemini/kb-import.md\");\n removed++;\n }\n\n // 3. Remove Codex wiring (local-only file only)\n const codexDirective = path.join(cwd, \".codex\", \"kb-directive.md\");\n if (fs.existsSync(codexDirective)) {\n await fs.remove(codexDirective);\n log.step(\"삭제: .codex/kb-directive.md\");\n removed++;\n }\n\n if (removed > 0) {\n log.success(`프로젝트 wiring ${removed}개 파일 제거 완료`);\n } else {\n log.info(\"현재 디렉토리에 제거할 wiring 파일이 없습니다.\");\n }\n\n // 4. Tracked files (CLAUDE.md, GEMINI.md, AGENTS.md) — don't touch\n const trackedFiles = [\"CLAUDE.md\", \"GEMINI.md\", \"AGENTS.md\"].filter(\n (f) => fs.existsSync(path.join(cwd, f)),\n );\n if (trackedFiles.length > 0) {\n log.warn(\n `${trackedFiles.join(\", \")}의 프로젝트 섹션은 수동으로 정리하세요 (사용자 내용과 섞여있을 수 있음).`,\n );\n }\n\n // 5. Remove config file\n const kbPath = getKbPath();\n const shouldRemoveConfig = await confirm({\n message: `설정 파일을 삭제할까요? (${CONFIG_PATH})`,\n default: true,\n });\n\n if (shouldRemoveConfig) {\n const didRemove = await removeConfig();\n if (didRemove) {\n log.step(\"설정 파일 삭제 완료\");\n }\n }\n\n // 6. KB directory — ask but warn\n if (kbPath && fs.existsSync(kbPath)) {\n const shouldRemoveKb = await confirm({\n message: `KB 디렉토리를 삭제할까요? (${kbPath}) — 팀 지식이 모두 삭제됩니다!`,\n default: false,\n });\n\n if (shouldRemoveKb) {\n await fs.remove(kbPath);\n log.step(`KB 디렉토리 삭제: ${kbPath}`);\n } else {\n log.info(`KB 디렉토리 유지: ${kbPath}`);\n }\n }\n\n console.log();\n log.success(\"uninstall 완료\");\n log.info(\"npm uninstall -g kb-cli 로 CLI 자체도 제거할 수 있습니다.\");\n}\n"],"mappings":";;;AAAA,SAAS,eAAe;AACxB,SAAS,qBAAqB;;;ACD9B,SAAS,aAAa;AACtB,OAAOA,SAAQ;AACf,OAAOC,WAAU;AACjB,SAAS,qBAAqB;;;ACH9B,OAAO,QAAQ;AAER,IAAM,MAAM;AAAA,EACjB,MAAM,CAAC,QAAgB,QAAQ,IAAI,GAAG,KAAK,QAAG,IAAI,MAAM,GAAG;AAAA,EAC3D,SAAS,CAAC,QAAgB,QAAQ,IAAI,GAAG,MAAM,QAAG,IAAI,MAAM,GAAG;AAAA,EAC/D,MAAM,CAAC,QAAgB,QAAQ,IAAI,GAAG,OAAO,QAAG,IAAI,MAAM,GAAG;AAAA,EAC7D,OAAO,CAAC,QAAgB,QAAQ,MAAM,GAAG,IAAI,QAAG,IAAI,MAAM,GAAG;AAAA,EAC7D,MAAM,CAAC,QAAgB,QAAQ,IAAI,GAAG,KAAK,UAAK,IAAI,MAAM,GAAG;AAC/D;;;ACJO,SAAS,eACd,UACA,MACQ;AACR,MAAI,SAAS;AACb,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,IAAI,GAAG;AAC/C,aAAS,OAAO,WAAW,KAAK,GAAG,MAAM,KAAK;AAAA,EAChD;AACA,SAAO;AACT;;;ACbA,OAAO,QAAQ;AACf,OAAO,UAAU;AAGjB,IAAM,aAAa,KAAK;AAAA,EACtB,QAAQ,IAAI,QAAQ;AAAA,EACpB;AAAA,EACA;AACF;AACA,IAAM,cAAc,KAAK,KAAK,YAAY,aAAa;AAShD,SAAS,YAAgC;AAC9C,MAAI;AACF,QAAI,GAAG,WAAW,WAAW,GAAG;AAC9B,YAAM,SAAmB,GAAG,aAAa,WAAW;AACpD,aAAO,OAAO;AAAA,IAChB;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAKA,eAAsB,WAAW,QAA+B;AAC9D,QAAM,GAAG,UAAU,UAAU;AAC7B,QAAM,GAAG,UAAU,aAAa,EAAE,OAAO,GAAG,EAAE,QAAQ,EAAE,CAAC;AACzD,MAAI,KAAK,8BAAU,WAAW,EAAE;AAClC;AAKA,eAAsB,eAAiC;AACrD,MAAI,GAAG,WAAW,WAAW,GAAG;AAC9B,UAAM,GAAG,OAAO,WAAW;AAC3B,WAAO;AAAA,EACT;AACA,SAAO;AACT;;;AChDA,OAAO,eAAmC;AAC1C,OAAOC,SAAQ;AAER,SAAS,OAAO,KAAyB;AAC9C,SAAO,UAAU,GAAG;AACtB;AAWA,eAAsB,SACpB,KACA,QACe;AACf,QAAM,MAAM,OAAO,GAAG;AACtB,QAAM,IAAI,KAAK;AACf,MAAI,QAAQ;AACV,UAAM,IAAI,UAAU,UAAU,MAAM;AAAA,EACtC;AACF;AAEA,eAAsB,UACpB,KACA,KACe;AACf,QAAMC,IAAG,UAAU,GAAG;AACtB,QAAM,MAAM,UAAU;AACtB,QAAM,IAAI,MAAM,KAAK,GAAG;AAC1B;;;AJzBA,IAAM,YAAYC,MAAK,QAAQ,cAAc,YAAY,GAAG,CAAC;AAC7D,IAAM,gBAAgBA,MAAK,KAAK,WAAW,MAAM,aAAa,cAAc;AAE5E,IAAM,UAAU;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,eAAsB,cAA6B;AACjD,MAAI,KAAK,oEAAkB;AAE3B,QAAM,cAAcA,MAAK,KAAK,QAAQ,IAAI,QAAQ,KAAK,SAAS;AAChE,QAAM,SAAS,MAAM,MAAM;AAAA,IACzB,SAAS;AAAA,IACT,SAAS;AAAA,EACX,CAAC;AACD,QAAM,eAAe,OAAO,WAAW,GAAG,IACtC,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,EAAE,IAC1CA,MAAK,QAAQ,MAAM;AAEvB,MAAIC,IAAG,WAAW,YAAY,KAAKA,IAAG,YAAY,YAAY,EAAE,SAAS,GAAG;AAC1E,QAAI,MAAM,GAAG,YAAY,kGAAuB;AAChD;AAAA,EACF;AAEA,QAAM,YAAY,MAAM,MAAM;AAAA,IAC5B,SAAS;AAAA,IACT,SAAS;AAAA,EACX,CAAC;AAED,QAAM,SAAQ,oBAAI,KAAK,GAAE,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC;AACnD,QAAM,OAAO,EAAE,MAAM,MAAM;AAG3B,MAAI,KAAK,kDAAe;AACxB,aAAW,OAAO,SAAS;AACzB,UAAMA,IAAG,UAAUD,MAAK,KAAK,cAAc,GAAG,CAAC;AAAA,EACjD;AACA,MAAI,QAAQ,qDAAa;AAGzB,QAAM,eAAeA,MAAK,KAAK,eAAe,WAAW;AACzD,QAAMC,IAAG,KAAK,cAAcD,MAAK,KAAK,cAAc,YAAY,CAAC;AACjE,MAAI,KAAK,yBAAe;AAGxB,QAAM,mBAAmBA,MAAK,KAAK,eAAe,gBAAgB;AAClE,QAAM,gBAAgB,MAAMC,IAAG,QAAQ,gBAAgB;AACvD,aAAW,QAAQ,eAAe;AAChC,UAAM,UAAU,MAAMA,IAAG,SAASD,MAAK,KAAK,kBAAkB,IAAI,GAAG,OAAO;AAC5E,UAAM,WAAW,eAAe,SAAS,IAAI;AAC7C,UAAMC,IAAG,UAAUD,MAAK,KAAK,cAAc,aAAa,IAAI,GAAG,QAAQ;AAAA,EACzE;AACA,MAAI,KAAK,8CAAW;AAGpB,QAAM,eAAeA,MAAK,KAAK,eAAe,YAAY;AAC1D,QAAM,gBAAgBA,MAAK,KAAK,cAAc,OAAO,SAAS,YAAY;AAC1E,QAAMC,IAAG,KAAK,cAAc,aAAa;AACzC,QAAMA,IAAG,MAAM,eAAe,GAAK;AACnC,MAAI,KAAK,8BAAoB;AAG7B,QAAM,aAAaD,MAAK,KAAK,eAAe,kBAAkB;AAC9D,QAAM,cAAcA,MAAK,KAAK,cAAc,OAAO,WAAW,kBAAkB;AAChF,QAAMC,IAAG,KAAK,YAAY,WAAW;AACrC,QAAMA,IAAG,MAAM,aAAa,GAAK;AACjC,MAAI,KAAK,+BAAqB;AAG9B,QAAM,YAAYD,MAAK,KAAK,eAAe,eAAe;AAC1D,QAAM,cAAcA,MAAK,KAAK,eAAe,iBAAiB;AAC9D,QAAMC,IAAG,KAAK,WAAWD,MAAK,KAAK,cAAc,WAAW,aAAa,eAAe,CAAC;AACzF,QAAMC,IAAG,KAAK,aAAaD,MAAK,KAAK,cAAc,WAAW,aAAa,iBAAiB,CAAC;AAC7F,MAAI,KAAK,4DAAyB;AAGlC,QAAMC,IAAG,UAAUD,MAAK,KAAK,cAAc,eAAe,GAAG,CAAC,CAAC;AAC/D,MAAI,KAAK,wDAA0B;AAGnC,QAAM,aAAaA,MAAK,KAAK,eAAe,aAAa;AACzD,QAAM,iBAAiB,MAAMC,IAAG,SAAS,YAAY,OAAO;AAC5D,QAAMA,IAAG;AAAA,IACPD,MAAK,KAAK,cAAc,cAAc,aAAa;AAAA,IACnD,eAAe,gBAAgB,IAAI;AAAA,EACrC;AAEA,QAAM,eAAeA,MAAK,KAAK,eAAe,eAAe;AAC7D,QAAM,mBAAmB,MAAMC,IAAG,SAAS,cAAc,OAAO;AAChE,QAAMA,IAAG;AAAA,IACPD,MAAK,KAAK,cAAc,cAAc,eAAe;AAAA,IACrD,eAAe,kBAAkB,IAAI;AAAA,EACvC;AACA,MAAI,KAAK,oEAAgD;AAGzD,QAAM,SAAS,cAAc,aAAa,MAAS;AACnD,MAAI,KAAK,cAAc,YAAY,cAAc,SAAS,KAAK,GAAG;AAGlE,QAAM,cAAcA,MAAK,KAAK,cAAc,QAAQ,SAAS,YAAY;AACzE,QAAMC,IAAG,KAAK,eAAe,WAAW;AACxC,QAAMA,IAAG,MAAM,aAAa,GAAK;AACjC,MAAI,KAAK,4CAAkC;AAG3C,QAAM,WAAW,YAAY;AAG7B,QAAM,OAAO,MAAM,OAAO,YAAY,GAAG,QAAQ,YAAY;AAC7D,QAAM,IAAI,IAAI,GAAG;AACjB,QAAM,IAAI,OAAO,oCAAgB;AACjC,MAAI,KAAK,wCAAU;AAEnB,MAAI,QAAQ,iCAAa,YAAY,EAAE;AACvC,MAAI,KAAK,4BAAQ;AACjB,MAAI,KAAK,0DAAuB;AAChC,MAAI,KAAK,UAAU;AACnB,MAAI,KAAK,+CAAiB;AAC5B;;;AK/IA,SAAS,SAAAC,cAAa;AACtB,OAAOC,SAAQ;AACf,OAAOC,WAAU;AAKjB,eAAsB,YAAY,WAAkC;AAClE,MAAI,KAAK,uDAAe;AAExB,QAAM,cAAcC,MAAK,KAAK,QAAQ,IAAI,QAAQ,KAAK,SAAS;AAChE,QAAM,SAAS,MAAMC,OAAM;AAAA,IACzB,SAAS;AAAA,IACT,SAAS;AAAA,EACX,CAAC;AACD,QAAM,eAAe,OAAO,WAAW,GAAG,IACtC,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,EAAE,IAC1CD,MAAK,QAAQ,MAAM;AAEvB,MAAIE,IAAG,WAAW,YAAY,KAAKA,IAAG,YAAY,YAAY,EAAE,SAAS,GAAG;AAC1E,QAAI,MAAM,GAAG,YAAY,kGAAuB;AAChD;AAAA,EACF;AAGA,MAAI,KAAK,qBAAgB;AACzB,QAAM,UAAU,WAAW,YAAY;AACvC,MAAI,QAAQ,oBAAU;AAGtB,QAAM,UAAUF,MAAK,KAAK,cAAc,OAAO,SAAS,YAAY;AACpE,QAAM,WAAWA,MAAK,KAAK,cAAc,QAAQ,SAAS,YAAY;AACtE,MAAIE,IAAG,WAAW,OAAO,GAAG;AAC1B,UAAMA,IAAG,KAAK,SAAS,QAAQ;AAC/B,UAAMA,IAAG,MAAM,UAAU,GAAK;AAC9B,QAAI,KAAK,8BAAoB;AAAA,EAC/B,OAAO;AACL,QAAI,KAAK,oFAAiD;AAAA,EAC5D;AAGA,QAAM,WAAW,YAAY;AAE7B,MAAI,QAAQ,iCAAa,YAAY,EAAE;AACvC,MAAI,KAAK,4BAAQ;AACjB,MAAI,KAAK,sEAA4D;AACvE;;;AC9CA,SAAS,SAAAC,cAAa;;;ACAtB,OAAOC,SAAQ;AACf,OAAOC,WAAU;;;ACDjB,OAAOC,SAAQ;AACf,OAAOC,WAAU;AAMjB,eAAsB,cACpB,QACA,UACe;AACf,QAAMC,IAAG,UAAUC,MAAK,QAAQ,QAAQ,CAAC;AAEzC,MAAID,IAAG,WAAW,QAAQ,GAAG;AAC3B,UAAM,OAAO,MAAMA,IAAG,MAAM,QAAQ;AACpC,QAAI,KAAK,eAAe,GAAG;AACzB,YAAM,WAAW,MAAMA,IAAG,SAAS,QAAQ;AAC3C,UAAI,aAAa,QAAQ;AACvB,YAAI,KAAK,sCAAkBC,MAAK,SAAS,QAAQ,CAAC,EAAE;AACpD;AAAA,MACF;AACA,YAAMD,IAAG,OAAO,QAAQ;AAAA,IAC1B,OAAO;AACL,UAAI,KAAK,GAAG,QAAQ,qGAA+B;AACnD,YAAMA,IAAG,OAAO,QAAQ;AAAA,IAC1B;AAAA,EACF;AAEA,MAAI,CAACA,IAAG,WAAW,MAAM,GAAG;AAC1B,QAAI,KAAK,mDAAqB,MAAM,iDAAc;AAAA,EACpD;AAEA,QAAMA,IAAG,QAAQ,QAAQ,QAAQ;AACjC,MAAI,KAAK,yBAAeC,MAAK,SAAS,QAAQ,CAAC,WAAM,MAAM,EAAE;AAC/D;;;AClCA,OAAOC,SAAQ;AACf,OAAOC,WAAU;AAOjB,eAAsB,wBACpB,KACA,UACe;AACf,QAAM,gBAAgBC,MAAK,KAAK,KAAK,YAAY;AAEjD,MAAI,UAAU;AACd,MAAIC,IAAG,WAAW,aAAa,GAAG;AAChC,cAAU,MAAMA,IAAG,SAAS,eAAe,OAAO;AAAA,EACpD;AAEA,QAAM,QAAQ,QAAQ,MAAM,IAAI;AAChC,QAAM,QAAkB,CAAC;AAEzB,aAAW,WAAW,UAAU;AAC9B,UAAM,UAAU,QAAQ,KAAK;AAC7B,QAAI,CAAC,MAAM,KAAK,CAAC,SAAS,KAAK,KAAK,MAAM,OAAO,GAAG;AAClD,YAAM,KAAK,OAAO;AAAA,IACpB;AAAA,EACF;AAEA,MAAI,MAAM,WAAW,GAAG;AACtB;AAAA,EACF;AAEA,QAAM,YAAY,QAAQ,SAAS,KAAK,CAAC,QAAQ,SAAS,IAAI,IAAI,OAAO;AACzE,QAAM,UACJ,YACA,iCACA,MAAM,KAAK,IAAI,IACf;AAEF,QAAMA,IAAG,WAAW,eAAe,OAAO;AAC1C,MAAI,KAAK,oBAAe,MAAM,MAAM,kCAAS;AAC/C;;;AFnCA,SAAS,uBAAuB,KAA0B;AACxD,SAAO;AAAA;AAAA,qBAEE,IAAI,MAAM;AAAA,qCACT,IAAI,MAAM;AAAA,qCACV,IAAI,MAAM;AAAA,iFACD,IAAI,MAAM;AAAA;AAE/B;AAEA,eAAsB,WAAW,KAAiC;AAChE,QAAM,WAAWC,MAAK,KAAK,IAAI,aAAa,WAAW,OAAO;AAC9D,QAAMC,IAAG,UAAU,QAAQ;AAG3B,QAAM,eAAeD,MAAK,KAAK,IAAI,QAAQ,YAAY;AACvD,QAAM,iBAAiB;AAAA,IACrB,EAAE,MAAM,eAAe,QAAQA,MAAK,KAAK,cAAc,aAAa,EAAE;AAAA,IACtE,EAAE,MAAM,iBAAiB,QAAQA,MAAK,KAAK,cAAc,eAAe,EAAE;AAAA,EAC5E;AAGA,MAAIC,IAAG,WAAW,YAAY,GAAG;AAC/B,UAAM,QAAQ,MAAMA,IAAG,QAAQ,YAAY;AAC3C,eAAW,QAAQ,OAAO;AACxB,UAAI,KAAK,SAAS,cAAc,GAAG;AACjC,uBAAe,KAAK;AAAA,UAClB,MAAM;AAAA,UACN,QAAQD,MAAK,KAAK,cAAc,IAAI;AAAA,QACtC,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,aAAW,EAAE,MAAM,OAAO,KAAK,gBAAgB;AAC7C,UAAM,cAAc,QAAQA,MAAK,KAAK,UAAU,IAAI,CAAC;AAAA,EACvD;AAGA,QAAM,eAAeA,MAAK,KAAK,UAAU,gBAAgB;AACzD,QAAMC,IAAG,UAAU,cAAc,uBAAuB,GAAG,CAAC;AAC5D,MAAI,KAAK,4DAA8B;AAGvC,QAAM,eAAeD,MAAK,KAAK,IAAI,aAAa,WAAW,eAAe;AAC1E,MAAI,CAACC,IAAG,WAAW,YAAY,GAAG;AAChC,UAAMA,IAAG,UAAU,cAAc,CAAC,GAAG,EAAE,QAAQ,EAAE,CAAC;AAClD,QAAI,KAAK,oCAA0B;AAAA,EACrC;AAGA,QAAM,wBAAwB,IAAI,aAAa;AAAA,IAC7C;AAAA,EACF,CAAC;AAED,MAAI,QAAQ,uCAAmB;AACjC;;;AG/DA,OAAOC,SAAQ;AACf,OAAOC,WAAU;AAMjB,SAAS,gBAAwB;AAC/B,SAAO;AACT;AAEA,SAAS,gBAAgB,KAA0B;AACjD,MAAI,UAAU;AAAA;AAAA,qBAEL,IAAI,MAAM;AAAA,qCACT,IAAI,MAAM;AAAA,qCACV,IAAI,MAAM;AAAA,iFACD,IAAI,MAAM;AAAA;AAAA;AAK7B,aAAW;AACX,aAAW;AAGX,QAAM,YAAYC,MAAK,KAAK,IAAI,QAAQ,YAAY;AACpD,MAAIC,IAAG,WAAW,SAAS,GAAG;AAC5B,UAAM,QAAQA,IAAG,YAAY,SAAS;AACtC,eAAW,QAAQ,OAAO;AACxB,UAAI,KAAK,SAAS,cAAc,GAAG;AACjC,mBAAW,eAAe,IAAI;AAAA;AAAA,MAChC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEA,eAAsB,WAAW,KAAiC;AAChE,QAAM,YAAYD,MAAK,KAAK,IAAI,aAAa,SAAS;AACtD,QAAMC,IAAG,UAAU,SAAS;AAG5B,QAAM,eAAeD,MAAK,KAAK,IAAI,aAAa,WAAW;AAC3D,QAAM,aAAa,cAAc;AACjC,MAAIC,IAAG,WAAW,YAAY,GAAG;AAC/B,UAAM,WAAW,MAAMA,IAAG,SAAS,cAAc,OAAO;AACxD,QAAI,CAAC,SAAS,SAAS,uBAAuB,GAAG;AAC/C,YAAM,UAAU,aAAa,OAAO;AACpC,YAAMA,IAAG,UAAU,cAAc,OAAO;AACxC,UAAI,KAAK,yCAA0B;AAAA,IACrC,OAAO;AACL,UAAI,KAAK,0EAAkC;AAAA,IAC7C;AAAA,EACF,OAAO;AACL,UAAMA,IAAG,UAAU,cAAc,UAAU;AAC3C,QAAI,KAAK,wBAAc;AAAA,EACzB;AAGA,QAAM,eAAeD,MAAK,KAAK,IAAI,QAAQ,YAAY;AACvD,QAAM,gBAAgBA,MAAK,KAAK,WAAW,YAAY;AACvD,QAAM,cAAc,cAAc,aAAa;AAG/C,QAAM,aAAaA,MAAK,KAAK,WAAW,cAAc;AACtD,QAAMC,IAAG,UAAU,YAAY,gBAAgB,GAAG,CAAC;AACnD,MAAI,KAAK,+DAA2C;AAGpD,QAAM,eAAeD,MAAK,KAAK,WAAW,eAAe;AACzD,MAAI,CAACC,IAAG,WAAW,YAAY,GAAG;AAChC,UAAMA,IAAG,UAAU,cAAc,CAAC,GAAG,EAAE,QAAQ,EAAE,CAAC;AAClD,QAAI,KAAK,oCAA0B;AAAA,EACrC;AAGA,QAAM,wBAAwB,IAAI,aAAa;AAAA,IAC7C;AAAA,IACA;AAAA,EACF,CAAC;AAED,MAAI,QAAQ,sCAAkB;AAChC;;;ACpFA,OAAOC,SAAQ;AACf,OAAOC,WAAU;AAKjB,SAAS,gBAAwB;AAC/B,SAAO;AACT;AAEA,SAAS,iBAAiB,KAA0B;AAClD,QAAM,YAAYC,MAAK,KAAK,IAAI,QAAQ,YAAY;AAEpD,SAAO;AAAA,wDACO,SAAS;AAAA;AAAA;AAAA;AAAA,qBAId,IAAI,MAAM;AAAA,qCACT,IAAI,MAAM;AAAA,qCACV,IAAI,MAAM;AAAA,iFACD,IAAI,MAAM;AAAA;AAE/B;AAEA,eAAsB,UAAU,KAAiC;AAC/D,QAAM,WAAWA,MAAK,KAAK,IAAI,aAAa,QAAQ;AACpD,QAAMC,IAAG,UAAU,QAAQ;AAG3B,QAAM,eAAeD,MAAK,KAAK,IAAI,aAAa,WAAW;AAC3D,QAAM,cAAc,cAAc;AAClC,MAAIC,IAAG,WAAW,YAAY,GAAG;AAC/B,UAAM,WAAW,MAAMA,IAAG,SAAS,cAAc,OAAO;AACxD,QAAI,CAAC,SAAS,SAAS,kBAAkB,GAAG;AAC1C,YAAMA,IAAG,WAAW,cAAc,OAAO,WAAW;AACpD,UAAI,KAAK,oDAAsB;AAAA,IACjC,OAAO;AACL,UAAI,KAAK,qFAA8B;AAAA,IACzC;AAAA,EACF,OAAO;AACL,UAAMA,IAAG,UAAU,cAAc,WAAW;AAC5C,QAAI,KAAK,wBAAc;AAAA,EACzB;AAGA,QAAM,gBAAgBD,MAAK,KAAK,UAAU,iBAAiB;AAC3D,QAAMC,IAAG,UAAU,eAAe,iBAAiB,GAAG,CAAC;AACvD,MAAI,KAAK,sEAAwC;AAGjD,QAAM,wBAAwB,IAAI,aAAa;AAAA,IAC7C;AAAA,EACF,CAAC;AAED,MAAI,QAAQ,qCAAiB;AAC/B;;;ALxCA,eAAe,qBAAkD;AAE/D,MAAI,SAAS,UAAU;AACvB,MAAI,CAAC,QAAQ;AACX,aAAS,MAAMC,OAAM;AAAA,MACnB,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAEA,MAAI,CAAC,QAAQ;AACX,QAAI,MAAM,uIAA6C;AACvD,WAAO;AAAA,EACT;AAEA,QAAM,cAAc,QAAQ,IAAI;AAChC,QAAM,WACJ,YAAY,MAAM,GAAG,EAAE,IAAI,KAAK;AAElC,SAAO,EAAE,QAAQ,aAAa,SAAS;AACzC;AAEA,eAAsB,YAAY,MAA6B;AAC7D,QAAM,aAAa,CAAC,UAAU,UAAU,OAAO;AAC/C,MAAI,CAAC,WAAW,SAAS,IAAI,GAAG;AAC9B,QAAI,MAAM,uDAAe,IAAI,+CAAgC;AAC7D;AAAA,EACF;AAEA,MAAI,KAAK,kCAAS,IAAI,qDAAa;AAEnC,QAAM,MAAM,MAAM,mBAAmB;AACrC,MAAI,CAAC,IAAK;AAEV,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,YAAM,WAAW,GAAG;AACpB;AAAA,IACF,KAAK;AACH,YAAM,WAAW,GAAG;AACpB;AAAA,IACF,KAAK;AACH,YAAM,UAAU,GAAG;AACnB;AAAA,EACJ;AACF;;;AM5DA,OAAOC,UAAQ;AACf,OAAOC,WAAU;AAUjB,eAAsB,gBAA+B;AACnD,MAAI,KAAK,sEAAoB;AAC7B,QAAM,UAAyB,CAAC;AAGhC,QAAM,SAAS,UAAU;AACzB,UAAQ,KAAK;AAAA,IACX,MAAM,8BAAU,WAAW;AAAA,IAC3B,IAAI,CAAC,CAAC;AAAA,IACN,QAAQ,UAAU;AAAA,EACpB,CAAC;AAED,MAAI,CAAC,QAAQ;AACX,iBAAa,OAAO;AACpB;AAAA,EACF;AAGA,QAAM,WAAWC,KAAG,WAAW,MAAM;AACrC,UAAQ,KAAK;AAAA,IACX,MAAM;AAAA,IACN,IAAI;AAAA,IACJ,QAAQ,WAAW,SAAS,GAAG,MAAM;AAAA,EACvC,CAAC;AAED,MAAI,CAAC,UAAU;AACb,iBAAa,OAAO;AACpB;AAAA,EACF;AAGA,QAAM,cAAcC,MAAK,KAAK,QAAQ,cAAc,aAAa;AACjE,QAAM,gBAAgBD,KAAG,WAAW,WAAW;AAC/C,UAAQ,KAAK;AAAA,IACX,MAAM;AAAA,IACN,IAAI;AAAA,IACJ,QAAQ,gBAAgB,iBAAO;AAAA,EACjC,CAAC;AAGD,QAAM,YAAYC,MAAK,KAAK,QAAQ,eAAe;AACnD,QAAM,cAAcD,KAAG,WAAW,SAAS;AAC3C,UAAQ,KAAK;AAAA,IACX,MAAM;AAAA,IACN,IAAI;AAAA,IACJ,QAAQ,cAAc,iBAAO;AAAA,EAC/B,CAAC;AAGD,QAAM,WAAWC,MAAK,KAAK,QAAQ,QAAQ,SAAS,YAAY;AAChE,QAAM,aAAaD,KAAG,WAAW,QAAQ;AACzC,UAAQ,KAAK;AAAA,IACX,MAAM;AAAA,IACN,IAAI;AAAA,IACJ,QAAQ,aAAa,uBAAQ;AAAA,EAC/B,CAAC;AAGD,QAAM,MAAM,QAAQ,IAAI;AACxB,MAAI,QAAQ,QAAQ;AAElB,UAAM,iBAAiBC,MAAK,KAAK,KAAK,WAAW,OAAO;AACxD,QAAID,KAAG,WAAW,cAAc,GAAG;AACjC,YAAM,cAAcC,MAAK,KAAK,gBAAgB,aAAa;AAC3D,UAAID,KAAG,WAAW,WAAW,GAAG;AAC9B,cAAM,OAAO,MAAMA,KAAG,MAAM,WAAW;AACvC,YAAI,KAAK,eAAe,GAAG;AACzB,gBAAM,SAAS,MAAMA,KAAG,SAAS,WAAW;AAC5C,gBAAM,cAAcA,KAAG,WAAW,MAAM;AACxC,kBAAQ,KAAK;AAAA,YACX,MAAM;AAAA,YACN,IAAI;AAAA,YACJ,QAAQ,cAAc,UAAK,MAAM,KAAK,+BAAgB,MAAM;AAAA,UAC9D,CAAC;AAAA,QACH;AAAA,MACF;AAEA,YAAM,eAAeC,MAAK,KAAK,gBAAgB,gBAAgB;AAC/D,cAAQ,KAAK;AAAA,QACX,MAAM;AAAA,QACN,IAAID,KAAG,WAAW,YAAY;AAAA,QAC9B,QAAQA,KAAG,WAAW,YAAY,IAAI,iBAAO;AAAA,MAC/C,CAAC;AAAA,IACH;AAGA,UAAM,eAAeC,MAAK,KAAK,KAAK,WAAW,cAAc;AAC7D,QAAID,KAAG,WAAWC,MAAK,KAAK,KAAK,WAAW,CAAC,GAAG;AAC9C,cAAQ,KAAK;AAAA,QACX,MAAM;AAAA,QACN,IAAID,KAAG,WAAW,YAAY;AAAA,QAC9B,QAAQA,KAAG,WAAW,YAAY,IAAI,iBAAO;AAAA,MAC/C,CAAC;AAAA,IACH;AAGA,UAAM,iBAAiBC,MAAK,KAAK,KAAK,UAAU,iBAAiB;AACjE,QAAID,KAAG,WAAWC,MAAK,KAAK,KAAK,WAAW,CAAC,GAAG;AAC9C,cAAQ,KAAK;AAAA,QACX,MAAM;AAAA,QACN,IAAID,KAAG,WAAW,cAAc;AAAA,QAChC,QAAQA,KAAG,WAAW,cAAc,IAAI,iBAAO;AAAA,MACjD,CAAC;AAAA,IACH;AAAA,EACF;AAEA,eAAa,OAAO;AACtB;AAEA,SAAS,aAAa,SAA8B;AAClD,MAAI,QAAQ;AACZ,aAAW,KAAK,SAAS;AACvB,QAAI,EAAE,IAAI;AACR,UAAI,QAAQ,GAAG,EAAE,IAAI,KAAK,EAAE,MAAM,EAAE;AAAA,IACtC,OAAO;AACL,UAAI,MAAM,GAAG,EAAE,IAAI,KAAK,EAAE,MAAM,EAAE;AAClC,cAAQ;AAAA,IACV;AAAA,EACF;AAEA,UAAQ,IAAI;AACZ,MAAI,OAAO;AACT,QAAI,QAAQ,wCAAU;AAAA,EACxB,OAAO;AACL,QAAI,KAAK,8IAAgC;AAAA,EAC3C;AACF;;;ACzIA,SAAS,eAAe;AACxB,OAAOE,UAAQ;AACf,OAAOC,YAAU;AAIjB,eAAsB,mBAAkC;AACtD,MAAI,KAAK,gEAAwB;AAEjC,QAAM,MAAM,QAAQ,IAAI;AACxB,MAAI,UAAU;AAGd,QAAM,iBAAiBC,OAAK,KAAK,KAAK,WAAW,OAAO;AACxD,MAAIC,KAAG,WAAW,cAAc,GAAG;AAEjC,UAAM,QAAQ,MAAMA,KAAG,QAAQ,cAAc;AAC7C,eAAW,QAAQ,OAAO;AACxB,YAAM,WAAWD,OAAK,KAAK,gBAAgB,IAAI;AAC/C,YAAM,OAAO,MAAMC,KAAG,MAAM,QAAQ;AACpC,UAAI,KAAK,eAAe,GAAG;AACzB,cAAMA,KAAG,OAAO,QAAQ;AACxB,YAAI,KAAK,uCAA6B,IAAI,EAAE;AAC5C;AAAA,MACF;AAAA,IACF;AAGA,UAAM,eAAeD,OAAK,KAAK,gBAAgB,gBAAgB;AAC/D,QAAIC,KAAG,WAAW,YAAY,GAAG;AAC/B,YAAMA,KAAG,OAAO,YAAY;AAC5B,UAAI,KAAK,4CAAkC;AAC3C;AAAA,IACF;AAAA,EACF;AAGA,QAAM,eAAeD,OAAK,KAAK,KAAK,WAAW,cAAc;AAC7D,MAAIC,KAAG,WAAW,YAAY,GAAG;AAC/B,UAAMA,KAAG,OAAO,YAAY;AAC5B,QAAI,KAAK,oCAA0B;AACnC;AAAA,EACF;AAGA,QAAM,iBAAiBD,OAAK,KAAK,KAAK,UAAU,iBAAiB;AACjE,MAAIC,KAAG,WAAW,cAAc,GAAG;AACjC,UAAMA,KAAG,OAAO,cAAc;AAC9B,QAAI,KAAK,sCAA4B;AACrC;AAAA,EACF;AAEA,MAAI,UAAU,GAAG;AACf,QAAI,QAAQ,mCAAe,OAAO,+CAAY;AAAA,EAChD,OAAO;AACL,QAAI,KAAK,oHAA+B;AAAA,EAC1C;AAGA,QAAM,eAAe,CAAC,aAAa,aAAa,WAAW,EAAE;AAAA,IAC3D,CAAC,MAAMA,KAAG,WAAWD,OAAK,KAAK,KAAK,CAAC,CAAC;AAAA,EACxC;AACA,MAAI,aAAa,SAAS,GAAG;AAC3B,QAAI;AAAA,MACF,GAAG,aAAa,KAAK,IAAI,CAAC;AAAA,IAC5B;AAAA,EACF;AAGA,QAAM,SAAS,UAAU;AACzB,QAAM,qBAAqB,MAAM,QAAQ;AAAA,IACvC,SAAS,oEAAkB,WAAW;AAAA,IACtC,SAAS;AAAA,EACX,CAAC;AAED,MAAI,oBAAoB;AACtB,UAAM,YAAY,MAAM,aAAa;AACrC,QAAI,WAAW;AACb,UAAI,KAAK,qDAAa;AAAA,IACxB;AAAA,EACF;AAGA,MAAI,UAAUC,KAAG,WAAW,MAAM,GAAG;AACnC,UAAM,iBAAiB,MAAM,QAAQ;AAAA,MACnC,SAAS,sEAAoB,MAAM;AAAA,MACnC,SAAS;AAAA,IACX,CAAC;AAED,QAAI,gBAAgB;AAClB,YAAMA,KAAG,OAAO,MAAM;AACtB,UAAI,KAAK,6CAAe,MAAM,EAAE;AAAA,IAClC,OAAO;AACL,UAAI,KAAK,6CAAe,MAAM,EAAE;AAAA,IAClC;AAAA,EACF;AAEA,UAAQ,IAAI;AACZ,MAAI,QAAQ,wBAAc;AAC1B,MAAI,KAAK,2GAA+C;AAC1D;;;Ad5FA,IAAMC,WAAU,cAAc,YAAY,GAAG;AAC7C,IAAM,EAAE,QAAQ,IAAIA,SAAQ,iBAAiB;AAE7C,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,IAAI,EACT,YAAY,iCAAiC,EAC7C,QAAQ,OAAO;AAElB,QACG,QAAQ,MAAM,EACd,YAAY,oDAAiB,EAC7B,OAAO,WAAW;AAErB,QACG,QAAQ,MAAM,EACd,YAAY,mDAAgB,EAC5B,SAAS,gBAAgB,gBAAgB,EACzC,OAAO,WAAW;AAErB,QACG,QAAQ,MAAM,EACd,YAAY,8DAAiB,EAC7B,SAAS,UAAU,yBAAyB,EAC5C,OAAO,WAAW;AAErB,QACG,QAAQ,QAAQ,EAChB,YAAY,iDAAc,EAC1B,OAAO,aAAa;AAEvB,QACG,QAAQ,WAAW,EACnB,YAAY,oDAAsB,EAClC,OAAO,gBAAgB;AAE1B,QAAQ,MAAM;","names":["fs","path","fs","fs","path","fs","input","fs","path","path","input","fs","input","fs","path","fs","path","fs","path","fs","path","path","fs","path","fs","fs","path","path","fs","fs","path","path","fs","input","fs","path","fs","path","fs","path","path","fs","require"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands/init.ts","../src/utils/log.ts","../src/utils/template.ts","../src/utils/config.ts","../src/utils/git.ts","../src/commands/join.ts","../src/commands/wire.ts","../src/commands/wire-claude.ts","../src/utils/symlink.ts","../src/utils/gitignore.ts","../src/commands/wire-gemini.ts","../src/commands/wire-codex.ts","../src/commands/doctor.ts","../src/commands/uninstall.ts","../src/commands/index-cmd.ts","../src/commands/query.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { createRequire } from \"node:module\";\nimport { initCommand } from \"./commands/init.js\";\nimport { joinCommand } from \"./commands/join.js\";\nimport { wireCommand } from \"./commands/wire.js\";\nimport { doctorCommand } from \"./commands/doctor.js\";\nimport { uninstallCommand } from \"./commands/uninstall.js\";\nimport { indexCommand } from \"./commands/index-cmd.js\";\nimport { queryCommand } from \"./commands/query.js\";\n\nconst require = createRequire(import.meta.url);\nconst { version } = require(\"../package.json\");\n\nconst program = new Command();\n\nprogram\n .name(\"kb\")\n .description(\"Team Knowledge Base harness CLI\")\n .version(version);\n\nprogram\n .command(\"init\")\n .description(\"KB 최초 생성 (팀 리드)\")\n .action(initCommand);\n\nprogram\n .command(\"join\")\n .description(\"기존 KB에 합류 (팀원)\")\n .argument(\"<remote-url>\", \"Git remote URL\")\n .action(joinCommand);\n\nprogram\n .command(\"wire\")\n .description(\"프로젝트에 LLM 도구 연결\")\n .argument(\"<tool>\", \"claude | gemini | codex\")\n .action(wireCommand);\n\nprogram\n .command(\"doctor\")\n .description(\"KB 환경 무결성 검증\")\n .action(doctorCommand);\n\nprogram\n .command(\"uninstall\")\n .description(\"KB wiring 제거 + 설정 정리\")\n .action(uninstallCommand);\n\nprogram\n .command(\"index\")\n .description(\"KB 인덱스 재생성 (Node.js 기반)\")\n .option(\"--check\", \"인덱스 생성 없이 frontmatter 검증만 수행\")\n .action(indexCommand);\n\nprogram\n .command(\"query\")\n .description(\"KB 검색 (키워드 OR 매칭)\")\n .argument(\"<keywords>\", \"검색 키워드 (공백으로 구분, OR 매칭)\")\n .option(\"-l, --limit <n>\", \"결과 수 제한\", \"5\")\n .option(\"-b, --brief\", \"tldr만 표시\")\n .option(\"-f, --full\", \"노트 전체 내용 표시\")\n .option(\"-r, --repo <name>\", \"특정 repo 우선 정렬\")\n .action(queryCommand);\n\nprogram.parse();\n","import { input } from \"@inquirer/prompts\";\nimport fs from \"fs-extra\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { log } from \"../utils/log.js\";\nimport { renderTemplate } from \"../utils/template.js\";\nimport { saveKbPath } from \"../utils/config.js\";\nimport { initRepo } from \"../utils/git.js\";\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\nconst TEMPLATES_DIR = path.join(__dirname, \"..\", \"templates\", \"kb-structure\");\n\nconst KB_DIRS = [\n \"global\",\n \"rules\",\n \"analysis\",\n \"decisions\",\n \"troubleshoot\",\n \"drafts\",\n \"areas\",\n \"templates\",\n \"ai-context\",\n \"archive\",\n \"00-inbox\",\n \"99-personal\",\n \".kb/hooks\",\n \".kb/scripts\",\n \".kb/setup\",\n \".github/workflows\",\n];\n\nexport async function initCommand(): Promise<void> {\n log.info(\"KB 최초 생성을 시작합니다.\");\n\n const defaultPath = path.join(process.env.HOME || \"~\", \"team-kb\");\n const kbPath = await input({\n message: \"KB 경로\",\n default: defaultPath,\n });\n const resolvedPath = kbPath.startsWith(\"~\")\n ? kbPath.replace(\"~\", process.env.HOME || \"\")\n : path.resolve(kbPath);\n\n if (fs.existsSync(resolvedPath) && fs.readdirSync(resolvedPath).length > 0) {\n log.error(`${resolvedPath} 가 이미 존재하고 비어있지 않습니다.`);\n return;\n }\n\n const remoteUrl = await input({\n message: \"Git remote URL (없으면 엔터)\",\n default: \"\",\n });\n\n const today = new Date().toISOString().split(\"T\")[0];\n const vars = { date: today };\n\n // 1. Create directory structure\n log.info(\"폴더 구조 생성 중...\");\n for (const dir of KB_DIRS) {\n await fs.ensureDir(path.join(resolvedPath, dir));\n }\n log.success(\"폴더 구조 생성 완료\");\n\n // 2. Copy .gitignore\n const gitignoreSrc = path.join(TEMPLATES_DIR, \"gitignore\");\n await fs.copy(gitignoreSrc, path.join(resolvedPath, \".gitignore\"));\n log.step(\".gitignore 생성\");\n\n // 3. Copy and render note templates\n const noteTemplatesDir = path.join(TEMPLATES_DIR, \"note-templates\");\n const noteTemplates = await fs.readdir(noteTemplatesDir);\n for (const file of noteTemplates) {\n const content = await fs.readFile(path.join(noteTemplatesDir, file), \"utf-8\");\n const rendered = renderTemplate(content, vars);\n await fs.writeFile(path.join(resolvedPath, \"templates\", file), rendered);\n }\n log.step(\"노트 템플릿 생성\");\n\n // 4. Copy pre-commit hook\n const preCommitSrc = path.join(TEMPLATES_DIR, \"pre-commit\");\n const preCommitDest = path.join(resolvedPath, \".kb\", \"hooks\", \"pre-commit\");\n await fs.copy(preCommitSrc, preCommitDest);\n await fs.chmod(preCommitDest, 0o755);\n log.step(\"pre-commit hook 생성\");\n\n // 5. Copy rebuild-index.sh\n const rebuildSrc = path.join(TEMPLATES_DIR, \"rebuild-index.sh\");\n const rebuildDest = path.join(resolvedPath, \".kb\", \"scripts\", \"rebuild-index.sh\");\n await fs.copy(rebuildSrc, rebuildDest);\n await fs.chmod(rebuildDest, 0o755);\n log.step(\"rebuild-index.sh 생성\");\n\n // 6. Copy GitHub Actions workflows\n const healthSrc = path.join(TEMPLATES_DIR, \"kb-health.yml\");\n const coverageSrc = path.join(TEMPLATES_DIR, \"kb-coverage.yml\");\n await fs.copy(healthSrc, path.join(resolvedPath, \".github\", \"workflows\", \"kb-health.yml\"));\n await fs.copy(coverageSrc, path.join(resolvedPath, \".github\", \"workflows\", \"kb-coverage.yml\"));\n log.step(\"GitHub Actions 워크플로우 생성\");\n\n // 7. Create kb-index.json (empty)\n await fs.writeJson(path.join(resolvedPath, \"kb-index.json\"), []);\n log.step(\"kb-index.json 초기화 (빈 배열)\");\n\n // 8. Create ai-context files\n const kbRulesSrc = path.join(TEMPLATES_DIR, \"kb-rules.md\");\n const kbRulesContent = await fs.readFile(kbRulesSrc, \"utf-8\");\n await fs.writeFile(\n path.join(resolvedPath, \"ai-context\", \"kb-rules.md\"),\n renderTemplate(kbRulesContent, vars),\n );\n\n const teamFocusSrc = path.join(TEMPLATES_DIR, \"team-focus.md\");\n const teamFocusContent = await fs.readFile(teamFocusSrc, \"utf-8\");\n await fs.writeFile(\n path.join(resolvedPath, \"ai-context\", \"team-focus.md\"),\n renderTemplate(teamFocusContent, vars),\n );\n log.step(\"ai-context/ 파일 생성 (kb-rules.md, team-focus.md)\");\n\n // 9. Git init + remote\n await initRepo(resolvedPath, remoteUrl || undefined);\n log.step(\"git init\" + (remoteUrl ? ` + remote: ${remoteUrl}` : \"\"));\n\n // 10. Install pre-commit hook (symlink for auto-update on git pull)\n const gitHookDest = path.join(resolvedPath, \".git\", \"hooks\", \"pre-commit\");\n await fs.remove(gitHookDest);\n try {\n await fs.symlink(preCommitDest, gitHookDest);\n log.step(\"pre-commit hook 설치 (symlink → .kb/hooks/)\");\n } catch {\n await fs.copy(preCommitDest, gitHookDest);\n await fs.chmod(gitHookDest, 0o755);\n log.step(\"pre-commit hook 설치 (복사 — symlink 실패)\");\n }\n\n // 11. Save config\n await saveKbPath(resolvedPath);\n\n // 12. Initial commit\n const git = (await import(\"simple-git\")).default(resolvedPath);\n await git.add(\".\");\n await git.commit(\"init: KB 구조 생성\");\n log.step(\"초기 커밋 완료\");\n\n log.success(`KB 생성 완료: ${resolvedPath}`);\n log.info(\"다음 단계:\");\n log.step(\"ai-context/ 오버뷰 초안 작성\");\n log.step(\"git push\");\n log.step(\"팀원에게 kb join 안내\");\n}\n","import pc from \"picocolors\";\n\nexport const log = {\n info: (msg: string) => console.log(pc.blue(\"ℹ\") + \" \" + msg),\n success: (msg: string) => console.log(pc.green(\"✔\") + \" \" + msg),\n warn: (msg: string) => console.log(pc.yellow(\"⚠\") + \" \" + msg),\n error: (msg: string) => console.error(pc.red(\"✖\") + \" \" + msg),\n step: (msg: string) => console.log(pc.gray(\" →\") + \" \" + msg),\n};\n","/**\n * Simple template variable replacement.\n * Replaces {{VAR_NAME}} with provided values.\n */\nexport function renderTemplate(\n template: string,\n vars: Record<string, string>,\n): string {\n let result = template;\n for (const [key, value] of Object.entries(vars)) {\n result = result.replaceAll(`{{${key}}}`, value);\n }\n return result;\n}\n","import fs from \"fs-extra\";\nimport path from \"node:path\";\nimport { log } from \"./log.js\";\n\nconst CONFIG_DIR = path.join(\n process.env.HOME || \"~\",\n \".config\",\n \"kb-cli\",\n);\nconst CONFIG_PATH = path.join(CONFIG_DIR, \"config.json\");\n\ninterface KbConfig {\n kbPath: string;\n}\n\n/**\n * Read KB path from config file.\n */\nexport function getKbPath(): string | undefined {\n try {\n if (fs.existsSync(CONFIG_PATH)) {\n const config: KbConfig = fs.readJsonSync(CONFIG_PATH);\n return config.kbPath;\n }\n } catch {\n // ignore parse errors\n }\n return undefined;\n}\n\n/**\n * Save KB path to config file.\n */\nexport async function saveKbPath(kbPath: string): Promise<void> {\n await fs.ensureDir(CONFIG_DIR);\n await fs.writeJson(CONFIG_PATH, { kbPath }, { spaces: 2 });\n log.step(`설정 저장: ${CONFIG_PATH}`);\n}\n\n/**\n * Remove config file.\n */\nexport async function removeConfig(): Promise<boolean> {\n if (fs.existsSync(CONFIG_PATH)) {\n await fs.remove(CONFIG_PATH);\n return true;\n }\n return false;\n}\n\nexport { CONFIG_PATH };\n","import simpleGit, { type SimpleGit } from \"simple-git\";\nimport fs from \"fs-extra\";\n\nexport function getGit(cwd?: string): SimpleGit {\n return simpleGit(cwd);\n}\n\nexport async function isGitRepo(dir: string): Promise<boolean> {\n try {\n const git = getGit(dir);\n return await git.checkIsRepo();\n } catch {\n return false;\n }\n}\n\nexport async function initRepo(\n dir: string,\n remote?: string,\n): Promise<void> {\n const git = getGit(dir);\n await git.init();\n if (remote) {\n await git.addRemote(\"origin\", remote);\n }\n}\n\nexport async function cloneRepo(\n url: string,\n dir: string,\n): Promise<void> {\n await fs.ensureDir(dir);\n const git = simpleGit();\n await git.clone(url, dir);\n}\n","import { input } from \"@inquirer/prompts\";\nimport fs from \"fs-extra\";\nimport path from \"node:path\";\nimport { log } from \"../utils/log.js\";\nimport { saveKbPath } from \"../utils/config.js\";\nimport { cloneRepo } from \"../utils/git.js\";\n\nexport async function joinCommand(remoteUrl: string): Promise<void> {\n log.info(\"기존 KB에 합류합니다.\");\n\n const defaultPath = path.join(process.env.HOME || \"~\", \"team-kb\");\n const kbPath = await input({\n message: \"로컬 경로\",\n default: defaultPath,\n });\n const resolvedPath = kbPath.startsWith(\"~\")\n ? kbPath.replace(\"~\", process.env.HOME || \"\")\n : path.resolve(kbPath);\n\n if (fs.existsSync(resolvedPath) && fs.readdirSync(resolvedPath).length > 0) {\n log.error(`${resolvedPath} 가 이미 존재하고 비어있지 않습니다.`);\n return;\n }\n\n // 1. Clone\n log.info(\"git clone 중...\");\n await cloneRepo(remoteUrl, resolvedPath);\n log.success(\"clone 완료\");\n\n // 2. Install pre-commit hook\n const hookSrc = path.join(resolvedPath, \".kb\", \"hooks\", \"pre-commit\");\n const hookDest = path.join(resolvedPath, \".git\", \"hooks\", \"pre-commit\");\n if (fs.existsSync(hookSrc)) {\n await fs.remove(hookDest);\n try {\n await fs.symlink(hookSrc, hookDest);\n log.step(\"pre-commit hook 설치 (symlink → .kb/hooks/)\");\n } catch {\n await fs.copy(hookSrc, hookDest);\n await fs.chmod(hookDest, 0o755);\n log.step(\"pre-commit hook 설치 (복사 — symlink 실패)\");\n }\n } else {\n log.warn(\"pre-commit hook 원본이 없습니다 (.kb/hooks/pre-commit)\");\n }\n\n // 3. Save config\n await saveKbPath(resolvedPath);\n\n log.success(`KB 합류 완료: ${resolvedPath}`);\n log.info(\"다음 단계:\");\n log.step(\"cd ~/repos/{project} && kb wire claude (또는 gemini / codex)\");\n}\n","import { input } from \"@inquirer/prompts\";\nimport { log } from \"../utils/log.js\";\nimport { getKbPath } from \"../utils/config.js\";\nimport { wireClaude } from \"./wire-claude.js\";\nimport { wireGemini } from \"./wire-gemini.js\";\nimport { wireCodex } from \"./wire-codex.js\";\n\nexport interface WireContext {\n /** Absolute path to the KB repo */\n kbPath: string;\n /** Current project root (cwd) */\n projectRoot: string;\n /** Current repo name (e.g., \"coupon-api\") */\n repoName: string;\n}\n\nasync function collectWireContext(): Promise<WireContext | null> {\n // Resolve KB path\n let kbPath = getKbPath();\n if (!kbPath) {\n kbPath = await input({\n message: \"KB 경로를 찾을 수 없습니다. KB 절대 경로를 입력하세요\",\n });\n }\n\n if (!kbPath) {\n log.error(\"KB 경로가 필요합니다. kb init 또는 kb join을 먼저 실행하세요.\");\n return null;\n }\n\n const projectRoot = process.cwd();\n const repoName =\n projectRoot.split(\"/\").pop() || \"unknown\";\n\n return { kbPath, projectRoot, repoName };\n}\n\nexport async function wireCommand(tool: string): Promise<void> {\n const validTools = [\"claude\", \"gemini\", \"codex\"];\n if (!validTools.includes(tool)) {\n log.error(`지원하지 않는 도구: ${tool}. (claude, gemini, codex 중 선택)`);\n return;\n }\n\n log.info(`프로젝트에 ${tool} 연결을 시작합니다.`);\n\n const ctx = await collectWireContext();\n if (!ctx) return;\n\n switch (tool) {\n case \"claude\":\n await wireClaude(ctx);\n break;\n case \"gemini\":\n await wireGemini(ctx);\n break;\n case \"codex\":\n await wireCodex(ctx);\n break;\n }\n}\n","import fs from \"fs-extra\";\nimport path from \"node:path\";\nimport { log } from \"../utils/log.js\";\nimport { createSymlink } from \"../utils/symlink.js\";\nimport { ensureGitignorePatterns } from \"../utils/gitignore.js\";\nimport type { WireContext } from \"./wire.js\";\n\nfunction buildKbLocationContent(ctx: WireContext): string {\n return `## KB 절대 경로\nLLM은 파일 접근 및 쉘 스크립트 실행 시 반드시 아래의 절대 경로를 그대로 사용할 것.\n- KB 루트: ${ctx.kbPath}\n- 전체 인덱스: ${ctx.kbPath}/kb-index.json\n- 로컬 인덱스: ${ctx.kbPath}/.kb-index.local.json\n- 로컬 인덱스 재생성 스크립트: ${ctx.kbPath}/.kb/scripts/rebuild-index.sh\n`;\n}\n\nexport async function wireClaude(ctx: WireContext): Promise<void> {\n const rulesDir = path.join(ctx.projectRoot, \".claude\", \"rules\");\n await fs.ensureDir(rulesDir);\n\n // 1. Symlinks to KB ai-context files\n const aiContextDir = path.join(ctx.kbPath, \"ai-context\");\n const symlinkTargets = [\n { name: \"kb-rules.md\", target: path.join(aiContextDir, \"kb-rules.md\") },\n { name: \"team-focus.md\", target: path.join(aiContextDir, \"team-focus.md\") },\n ];\n\n // Also symlink any *-overview.md files\n if (fs.existsSync(aiContextDir)) {\n const files = await fs.readdir(aiContextDir);\n for (const file of files) {\n if (file.endsWith(\"-overview.md\")) {\n symlinkTargets.push({\n name: file,\n target: path.join(aiContextDir, file),\n });\n }\n }\n }\n\n for (const { name, target } of symlinkTargets) {\n await createSymlink(target, path.join(rulesDir, name));\n }\n\n // 3. kb-location.md — explicit paths (local-only)\n const locationPath = path.join(rulesDir, \"kb-location.md\");\n await fs.writeFile(locationPath, buildKbLocationContent(ctx));\n log.step(\"kb-location.md 생성 (KB 절대 경로)\");\n\n // 3. .claude/settings.json\n const settingsPath = path.join(ctx.projectRoot, \".claude\", \"settings.json\");\n if (!fs.existsSync(settingsPath)) {\n await fs.writeJson(settingsPath, {}, { spaces: 2 });\n log.step(\".claude/settings.json 생성\");\n }\n\n // 4. Update .gitignore\n await ensureGitignorePatterns(ctx.projectRoot, [\n \".claude/rules/\",\n ]);\n\n log.success(\"Claude Code 연결 완료\");\n}\n","import fs from \"fs-extra\";\nimport path from \"node:path\";\nimport { log } from \"./log.js\";\n\n/**\n * Create a symlink. If target doesn't exist, warn but still create.\n */\nexport async function createSymlink(\n target: string,\n linkPath: string,\n): Promise<void> {\n await fs.ensureDir(path.dirname(linkPath));\n\n if (fs.existsSync(linkPath)) {\n const stat = await fs.lstat(linkPath);\n if (stat.isSymbolicLink()) {\n const existing = await fs.readlink(linkPath);\n if (existing === target) {\n log.step(`symlink 이미 존재: ${path.basename(linkPath)}`);\n return;\n }\n await fs.remove(linkPath);\n } else {\n log.warn(`${linkPath} 이 일반 파일로 존재. symlink로 교체합니다.`);\n await fs.remove(linkPath);\n }\n }\n\n if (!fs.existsSync(target)) {\n log.warn(`symlink 대상 파일 없음: ${target} (나중에 생성 필요)`);\n }\n\n await fs.symlink(target, linkPath);\n log.step(`symlink 생성: ${path.basename(linkPath)} → ${target}`);\n}\n","import fs from \"fs-extra\";\nimport path from \"node:path\";\nimport { log } from \"./log.js\";\n\n/**\n * Ensure patterns exist in a .gitignore file.\n * Creates the file if it doesn't exist. Skips patterns already present.\n */\nexport async function ensureGitignorePatterns(\n dir: string,\n patterns: string[],\n): Promise<void> {\n const gitignorePath = path.join(dir, \".gitignore\");\n\n let content = \"\";\n if (fs.existsSync(gitignorePath)) {\n content = await fs.readFile(gitignorePath, \"utf-8\");\n }\n\n const lines = content.split(\"\\n\");\n const toAdd: string[] = [];\n\n for (const pattern of patterns) {\n const trimmed = pattern.trim();\n if (!lines.some((line) => line.trim() === trimmed)) {\n toAdd.push(trimmed);\n }\n }\n\n if (toAdd.length === 0) {\n return;\n }\n\n const separator = content.length > 0 && !content.endsWith(\"\\n\") ? \"\\n\" : \"\";\n const section =\n separator +\n \"\\n# KB wiring (local-only)\\n\" +\n toAdd.join(\"\\n\") +\n \"\\n\";\n\n await fs.appendFile(gitignorePath, section);\n log.step(`.gitignore에 ${toAdd.length}개 패턴 추가`);\n}\n","import fs from \"fs-extra\";\nimport path from \"node:path\";\nimport { log } from \"../utils/log.js\";\nimport { createSymlink } from \"../utils/symlink.js\";\nimport { ensureGitignorePatterns } from \"../utils/gitignore.js\";\nimport type { WireContext } from \"./wire.js\";\n\nfunction buildGeminiMd(): string {\n return \"도메인 지식 질문은 코드 탐색 전에 반드시 KB를 먼저 확인할 것.\\n\\n@.gemini/kb-import.md\\n\";\n}\n\nfunction buildKbImportMd(ctx: WireContext): string {\n let content = `## KB 절대 경로\nLLM은 파일 접근 및 쉘 스크립트 실행 시 반드시 아래의 절대 경로를 그대로 사용할 것.\n- KB 루트: ${ctx.kbPath}\n- 전체 인덱스: ${ctx.kbPath}/kb-index.json\n- 로컬 인덱스: ${ctx.kbPath}/.kb-index.local.json\n- 로컬 인덱스 재생성 스크립트: ${ctx.kbPath}/.kb/scripts/rebuild-index.sh\n\n`;\n\n // @import via symlink (relative to this file's location)\n content += \"@kb-context/kb-rules.md\\n\";\n content += \"@kb-context/team-focus.md\\n\";\n\n // Also import any *-overview.md files\n const aiContext = path.join(ctx.kbPath, \"ai-context\");\n if (fs.existsSync(aiContext)) {\n const files = fs.readdirSync(aiContext);\n for (const file of files) {\n if (file.endsWith(\"-overview.md\")) {\n content += `@kb-context/${file}\\n`;\n }\n }\n }\n\n return content;\n}\n\nexport async function wireGemini(ctx: WireContext): Promise<void> {\n const geminiDir = path.join(ctx.projectRoot, \".gemini\");\n await fs.ensureDir(geminiDir);\n\n // 1. GEMINI.md (tracked — @import only)\n const geminiMdPath = path.join(ctx.projectRoot, \"GEMINI.md\");\n const importLine = buildGeminiMd();\n if (fs.existsSync(geminiMdPath)) {\n const existing = await fs.readFile(geminiMdPath, \"utf-8\");\n if (!existing.includes(\"@.gemini/kb-import.md\")) {\n const updated = importLine + \"\\n\" + existing;\n await fs.writeFile(geminiMdPath, updated);\n log.step(\"GEMINI.md에 KB @import 추가\");\n } else {\n log.step(\"GEMINI.md에 KB @import 이미 존재 — 스킵\");\n }\n } else {\n await fs.writeFile(geminiMdPath, importLine);\n log.step(\"GEMINI.md 생성\");\n }\n\n // 2. .gemini/kb-context symlink → KB ai-context/\n const aiContextDir = path.join(ctx.kbPath, \"ai-context\");\n const kbContextLink = path.join(geminiDir, \"kb-context\");\n await createSymlink(aiContextDir, kbContextLink);\n\n // 3. .gemini/kb-import.md (local-only — paths + @import via symlink)\n const importPath = path.join(geminiDir, \"kb-import.md\");\n await fs.writeFile(importPath, buildKbImportMd(ctx));\n log.step(\".gemini/kb-import.md 생성 (KB 경로 + @import)\");\n\n // 4. .gemini/settings.json\n const settingsPath = path.join(geminiDir, \"settings.json\");\n if (!fs.existsSync(settingsPath)) {\n await fs.writeJson(settingsPath, {}, { spaces: 2 });\n log.step(\".gemini/settings.json 생성\");\n }\n\n // 5. Update .gitignore\n await ensureGitignorePatterns(ctx.projectRoot, [\n \".gemini/kb-import.md\",\n \".gemini/kb-context\",\n ]);\n\n log.success(\"Gemini CLI 연결 완료\");\n}\n","import fs from \"fs-extra\";\nimport path from \"node:path\";\nimport { log } from \"../utils/log.js\";\nimport { ensureGitignorePatterns } from \"../utils/gitignore.js\";\nimport type { WireContext } from \"./wire.js\";\n\nfunction buildAgentsMd(): string {\n return \"# Knowledge Base\\n- 도메인 지식 질문은 코드 탐색 전에 반드시 KB를 먼저 확인할 것\\n- 세션 시작 시 반드시 .codex/kb-directive.md 파일을 먼저 읽고 그 안의 경로 지시를 따를 것\\n\";\n}\n\nfunction buildDirectiveMd(ctx: WireContext): string {\n const aiContext = path.join(ctx.kbPath, \"ai-context\");\n\n return `## KB 작동 지시\n- 세션 시작 시 반드시 ${aiContext}/kb-rules.md 를 먼저 읽을 것\n\n## KB 절대 경로\nLLM은 파일 접근 및 쉘 스크립트 실행 시 반드시 아래의 절대 경로를 그대로 사용할 것.\n- KB 루트: ${ctx.kbPath}\n- 전체 인덱스: ${ctx.kbPath}/kb-index.json\n- 로컬 인덱스: ${ctx.kbPath}/.kb-index.local.json\n- 로컬 인덱스 재생성 스크립트: ${ctx.kbPath}/.kb/scripts/rebuild-index.sh\n`;\n}\n\nexport async function wireCodex(ctx: WireContext): Promise<void> {\n const codexDir = path.join(ctx.projectRoot, \".codex\");\n await fs.ensureDir(codexDir);\n\n // 1. AGENTS.md (tracked — KB directive reference only)\n const agentsMdPath = path.join(ctx.projectRoot, \"AGENTS.md\");\n const kbDirective = buildAgentsMd();\n if (fs.existsSync(agentsMdPath)) {\n const existing = await fs.readFile(agentsMdPath, \"utf-8\");\n if (!existing.includes(\"# Knowledge Base\")) {\n await fs.appendFile(agentsMdPath, \"\\n\" + kbDirective);\n log.step(\"AGENTS.md에 KB 지시문 추가\");\n } else {\n log.step(\"AGENTS.md에 KB 지시문 이미 존재 — 스킵\");\n }\n } else {\n await fs.writeFile(agentsMdPath, kbDirective);\n log.step(\"AGENTS.md 생성\");\n }\n\n // 2. .codex/kb-directive.md (local-only — absolute paths)\n const directivePath = path.join(codexDir, \"kb-directive.md\");\n await fs.writeFile(directivePath, buildDirectiveMd(ctx));\n log.step(\".codex/kb-directive.md 생성 (KB 경로 + 지시)\");\n\n // 3. Update .gitignore\n await ensureGitignorePatterns(ctx.projectRoot, [\n \".codex/kb-directive.md\",\n ]);\n\n log.success(\"Codex CLI 연결 완료\");\n}\n","import fs from \"fs-extra\";\nimport path from \"node:path\";\nimport { log } from \"../utils/log.js\";\nimport { getKbPath, CONFIG_PATH } from \"../utils/config.js\";\n\ninterface CheckResult {\n name: string;\n ok: boolean;\n detail: string;\n}\n\nexport async function doctorCommand(): Promise<void> {\n log.info(\"KB 환경 진단을 시작합니다.\\n\");\n const results: CheckResult[] = [];\n\n // 1. KB config\n const kbPath = getKbPath();\n results.push({\n name: `설정 파일 (${CONFIG_PATH})`,\n ok: !!kbPath,\n detail: kbPath || \"미설정. kb init 또는 kb join을 먼저 실행하세요.\",\n });\n\n if (!kbPath) {\n printResults(results);\n return;\n }\n\n // 2. KB directory exists and is accessible\n const kbExists = fs.existsSync(kbPath);\n results.push({\n name: \"KB 디렉토리 접근\",\n ok: kbExists,\n detail: kbExists ? kbPath : `${kbPath} 경로가 존재하지 않습니다.`,\n });\n\n if (!kbExists) {\n printResults(results);\n return;\n }\n\n // 3. ai-context/kb-rules.md exists\n const kbRulesPath = path.join(kbPath, \"ai-context\", \"kb-rules.md\");\n const kbRulesExists = fs.existsSync(kbRulesPath);\n results.push({\n name: \"ai-context/kb-rules.md\",\n ok: kbRulesExists,\n detail: kbRulesExists ? \"존재\" : \"없음. ai-context/ 초기 파일을 작성하세요.\",\n });\n\n // 4. kb-index.json exists\n const indexPath = path.join(kbPath, \"kb-index.json\");\n const indexExists = fs.existsSync(indexPath);\n results.push({\n name: \"kb-index.json\",\n ok: indexExists,\n detail: indexExists ? \"존재\" : \"없음. git push 후 CI가 생성합니다.\",\n });\n\n // 5. pre-commit hook installed\n const hookPath = path.join(kbPath, \".git\", \"hooks\", \"pre-commit\");\n const hookExists = fs.existsSync(hookPath);\n results.push({\n name: \"pre-commit hook\",\n ok: hookExists,\n detail: hookExists ? \"설치됨\" : \"미설치. kb join을 다시 실행하세요.\",\n });\n\n // 6. Check project wiring (if in a project directory)\n const cwd = process.cwd();\n if (cwd !== kbPath) {\n // Claude\n const claudeRulesDir = path.join(cwd, \".claude\", \"rules\");\n if (fs.existsSync(claudeRulesDir)) {\n const kbRulesLink = path.join(claudeRulesDir, \"kb-rules.md\");\n if (fs.existsSync(kbRulesLink)) {\n const stat = await fs.lstat(kbRulesLink);\n if (stat.isSymbolicLink()) {\n const target = await fs.readlink(kbRulesLink);\n const targetValid = fs.existsSync(target);\n results.push({\n name: \"Claude symlink (kb-rules.md)\",\n ok: targetValid,\n detail: targetValid ? `→ ${target}` : `깨진 symlink → ${target}`,\n });\n }\n }\n\n const locationFile = path.join(claudeRulesDir, \"kb-location.md\");\n results.push({\n name: \"Claude kb-location.md\",\n ok: fs.existsSync(locationFile),\n detail: fs.existsSync(locationFile) ? \"존재\" : \"없음. kb wire claude를 실행하세요.\",\n });\n }\n\n // Gemini\n const geminiImport = path.join(cwd, \".gemini\", \"kb-import.md\");\n if (fs.existsSync(path.join(cwd, \"GEMINI.md\"))) {\n results.push({\n name: \"Gemini kb-import.md\",\n ok: fs.existsSync(geminiImport),\n detail: fs.existsSync(geminiImport) ? \"존재\" : \"없음. kb wire gemini를 실행하세요.\",\n });\n }\n\n // Codex\n const codexDirective = path.join(cwd, \".codex\", \"kb-directive.md\");\n if (fs.existsSync(path.join(cwd, \"AGENTS.md\"))) {\n results.push({\n name: \"Codex kb-directive.md\",\n ok: fs.existsSync(codexDirective),\n detail: fs.existsSync(codexDirective) ? \"존재\" : \"없음. kb wire codex를 실행하세요.\",\n });\n }\n }\n\n printResults(results);\n}\n\nfunction printResults(results: CheckResult[]): void {\n let allOk = true;\n for (const r of results) {\n if (r.ok) {\n log.success(`${r.name}: ${r.detail}`);\n } else {\n log.error(`${r.name}: ${r.detail}`);\n allOk = false;\n }\n }\n\n console.log();\n if (allOk) {\n log.success(\"모든 검증 통과\");\n } else {\n log.warn(\"일부 항목에 문제가 있습니다. 위 메시지를 확인하세요.\");\n }\n}\n","import { confirm } from \"@inquirer/prompts\";\nimport fs from \"fs-extra\";\nimport path from \"node:path\";\nimport { log } from \"../utils/log.js\";\nimport { getKbPath, removeConfig, CONFIG_PATH } from \"../utils/config.js\";\n\nexport async function uninstallCommand(): Promise<void> {\n log.info(\"KB wiring 제거를 시작합니다.\\n\");\n\n const cwd = process.cwd();\n let removed = 0;\n\n // 1. Remove Claude wiring (local-only files only)\n const claudeRulesDir = path.join(cwd, \".claude\", \"rules\");\n if (fs.existsSync(claudeRulesDir)) {\n // Remove symlinks (KB-related only)\n const files = await fs.readdir(claudeRulesDir);\n for (const file of files) {\n const filePath = path.join(claudeRulesDir, file);\n const stat = await fs.lstat(filePath);\n if (stat.isSymbolicLink()) {\n await fs.remove(filePath);\n log.step(`symlink 삭제: .claude/rules/${file}`);\n removed++;\n }\n }\n\n // Remove kb-location.md\n const locationPath = path.join(claudeRulesDir, \"kb-location.md\");\n if (fs.existsSync(locationPath)) {\n await fs.remove(locationPath);\n log.step(\"삭제: .claude/rules/kb-location.md\");\n removed++;\n }\n }\n\n // 2. Remove Gemini wiring (local-only file only)\n const geminiImport = path.join(cwd, \".gemini\", \"kb-import.md\");\n if (fs.existsSync(geminiImport)) {\n await fs.remove(geminiImport);\n log.step(\"삭제: .gemini/kb-import.md\");\n removed++;\n }\n\n // 3. Remove Codex wiring (local-only file only)\n const codexDirective = path.join(cwd, \".codex\", \"kb-directive.md\");\n if (fs.existsSync(codexDirective)) {\n await fs.remove(codexDirective);\n log.step(\"삭제: .codex/kb-directive.md\");\n removed++;\n }\n\n if (removed > 0) {\n log.success(`프로젝트 wiring ${removed}개 파일 제거 완료`);\n } else {\n log.info(\"현재 디렉토리에 제거할 wiring 파일이 없습니다.\");\n }\n\n // 4. Tracked files (CLAUDE.md, GEMINI.md, AGENTS.md) — don't touch\n const trackedFiles = [\"CLAUDE.md\", \"GEMINI.md\", \"AGENTS.md\"].filter(\n (f) => fs.existsSync(path.join(cwd, f)),\n );\n if (trackedFiles.length > 0) {\n log.warn(\n `${trackedFiles.join(\", \")}의 프로젝트 섹션은 수동으로 정리하세요 (사용자 내용과 섞여있을 수 있음).`,\n );\n }\n\n // 5. Remove config file\n const kbPath = getKbPath();\n const shouldRemoveConfig = await confirm({\n message: `설정 파일을 삭제할까요? (${CONFIG_PATH})`,\n default: true,\n });\n\n if (shouldRemoveConfig) {\n const didRemove = await removeConfig();\n if (didRemove) {\n log.step(\"설정 파일 삭제 완료\");\n }\n }\n\n // 6. KB directory — ask but warn\n if (kbPath && fs.existsSync(kbPath)) {\n const shouldRemoveKb = await confirm({\n message: `KB 디렉토리를 삭제할까요? (${kbPath}) — 팀 지식이 모두 삭제됩니다!`,\n default: false,\n });\n\n if (shouldRemoveKb) {\n await fs.remove(kbPath);\n log.step(`KB 디렉토리 삭제: ${kbPath}`);\n } else {\n log.info(`KB 디렉토리 유지: ${kbPath}`);\n }\n }\n\n console.log();\n log.success(\"uninstall 완료\");\n log.info(\"npm uninstall -g kb-cli 로 CLI 자체도 제거할 수 있습니다.\");\n}\n","import fs from \"fs-extra\";\nimport path from \"node:path\";\nimport matter from \"gray-matter\";\nimport { log } from \"../utils/log.js\";\nimport { getKbPath } from \"../utils/config.js\";\n\ninterface IndexEntry {\n path: string;\n tags: string[];\n tldr: string;\n updated: string;\n}\n\nconst EXCLUDE_DIRS = [\".kb\", \"templates\", \"99-personal\", \"00-inbox\", \".github\"];\nconst EXCLUDE_FILES = [\"README.md\"];\n\nfunction shouldInclude(filePath: string): boolean {\n for (const dir of EXCLUDE_DIRS) {\n if (filePath.startsWith(`./${dir}/`) || filePath.startsWith(`${dir}/`)) {\n return false;\n }\n }\n for (const file of EXCLUDE_FILES) {\n if (path.basename(filePath) === file) return false;\n }\n return filePath.endsWith(\".md\");\n}\n\nasync function collectMarkdownFiles(dir: string): Promise<string[]> {\n const results: string[] = [];\n const entries = await fs.readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n const rel = path.relative(dir, path.join(dir, entry.name));\n if (entry.isDirectory()) {\n if (EXCLUDE_DIRS.includes(entry.name) || entry.name.startsWith(\".\")) continue;\n const sub = await collectMarkdownFiles(path.join(dir, entry.name));\n results.push(...sub);\n } else if (entry.isFile() && shouldInclude(`./${rel}`)) {\n results.push(path.join(dir, entry.name));\n }\n }\n return results;\n}\n\nfunction parseFrontmatter(filePath: string): IndexEntry | null {\n try {\n const content = fs.readFileSync(filePath, \"utf-8\");\n const { data } = matter(content);\n\n let tags: string[] = [];\n if (Array.isArray(data.tags)) {\n tags = data.tags.map(String);\n } else if (typeof data.tags === \"string\") {\n tags = data.tags\n .replace(/^\\[|\\]$/g, \"\")\n .split(\",\")\n .map((t: string) => t.trim())\n .filter(Boolean);\n }\n\n const tldr = typeof data.tldr === \"string\" ? data.tldr : \"\";\n const updated = typeof data.updated === \"string\"\n ? data.updated\n : data.updated instanceof Date\n ? data.updated.toISOString().split(\"T\")[0]\n : \"unknown\";\n\n return { path: \"\", tags, tldr, updated };\n } catch {\n return null;\n }\n}\n\nexport async function indexCommand(options: { check?: boolean }): Promise<void> {\n const kbPath = getKbPath();\n if (!kbPath) {\n log.error(\"KB 경로가 설정되지 않았습니다. kb init 또는 kb join을 먼저 실행하세요.\");\n process.exit(1);\n }\n\n if (!fs.existsSync(kbPath)) {\n log.error(`KB 디렉토리가 존재하지 않습니다: ${kbPath}`);\n process.exit(1);\n }\n\n const files = await collectMarkdownFiles(kbPath);\n const entries: IndexEntry[] = [];\n let errors = 0;\n\n for (const filePath of files) {\n const rel = \"./\" + path.relative(kbPath, filePath);\n const entry = parseFrontmatter(filePath);\n\n if (!entry) {\n log.warn(`파싱 실패: ${rel}`);\n errors++;\n continue;\n }\n\n if (!entry.tldr) {\n log.warn(`tldr 필드 없음: ${rel}`);\n errors++;\n }\n if (entry.tags.length === 0) {\n log.warn(`tags 필드 없음: ${rel}`);\n errors++;\n }\n\n entry.path = rel;\n entries.push(entry);\n }\n\n if (options.check) {\n if (errors > 0) {\n log.error(`검증 실패: ${errors}개 문제 발견`);\n process.exit(1);\n }\n log.success(`검증 통과: ${entries.length}개 노트`);\n return;\n }\n\n // Write both index files\n const indexJson = JSON.stringify(entries, null, 2);\n\n const sharedIndex = path.join(kbPath, \"kb-index.json\");\n await fs.writeFile(sharedIndex, indexJson + \"\\n\", \"utf-8\");\n\n const localIndex = path.join(kbPath, \".kb-index.local.json\");\n await fs.writeFile(localIndex, indexJson + \"\\n\", \"utf-8\");\n\n log.success(`인덱스 생성 완료: ${entries.length}개 노트`);\n}\n","import fs from \"fs-extra\";\nimport path from \"node:path\";\nimport pc from \"picocolors\";\nimport { log } from \"../utils/log.js\";\nimport { getKbPath } from \"../utils/config.js\";\n\ninterface IndexEntry {\n path: string;\n tags: string[];\n tldr: string;\n updated: string;\n}\n\ninterface ScoredEntry extends IndexEntry {\n score: number;\n}\n\nconst TRUST_LEVELS: Record<string, string> = {\n global: \"highest\",\n rules: \"verified\",\n decisions: \"verified\",\n analysis: \"reliable\",\n troubleshoot: \"reliable\",\n drafts: \"unverified\",\n archive: \"inactive\",\n};\n\nfunction getTrustLevel(notePath: string): string {\n const folder = notePath.replace(/^\\.\\//, \"\").split(\"/\")[0];\n return TRUST_LEVELS[folder] || \"unknown\";\n}\n\nfunction scoreEntry(entry: IndexEntry, keywords: string[], repo?: string): number {\n let score = 0;\n const lowerKeywords = keywords.map((k) => k.toLowerCase());\n\n for (const kw of lowerKeywords) {\n // Tag exact match (highest weight)\n for (const tag of entry.tags) {\n if (tag.toLowerCase().includes(kw)) score += 10;\n }\n // TLDR match\n if (entry.tldr.toLowerCase().includes(kw)) score += 5;\n // Path match\n if (entry.path.toLowerCase().includes(kw)) score += 3;\n }\n\n // Repo bonus\n if (repo) {\n const repoLower = repo.toLowerCase();\n for (const tag of entry.tags) {\n if (tag.toLowerCase().includes(`repo/${repoLower}`)) score += 20;\n }\n }\n\n return score;\n}\n\nfunction loadIndex(kbPath: string): IndexEntry[] {\n const entries: IndexEntry[] = [];\n\n const sharedPath = path.join(kbPath, \"kb-index.json\");\n const localPath = path.join(kbPath, \".kb-index.local.json\");\n\n for (const indexPath of [sharedPath, localPath]) {\n if (fs.existsSync(indexPath)) {\n try {\n const data = fs.readJsonSync(indexPath);\n if (Array.isArray(data)) entries.push(...data);\n } catch {\n // skip invalid JSON\n }\n }\n }\n\n // Deduplicate by path\n const seen = new Set<string>();\n return entries.filter((e) => {\n if (seen.has(e.path)) return false;\n seen.add(e.path);\n return true;\n });\n}\n\nconst DEFAULT_LIMIT = 5;\nconst DEFAULT_LINES_PER_NOTE = 30;\n\nexport async function queryCommand(\n keywords: string,\n options: { limit?: string; brief?: boolean; full?: boolean; repo?: string },\n): Promise<void> {\n const kbPath = getKbPath();\n if (!kbPath) {\n log.error(\"KB 경로가 설정되지 않았습니다. kb init 또는 kb join을 먼저 실행하세요.\");\n process.exit(1);\n }\n\n const kwList = keywords\n .split(/\\s+/)\n .map((k) => k.trim())\n .filter(Boolean);\n\n if (kwList.length === 0) {\n log.error(\"검색 키워드를 입력하세요.\");\n process.exit(1);\n }\n\n const entries = loadIndex(kbPath);\n if (entries.length === 0) {\n log.warn(\"인덱스가 비어있습니다. kb index를 실행하세요.\");\n return;\n }\n\n // Score and filter (OR matching: score > 0 means at least one keyword matched)\n const scored: ScoredEntry[] = entries\n .map((e) => ({ ...e, score: scoreEntry(e, kwList, options.repo) }))\n .filter((e) => e.score > 0)\n .sort((a, b) => b.score - a.score);\n\n const limit = options.limit ? parseInt(options.limit, 10) : DEFAULT_LIMIT;\n const top = scored.slice(0, limit);\n\n if (top.length === 0) {\n console.log(\"검색 결과 없음\");\n return;\n }\n\n console.log(`${pc.blue(`[${scored.length}개 매칭, 상위 ${top.length}개 표시]`)}\\n`);\n\n for (const entry of top) {\n const trust = getTrustLevel(entry.path);\n const header = `${pc.green(\"##\")} ${entry.path} ${pc.gray(`[${trust}]`)}`;\n console.log(header);\n console.log(`${pc.gray(\"tags:\")} ${entry.tags.join(\", \")}`);\n console.log(`${pc.gray(\"tldr:\")} ${entry.tldr}`);\n\n if (!options.brief) {\n const fullPath = path.join(kbPath, entry.path.replace(/^\\.\\//, \"\"));\n if (fs.existsSync(fullPath)) {\n const content = fs.readFileSync(fullPath, \"utf-8\");\n // Strip frontmatter\n const body = content.replace(/^---[\\s\\S]*?---\\s*/, \"\").trim();\n if (body) {\n const lines = body.split(\"\\n\");\n const maxLines = options.full ? lines.length : DEFAULT_LINES_PER_NOTE;\n const display = lines.slice(0, maxLines).join(\"\\n\");\n console.log();\n console.log(display);\n if (!options.full && lines.length > maxLines) {\n console.log(pc.gray(`\\n... (${lines.length - maxLines}줄 더)`));\n }\n }\n }\n }\n console.log();\n }\n}\n"],"mappings":"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","names":["fs","path","fs","fs","path","fs","input","fs","path","path","input","fs","input","fs","path","fs","path","fs","path","fs","path","path","fs","path","fs","fs","path","path","fs","fs","path","path","fs","input","fs","path","fs","path","fs","path","path","fs","fs","path","path","fs","fs","path","pc","path","fs","pc","require"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@01b/team-kb",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Team Knowledge Base harness CLI - scaffold, wire, and manage KB for LLM-assisted development",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"@inquirer/prompts": "^7.0.0",
|
|
20
20
|
"commander": "^13.0.0",
|
|
21
21
|
"fs-extra": "^11.0.0",
|
|
22
|
+
"gray-matter": "^4.0.3",
|
|
22
23
|
"picocolors": "^1.0.0",
|
|
23
24
|
"simple-git": "^3.0.0"
|
|
24
25
|
},
|
|
@@ -34,6 +34,9 @@ jobs:
|
|
|
34
34
|
if ! grep -q 'tldr:' "$f"; then
|
|
35
35
|
echo "MISSING tldr: $f"; ERRORS=$((ERRORS+1))
|
|
36
36
|
fi
|
|
37
|
+
if ! grep -q 'tags:' "$f"; then
|
|
38
|
+
echo "MISSING tags: $f"; ERRORS=$((ERRORS+1))
|
|
39
|
+
fi
|
|
37
40
|
done
|
|
38
41
|
if [ $ERRORS -gt 0 ]; then exit 1; fi
|
|
39
42
|
|
|
@@ -46,26 +49,28 @@ jobs:
|
|
|
46
49
|
|
|
47
50
|
- name: 빈 노트 탐지
|
|
48
51
|
run: |
|
|
49
|
-
find . -name '*.md' -not -path './.kb/*' -not -path './templates/*' \
|
|
50
|
-
-
|
|
52
|
+
FOUND=$(find . -name '*.md' -not -path './.kb/*' -not -path './templates/*' \
|
|
53
|
+
-not -path './99-personal/*' -not -path './00-inbox/*' \
|
|
54
|
+
-not -path './.github/*' -not -name 'README.md' \
|
|
55
|
+
-size -50c)
|
|
56
|
+
if [ -n "$FOUND" ]; then
|
|
57
|
+
echo "ERROR: 빈 노트 발견:"
|
|
58
|
+
echo "$FOUND"
|
|
59
|
+
exit 1
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
- name: Node.js 설치
|
|
63
|
+
uses: actions/setup-node@v4
|
|
64
|
+
with:
|
|
65
|
+
node-version: '18'
|
|
51
66
|
|
|
52
67
|
- name: kb-index.json 갱신
|
|
53
68
|
run: |
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
-not -path './.github/*' -not -name 'README.md'); do
|
|
60
|
-
TAGS=$(grep -m1 'tags:' "$f" 2>/dev/null | sed 's/tags: *//')
|
|
61
|
-
TLDR=$(grep -m1 'tldr:' "$f" 2>/dev/null | sed 's/tldr: *//')
|
|
62
|
-
UPDATED=$(grep -m1 'updated:' "$f" 2>/dev/null | sed 's/updated: *//')
|
|
63
|
-
if [ "$FIRST" = true ]; then FIRST=false; else echo "," >> kb-index.json; fi
|
|
64
|
-
printf ' {"path":"%s","tags":%s,"tldr":%s,"updated":"%s"}' \
|
|
65
|
-
"$f" "${TAGS:-[]}" "${TLDR:-\"\"}" "${UPDATED:-unknown}" >> kb-index.json
|
|
66
|
-
done
|
|
67
|
-
echo "" >> kb-index.json
|
|
68
|
-
echo "]" >> kb-index.json
|
|
69
|
+
npx @01b/team-kb index
|
|
70
|
+
|
|
71
|
+
- name: kb-index.json 유효성 검증
|
|
72
|
+
run: |
|
|
73
|
+
node -e "JSON.parse(require('fs').readFileSync('kb-index.json','utf-8'))"
|
|
69
74
|
|
|
70
75
|
- name: kb-index.json 커밋
|
|
71
76
|
run: |
|
|
@@ -8,13 +8,12 @@ updated: {{date}}
|
|
|
8
8
|
- 도메인 지식 질문(비즈니스 룰, 시스템 동작, 아키텍처)은 코드 탐색 전에 KB를 먼저 확인할 것
|
|
9
9
|
- KB는 가이드, 코드가 source of truth. 코드 동작에 대한 답변 시 관련 코드도 가볍게 확인할 것
|
|
10
10
|
- KB와 코드가 불일치하면 코드 기준 답변 + 불일치 보고 + KB 업데이트 제안
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
- 검색 결과가 많으면 현재 repo 관련 노트를 먼저 확인하되, 다른 repo의 노트도 관련 있으면 포함할 것
|
|
11
|
+
- 검색은 `kb query` 커맨드를 사용할 것 (인덱스 파일을 직접 읽지 말 것)
|
|
12
|
+
- `kb query "키워드1 키워드2"` — 공백 구분, OR 매칭으로 관련 노트를 검색하여 내용 표시
|
|
13
|
+
- 한/영 키워드를 모두 포함하면 검색 정확도가 높아짐 (예: `kb query "쿠폰 coupon discount"`)
|
|
14
|
+
- 현재 repo와 관련된 노트를 우선하려면 `--repo` 옵션 사용
|
|
15
|
+
- 결과 목록만 먼저 보려면 `--brief` 옵션 사용
|
|
16
|
+
- `kb query`가 없으면 (구버전 CLI): kb-index.json에서 tags/tldr을 Grep으로 키워드 검색
|
|
18
17
|
|
|
19
18
|
## KB 기록 규칙
|
|
20
19
|
- 코딩/분석 중 새로운 비즈니스 룰, 코드 패턴, 장애 원인을 발견하면 KB에 기록 제안
|
|
@@ -30,7 +29,7 @@ updated: {{date}}
|
|
|
30
29
|
- frontmatter 필수: tags, tldr, created, updated
|
|
31
30
|
- 태그 네이밍: 네임스페이스는 `/`로 구분 (예: `repo/gmkt-dc-api`, `tech/redis`, `domain/coupon`)
|
|
32
31
|
- 템플릿(templates/)의 형식을 따를 것
|
|
33
|
-
- 노트를 생성/수정/이동한 직후,
|
|
32
|
+
- 노트를 생성/수정/이동한 직후, `kb index`를 실행하여 인덱스를 최신화할 것
|
|
34
33
|
|
|
35
34
|
## KB 갭 인식
|
|
36
35
|
- KB 검색 결과 관련 노트가 없으면 사용자에게 알릴 것
|
|
@@ -36,8 +36,12 @@ if [ $ERRORS -gt 0 ]; then exit 1; fi
|
|
|
36
36
|
# Auto-rebuild index if .md files changed
|
|
37
37
|
STAGED_MD=$(git diff --cached --name-only --diff-filter=ACDMR -- '*.md')
|
|
38
38
|
if [ -n "$STAGED_MD" ]; then
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
if command -v kb &> /dev/null && kb index --help &> /dev/null 2>&1; then
|
|
40
|
+
kb index > /dev/null
|
|
41
|
+
else
|
|
42
|
+
"$KB_ROOT/.kb/scripts/rebuild-index.sh" > /dev/null
|
|
43
|
+
cp "$KB_ROOT/.kb-index.local.json" "$KB_ROOT/kb-index.json"
|
|
44
|
+
fi
|
|
41
45
|
git add "$KB_ROOT/kb-index.json" 2>/dev/null
|
|
42
46
|
echo "kb-index 자동 갱신 완료"
|
|
43
47
|
fi
|