project-librarian 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ko.md +42 -11
- package/README.md +39 -9
- package/SKILL.md +1 -0
- package/dist/args.js +20 -3
- package/dist/code-index/evidence.js +79 -0
- package/dist/code-index/extractors/config.js +58 -0
- package/dist/code-index/extractors/light-languages.js +52 -0
- package/dist/code-index/extractors/registry.js +137 -0
- package/dist/code-index/extractors/shared.js +36 -0
- package/dist/code-index/extractors/tree-sitter.js +319 -0
- package/dist/code-index/extractors/types.js +2 -0
- package/dist/code-index/extractors/typescript.js +211 -0
- package/dist/code-index/incremental.js +16 -0
- package/dist/code-index/index-health.js +164 -0
- package/dist/code-index/modes.js +303 -0
- package/dist/code-index/ownership.js +183 -0
- package/dist/code-index/reports.js +322 -0
- package/dist/code-index/schema.js +196 -0
- package/dist/code-index/search.js +153 -0
- package/dist/code-index-file-policy.js +21 -27
- package/dist/code-index.js +224 -1657
- package/dist/init-project-wiki.js +65 -37
- package/dist/mcp-server.js +325 -11
- package/dist/migration.js +10 -6
- package/dist/modes.js +139 -54
- package/dist/path-ignore-policy.js +30 -0
- package/dist/retrieval-eval.js +68 -0
- package/dist/wiki-concepts.js +49 -0
- package/dist/wiki-corpus.js +25 -0
- package/dist/wiki-diagnostics.js +19 -0
- package/dist/wiki-files.js +107 -1
- package/dist/wiki-graph.js +26 -2
- package/dist/wiki-visualizer.js +558 -0
- package/package.json +11 -4
package/README.ko.md
CHANGED
|
@@ -38,6 +38,7 @@ npx project-librarian install-skill --scope project --agents all
|
|
|
38
38
|
- **첫 읽기를 작게.** 세션 시작 훅은 `wiki/startup.md`와 `wiki/index.md`만 주입하고, 에이전트는 저장소 전체를 처음부터 훑는 대신 필요할 때 더 깊은 페이지로 이동합니다.
|
|
39
39
|
- **한 번 설정, 네 에이전트.** Codex, Claude Code, Cursor, Gemini CLI가 같은 위키 우선 계약과 훅, 규칙을 공유합니다.
|
|
40
40
|
- **구조적인 위키 작성.** 새 프로젝트 내용은 작성하거나 취합하기 전에 `wiki/meta/document-taxonomy.md`로 분류하므로 PRD, 정책, UX, 데이터, API, QA, 릴리즈, 운영 메모가 하나의 잡다한 페이지로 합쳐지지 않습니다.
|
|
41
|
+
- **검토 가능한 위키 그래프.** `--wiki-visualize`는 `.project-wiki/` 아래에 독립 실행형 HTML 그래프를 작성해, 시작 컨텍스트를 늘리지 않고 페이지 유형·라우터 깊이·역링크·결정 참조를 보여줍니다.
|
|
41
42
|
- **막연한 표현이 아니라 측정값.** 모든 성능 주장은 격리된 Codex 벤치마크에서 나오며, 손해를 본 경우도 이긴 경우 바로 옆에 보여 줍니다.
|
|
42
43
|
- **선택적 코드 근거.** 재생성 가능한 SQLite 인덱스와 답변 형태 MCP 도구가 영향·소유권·워크스페이스 그래프 질문에 답하며, 추가 런타임 의존성이 전혀 없습니다.
|
|
43
44
|
- **다시 실행해도 안전.** 부트스트랩은 멱등하고 기존 내용 보존을 우선하며, 진단은 깨진 경로·도달 불가 페이지·오래된 사실을 에이전트가 오해하기 전에 잡아냅니다.
|
|
@@ -56,6 +57,7 @@ Project Librarian은 에이전트에게 두 가지 로컬 정본을 제공합니
|
|
|
56
57
|
| `.codex/`, `.claude/`, `.cursor/`, `.gemini/` 훅 | 전체 위키를 불러오지 않는 Codex/Claude Code/Cursor/Gemini CLI 시작 컨텍스트. |
|
|
57
58
|
| `GEMINI.md` 및 `.cursor/rules/` | Gemini CLI와 Cursor를 같은 간결한 위키 우선 계약으로 안내하는 지침 파일. |
|
|
58
59
|
| `.project-wiki/code-evidence.sqlite` | 파일, 심볼, import, route, 소유권, 워크스페이스 그래프, 보고서, 영향 확인을 위한 재생성 가능한 코드 근거. |
|
|
60
|
+
| `.project-wiki/wiki-graph.html` | 파생 concept type, 라우터 도달성, 링크, 역링크, 결정 참조를 보여주는 선택적 정적 위키 그래프 시각화. |
|
|
59
61
|
| 진단 및 마이그레이션 모드 | 링크 확인, 품질 확인, 마이그레이션 수신함, 오래된 신호 보고, 작업 흐름에서 문제가 드러날 때의 이슈 초안. |
|
|
60
62
|
|
|
61
63
|
핵심은 “문서를 더 많이 쓰자”가 아닙니다. 첫 에이전트 읽기량을 작게 유지하고, 더 깊은 프로젝트 정본과 코드 근거로 가는 신뢰 가능한 경로를 제공하는 것입니다.
|
|
@@ -69,7 +71,8 @@ Project Librarian은 에이전트에게 두 가지 로컬 정본을 제공합니
|
|
|
69
71
|
아래 표에서 **“적음” / “많음”** 은 대조군 대비 비용 가중 토큰을, **“빠름” / “느림”** 은 실행 시간을 비교한 것입니다. (비용 가중 = uncached input + 0.1 × cached input + output + reasoning output. 캐시된 재전송은 정가가 아니므로 할인하며, 단순 합산 총량은 턴을 추가하는 도구를 부당하게 불리하게 만들기 때문입니다.) 위키 라우팅 트랙과 코드 그래프 트랙은 분리해 측정·보고하며, 한 트랙의 우위가 다른 트랙의 주장을 뒷받침하지 않습니다. `benchmarks/reports/llm/` 아래 생성 보고서는 기본적으로 무시됩니다. 공개 주장 근거로 쓸 릴리스 기준선만 의도적으로 커밋해야 합니다. 릴리스 후보는 다음 명령으로 재현할 수 있습니다.
|
|
70
72
|
|
|
71
73
|
```bash
|
|
72
|
-
npm run benchmark:release
|
|
74
|
+
npm run benchmark:release:preview
|
|
75
|
+
npm run benchmark:release -- --allow-codex-run
|
|
73
76
|
```
|
|
74
77
|
|
|
75
78
|
### 위키 트랙 (계획 문서 라우팅)
|
|
@@ -78,11 +81,11 @@ npm run benchmark:release
|
|
|
78
81
|
|
|
79
82
|
| 규모 | decision_lookup | aggregation | multi_session (2번째 세션) |
|
|
80
83
|
| --- | --- | --- | --- |
|
|
81
|
-
| 소형 |
|
|
82
|
-
| 중형 |
|
|
83
|
-
| 대형
|
|
84
|
+
| 소형 | 43.8% 적음 | 144.5% 많음 | 5.4% 많음 |
|
|
85
|
+
| 중형 | 53.4% 적음 | 4.4% 적음 | 68.5% 적음 |
|
|
86
|
+
| 대형 | 71.6% 적음* | 12.8% 적음 | 66.0% 적음 |
|
|
84
87
|
|
|
85
|
-
|
|
88
|
+
최신 합성 위키 트랙 릴리스 후보는 2026-06-16에 `gpt-5.5`로 측정했으며, 42개 시나리오를 각 3회 측정하고 1회 예열했습니다. 전체 주장 게이트는 **실패**했습니다. 42개 중 41개 시나리오는 정확성 검사를 통과했지만, Project Librarian이 없는 대형 `decision_lookup` 대조군이 3회 중 2회만 정답이었습니다. 실패한 대조군 실행은 날짜가 붙은 히스토리 파일에서 `2026-05-04`를 골랐고, 기대값은 결정 로그의 최신 벤치마크 근거 결정인 `2026-06-10`이었습니다. 따라서 이 표는 공개 릴리스 주장이 아니라 진단 근거로만 보아야 하며, 깨끗한 릴리스 실행이 주장 게이트를 통과해야 공개 주장으로 쓸 수 있습니다. 숨기지 않는 한계도 그대로 남습니다. 소형 `aggregation`은 위키를 켰을 때 훨씬 비싸고, 소형 `multi_session`도 약간 더 비싸며, `aggregation`은 토큰 비용이 줄어드는 규모에서도 실행 시간은 매번 더 느립니다.
|
|
86
89
|
|
|
87
90
|
### 코드 그래프 트랙 (코드 근거 인덱스, 실제 저장소)
|
|
88
91
|
|
|
@@ -164,12 +167,14 @@ npx project-librarian install-skill --scope project --agents all
|
|
|
164
167
|
| 목적 | 에이전트에게 요청할 말 | 내부 액션 |
|
|
165
168
|
| --- | --- | --- |
|
|
166
169
|
| 위키 생성 또는 갱신 | "Project Librarian으로 이 저장소의 계획 위키를 설정하거나 갱신해줘." | `[init]` |
|
|
170
|
+
| 마이그레이션 없이 기존 설정 갱신 | "위키를 마이그레이션하지 말고 이 저장소의 Project Librarian 설정을 갱신해줘." | `update` |
|
|
167
171
|
| 기존 문서/위키 마이그레이션 | "Project Librarian으로 기존 docs/wiki 내용을 마이그레이션해줘." | `--migrate` |
|
|
168
172
|
| 생성된 설정 검증 | "Project Librarian 검증을 실행해줘." | `--lint` |
|
|
169
173
|
| 링크와 문서 품질 점검 | "Project Librarian 진단을 실행해줘." | `--doctor` |
|
|
170
174
|
| 진단 전에 생성된 라우팅 갱신 | "Project Librarian 라우팅을 갱신한 뒤 진단을 실행해줘." | `--doctor --fix` |
|
|
171
175
|
| 위키 내용 검색 | "Project Librarian 위키에서 authentication decisions를 찾아줘." | `--query "authentication decisions"` |
|
|
172
176
|
| 페이지의 역링크/결정 인용 확인 | "decisions/release-policy의 Project Librarian 위키 영향도를 보여줘." | `--wiki-impact "decisions/release-policy"` |
|
|
177
|
+
| 위키 그래프 시각화 생성 | "Project Librarian 위키 그래프 시각화를 생성해줘." | `--wiki-visualize` |
|
|
173
178
|
| 후보 메모 저장 | "이 내용을 Project Librarian 후보 메모로 저장해줘: <내용>." | `--capture-inbox --title "Candidate" --content "Details"` |
|
|
174
179
|
| 오래되었거나 미해결인 위키 페이지 보고 | "Project Librarian에서 오래되었거나 미해결인 페이지를 확인해줘." | `--prune-check` |
|
|
175
180
|
| git 설정 변경 없이 훅 파일 설치 | "git 설정은 바꾸지 말고 Project Librarian 훅 파일만 설정해줘." | `--no-git-config` |
|
|
@@ -183,11 +188,13 @@ npx project-librarian install-skill --scope project --agents all
|
|
|
183
188
|
| 증분 갱신 요구 | "Project Librarian 코드 근거 인덱스를 증분 갱신해줘." | `--code-index --incremental` |
|
|
184
189
|
| 전체 재생성 강제 | "Project Librarian 코드 근거 인덱스를 전체 재생성해줘." | `--code-index --code-index-full` |
|
|
185
190
|
| 선택적 Tree-sitter 백엔드 사용 | "Tree-sitter 파서로 Project Librarian 코드 근거를 만들어줘." | `--code-index --code-parser tree-sitter` |
|
|
191
|
+
| 캐시 호환성 진단 | "Project Librarian 코드 근거 캐시 health를 확인해줘." | `--code-index-health` |
|
|
186
192
|
| 캐시 상태 보기 | "Project Librarian 코드 근거 상태를 보여줘." | `--code-status` |
|
|
187
193
|
| 인덱싱된 파일 목록 | "Project Librarian 코드 근거에 인덱싱된 파일을 보여줘." | `--code-files` |
|
|
188
194
|
| 아키텍처/소유권 보고서 출력 | "Project Librarian 코드 보고서를 보여줘." | `--code-report` |
|
|
189
195
|
| 보고서 섹션 하나만 출력 | "Project Librarian 코드 보고서의 routes 섹션을 보여줘." | `--code-report --code-report-section routes` |
|
|
190
196
|
| 영향 근거 확인 | "`healthHandler`에 대한 Project Librarian 영향 근거를 보여줘." | `--code-impact healthHandler` |
|
|
197
|
+
| 컨텍스트 팩 생성 | "`healthHandler`에 대한 Project Librarian 컨텍스트 팩을 만들어줘." | `--code-context-pack healthHandler` |
|
|
191
198
|
| 인덱싱된 심볼 검색 | "Project Librarian 코드 근거에서 `Auth` 심볼을 찾아줘." | `--code-search-symbol Auth` |
|
|
192
199
|
| 보수적인 읽기 전용 SQL 실행 | "파일 경로를 확인하는 읽기 전용 Project Librarian 코드 근거 쿼리를 실행해줘." | `--code-query "select path from files order by path"` |
|
|
193
200
|
|
|
@@ -234,7 +241,7 @@ Git 훅 파일:
|
|
|
234
241
|
- `wiki/index.md`
|
|
235
242
|
- `wiki/meta/document-taxonomy.md`
|
|
236
243
|
|
|
237
|
-
`canonical/project-brief.md`, `canonical/open-questions.md`, `canonical/assumptions.md`, `canonical/risks.md`, ADR 템플릿처럼 실제 내용이 없는 빈 프로젝트 문서는 기본 생성하지 않습니다. 나중에 실제 내용이 생기면 문서를 만들고 `--refresh-index`로 라우팅할 수 있습니다. 마이그레이션 중 발견한 양식 전용
|
|
244
|
+
`canonical/project-brief.md`, `canonical/open-questions.md`, `canonical/assumptions.md`, `canonical/risks.md`, ADR 템플릿처럼 실제 내용이 없는 빈 프로젝트 문서는 기본 생성하지 않습니다. 나중에 실제 내용이 생기면 문서를 만들고 `--refresh-index`로 라우팅할 수 있습니다. 마이그레이션 중 발견한 양식 전용 기존 템플릿은 새 위키 페이지나 검토 행으로 만들지 않고 `wiki/migration/inventory.md`에 스킵 사유만 남깁니다.
|
|
238
245
|
|
|
239
246
|
MCP 서버 등록 (`mcpServers`에 기존 항목 보존하며 병합):
|
|
240
247
|
|
|
@@ -248,7 +255,9 @@ MCP 서버 등록 (`mcpServers`에 기존 항목 보존하며 병합):
|
|
|
248
255
|
|
|
249
256
|
## 코드 근거 MCP 서버
|
|
250
257
|
|
|
251
|
-
`project-librarian mcp`는 직접 구현한 stdio MCP 서버(줄바꿈 구분 JSON 위의 JSON-RPC 2.0, 추가 런타임 의존성 없음)를 실행해 기존 `.project-wiki` 코드 근거 인덱스를 읽기 전용으로 제공합니다. 답변 형태 도구 — `code_impact`, `code_ownership`(CODEOWNERS 마지막 일치 우선순위), `code_workspace_graph`, `code_search`, `code_status` — 를 노출하며, 각 응답은 한 줄 답변으로 시작해 간결한 경로/심볼/시그니처 근거가 뒤따르고, 응답마다 길이를 제한하며, `code_status`가 인덱스가 오래되었다고 보고하면 경고를 앞에 붙입니다.
|
|
258
|
+
`project-librarian mcp`는 직접 구현한 stdio MCP 서버(줄바꿈 구분 JSON 위의 JSON-RPC 2.0, 추가 런타임 의존성 없음)를 실행해 기존 `.project-wiki` 코드 근거 인덱스를 읽기 전용으로 제공합니다. 답변 형태 도구 — `code_context_pack`, `code_impact`, `code_ownership`(CODEOWNERS 마지막 일치 우선순위), `code_workspace_graph`, `code_search`, `code_status` — 를 노출하며, 각 응답은 한 줄 답변으로 시작해 간결한 경로/심볼/시그니처 근거가 뒤따르고, 응답마다 길이를 제한하며, `code_status`가 인덱스가 오래되었다고 보고하면 경고를 앞에 붙입니다.
|
|
259
|
+
|
|
260
|
+
서버는 고정 리소스 — `project-librarian://wiki/startup`, `project-librarian://wiki/index`, `project-librarian://code/status` — 와 위키 분류 갱신, 코드 영향 추적, 검색 품질 검토용 프롬프트 템플릿도 제공합니다. 리소스 읽기는 임의 파일 경로가 아니라 고정 URI 레지스트리에서만 처리합니다.
|
|
252
261
|
|
|
253
262
|
부트스트랩은 Claude Code(`.mcp.json`), Cursor(`.cursor/mcp.json`), Gemini CLI(`.gemini/settings.json`의 `mcpServers`)에 서버를 등록하며, 기존 서버와 키를 보존하고 다시 실행하면 `exists`를 보고합니다. 저장소에 로컬 실행 경로가 있으면 `node <runner> mcp`로, 없으면 설치된 `project-librarian mcp` 바이너리로 등록합니다.
|
|
254
263
|
|
|
@@ -267,10 +276,13 @@ codex mcp add project-librarian -- node .codex/skills/project-librarian/dist/ini
|
|
|
267
276
|
5. 새 프로젝트 계획 내용은 작성하거나 취합하기 전에 `wiki/meta/document-taxonomy.md`로 분류해 상위/하위 문서 관계가 보이도록 유지합니다.
|
|
268
277
|
6. `--refresh-index`는 새로 발견한 위키 페이지를 라우팅하며, route가 많으면 `wiki/indexes/auto-*.md` 범위별 라우터로 분리합니다.
|
|
269
278
|
7. `--code-index`는 `.project-wiki/` 아래 폐기 가능한 SQLite 근거 캐시를 만듭니다.
|
|
270
|
-
8. `--code-report`, `--code-impact`, `--code-search-symbol`, `--code-query`가 계획 갱신용 코드 근거를 제공합니다.
|
|
271
|
-
9.
|
|
279
|
+
8. `--code-report`, `--code-impact`, `--code-context-pack`, `--code-search-symbol`, `--code-query`가 계획 갱신용 코드 근거를 제공합니다.
|
|
280
|
+
9. 읽기 전용 위키 소비자는 공통 개념 읽기 모델을 사용해 정본 위키 스키마를 다시 쓰지 않고 경로와 frontmatter에서 사용자용 페이지 유형을 파생합니다.
|
|
281
|
+
10. 위키 생산자는 기존 Markdown/YAML 정본 스키마를 계속 작성하고, 진단·MCP·시각화 같은 읽기 전용 소비자는 원본 문서를 바꾸지 않는 파생 보기를 사용합니다.
|
|
282
|
+
11. `--wiki-visualize`는 데이터베이스나 서버를 추가하지 않고 기존 위키 그래프와 개념 읽기 모델을 재사용해 `.project-wiki/` 아래 정적 그래프 산출물을 작성합니다.
|
|
283
|
+
12. 진단은 깨진 링크, 중복 route, 고아 페이지, 오래된 페이지, 누락된 TL;DR, 근거 누락, 마이그레이션 정책 위반을 보고합니다.
|
|
272
284
|
|
|
273
|
-
마이그레이션은 검토를 우선합니다. `--migrate`는 기존 `wiki/`를 `wiki_legacy*`로 보존하고, 양식 전용
|
|
285
|
+
마이그레이션은 검토를 우선합니다. `--migrate`는 기존 `wiki/`를 `wiki_legacy*`로 보존하고, 양식 전용 기존 파일은 제외한 뒤, 여러 성격의 내용이 섞인 기존 페이지를 의미 단위로 나눕니다. 이후 각 단위를 문서 분류 체계에 따라 분류해 `wiki/migration/` 아래 검토 파일을 작성합니다.
|
|
274
286
|
|
|
275
287
|
- `inventory.md`는 기존 마크다운 파일 목록과 파일 단위 분류를 기록합니다.
|
|
276
288
|
- `unit-map.md`는 각 제목, 문단, 목록 항목, 표 행, 코드 블록의 권장 분류 영역과 대상 페이지를 기록합니다.
|
|
@@ -308,10 +320,12 @@ codex mcp add project-librarian -- node .codex/skills/project-librarian/dist/ini
|
|
|
308
320
|
자동화나 직접 CLI 실행에는 확인된 로컬 실행 경로를 사용합니다.
|
|
309
321
|
|
|
310
322
|
```bash
|
|
311
|
-
node .codex/skills/project-librarian/dist/init-project-wiki.js [init] [options]
|
|
323
|
+
node .codex/skills/project-librarian/dist/init-project-wiki.js [init|update] [options]
|
|
312
324
|
node .codex/skills/project-librarian/dist/init-project-wiki.js install-skill [--scope user|project] [--agents codex|claude|cursor|gemini|all]
|
|
313
325
|
```
|
|
314
326
|
|
|
327
|
+
`update`는 기존 프로젝트 설정을 명시적으로 갱신하는 명령입니다. `--migrate`와 `--adopt-existing`는 함께 쓸 수 없습니다. 기존 문서나 위키를 `wiki_legacy*`로 보존하고 검토해야 할 때는 최상위 `--migrate`를 사용합니다.
|
|
328
|
+
|
|
315
329
|
중요 옵션:
|
|
316
330
|
|
|
317
331
|
| 옵션 | 용도 |
|
|
@@ -327,6 +341,8 @@ node .codex/skills/project-librarian/dist/init-project-wiki.js install-skill [--
|
|
|
327
341
|
| `--migration-doctor` | migration-lint와 migration-quality-check를 함께 실행합니다. |
|
|
328
342
|
| `--query <terms>` | 위키 경로, 메타데이터, 제목, 본문을 검색합니다. 답변 우선 출력에 페이지별 TL;DR 줄을 붙이고 고정 크기 상한을 적용합니다. |
|
|
329
343
|
| `--wiki-impact <page-or-term>` | 일치하는 페이지의 위키 역링크, `decision_ref` 인용, 나가는 링크, 라우터 깊이를 보여줍니다. |
|
|
344
|
+
| `--wiki-visualize` | `.project-wiki/wiki-graph.html`에 독립 실행형 정적 위키 그래프 시각화를 작성합니다. |
|
|
345
|
+
| `--wiki-visualize-out <path>` | `--wiki-visualize`와 함께 사용해 `.project-wiki/` 아래의 사용자 지정 저장소 상대 경로에 작성합니다. |
|
|
330
346
|
| `--refresh-index` | 생성된 자동 발견 위키 라우팅을 갱신합니다. |
|
|
331
347
|
| `--capture-inbox --title <title> --content <content>` | 위키 수신함에 후보 메모를 추가합니다. |
|
|
332
348
|
| `--issue-draft --issue-title <title>` | 문제 또는 부작용에 대한 읽기 전용 GitHub 이슈 본문 초안을 출력합니다. |
|
|
@@ -336,9 +352,11 @@ node .codex/skills/project-librarian/dist/init-project-wiki.js install-skill [--
|
|
|
336
352
|
| `--review-migration`, `--semantic-migrate` | 마이그레이션 coverage와 수신함 상태를 마이그레이션 검토 파일에 동기화합니다. |
|
|
337
353
|
| `--no-git-config` | `git core.hooksPath`를 바꾸지 않고 훅 파일을 설치합니다. |
|
|
338
354
|
| `--code-index` | 폐기 가능한 코드 근거 인덱스를 빌드합니다. |
|
|
355
|
+
| `--code-index-health` | 코드 근거 캐시 호환성을 검사하고 쓰기 없이 재빌드 안내를 출력합니다. |
|
|
339
356
|
| `--code-report` | 근거 인덱스에서 아키텍처/소유권 요약을 출력합니다. |
|
|
340
357
|
| `--code-report-section <section>` | 한 섹션만 출력: `coverage`, `ownership`, `languages`, `parsers`, `workspaces`, `workspace-graph`, `routes`, `hotspots`, `configs`, `edges`. |
|
|
341
358
|
| `--code-impact <term>` | 파일, 심볼, route, import, edge, 소유자 영향 근거를 보여줍니다. |
|
|
359
|
+
| `--code-context-pack <term>` | 구조적 파일, 심볼, route, import, edge, 소유권 근거를 담은 예산 제한 1차 컨텍스트 팩을 출력합니다. |
|
|
342
360
|
| `--code-search-symbol <term>` | 인덱싱된 심볼을 검색합니다. |
|
|
343
361
|
| `--code-query <sql>` | 근거 인덱스에 대해 보수적인 읽기 전용 SQL을 실행합니다. |
|
|
344
362
|
|
|
@@ -351,13 +369,26 @@ npm install
|
|
|
351
369
|
npm run typecheck
|
|
352
370
|
npm run build
|
|
353
371
|
npm test
|
|
372
|
+
npm run benchmark:claim-ledger
|
|
373
|
+
npm run release:check
|
|
354
374
|
npm pack --dry-run
|
|
355
375
|
```
|
|
356
376
|
|
|
357
377
|
`src/` 아래 TypeScript를 수정할 때는 커밋 전에 빌드해 `dist/`를 최신 상태로 유지하세요.
|
|
358
378
|
|
|
379
|
+
`npm run release:check`는 로컬 전용 관리자 게이트입니다. 테스트, 벤치마크 파서 smoke, 벤치마크 release preview, 벤치마크 claim ledger 분류, package dry-run 검사, dist 실행 가능 여부, README 벤치마크 claim 경계 문구를 확인합니다. publish하지 않고 measured Codex 벤치마크도 실행하지 않습니다.
|
|
380
|
+
|
|
359
381
|
관리자 벤치마크 명령은 [benchmarks/README.md](benchmarks/README.md)에 있습니다. 이 명령은 릴리스 근거와 공개 주장 검증을 위한 것이며, 일반 사용자 설정 절차가 아닙니다.
|
|
360
382
|
|
|
383
|
+
코드 근거 런타임/스토리지 점검에는 `npm run perf:code-efficiency`를 사용합니다. 이 명령은 3k/10k/50k 픽스처를 생성하고 `benchmarks/reports/code-performance-efficiency/current.json`과 `.md`를 작성합니다. 명령 시간에는 CLI 시작과 freshness 확인이 포함되며, `query_groups` 섹션은 대표 file/symbol/route/import/edge 쿼리의 직접 DB 시간을 따로 보고합니다. 보고서에는 `mixed-monorepo`를 포함한 체크인 샘플 corpus도 합성 scale fixture와 분리해 포함됩니다.
|
|
384
|
+
|
|
385
|
+
무시된 오래된 LLM 벤치마크 raw 출력은 격리 Codex home을 삭제하기 전에 dry-run-first 헬퍼로 먼저 감사할 수 있습니다.
|
|
386
|
+
|
|
387
|
+
```bash
|
|
388
|
+
npm run benchmark:llm:prune-raw -- --older-than-days 14
|
|
389
|
+
npm run benchmark:llm:prune-raw -- --older-than-days 14 --execute
|
|
390
|
+
```
|
|
391
|
+
|
|
361
392
|
## 영감
|
|
362
393
|
|
|
363
394
|
이 프로젝트는 Andrej Karpathy의 [LLM Wiki](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f) 패턴에서 영감을 받았습니다. 긴 대화 기록에서 프로젝트 상태를 재구성하는 대신, 지속되는 markdown 컨텍스트를 작업 가까이에 둡니다.
|
package/README.md
CHANGED
|
@@ -38,6 +38,7 @@ npx project-librarian install-skill --scope project --agents all
|
|
|
38
38
|
- **Small first read.** Session-start hooks inject only `wiki/startup.md` and `wiki/index.md`; agents route to deeper pages on demand instead of grepping the whole repo cold.
|
|
39
39
|
- **One setup, four agents.** Codex, Claude Code, Cursor, and Gemini CLI share the same wiki-first contract, hooks, and rules.
|
|
40
40
|
- **Structured wiki writing.** New project content is classified through `wiki/meta/document-taxonomy.md` before it is written or consolidated, so PRDs, policies, UX, data, APIs, QA, release, and operations notes do not collapse into one catch-all page.
|
|
41
|
+
- **Inspectable wiki graph.** `--wiki-visualize` writes a self-contained HTML graph under `.project-wiki/`, showing page types, router depth, backlinks, and decision references without adding to startup context.
|
|
41
42
|
- **Measured, not hand-wavy.** Every performance claim comes from hermetic Codex benchmarks — and the cases where it costs *more* are shown right next to the wins.
|
|
42
43
|
- **Optional code evidence.** A regenerable SQLite index plus answer-shaped MCP tools answer impact, ownership, and workspace-graph questions, with zero extra runtime dependencies.
|
|
43
44
|
- **Safe to re-run.** Bootstrap is idempotent and preservation-first; diagnostics flag broken routes, unreachable pages, and stale truth before they mislead an agent.
|
|
@@ -56,6 +57,7 @@ Project Librarian gives agents two local sources of truth:
|
|
|
56
57
|
| `.codex/`, `.claude/`, `.cursor/`, and `.gemini/` hooks | Automatic startup context for Codex, Claude Code, Cursor, and Gemini CLI without loading the full wiki. |
|
|
57
58
|
| `GEMINI.md` and `.cursor/rules/` | Gemini CLI and Cursor instruction files that route agents to the same compact wiki-first contract. |
|
|
58
59
|
| `.project-wiki/code-evidence.sqlite` | Regenerable code evidence for files, symbols, imports, routes, ownership, workspace graph, reports, and impact checks. |
|
|
60
|
+
| `.project-wiki/wiki-graph.html` | Optional static wiki graph visualizer with derived concept types, router reachability, links, backlinks, and decision references. |
|
|
59
61
|
| Diagnostics and migration modes | Link checks, quality checks, migration inboxes, stale-signal reports, and issue drafts when the workflow exposes a problem. |
|
|
60
62
|
|
|
61
63
|
The core idea is not "write more docs." It is "keep the first agent read small, then give it reliable routes to deeper project truth and code evidence."
|
|
@@ -69,7 +71,8 @@ These numbers are maintainer release evidence, not a blanket promise. Every valu
|
|
|
69
71
|
In the tables below, **"less" / "more"** compares cost-weighted tokens against that control, and **"faster" / "slower"** compares wall-clock time. (Cost-weighted = uncached input + 0.1 × cached input + output + reasoning output; cached resends are discounted, and raw merged totals would unfairly penalize any tool that adds a turn.) The wiki-routing track and the code-graph track are measured and reported separately — a win on one never backs a claim about the other. Generated benchmark reports under `benchmarks/reports/llm/` are ignored by default; maintainers should commit deliberate release baselines only when they are meant to support a public claim. Reproduce a release candidate with:
|
|
70
72
|
|
|
71
73
|
```bash
|
|
72
|
-
npm run benchmark:release
|
|
74
|
+
npm run benchmark:release:preview
|
|
75
|
+
npm run benchmark:release -- --allow-codex-run
|
|
73
76
|
```
|
|
74
77
|
|
|
75
78
|
### Wiki track (planning-doc routing)
|
|
@@ -78,11 +81,11 @@ Cost-weighted tokens, Project Librarian vs control:
|
|
|
78
81
|
|
|
79
82
|
| Scale | decision_lookup | aggregation | multi_session (2nd session) |
|
|
80
83
|
| --- | --- | --- | --- |
|
|
81
|
-
| Small |
|
|
82
|
-
| Medium |
|
|
83
|
-
| Large
|
|
84
|
+
| Small | 43.8% less | 144.5% more | 5.4% more |
|
|
85
|
+
| Medium | 53.4% less | 4.4% less | 68.5% less |
|
|
86
|
+
| Large | 71.6% less* | 12.8% less | 66.0% less |
|
|
84
87
|
|
|
85
|
-
|
|
88
|
+
Latest synthetic wiki-track release candidate: 2026-06-16, `gpt-5.5`, 42 scenarios, 3 measured runs plus 1 warmup each. The overall claim gate **failed**: 41/42 scenarios passed correctness, but `decision_lookup` at large scale on the no-Project-Librarian control had only 2/3 correct measured runs. The failed control run selected `2026-05-04` from a dated history file instead of the expected latest benchmark-evidence decision `2026-06-10` from the decision log. Treat this table as diagnostic evidence, not a public release claim, until a clean release run passes the claim gate. Published boundaries remain visible: small `aggregation` is much more expensive with the wiki, small `multi_session` is slightly more expensive, and `aggregation` stays slower at every scale even when token cost drops.
|
|
86
89
|
|
|
87
90
|
### Code-graph track (code evidence index, real repositories)
|
|
88
91
|
|
|
@@ -164,12 +167,14 @@ Wiki setup and maintenance:
|
|
|
164
167
|
| Goal | Ask The Agent | Internal Action |
|
|
165
168
|
| --- | --- | --- |
|
|
166
169
|
| Create or update the wiki | "Use Project Librarian to set up or update this repository's planning wiki." | `[init]` |
|
|
170
|
+
| Update existing setup without migration | "Update this repository's Project Librarian setup without migrating the wiki." | `update` |
|
|
167
171
|
| Migrate existing docs/wiki content | "Use Project Librarian to migrate the existing docs/wiki content." | `--migrate` |
|
|
168
172
|
| Validate generated setup | "Run Project Librarian validation." | `--lint` |
|
|
169
173
|
| Check links and document quality | "Run Project Librarian diagnostics." | `--doctor` |
|
|
170
174
|
| Refresh generated routing before diagnostics | "Refresh Project Librarian routing and then run diagnostics." | `--doctor --fix` |
|
|
171
175
|
| Search project wiki content | "Search the Project Librarian wiki for authentication decisions." | `--query "authentication decisions"` |
|
|
172
176
|
| Show backlinks and decision citations for a page | "Show Project Librarian wiki impact for decisions/release-policy." | `--wiki-impact "decisions/release-policy"` |
|
|
177
|
+
| Generate a wiki graph visualizer | "Generate the Project Librarian wiki graph visualizer." | `--wiki-visualize` |
|
|
173
178
|
| Capture a candidate note | "Capture this as a Project Librarian candidate note: <details>." | `--capture-inbox --title "Candidate" --content "Details"` |
|
|
174
179
|
| Report stale or unresolved wiki pages | "Check Project Librarian for stale or unresolved pages." | `--prune-check` |
|
|
175
180
|
| Install hook files without changing git config | "Set up Project Librarian hook files without changing git config." | `--no-git-config` |
|
|
@@ -188,6 +193,7 @@ Code evidence:
|
|
|
188
193
|
| Print architecture and ownership report | "Show the Project Librarian code report." | `--code-report` |
|
|
189
194
|
| Print one report section | "Show the routes section of the Project Librarian code report." | `--code-report --code-report-section routes` |
|
|
190
195
|
| Inspect impact evidence | "Show Project Librarian impact evidence for `healthHandler`." | `--code-impact healthHandler` |
|
|
196
|
+
| Build a context pack | "Build a Project Librarian context pack for `healthHandler`." | `--code-context-pack healthHandler` |
|
|
191
197
|
| Search indexed symbols | "Search Project Librarian code evidence for symbol `Auth`." | `--code-search-symbol Auth` |
|
|
192
198
|
| Run conservative read-only SQL | "Run a read-only Project Librarian code evidence query for file paths." | `--code-query "select path from files order by path"` |
|
|
193
199
|
|
|
@@ -248,7 +254,9 @@ Disposable code evidence cache:
|
|
|
248
254
|
|
|
249
255
|
## Code Evidence MCP Server
|
|
250
256
|
|
|
251
|
-
`project-librarian mcp` runs a hand-rolled stdio MCP server (JSON-RPC 2.0 over newline-delimited JSON, no extra runtime dependencies) that serves the existing `.project-wiki` code-evidence index read-only. It exposes answer-shaped tools — `code_impact`, `code_ownership` (CODEOWNERS last-match precedence), `code_workspace_graph`, `code_search`, and `code_status` — whose responses lead with a one-line answer, follow with compact path/symbol/signature evidence, cap each reply, and prepend a warning when `code_status` reports the index is stale.
|
|
257
|
+
`project-librarian mcp` runs a hand-rolled stdio MCP server (JSON-RPC 2.0 over newline-delimited JSON, no extra runtime dependencies) that serves the existing `.project-wiki` code-evidence index read-only. It exposes answer-shaped tools — `code_context_pack`, `code_impact`, `code_ownership` (CODEOWNERS last-match precedence), `code_workspace_graph`, `code_search`, and `code_status` — whose responses lead with a one-line answer, follow with compact path/symbol/signature evidence, cap each reply, and prepend a warning when `code_status` reports the index is stale.
|
|
258
|
+
|
|
259
|
+
The server also exposes fixed resources — `project-librarian://wiki/startup`, `project-librarian://wiki/index`, and `project-librarian://code/status` — plus prompt templates for wiki taxonomy updates, code impact traces, and retrieval quality reviews. Resource reads come from a fixed URI registry rather than arbitrary filesystem paths.
|
|
252
260
|
|
|
253
261
|
Bootstrap registers the server for Claude Code (`.mcp.json`), Cursor (`.cursor/mcp.json`), and Gemini CLI (`mcpServers` in `.gemini/settings.json`), preserving any existing servers and keys and reporting `exists` on a re-run. When the repository contains a local runner the registration uses `node <runner> mcp`; otherwise it uses the installed `project-librarian mcp` binary.
|
|
254
262
|
|
|
@@ -267,8 +275,11 @@ codex mcp add project-librarian -- node .codex/skills/project-librarian/dist/ini
|
|
|
267
275
|
5. New project-planning content is classified through `wiki/meta/document-taxonomy.md` before it is written or consolidated, keeping upstream/downstream document relationships visible.
|
|
268
276
|
6. `--refresh-index` routes newly discovered wiki pages; large route sets are split into `wiki/indexes/auto-*.md` scoped routers.
|
|
269
277
|
7. `--code-index` creates a disposable SQLite evidence cache under `.project-wiki/`.
|
|
270
|
-
8. `--code-report`, `--code-impact`, `--code-search-symbol`, and `--code-query` expose code-backed evidence for planning updates.
|
|
271
|
-
9.
|
|
278
|
+
8. `--code-report`, `--code-impact`, `--code-context-pack`, `--code-search-symbol`, and `--code-query` expose code-backed evidence for planning updates.
|
|
279
|
+
9. Read-only wiki consumers share a concept read model that derives user-facing page types from paths and frontmatter without rewriting the canonical wiki schema.
|
|
280
|
+
10. Wiki producers keep writing the canonical markdown/YAML schema, while read-only consumers such as diagnostics, MCP, and the visualizer use derived projections instead of mutating source documents.
|
|
281
|
+
11. `--wiki-visualize` writes a static graph artifact to `.project-wiki/`, reusing the wiki graph and concept read model instead of introducing a database or server.
|
|
282
|
+
12. Diagnostics report broken links, duplicate routes, orphan pages, stale pages, missing TL;DRs, evidence gaps, and migration policy violations.
|
|
272
283
|
|
|
273
284
|
Migration is intentionally review-first. `--migrate` preserves an existing `wiki/` as `wiki_legacy*`, skips form-only/template legacy files, splits mixed legacy pages into meaning units, classifies each unit through the document taxonomy, and writes review files under `wiki/migration/`:
|
|
274
285
|
|
|
@@ -308,10 +319,12 @@ Recognized but inventory-only extensions include `.rb`, `.vue`, and `.css`. Conf
|
|
|
308
319
|
Use the resolved local runner for automation or direct CLI execution:
|
|
309
320
|
|
|
310
321
|
```bash
|
|
311
|
-
node .codex/skills/project-librarian/dist/init-project-wiki.js [init] [options]
|
|
322
|
+
node .codex/skills/project-librarian/dist/init-project-wiki.js [init|update] [options]
|
|
312
323
|
node .codex/skills/project-librarian/dist/init-project-wiki.js install-skill [--scope user|project] [--agents codex|claude|cursor|gemini|all]
|
|
313
324
|
```
|
|
314
325
|
|
|
326
|
+
`update` is the explicit existing-project update command. It rejects `--migrate` and `--adopt-existing`; use top-level `--migrate` when legacy docs or wiki content should be preserved into `wiki_legacy*` and reviewed.
|
|
327
|
+
|
|
315
328
|
Important options:
|
|
316
329
|
|
|
317
330
|
| Option | Purpose |
|
|
@@ -327,6 +340,8 @@ Important options:
|
|
|
327
340
|
| `--migration-doctor` | Run migration-lint and migration-quality-check together. |
|
|
328
341
|
| `--query <terms>` | Search wiki paths, metadata, titles, and bodies; answer-first output with per-page TL;DR lines under a hard size cap. |
|
|
329
342
|
| `--wiki-impact <page-or-term>` | Show wiki backlinks, `decision_ref` citations, outgoing links, and router depth for matching pages. |
|
|
343
|
+
| `--wiki-visualize` | Write a self-contained static wiki graph visualizer to `.project-wiki/wiki-graph.html`. |
|
|
344
|
+
| `--wiki-visualize-out <path>` | With `--wiki-visualize`, write to a custom repository-relative path under `.project-wiki/`. |
|
|
330
345
|
| `--refresh-index` | Update generated auto-discovered wiki routing. |
|
|
331
346
|
| `--capture-inbox --title <title> --content <content>` | Append a candidate note to the wiki inbox. |
|
|
332
347
|
| `--issue-draft --issue-title <title>` | Print a read-only GitHub issue body draft for problems or side effects. |
|
|
@@ -336,9 +351,11 @@ Important options:
|
|
|
336
351
|
| `--review-migration`, `--semantic-migrate` | Sync migration coverage and inbox statuses into migration review files. |
|
|
337
352
|
| `--no-git-config` | Install hook files without changing `git core.hooksPath`. |
|
|
338
353
|
| `--code-index` | Build the disposable code evidence index. |
|
|
354
|
+
| `--code-index-health` | Inspect code evidence cache compatibility and print rebuild guidance without writing. |
|
|
339
355
|
| `--code-report` | Print architecture and ownership summaries from the evidence index. |
|
|
340
356
|
| `--code-report-section <section>` | Print one section: `coverage`, `ownership`, `languages`, `parsers`, `workspaces`, `workspace-graph`, `routes`, `hotspots`, `configs`, or `edges`. |
|
|
341
357
|
| `--code-impact <term>` | Show file, symbol, route, import, edge, and owner impact evidence. |
|
|
358
|
+
| `--code-context-pack <term>` | Print a budgeted first-pass context pack with structural file, symbol, route, import, edge, and ownership evidence. |
|
|
342
359
|
| `--code-search-symbol <term>` | Search indexed symbols. |
|
|
343
360
|
| `--code-query <sql>` | Run conservative read-only SQL over the evidence index. |
|
|
344
361
|
|
|
@@ -351,13 +368,26 @@ npm install
|
|
|
351
368
|
npm run typecheck
|
|
352
369
|
npm run build
|
|
353
370
|
npm test
|
|
371
|
+
npm run benchmark:claim-ledger
|
|
372
|
+
npm run release:check
|
|
354
373
|
npm pack --dry-run
|
|
355
374
|
```
|
|
356
375
|
|
|
357
376
|
When editing TypeScript under `src/`, rebuild before committing so `dist/` stays current.
|
|
358
377
|
|
|
378
|
+
`npm run release:check` is a local-only maintainer gate: it runs tests, benchmark parser smoke, benchmark release preview, benchmark claim-ledger classification, package dry-run inspection, dist executable checks, and README benchmark-claim boundary checks. It never publishes and never launches a measured Codex benchmark.
|
|
379
|
+
|
|
359
380
|
Maintainer benchmark commands live in [benchmarks/README.md](benchmarks/README.md). They are for release evidence and public claim validation, not normal end-user setup.
|
|
360
381
|
|
|
382
|
+
For code-evidence runtime/storage checks, `npm run perf:code-efficiency` generates 3k/10k/50k fixtures and writes `benchmarks/reports/code-performance-efficiency/current.json` plus `.md`. Command timings include CLI startup and freshness checks; the `query_groups` section reports direct DB timings for representative file/symbol/route/import/edge queries. The report also includes checked-in sample corpora, including `mixed-monorepo`, separately from synthetic scale fixtures.
|
|
383
|
+
|
|
384
|
+
Old ignored LLM benchmark raw output can be audited with the dry-run-first helper before deleting retained isolated Codex homes:
|
|
385
|
+
|
|
386
|
+
```bash
|
|
387
|
+
npm run benchmark:llm:prune-raw -- --older-than-days 14
|
|
388
|
+
npm run benchmark:llm:prune-raw -- --older-than-days 14 --execute
|
|
389
|
+
```
|
|
390
|
+
|
|
361
391
|
## Inspiration
|
|
362
392
|
|
|
363
393
|
This project is inspired by Andrej Karpathy's [LLM Wiki](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f) pattern: keep persistent markdown context close to the work instead of reconstructing project state from long chat history.
|
package/SKILL.md
CHANGED
|
@@ -57,6 +57,7 @@ $PROJECT_LIBRARIAN
|
|
|
57
57
|
Use the command variants as follows:
|
|
58
58
|
|
|
59
59
|
- New project wiki or normal update: `$PROJECT_LIBRARIAN`.
|
|
60
|
+
- Explicit existing-project update without migration: `$PROJECT_LIBRARIAN update` (rejects `--migrate` and `--adopt-existing`).
|
|
60
61
|
- Existing wiki/docs need migration: `$PROJECT_LIBRARIAN --migrate`.
|
|
61
62
|
- Install hook files without changing git config: `$PROJECT_LIBRARIAN --no-git-config`.
|
|
62
63
|
|
package/dist/args.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
exports.issueDraftTitle = exports.issueBodyFile = exports.captureCategory = void 0;
|
|
3
|
+
exports.codeSearchSymbol = exports.codeReportSection = exports.codeQuerySql = exports.codeImpactTarget = exports.codeContextPackTarget = exports.wikiVisualizeOutput = exports.wikiVisualizeMode = exports.wikiImpactTarget = exports.wikiImpactMode = exports.queryTerm = exports.codeSearchSymbolMode = exports.codeQueryMode = exports.codeImpactMode = exports.codeParserMode = exports.codeContextPackMode = exports.codeFilesMode = exports.codeStatusMode = exports.codeReportMode = exports.codeIndexHealthMode = exports.codeIndexFullMode = exports.codeIndexIncrementalMode = exports.codeIndexMode = exports.acknowledgeSmallRepoMode = exports.noGitConfigMode = exports.reviewMigrationMode = exports.pruneCheckMode = exports.captureInboxMode = exports.refreshIndexMode = exports.issueDraftMode = exports.issueCreateMode = exports.glossaryMode = exports.fixMode = exports.doctorMode = exports.qualityCheckMode = exports.linkCheckMode = exports.migrationQualityCheckMode = exports.migrationLintMode = exports.migrationDoctorMode = exports.lintMode = exports.migrateMode = exports.missingValueOptions = exports.unexpectedValueOptions = exports.unknownOptions = exports.args = exports.commandArgs = exports.command = exports.unknownCommand = exports.helpMode = exports.parsedArgs = exports.rawArgs = void 0;
|
|
4
|
+
exports.issueDraftTitle = exports.issueBodyFile = exports.captureCategory = exports.captureContent = exports.captureTitle = exports.codeIndexScopes = exports.codeParser = exports.codeIndexOutput = void 0;
|
|
5
5
|
exports.parseArgs = parseArgs;
|
|
6
6
|
exports.argValue = argValue;
|
|
7
7
|
exports.argValues = argValues;
|
|
8
8
|
exports.rawArgs = process.argv.slice(2);
|
|
9
|
-
const knownCommands = new Set(["init", "install-skill", "mcp"]);
|
|
9
|
+
const knownCommands = new Set(["init", "update", "install-skill", "mcp"]);
|
|
10
10
|
const flagsWithoutValues = new Set([
|
|
11
11
|
"--acknowledge-small-repo",
|
|
12
12
|
"--adopt-existing",
|
|
@@ -18,6 +18,7 @@ const flagsWithoutValues = new Set([
|
|
|
18
18
|
"--code-incremental",
|
|
19
19
|
"--code-index",
|
|
20
20
|
"--code-index-full",
|
|
21
|
+
"--code-index-health",
|
|
21
22
|
"--code-index-incremental",
|
|
22
23
|
"--code-evidence-index-full",
|
|
23
24
|
"--code-evidence-index-incremental",
|
|
@@ -43,11 +44,15 @@ const flagsWithoutValues = new Set([
|
|
|
43
44
|
"--refresh-index",
|
|
44
45
|
"--review-migration",
|
|
45
46
|
"--semantic-migrate",
|
|
47
|
+
"--wiki-graph-html",
|
|
48
|
+
"--wiki-visualize",
|
|
46
49
|
]);
|
|
47
50
|
const flagsWithValues = new Set([
|
|
48
51
|
"--agents",
|
|
49
52
|
"--category",
|
|
53
|
+
"--code-evidence-context-pack",
|
|
50
54
|
"--code-evidence-impact",
|
|
55
|
+
"--code-context-pack",
|
|
51
56
|
"--code-evidence-out",
|
|
52
57
|
"--code-evidence-parser",
|
|
53
58
|
"--code-evidence-query",
|
|
@@ -68,6 +73,7 @@ const flagsWithValues = new Set([
|
|
|
68
73
|
"--scope",
|
|
69
74
|
"--title",
|
|
70
75
|
"--wiki-impact",
|
|
76
|
+
"--wiki-visualize-out",
|
|
71
77
|
]);
|
|
72
78
|
const knownFlags = new Set([...flagsWithoutValues, ...flagsWithValues, "--help", "-h"]);
|
|
73
79
|
function flagName(arg) {
|
|
@@ -130,6 +136,7 @@ function parseArgs(argv) {
|
|
|
130
136
|
const argValue = (name) => argValueFrom(commandArgs, name);
|
|
131
137
|
const argValues = (name) => argValuesFrom(commandArgs, name);
|
|
132
138
|
const codeImpactTarget = argValue("--code-impact") || argValue("--code-evidence-impact");
|
|
139
|
+
const codeContextPackTarget = argValue("--code-context-pack") || argValue("--code-evidence-context-pack");
|
|
133
140
|
const codeQuerySql = argValue("--code-query") || argValue("--code-evidence-query");
|
|
134
141
|
const codeSearchSymbol = argValue("--code-search-symbol") || argValue("--code-evidence-symbol");
|
|
135
142
|
return {
|
|
@@ -139,10 +146,13 @@ function parseArgs(argv) {
|
|
|
139
146
|
captureContent: argValue("--content"),
|
|
140
147
|
captureInboxMode: args.has("--capture-inbox"),
|
|
141
148
|
captureTitle: argValue("--title"),
|
|
149
|
+
codeContextPackMode: hasFlag("--code-context-pack") || hasFlag("--code-evidence-context-pack"),
|
|
150
|
+
codeContextPackTarget,
|
|
142
151
|
codeFilesMode: args.has("--code-files") || args.has("--code-evidence-files"),
|
|
143
152
|
codeImpactMode: hasFlag("--code-impact") || hasFlag("--code-evidence-impact"),
|
|
144
153
|
codeImpactTarget,
|
|
145
154
|
codeIndexFullMode: args.has("--code-index-full") || args.has("--code-evidence-index-full"),
|
|
155
|
+
codeIndexHealthMode: args.has("--code-index-health"),
|
|
146
156
|
codeIndexIncrementalMode: args.has("--incremental") || args.has("--code-incremental") || args.has("--code-index-incremental") || args.has("--code-evidence-index-incremental"),
|
|
147
157
|
codeIndexMode: args.has("--code-index") || args.has("--code-evidence-index"),
|
|
148
158
|
codeIndexOutput: argValue("--code-index-out") || argValue("--code-evidence-out") || ".project-wiki/code-evidence.sqlite",
|
|
@@ -191,6 +201,8 @@ function parseArgs(argv) {
|
|
|
191
201
|
.filter((arg) => !knownFlags.has(arg)))),
|
|
192
202
|
wikiImpactMode: hasFlag("--wiki-impact"),
|
|
193
203
|
wikiImpactTarget: argValue("--wiki-impact"),
|
|
204
|
+
wikiVisualizeMode: hasFlag("--wiki-visualize") || hasFlag("--wiki-graph-html"),
|
|
205
|
+
wikiVisualizeOutput: argValue("--wiki-visualize-out"),
|
|
194
206
|
};
|
|
195
207
|
}
|
|
196
208
|
exports.parsedArgs = parseArgs(exports.rawArgs);
|
|
@@ -223,9 +235,11 @@ exports.acknowledgeSmallRepoMode = exports.parsedArgs.acknowledgeSmallRepoMode;
|
|
|
223
235
|
exports.codeIndexMode = exports.parsedArgs.codeIndexMode;
|
|
224
236
|
exports.codeIndexIncrementalMode = exports.parsedArgs.codeIndexIncrementalMode;
|
|
225
237
|
exports.codeIndexFullMode = exports.parsedArgs.codeIndexFullMode;
|
|
238
|
+
exports.codeIndexHealthMode = exports.parsedArgs.codeIndexHealthMode;
|
|
226
239
|
exports.codeReportMode = exports.parsedArgs.codeReportMode;
|
|
227
240
|
exports.codeStatusMode = exports.parsedArgs.codeStatusMode;
|
|
228
241
|
exports.codeFilesMode = exports.parsedArgs.codeFilesMode;
|
|
242
|
+
exports.codeContextPackMode = exports.parsedArgs.codeContextPackMode;
|
|
229
243
|
exports.codeParserMode = exports.parsedArgs.codeParserMode;
|
|
230
244
|
exports.codeImpactMode = exports.parsedArgs.codeImpactMode;
|
|
231
245
|
exports.codeQueryMode = exports.parsedArgs.codeQueryMode;
|
|
@@ -239,6 +253,9 @@ function argValues(name) {
|
|
|
239
253
|
exports.queryTerm = exports.parsedArgs.queryTerm;
|
|
240
254
|
exports.wikiImpactMode = exports.parsedArgs.wikiImpactMode;
|
|
241
255
|
exports.wikiImpactTarget = exports.parsedArgs.wikiImpactTarget;
|
|
256
|
+
exports.wikiVisualizeMode = exports.parsedArgs.wikiVisualizeMode;
|
|
257
|
+
exports.wikiVisualizeOutput = exports.parsedArgs.wikiVisualizeOutput;
|
|
258
|
+
exports.codeContextPackTarget = exports.parsedArgs.codeContextPackTarget;
|
|
242
259
|
exports.codeImpactTarget = exports.parsedArgs.codeImpactTarget;
|
|
243
260
|
exports.codeQuerySql = exports.parsedArgs.codeQuerySql;
|
|
244
261
|
exports.codeReportSection = exports.parsedArgs.codeReportSection;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.collectCodeEvidence = collectCodeEvidence;
|
|
4
|
+
const ownership_1 = require("./ownership");
|
|
5
|
+
const search_1 = require("./search");
|
|
6
|
+
function sortedUnique(values) {
|
|
7
|
+
return Array.from(new Set(values.filter(Boolean))).sort();
|
|
8
|
+
}
|
|
9
|
+
function ownerRowsForFilePaths(filePaths, options) {
|
|
10
|
+
const ownership = (0, ownership_1.ownershipContext)();
|
|
11
|
+
const ownersByName = new Map();
|
|
12
|
+
for (const filePath of filePaths) {
|
|
13
|
+
const info = (0, ownership_1.ownershipInfo)(filePath, ownership);
|
|
14
|
+
const current = ownersByName.get(info.owner) ?? {
|
|
15
|
+
codeowners: new Set(),
|
|
16
|
+
files: 0,
|
|
17
|
+
owner: info.owner,
|
|
18
|
+
owner_source: info.owner_source,
|
|
19
|
+
sample_files: [],
|
|
20
|
+
};
|
|
21
|
+
current.files += 1;
|
|
22
|
+
if (current.sample_files.length < options.ownerSampleLimit)
|
|
23
|
+
current.sample_files.push(filePath);
|
|
24
|
+
if (options.includeOwnerCodeowners && info.codeowners) {
|
|
25
|
+
for (const owner of info.codeowners.split(", ").filter(Boolean))
|
|
26
|
+
current.codeowners.add(owner);
|
|
27
|
+
}
|
|
28
|
+
ownersByName.set(info.owner, current);
|
|
29
|
+
}
|
|
30
|
+
return Array.from(ownersByName.values()).map((owner) => {
|
|
31
|
+
const row = {
|
|
32
|
+
files: owner.files,
|
|
33
|
+
owner: owner.owner,
|
|
34
|
+
owner_source: owner.owner_source,
|
|
35
|
+
sample_files: owner.sample_files,
|
|
36
|
+
};
|
|
37
|
+
if (options.includeOwnerCodeowners)
|
|
38
|
+
row.codeowners = Array.from(owner.codeowners).sort().join(", ");
|
|
39
|
+
return row;
|
|
40
|
+
}).sort((left, right) => right.files - left.files || left.owner.localeCompare(right.owner));
|
|
41
|
+
}
|
|
42
|
+
function collectCodeEvidence(database, query, options) {
|
|
43
|
+
const normalized = query.trim();
|
|
44
|
+
const like = (0, search_1.containsLikePattern)(normalized);
|
|
45
|
+
const files = (0, search_1.searchFiles)(database, normalized, options.fileLimit);
|
|
46
|
+
const symbols = (0, search_1.searchSymbols)(database, normalized, options.symbolLimit);
|
|
47
|
+
const routes = database.prepare("SELECT method, route, file_path, line, handler FROM routes WHERE route LIKE ? ESCAPE '\\' OR handler LIKE ? ESCAPE '\\' OR file_path LIKE ? ESCAPE '\\' ORDER BY file_path, line LIMIT ?").all(like, like, like, options.routeLimit);
|
|
48
|
+
const imports = database.prepare("SELECT from_file, to_ref, imported, line, raw FROM imports WHERE from_file LIKE ? ESCAPE '\\' OR to_ref LIKE ? ESCAPE '\\' OR imported LIKE ? ESCAPE '\\' ORDER BY from_file, line LIMIT ?").all(like, like, like, options.importLimit);
|
|
49
|
+
const outgoingEdges = options.includeEdgeEvidenceMatches
|
|
50
|
+
? database.prepare("SELECT kind, source_kind, source, target_kind, target, file_path, line, evidence FROM edges WHERE file_path LIKE ? ESCAPE '\\' OR source LIKE ? ESCAPE '\\' OR evidence LIKE ? ESCAPE '\\' ORDER BY file_path, line LIMIT ?").all(like, like, like, options.edgeLimit)
|
|
51
|
+
: database.prepare("SELECT kind, source_kind, source, target_kind, target, file_path, line, evidence FROM edges WHERE file_path LIKE ? ESCAPE '\\' OR source LIKE ? ESCAPE '\\' ORDER BY file_path, line LIMIT ?").all(like, like, options.edgeLimit);
|
|
52
|
+
const incomingEdges = options.includeEdgeEvidenceMatches
|
|
53
|
+
? database.prepare("SELECT kind, source_kind, source, target_kind, target, file_path, line, evidence FROM edges WHERE target LIKE ? ESCAPE '\\' OR evidence LIKE ? ESCAPE '\\' ORDER BY file_path, line LIMIT ?").all(like, like, options.edgeLimit)
|
|
54
|
+
: database.prepare("SELECT kind, source_kind, source, target_kind, target, file_path, line, evidence FROM edges WHERE target LIKE ? ESCAPE '\\' ORDER BY file_path, line LIMIT ?").all(like, options.edgeLimit);
|
|
55
|
+
const routeTargets = routes.map((row) => `${String(row.method)} ${String(row.route)}`);
|
|
56
|
+
const routeEdges = options.includeRouteEdges && routeTargets.length > 0
|
|
57
|
+
? database.prepare(`SELECT kind, source_kind, source, target_kind, target, file_path, line, evidence FROM edges WHERE source IN (${routeTargets.map(() => "?").join(", ")}) ORDER BY file_path, line LIMIT ?`).all(...routeTargets, options.routeEdgeLimit)
|
|
58
|
+
: [];
|
|
59
|
+
const relatedFilePaths = sortedUnique([
|
|
60
|
+
...files.map((row) => String(row.path ?? "")),
|
|
61
|
+
...symbols.map((row) => String(row.file_path ?? "")),
|
|
62
|
+
...routes.map((row) => String(row.file_path ?? "")),
|
|
63
|
+
...imports.map((row) => String(row.from_file ?? "")),
|
|
64
|
+
...outgoingEdges.map((row) => String(row.file_path ?? "")),
|
|
65
|
+
...incomingEdges.map((row) => String(row.file_path ?? "")),
|
|
66
|
+
...routeEdges.map((row) => String(row.file_path ?? "")),
|
|
67
|
+
]);
|
|
68
|
+
return {
|
|
69
|
+
files,
|
|
70
|
+
imports,
|
|
71
|
+
incomingEdges,
|
|
72
|
+
owners: ownerRowsForFilePaths(relatedFilePaths, options),
|
|
73
|
+
relatedFilePaths,
|
|
74
|
+
outgoingEdges,
|
|
75
|
+
routeEdges,
|
|
76
|
+
routes,
|
|
77
|
+
symbols,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.indexConfigs = indexConfigs;
|
|
37
|
+
const path = __importStar(require("node:path"));
|
|
38
|
+
const shared_1 = require("./shared");
|
|
39
|
+
function indexConfigs(file, insertConfig) {
|
|
40
|
+
if (path.basename(file.path) === "package.json") {
|
|
41
|
+
try {
|
|
42
|
+
const parsed = JSON.parse(file.text);
|
|
43
|
+
for (const [name, value] of Object.entries(parsed.scripts ?? {}))
|
|
44
|
+
insertConfig.run(`script:${name}`, value, file.path, 1);
|
|
45
|
+
for (const [name, value] of Object.entries(parsed.dependencies ?? {}))
|
|
46
|
+
insertConfig.run(`dependency:${name}`, value, file.path, 1);
|
|
47
|
+
for (const [name, value] of Object.entries(parsed.devDependencies ?? {}))
|
|
48
|
+
insertConfig.run(`devDependency:${name}`, value, file.path, 1);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
insertConfig.run("parse-error", "package.json is not valid JSON", file.path, 1);
|
|
52
|
+
}
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
(0, shared_1.insertMatches)(file, /^\s*([A-Za-z0-9_.-]+)\s*[:=]\s*(.+)$/gm, (match, line) => {
|
|
56
|
+
insertConfig.run(match[1] ?? "", (match[2] ?? "").trim(), file.path, line);
|
|
57
|
+
});
|
|
58
|
+
}
|