@getmikie/cli 1.1.97 → 1.1.99
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/bin/mikie.mjs +14 -0
- package/lib/update.mjs +59 -1
- package/package.json +9 -5
- package/scripts/reconcile-install.mjs +59 -0
package/bin/mikie.mjs
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
detectUpdateTopology,
|
|
24
24
|
externalRecoveryInvocation,
|
|
25
25
|
parseUpdateHandoff,
|
|
26
|
+
parseTrajectoryReconciliationReceipt,
|
|
26
27
|
runUpdateTransaction,
|
|
27
28
|
} from "../lib/update.mjs";
|
|
28
29
|
|
|
@@ -163,6 +164,19 @@ All commands execute the compiled Mikie native engine.`);
|
|
|
163
164
|
throw new Error("candidate owned-adapter settlement failed");
|
|
164
165
|
}
|
|
165
166
|
},
|
|
167
|
+
reconcileTrajectoryStore: async (reconciliationBinary) => {
|
|
168
|
+
const reconciliation = await commands.run(
|
|
169
|
+
reconciliationBinary,
|
|
170
|
+
["reconcile-trajectory-store-v2", "--json"],
|
|
171
|
+
{ shell: false, capture: true },
|
|
172
|
+
);
|
|
173
|
+
if (reconciliation.code !== 0) {
|
|
174
|
+
throw new Error("trajectory-store reconciliation failed");
|
|
175
|
+
}
|
|
176
|
+
parseTrajectoryReconciliationReceipt(reconciliation.stdout, {
|
|
177
|
+
allowNotConfigured: true,
|
|
178
|
+
});
|
|
179
|
+
},
|
|
166
180
|
});
|
|
167
181
|
const result = await runUpdateTransaction({
|
|
168
182
|
handoff,
|
package/lib/update.mjs
CHANGED
|
@@ -20,6 +20,7 @@ import { isDeepStrictEqual } from "node:util";
|
|
|
20
20
|
const WRAPPER_PACKAGE = "@getmikie/cli";
|
|
21
21
|
const HANDOFF_SCHEMA = "mikie.update-handoff.v1";
|
|
22
22
|
const REPAIR_SCHEMA = "mikie.claude-hook-repair.v1";
|
|
23
|
+
const TRAJECTORY_RECONCILIATION_SCHEMA = "mikie.trajectory-store-reconciliation.v1";
|
|
23
24
|
const RERUN_COMMAND = "npx -y @getmikie/cli@latest update";
|
|
24
25
|
const MAX_COMMAND_OUTPUT_BYTES = 1024 * 1024;
|
|
25
26
|
const DEFAULT_COMMAND_TIMEOUT_MS = 30_000;
|
|
@@ -640,6 +641,30 @@ function parseRepairReceipt(stdout) {
|
|
|
640
641
|
return { receipt, skipped };
|
|
641
642
|
}
|
|
642
643
|
|
|
644
|
+
export function parseTrajectoryReconciliationReceipt(stdout, { allowNotConfigured = false } = {}) {
|
|
645
|
+
let receipt;
|
|
646
|
+
try {
|
|
647
|
+
receipt = JSON.parse(stdout.trim());
|
|
648
|
+
} catch {
|
|
649
|
+
throw new Error("trajectory-store reconciliation returned invalid JSON");
|
|
650
|
+
}
|
|
651
|
+
const ready =
|
|
652
|
+
receipt?.status === "ready" &&
|
|
653
|
+
["fresh", "migrated_v1"].includes(receipt.activation);
|
|
654
|
+
const notConfigured =
|
|
655
|
+
allowNotConfigured &&
|
|
656
|
+
receipt?.status === "not_configured" &&
|
|
657
|
+
receipt.activation === null;
|
|
658
|
+
if (
|
|
659
|
+
!hasExactKeys(receipt, ["schema_version", "status", "activation"]) ||
|
|
660
|
+
receipt.schema_version !== TRAJECTORY_RECONCILIATION_SCHEMA ||
|
|
661
|
+
(!ready && !notConfigured)
|
|
662
|
+
) {
|
|
663
|
+
throw new Error("trajectory-store reconciliation returned an invalid receipt");
|
|
664
|
+
}
|
|
665
|
+
return receipt;
|
|
666
|
+
}
|
|
667
|
+
|
|
643
668
|
function recoveryCommand(currentVersion) {
|
|
644
669
|
return `npm install --global ${WRAPPER_PACKAGE}@${currentVersion}`;
|
|
645
670
|
}
|
|
@@ -715,7 +740,11 @@ export async function runUpdateTransaction({
|
|
|
715
740
|
{
|
|
716
741
|
shell: false,
|
|
717
742
|
capture: true,
|
|
718
|
-
environment: {
|
|
743
|
+
environment: {
|
|
744
|
+
npm_config_prefix: stagingPrefix,
|
|
745
|
+
MIKIE_UPDATE_CANDIDATE_STAGING: stagingPrefix,
|
|
746
|
+
MIKIE_UPDATE_CANDIDATE_TOKEN: snapshot.lease.token,
|
|
747
|
+
},
|
|
719
748
|
},
|
|
720
749
|
);
|
|
721
750
|
if (stagedInstall.code !== 0) throw new Error("exact staged npm install failed");
|
|
@@ -784,6 +813,7 @@ export async function runUpdateTransaction({
|
|
|
784
813
|
const settlementRequired = repairResult.receipt.action === "migrated";
|
|
785
814
|
await files.decideCommit(snapshot, { settlementRequired });
|
|
786
815
|
commitDecided = true;
|
|
816
|
+
await files.reconcileTrajectoryStore(snapshot);
|
|
787
817
|
if (settlementRequired) {
|
|
788
818
|
const settlement = await commands.run(candidate.binary, handoff.repair_command, {
|
|
789
819
|
shell: false,
|
|
@@ -1231,6 +1261,7 @@ export function createFilesystemAdapter({
|
|
|
1231
1261
|
processId = process.pid,
|
|
1232
1262
|
isProcessAlive = processIsAlive,
|
|
1233
1263
|
settleProviderRepair,
|
|
1264
|
+
reconcileTrajectoryStore,
|
|
1234
1265
|
activationBoundary,
|
|
1235
1266
|
}) {
|
|
1236
1267
|
const currentRoots = validateInstallationLayout(currentLayout);
|
|
@@ -1244,6 +1275,7 @@ export function createFilesystemAdapter({
|
|
|
1244
1275
|
typeof transactionRoot !== "string" ||
|
|
1245
1276
|
!path.isAbsolute(transactionRoot) ||
|
|
1246
1277
|
(settleProviderRepair !== undefined && typeof settleProviderRepair !== "function") ||
|
|
1278
|
+
(reconcileTrajectoryStore !== undefined && typeof reconcileTrajectoryStore !== "function") ||
|
|
1247
1279
|
(activationBoundary !== undefined && typeof activationBoundary !== "function")
|
|
1248
1280
|
) {
|
|
1249
1281
|
throw new Error("unsafe Mikie update filesystem path");
|
|
@@ -2203,6 +2235,10 @@ export function createFilesystemAdapter({
|
|
|
2203
2235
|
}
|
|
2204
2236
|
const snapshot = await hydrateJournal(lease, expectedJournalToken);
|
|
2205
2237
|
if (snapshot.phase === "commit_decided") {
|
|
2238
|
+
if (!reconcileTrajectoryStore) {
|
|
2239
|
+
throw new Error("trajectory-store reconciliation is unavailable");
|
|
2240
|
+
}
|
|
2241
|
+
await reconcileTrajectoryStore(snapshot.preparedCandidate.finalLauncher, snapshot);
|
|
2206
2242
|
if (!settleProviderRepair) {
|
|
2207
2243
|
throw new Error("candidate owned-adapter settlement is unavailable");
|
|
2208
2244
|
}
|
|
@@ -2214,6 +2250,10 @@ export function createFilesystemAdapter({
|
|
|
2214
2250
|
return;
|
|
2215
2251
|
}
|
|
2216
2252
|
if (snapshot.phase === "commit_decided_no_repair") {
|
|
2253
|
+
if (!reconcileTrajectoryStore) {
|
|
2254
|
+
throw new Error("trajectory-store reconciliation is unavailable");
|
|
2255
|
+
}
|
|
2256
|
+
await reconcileTrajectoryStore(snapshot.preparedCandidate.finalLauncher, snapshot);
|
|
2217
2257
|
snapshot.phase = "committed";
|
|
2218
2258
|
await writeJournal(snapshot);
|
|
2219
2259
|
await cleanupCommittedActivation(snapshot);
|
|
@@ -2713,6 +2753,13 @@ export function createFilesystemAdapter({
|
|
|
2713
2753
|
snapshot.phase = settlementRequired ? "commit_decided" : "commit_decided_no_repair";
|
|
2714
2754
|
await writeJournal(snapshot);
|
|
2715
2755
|
},
|
|
2756
|
+
async reconcileTrajectoryStore(snapshot) {
|
|
2757
|
+
const binary = snapshot?.preparedCandidate?.finalLauncher;
|
|
2758
|
+
if (!reconcileTrajectoryStore || typeof binary !== "string" || !path.isAbsolute(binary)) {
|
|
2759
|
+
throw new Error("trajectory-store reconciliation is unavailable");
|
|
2760
|
+
}
|
|
2761
|
+
await reconcileTrajectoryStore(binary, snapshot);
|
|
2762
|
+
},
|
|
2716
2763
|
async locateCandidate(request) {
|
|
2717
2764
|
const candidate = await locateCandidate(request);
|
|
2718
2765
|
const candidateRoots = validateInstallationLayout(candidate);
|
|
@@ -2938,6 +2985,17 @@ export async function recoverExternalNpmUpdate(transactionRoot, expectedAuthorit
|
|
|
2938
2985
|
throw new Error("candidate owned-adapter settlement failed");
|
|
2939
2986
|
}
|
|
2940
2987
|
},
|
|
2988
|
+
reconcileTrajectoryStore: async (binary) => {
|
|
2989
|
+
const result = await commands.run(
|
|
2990
|
+
binary,
|
|
2991
|
+
["reconcile-trajectory-store-v2", "--json"],
|
|
2992
|
+
{ shell: false, capture: true },
|
|
2993
|
+
);
|
|
2994
|
+
if (result.code !== 0) {
|
|
2995
|
+
throw new Error("trajectory-store reconciliation failed");
|
|
2996
|
+
}
|
|
2997
|
+
parseTrajectoryReconciliationReceipt(result.stdout, { allowNotConfigured: true });
|
|
2998
|
+
},
|
|
2941
2999
|
});
|
|
2942
3000
|
const lease = await files.beginTransaction();
|
|
2943
3001
|
await files.endTransaction(lease);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getmikie/cli",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.99",
|
|
4
4
|
"description": "Native Mikie relay launcher for MCP clients",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -11,19 +11,23 @@
|
|
|
11
11
|
"bin": {
|
|
12
12
|
"mikie": "bin/mikie.mjs"
|
|
13
13
|
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"postinstall": "node ./scripts/reconcile-install.mjs"
|
|
16
|
+
},
|
|
14
17
|
"files": [
|
|
15
18
|
"bin",
|
|
16
19
|
"lib",
|
|
20
|
+
"scripts",
|
|
17
21
|
"README.md"
|
|
18
22
|
],
|
|
19
23
|
"engines": {
|
|
20
24
|
"node": ">=22"
|
|
21
25
|
},
|
|
22
26
|
"optionalDependencies": {
|
|
23
|
-
"@getmikie/darwin-arm64": "1.1.
|
|
24
|
-
"@getmikie/darwin-x64": "1.1.
|
|
25
|
-
"@getmikie/linux-x64-gnu": "1.1.
|
|
26
|
-
"@getmikie/win32-x64": "1.1.
|
|
27
|
+
"@getmikie/darwin-arm64": "1.1.99",
|
|
28
|
+
"@getmikie/darwin-x64": "1.1.99",
|
|
29
|
+
"@getmikie/linux-x64-gnu": "1.1.99",
|
|
30
|
+
"@getmikie/win32-x64": "1.1.99"
|
|
27
31
|
},
|
|
28
32
|
"publishConfig": {
|
|
29
33
|
"access": "public",
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
|
|
4
|
+
import { resolveNativeBinary } from "../lib/launcher.mjs";
|
|
5
|
+
import {
|
|
6
|
+
createCommandAdapter,
|
|
7
|
+
parseTrajectoryReconciliationReceipt,
|
|
8
|
+
} from "../lib/update.mjs";
|
|
9
|
+
|
|
10
|
+
const RECONCILIATION_ARGUMENTS = ["reconcile-trajectory-store-v2", "--json"];
|
|
11
|
+
const TRANSACTION_TOKEN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
12
|
+
|
|
13
|
+
function pathIdentity(value, platform) {
|
|
14
|
+
const pathApi = platform === "win32" ? path.win32 : path.posix;
|
|
15
|
+
if (typeof value !== "string" || !pathApi.isAbsolute(value)) return null;
|
|
16
|
+
const identity = pathApi.normalize(pathApi.resolve(value));
|
|
17
|
+
return platform === "win32" ? identity.toLowerCase() : identity;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function isTransactionStagedInstall(
|
|
21
|
+
environment = process.env,
|
|
22
|
+
platform = process.platform,
|
|
23
|
+
) {
|
|
24
|
+
const marker = pathIdentity(environment.MIKIE_UPDATE_CANDIDATE_STAGING, platform);
|
|
25
|
+
const npmPrefix = pathIdentity(environment.npm_config_prefix, platform);
|
|
26
|
+
return (
|
|
27
|
+
marker !== null &&
|
|
28
|
+
marker === npmPrefix &&
|
|
29
|
+
TRANSACTION_TOKEN.test(environment.MIKIE_UPDATE_CANDIDATE_TOKEN ?? "")
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export async function reconcileInstalledTrajectory({
|
|
34
|
+
environment = process.env,
|
|
35
|
+
platform = process.platform,
|
|
36
|
+
resolveBinary = resolveNativeBinary,
|
|
37
|
+
commands = createCommandAdapter({ environment, platform }),
|
|
38
|
+
} = {}) {
|
|
39
|
+
if (isTransactionStagedInstall(environment, platform)) {
|
|
40
|
+
return { status: "staged_candidate" };
|
|
41
|
+
}
|
|
42
|
+
const binary = await resolveBinary();
|
|
43
|
+
const result = await commands.run(binary, RECONCILIATION_ARGUMENTS, { shell: false });
|
|
44
|
+
if (result.code !== 0) {
|
|
45
|
+
throw new Error("native trajectory-store reconciliation failed");
|
|
46
|
+
}
|
|
47
|
+
return parseTrajectoryReconciliationReceipt(result.stdout, { allowNotConfigured: true });
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const scriptIdentity = pathIdentity(fileURLToPath(import.meta.url), process.platform);
|
|
51
|
+
const invokedIdentity = pathIdentity(process.argv[1], process.platform);
|
|
52
|
+
if (scriptIdentity !== null && scriptIdentity === invokedIdentity) {
|
|
53
|
+
try {
|
|
54
|
+
await reconcileInstalledTrajectory();
|
|
55
|
+
} catch (error) {
|
|
56
|
+
console.error(`Mikie install reconciliation failed: ${error.message}`);
|
|
57
|
+
process.exitCode = 1;
|
|
58
|
+
}
|
|
59
|
+
}
|