@moonshot-ai/kimi-code 0.39.0 → 0.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.mjs +13287 -16480
- package/dist-web/assets/{CodeBlockNode-TQKPIcUp.js → CodeBlockNode-BNOCy4ai.js} +2 -2
- package/dist-web/assets/{Tooltip-3Kylewm2.js → Tooltip-DebxPz-0.js} +1 -1
- package/dist-web/assets/{abnfDiagram-VRR7QNED-DZ5l2NNF.js → abnfDiagram-VRR7QNED-Bo8g46XA.js} +1 -1
- package/dist-web/assets/{arc-C525Mmp6.js → arc-CxCMb0Ef.js} +1 -1
- package/dist-web/assets/{architectureDiagram-ZJ3FMSHR-DsZ4TpMi.js → architectureDiagram-ZJ3FMSHR-ZNnAzHHt.js} +1 -1
- package/dist-web/assets/{blockDiagram-677ZJIJ3-DHUznNgz.js → blockDiagram-677ZJIJ3-DeafJYAk.js} +1 -1
- package/dist-web/assets/{c4Diagram-LMCZKHZV-BRKLxvwh.js → c4Diagram-LMCZKHZV-oGCYLt-v.js} +1 -1
- package/dist-web/assets/channel-B8eMh4sk.js +1 -0
- package/dist-web/assets/{chunk-2Q5K7J3B-CldwFnN4.js → chunk-2Q5K7J3B-CdhiweKX.js} +1 -1
- package/dist-web/assets/{chunk-32BRIVSS-0ImWpiFu.js → chunk-32BRIVSS-mfMW4-bV.js} +1 -1
- package/dist-web/assets/{chunk-5VM5RSS4-K_NNkrmw.js → chunk-5VM5RSS4-BRWxG5tM.js} +1 -1
- package/dist-web/assets/{chunk-EX3LRPZG-Du5tJK2w.js → chunk-EX3LRPZG-DoQjV3QX.js} +1 -1
- package/dist-web/assets/{chunk-JWPE2WC7-CnsTQcA8.js → chunk-JWPE2WC7-C7S97jLg.js} +1 -1
- package/dist-web/assets/{chunk-MOJQB5TN-BWiH3s-c.js → chunk-MOJQB5TN-DcgqWRh_.js} +1 -1
- package/dist-web/assets/{chunk-RYQCIY6F-Bg4GHN0V.js → chunk-RYQCIY6F-DRHEFBXE.js} +1 -1
- package/dist-web/assets/{chunk-V7JOEXUC-5w7loxVR.js → chunk-V7JOEXUC-Ci6LL3n4.js} +1 -1
- package/dist-web/assets/{chunk-VR4S4FIN-Cp8JVohH.js → chunk-VR4S4FIN-DW1NNlBr.js} +1 -1
- package/dist-web/assets/{chunk-XXDRQBXY-BwEKpC0s.js → chunk-XXDRQBXY-4LplLZkT.js} +1 -1
- package/dist-web/assets/classDiagram-OUVF2IWQ-DDHH-ciJ.js +1 -0
- package/dist-web/assets/classDiagram-v2-EOCWNBFH-DDHH-ciJ.js +1 -0
- package/dist-web/assets/{cose-bilkent-JH36ORCC-CyvFRDuS.js → cose-bilkent-JH36ORCC-B9Aj57Fl.js} +1 -1
- package/dist-web/assets/{cynefin-VYW2F7L2-Ct8il_Gb.js → cynefin-VYW2F7L2-DEnbetzx.js} +1 -1
- package/dist-web/assets/{cynefinDiagram-TSTJHNR4-BP26cYtj.js → cynefinDiagram-TSTJHNR4-BrabEtIe.js} +1 -1
- package/dist-web/assets/{dagre-VKFMJZFB-BuaL-XNK.js → dagre-VKFMJZFB-BDxu-EPk.js} +1 -1
- package/dist-web/assets/{diagram-FQU43EPY-BXKGXolr.js → diagram-FQU43EPY-D5Cw9BLp.js} +1 -1
- package/dist-web/assets/{diagram-G47NLZAW-DsoHq3g9.js → diagram-G47NLZAW-CgstEr0d.js} +1 -1
- package/dist-web/assets/{diagram-NH7WQ7WH-l2Pip_5t.js → diagram-NH7WQ7WH-BO_tIsIn.js} +1 -1
- package/dist-web/assets/{diagram-OA4YK3LP-DO8otT0J.js → diagram-OA4YK3LP-BiXs8uY6.js} +1 -1
- package/dist-web/assets/{diagram-WEI45ONY-tJhlXXXb.js → diagram-WEI45ONY-DzHIyeb8.js} +1 -1
- package/dist-web/assets/{ebnfDiagram-CCIWWBDH-DuVJXtzP.js → ebnfDiagram-CCIWWBDH-KkwEvI7D.js} +1 -1
- package/dist-web/assets/{erDiagram-Q63AITRT-q8LwmVdA.js → erDiagram-Q63AITRT-Ca__aYfw.js} +1 -1
- package/dist-web/assets/{flowDiagram-23GEKE2U-CSk8qFwd.js → flowDiagram-23GEKE2U-CW0gFw60.js} +1 -1
- package/dist-web/assets/{ganttDiagram-NO4QXBWP-BliHEJI2.js → ganttDiagram-NO4QXBWP-BA6Xg4gl.js} +1 -1
- package/dist-web/assets/{gitGraphDiagram-IHSO6WYX-DbTFMBma.js → gitGraphDiagram-IHSO6WYX-CuVLyl1X.js} +1 -1
- package/dist-web/assets/index--0t1wzw_.js +812 -0
- package/dist-web/assets/{index-DuIqvsra.js → index--RgMhz1s.js} +1 -1
- package/dist-web/assets/{index-BlRksujk.js → index-BAprvwXC.js} +1 -1
- package/dist-web/assets/{index-Dq61ZbBp.js → index-D6YNmmDH.js} +2 -2
- package/dist-web/assets/index-DDrI0Pxr.css +32 -0
- package/dist-web/assets/{index10-C0TQjdWb.js → index10-BOfr-M0b.js} +1 -1
- package/dist-web/assets/{index11-DNt97Omj.js → index11-BuI7qYB6.js} +1 -1
- package/dist-web/assets/{index5-DPyXoDa2.js → index5-DEKGWcGw.js} +1 -1
- package/dist-web/assets/{index6-RUyA_B9p.js → index6-BW9QZVgb.js} +1 -1
- package/dist-web/assets/{index7-ClRJOaWc.js → index7-N0eJaunx.js} +1 -1
- package/dist-web/assets/{index8-Dx-vzK_w.js → index8-DQP5_GpC.js} +1 -1
- package/dist-web/assets/{infoDiagram-FWYZ7A6U-Bge59IZG.js → infoDiagram-FWYZ7A6U-CX4ZaiQy.js} +1 -1
- package/dist-web/assets/{ishikawaDiagram-FXEZZL3T-y8Y7SwAW.js → ishikawaDiagram-FXEZZL3T-BRv7GetB.js} +1 -1
- package/dist-web/assets/{journeyDiagram-5HDEW3XC-B1mQtsyC.js → journeyDiagram-5HDEW3XC-DnAUfwJf.js} +1 -1
- package/dist-web/assets/{kanban-definition-HUTT4EX6-Bpgk0PjP.js → kanban-definition-HUTT4EX6-DgSN0HrV.js} +1 -1
- package/dist-web/assets/{linear-Cu3jckud.js → linear-DLj646oc.js} +1 -1
- package/dist-web/assets/{mermaid.core-CGrLstUA.js → mermaid.core-CqiFQExc.js} +4 -4
- package/dist-web/assets/{mindmap-definition-LN4V7U3C-jRWZCKa4.js → mindmap-definition-LN4V7U3C-Cny-i6X0.js} +1 -1
- package/dist-web/assets/{pegDiagram-2B236MQR-BBHHexxE.js → pegDiagram-2B236MQR-CBag-DmB.js} +1 -1
- package/dist-web/assets/{pieDiagram-ENE6RG2P-h3KzynJ8.js → pieDiagram-ENE6RG2P-CTlOLW1d.js} +1 -1
- package/dist-web/assets/{quadrantDiagram-ABIIQ3AL-DFm-eCQb.js → quadrantDiagram-ABIIQ3AL-BjfJ-MB6.js} +1 -1
- package/dist-web/assets/{railroadDiagram-RFXS5EU6-Buc-7xRH.js → railroadDiagram-RFXS5EU6-B94MRAkj.js} +1 -1
- package/dist-web/assets/{requirementDiagram-TGXJPOKE-CSxNTrK4.js → requirementDiagram-TGXJPOKE-Blc39rih.js} +1 -1
- package/dist-web/assets/{sankeyDiagram-HTMAVEWB-Dd9T4UrJ.js → sankeyDiagram-HTMAVEWB-RXRXikwd.js} +1 -1
- package/dist-web/assets/{sequenceDiagram-DBY2YBRQ-Cr-Sj8Pb.js → sequenceDiagram-DBY2YBRQ-BQbflmP-.js} +1 -1
- package/dist-web/assets/{sizeCapture-X5ZJPWSS-Cl-kJspZ.js → sizeCapture-X5ZJPWSS-BVkVkPWz.js} +1 -1
- package/dist-web/assets/{stateDiagram-2N3HPSRC-BYfWdLSL.js → stateDiagram-2N3HPSRC-DazF4orO.js} +1 -1
- package/dist-web/assets/stateDiagram-v2-6OUMAXLB-BtkBtrYE.js +1 -0
- package/dist-web/assets/{swimlanes-5IMT3BWC-48M2vHyU.js → swimlanes-5IMT3BWC-C91Fo-8f.js} +2 -2
- package/dist-web/assets/swimlanesDiagram-G3AALYLV-DhDMBrjk.js +8 -0
- package/dist-web/assets/{timeline-definition-FHXFAJF6-CsGFMDtB.js → timeline-definition-FHXFAJF6-BIlewsXZ.js} +1 -1
- package/dist-web/assets/{vennDiagram-L72KCM5P-B5PLrg4a.js → vennDiagram-L72KCM5P-mckuIa7o.js} +1 -1
- package/dist-web/assets/{vue.runtime.esm-bundler-Ii2EKmOx.js → vue.runtime.esm-bundler-D7X8t2I9.js} +1 -1
- package/dist-web/assets/{wardleyDiagram-EHGQE667-B6OLyL9l.js → wardleyDiagram-EHGQE667-L9Dc-js-.js} +1 -1
- package/dist-web/assets/{xychartDiagram-FW5EYKEG-DfHxJPKU.js → xychartDiagram-FW5EYKEG-C2C9LElX.js} +1 -1
- package/dist-web/index.html +2 -2
- package/package.json +3 -4
- package/scripts/postinstall/migrate.mjs +34 -37
- package/scripts/postinstall/platform.mjs +29 -0
- package/scripts/postinstall/reach.mjs +12 -29
- package/scripts/postinstall/takeover.mjs +98 -0
- package/scripts/postinstall/ui.mjs +91 -0
- package/scripts/postinstall.mjs +59 -153
- package/dist-web/assets/channel-5_2atmZK.js +0 -1
- package/dist-web/assets/classDiagram-OUVF2IWQ-CNk36E8O.js +0 -1
- package/dist-web/assets/classDiagram-v2-EOCWNBFH-CNk36E8O.js +0 -1
- package/dist-web/assets/index-BxiMZi52.css +0 -32
- package/dist-web/assets/index-CvgiEu-R.js +0 -818
- package/dist-web/assets/stateDiagram-v2-6OUMAXLB-D2Op2fy3.js +0 -1
- package/dist-web/assets/swimlanesDiagram-G3AALYLV-gPkWeD2t.js +0 -8
|
@@ -28,32 +28,13 @@
|
|
|
28
28
|
|
|
29
29
|
import { spawn } from 'node:child_process';
|
|
30
30
|
import { promises as fs } from 'node:fs';
|
|
31
|
-
import { delimiter, dirname, join
|
|
31
|
+
import { delimiter, dirname, join } from 'node:path';
|
|
32
|
+
|
|
33
|
+
import { executableCandidates, pathFlavor } from './platform.mjs';
|
|
32
34
|
|
|
33
35
|
const LEGACY_BIN = 'kimi';
|
|
34
36
|
const IS_WINDOWS = process.platform === 'win32';
|
|
35
37
|
|
|
36
|
-
/**
|
|
37
|
-
* Expand a basename like `kimi` into the set of filenames the OS
|
|
38
|
-
* would actually match on PATH.
|
|
39
|
-
*
|
|
40
|
-
* On POSIX: just `['kimi']`.
|
|
41
|
-
*
|
|
42
|
-
* On Windows: `['kimi', 'kimi.exe', 'kimi.cmd', …]` — every
|
|
43
|
-
* extension in `PATHEXT`. Without this, our PATH walk would miss
|
|
44
|
-
* the typical `kimi.exe` shim produced by `uv tool install` on
|
|
45
|
-
* Windows.
|
|
46
|
-
*/
|
|
47
|
-
export function executableCandidates(basename) {
|
|
48
|
-
if (!IS_WINDOWS) return [basename];
|
|
49
|
-
const pathext = (process.env['PATHEXT'] ?? '.EXE;.CMD;.BAT;.COM')
|
|
50
|
-
.toLowerCase()
|
|
51
|
-
.split(';')
|
|
52
|
-
.map((e) => e.trim())
|
|
53
|
-
.filter(Boolean);
|
|
54
|
-
return [basename, ...pathext.map((ext) => basename + ext)];
|
|
55
|
-
}
|
|
56
|
-
|
|
57
38
|
/**
|
|
58
39
|
* Identify which package manager ran us. `npm_config_user_agent` is
|
|
59
40
|
* set by npm, yarn (classic + berry), and pnpm, and starts with the
|
|
@@ -223,7 +204,7 @@ export async function ownPackageRoot(startDir) {
|
|
|
223
204
|
return null;
|
|
224
205
|
}
|
|
225
206
|
|
|
226
|
-
async function isExecutableFile(filePath) {
|
|
207
|
+
async function isExecutableFile(filePath, platform) {
|
|
227
208
|
try {
|
|
228
209
|
const info = await fs.stat(filePath);
|
|
229
210
|
if (!info.isFile()) return false;
|
|
@@ -231,7 +212,7 @@ async function isExecutableFile(filePath) {
|
|
|
231
212
|
// existence + a recognized extension is what PATHEXT-style lookup
|
|
232
213
|
// checks. Callers only pass us candidates that already match an
|
|
233
214
|
// extension in `executableCandidates()`, so "is a file" suffices.
|
|
234
|
-
if (
|
|
215
|
+
if (platform === 'win32') return true;
|
|
235
216
|
return (info.mode & 0o111) !== 0;
|
|
236
217
|
} catch {
|
|
237
218
|
return false;
|
|
@@ -304,20 +285,22 @@ export async function findFirstResolvableKimi(
|
|
|
304
285
|
pathString,
|
|
305
286
|
actionableShimPaths,
|
|
306
287
|
allDetectedShimPaths,
|
|
288
|
+
platform = process.platform,
|
|
307
289
|
) {
|
|
308
290
|
if (!ownRoot || !pathString) return { kind: 'none' };
|
|
309
|
-
const
|
|
310
|
-
const
|
|
291
|
+
const { delimiter: flavorDelimiter, join: flavorJoin, sep: flavorSep } = pathFlavor(platform);
|
|
292
|
+
const ownPrefix = ownRoot + flavorSep;
|
|
293
|
+
const candidates = executableCandidates(LEGACY_BIN, platform);
|
|
311
294
|
const skipSet = new Set(actionableShimPaths ?? []);
|
|
312
295
|
const knownLegacySet = new Set(allDetectedShimPaths ?? []);
|
|
313
296
|
const seenDirs = new Set();
|
|
314
|
-
for (const dir of pathString.split(
|
|
297
|
+
for (const dir of pathString.split(flavorDelimiter)) {
|
|
315
298
|
if (!dir || seenDirs.has(dir)) continue;
|
|
316
299
|
seenDirs.add(dir);
|
|
317
300
|
for (const name of candidates) {
|
|
318
|
-
const shim =
|
|
301
|
+
const shim = flavorJoin(dir, name);
|
|
319
302
|
if (skipSet.has(shim)) continue;
|
|
320
|
-
if (!(await isExecutableFile(shim))) continue;
|
|
303
|
+
if (!(await isExecutableFile(shim, platform))) continue;
|
|
321
304
|
const kind = await classifyShim(shim, ownRoot, ownPrefix);
|
|
322
305
|
if (kind === 'unreadable') continue;
|
|
323
306
|
if (kind === 'own') return { kind: 'own' };
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { findFirstResolvableKimi } from './reach.mjs';
|
|
2
|
+
import {
|
|
3
|
+
classifyShim,
|
|
4
|
+
deleteShim,
|
|
5
|
+
detectLegacyShims,
|
|
6
|
+
renameInPlace,
|
|
7
|
+
} from './migrate.mjs';
|
|
8
|
+
|
|
9
|
+
export async function planTakeover(ownRoot, detectionPath, reachabilityPath, platform) {
|
|
10
|
+
const detections = await detectLegacyShims(ownRoot, detectionPath, platform);
|
|
11
|
+
if (detections.length === 0) return { kind: /** @type {const} */ ('noop') };
|
|
12
|
+
|
|
13
|
+
const classifications = await Promise.all(
|
|
14
|
+
detections.map(async (detection) => {
|
|
15
|
+
const c = await classifyShim(detection.shimPath, platform);
|
|
16
|
+
return { ...c, detection };
|
|
17
|
+
}),
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
const actionable = classifications.filter((c) => c.kind !== 'blocked');
|
|
21
|
+
const blocked = classifications.filter((c) => c.kind === 'blocked');
|
|
22
|
+
const blocker = await findFirstResolvableKimi(
|
|
23
|
+
ownRoot,
|
|
24
|
+
reachabilityPath,
|
|
25
|
+
actionable.map((c) => c.shimPath),
|
|
26
|
+
classifications.map((c) => c.shimPath),
|
|
27
|
+
platform,
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
if (blocker.kind === 'own') {
|
|
31
|
+
return { kind: /** @type {const} */ ('proceed'), detections, classifications, actionable, blocked };
|
|
32
|
+
}
|
|
33
|
+
if (blocker.kind === 'blocked-legacy') {
|
|
34
|
+
return { kind: /** @type {const} */ ('blocked'), blocked, actionable };
|
|
35
|
+
}
|
|
36
|
+
if (blocker.kind === 'foreign') {
|
|
37
|
+
return { kind: /** @type {const} */ ('foreign'), path: blocker.path };
|
|
38
|
+
}
|
|
39
|
+
return { kind: /** @type {const} */ ('not-on-path'), detection: detections[0] };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function executeTakeover(classifications) {
|
|
43
|
+
const renames = [];
|
|
44
|
+
const consolidates = [];
|
|
45
|
+
const skippedForeignTarget = [];
|
|
46
|
+
const deletes = [];
|
|
47
|
+
const errors = [];
|
|
48
|
+
let preserved = false;
|
|
49
|
+
|
|
50
|
+
for (const c of classifications) {
|
|
51
|
+
if (c.kind === 'blocked') continue;
|
|
52
|
+
|
|
53
|
+
if (!preserved) {
|
|
54
|
+
if (c.kind === 'renameable') {
|
|
55
|
+
const r = await renameInPlace(c.shimPath, c.target);
|
|
56
|
+
if (r.success) {
|
|
57
|
+
renames.push(c);
|
|
58
|
+
preserved = true;
|
|
59
|
+
} else {
|
|
60
|
+
errors.push({ ...c, ...r });
|
|
61
|
+
}
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (c.kind === 'consolidate') {
|
|
65
|
+
const r = await deleteShim(c.shimPath);
|
|
66
|
+
if (r.success) {
|
|
67
|
+
consolidates.push(c);
|
|
68
|
+
preserved = true;
|
|
69
|
+
} else {
|
|
70
|
+
errors.push({ ...c, ...r });
|
|
71
|
+
}
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (c.kind === 'delete-only') {
|
|
75
|
+
const r = await deleteShim(c.shimPath);
|
|
76
|
+
if (r.success) {
|
|
77
|
+
skippedForeignTarget.push(c);
|
|
78
|
+
} else {
|
|
79
|
+
errors.push({ ...c, ...r });
|
|
80
|
+
}
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
} else {
|
|
84
|
+
const r = await deleteShim(c.shimPath);
|
|
85
|
+
if (r.success) {
|
|
86
|
+
deletes.push(c);
|
|
87
|
+
} else {
|
|
88
|
+
errors.push({ ...c, ...r });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return { renames, consolidates, skippedForeignTarget, deletes, errors, preserved };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export async function verifyTakeover(ownRoot, reachabilityPath, allDetectedShimPaths, platform) {
|
|
97
|
+
return findFirstResolvableKimi(ownRoot, reachabilityPath, [], allDetectedShimPaths, platform);
|
|
98
|
+
}
|
|
@@ -406,6 +406,97 @@ export function logForeignKimiInTheWay(foreignPath, pm) {
|
|
|
406
406
|
);
|
|
407
407
|
}
|
|
408
408
|
|
|
409
|
+
/**
|
|
410
|
+
* A takeover that was executed but did NOT hold up under post-execution
|
|
411
|
+
* verification: `kimi` still resolves to a legacy/foreign file (or to
|
|
412
|
+
* nothing at all). The heading must not claim success — list what was
|
|
413
|
+
* actually changed, what still blocks resolution, and how to finish
|
|
414
|
+
* the job by hand.
|
|
415
|
+
*/
|
|
416
|
+
export function logMigrationIncomplete(input, pm) {
|
|
417
|
+
const { outcomes, verify } = input;
|
|
418
|
+
const { renames, consolidates, skippedForeignTarget, deletes, errors } = outcomes;
|
|
419
|
+
const isWindows = process.platform === 'win32';
|
|
420
|
+
const reinstallCmd = pmGlobalInstallCommand(pm, '@moonshot-ai/kimi-code');
|
|
421
|
+
|
|
422
|
+
const lines = [warningHeading('Couldn\'t finish switching to the new kimi'), ''];
|
|
423
|
+
|
|
424
|
+
if (verify.kind === 'blocked-legacy') {
|
|
425
|
+
lines.push(
|
|
426
|
+
pad(' Typing `kimi` still runs the old version. This file is in'),
|
|
427
|
+
pad(' the way and we couldn\'t change it:'),
|
|
428
|
+
pathInBox(verify.shim),
|
|
429
|
+
'',
|
|
430
|
+
);
|
|
431
|
+
} else if (verify.kind === 'foreign') {
|
|
432
|
+
lines.push(
|
|
433
|
+
pad(' Typing `kimi` runs a file we don\'t recognize (not the new'),
|
|
434
|
+
pad(' CLI, not the old one). It\'s still in the way:'),
|
|
435
|
+
pathInBox(verify.path),
|
|
436
|
+
'',
|
|
437
|
+
);
|
|
438
|
+
} else {
|
|
439
|
+
lines.push(
|
|
440
|
+
pad(' Typing `kimi` currently finds nothing at all — the old'),
|
|
441
|
+
pad(' shim was removed but the new one isn\'t reachable yet.'),
|
|
442
|
+
'',
|
|
443
|
+
);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
const changed = [
|
|
447
|
+
...renames.map((c) => c.shimPath + ' -> ' + c.target),
|
|
448
|
+
...consolidates.map((c) => c.shimPath + ' (removed; kimi-legacy kept)'),
|
|
449
|
+
...skippedForeignTarget.map((c) => c.shimPath + ' (removed)'),
|
|
450
|
+
...deletes.map((c) => c.shimPath + ' (removed)'),
|
|
451
|
+
];
|
|
452
|
+
if (changed.length > 0) {
|
|
453
|
+
lines.push(pad(' Changes already made:'));
|
|
454
|
+
for (const line of changed) lines.push(pathInBox(line));
|
|
455
|
+
lines.push('');
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
if (errors.length > 0) {
|
|
459
|
+
lines.push(pad(' Changes that didn\'t go through:'));
|
|
460
|
+
for (const e of errors) {
|
|
461
|
+
lines.push(pathInBox(e.shimPath + ' (' + (e.message ?? e.code ?? 'error') + ')'));
|
|
462
|
+
}
|
|
463
|
+
lines.push('');
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
if (verify.kind === 'blocked-legacy') {
|
|
467
|
+
const c = verify;
|
|
468
|
+
lines.push(pad(' Delete it yourself, then install again:'));
|
|
469
|
+
if (isWindows) {
|
|
470
|
+
lines.push(pathInBox('Remove-Item ' + quotePowerShellPath(c.shim)));
|
|
471
|
+
} else {
|
|
472
|
+
lines.push(pathInBox('rm ' + quotePosixPath(c.shim)));
|
|
473
|
+
lines.push(pad(' (use sudo if it\'s in a system directory)'));
|
|
474
|
+
}
|
|
475
|
+
lines.push(pathInBox(reinstallCmd), '');
|
|
476
|
+
} else if (verify.kind === 'foreign') {
|
|
477
|
+
lines.push(
|
|
478
|
+
pad(' Delete or rename that file, then install again:'),
|
|
479
|
+
pathInBox(reinstallCmd),
|
|
480
|
+
'',
|
|
481
|
+
);
|
|
482
|
+
} else {
|
|
483
|
+
lines.push(
|
|
484
|
+
pad(' Open a new terminal and check `which kimi`. If it finds'),
|
|
485
|
+
pad(' nothing, reinstall to restore a working shim:'),
|
|
486
|
+
pathInBox(reinstallCmd),
|
|
487
|
+
'',
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
if (renames.length > 0 || consolidates.length > 0) {
|
|
492
|
+
lines.push(
|
|
493
|
+
pad(' The old version is still available as `kimi-legacy`.'),
|
|
494
|
+
);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
emit(renderBox(lines));
|
|
498
|
+
}
|
|
499
|
+
|
|
409
500
|
/**
|
|
410
501
|
* The legacy `kimi` was found, but the directory where the package
|
|
411
502
|
* manager placed the new `kimi` shim is not on the user's PATH.
|
package/scripts/postinstall.mjs
CHANGED
|
@@ -37,9 +37,10 @@
|
|
|
37
37
|
* - `./postinstall/migrate.mjs` — legacy detection,
|
|
38
38
|
* `kimi`-vs-`kimi-legacy` classification, the rename / unlink
|
|
39
39
|
* primitives.
|
|
40
|
+
* - `./postinstall/takeover.mjs` — the plan → execute → verify
|
|
41
|
+
* state machine this orchestrator drives.
|
|
40
42
|
* - `./postinstall/ui.mjs` — `notify()` (with `/dev/tty` fallback),
|
|
41
|
-
* ANSI styling, the fixed-width box, and the
|
|
42
|
-
* renderers.
|
|
43
|
+
* ANSI styling, the fixed-width box, and the outcome renderers.
|
|
43
44
|
*
|
|
44
45
|
* ## Workflow
|
|
45
46
|
*
|
|
@@ -60,41 +61,26 @@
|
|
|
60
61
|
* shell can't be probed). Sharing one probe keeps detection
|
|
61
62
|
* and reachability symmetric and avoids running `$SHELL -l`
|
|
62
63
|
* twice.
|
|
63
|
-
* 5.
|
|
64
|
-
* PATH
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
* `
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
* `logNewCliNotOnPath`; touch nothing.
|
|
84
|
-
* 8. Execute. The FIRST classification in PATH order that we can
|
|
85
|
-
* touch becomes `kimi-legacy` (preserves what `kimi` referred
|
|
86
|
-
* to before this install). Each subsequent shim is `unlink`ed —
|
|
87
|
-
* keeping it as a dormant duplicate adds no value. If the
|
|
88
|
-
* first shim's `kimi-legacy` target is already user-managed,
|
|
89
|
-
* we delete `kimi` anyway (still achieves takeover) and tell
|
|
90
|
-
* the user we couldn't preserve a fallback. Extension is
|
|
91
|
-
* preserved on Windows (`kimi.exe` → `kimi-legacy.exe`).
|
|
92
|
-
* 9. One end-of-orchestration notice (`logMigrationDone`)
|
|
93
|
-
* summarizes every action — renames, consolidates,
|
|
94
|
-
* delete-only, deletes, and harmless blocked leftovers. The
|
|
95
|
-
* takeover-success line only fires on this path because Step 7
|
|
96
|
-
* already certified it.
|
|
97
|
-
* 10. The manager completes the install with its usual summary.
|
|
64
|
+
* 5. `planTakeover`: detect EVERY previous Python `kimi-cli` shim
|
|
65
|
+
* on the detection PATH, pre-flight classify each (no writes),
|
|
66
|
+
* and simulate PATH resolution with the actionable shims gone:
|
|
67
|
+
* - `own` wins → proceed.
|
|
68
|
+
* - a blocked legacy still wins → `logMigrationBlocked`.
|
|
69
|
+
* - a foreign `kimi` wins → `logForeignKimiInTheWay`.
|
|
70
|
+
* - nothing resolves → `logNewCliNotOnPath`.
|
|
71
|
+
* The abort branches touch NOTHING.
|
|
72
|
+
* 6. `executeTakeover`: the FIRST shim in PATH order that can be
|
|
73
|
+
* preserved becomes `kimi-legacy`; each subsequent shim is
|
|
74
|
+
* `unlink`ed. A failed preserve attempt does not promote the
|
|
75
|
+
* next shim to deletion — it gets its own preserve attempt, so
|
|
76
|
+
* a usable legacy fallback survives whenever one is possible.
|
|
77
|
+
* 7. `verifyTakeover`: walk the reachability PATH as it actually
|
|
78
|
+
* is AFTER execution. Only `{ kind: 'own' }` renders the
|
|
79
|
+
* success box (`logMigrationDone`); anything else renders
|
|
80
|
+
* `logMigrationIncomplete` — what changed, what still blocks,
|
|
81
|
+
* and how to finish by hand. The pre-flight simulation in
|
|
82
|
+
* step 5 is never reported as proof of success.
|
|
83
|
+
* 8. The manager completes the install with its usual summary.
|
|
98
84
|
* This script always exits 0; any uncaught error is swallowed
|
|
99
85
|
* by the top-level `catch` so the install never fails because
|
|
100
86
|
* of the migration.
|
|
@@ -102,21 +88,20 @@
|
|
|
102
88
|
|
|
103
89
|
import {
|
|
104
90
|
detectPackageManager,
|
|
105
|
-
findFirstResolvableKimi,
|
|
106
91
|
isGlobalInstall,
|
|
107
92
|
ownPackageRoot,
|
|
108
93
|
postinstallPaths,
|
|
109
94
|
} from './postinstall/reach.mjs';
|
|
110
95
|
import {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
} from './postinstall/migrate.mjs';
|
|
96
|
+
executeTakeover,
|
|
97
|
+
planTakeover,
|
|
98
|
+
verifyTakeover,
|
|
99
|
+
} from './postinstall/takeover.mjs';
|
|
116
100
|
import {
|
|
117
101
|
logForeignKimiInTheWay,
|
|
118
102
|
logMigrationBlocked,
|
|
119
103
|
logMigrationDone,
|
|
104
|
+
logMigrationIncomplete,
|
|
120
105
|
logNewCliNotOnPath,
|
|
121
106
|
notify,
|
|
122
107
|
} from './postinstall/ui.mjs';
|
|
@@ -143,124 +128,45 @@ async function main() {
|
|
|
143
128
|
// installer's env).
|
|
144
129
|
const paths = await postinstallPaths();
|
|
145
130
|
|
|
146
|
-
// Step 4:
|
|
147
|
-
|
|
148
|
-
// install` would have two; we must address all of them or the
|
|
149
|
-
// survivor still shadows the new CLI.
|
|
150
|
-
const detections = await detectLegacyShims(ownRoot, paths.detection);
|
|
151
|
-
if (detections.length === 0) return;
|
|
152
|
-
|
|
153
|
-
// Step 5: pre-flight classify every shim WITHOUT touching the
|
|
154
|
-
// filesystem yet. The orchestrator decides abort-or-proceed against
|
|
155
|
-
// the whole set rather than discovering mid-loop that we got partway
|
|
156
|
-
// and have to backtrack.
|
|
157
|
-
const classifications = await Promise.all(
|
|
158
|
-
detections.map(async (detection) => {
|
|
159
|
-
const c = await classifyShim(detection.shimPath);
|
|
160
|
-
return { ...c, detection };
|
|
161
|
-
}),
|
|
162
|
-
);
|
|
163
|
-
|
|
164
|
-
// Step 6: figure out what wins PATH resolution once every shim we
|
|
165
|
-
// CAN touch is treated as gone. Three possible blockers:
|
|
166
|
-
// - a legacy shim we couldn't classify as actionable (sudo/admin
|
|
167
|
-
// needed)
|
|
168
|
-
// - an unrelated `kimi` we don't recognize (a user's own wrapper
|
|
169
|
-
// script — they own the decision)
|
|
170
|
-
// - nothing resolves (our shim isn't on PATH at all)
|
|
171
|
-
// For each we render a different notice and touch NOTHING. The
|
|
172
|
-
// common-case fourth result is "our shim wins" — we proceed.
|
|
173
|
-
const actionable = classifications.filter((c) => c.kind !== 'blocked');
|
|
174
|
-
const blocked = classifications.filter((c) => c.kind === 'blocked');
|
|
175
|
-
const actionableShimPaths = actionable.map((c) => c.shimPath);
|
|
176
|
-
const allDetectedShimPaths = classifications.map((c) => c.shimPath);
|
|
177
|
-
|
|
178
|
-
const blocker = await findFirstResolvableKimi(
|
|
131
|
+
// Step 4: plan against the whole detected shim set without writing.
|
|
132
|
+
const plan = await planTakeover(
|
|
179
133
|
ownRoot,
|
|
134
|
+
paths.detection,
|
|
180
135
|
paths.reachability,
|
|
181
|
-
|
|
182
|
-
allDetectedShimPaths,
|
|
136
|
+
process.platform,
|
|
183
137
|
);
|
|
184
|
-
if (
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
} else if (blocker.kind === 'foreign') {
|
|
188
|
-
logForeignKimiInTheWay(blocker.path, pm);
|
|
189
|
-
} else {
|
|
190
|
-
// 'none' — our shim isn't on PATH at all.
|
|
191
|
-
logNewCliNotOnPath(detections[0], pm);
|
|
192
|
-
}
|
|
138
|
+
if (plan.kind === 'noop') return;
|
|
139
|
+
if (plan.kind === 'blocked') {
|
|
140
|
+
logMigrationBlocked(plan.blocked, plan.actionable, pm);
|
|
193
141
|
return;
|
|
194
142
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
const skippedForeignTarget = [];
|
|
203
|
-
const deletes = [];
|
|
204
|
-
const errors = [];
|
|
205
|
-
let preservedFirst = false;
|
|
206
|
-
|
|
207
|
-
for (const c of classifications) {
|
|
208
|
-
if (c.kind === 'blocked') continue; // already established harmless
|
|
209
|
-
|
|
210
|
-
if (!preservedFirst) {
|
|
211
|
-
preservedFirst = true;
|
|
212
|
-
if (c.kind === 'renameable') {
|
|
213
|
-
const r = await renameInPlace(c.shimPath, c.target);
|
|
214
|
-
if (r.success) {
|
|
215
|
-
renames.push(c);
|
|
216
|
-
} else {
|
|
217
|
-
errors.push({ ...c, ...r });
|
|
218
|
-
}
|
|
219
|
-
continue;
|
|
220
|
-
}
|
|
221
|
-
if (c.kind === 'consolidate') {
|
|
222
|
-
const r = await deleteShim(c.shimPath);
|
|
223
|
-
if (r.success) {
|
|
224
|
-
consolidates.push(c);
|
|
225
|
-
} else {
|
|
226
|
-
errors.push({ ...c, ...r });
|
|
227
|
-
}
|
|
228
|
-
continue;
|
|
229
|
-
}
|
|
230
|
-
if (c.kind === 'delete-only') {
|
|
231
|
-
const r = await deleteShim(c.shimPath);
|
|
232
|
-
if (r.success) {
|
|
233
|
-
skippedForeignTarget.push(c);
|
|
234
|
-
} else {
|
|
235
|
-
errors.push({ ...c, ...r });
|
|
236
|
-
}
|
|
237
|
-
continue;
|
|
238
|
-
}
|
|
239
|
-
} else {
|
|
240
|
-
// Not the first actionable shim. Just delete it.
|
|
241
|
-
const r = await deleteShim(c.shimPath);
|
|
242
|
-
if (r.success) {
|
|
243
|
-
deletes.push(c);
|
|
244
|
-
} else {
|
|
245
|
-
errors.push({ ...c, ...r });
|
|
246
|
-
}
|
|
247
|
-
}
|
|
143
|
+
if (plan.kind === 'foreign') {
|
|
144
|
+
logForeignKimiInTheWay(plan.path, pm);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
if (plan.kind === 'not-on-path') {
|
|
148
|
+
logNewCliNotOnPath(plan.detection, pm);
|
|
149
|
+
return;
|
|
248
150
|
}
|
|
249
151
|
|
|
250
|
-
// Step
|
|
251
|
-
//
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
pm,
|
|
152
|
+
// Step 5: execute (preserve the first preservable shim as
|
|
153
|
+
// `kimi-legacy`, delete the rest).
|
|
154
|
+
const outcomes = await executeTakeover(plan.classifications);
|
|
155
|
+
|
|
156
|
+
// Step 6: post-execution verification — the ONLY ground for a
|
|
157
|
+
// success claim. If reality diverged from the step-4 simulation
|
|
158
|
+
// (a rename failed, a new shim appeared), report it honestly.
|
|
159
|
+
const verify = await verifyTakeover(
|
|
160
|
+
ownRoot,
|
|
161
|
+
paths.reachability,
|
|
162
|
+
plan.classifications.map((c) => c.shimPath),
|
|
163
|
+
process.platform,
|
|
263
164
|
);
|
|
165
|
+
if (verify.kind === 'own') {
|
|
166
|
+
logMigrationDone({ ...outcomes, blockedHarmless: plan.blocked }, pm);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
logMigrationIncomplete({ outcomes, verify, blocked: plan.blocked }, pm);
|
|
264
170
|
}
|
|
265
171
|
|
|
266
172
|
main().catch((err) => {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{U as a,O as n}from"./mermaid.core-CGrLstUA.js";const t=(r,o)=>a.lang.round(n.parse(r)[o]);export{t as c};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as a,c as s,a as e,C as t}from"./chunk-V7JOEXUC-5w7loxVR.js";import{_ as i}from"./mermaid.core-CGrLstUA.js";import"./chunk-5VM5RSS4-K_NNkrmw.js";import"./chunk-XXDRQBXY-BwEKpC0s.js";import"./chunk-VR4S4FIN-Cp8JVohH.js";import"./chunk-32BRIVSS-0ImWpiFu.js";import"./index-CvgiEu-R.js";import"./_commonjsHelpers-CqkleIqs.js";var f={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{f as diagram};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as a,c as s,a as e,C as t}from"./chunk-V7JOEXUC-5w7loxVR.js";import{_ as i}from"./mermaid.core-CGrLstUA.js";import"./chunk-5VM5RSS4-K_NNkrmw.js";import"./chunk-XXDRQBXY-BwEKpC0s.js";import"./chunk-VR4S4FIN-Cp8JVohH.js";import"./chunk-32BRIVSS-0ImWpiFu.js";import"./index-CvgiEu-R.js";import"./_commonjsHelpers-CqkleIqs.js";var f={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{f as diagram};
|