@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 +15 -0
- package/bin/mikie.mjs +7 -2
- package/lib/launcher.mjs +139 -2
- package/package.json +5 -5
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
|
|
187
|
-
|
|
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 {
|
|
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.
|
|
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.
|
|
24
|
-
"@getmikie/darwin-x64": "1.1.
|
|
25
|
-
"@getmikie/linux-x64-gnu": "1.1.
|
|
26
|
-
"@getmikie/win32-x64": "1.1.
|
|
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",
|