@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 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: { npm_config_prefix: stagingPrefix },
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.97",
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.97",
24
- "@getmikie/darwin-x64": "1.1.97",
25
- "@getmikie/linux-x64-gnu": "1.1.97",
26
- "@getmikie/win32-x64": "1.1.97"
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
+ }