llm-wiki-kit 0.2.11 → 0.2.13
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 +19 -7
- package/docs/integrations/claude-code.md +2 -0
- package/docs/integrations/codex.md +1 -0
- package/docs/manual.md +135 -396
- package/docs/operations.md +3 -1
- package/docs/troubleshooting.md +2 -0
- package/package.json +12 -2
- package/src/capture-policy.js +11 -4
- package/src/cli.js +17 -4
- package/src/hook.js +15 -7
- package/src/language.js +73 -0
- package/src/live-qa.js +1 -1
- package/src/maintenance.js +13 -8
- package/src/project-state.js +20 -9
- package/src/project.js +5 -3
- package/src/templates.js +89 -82
- package/src/update-notice.js +14 -4
- package/src/update.js +168 -3
- package/src/wiki-search.js +35 -13
package/src/templates.js
CHANGED
|
@@ -8,18 +8,19 @@ export function rootAgentsPolicy() {
|
|
|
8
8
|
This repository uses llm-wiki-kit as a hook-first living Markdown wiki for Codex and Claude Code.
|
|
9
9
|
|
|
10
10
|
- This block supersedes older OMX/OMC/\`omx_wiki/\` LLM Wiki instructions for this repository.
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
- \`llm-wiki/
|
|
15
|
-
- \`llm-wiki/wiki
|
|
16
|
-
-
|
|
17
|
-
- hook
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
11
|
+
- Use Codex or Claude Code normally. Do not create a workflow where users must remember extra \`llm-wiki\` commands during ordinary work.
|
|
12
|
+
- Language: respond in the user's current prompt language when it is clearly Korean or English. Keep technical identifiers, commands, paths, code, and original error text unchanged. If no prompt language is clear, follow local \`CLAUDE.md\`/\`AGENTS.md\` guidance, then fall back to English.
|
|
13
|
+
- Treat chat memory as temporary. Durable project knowledge belongs in repository Markdown under \`llm-wiki/\`.
|
|
14
|
+
- \`llm-wiki/raw/\` is the immutable or redacted evidence layer. Do not modify raw captures except safe hook envelope append.
|
|
15
|
+
- \`llm-wiki/wiki/\` is the curated knowledge layer managed by the agent. Put decisions, architecture, debugging findings, concepts, procedures, and context there.
|
|
16
|
+
- Keep \`llm-wiki/wiki/memory.md\` short. Link to important documents instead of copying long explanations.
|
|
17
|
+
- Use hook-injected context when helpful, but answer the current user request first. Use \`llm-wiki context\`, \`llm-wiki lint\`, and \`llm-wiki consolidate\` only as agent maintenance helpers.
|
|
18
|
+
- Hooks safely store redacted raw envelopes and work/decision-focused live Q&A. Simple answers, status checks, and keyword-only turns should not be promoted to live Q&A or durable wiki by default.
|
|
19
|
+
- Hooks may queue durable cleanup candidates in \`llm-wiki/outputs/maintenance/queue.md\` at stop/start boundaries. Treat maintenance as a soft agent-side reminder; merge pending items only when relevant and mark them \`done\` or \`skipped\`.
|
|
20
|
+
- Before creating new wiki pages, search existing pages and update the right one when possible. Reusable facts should not stay only in chunked \`outputs/questions/\`.
|
|
21
|
+
- Store one-off work or decision records in \`llm-wiki/outputs/questions/YYYY-MM-DD/live-qa-001.md\` when needed. Merge reusable knowledge into \`wiki/architecture/\`, \`wiki/debugging/\`, \`wiki/decisions/\`, \`wiki/concepts/\`, or \`procedures/\` when approved or clearly important.
|
|
22
|
+
- Record verification commands, evidence files, and uncertainty. Mark inference explicitly and preserve contradictions in Open Questions or Contradictions.
|
|
23
|
+
- Never store credentials, tokens, passwords, private keys, or raw \`.env\` contents. Store only redacted summaries when needed.
|
|
23
24
|
|
|
24
25
|
<!-- llm-wiki-kit:end -->
|
|
25
26
|
`;
|
|
@@ -31,29 +32,35 @@ export function llmWikiAgents() {
|
|
|
31
32
|
Generated by llm-wiki-kit ${runtimeVersion()}.
|
|
32
33
|
|
|
33
34
|
## Purpose
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
Maintain a living Markdown LLM Wiki while users work normally in Codex or Claude Code.
|
|
36
|
+
The user should not need to run many \`llm-wiki\` commands manually. The agent checks and maintains wiki context when useful, but the current user answer comes first.
|
|
37
|
+
These rules replace older OMX/OMC/\`omx_wiki/\` rules for this project.
|
|
38
|
+
|
|
39
|
+
## Language
|
|
40
|
+
- Follow the user's current prompt language when it is clearly Korean or English.
|
|
41
|
+
- If no current prompt language is clear, follow local \`CLAUDE.md\`/\`AGENTS.md\` guidance, then fall back to English.
|
|
42
|
+
- Keep commands, paths, code identifiers, API names, package names, logs, and original error text unchanged.
|
|
43
|
+
- Korean and English users should both be able to use Codex/Claude Code naturally without changing \`llm-wiki\` commands.
|
|
37
44
|
|
|
38
45
|
## Directories
|
|
39
|
-
- \`raw/\`:
|
|
40
|
-
- \`wiki/\`:
|
|
41
|
-
- \`outputs/\`: live Q&A,
|
|
42
|
-
- \`procedures/\`: ingest, query, lint, security
|
|
46
|
+
- \`raw/\`: immutable or redacted evidence. Do not edit raw captures except safe hook envelope append.
|
|
47
|
+
- \`wiki/\`: curated knowledge pages maintained by the agent. \`wiki/memory.md\` is the short hot index injected into hook context.
|
|
48
|
+
- \`outputs/\`: live Q&A, reports, maintenance candidates, and long generated artifacts. One-off records belong here.
|
|
49
|
+
- \`procedures/\`: operating rules for ingest, query, lint, and security.
|
|
43
50
|
|
|
44
51
|
## Core Rules
|
|
45
|
-
-
|
|
46
|
-
- \`raw/\`
|
|
47
|
-
-
|
|
48
|
-
-
|
|
49
|
-
-
|
|
50
|
-
-
|
|
51
|
-
-
|
|
52
|
-
-
|
|
53
|
-
-
|
|
54
|
-
- \`wiki/memory.md
|
|
55
|
-
-
|
|
56
|
-
-
|
|
52
|
+
- Users work normally in Claude Code/Codex. The agent performs wiki lookup and maintenance naturally, but answers the current request first.
|
|
53
|
+
- Do not modify \`raw/\` source material except safe hook envelope append.
|
|
54
|
+
- Do not state unsupported claims as facts. Mark inference explicitly.
|
|
55
|
+
- Important claims should include at least one of: \`source_ids\`, file paths, or verification commands.
|
|
56
|
+
- When durable knowledge appears, search existing \`wiki/\` pages before creating a new page.
|
|
57
|
+
- Do not promote simple answers, status checks, keyword-only replies, or one-off chat into live Q&A, \`wiki/queries\`, or maintenance.
|
|
58
|
+
- Merge reusable knowledge into \`wiki/architecture/\`, \`wiki/debugging/\`, \`wiki/decisions/\`, \`wiki/concepts/\`, or \`procedures/\` based on importance and user consent flow.
|
|
59
|
+
- Review \`outputs/maintenance/queue.md\` pending items only when related to the current request or when review is due. Merge into existing durable wiki pages, then mark items \`done\` or \`skipped\`.
|
|
60
|
+
- Periodic maintenance is agent review, not automatic editing. Show only short reminders at \`SessionStart\`/\`InstructionsLoaded\`, and only show prompt-time reminders for wiki/maintenance-related user prompts.
|
|
61
|
+
- Keep \`wiki/memory.md\` short. Use links to current state and important documents instead of long explanations.
|
|
62
|
+
- Preserve contradictions in \`Contradictions\` or \`Open Questions\`; do not overwrite them silently.
|
|
63
|
+
- Do not store credentials, tokens, passwords, private keys, or raw \`.env\` contents in wiki.
|
|
57
64
|
|
|
58
65
|
## Page Format
|
|
59
66
|
Use YAML frontmatter when creating wiki pages:
|
|
@@ -75,11 +82,11 @@ superseded_by: []
|
|
|
75
82
|
\`\`\`
|
|
76
83
|
|
|
77
84
|
## Operations
|
|
78
|
-
- ingest: \`wiki/memory.md
|
|
79
|
-
- query: hook
|
|
80
|
-
- lint:
|
|
81
|
-
- consolidate:
|
|
82
|
-
- maintenance: \`outputs/maintenance/queue.md
|
|
85
|
+
- ingest: read \`wiki/memory.md\` and \`wiki/index.md\` first, verify new evidence, then prefer updating existing wiki pages.
|
|
86
|
+
- query: use hook-injected context when useful, but answer the current request first. Manual commands are diagnostics, not required daily workflow.
|
|
87
|
+
- lint: agent helper for user-requested or wiki maintenance work. Do not run it every turn.
|
|
88
|
+
- consolidate: safely refresh generated blocks in \`memory.md\`/\`index.md\`. Do not overwrite handwritten sections or curated document bodies.
|
|
89
|
+
- maintenance: \`outputs/maintenance/queue.md\` stores stop/start cleanup candidates. Review and update it only when it does not delay the current user request.
|
|
83
90
|
`;
|
|
84
91
|
}
|
|
85
92
|
|
|
@@ -90,31 +97,31 @@ Generated by llm-wiki-kit.
|
|
|
90
97
|
|
|
91
98
|
## Overview
|
|
92
99
|
|
|
93
|
-
|
|
100
|
+
This file is the short navigation map for the living wiki. Keep entry points easy to scan instead of adding long explanations here.
|
|
94
101
|
|
|
95
102
|
## Main Areas
|
|
96
103
|
|
|
97
|
-
- [Memory](memory.md) -
|
|
98
|
-
- [Sources](sources/) - source
|
|
99
|
-
- [Concepts](concepts/) -
|
|
100
|
-
- [Entities](entities/) -
|
|
101
|
-
- [Decisions](decisions/) -
|
|
102
|
-
- [Architecture](architecture/) -
|
|
103
|
-
- [Debugging](debugging/) -
|
|
104
|
-
- [Context](context/) -
|
|
105
|
-
- [Queries](queries/) -
|
|
104
|
+
- [Memory](memory.md) - short active memory and durable entry points.
|
|
105
|
+
- [Sources](sources/) - source summaries and source IDs.
|
|
106
|
+
- [Concepts](concepts/) - reusable concepts and terminology.
|
|
107
|
+
- [Entities](entities/) - systems, modules, tools, services, and important objects.
|
|
108
|
+
- [Decisions](decisions/) - decisions and rationale.
|
|
109
|
+
- [Architecture](architecture/) - structure, data flow, and control flow.
|
|
110
|
+
- [Debugging](debugging/) - causes, fixes, and verification evidence.
|
|
111
|
+
- [Context](context/) - session continuity and project context.
|
|
112
|
+
- [Queries](queries/) - reusable question answers. One-off records belong in outputs/questions.
|
|
106
113
|
|
|
107
114
|
## Operating Notes
|
|
108
115
|
|
|
109
|
-
-
|
|
110
|
-
-
|
|
111
|
-
-
|
|
112
|
-
-
|
|
116
|
+
- Start broad questions from memory and this index.
|
|
117
|
+
- Before creating a new page, check 3-7 relevant existing pages.
|
|
118
|
+
- Merge durable facts into existing curated pages. Keep one-off work/decision records in chunked outputs/questions.
|
|
119
|
+
- Add \`[[page-or-topic]]\` links when related pages become useful.
|
|
113
120
|
|
|
114
121
|
<!-- llm-wiki-kit:index-start -->
|
|
115
122
|
## Generated Page Map
|
|
116
123
|
|
|
117
|
-
|
|
124
|
+
The agent may refresh this generated block with \`llm-wiki consolidate --workspace <project>\`.
|
|
118
125
|
<!-- llm-wiki-kit:index-end -->
|
|
119
126
|
`;
|
|
120
127
|
}
|
|
@@ -136,11 +143,11 @@ superseded_by: []
|
|
|
136
143
|
|
|
137
144
|
# LLM Wiki Memory
|
|
138
145
|
|
|
139
|
-
|
|
146
|
+
Short active memory for hook context. Keep it small and link to deeper documents instead of copying long explanations.
|
|
140
147
|
|
|
141
148
|
## Current Focus
|
|
142
149
|
|
|
143
|
-
-
|
|
150
|
+
- Add the current durable project focus here in a few short bullets.
|
|
144
151
|
|
|
145
152
|
## Durable Entry Points
|
|
146
153
|
|
|
@@ -150,7 +157,7 @@ superseded_by: []
|
|
|
150
157
|
<!-- llm-wiki-kit:memory-start -->
|
|
151
158
|
## Generated Memory Map
|
|
152
159
|
|
|
153
|
-
|
|
160
|
+
The agent may refresh this generated block with \`llm-wiki consolidate --workspace <project>\`.
|
|
154
161
|
<!-- llm-wiki-kit:memory-end -->
|
|
155
162
|
`;
|
|
156
163
|
}
|
|
@@ -166,50 +173,50 @@ export function procedure(name) {
|
|
|
166
173
|
const procedures = {
|
|
167
174
|
'ingest.md': `# Ingest Procedure
|
|
168
175
|
|
|
169
|
-
1. \`wiki/memory.md
|
|
170
|
-
2.
|
|
171
|
-
3.
|
|
172
|
-
4.
|
|
173
|
-
5.
|
|
174
|
-
6.
|
|
175
|
-
7.
|
|
176
|
-
8. durable entry
|
|
177
|
-
9.
|
|
176
|
+
1. Read \`wiki/memory.md\` and \`wiki/index.md\` first.
|
|
177
|
+
2. If new evidence exists, inspect \`raw/inbox/\` or \`raw/sources/\`.
|
|
178
|
+
3. Create or update \`wiki/sources/<slug>.md\` only when a source summary is useful.
|
|
179
|
+
4. Before creating a new page, look for related concept/entity/decision/architecture/debugging/context pages and update those first.
|
|
180
|
+
5. Do not create duplicates. Merge facts into existing pages when they already exist.
|
|
181
|
+
6. Do not promote simple answers or one-off chat into durable wiki.
|
|
182
|
+
7. Important claims should record source references, confidence, memory type, importance, and verification status.
|
|
183
|
+
8. When durable entry points change, update \`wiki/memory.md\` briefly or use \`llm-wiki consolidate\`.
|
|
184
|
+
9. Add a short entry to \`wiki/log.md\` for meaningful wiki changes.
|
|
178
185
|
`,
|
|
179
186
|
'query.md': `# Query Procedure
|
|
180
187
|
|
|
181
|
-
1.
|
|
182
|
-
2. \`wiki/memory.md
|
|
183
|
-
3.
|
|
184
|
-
4.
|
|
185
|
-
5.
|
|
186
|
-
6.
|
|
187
|
-
7.
|
|
188
|
-
8.
|
|
188
|
+
1. Answer the current user question first. Use hook-injected context only as needed.
|
|
189
|
+
2. Start from \`wiki/memory.md\` and \`wiki/index.md\`.
|
|
190
|
+
3. Read the smallest relevant set of \`wiki/\` documents.
|
|
191
|
+
4. Inspect raw sources only when exact evidence matters.
|
|
192
|
+
5. Separate verified facts from inference.
|
|
193
|
+
6. Use \`llm-wiki context "<query>"\` only when manual inspection is useful. Add \`--include-episodic\` only for historical query/context pages, and \`--include-archived\` only for archived/superseded pages.
|
|
194
|
+
7. Do not promote one-off answers, status checks, or keyword-only replies to durable wiki or live Q&A. Archive only work turns with tool evidence, changed-file evidence, verification, or structured decision/debugging conclusions.
|
|
195
|
+
8. Merge reusable facts into \`wiki/architecture/\`, \`wiki/debugging/\`, \`wiki/decisions/\`, \`wiki/concepts/\`, or \`procedures/\` based on importance and user consent flow.
|
|
189
196
|
`,
|
|
190
197
|
'lint.md': `# Lint Procedure
|
|
191
198
|
|
|
192
|
-
\`llm-wiki lint --workspace <project
|
|
199
|
+
\`llm-wiki lint --workspace <project>\` is an agent-side wiki health check. Users should not need to run it every turn.
|
|
193
200
|
|
|
194
|
-
|
|
201
|
+
Checks include stale pages, orphan pages, broken wiki/Markdown links, unsafe source IDs, secret-like content, missing sources, duplicate concepts/titles, unsupported claims, unresolved contradictions, outdated managed rules, memory budget pressure, page-count growth, hidden episodic/context growth, stale/archived discoverability, maintenance review due, oversized legacy live Q&A, and oversized live Q&A chunks.
|
|
195
202
|
|
|
196
|
-
|
|
203
|
+
Periodic maintenance is an agent-side task, not a per-turn user command. When needed, the agent checks:
|
|
197
204
|
|
|
198
205
|
1. \`llm-wiki lint --workspace <project>\`
|
|
199
206
|
2. \`llm-wiki maintenance --workspace <project>\`
|
|
200
|
-
3. pending
|
|
207
|
+
3. Merge pending items into existing durable pages, then mark them \`done\` or \`skipped\`.
|
|
201
208
|
4. \`llm-wiki consolidate --workspace <project> --dry-run\`
|
|
202
|
-
5.
|
|
209
|
+
5. Run \`llm-wiki consolidate --workspace <project>\` when the dry run is acceptable.
|
|
203
210
|
|
|
204
|
-
|
|
211
|
+
Apply automatic fixes only to clearly managed kit areas. Do not overwrite user-editable documents; surface cleanup needs in the next work context.
|
|
205
212
|
`,
|
|
206
213
|
'security.md': `# Security Procedure
|
|
207
214
|
|
|
208
|
-
-
|
|
209
|
-
-
|
|
210
|
-
-
|
|
211
|
-
-
|
|
212
|
-
-
|
|
215
|
+
- Preserve useful local project work context.
|
|
216
|
+
- Do not block reads or tool calls only because input looks sensitive.
|
|
217
|
+
- Redact authentication values such as tokens, passwords, bearer credentials, private keys, and raw \`.env\` contents before writing hook payloads, summaries, context packs, or wiki pages.
|
|
218
|
+
- If sensitive material may have entered the wiki, use \`llm-wiki lint --workspace <project>\`.
|
|
219
|
+
- Full raw transcript capture is disabled by default. Allow it only when a project explicitly opts in and has a redaction path.
|
|
213
220
|
`,
|
|
214
221
|
};
|
|
215
222
|
return procedures[name] || '';
|
package/src/update-notice.js
CHANGED
|
@@ -113,12 +113,22 @@ export async function updateNoticeContext(projectRoot, eventName, options = {})
|
|
|
113
113
|
|
|
114
114
|
const workspace = resolve(projectRoot || process.cwd());
|
|
115
115
|
const updateCommand = commandForProject('update', workspace);
|
|
116
|
+
if (options.language === 'ko') {
|
|
117
|
+
return [
|
|
118
|
+
'LLM Wiki runtime update status:',
|
|
119
|
+
`- current hook runtime: ${notice.installedVersion}; npm registry: ${notice.latestVersion}`,
|
|
120
|
+
'- 현재 요청 처리가 우선이며, 현재 runtime 기능은 계속 동작한다.',
|
|
121
|
+
`- 업데이트/정비를 수행할 때 사용할 명령: \`${updateCommand}\``,
|
|
122
|
+
'- npm 전역 설치 권한 오류가 나면 환경에 맞게 `npm install -g llm-wiki-kit@latest` 또는 `sudo npm install -g llm-wiki-kit@latest` 후 같은 update 명령을 다시 실행한다.',
|
|
123
|
+
'- 이 status만으로 설치나 업데이트를 실행하지 않는다.',
|
|
124
|
+
].join('\n');
|
|
125
|
+
}
|
|
116
126
|
return [
|
|
117
127
|
'LLM Wiki runtime update status:',
|
|
118
128
|
`- current hook runtime: ${notice.installedVersion}; npm registry: ${notice.latestVersion}`,
|
|
119
|
-
'-
|
|
120
|
-
`-
|
|
121
|
-
'- npm
|
|
122
|
-
'-
|
|
129
|
+
'- The current request comes first, and the current runtime continues to work.',
|
|
130
|
+
`- Use this command only when performing update or maintenance work: \`${updateCommand}\``,
|
|
131
|
+
'- If global npm install hits a permission error, run `npm install -g llm-wiki-kit@latest` or `sudo npm install -g llm-wiki-kit@latest` as appropriate, then rerun the same update command.',
|
|
132
|
+
'- Do not install or update only because this status is present.',
|
|
123
133
|
].join('\n');
|
|
124
134
|
}
|
package/src/update.js
CHANGED
|
@@ -3,10 +3,10 @@ import { join, resolve } from 'path';
|
|
|
3
3
|
import { exists } from './fs-utils.js';
|
|
4
4
|
import { appendWikiLog } from './project.js';
|
|
5
5
|
import { install } from './install.js';
|
|
6
|
-
import { isWindows } from './platform.js';
|
|
6
|
+
import { commandMatchesRuntime, commandPaths, isWindows, sameResolvedPath } from './platform.js';
|
|
7
7
|
import { applyProjectTemplateUpdate, inspectProjectState } from './project-state.js';
|
|
8
8
|
import { knownProjectRoots, recordProject } from './projects.js';
|
|
9
|
-
import { binPath, detectInstallSource, packageName, runtimeVersion } from './version.js';
|
|
9
|
+
import { binPath, detectInstallSource, packageName, packageRoot, runtimeVersion } from './version.js';
|
|
10
10
|
|
|
11
11
|
function commandLine(command, args) {
|
|
12
12
|
return [command, ...args].join(' ');
|
|
@@ -115,6 +115,10 @@ function binCommand() {
|
|
|
115
115
|
return process.env.LLM_WIKI_KIT_BIN || binPath;
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
+
function packageSpec(target) {
|
|
119
|
+
return `${packageName()}@${target}`;
|
|
120
|
+
}
|
|
121
|
+
|
|
118
122
|
function assertCommandOk(result, label) {
|
|
119
123
|
if (result.status === 0 && !result.error) return;
|
|
120
124
|
const detail = result.stderr.trim() ||
|
|
@@ -125,6 +129,45 @@ function assertCommandOk(result, label) {
|
|
|
125
129
|
throw new Error(`${label} failed: ${detail}`);
|
|
126
130
|
}
|
|
127
131
|
|
|
132
|
+
function postUpdateCommand(workspace, options = {}) {
|
|
133
|
+
const command = ['llm-wiki', 'post-update'];
|
|
134
|
+
if (shouldUpdateAllProjects(options)) command.push('--all');
|
|
135
|
+
command.push('--workspace', workspace);
|
|
136
|
+
return command.join(' ');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function formatRemediation(workspace, target, options = {}) {
|
|
140
|
+
const install = isWindows(options)
|
|
141
|
+
? `npm install -g ${packageSpec(target)}`
|
|
142
|
+
: `sudo npm install -g ${packageSpec(target)}`;
|
|
143
|
+
return [
|
|
144
|
+
'Run the npm install command that owns the active runtime, then reapply hooks/templates:',
|
|
145
|
+
` ${install}`,
|
|
146
|
+
` ${postUpdateCommand(workspace, options)}`,
|
|
147
|
+
'Then verify:',
|
|
148
|
+
` llm-wiki status --workspace ${workspace}`,
|
|
149
|
+
].join('\n');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function createUpdateVerificationError(message, diagnostics = {}, workspace, target, options = {}) {
|
|
153
|
+
const lines = [
|
|
154
|
+
'llm-wiki-kit update did not update the active runtime.',
|
|
155
|
+
message,
|
|
156
|
+
];
|
|
157
|
+
if (diagnostics.registryTarget) lines.push(`- registry target: ${diagnostics.registryTarget}`);
|
|
158
|
+
if (diagnostics.runtimeBefore) lines.push(`- runtime before: ${diagnostics.runtimeBefore}`);
|
|
159
|
+
if (diagnostics.runtimeAfter) lines.push(`- runtime after: ${diagnostics.runtimeAfter}`);
|
|
160
|
+
if (diagnostics.activePackageRoot) lines.push(`- active runtime root: ${diagnostics.activePackageRoot}`);
|
|
161
|
+
if (diagnostics.npmRoot) lines.push(`- npm global root: ${diagnostics.npmRoot}`);
|
|
162
|
+
if (diagnostics.npmPackageRoot) lines.push(`- npm target package root: ${diagnostics.npmPackageRoot}`);
|
|
163
|
+
if (diagnostics.commandPath) lines.push(`- command on PATH: ${diagnostics.commandPath}`);
|
|
164
|
+
if (diagnostics.commandMatchesRuntime !== undefined) {
|
|
165
|
+
lines.push(`- command matches runtime: ${diagnostics.commandMatchesRuntime ? 'yes' : 'no'}`);
|
|
166
|
+
}
|
|
167
|
+
lines.push(formatRemediation(workspace, target, options));
|
|
168
|
+
return Object.assign(new Error(lines.join('\n')), { diagnostics });
|
|
169
|
+
}
|
|
170
|
+
|
|
128
171
|
async function hasProjectWiki(projectRoot) {
|
|
129
172
|
return exists(join(projectRoot, 'llm-wiki', 'wiki'));
|
|
130
173
|
}
|
|
@@ -190,6 +233,74 @@ export function compareVersions(a, b) {
|
|
|
190
233
|
return left.prerelease > right.prerelease ? 1 : -1;
|
|
191
234
|
}
|
|
192
235
|
|
|
236
|
+
async function npmGlobalInfo(options = {}) {
|
|
237
|
+
const rootResult = await runCommand(npmCommand(), ['root', '-g'], {
|
|
238
|
+
...options,
|
|
239
|
+
label: 'npm root -g',
|
|
240
|
+
timeout: options.timeout || 30000,
|
|
241
|
+
});
|
|
242
|
+
assertCommandOk(rootResult, 'npm root -g');
|
|
243
|
+
const prefixResult = await runCommand(npmCommand(), ['prefix', '-g'], {
|
|
244
|
+
...options,
|
|
245
|
+
label: 'npm prefix -g',
|
|
246
|
+
timeout: options.timeout || 30000,
|
|
247
|
+
});
|
|
248
|
+
assertCommandOk(prefixResult, 'npm prefix -g');
|
|
249
|
+
const root = rootResult.stdout.trim().split(/\r?\n/).at(-1) || '';
|
|
250
|
+
const prefix = prefixResult.stdout.trim().split(/\r?\n/).at(-1) || '';
|
|
251
|
+
return {
|
|
252
|
+
root,
|
|
253
|
+
prefix,
|
|
254
|
+
packageRoot: root ? join(root, packageName()) : '',
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
async function commandInfo(options = {}) {
|
|
259
|
+
const paths = await commandPaths('llm-wiki', options);
|
|
260
|
+
const commandPath = paths[0] || null;
|
|
261
|
+
const matchesRuntime = await commandMatchesRuntime(commandPath, binPath, {
|
|
262
|
+
...options,
|
|
263
|
+
installSource: detectInstallSource(),
|
|
264
|
+
});
|
|
265
|
+
return {
|
|
266
|
+
path: commandPath,
|
|
267
|
+
paths,
|
|
268
|
+
matchesRuntime: Boolean(matchesRuntime),
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function runtimeSatisfiesTarget(runtime, targetVersion) {
|
|
273
|
+
return compareVersions(runtime, targetVersion) >= 0;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function rootMatchesActiveRuntime(npmPackageRoot) {
|
|
277
|
+
return sameResolvedPath(npmPackageRoot, packageRoot) ||
|
|
278
|
+
resolve(npmPackageRoot || '') === resolve(packageRoot);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
async function preflightRuntimeUpdate(check, workspace, target, options = {}) {
|
|
282
|
+
const npmGlobal = await npmGlobalInfo(options);
|
|
283
|
+
const command = await commandInfo(options);
|
|
284
|
+
if (check.updateAvailable && detectInstallSource() === 'npm' && !rootMatchesActiveRuntime(npmGlobal.packageRoot)) {
|
|
285
|
+
throw createUpdateVerificationError(
|
|
286
|
+
'The active llm-wiki runtime is not under the npm global root that this update command would modify.',
|
|
287
|
+
{
|
|
288
|
+
registryTarget: check.latestVersion,
|
|
289
|
+
runtimeBefore: check.installedVersion,
|
|
290
|
+
activePackageRoot: packageRoot,
|
|
291
|
+
npmRoot: npmGlobal.root,
|
|
292
|
+
npmPackageRoot: npmGlobal.packageRoot,
|
|
293
|
+
commandPath: command.path,
|
|
294
|
+
commandMatchesRuntime: command.matchesRuntime,
|
|
295
|
+
},
|
|
296
|
+
workspace,
|
|
297
|
+
target,
|
|
298
|
+
options
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
return { npmGlobal, command };
|
|
302
|
+
}
|
|
303
|
+
|
|
193
304
|
export async function checkForUpdate(options = {}) {
|
|
194
305
|
const target = options.to || 'latest';
|
|
195
306
|
const installedVersion = runtimeVersion();
|
|
@@ -297,9 +408,10 @@ export async function update(options = {}) {
|
|
|
297
408
|
}
|
|
298
409
|
|
|
299
410
|
const target = options.to || 'latest';
|
|
411
|
+
const beforeDiagnostics = await preflightRuntimeUpdate(check, workspace, target, options);
|
|
300
412
|
const shouldRunNpmInstall = check.updateAvailable;
|
|
301
413
|
const installResult = shouldRunNpmInstall
|
|
302
|
-
? await runCommand(npmCommand(), ['install', '-g',
|
|
414
|
+
? await runCommand(npmCommand(), ['install', '-g', packageSpec(target)], {
|
|
303
415
|
...options,
|
|
304
416
|
label: 'npm install -g',
|
|
305
417
|
timeout: options.timeout || 120000,
|
|
@@ -310,6 +422,25 @@ export async function update(options = {}) {
|
|
|
310
422
|
stderr: '',
|
|
311
423
|
};
|
|
312
424
|
assertCommandOk(installResult, 'npm install -g');
|
|
425
|
+
const runtimeAfterInstall = runtimeVersion();
|
|
426
|
+
if (shouldRunNpmInstall && !runtimeSatisfiesTarget(runtimeAfterInstall, check.latestVersion)) {
|
|
427
|
+
throw createUpdateVerificationError(
|
|
428
|
+
'npm install -g exited successfully, but the active runtime version did not change to the registry target.',
|
|
429
|
+
{
|
|
430
|
+
registryTarget: check.latestVersion,
|
|
431
|
+
runtimeBefore: check.installedVersion,
|
|
432
|
+
runtimeAfter: runtimeAfterInstall,
|
|
433
|
+
activePackageRoot: packageRoot,
|
|
434
|
+
npmRoot: beforeDiagnostics.npmGlobal.root,
|
|
435
|
+
npmPackageRoot: beforeDiagnostics.npmGlobal.packageRoot,
|
|
436
|
+
commandPath: beforeDiagnostics.command.path,
|
|
437
|
+
commandMatchesRuntime: beforeDiagnostics.command.matchesRuntime,
|
|
438
|
+
},
|
|
439
|
+
workspace,
|
|
440
|
+
target,
|
|
441
|
+
options
|
|
442
|
+
);
|
|
443
|
+
}
|
|
313
444
|
|
|
314
445
|
const postArgs = [binCommand(), 'post-update', '--workspace', workspace, '--json'];
|
|
315
446
|
if (shouldUpdateAllProjects(options)) postArgs.push('--all');
|
|
@@ -328,13 +459,47 @@ export async function update(options = {}) {
|
|
|
328
459
|
});
|
|
329
460
|
assertCommandOk(postResult, 'post-update');
|
|
330
461
|
const parsedPostUpdate = parseJsonOutput(postResult.stdout);
|
|
462
|
+
const postRuntimeVersion = parsedPostUpdate?.runtimeVersion || null;
|
|
463
|
+
if (shouldRunNpmInstall && postRuntimeVersion && !runtimeSatisfiesTarget(postRuntimeVersion, check.latestVersion)) {
|
|
464
|
+
throw createUpdateVerificationError(
|
|
465
|
+
'post-update ran, but it did not run from the registry target runtime.',
|
|
466
|
+
{
|
|
467
|
+
registryTarget: check.latestVersion,
|
|
468
|
+
runtimeBefore: check.installedVersion,
|
|
469
|
+
runtimeAfter: postRuntimeVersion,
|
|
470
|
+
activePackageRoot: packageRoot,
|
|
471
|
+
npmRoot: beforeDiagnostics.npmGlobal.root,
|
|
472
|
+
npmPackageRoot: beforeDiagnostics.npmGlobal.packageRoot,
|
|
473
|
+
commandPath: beforeDiagnostics.command.path,
|
|
474
|
+
commandMatchesRuntime: beforeDiagnostics.command.matchesRuntime,
|
|
475
|
+
},
|
|
476
|
+
workspace,
|
|
477
|
+
target,
|
|
478
|
+
options
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
const afterCommand = await commandInfo(options);
|
|
482
|
+
const warnings = [];
|
|
483
|
+
if (!afterCommand.matchesRuntime) {
|
|
484
|
+
warnings.push(`llm-wiki command on PATH does not resolve to the active runtime: ${afterCommand.path || 'not found'}`);
|
|
485
|
+
}
|
|
331
486
|
|
|
332
487
|
return {
|
|
333
488
|
mode: 'update',
|
|
334
489
|
workspace,
|
|
335
490
|
before: check.installedVersion,
|
|
336
491
|
target,
|
|
492
|
+
latest: check.latestVersion,
|
|
493
|
+
runtimeBefore: check.installedVersion,
|
|
494
|
+
runtimeAfter: runtimeAfterInstall,
|
|
495
|
+
postUpdateRuntime: postRuntimeVersion,
|
|
496
|
+
updateApplied: shouldRunNpmInstall,
|
|
497
|
+
runtimeVerified: runtimeSatisfiesTarget(runtimeAfterInstall, check.latestVersion),
|
|
337
498
|
scope: shouldUpdateAllProjects(options) ? 'all' : 'current',
|
|
499
|
+
activePackageRoot: packageRoot,
|
|
500
|
+
npmGlobal: beforeDiagnostics.npmGlobal,
|
|
501
|
+
command: afterCommand,
|
|
502
|
+
warnings,
|
|
338
503
|
npmInstall: {
|
|
339
504
|
skipped: !shouldRunNpmInstall,
|
|
340
505
|
stdout: installResult.stdout.trim(),
|