@getmikie/cli 1.1.87 → 1.1.89

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 CHANGED
@@ -16,3 +16,18 @@ mikie mcp
16
16
  The launcher contains no relay, pricing, receipt, or model logic. npm installs
17
17
  the matching `@getmikie/*` optional platform package and the launcher executes that
18
18
  binary with inherited stdio.
19
+
20
+ ## Mikie Control
21
+
22
+ Run one immutable, repository-scoped request through the verified Codex App
23
+ Server runtime:
24
+
25
+ ```sh
26
+ mikie control run --request C:\absolute\path\control-request.json --json
27
+ ```
28
+
29
+ The request must be an existing absolute JSON file. Mikie validates the frozen
30
+ repository, allowed paths, deterministic verifier, exact model and reasoning
31
+ effort, bounded model-turn timeout, and private temporary root before execution. The JSON result is
32
+ content-free: it reports terminal status and hashes, never prompts, context,
33
+ patch bodies, verifier output, or credentials.
package/bin/mikie.mjs CHANGED
@@ -9,6 +9,7 @@ import { fileURLToPath } from "node:url";
9
9
  import {
10
10
  launchNativeCaptured,
11
11
  launchNative,
12
+ prepareNativeLaunch,
12
13
  resolveNativeBinary,
13
14
  selectPlatformPackage,
14
15
  translateArguments,
@@ -38,6 +39,7 @@ Usage:
38
39
  mikie mcp [--adapter codex|claude_code]
39
40
  mikie login
40
41
  mikie connect .
42
+ mikie control run --request <absolute-json> --json
41
43
  mikie doctor
42
44
  mikie update
43
45
 
@@ -183,8 +185,11 @@ All commands execute the compiled Mikie native engine.`);
183
185
  }
184
186
  } else {
185
187
  try {
186
- const binary = await resolveNativeBinary();
187
- process.exitCode = await launchNative(binary, translateArguments(arguments_));
188
+ const nativeArguments = translateArguments(arguments_);
189
+ const binary = await prepareNativeLaunch(await resolveNativeBinary(), nativeArguments, {
190
+ version: packageMetadata.version,
191
+ });
192
+ process.exitCode = await launchNative(binary, nativeArguments);
188
193
  } catch (error) {
189
194
  const message = error instanceof Error ? error.message : "Mikie is unavailable";
190
195
  console.error(`mikie: ${message}`);
package/lib/launcher.mjs CHANGED
@@ -1,6 +1,7 @@
1
1
  import { createRequire } from "node:module";
2
- import { access, stat } from "node:fs/promises";
3
- import { constants as fsConstants } from "node:fs";
2
+ import { createHash, randomUUID } from "node:crypto";
3
+ import { constants as fsConstants, createReadStream } from "node:fs";
4
+ import { access, copyFile, lstat, mkdir, readdir, rename, rm, stat } from "node:fs/promises";
4
5
  import path from "node:path";
5
6
  import { spawn } from "node:child_process";
6
7
 
@@ -18,6 +19,142 @@ const SIGNAL_EXIT_CODES = new Map([
18
19
  ]);
19
20
 
20
21
  const MAX_CAPTURED_OUTPUT_BYTES = 1024 * 1024;
22
+ const SAFE_RUNTIME_VERSION = /^[0-9A-Za-z][0-9A-Za-z._-]{0,127}$/;
23
+ const SAFE_RUNTIME_DIRECTORY = /^[0-9A-Za-z][0-9A-Za-z._-]{0,127}-[0-9a-f]{64}$/;
24
+ const HISTORICAL_RUNTIME_GRACE_MS = 24 * 60 * 60 * 1000;
25
+
26
+ async function sha256File(file) {
27
+ const digest = createHash("sha256");
28
+ for await (const chunk of createReadStream(file)) {
29
+ digest.update(chunk);
30
+ }
31
+ return digest.digest("hex");
32
+ }
33
+
34
+ async function verifyMaterializedRuntime(file, expectedSha256, { allowMissing = false } = {}) {
35
+ try {
36
+ const metadata = await lstat(file);
37
+ if (!metadata.isFile() || metadata.isSymbolicLink() || metadata.size === 0) {
38
+ throw new Error("Mikie cached Windows runtime is invalid");
39
+ }
40
+ if ((await sha256File(file)) !== expectedSha256) {
41
+ throw new Error("Mikie cached Windows runtime hash does not match");
42
+ }
43
+ return true;
44
+ } catch (error) {
45
+ if (allowMissing && error?.code === "ENOENT") return false;
46
+ throw error;
47
+ }
48
+ }
49
+
50
+ async function cleanupHistoricalWindowsRuntimes(runtimeRoot, selectedDirectory) {
51
+ let entries;
52
+ try {
53
+ entries = await readdir(runtimeRoot, { withFileTypes: true });
54
+ } catch {
55
+ return;
56
+ }
57
+ const cutoff = Date.now() - HISTORICAL_RUNTIME_GRACE_MS;
58
+ await Promise.all(
59
+ entries.map(async (entry) => {
60
+ if (
61
+ !entry.isDirectory() ||
62
+ entry.name === selectedDirectory ||
63
+ !SAFE_RUNTIME_DIRECTORY.test(entry.name)
64
+ ) {
65
+ return;
66
+ }
67
+ const candidate = path.join(runtimeRoot, entry.name);
68
+ try {
69
+ if ((await lstat(candidate)).mtimeMs > cutoff) return;
70
+ await rm(candidate, { recursive: true, force: true, maxRetries: 0 });
71
+ } catch {
72
+ // Active Windows executables remain locked and are retried by a later launch.
73
+ }
74
+ }),
75
+ );
76
+ }
77
+
78
+ export function shouldStageWindowsRuntime(arguments_) {
79
+ if (arguments_.length === 0) return true;
80
+ if (["mcp", "serve", "run-relay"].includes(arguments_[0])) return true;
81
+ return arguments_[0] === "control" && arguments_[1] === "run";
82
+ }
83
+
84
+ export async function materializeWindowsRuntime(
85
+ binary,
86
+ { version, localAppData = process.env.LOCALAPPDATA } = {},
87
+ ) {
88
+ if (
89
+ !path.isAbsolute(binary) ||
90
+ !path.isAbsolute(localAppData ?? "") ||
91
+ !SAFE_RUNTIME_VERSION.test(version ?? "")
92
+ ) {
93
+ throw new Error("Mikie cached Windows runtime authority is invalid");
94
+ }
95
+ const sourceMetadata = await lstat(binary);
96
+ if (!sourceMetadata.isFile() || sourceMetadata.isSymbolicLink() || sourceMetadata.size === 0) {
97
+ throw new Error("Mikie native Windows runtime is invalid");
98
+ }
99
+ const sourceSha256 = await sha256File(binary);
100
+ const runtimeRoot = path.join(localAppData, "Mikie", "runtime-v1");
101
+ const selectedDirectory = `${version}-${sourceSha256}`;
102
+ const runtimeDirectory = path.join(runtimeRoot, selectedDirectory);
103
+ const materialized = path.join(runtimeDirectory, "mikie.exe");
104
+ await mkdir(runtimeDirectory, { recursive: true });
105
+ if (await verifyMaterializedRuntime(materialized, sourceSha256, { allowMissing: true })) {
106
+ await cleanupHistoricalWindowsRuntimes(runtimeRoot, selectedDirectory);
107
+ return materialized;
108
+ }
109
+
110
+ const temporary = path.join(
111
+ runtimeDirectory,
112
+ `.mikie-${process.pid}-${randomUUID()}.tmp`,
113
+ );
114
+ try {
115
+ await copyFile(binary, temporary, fsConstants.COPYFILE_EXCL);
116
+ const [copiedSha256, stableSourceSha256] = await Promise.all([
117
+ sha256File(temporary),
118
+ sha256File(binary),
119
+ ]);
120
+ if (copiedSha256 !== sourceSha256 || stableSourceSha256 !== sourceSha256) {
121
+ throw new Error("Mikie native Windows runtime changed during materialization");
122
+ }
123
+ try {
124
+ await rename(temporary, materialized);
125
+ } catch (error) {
126
+ if (
127
+ !["EEXIST", "EPERM"].includes(error?.code) ||
128
+ !(await verifyMaterializedRuntime(materialized, sourceSha256, { allowMissing: true }))
129
+ ) {
130
+ throw error;
131
+ }
132
+ }
133
+ await verifyMaterializedRuntime(materialized, sourceSha256);
134
+ await cleanupHistoricalWindowsRuntimes(runtimeRoot, selectedDirectory);
135
+ return materialized;
136
+ } finally {
137
+ await rm(temporary, { force: true }).catch(() => {});
138
+ }
139
+ }
140
+
141
+ export async function prepareNativeLaunch(
142
+ binary,
143
+ arguments_,
144
+ {
145
+ platform = process.platform,
146
+ version,
147
+ environment = process.env,
148
+ } = {},
149
+ ) {
150
+ if (platform !== "win32" || !shouldStageWindowsRuntime(arguments_)) {
151
+ return binary;
152
+ }
153
+ return materializeWindowsRuntime(binary, {
154
+ version,
155
+ localAppData: environment.LOCALAPPDATA,
156
+ });
157
+ }
21
158
 
22
159
  function currentRuntimeUsesGlibc() {
23
160
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getmikie/cli",
3
- "version": "1.1.87",
3
+ "version": "1.1.89",
4
4
  "description": "Native Mikie relay launcher for MCP clients",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -20,10 +20,10 @@
20
20
  "node": ">=22"
21
21
  },
22
22
  "optionalDependencies": {
23
- "@getmikie/darwin-arm64": "1.1.87",
24
- "@getmikie/darwin-x64": "1.1.87",
25
- "@getmikie/linux-x64-gnu": "1.1.87",
26
- "@getmikie/win32-x64": "1.1.87"
23
+ "@getmikie/darwin-arm64": "1.1.89",
24
+ "@getmikie/darwin-x64": "1.1.89",
25
+ "@getmikie/linux-x64-gnu": "1.1.89",
26
+ "@getmikie/win32-x64": "1.1.89"
27
27
  },
28
28
  "publishConfig": {
29
29
  "access": "public",