llm-wiki-kit 0.2.12 → 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 +1 -1
- package/docs/manual.md +4 -1
- package/docs/operations.md +3 -1
- package/docs/troubleshooting.md +2 -0
- package/package.json +1 -1
- package/src/cli.js +15 -2
- package/src/update.js +168 -3
package/README.md
CHANGED
|
@@ -133,7 +133,7 @@ Most users should not need these during daily Claude Code/Codex work. They exist
|
|
|
133
133
|
|
|
134
134
|
`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.
|
|
135
135
|
|
|
136
|
-
`llm-wiki update` upgrades the global npm package when npm has a newer target, reinstalls the hook entries, and reapplies safe managed template updates across known project roots. If the installed runtime already satisfies the registry target, it skips `npm install -g
|
|
136
|
+
`llm-wiki update` upgrades the global npm package when npm has a newer target, reinstalls the hook entries, and reapplies safe managed template updates across known project roots. Before installing, it checks whether `npm root -g` points at the active runtime package root; after installing, it verifies the active runtime and `post-update` runtime reached the registry target. If either check fails, it exits nonzero and prints the exact runtime/npm roots plus the manual install/post-update commands to run. If the installed runtime already satisfies the registry target, it prints an already-current result, skips `npm install -g`, and still runs post-update maintenance. Use `--current-only` when you intentionally want to update only the supplied workspace. Existing wiki content is not overwritten. The command prints step progress to stderr, including registry lookup, npm root/prefix checks, npm install, post-update, and project discovery. Use `--timeout-ms <ms>` to bound external commands and `--max-dirs <n>` to bound project discovery under large or slow roots such as WSL `/mnt/*` trees.
|
|
137
137
|
|
|
138
138
|
Installed npm runtimes also perform a cached update notice check from hooks while the user works. This does not install anything automatically. When a newer npm release is detected, Codex and Claude receive the same passive runtime update status in hook context: current runtime, npm registry target, and the manual command to use when the user asks for update or maintenance work. It is not an instruction to interrupt the current answer or to sell the update to the user. The cache is scoped to the npm command used for lookup so test/fake npm checks do not leak into normal hook sessions. Set `LLM_WIKI_KIT_UPDATE_NOTICE=0` only when diagnosing or suppressing that status block.
|
|
139
139
|
|
package/docs/manual.md
CHANGED
|
@@ -163,10 +163,13 @@ Most users should not need these during daily coding. They are for install, upda
|
|
|
163
163
|
|
|
164
164
|
- runs `npm install -g llm-wiki-kit@<target>` only when needed;
|
|
165
165
|
- skips npm install when the installed runtime already satisfies the target;
|
|
166
|
-
-
|
|
166
|
+
- checks that `npm root -g` points at the active runtime package root before installing;
|
|
167
|
+
- verifies that the active runtime and `post-update` runtime reached the registry target after installing;
|
|
168
|
+
- exits nonzero instead of printing `updated` when `npm install -g` succeeds but the active runtime is still old;
|
|
167
169
|
- reinstalls hooks without duplicating them;
|
|
168
170
|
- updates only managed project templates and policy blocks;
|
|
169
171
|
- preserves user-edited files and curated wiki contents;
|
|
172
|
+
- prints before/after runtime, registry target, npm global root, active runtime root, and PATH command diagnostics;
|
|
170
173
|
- prints progress to stderr so JSON stdout remains parseable;
|
|
171
174
|
- supports `--timeout-ms` and `--max-dirs` for slow npm, WSL, or large search roots.
|
|
172
175
|
|
package/docs/operations.md
CHANGED
|
@@ -127,7 +127,9 @@ Installed npm runtimes also run a cached hook-side update notice check while the
|
|
|
127
127
|
|
|
128
128
|
- runs `npm install -g llm-wiki-kit@<target>` only when the registry target is newer than the installed runtime
|
|
129
129
|
- skips npm installation when the installed runtime already satisfies the target, then still runs post-update maintenance
|
|
130
|
-
-
|
|
130
|
+
- checks `npm root -g`/`npm prefix -g` before install and refuses to claim success when npm would update a different global prefix than the active runtime
|
|
131
|
+
- verifies that the active runtime and `post-update` child runtime reached the registry target after install
|
|
132
|
+
- prints before/after runtime, registry target, npm global root, active runtime root, and PATH command diagnostics
|
|
131
133
|
- reinstalls hook entries without duplicating them
|
|
132
134
|
- patches only managed project files across known or discovered project roots
|
|
133
135
|
- backs up changed files under `~/.local/share/llm-wiki-kit/backups/`
|
package/docs/troubleshooting.md
CHANGED
|
@@ -113,6 +113,8 @@ If the proxy performs TLS inspection, install the organization's CA and set `caf
|
|
|
113
113
|
|
|
114
114
|
If `npm install -g llm-wiki-kit@latest` succeeds but `llm-wiki --help` does not show newer commands such as `projects`, `context`, `lint`, or `consolidate`, the shell is probably executing an older source checkout or stale shim before the npm global binary.
|
|
115
115
|
|
|
116
|
+
Newer `llm-wiki update` releases diagnose this before claiming success. If the npm global root does not match the active runtime root, or if `npm install -g` exits 0 but the active runtime is still old, `update` exits nonzero with details such as `active runtime root`, `npm global root`, `runtime before`, `runtime after`, and `command matches runtime`. On root-owned Linux prefixes, run the printed `sudo npm install -g llm-wiki-kit@<target>` command, then run the printed `llm-wiki post-update ...` command as the normal Codex/Claude user.
|
|
117
|
+
|
|
116
118
|
Confirm what is actually running:
|
|
117
119
|
|
|
118
120
|
```bash
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -348,13 +348,26 @@ function formatUpdate(value) {
|
|
|
348
348
|
`- project template skipped: ${skipped}`,
|
|
349
349
|
].join('\n');
|
|
350
350
|
}
|
|
351
|
+
const title = value.updateApplied
|
|
352
|
+
? 'llm-wiki-kit updated'
|
|
353
|
+
: 'llm-wiki-kit already current; post-update complete';
|
|
351
354
|
return [
|
|
352
|
-
|
|
355
|
+
title,
|
|
353
356
|
`- workspace: ${value.workspace}`,
|
|
354
|
-
`- before: ${value.before}`,
|
|
357
|
+
`- runtime before: ${value.runtimeBefore || value.before}`,
|
|
358
|
+
`- registry target: ${value.latest || value.target}`,
|
|
359
|
+
`- runtime after: ${value.runtimeAfter || 'unknown'}`,
|
|
360
|
+
...(value.postUpdateRuntime ? [`- post-update runtime: ${value.postUpdateRuntime}`] : []),
|
|
361
|
+
`- runtime verified: ${value.runtimeVerified ? 'yes' : 'no'}`,
|
|
362
|
+
`- npm install: ${value.npmInstall?.skipped ? 'skipped' : 'ran'}`,
|
|
355
363
|
`- target: ${value.target}`,
|
|
364
|
+
`- active runtime root: ${value.activePackageRoot || 'unknown'}`,
|
|
365
|
+
`- npm global root: ${value.npmGlobal?.root || 'unknown'}`,
|
|
366
|
+
`- command: ${value.command?.path || 'not found'}`,
|
|
367
|
+
`- command matches runtime: ${value.command?.matchesRuntime ? 'yes' : 'no'}`,
|
|
356
368
|
`- scope: ${value.scope || 'current'}`,
|
|
357
369
|
...(value.projects ? [`- projects updated: ${value.projects.length}`] : []),
|
|
370
|
+
...((value.warnings || []).map((warning) => `- warning: ${warning}`)),
|
|
358
371
|
].join('\n');
|
|
359
372
|
}
|
|
360
373
|
|
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(),
|