llm-wiki-kit 0.1.14 → 0.2.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.md +11 -8
- package/docs/concepts.md +8 -7
- package/docs/integrations/claude-code.md +3 -2
- package/docs/integrations/codex.md +5 -3
- package/docs/manual.md +461 -0
- package/docs/operations.md +8 -3
- package/docs/troubleshooting.md +2 -2
- package/package.json +1 -1
- package/src/capture-policy.js +163 -0
- package/src/cli.js +11 -1
- package/src/hook.js +50 -16
- package/src/maintenance.js +22 -4
- package/src/project.js +1 -1
- package/src/templates.js +20 -17
- package/src/wiki-search.js +18 -4
package/README.md
CHANGED
|
@@ -73,18 +73,18 @@ Use Claude Code or Codex normally.
|
|
|
73
73
|
The installed hooks:
|
|
74
74
|
|
|
75
75
|
- inject `wiki/memory.md`, `wiki/index.md`, and relevant wiki context at session start, instructions loaded, prompt submit, and post-compact time
|
|
76
|
-
- record redacted turn
|
|
76
|
+
- record small redacted raw event envelopes and per-turn state
|
|
77
77
|
- capture decision points, debugging findings, changed files, and verification notes
|
|
78
78
|
- allow tool calls to proceed without secret/PII-based hook blocking
|
|
79
|
-
- update `llm-wiki/outputs/questions/YYYY-MM-DD-live-qa.md`
|
|
80
|
-
-
|
|
81
|
-
-
|
|
82
|
-
- queue durable cleanup candidates in `llm-wiki/outputs/maintenance/queue.md` at stop/session-end time
|
|
79
|
+
- update `llm-wiki/outputs/questions/YYYY-MM-DD-live-qa.md` only for meaningful work turns
|
|
80
|
+
- avoid automatic `wiki/queries/` and `wiki/decisions/` promotion in the default answer-first mode
|
|
81
|
+
- queue durable cleanup candidates only for explicit documentation requests that were not reflected in durable wiki files, or when stale turn state is recovered
|
|
83
82
|
- recover stale per-turn state into that queue on the next session start or prompt submit when the previous stop hook did not complete
|
|
84
|
-
- nudge the active LLM to fold reusable facts into existing wiki pages instead of leaving everything as one-off Q&A
|
|
83
|
+
- nudge the active LLM to fold approved reusable facts into existing wiki pages instead of leaving everything as one-off Q&A
|
|
85
84
|
- automatically refresh managed rules/templates for older projects when the current runtime starts a session
|
|
86
85
|
|
|
87
86
|
If you need to think about saving every answer manually, the setup has failed.
|
|
87
|
+
If wiki maintenance delays the actual answer, the setup is being used wrong. The default capture mode is `LLM_WIKI_KIT_CAPTURE_MODE=answer-first`; the old eager query/decision capture path remains only as deprecated compatibility mode via `LLM_WIKI_KIT_CAPTURE_MODE=legacy-eager`.
|
|
88
88
|
|
|
89
89
|
## Operational Commands
|
|
90
90
|
|
|
@@ -92,9 +92,12 @@ Most users should not need these during daily Claude Code/Codex work. They exist
|
|
|
92
92
|
|
|
93
93
|
- Install/update: `llm-wiki install`, `llm-wiki update`, `llm-wiki post-update`, `llm-wiki projects`
|
|
94
94
|
- Diagnostics: `llm-wiki doctor`, `llm-wiki status`, `llm-wiki version`
|
|
95
|
+
- Manual: `llm-wiki manual`
|
|
95
96
|
- Agent maintenance helpers: `llm-wiki context`, `llm-wiki lint`, `llm-wiki consolidate`, `llm-wiki maintenance`
|
|
96
97
|
- Cleanup: `llm-wiki uninstall`
|
|
97
98
|
|
|
99
|
+
`llm-wiki manual` prints the full package manual from `docs/manual.md`. Keep that document current when adding public commands, options, hook behavior, directory conventions, security policy, or update flows.
|
|
100
|
+
|
|
98
101
|
`llm-wiki status` is an offline consistency check. It reports the installed runtime version, hook targets, whether the `llm-wiki` command on `PATH` resolves to the current runtime, whether the current workspace has the current managed templates applied, how many rules are auto-updateable, how many managed-looking rules need agent cleanup, and how many wiki maintenance items are pending.
|
|
99
102
|
|
|
100
103
|
`llm-wiki update --check [--to <version-or-tag>]` is the online update check. It compares the installed package version with the npm registry target without changing files, and reports an available update only when the target version is newer than the installed version.
|
|
@@ -103,13 +106,13 @@ Most users should not need these during daily Claude Code/Codex work. They exist
|
|
|
103
106
|
|
|
104
107
|
`llm-wiki post-update --workspace <project>` reapplies the current runtime's hook entries and safe managed template updates without running `npm install -g`. Use `post-update --all --workspace <search-root>` to reapply templates across discovered project roots.
|
|
105
108
|
|
|
106
|
-
`llm-wiki context "<query>"` prints the same layered context used by hooks. It is mainly for debugging what Codex/Claude Code will see; daily use should rely on hook injection.
|
|
109
|
+
`llm-wiki context "<query>"` prints the same layered context used by hooks. It is mainly for debugging what Codex/Claude Code will see; daily use should rely on hook injection. By default, episodic `wiki/queries/` pages are excluded from search unless they were promoted with `memory_type: semantic` or `procedural` and `importance >= 4`; use `--include-episodic` only when debugging old automatic query records.
|
|
107
110
|
|
|
108
111
|
`llm-wiki lint` checks wiki health and detects outdated managed rules from older kit versions. Agents may use it before/after meaningful wiki maintenance.
|
|
109
112
|
|
|
110
113
|
`llm-wiki consolidate` refreshes only generated marker blocks in `wiki/memory.md` and `wiki/index.md`. It is an agent maintenance helper, not a command users should run after every turn.
|
|
111
114
|
|
|
112
|
-
`llm-wiki maintenance` prints the pending queue from `llm-wiki/outputs/maintenance/queue.md`. Hooks create candidates; the active agent should merge reusable items into existing durable wiki pages and mark queue items `done` or `skipped
|
|
115
|
+
`llm-wiki maintenance` prints the pending queue from `llm-wiki/outputs/maintenance/queue.md`. Hooks create only selective candidates; the active agent should merge reusable items into existing durable wiki pages and mark queue items `done` or `skipped` without delaying unrelated user answers.
|
|
113
116
|
|
|
114
117
|
`llm-wiki projects --workspace /apps` lists project roots that already have `llm-wiki-kit` state or an older `llm-wiki/wiki/index.md`, and shows the update commands to run. `llm-wiki update --workspace /apps` updates the global runtime once, then reapplies managed templates across every known or discovered project root under `/apps`.
|
|
115
118
|
|
package/docs/concepts.md
CHANGED
|
@@ -15,13 +15,14 @@ raw sources -> wiki -> schema/rules
|
|
|
15
15
|
The important behavior is a loop:
|
|
16
16
|
|
|
17
17
|
1. A Claude Code or Codex session starts.
|
|
18
|
-
2. `memory.md`, `index.md`, and relevant wiki context are injected automatically.
|
|
18
|
+
2. `memory.md`, `index.md`, and relevant wiki context are injected automatically with an answer-first instruction.
|
|
19
19
|
3. The user works normally; no extra command loop is required.
|
|
20
20
|
4. Hooks gather redacted prompt/tool/result summaries.
|
|
21
|
-
5. At stop/session end, hooks append redacted live Q&A
|
|
22
|
-
6.
|
|
23
|
-
7.
|
|
24
|
-
8.
|
|
21
|
+
5. At stop/session end, hooks append redacted live Q&A only for meaningful work turns.
|
|
22
|
+
6. Durable wiki promotion is selective: explicit record/document requests should be handled by the active agent in existing wiki pages; the hook queues review only when such a request was not reflected in durable files.
|
|
23
|
+
7. At the next start/prompt after an abrupt shutdown, hooks can recover stale turn state into `outputs/maintenance/queue.md`.
|
|
24
|
+
8. When reusable knowledge appears, the active Claude Code/Codex agent folds approved facts into existing durable wiki pages instead of leaving everything as one-off Q&A.
|
|
25
|
+
9. Future sessions start from the improved wiki instead of relying on long chat history.
|
|
25
26
|
|
|
26
27
|
The kit is a template/runtime repository. It must not centralize project wiki contents.
|
|
27
28
|
|
|
@@ -38,7 +39,7 @@ The maintenance loop is intentionally layered:
|
|
|
38
39
|
|
|
39
40
|
- `memory.md`: short hot index for current durable facts.
|
|
40
41
|
- `index.md`: broad navigation map.
|
|
41
|
-
- MiniSearch + wikilinks: retrieval over
|
|
42
|
-
- `outputs/maintenance/queue.md`:
|
|
42
|
+
- MiniSearch + wikilinks: retrieval over durable `wiki/**/*.md`, with episodic `wiki/queries/` hidden by default unless `--include-episodic` is requested.
|
|
43
|
+
- `outputs/maintenance/queue.md`: selective reminders for explicit durable requests that need review, plus stale turn recovery.
|
|
43
44
|
- `lint`: finds broken links, stale pages, duplicates, metadata gaps, secret-like content, and outdated managed rules.
|
|
44
45
|
- `consolidate`: agent helper that refreshes generated blocks in `memory.md` and `index.md` while preserving handwritten notes and keeping default query/context/session pages out of the durable generated maps.
|
|
@@ -40,11 +40,12 @@ when no project `CLAUDE.md` exists. Existing `CLAUDE.md` files are not overwritt
|
|
|
40
40
|
|
|
41
41
|
The hook records redacted turn summaries but does not deny tool calls only because an input looks sensitive. Hook payloads are stored as small redacted event envelopes rather than full transcripts, and context output is redacted field by field before it is returned to Claude Code.
|
|
42
42
|
|
|
43
|
-
At `SessionStart`/`InstructionsLoaded`, the hook first attempts a safe managed-template refresh, recovers stale turn state into `outputs/maintenance/queue.md`, then injects `llm-wiki/wiki/memory.md`, `llm-wiki/wiki/index.md`, recent log context, operating rules,
|
|
43
|
+
At `SessionStart`/`InstructionsLoaded`, the hook first attempts a safe managed-template refresh, recovers stale turn state into `outputs/maintenance/queue.md`, then injects `llm-wiki/wiki/memory.md`, `llm-wiki/wiki/index.md`, recent log context, operating rules, a one-item maintenance summary when needed, and any maintenance note for outdated or customized managed rules. At `UserPromptSubmit`, it recovers stale turn state, searches wiki pages with MiniSearch or substring fallback, expands one-hop wikilinks, redacts context fields, and injects the smallest useful context set. Maintenance reminders are shown only when the prompt is wiki/maintenance related or matches a queue topic.
|
|
44
44
|
|
|
45
|
-
`PostToolUse` and `PostToolBatch` record redacted tool summaries in the same turn buffer. `PreCompact` records a compaction note, and `PostCompact` records the note and returns fresh wiki context. `SubagentStop
|
|
45
|
+
`PostToolUse` and `PostToolBatch` record redacted tool summaries in the same turn buffer. `PreCompact` records a compaction note, and `PostCompact` records the note and returns fresh wiki context. In the default `answer-first` mode, `SubagentStop` does not create live Q&A, query, decision, or maintenance files. `Stop` and `SessionEnd` append live Q&A only for meaningful work turns and do not auto-create `wiki/queries/` or `wiki/decisions/`. If the user explicitly asked to record or document durable knowledge and no durable wiki update is detected, `Stop`/`SessionEnd` queue a pending maintenance item for agent review. `Stop` and `SessionEnd` then clear the per-session turn buffer; `SubagentStop` does not.
|
|
46
46
|
|
|
47
47
|
Set `LLM_WIKI_KIT_AUTO_PROJECT_UPDATE=0` only while diagnosing automatic managed-template refresh behavior.
|
|
48
|
+
Set `LLM_WIKI_KIT_CAPTURE_MODE=legacy-eager` only as deprecated compatibility mode for the old eager query/decision capture behavior.
|
|
48
49
|
|
|
49
50
|
After installation or update, run:
|
|
50
51
|
|
|
@@ -29,17 +29,19 @@ Handled events:
|
|
|
29
29
|
|
|
30
30
|
Expected behavior:
|
|
31
31
|
|
|
32
|
-
- `SessionStart` first attempts a safe managed-template refresh, recovers stale turn state into `outputs/maintenance/queue.md`, then injects `llm-wiki/wiki/memory.md`, `llm-wiki/wiki/index.md`, recent log context, operating rules,
|
|
33
|
-
- `UserPromptSubmit` recovers stale turn state, searches project wiki pages with MiniSearch or substring fallback, expands one-hop wikilinks, redacts context fields, and injects the smallest useful context set
|
|
32
|
+
- `SessionStart` first attempts a safe managed-template refresh, recovers stale turn state into `outputs/maintenance/queue.md`, then injects `llm-wiki/wiki/memory.md`, `llm-wiki/wiki/index.md`, recent log context, operating rules, a one-item maintenance summary when needed, and any maintenance note for outdated or customized managed rules.
|
|
33
|
+
- `UserPromptSubmit` recovers stale turn state, searches project wiki pages with MiniSearch or substring fallback, expands one-hop wikilinks, redacts context fields, and injects the smallest useful context set. Maintenance reminders are shown only when the prompt is wiki/maintenance related or matches a queue topic.
|
|
34
34
|
- `PreToolUse` records redacted tool summaries without blocking tool calls.
|
|
35
35
|
- `PostToolUse` records redacted tool summaries in a turn buffer.
|
|
36
36
|
- `PreCompact` records a compaction note; `PostCompact` records the note and returns fresh wiki context.
|
|
37
|
-
- `
|
|
37
|
+
- In the default `answer-first` mode, `SubagentStop` does not create live Q&A, query, decision, or maintenance files. `Stop` appends live Q&A only for meaningful work turns and does not auto-create `wiki/queries/` or `wiki/decisions/`.
|
|
38
|
+
- If the user explicitly asked to record or document durable knowledge and no durable wiki update is detected, `Stop` queues a pending maintenance item for agent review.
|
|
38
39
|
- `Stop` clears the per-session turn buffer after recording. `SubagentStop` leaves the parent turn buffer available for the final stop event.
|
|
39
40
|
|
|
40
41
|
Hook payloads are stored as small redacted event envelopes rather than full transcripts. Context output is also redacted field by field before it is returned to Codex.
|
|
41
42
|
|
|
42
43
|
Set `LLM_WIKI_KIT_AUTO_PROJECT_UPDATE=0` only while diagnosing automatic managed-template refresh behavior.
|
|
44
|
+
Set `LLM_WIKI_KIT_CAPTURE_MODE=legacy-eager` only as deprecated compatibility mode for the old eager query/decision capture behavior.
|
|
43
45
|
|
|
44
46
|
Run these after install:
|
|
45
47
|
|
package/docs/manual.md
ADDED
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
# llm-wiki-kit Manual
|
|
2
|
+
|
|
3
|
+
`llm-wiki-kit`은 Codex와 Claude Code를 평소처럼 사용하는 동안 프로젝트 안에 living Markdown wiki를 유지하는 hook-first runtime이다.
|
|
4
|
+
|
|
5
|
+
핵심 원칙은 단순하다. 사용자는 별도 기록 명령을 외워서 매번 실행하지 않는다. 평소처럼 질문하고, 구현하고, 검증한다. 내부적으로는 hook이 필요한 context를 주입하고, 안전하게 요약을 남기고, 오래 쓸 지식을 agent가 `llm-wiki/` Markdown에 정리할 수 있도록 돕는다.
|
|
6
|
+
|
|
7
|
+
## Mental Model
|
|
8
|
+
|
|
9
|
+
LLM Wiki는 세 층으로 움직인다.
|
|
10
|
+
|
|
11
|
+
```text
|
|
12
|
+
raw evidence -> curated wiki -> rules and retrieval
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
- `raw/`: 원본 또는 redacted 근거 저장소다. 기본 hook은 작은 redacted event envelope만 저장한다.
|
|
16
|
+
- `wiki/`: agent가 관리하는 정식 지식층이다. 결정, 구조, 디버깅, 개념, 절차, 맥락을 Markdown으로 보존한다.
|
|
17
|
+
- `outputs/`: live Q&A, 보고서, maintenance queue 같은 일회성 또는 작업 산출물을 둔다.
|
|
18
|
+
- `AGENTS.md`, `CLAUDE.md`, `procedures/`: agent가 wiki를 다루는 규칙과 절차다.
|
|
19
|
+
|
|
20
|
+
채팅 history는 임시 context다. 오래 남길 지식은 repository Markdown으로 이동해야 다음 세션, 다른 agent, compact 이후에도 검색 가능하다.
|
|
21
|
+
|
|
22
|
+
## What Gets Created
|
|
23
|
+
|
|
24
|
+
프로젝트를 bootstrap하거나 install하면 보통 다음 구조가 생긴다.
|
|
25
|
+
|
|
26
|
+
```text
|
|
27
|
+
llm-wiki/
|
|
28
|
+
├── .kit-state.json
|
|
29
|
+
├── raw/
|
|
30
|
+
│ ├── inbox/
|
|
31
|
+
│ ├── sessions/
|
|
32
|
+
│ ├── sources/
|
|
33
|
+
│ └── assets/
|
|
34
|
+
├── wiki/
|
|
35
|
+
│ ├── index.md
|
|
36
|
+
│ ├── memory.md
|
|
37
|
+
│ ├── log.md
|
|
38
|
+
│ ├── sources/
|
|
39
|
+
│ ├── concepts/
|
|
40
|
+
│ ├── entities/
|
|
41
|
+
│ ├── decisions/
|
|
42
|
+
│ ├── architecture/
|
|
43
|
+
│ ├── debugging/
|
|
44
|
+
│ ├── context/
|
|
45
|
+
│ └── queries/
|
|
46
|
+
├── outputs/
|
|
47
|
+
│ ├── questions/
|
|
48
|
+
│ ├── reports/
|
|
49
|
+
│ └── maintenance/
|
|
50
|
+
└── procedures/
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`wiki/memory.md`는 hook context에 들어가는 짧은 hot index다. 긴 설명을 복사하지 말고 중요한 entry point만 둔다.
|
|
54
|
+
|
|
55
|
+
`wiki/index.md`는 wiki 전체의 navigation map이다. agent는 넓은 질문을 받으면 여기와 `memory.md`에서 시작한다.
|
|
56
|
+
|
|
57
|
+
`.kit-state.json`은 현재 project rules/templates가 어느 runtime version으로 적용되었는지 기록한다. runtime update와 project knowledge는 별개다. npm package update가 기존 wiki 내용을 덮어쓰지 않는다.
|
|
58
|
+
|
|
59
|
+
## Normal Use
|
|
60
|
+
|
|
61
|
+
평소처럼 Codex 또는 Claude Code를 사용한다.
|
|
62
|
+
|
|
63
|
+
설치된 hook은 다음 일을 자동으로 수행한다.
|
|
64
|
+
|
|
65
|
+
- session start, prompt submit, post compact 시점에 `wiki/memory.md`, `wiki/index.md`, 관련 wiki 검색 결과를 context로 주입한다.
|
|
66
|
+
- prompt/tool/result summary를 redaction한 뒤 turn buffer에 기록한다.
|
|
67
|
+
- 의미 있는 작업 turn만 `outputs/questions/YYYY-MM-DD-live-qa.md`에 live Q&A로 남긴다.
|
|
68
|
+
- 기본 answer-first mode에서는 `wiki/queries/`와 `wiki/decisions/`를 매 turn 자동 생성하지 않는다.
|
|
69
|
+
- 사용자가 명시적으로 문서화/기록을 요청했는데 durable wiki 반영이 없으면 `outputs/maintenance/queue.md`에 정리 후보를 남긴다.
|
|
70
|
+
- 이전 session이 깨끗하게 종료되지 않았을 때 stale turn state를 maintenance queue로 복구할 수 있다.
|
|
71
|
+
- 새 runtime이 오래된 project rules/templates를 발견하면 안전하게 갱신 가능한 managed file만 refresh한다.
|
|
72
|
+
|
|
73
|
+
매번 저장 여부를 사용자가 고민해야 한다면 잘못 쓰고 있는 것이다. 답변보다 wiki maintenance가 먼저 오면 안 된다. 현재 사용자 요청을 먼저 처리하고, 오래 쓸 지식만 필요한 만큼 정리한다.
|
|
74
|
+
|
|
75
|
+
## Capture Modes
|
|
76
|
+
|
|
77
|
+
기본값은 다음과 같다.
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
LLM_WIKI_KIT_CAPTURE_MODE=answer-first
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`answer-first` mode는 현재 답변을 우선한다.
|
|
84
|
+
|
|
85
|
+
- 단순 Q&A나 상태 확인은 durable wiki로 승격하지 않는다.
|
|
86
|
+
- 의미 있는 작업 turn은 live Q&A archive에 남길 수 있다.
|
|
87
|
+
- explicit durable request가 빠졌을 때만 selective maintenance queue를 만든다.
|
|
88
|
+
- reusable fact는 active agent가 기존 wiki 문서에 병합한다.
|
|
89
|
+
|
|
90
|
+
과거 호환용 eager mode도 남아 있다.
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
LLM_WIKI_KIT_CAPTURE_MODE=legacy-eager
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
`legacy-eager`는 old query/decision auto-promotion 흐름을 유지하기 위한 deprecated compatibility mode다. 새 project는 answer-first mode를 사용한다.
|
|
97
|
+
|
|
98
|
+
## Command Reference
|
|
99
|
+
|
|
100
|
+
대부분의 사용자는 일상 작업 중 이 명령들을 직접 실행할 필요가 없다. 설치, 업데이트, 진단, agent-side maintenance용 interface다.
|
|
101
|
+
|
|
102
|
+
### `llm-wiki manual`
|
|
103
|
+
|
|
104
|
+
이 문서를 출력한다.
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
llm-wiki manual
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
새 기능이나 명령이 추가되면 `docs/manual.md`를 함께 갱신한다. 이 문서가 CLI manual의 단일 원본이다.
|
|
111
|
+
|
|
112
|
+
### `llm-wiki install`
|
|
113
|
+
|
|
114
|
+
Codex/Claude Code hook을 설치하고 workspace를 bootstrap한다.
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
llm-wiki install --workspace /apps --profile standard
|
|
118
|
+
llm-wiki install --workspace /path/to/project --profile standard
|
|
119
|
+
llm-wiki install --workspace /path/to/project --profile standard --no-project
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
`standard` profile은 기본 profile이다.
|
|
123
|
+
|
|
124
|
+
- context injection
|
|
125
|
+
- redacted summary recording
|
|
126
|
+
- tool call allow with storage redaction
|
|
127
|
+
- project-local `llm-wiki/` bootstrap
|
|
128
|
+
- hook entry merge
|
|
129
|
+
|
|
130
|
+
`--no-project`는 hook/bin 설치만 하고 현재 workspace bootstrap은 하지 않을 때 사용한다.
|
|
131
|
+
|
|
132
|
+
global npm package 설치 자체는 환경에 따라 `npm install -g` 또는 `sudo npm install -g`로 수행한다. hook 설정 갱신은 보통 일반 사용자 home 아래 파일을 수정하므로 `llm-wiki install`은 해당 user로 실행한다.
|
|
133
|
+
|
|
134
|
+
### `llm-wiki update`
|
|
135
|
+
|
|
136
|
+
npm registry target과 installed runtime을 비교하고, 필요하면 global package를 업데이트한 뒤 hook과 managed project templates를 갱신한다.
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
llm-wiki update --check --workspace /path/to/project
|
|
140
|
+
llm-wiki update --workspace /path/to/search-root
|
|
141
|
+
llm-wiki update --workspace /path/to/search-root --to 0.2.1
|
|
142
|
+
llm-wiki update --workspace /path/to/project --current-only
|
|
143
|
+
llm-wiki update --workspace /path/to/project --dry-run
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
`--check`는 network를 사용하지만 파일을 변경하지 않는다. installed version보다 registry target이 최신일 때만 update available을 보고한다.
|
|
147
|
+
|
|
148
|
+
기본 `update --workspace <search-root>`는 runtime update를 한 번 수행한 뒤, known/discovered project roots의 managed templates를 재적용한다. 기존 wiki contents는 덮어쓰지 않는다.
|
|
149
|
+
|
|
150
|
+
`update`는 source checkout에서 self-update하지 않는다. source checkout 개발 중에는 npm package나 local tarball로 global install한 뒤 update behavior를 테스트한다.
|
|
151
|
+
|
|
152
|
+
### `llm-wiki post-update`
|
|
153
|
+
|
|
154
|
+
npm install 없이 현재 runtime으로 hook entries와 managed project templates를 다시 적용한다.
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
llm-wiki post-update --workspace /path/to/project
|
|
158
|
+
llm-wiki post-update --all --workspace /path/to/search-root
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
plain `npm install -g llm-wiki-kit@latest` 후 hook/template을 다시 맞출 때 사용한다.
|
|
162
|
+
|
|
163
|
+
### `llm-wiki projects`
|
|
164
|
+
|
|
165
|
+
search root 아래의 project roots를 찾고 update 상태를 요약한다.
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
llm-wiki projects --workspace /apps
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
`llm-wiki/.kit-state.json`이 있거나 older `llm-wiki/wiki/index.md`가 있는 root를 찾는다. 출력 끝에는 전체 update, current-only update, post-update command 예시가 함께 나온다.
|
|
172
|
+
|
|
173
|
+
### `llm-wiki status`
|
|
174
|
+
|
|
175
|
+
offline consistency check다.
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
llm-wiki status --workspace /path/to/project
|
|
179
|
+
llm-wiki status
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
보고 항목:
|
|
183
|
+
|
|
184
|
+
- runtime version과 install source
|
|
185
|
+
- binary path와 `PATH` command가 current runtime을 가리키는지
|
|
186
|
+
- Codex/Claude hook이 current runtime인지
|
|
187
|
+
- project applied runtime
|
|
188
|
+
- managed templates current 여부
|
|
189
|
+
- auto-updateable rules count
|
|
190
|
+
- agent cleanup이 필요한 managed-looking rules count
|
|
191
|
+
- pending maintenance count
|
|
192
|
+
|
|
193
|
+
network를 사용하지 않는다.
|
|
194
|
+
|
|
195
|
+
### `llm-wiki version`
|
|
196
|
+
|
|
197
|
+
installed runtime version만 출력한다.
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
llm-wiki version
|
|
201
|
+
llm-wiki --version
|
|
202
|
+
llm-wiki -v
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
script나 smoke test에서 가장 가볍게 runtime version을 확인할 때 쓴다.
|
|
206
|
+
|
|
207
|
+
### `llm-wiki doctor`
|
|
208
|
+
|
|
209
|
+
설치와 hook roundtrip을 진단한다.
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
llm-wiki doctor --workspace /path/to/project
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
확인 항목:
|
|
216
|
+
|
|
217
|
+
- Node version
|
|
218
|
+
- docs presence
|
|
219
|
+
- Codex/Claude command availability
|
|
220
|
+
- state directory writability
|
|
221
|
+
- hook target 상태
|
|
222
|
+
- sample hook roundtrip
|
|
223
|
+
- status summary
|
|
224
|
+
|
|
225
|
+
문제가 있으면 remediation hint를 출력한다.
|
|
226
|
+
|
|
227
|
+
### `llm-wiki bootstrap`
|
|
228
|
+
|
|
229
|
+
project-local `llm-wiki/` 구조와 root policy block을 생성한다.
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
llm-wiki bootstrap --workspace /path/to/project
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
직접 bootstrap할 수 있지만 보통 `install`이 함께 처리한다. 기존 wiki content는 덮어쓰지 않는다.
|
|
236
|
+
|
|
237
|
+
### `llm-wiki migrate`
|
|
238
|
+
|
|
239
|
+
legacy wiki material을 current `llm-wiki/` 구조로 copy-only migration한다.
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
llm-wiki migrate --workspace /path/to/project
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
older OMX/OMC/`omx_wiki/` material은 migration input일 뿐이다. 현재 project knowledge는 `llm-wiki-kit`과 `llm-wiki/` 아래에서 유지한다.
|
|
246
|
+
|
|
247
|
+
### `llm-wiki context`
|
|
248
|
+
|
|
249
|
+
hook이 주입하는 layered context를 수동으로 확인한다.
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
llm-wiki context "auth architecture" --workspace /path/to/project
|
|
253
|
+
llm-wiki context "auth architecture" --workspace /path/to/project --json
|
|
254
|
+
llm-wiki context "auth architecture" --workspace /path/to/project --limit 8
|
|
255
|
+
llm-wiki context "auth architecture" --workspace /path/to/project --no-expand
|
|
256
|
+
llm-wiki context "auth architecture" --workspace /path/to/project --include-episodic
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
읽는 자료:
|
|
260
|
+
|
|
261
|
+
- `wiki/memory.md`
|
|
262
|
+
- `wiki/index.md`
|
|
263
|
+
- recent `wiki/log.md` excerpt
|
|
264
|
+
- MiniSearch 또는 substring fallback 결과
|
|
265
|
+
- strong match의 one-hop wikilink neighbors
|
|
266
|
+
|
|
267
|
+
기본 검색은 episodic `wiki/queries/`를 제외한다. 오래된 automatic query record까지 보고 싶을 때만 `--include-episodic`을 쓴다.
|
|
268
|
+
|
|
269
|
+
### `llm-wiki lint`
|
|
270
|
+
|
|
271
|
+
wiki health check를 수행한다. 파일을 수정하지 않는다.
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
llm-wiki lint --workspace /path/to/project
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
점검 항목:
|
|
278
|
+
|
|
279
|
+
- missing `index.md`, `memory.md`, `log.md`
|
|
280
|
+
- missing/invalid frontmatter
|
|
281
|
+
- broken or ambiguous `[[wikilinks]]`
|
|
282
|
+
- broken relative Markdown links
|
|
283
|
+
- invalid or unsafe `source_ids`
|
|
284
|
+
- missing source files
|
|
285
|
+
- secret-like content
|
|
286
|
+
- duplicate aliases/titles
|
|
287
|
+
- stale pages and orphan candidates
|
|
288
|
+
- outdated managed rules/templates
|
|
289
|
+
- stale or oversized maintenance queue
|
|
290
|
+
|
|
291
|
+
broken links, invalid source IDs, secret-like content는 error이며 exit code 1을 반환한다. metadata/discoverability gap은 warning이다.
|
|
292
|
+
|
|
293
|
+
### `llm-wiki consolidate`
|
|
294
|
+
|
|
295
|
+
generated marker block만 보수적으로 갱신한다.
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
llm-wiki consolidate --workspace /path/to/project
|
|
299
|
+
llm-wiki consolidate --workspace /path/to/project --dry-run
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
갱신 대상:
|
|
303
|
+
|
|
304
|
+
- `wiki/memory.md`의 generated memory map
|
|
305
|
+
- `wiki/index.md`의 generated page map
|
|
306
|
+
|
|
307
|
+
handwritten content는 보존한다. malformed marker block은 덮어쓰지 않고 건너뛴다. 기본 `query`, `context`, `session-log` page는 explicit durable metadata가 없으면 generated map에서 제외한다.
|
|
308
|
+
|
|
309
|
+
### `llm-wiki maintenance`
|
|
310
|
+
|
|
311
|
+
maintenance queue summary를 출력한다.
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
llm-wiki maintenance --workspace /path/to/project
|
|
315
|
+
llm-wiki maintenance --workspace /path/to/project --json
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
이 명령은 page merge를 자동 수행하지 않는다. active agent가 pending item을 읽고, 가장 가까운 durable wiki 문서에 병합한 뒤 queue item을 `done` 또는 `skipped`로 표시한다.
|
|
319
|
+
|
|
320
|
+
### `llm-wiki uninstall`
|
|
321
|
+
|
|
322
|
+
kit이 설치한 hook entries를 제거한다.
|
|
323
|
+
|
|
324
|
+
```bash
|
|
325
|
+
llm-wiki uninstall
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
project-local `llm-wiki/` contents는 남긴다. 지식 저장소를 삭제하는 명령이 아니다.
|
|
329
|
+
|
|
330
|
+
### `llm-wiki hook`
|
|
331
|
+
|
|
332
|
+
Codex/Claude Code hook target으로 쓰는 내부 runtime command다.
|
|
333
|
+
|
|
334
|
+
```bash
|
|
335
|
+
llm-wiki hook codex SessionStart
|
|
336
|
+
llm-wiki hook codex UserPromptSubmit
|
|
337
|
+
llm-wiki hook codex Stop
|
|
338
|
+
llm-wiki hook claude InstructionsLoaded
|
|
339
|
+
llm-wiki hook claude Stop
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
일반 사용자가 직접 호출할 필요는 거의 없다. hook integration이나 smoke test를 디버깅할 때만 사용한다.
|
|
343
|
+
|
|
344
|
+
## Hook Events
|
|
345
|
+
|
|
346
|
+
Codex handled events:
|
|
347
|
+
|
|
348
|
+
- `SessionStart`
|
|
349
|
+
- `UserPromptSubmit`
|
|
350
|
+
- `PreToolUse`
|
|
351
|
+
- `PostToolUse`
|
|
352
|
+
- `PreCompact`
|
|
353
|
+
- `PostCompact`
|
|
354
|
+
- `SubagentStop`
|
|
355
|
+
- `Stop`
|
|
356
|
+
|
|
357
|
+
Claude Code handled events:
|
|
358
|
+
|
|
359
|
+
- `SessionStart`
|
|
360
|
+
- `InstructionsLoaded`
|
|
361
|
+
- `UserPromptSubmit`
|
|
362
|
+
- `PreToolUse`
|
|
363
|
+
- `PostToolUse`
|
|
364
|
+
- `PostToolBatch`
|
|
365
|
+
- `PreCompact`
|
|
366
|
+
- `PostCompact`
|
|
367
|
+
- `SubagentStop`
|
|
368
|
+
- `Stop`
|
|
369
|
+
- `SessionEnd`
|
|
370
|
+
|
|
371
|
+
Hook payload는 full transcript가 아니라 작은 redacted event envelope다. context output도 field별 redaction을 거친다.
|
|
372
|
+
|
|
373
|
+
## Security Defaults
|
|
374
|
+
|
|
375
|
+
기본 정책은 aggressive blocking보다 useful local work wiki를 우선한다.
|
|
376
|
+
|
|
377
|
+
- input이 민감해 보인다는 이유만으로 tool call을 막지 않는다.
|
|
378
|
+
- token, password, bearer credential, private key, `.env` 원문 같은 authentication value는 durable summary에 쓰기 전 redaction한다.
|
|
379
|
+
- phone number, email, date, business identifier는 local work context로 유용할 수 있어 기본 보존한다.
|
|
380
|
+
- full raw transcript capture는 기본 기능이 아니다.
|
|
381
|
+
- `llm-wiki lint`는 wiki 안의 secret-like content를 error로 보고한다.
|
|
382
|
+
|
|
383
|
+
민감한 raw command output, log, screenshot, transcript를 저장해야 할 때는 먼저 redaction한다. 인증값은 wiki, report, live Q&A, command history에 남기지 않는다.
|
|
384
|
+
|
|
385
|
+
## Updating Existing Installs
|
|
386
|
+
|
|
387
|
+
일반 흐름:
|
|
388
|
+
|
|
389
|
+
```bash
|
|
390
|
+
npm install -g llm-wiki-kit@latest --registry=https://registry.npmjs.org/ --prefer-online
|
|
391
|
+
llm-wiki post-update --all --workspace /apps
|
|
392
|
+
llm-wiki status --workspace /apps
|
|
393
|
+
llm-wiki doctor --workspace /apps
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
system global npm prefix가 root-owned인 서버에서는 package install에 `sudo npm install -g`가 필요할 수 있다. 단, user home의 Codex/Claude hook 설정을 갱신하는 `llm-wiki install` 또는 `llm-wiki post-update`는 해당 user로 실행하는 것이 일반적으로 맞다.
|
|
397
|
+
|
|
398
|
+
source checkout 개발 중 pre-publish smoke:
|
|
399
|
+
|
|
400
|
+
```bash
|
|
401
|
+
npm pack --pack-destination /tmp
|
|
402
|
+
npm install -g /tmp/llm-wiki-kit-<version>.tgz
|
|
403
|
+
llm-wiki install --workspace /apps --profile standard
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
publish 전 검증:
|
|
407
|
+
|
|
408
|
+
```bash
|
|
409
|
+
node --test
|
|
410
|
+
npm pack --dry-run
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
publish 후 검증:
|
|
414
|
+
|
|
415
|
+
```bash
|
|
416
|
+
npm view llm-wiki-kit version --registry=https://registry.npmjs.org/
|
|
417
|
+
llm-wiki version
|
|
418
|
+
llm-wiki manual
|
|
419
|
+
llm-wiki status --workspace /apps
|
|
420
|
+
llm-wiki doctor --workspace /apps
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
## Troubleshooting Shortcuts
|
|
424
|
+
|
|
425
|
+
hook이 안 돈다면:
|
|
426
|
+
|
|
427
|
+
```bash
|
|
428
|
+
llm-wiki status --workspace /path/to/project
|
|
429
|
+
llm-wiki doctor --workspace /path/to/project
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
`npm install -g` 후에도 old command가 실행된다면:
|
|
433
|
+
|
|
434
|
+
```bash
|
|
435
|
+
which -a llm-wiki
|
|
436
|
+
readlink -f "$(command -v llm-wiki)"
|
|
437
|
+
npm root -g
|
|
438
|
+
node "$(npm root -g)/llm-wiki-kit/bin/llm-wiki.js" version
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
local shim이 npm global command를 shadowing하면:
|
|
442
|
+
|
|
443
|
+
```bash
|
|
444
|
+
llm-wiki install --workspace /path/to/project --profile standard
|
|
445
|
+
hash -r
|
|
446
|
+
llm-wiki version
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
wiki page가 중복되거나 오래된 것 같다면:
|
|
450
|
+
|
|
451
|
+
```bash
|
|
452
|
+
llm-wiki lint --workspace /path/to/project
|
|
453
|
+
llm-wiki maintenance --workspace /path/to/project
|
|
454
|
+
llm-wiki consolidate --workspace /path/to/project
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
## Manual Maintenance Rule
|
|
458
|
+
|
|
459
|
+
이 문서는 `llm-wiki manual`의 출력 원본이다.
|
|
460
|
+
|
|
461
|
+
새 public command, option, hook behavior, directory convention, security policy, update flow가 생기면 구현과 같은 change set에서 `docs/manual.md`를 갱신한다. README는 빠른 시작과 요약을 담고, 자세한 기능 설명은 이 manual에 둔다.
|
package/docs/operations.md
CHANGED
|
@@ -120,24 +120,29 @@ After a plain `npm install -g llm-wiki-kit@latest`, existing hooks keep working
|
|
|
120
120
|
|
|
121
121
|
## Context And Wiki Maintenance
|
|
122
122
|
|
|
123
|
-
Daily use should be Claude Code/Codex first. The user should not need to run a chain of `llm-wiki` commands while working. Hooks inject
|
|
123
|
+
Daily use should be Claude Code/Codex first. The user should not need to run a chain of `llm-wiki` commands while working. Hooks inject context automatically, but the current user answer takes priority over wiki cleanup. The active agent updates durable wiki pages when reusable project knowledge appears and the turn's importance or user consent justifies persistence.
|
|
124
124
|
|
|
125
|
-
`Stop` and `SessionEnd`
|
|
125
|
+
In the default `LLM_WIKI_KIT_CAPTURE_MODE=answer-first` mode, `Stop` and `SessionEnd` append live Q&A only for meaningful work turns. They do not auto-create `wiki/queries/` or `wiki/decisions/`. If the user explicitly asked for recording/documentation and no durable wiki update is detected, a pending cleanup candidate is written to `llm-wiki/outputs/maintenance/queue.md`. `SessionStart` and `UserPromptSubmit` also recover stale per-turn state into the same queue when the previous stop hook did not complete. `SessionStart` injects a one-item queue summary; `UserPromptSubmit` injects a soft reminder only when the prompt is wiki/maintenance related or matches a queue topic. This is a recovery and reminder layer, not a full transcript capture path.
|
|
126
|
+
|
|
127
|
+
`LLM_WIKI_KIT_CAPTURE_MODE=legacy-eager` keeps the old eager live Q&A/query/decision/maintenance behavior for compatibility only. New projects should rely on the answer-first default.
|
|
126
128
|
|
|
127
129
|
`llm-wiki context "<query>"` is the manual debug form of hook context injection. It reads:
|
|
128
130
|
|
|
129
131
|
- `llm-wiki/wiki/memory.md` as the short hot index
|
|
130
132
|
- `llm-wiki/wiki/index.md` as the navigation map
|
|
131
|
-
- MiniSearch results from `llm-wiki/wiki/**/*.md`, with substring fallback when MiniSearch is unavailable
|
|
133
|
+
- MiniSearch results from durable `llm-wiki/wiki/**/*.md`, with substring fallback when MiniSearch is unavailable
|
|
132
134
|
- one-hop wikilink neighbors for the strongest matches
|
|
133
135
|
- redacted output fields for query text, memory/index/log excerpts, hit paths, titles, snippets, matched terms, and link expansion metadata
|
|
134
136
|
|
|
137
|
+
Default context search excludes episodic `wiki/queries/` pages unless they were explicitly promoted with `memory_type: semantic` or `procedural` and `importance >= 4`. Use `--include-episodic` only when debugging historical automatic query pages:
|
|
138
|
+
|
|
135
139
|
Use it only when you want to inspect what the next agent turn should see:
|
|
136
140
|
|
|
137
141
|
```bash
|
|
138
142
|
llm-wiki context "auth architecture" --workspace /path/to/project
|
|
139
143
|
llm-wiki context "auth architecture" --workspace /path/to/project --json
|
|
140
144
|
llm-wiki context "auth architecture" --workspace /path/to/project --limit 8 --no-expand
|
|
145
|
+
llm-wiki context "auth architecture" --workspace /path/to/project --include-episodic
|
|
141
146
|
```
|
|
142
147
|
|
|
143
148
|
`llm-wiki lint` checks Markdown wiki health without modifying files:
|
package/docs/troubleshooting.md
CHANGED
|
@@ -179,7 +179,7 @@ Check:
|
|
|
179
179
|
|
|
180
180
|
## Maintenance Queue Is Empty Or Stale
|
|
181
181
|
|
|
182
|
-
`llm-wiki/outputs/maintenance/queue.md` is created only
|
|
182
|
+
In the default answer-first mode, `llm-wiki/outputs/maintenance/queue.md` is created only when a user explicitly asked for durable recording/documentation but no durable wiki update was detected, or when `SessionStart`/`UserPromptSubmit` recovers stale per-turn state from a session that did not stop cleanly. It is not expected to grow after every normal `Stop`.
|
|
183
183
|
|
|
184
184
|
Check the queue and health warnings:
|
|
185
185
|
|
|
@@ -188,7 +188,7 @@ llm-wiki maintenance --workspace /path/to/project
|
|
|
188
188
|
llm-wiki lint --workspace /path/to/project
|
|
189
189
|
```
|
|
190
190
|
|
|
191
|
-
If the queue is always empty, confirm hooks run and that the turn had a captured `UserPromptSubmit`. If pending items stay around, the active agent should merge reusable content into existing durable wiki pages and mark each
|
|
191
|
+
If the queue is always empty during ordinary Q&A, that is normal. If you expected an explicit documentation request to queue, confirm hooks run and that the turn had a captured `UserPromptSubmit`. If pending items stay around, the active agent should merge reusable content into existing durable wiki pages and mark each item `done` or `skipped` without delaying unrelated answers.
|
|
192
192
|
|
|
193
193
|
## Authentication Values Were Redacted
|
|
194
194
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
const NOT_CAPTURED = '(not captured)';
|
|
2
|
+
|
|
3
|
+
const EXPLICIT_DURABLE_RE = /(?:기록해|기록해줘|문서화|문서화해|wiki에\s*남겨|위키에\s*남겨|wiki[^.\n]{0,40}(?:남겨|저장|기록)|위키[^.\n]{0,40}(?:남겨|저장|기록)|remember\s+this|save\s+this|document\s+this|record\s+this|persist\s+this)/i;
|
|
4
|
+
|
|
5
|
+
const DURABLE_KEYWORD_RE = /(?:debug|bug|fix|failure|failed|error|root cause|architecture|runtime|hook|install|update|deploy|release|publish|migration|security|policy|procedure|decision|decided|verification|test|lint|build|doctor|디버깅|버그|오류|에러|실패|수정|원인|아키텍처|구조|런타임|훅|설치|업데이트|배포|릴리스|마이그레이션|보안|정책|절차|결정|선택|채택|확정|검증|테스트|문서|위키|wiki)/i;
|
|
6
|
+
|
|
7
|
+
const MAINTENANCE_QUERY_RE = /(?:llm-wiki|wiki|위키|maintenance|maintain|문서|문서화|기록|정리|consolidate|lint|queue|AGENTS\.md)/i;
|
|
8
|
+
|
|
9
|
+
export function captureMode(env = process.env) {
|
|
10
|
+
return env.LLM_WIKI_KIT_CAPTURE_MODE === 'legacy-eager' ? 'legacy-eager' : 'answer-first';
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function isLegacyEagerCaptureMode(env = process.env) {
|
|
14
|
+
return captureMode(env) === 'legacy-eager';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function capturedText(value) {
|
|
18
|
+
const text = String(value || '').trim();
|
|
19
|
+
if (!text || text === NOT_CAPTURED) return '';
|
|
20
|
+
return text;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function hasCapturedQuestion(entry) {
|
|
24
|
+
return capturedText(entry?.question).length >= 8;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function entrySearchText(entry) {
|
|
28
|
+
return [
|
|
29
|
+
entry?.question,
|
|
30
|
+
entry?.result,
|
|
31
|
+
entry?.work,
|
|
32
|
+
entry?.changedFiles,
|
|
33
|
+
entry?.verification,
|
|
34
|
+
].map(capturedText).filter(Boolean).join('\n');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function explicitDurableRequested(value) {
|
|
38
|
+
const text = typeof value === 'string' ? value : entrySearchText(value);
|
|
39
|
+
return EXPLICIT_DURABLE_RE.test(text);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function hasDurableKeyword(value) {
|
|
43
|
+
const text = typeof value === 'string' ? value : entrySearchText(value);
|
|
44
|
+
return DURABLE_KEYWORD_RE.test(text);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function isMaintenanceRelatedQuery(query, pendingItems = []) {
|
|
48
|
+
const text = capturedText(query);
|
|
49
|
+
if (!text) return false;
|
|
50
|
+
if (MAINTENANCE_QUERY_RE.test(text)) return true;
|
|
51
|
+
const terms = text
|
|
52
|
+
.normalize('NFC')
|
|
53
|
+
.toLowerCase()
|
|
54
|
+
.replace(/[^\p{Letter}\p{Number}]+/gu, ' ')
|
|
55
|
+
.split(/\s+/)
|
|
56
|
+
.filter((term) => term.length >= 3);
|
|
57
|
+
if (terms.length === 0) return false;
|
|
58
|
+
return pendingItems.some((item) => {
|
|
59
|
+
const topic = `${item.topic || ''} ${item.source || ''}`.normalize('NFC').toLowerCase();
|
|
60
|
+
return terms.some((term) => topic.includes(term));
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function hasDetectedDurableWikiChange(entry) {
|
|
65
|
+
const text = [
|
|
66
|
+
entry?.changedFiles,
|
|
67
|
+
entry?.work,
|
|
68
|
+
].map(capturedText).filter(Boolean).join('\n');
|
|
69
|
+
return /(?:^|[\s"'`])(?:llm-wiki\/)?(?:wiki\/(?!queries\/)(?:architecture|debugging|decisions|concepts|entities|sources|context)\/|procedures\/|llm-wiki\/wiki\/(?!queries\/)(?:architecture|debugging|decisions|concepts|entities|sources|context)\/|llm-wiki\/procedures\/)[^\s"'`]+\.md\b/i.test(text);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function classifyTurn(entry, eventName = '') {
|
|
73
|
+
if (eventName === 'SubagentStop') {
|
|
74
|
+
return {
|
|
75
|
+
kind: 'subagent',
|
|
76
|
+
archive: false,
|
|
77
|
+
suggestDurable: false,
|
|
78
|
+
queueIfMissingDurable: false,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const question = capturedText(entry?.question);
|
|
83
|
+
const result = capturedText(entry?.result);
|
|
84
|
+
const work = capturedText(entry?.work);
|
|
85
|
+
const changedFiles = capturedText(entry?.changedFiles);
|
|
86
|
+
const verification = capturedText(entry?.verification);
|
|
87
|
+
const text = entrySearchText(entry);
|
|
88
|
+
|
|
89
|
+
if (!question && !result) {
|
|
90
|
+
return {
|
|
91
|
+
kind: 'empty',
|
|
92
|
+
archive: false,
|
|
93
|
+
suggestDurable: false,
|
|
94
|
+
queueIfMissingDurable: false,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (explicitDurableRequested(text)) {
|
|
99
|
+
return {
|
|
100
|
+
kind: 'explicit-durable',
|
|
101
|
+
archive: true,
|
|
102
|
+
suggestDurable: false,
|
|
103
|
+
queueIfMissingDurable: true,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const hasWork = Boolean(work);
|
|
108
|
+
const hasFiles = Boolean(changedFiles);
|
|
109
|
+
const hasVerification = Boolean(verification);
|
|
110
|
+
const longWork = work.length > 800;
|
|
111
|
+
const durableKeyword = hasDurableKeyword(text);
|
|
112
|
+
const simple =
|
|
113
|
+
!hasWork &&
|
|
114
|
+
!hasFiles &&
|
|
115
|
+
!hasVerification &&
|
|
116
|
+
question.length <= 120 &&
|
|
117
|
+
result.length <= 800 &&
|
|
118
|
+
!durableKeyword;
|
|
119
|
+
|
|
120
|
+
if (simple) {
|
|
121
|
+
return {
|
|
122
|
+
kind: 'simple',
|
|
123
|
+
archive: false,
|
|
124
|
+
suggestDurable: false,
|
|
125
|
+
queueIfMissingDurable: false,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (durableKeyword) {
|
|
130
|
+
return {
|
|
131
|
+
kind: 'suggest-durable',
|
|
132
|
+
archive: true,
|
|
133
|
+
suggestDurable: true,
|
|
134
|
+
queueIfMissingDurable: false,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
kind: hasWork || hasFiles || hasVerification || longWork || result.length > 800 ? 'archive-only' : 'simple',
|
|
140
|
+
archive: hasWork || hasFiles || hasVerification || longWork || result.length > 800,
|
|
141
|
+
suggestDurable: false,
|
|
142
|
+
queueIfMissingDurable: false,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export function formatDurableCaptureGuidance(query) {
|
|
147
|
+
const text = capturedText(query);
|
|
148
|
+
if (!text) return '';
|
|
149
|
+
if (explicitDurableRequested(text)) {
|
|
150
|
+
return [
|
|
151
|
+
'LLM Wiki durable documentation request detected:',
|
|
152
|
+
'- 현재 사용자 요청을 먼저 처리하되, 사용자가 기록/문서화를 요청했으므로 기존 durable wiki 문서를 찾아 갱신한다.',
|
|
153
|
+
'- 새 문서는 관련 기존 문서가 없을 때만 만들고, credentials/private data는 저장하지 않는다.',
|
|
154
|
+
].join('\n');
|
|
155
|
+
}
|
|
156
|
+
if (hasDurableKeyword(text)) {
|
|
157
|
+
return [
|
|
158
|
+
'LLM Wiki durable knowledge note:',
|
|
159
|
+
'- 현재 답변을 먼저 한다. 다음 세션에도 쓸 결론이면 답변 끝에서 짧게 wiki 문서화 여부를 물어본다.',
|
|
160
|
+
].join('\n');
|
|
161
|
+
}
|
|
162
|
+
return '';
|
|
163
|
+
}
|
package/src/cli.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { readFile } from 'fs/promises';
|
|
1
2
|
import { resolve } from 'path';
|
|
2
3
|
import { formatConsolidateResult, runConsolidate } from './consolidate.js';
|
|
3
4
|
import { handleHook } from './hook.js';
|
|
@@ -51,6 +52,8 @@ function parseOptions(args) {
|
|
|
51
52
|
i += 1;
|
|
52
53
|
} else if (arg === '--no-expand') {
|
|
53
54
|
options.expand = false;
|
|
55
|
+
} else if (arg === '--include-episodic') {
|
|
56
|
+
options.includeEpisodic = true;
|
|
54
57
|
} else if (arg === '--replace-hooks') {
|
|
55
58
|
options.replaceHooks = true;
|
|
56
59
|
} else if (arg === '--all') {
|
|
@@ -91,12 +94,13 @@ Usage:
|
|
|
91
94
|
llm-wiki projects --workspace /apps
|
|
92
95
|
llm-wiki status
|
|
93
96
|
llm-wiki version
|
|
97
|
+
llm-wiki manual
|
|
94
98
|
llm-wiki uninstall
|
|
95
99
|
llm-wiki hook codex <EventName>
|
|
96
100
|
llm-wiki hook claude <EventName>
|
|
97
101
|
llm-wiki bootstrap --workspace <project>
|
|
98
102
|
llm-wiki migrate --workspace <project>
|
|
99
|
-
llm-wiki context "<query>" --workspace <project> [--limit 5] [--no-expand]
|
|
103
|
+
llm-wiki context "<query>" --workspace <project> [--limit 5] [--no-expand] [--include-episodic]
|
|
100
104
|
llm-wiki lint --workspace <project>
|
|
101
105
|
llm-wiki consolidate --workspace <project> [--dry-run]
|
|
102
106
|
llm-wiki maintenance --workspace <project> [--json]
|
|
@@ -139,6 +143,12 @@ Usage:
|
|
|
139
143
|
return;
|
|
140
144
|
}
|
|
141
145
|
|
|
146
|
+
if (command === 'manual') {
|
|
147
|
+
const manual = await readFile(new URL('../docs/manual.md', import.meta.url), 'utf8');
|
|
148
|
+
process.stdout.write(manual.endsWith('\n') ? manual : `${manual}\n`);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
142
152
|
if (command === 'projects') {
|
|
143
153
|
const result = await listProjects(options);
|
|
144
154
|
printJsonOrText(result, options, formatProjects);
|
package/src/hook.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { findProjectRoot } from './fs-utils.js';
|
|
2
|
+
import { classifyTurn, formatDurableCaptureGuidance, hasDetectedDurableWikiChange, isLegacyEagerCaptureMode } from './capture-policy.js';
|
|
2
3
|
import { bootstrapProject, appendContextNote, appendLiveQa, appendSessionEnvelope, appendWikiLog, buildContextBrief, writeDecisionPage, writeQueryPage } from './project.js';
|
|
3
4
|
import { recoverStaleTurnStates, recordMaintenanceForEntry } from './maintenance.js';
|
|
4
5
|
import { applyProjectTemplateUpdate, inspectProjectState } from './project-state.js';
|
|
@@ -41,6 +42,49 @@ function contextOutput(eventName, context) {
|
|
|
41
42
|
};
|
|
42
43
|
}
|
|
43
44
|
|
|
45
|
+
async function handleLegacyEagerStop(projectRoot, eventName, payload, entry) {
|
|
46
|
+
if (entry.question !== '(not captured)' || entry.result !== '(not captured)') {
|
|
47
|
+
const liveQaPath = await appendLiveQa(projectRoot, entry);
|
|
48
|
+
const queryPath = await writeQueryPage(projectRoot, entry);
|
|
49
|
+
const decisionPath = await writeDecisionPage(projectRoot, entry);
|
|
50
|
+
if (eventName === 'Stop' || eventName === 'SessionEnd') {
|
|
51
|
+
await recordMaintenanceForEntry(projectRoot, entry, {
|
|
52
|
+
source: decisionPath || queryPath || liveQaPath,
|
|
53
|
+
eventName,
|
|
54
|
+
reason: 'Captured turn needs durable wiki review.',
|
|
55
|
+
}).catch(() => {});
|
|
56
|
+
}
|
|
57
|
+
await appendWikiLog(projectRoot, `captured ${eventName}${queryPath ? `; query=${relative(projectRoot, queryPath)}` : ''}${decisionPath ? `; decision=${relative(projectRoot, decisionPath)}` : ''}`);
|
|
58
|
+
}
|
|
59
|
+
if (eventName === 'Stop' || eventName === 'SessionEnd') {
|
|
60
|
+
await clearTurnState(projectRoot, payload).catch(() => {});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async function handleAnswerFirstStop(projectRoot, eventName, payload, entry) {
|
|
65
|
+
const classification = classifyTurn(entry, eventName);
|
|
66
|
+
if (classification.archive) {
|
|
67
|
+
const archiveEntry = {
|
|
68
|
+
...entry,
|
|
69
|
+
followUp: classification.suggestDurable
|
|
70
|
+
? '이 결론은 다음 세션에도 쓸 수 있어 보입니다. 사용자가 승인하면 기존 durable wiki 문서에 합친다.'
|
|
71
|
+
: entry.followUp,
|
|
72
|
+
};
|
|
73
|
+
const liveQaPath = await appendLiveQa(projectRoot, archiveEntry);
|
|
74
|
+
if (classification.queueIfMissingDurable && !hasDetectedDurableWikiChange(entry)) {
|
|
75
|
+
await recordMaintenanceForEntry(projectRoot, entry, {
|
|
76
|
+
source: liveQaPath,
|
|
77
|
+
eventName,
|
|
78
|
+
reason: 'Explicit durable documentation request did not have a detected durable wiki update.',
|
|
79
|
+
}).catch(() => {});
|
|
80
|
+
}
|
|
81
|
+
await appendWikiLog(projectRoot, `captured ${eventName}; archive=${relative(projectRoot, liveQaPath)}; classification=${classification.kind}`);
|
|
82
|
+
}
|
|
83
|
+
if (eventName === 'Stop' || eventName === 'SessionEnd') {
|
|
84
|
+
await clearTurnState(projectRoot, payload).catch(() => {});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
44
88
|
async function autoUpdateManagedProject(projectRoot, eventName) {
|
|
45
89
|
if (process.env.LLM_WIKI_KIT_AUTO_PROJECT_UPDATE === '0') return;
|
|
46
90
|
if (eventName !== 'SessionStart' && eventName !== 'InstructionsLoaded') return;
|
|
@@ -74,7 +118,8 @@ export async function handleHook(provider, explicitEvent) {
|
|
|
74
118
|
if (eventName === 'UserPromptSubmit') {
|
|
75
119
|
const prompt = promptText(payload);
|
|
76
120
|
await rememberQuestion(projectRoot, payload, prompt);
|
|
77
|
-
const
|
|
121
|
+
const guidance = formatDurableCaptureGuidance(prompt);
|
|
122
|
+
const context = [await buildContextBrief(projectRoot, eventName, prompt), guidance].filter(Boolean).join('\n\n');
|
|
78
123
|
return contextOutput(eventName, context);
|
|
79
124
|
}
|
|
80
125
|
|
|
@@ -99,21 +144,10 @@ export async function handleHook(provider, explicitEvent) {
|
|
|
99
144
|
if (eventName === 'Stop' || eventName === 'SubagentStop' || eventName === 'SessionEnd') {
|
|
100
145
|
const assistantText = payload.last_assistant_message || payload.response || payload.assistant_response || '';
|
|
101
146
|
const entry = await buildEntryFromState(projectRoot, payload, assistantText);
|
|
102
|
-
if (
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
if (eventName === 'Stop' || eventName === 'SessionEnd') {
|
|
107
|
-
await recordMaintenanceForEntry(projectRoot, entry, {
|
|
108
|
-
source: decisionPath || queryPath || liveQaPath,
|
|
109
|
-
eventName,
|
|
110
|
-
reason: 'Captured turn needs durable wiki review.',
|
|
111
|
-
}).catch(() => {});
|
|
112
|
-
}
|
|
113
|
-
await appendWikiLog(projectRoot, `captured ${eventName}${queryPath ? `; query=${relative(projectRoot, queryPath)}` : ''}${decisionPath ? `; decision=${relative(projectRoot, decisionPath)}` : ''}`);
|
|
114
|
-
}
|
|
115
|
-
if (eventName === 'Stop' || eventName === 'SessionEnd') {
|
|
116
|
-
await clearTurnState(projectRoot, payload).catch(() => {});
|
|
147
|
+
if (isLegacyEagerCaptureMode()) {
|
|
148
|
+
await handleLegacyEagerStop(projectRoot, eventName, payload, entry);
|
|
149
|
+
} else {
|
|
150
|
+
await handleAnswerFirstStop(projectRoot, eventName, payload, entry);
|
|
117
151
|
}
|
|
118
152
|
return {};
|
|
119
153
|
}
|
package/src/maintenance.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readdir, unlink } from 'fs/promises';
|
|
2
2
|
import { join, relative } from 'path';
|
|
3
3
|
import { appendText, exists, kitDataDir, readJson, readText, sha256, writeTextIfMissing } from './fs-utils.js';
|
|
4
|
+
import { classifyTurn, isMaintenanceRelatedQuery } from './capture-policy.js';
|
|
4
5
|
import { redactText, summarizeForStorage } from './redaction.js';
|
|
5
6
|
import { buildEntryFromTurnState, hasRecoverableTurnState } from './state.js';
|
|
6
7
|
|
|
@@ -206,6 +207,11 @@ export async function recoverStaleTurnStates(projectRoot, options = {}) {
|
|
|
206
207
|
if (Number.isFinite(updated) && now - updated < cutoffMs) continue;
|
|
207
208
|
if (!hasRecoverableTurnState(state)) continue;
|
|
208
209
|
const entry = buildEntryFromTurnState(state, '');
|
|
210
|
+
if (!classifyTurn(entry, 'recovered stale turn state').archive) {
|
|
211
|
+
await unlink(path).catch(() => {});
|
|
212
|
+
output.push({ created: false, reason: 'simple-stale-turn', statePath: path, session: state.session });
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
209
215
|
const result = await recordMaintenanceForEntry(projectRoot, entry, {
|
|
210
216
|
source: `state:${state.session || path.split('/').pop()?.replace(/\.json$/, '')}`,
|
|
211
217
|
eventName: 'recovered stale turn state',
|
|
@@ -219,12 +225,24 @@ export async function recoverStaleTurnStates(projectRoot, options = {}) {
|
|
|
219
225
|
}
|
|
220
226
|
|
|
221
227
|
export function formatMaintenanceContext(summary, options = {}) {
|
|
222
|
-
const
|
|
223
|
-
const
|
|
228
|
+
const eventName = options.eventName || '';
|
|
229
|
+
const defaultLimit = eventName === 'SessionStart' || eventName === 'InstructionsLoaded' ? 1 : 5;
|
|
230
|
+
const limit = options.limit || defaultLimit;
|
|
231
|
+
let pending = summary.pending.slice(0, limit);
|
|
224
232
|
if (pending.length === 0) return '';
|
|
233
|
+
|
|
234
|
+
if (eventName === 'UserPromptSubmit') {
|
|
235
|
+
if (!isMaintenanceRelatedQuery(options.query || '', summary.pending)) return '';
|
|
236
|
+
pending = summary.pending.slice(0, 1);
|
|
237
|
+
} else if (eventName !== 'SessionStart' && eventName !== 'InstructionsLoaded') {
|
|
238
|
+
return '';
|
|
239
|
+
}
|
|
240
|
+
|
|
225
241
|
const lines = [
|
|
226
|
-
|
|
227
|
-
|
|
242
|
+
eventName === 'UserPromptSubmit'
|
|
243
|
+
? 'LLM Wiki maintenance queue soft reminder:'
|
|
244
|
+
: 'LLM Wiki maintenance queue summary:',
|
|
245
|
+
`- pending: ${summary.pendingCount}. 현재 사용자 요청을 지연시키지 말고, 관련 있을 때만 기존 durable wiki 문서에 병합한다.`,
|
|
228
246
|
];
|
|
229
247
|
for (const item of pending) {
|
|
230
248
|
lines.push(`- ${item.topic || item.id}: source=${item.source}; target=${item.suggested_target}; reason=${item.reason}${item.result_missing ? '; result_missing=true' : ''}`);
|
package/src/project.js
CHANGED
|
@@ -169,7 +169,7 @@ export async function buildContextBrief(projectRoot, eventName, query = '') {
|
|
|
169
169
|
.then(formatProjectMaintenanceContext)
|
|
170
170
|
.catch(() => '');
|
|
171
171
|
const wikiMaintenance = await maintenanceSummary(projectRoot)
|
|
172
|
-
.then(formatMaintenanceContext)
|
|
172
|
+
.then((summary) => formatMaintenanceContext(summary, { eventName, query }))
|
|
173
173
|
.catch(() => '');
|
|
174
174
|
return [formatContextPack(pack), maintenance, wikiMaintenance].filter(Boolean).join('\n\n');
|
|
175
175
|
}
|
package/src/templates.js
CHANGED
|
@@ -13,11 +13,11 @@ This repository uses llm-wiki-kit as a hook-first living Markdown wiki for Codex
|
|
|
13
13
|
- \`llm-wiki/raw/\`는 원본 또는 redacted 근거 저장소다. hook envelope append 외에는 원본 capture를 수정하지 않는다.
|
|
14
14
|
- \`llm-wiki/wiki/\`는 agent가 관리하는 지식층이다. 결정, 구조, 디버깅, 개념, 절차, 맥락을 여기에 정리한다.
|
|
15
15
|
- \`llm-wiki/wiki/memory.md\`는 짧은 핵심 기억이다. 긴 설명 대신 현재 상태와 중요한 문서 링크만 유지한다.
|
|
16
|
-
- hook이 주입한 context를
|
|
17
|
-
- hook은 redacted live Q&A
|
|
18
|
-
- hook은 종료/시작 경계에서 정리 후보를 \`llm-wiki/outputs/maintenance/queue.md\`에 남길 수 있다. pending 항목은
|
|
16
|
+
- hook이 주입한 context를 참고하되, 현재 사용자 답변을 먼저 처리한다. 수동 확인이나 정리에는 \`llm-wiki context\`, \`llm-wiki lint\`, \`llm-wiki consolidate\`를 agent 보조 도구로 사용한다.
|
|
17
|
+
- hook은 redacted raw envelope와 필요한 live Q&A를 안전하게 남긴다. \`wiki/queries\`/\`wiki/decisions\` 자동 승격은 기본값이 아니며, durable 지식은 중요도와 동의 흐름에 따라 agent가 기존 정식 wiki 문서에 합친다.
|
|
18
|
+
- hook은 종료/시작 경계에서 정말 필요한 정리 후보를 \`llm-wiki/outputs/maintenance/queue.md\`에 남길 수 있다. pending 항목은 현재 응답을 지연시키지 않는 범위에서 agent가 병합하거나 done/skipped로 표시한다.
|
|
19
19
|
- 새 문서를 만들기 전에 기존 wiki 문서를 먼저 찾아 갱신한다. 반복해서 쓸 사실은 \`outputs/questions/\`에만 두지 말고 적절한 wiki 문서에 합친다.
|
|
20
|
-
- 일회성 작업 기록은 \`llm-wiki/outputs/questions/\`에 보존하고, 재사용 가능한 결론은 \`wiki/architecture/\`, \`wiki/debugging/\`, \`wiki/decisions/\`, \`wiki/concepts/\`, \`procedures/\`에 반영한다.
|
|
20
|
+
- 일회성 작업 기록은 필요할 때 \`llm-wiki/outputs/questions/\`에 보존하고, 재사용 가능한 결론은 승인된 경우 \`wiki/architecture/\`, \`wiki/debugging/\`, \`wiki/decisions/\`, \`wiki/concepts/\`, \`procedures/\`에 반영한다.
|
|
21
21
|
- 검증 명령, 근거 파일, 불확실한 점을 함께 남긴다. 추론은 추론이라고 표시하고, 모순은 지우지 말고 Open Questions 또는 Contradictions에 남긴다.
|
|
22
22
|
- 인증값, token, password, private key, \`.env\` 원문은 저장하지 않는다. 필요한 경우 redacted summary만 남긴다.
|
|
23
23
|
|
|
@@ -32,7 +32,7 @@ Generated by llm-wiki-kit ${runtimeVersion()}.
|
|
|
32
32
|
|
|
33
33
|
## Purpose
|
|
34
34
|
Codex와 Claude Code를 평소처럼 사용하는 동안 living Markdown LLM Wiki를 자연스럽게 유지한다.
|
|
35
|
-
사용자가 많은 \`llm-wiki\` 명령을 직접 실행하는 방식이 아니라, agent가 작업 중 필요한 wiki 조회와 정리를
|
|
35
|
+
사용자가 많은 \`llm-wiki\` 명령을 직접 실행하는 방식이 아니라, agent가 작업 중 필요한 wiki 조회와 정리를 수행하되 현재 사용자 답변을 지연시키지 않는 것이 기본이다.
|
|
36
36
|
이 규칙은 오래된 OMX/OMC/\`omx_wiki/\` 규칙을 대체한다.
|
|
37
37
|
|
|
38
38
|
## Directories
|
|
@@ -42,13 +42,14 @@ Codex와 Claude Code를 평소처럼 사용하는 동안 living Markdown LLM Wik
|
|
|
42
42
|
- \`procedures/\`: ingest, query, lint, security 같은 운영 규칙.
|
|
43
43
|
|
|
44
44
|
## Core Rules
|
|
45
|
-
- 사용자는 Claude Code/Codex를 평소처럼 사용한다. agent가 필요한 wiki 조회와 정리를 자연스럽게
|
|
45
|
+
- 사용자는 Claude Code/Codex를 평소처럼 사용한다. agent가 필요한 wiki 조회와 정리를 자연스럽게 수행하되, 현재 사용자 요청에 대한 답변을 먼저 끝낸다.
|
|
46
46
|
- \`raw/\` 원본은 수정하지 않는다. 안전한 hook envelope append만 예외다.
|
|
47
47
|
- 근거 없는 내용을 사실처럼 쓰지 않는다. 추론은 명시한다.
|
|
48
48
|
- 중요한 주장에는 \`source_ids\`, 파일 경로, 검증 명령 중 하나 이상을 남긴다.
|
|
49
49
|
- 오래 남길 내용이 생기면 새 문서부터 만들지 말고 기존 \`wiki/\` 문서를 먼저 찾아 갱신한다.
|
|
50
|
-
-
|
|
51
|
-
-
|
|
50
|
+
- 단순 답변, 상태 확인, 일회성 대화는 과도하게 \`wiki/queries\`나 maintenance로 승격하지 않는다.
|
|
51
|
+
- 반복해서 쓸 지식은 중요도와 동의 흐름에 따라 \`wiki/architecture/\`, \`wiki/debugging/\`, \`wiki/decisions/\`, \`wiki/concepts/\`, \`procedures/\`에 합친다.
|
|
52
|
+
- hook이 만든 \`outputs/maintenance/queue.md\` pending 항목은 현재 요청과 관련 있을 때 확인하고, 기존 정식 wiki 문서에 병합한 뒤 done 또는 skipped로 표시한다.
|
|
52
53
|
- \`wiki/memory.md\`는 짧게 유지한다. 긴 설명 대신 현재 상태와 중요한 문서 링크를 둔다.
|
|
53
54
|
- 모순은 덮어쓰지 말고 \`Contradictions\` 또는 \`Open Questions\`에 보존한다.
|
|
54
55
|
- 인증값, token, password, private key, \`.env\` 원문은 wiki에 저장하지 않는다.
|
|
@@ -74,10 +75,10 @@ superseded_by: []
|
|
|
74
75
|
|
|
75
76
|
## Operations
|
|
76
77
|
- ingest: \`wiki/memory.md\`와 \`wiki/index.md\`를 먼저 읽고, 새 근거를 확인한 뒤 기존 wiki 문서를 우선 갱신한다.
|
|
77
|
-
- query: hook이 주입한 context를
|
|
78
|
-
- lint:
|
|
78
|
+
- query: hook이 주입한 context를 참고하되 현재 답변을 먼저 한다. 수동 명령은 점검용이며 일반 사용 흐름의 필수 단계가 아니다.
|
|
79
|
+
- lint: 사용자가 요청했거나 wiki 유지보수 작업일 때 agent가 쓰는 보조 도구다. 매 turn 실행하지 않는다.
|
|
79
80
|
- consolidate: agent가 \`memory.md\`/\`index.md\` generated block을 안전하게 갱신할 때 쓰는 보조 도구다. 손글씨 영역과 정식 문서 본문은 덮어쓰지 않는다.
|
|
80
|
-
- maintenance: \`outputs/maintenance/queue.md\`는 종료/시작 경계에서 생긴 정리 후보 목록이다. agent가 기존 문서 병합 여부를 판단하고 상태를 갱신한다.
|
|
81
|
+
- maintenance: \`outputs/maintenance/queue.md\`는 종료/시작 경계에서 생긴 정리 후보 목록이다. 현재 요청을 지연시키지 않는 범위에서 agent가 기존 문서 병합 여부를 판단하고 상태를 갱신한다.
|
|
81
82
|
`;
|
|
82
83
|
}
|
|
83
84
|
|
|
@@ -169,19 +170,21 @@ export function procedure(name) {
|
|
|
169
170
|
3. source별 요약이 필요하면 \`wiki/sources/<slug>.md\`를 만들거나 갱신한다.
|
|
170
171
|
4. 새 문서부터 만들지 말고 관련 concept/entity/decision/architecture/debugging/context 문서를 먼저 찾아 갱신한다.
|
|
171
172
|
5. 중복 문서를 만들지 않는다. 같은 사실이 이미 있으면 기존 문서에 합친다.
|
|
172
|
-
6.
|
|
173
|
-
7.
|
|
174
|
-
8.
|
|
173
|
+
6. 단순 답변과 일회성 대화는 durable wiki로 승격하지 않는다.
|
|
174
|
+
7. 중요한 주장에는 source reference, confidence, memory type, importance, verification status를 남긴다.
|
|
175
|
+
8. durable entry point가 바뀌면 \`wiki/memory.md\`를 짧게 갱신하거나 agent가 \`llm-wiki consolidate\`를 사용한다.
|
|
176
|
+
9. 의미 있는 변화는 \`wiki/log.md\`에 짧게 남긴다.
|
|
175
177
|
`,
|
|
176
178
|
'query.md': `# Query Procedure
|
|
177
179
|
|
|
178
|
-
1.
|
|
180
|
+
1. 현재 사용자 질문에 먼저 답한다. hook이 주입한 context는 필요한 만큼만 참고한다.
|
|
179
181
|
2. \`wiki/memory.md\`와 \`wiki/index.md\`에서 시작한다.
|
|
180
182
|
3. 관련 \`wiki/\` 문서를 최소한으로 읽는다.
|
|
181
183
|
4. 정확한 근거가 필요할 때만 raw source를 확인한다.
|
|
182
184
|
5. 검증된 사실과 추론을 분리한다.
|
|
183
|
-
6.
|
|
184
|
-
7.
|
|
185
|
+
6. 수동 확인이 필요할 때만 \`llm-wiki context "<query>"\`를 쓴다. 과거 episodic query까지 봐야 할 때는 \`--include-episodic\`을 붙인다.
|
|
186
|
+
7. 일회성 답변은 durable wiki로 승격하지 않는다. 필요한 작업 turn만 \`outputs/questions/\`에 남긴다.
|
|
187
|
+
8. 반복해서 쓸 결론은 중요도와 동의 흐름에 따라 \`wiki/architecture/\`, \`wiki/debugging/\`, \`wiki/decisions/\`, \`wiki/concepts/\`, \`procedures/\`에 합친다.
|
|
185
188
|
`,
|
|
186
189
|
'lint.md': `# Lint Procedure
|
|
187
190
|
|
package/src/wiki-search.js
CHANGED
|
@@ -79,6 +79,20 @@ function sortHits(a, b) {
|
|
|
79
79
|
return a.path.localeCompare(b.path);
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
function importance(page) {
|
|
83
|
+
const value = Number(page?.frontmatter?.importance || 0);
|
|
84
|
+
return Number.isFinite(value) ? value : 0;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function isDefaultSearchCandidate(page, options = {}) {
|
|
88
|
+
if (options.includeEpisodic) return true;
|
|
89
|
+
const type = String(page.type || '').toLowerCase();
|
|
90
|
+
if (type === 'query' || page.rel.startsWith('wiki/queries/')) {
|
|
91
|
+
return ['semantic', 'procedural'].includes(page.memoryType) && importance(page) >= 4;
|
|
92
|
+
}
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
|
|
82
96
|
export async function searchWiki(projectRoot, query, options = {}) {
|
|
83
97
|
return (await performSearch(projectRoot, query, options)).hits;
|
|
84
98
|
}
|
|
@@ -94,7 +108,7 @@ async function performSearch(projectRoot, query, options = {}) {
|
|
|
94
108
|
|
|
95
109
|
let pages = [];
|
|
96
110
|
try {
|
|
97
|
-
pages = await collectWikiPages(projectRoot, opts);
|
|
111
|
+
pages = (await collectWikiPages(projectRoot, opts)).filter((page) => isDefaultSearchCandidate(page, opts));
|
|
98
112
|
} catch {
|
|
99
113
|
return { hits: [], search: 'missing-wiki' };
|
|
100
114
|
}
|
|
@@ -212,12 +226,12 @@ export async function buildContextPack(projectRoot, query, options = {}) {
|
|
|
212
226
|
|
|
213
227
|
export function formatContextPack(pack) {
|
|
214
228
|
const lines = [
|
|
215
|
-
'LLM Wiki context from llm-wiki-kit:',
|
|
229
|
+
'LLM Wiki context from llm-wiki-kit: answer the current user request first; use wiki context only when it helps.',
|
|
216
230
|
'- Treat chat memory as temporary; update project Markdown when knowledge should persist.',
|
|
217
231
|
'- Preserve raw/wiki separation. Do not store secrets, tokens, .env contents, private keys, or personal/customer identifiers.',
|
|
218
232
|
'- Prefer updating existing wiki pages over creating duplicate pages.',
|
|
219
|
-
'- Claude Code/Codex를 평소처럼 사용한다. 사용자가 별도 명령을 실행하지 않아도 agent가 필요한 wiki 조회와 정리를
|
|
220
|
-
'- 오래 쓸 지식은
|
|
233
|
+
'- Claude Code/Codex를 평소처럼 사용한다. 사용자가 별도 명령을 실행하지 않아도 agent가 필요한 wiki 조회와 정리를 수행하되, 현재 사용자 답변을 지연시키지 않는다.',
|
|
234
|
+
'- durable 기록은 중요도와 동의 흐름에 따라 선택적으로 승격한다. 오래 쓸 지식은 승인된 경우 기존 wiki/architecture, wiki/debugging, wiki/decisions, wiki/concepts, procedures 문서에 합친다.',
|
|
221
235
|
'- wiki/memory.md는 짧은 핵심 기억으로 유지하고, 긴 설명 대신 관련 정식 문서 링크를 둔다.',
|
|
222
236
|
];
|
|
223
237
|
if (pack.query) {
|