@mytegroupinc/myte-core 0.0.40 → 0.0.42
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/mytecody-cli.js +297 -10
- package/package.json +1 -1
package/mytecody-cli.js
CHANGED
|
@@ -168,6 +168,10 @@ function currentBridgePath() {
|
|
|
168
168
|
return path.join(currentInstallRoot(), "lib", "mytecody-async-responses-bridge.js");
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
+
function currentControllerPath() {
|
|
172
|
+
return path.join(currentInstallRoot(), "lib", "mytecody-controller.js");
|
|
173
|
+
}
|
|
174
|
+
|
|
171
175
|
function codexHome() {
|
|
172
176
|
return path.join(installRoot(), "engine-home");
|
|
173
177
|
}
|
|
@@ -193,7 +197,12 @@ function installedClientCommand() {
|
|
|
193
197
|
}
|
|
194
198
|
|
|
195
199
|
function installedClientUsable() {
|
|
196
|
-
return Boolean(
|
|
200
|
+
return Boolean(
|
|
201
|
+
installedClientCommand() &&
|
|
202
|
+
fs.existsSync(currentBridgePath()) &&
|
|
203
|
+
fs.existsSync(currentControllerPath()) &&
|
|
204
|
+
readCurrentClientManifest(),
|
|
205
|
+
);
|
|
197
206
|
}
|
|
198
207
|
|
|
199
208
|
function loadSignedBridge() {
|
|
@@ -208,6 +217,18 @@ function loadSignedBridge() {
|
|
|
208
217
|
return bridge;
|
|
209
218
|
}
|
|
210
219
|
|
|
220
|
+
function loadSignedController() {
|
|
221
|
+
const controllerPath = currentControllerPath();
|
|
222
|
+
if (!fs.existsSync(controllerPath)) {
|
|
223
|
+
throw new Error("signed MyteCody controller asset is missing; run `mytecody update`.");
|
|
224
|
+
}
|
|
225
|
+
const controller = require(controllerPath);
|
|
226
|
+
if (!controller || typeof controller.runMyteCodyController !== "function") {
|
|
227
|
+
throw new Error("signed MyteCody controller asset is invalid.");
|
|
228
|
+
}
|
|
229
|
+
return controller;
|
|
230
|
+
}
|
|
231
|
+
|
|
211
232
|
function releaseAssetsForPlatform(manifest, artifact) {
|
|
212
233
|
const assets = [];
|
|
213
234
|
const collect = (value, source) => {
|
|
@@ -373,9 +394,11 @@ function commonStatus(args, envPath) {
|
|
|
373
394
|
install_root: installRoot(),
|
|
374
395
|
engine_path: currentEnginePath(),
|
|
375
396
|
bridge_path: currentBridgePath(),
|
|
397
|
+
controller_path: currentControllerPath(),
|
|
376
398
|
client_manifest: currentClientManifestPath(),
|
|
377
399
|
client_installed: Boolean(current && installedClientCommand()),
|
|
378
400
|
bridge_installed: fs.existsSync(currentBridgePath()),
|
|
401
|
+
controller_installed: fs.existsSync(currentControllerPath()),
|
|
379
402
|
client_version: current && current.version ? current.version : null,
|
|
380
403
|
},
|
|
381
404
|
};
|
|
@@ -724,6 +747,63 @@ function installArtifactBytes(bytes, manifest, artifact) {
|
|
|
724
747
|
return installedManifest;
|
|
725
748
|
}
|
|
726
749
|
|
|
750
|
+
function reusableInstalledArtifact(artifact) {
|
|
751
|
+
const enginePath = currentEnginePath();
|
|
752
|
+
const current = readCurrentClientManifest();
|
|
753
|
+
if (!current || !fs.existsSync(enginePath)) return null;
|
|
754
|
+
|
|
755
|
+
const currentArtifact = current.artifact || {};
|
|
756
|
+
if (artifact && artifact.sha256) {
|
|
757
|
+
if (String(currentArtifact.sha256 || "").toLowerCase() !== String(artifact.sha256 || "").toLowerCase()) {
|
|
758
|
+
return null;
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
const engineBytes = fs.readFileSync(enginePath);
|
|
763
|
+
const installedSha = sha256Hex(engineBytes);
|
|
764
|
+
const expectedInstalledSha =
|
|
765
|
+
artifact && (artifact.installed_sha256 || artifact.executable_sha256 || artifact.uncompressed_sha256);
|
|
766
|
+
if (expectedInstalledSha && installedSha.toLowerCase() !== String(expectedInstalledSha).toLowerCase()) {
|
|
767
|
+
return null;
|
|
768
|
+
}
|
|
769
|
+
if (
|
|
770
|
+
currentArtifact.installed_sha256 &&
|
|
771
|
+
installedSha.toLowerCase() !== String(currentArtifact.installed_sha256).toLowerCase()
|
|
772
|
+
) {
|
|
773
|
+
return null;
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
return {
|
|
777
|
+
enginePath,
|
|
778
|
+
engineBytes,
|
|
779
|
+
artifactSizeBytes: Number(currentArtifact.size_bytes || artifact?.size_bytes || 0),
|
|
780
|
+
installedSha,
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
function installManifestForReusableArtifact(reusable, manifest, artifact) {
|
|
785
|
+
const installedManifest = {
|
|
786
|
+
schema_version: manifest.schema_version || 1,
|
|
787
|
+
channel: manifest.channel || DEFAULT_CHANNEL,
|
|
788
|
+
version: manifest.version || "unknown",
|
|
789
|
+
installed_at: new Date().toISOString(),
|
|
790
|
+
launcher_version: PACKAGE_VERSION,
|
|
791
|
+
platform: platformKey(),
|
|
792
|
+
executable: reusable.enginePath,
|
|
793
|
+
artifact: {
|
|
794
|
+
url: artifact.url,
|
|
795
|
+
sha256: artifact.sha256,
|
|
796
|
+
format: artifactFormat(artifact),
|
|
797
|
+
size_bytes: reusable.artifactSizeBytes,
|
|
798
|
+
installed_sha256: reusable.installedSha,
|
|
799
|
+
installed_size_bytes: reusable.engineBytes.length,
|
|
800
|
+
},
|
|
801
|
+
};
|
|
802
|
+
fs.mkdirSync(path.dirname(currentClientManifestPath()), { recursive: true });
|
|
803
|
+
fs.writeFileSync(currentClientManifestPath(), JSON.stringify(installedManifest, null, 2), "utf8");
|
|
804
|
+
return installedManifest;
|
|
805
|
+
}
|
|
806
|
+
|
|
727
807
|
async function installReleaseAssets(manifest, artifact, { progress } = {}) {
|
|
728
808
|
const assets = releaseAssetsForPlatform(manifest, artifact);
|
|
729
809
|
const installed = [];
|
|
@@ -1005,6 +1085,157 @@ function codexLaunchArgs(rawArgs, args = {}, providerBaseUrl = codyInferenceBase
|
|
|
1005
1085
|
return [...providerArgs, ...rawArgs];
|
|
1006
1086
|
}
|
|
1007
1087
|
|
|
1088
|
+
function execArgsAndStdin(rawArgs) {
|
|
1089
|
+
if (!rawArgs.length) return { args: [], stdin: null };
|
|
1090
|
+
const valueOptions = new Set([
|
|
1091
|
+
"-a",
|
|
1092
|
+
"--ask-for-approval",
|
|
1093
|
+
"-C",
|
|
1094
|
+
"--cd",
|
|
1095
|
+
"-c",
|
|
1096
|
+
"--config",
|
|
1097
|
+
"-i",
|
|
1098
|
+
"--image",
|
|
1099
|
+
"-m",
|
|
1100
|
+
"--model",
|
|
1101
|
+
"-o",
|
|
1102
|
+
"--output-last-message",
|
|
1103
|
+
"-p",
|
|
1104
|
+
"--profile",
|
|
1105
|
+
"-s",
|
|
1106
|
+
"--sandbox",
|
|
1107
|
+
"--color",
|
|
1108
|
+
"--local-provider",
|
|
1109
|
+
"--output-schema",
|
|
1110
|
+
]);
|
|
1111
|
+
const forwarded = [];
|
|
1112
|
+
let index = 0;
|
|
1113
|
+
while (index < rawArgs.length) {
|
|
1114
|
+
const arg = rawArgs[index];
|
|
1115
|
+
if (arg === "--") {
|
|
1116
|
+
index += 1;
|
|
1117
|
+
break;
|
|
1118
|
+
}
|
|
1119
|
+
if (arg === "-") break;
|
|
1120
|
+
if (!arg.startsWith("-")) break;
|
|
1121
|
+
forwarded.push(arg);
|
|
1122
|
+
index += 1;
|
|
1123
|
+
if (valueOptions.has(arg) && index < rawArgs.length) {
|
|
1124
|
+
forwarded.push(rawArgs[index]);
|
|
1125
|
+
index += 1;
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
const promptParts = rawArgs.slice(index);
|
|
1129
|
+
if (!promptParts.length) return { args: forwarded, stdin: null };
|
|
1130
|
+
if (promptParts.length === 1 && promptParts[0] === "-") {
|
|
1131
|
+
return { args: [...forwarded, "-"], stdin: fs.readFileSync(0, "utf8") };
|
|
1132
|
+
}
|
|
1133
|
+
const prompt = promptParts.join(" ");
|
|
1134
|
+
if (prompt.includes("\n") || prompt.includes("\r") || promptParts.length > 1) {
|
|
1135
|
+
return { args: [...forwarded, "-"], stdin: prompt };
|
|
1136
|
+
}
|
|
1137
|
+
return { args: [...forwarded, prompt], stdin: null };
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
function stripControllerArgs(rawArgs) {
|
|
1141
|
+
const kept = [];
|
|
1142
|
+
let enabled = process.env.MYTE_CODY_CONTROLLER !== "0";
|
|
1143
|
+
for (let i = 0; i < rawArgs.length; i += 1) {
|
|
1144
|
+
const arg = rawArgs[i];
|
|
1145
|
+
if (arg === "--controller") {
|
|
1146
|
+
const next = rawArgs[i + 1];
|
|
1147
|
+
if (next !== undefined && !next.startsWith("-")) {
|
|
1148
|
+
enabled = !["0", "false", "off", "raw"].includes(String(next).toLowerCase());
|
|
1149
|
+
i += 1;
|
|
1150
|
+
} else {
|
|
1151
|
+
enabled = true;
|
|
1152
|
+
}
|
|
1153
|
+
continue;
|
|
1154
|
+
}
|
|
1155
|
+
if (arg.startsWith("--controller=")) {
|
|
1156
|
+
const value = arg.slice("--controller=".length);
|
|
1157
|
+
enabled = !["0", "false", "off", "raw"].includes(String(value).toLowerCase());
|
|
1158
|
+
continue;
|
|
1159
|
+
}
|
|
1160
|
+
if (arg === "--no-controller") {
|
|
1161
|
+
enabled = false;
|
|
1162
|
+
continue;
|
|
1163
|
+
}
|
|
1164
|
+
kept.push(arg);
|
|
1165
|
+
}
|
|
1166
|
+
return { enabled, args: kept };
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
function controllerPromptFromExecArgs(rawArgs) {
|
|
1170
|
+
const execInput = execArgsAndStdin(rawArgs);
|
|
1171
|
+
if (execInput.stdin != null) return { prompt: execInput.stdin, forwardedArgs: [] };
|
|
1172
|
+
const prompt = execInput.args.length ? execInput.args[execInput.args.length - 1] : "";
|
|
1173
|
+
if (!prompt || prompt.startsWith("-")) {
|
|
1174
|
+
return { prompt: "", forwardedArgs: execInput.args };
|
|
1175
|
+
}
|
|
1176
|
+
return { prompt, forwardedArgs: execInput.args.slice(0, -1) };
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
function runEngineExecWorker({ command, args, providerBaseUrl, token, prompt, timeoutMs }) {
|
|
1180
|
+
return new Promise((resolve) => {
|
|
1181
|
+
const started = Date.now();
|
|
1182
|
+
const env = {
|
|
1183
|
+
...process.env,
|
|
1184
|
+
CODEX_HOME: codexHome(),
|
|
1185
|
+
MYTE_CODY_AUTH_TOKEN: token,
|
|
1186
|
+
MYTE_CODY_BRAND: "1",
|
|
1187
|
+
MYTE_CODY_CONTROLLER: "0",
|
|
1188
|
+
MYTE_CODY_BRIDGE_BASE_URL: providerBaseUrl,
|
|
1189
|
+
};
|
|
1190
|
+
const launchArgs = [...command.args, ...codexLaunchArgs(["exec", "--json", "-"], args, providerBaseUrl)];
|
|
1191
|
+
const child = spawn(command.cmd, launchArgs, {
|
|
1192
|
+
cwd: process.cwd(),
|
|
1193
|
+
env,
|
|
1194
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
1195
|
+
shell: process.platform === "win32" && command.cmd === "codex",
|
|
1196
|
+
});
|
|
1197
|
+
let stdout = "";
|
|
1198
|
+
let stderr = "";
|
|
1199
|
+
let settled = false;
|
|
1200
|
+
const timer = setTimeout(() => {
|
|
1201
|
+
if (settled) return;
|
|
1202
|
+
try {
|
|
1203
|
+
child.kill();
|
|
1204
|
+
} catch {}
|
|
1205
|
+
}, timeoutMs || 180000);
|
|
1206
|
+
child.stdout.on("data", (chunk) => {
|
|
1207
|
+
stdout += chunk.toString();
|
|
1208
|
+
});
|
|
1209
|
+
child.stderr.on("data", (chunk) => {
|
|
1210
|
+
stderr += chunk.toString();
|
|
1211
|
+
});
|
|
1212
|
+
child.on("error", (error) => {
|
|
1213
|
+
settled = true;
|
|
1214
|
+
clearTimeout(timer);
|
|
1215
|
+
resolve({
|
|
1216
|
+
status: 1,
|
|
1217
|
+
stdout,
|
|
1218
|
+
stderr,
|
|
1219
|
+
error: error.message || String(error),
|
|
1220
|
+
durationMs: Date.now() - started,
|
|
1221
|
+
});
|
|
1222
|
+
});
|
|
1223
|
+
child.on("exit", (code, signal) => {
|
|
1224
|
+
settled = true;
|
|
1225
|
+
clearTimeout(timer);
|
|
1226
|
+
resolve({
|
|
1227
|
+
status: code == null ? 1 : code,
|
|
1228
|
+
signal: signal || null,
|
|
1229
|
+
stdout,
|
|
1230
|
+
stderr,
|
|
1231
|
+
error: null,
|
|
1232
|
+
durationMs: Date.now() - started,
|
|
1233
|
+
});
|
|
1234
|
+
});
|
|
1235
|
+
child.stdin.end(prompt);
|
|
1236
|
+
});
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1008
1239
|
async function runCodex(rawArgs, args = {}, envPath = null) {
|
|
1009
1240
|
const token = getAuthToken();
|
|
1010
1241
|
if (!token) {
|
|
@@ -1063,7 +1294,48 @@ async function runCodex(rawArgs, args = {}, envPath = null) {
|
|
|
1063
1294
|
return 1;
|
|
1064
1295
|
}
|
|
1065
1296
|
|
|
1066
|
-
const
|
|
1297
|
+
const normalizedRawArgs = rawArgs[0] === "exec" ? ["exec", ...stripControllerArgs(rawArgs.slice(1)).args] : rawArgs;
|
|
1298
|
+
const controllerState = rawArgs[0] === "exec" ? stripControllerArgs(rawArgs.slice(1)) : { enabled: false, args: [] };
|
|
1299
|
+
if (rawArgs[0] === "exec" && controllerState.enabled) {
|
|
1300
|
+
try {
|
|
1301
|
+
progress("opening MyteCody controller");
|
|
1302
|
+
const signedController = loadSignedController();
|
|
1303
|
+
const promptInfo = controllerPromptFromExecArgs(controllerState.args);
|
|
1304
|
+
if (!promptInfo.prompt.trim()) {
|
|
1305
|
+
await splash.stop();
|
|
1306
|
+
await bridge.close();
|
|
1307
|
+
console.error("MyteCody controller exec requires a prompt or stdin via exec -.");
|
|
1308
|
+
return 1;
|
|
1309
|
+
}
|
|
1310
|
+
await splash.stop();
|
|
1311
|
+
if (packageNotice) statusLine(packageNotice);
|
|
1312
|
+
const summary = await signedController.runMyteCodyController({
|
|
1313
|
+
prompt: promptInfo.prompt,
|
|
1314
|
+
workspace: process.cwd(),
|
|
1315
|
+
artifactRoot: path.join(installRoot(), "controller-runs"),
|
|
1316
|
+
runWorker: (workerPrompt, workerOptions = {}) =>
|
|
1317
|
+
runEngineExecWorker({
|
|
1318
|
+
command,
|
|
1319
|
+
args,
|
|
1320
|
+
providerBaseUrl: bridge.baseUrl,
|
|
1321
|
+
token,
|
|
1322
|
+
prompt: workerPrompt,
|
|
1323
|
+
timeoutMs: workerOptions.timeoutMs || 180000,
|
|
1324
|
+
}),
|
|
1325
|
+
});
|
|
1326
|
+
console.error(`[MYTE CODY] controller run: ${summary.artifact_dir}`);
|
|
1327
|
+
console.error(`[MYTE CODY] controller status: ${summary.status}`);
|
|
1328
|
+
await bridge.close();
|
|
1329
|
+
return summary.status === "pass" ? 0 : 1;
|
|
1330
|
+
} catch (error) {
|
|
1331
|
+
await splash.stop();
|
|
1332
|
+
await bridge.close();
|
|
1333
|
+
console.error(`MyteCody controller failed: ${error && error.message ? error.message : error}`);
|
|
1334
|
+
return 1;
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
const launchArgs = [...command.args, ...codexLaunchArgs(normalizedRawArgs, args, bridge.baseUrl)];
|
|
1067
1339
|
const env = {
|
|
1068
1340
|
...process.env,
|
|
1069
1341
|
CODEX_HOME: codexHome(),
|
|
@@ -1102,7 +1374,10 @@ async function runDoctor(args, envPath) {
|
|
|
1102
1374
|
payload.gateway.probe = await probeGateway(args);
|
|
1103
1375
|
}
|
|
1104
1376
|
payload.ready_for_coding =
|
|
1105
|
-
payload.auth.present &&
|
|
1377
|
+
payload.auth.present &&
|
|
1378
|
+
payload.release.client_installed &&
|
|
1379
|
+
payload.release.bridge_installed &&
|
|
1380
|
+
payload.release.controller_installed;
|
|
1106
1381
|
if (payload.gateway.probe) {
|
|
1107
1382
|
payload.ready_for_coding = Boolean(payload.ready_for_coding && payload.gateway.probe.ok);
|
|
1108
1383
|
}
|
|
@@ -1182,12 +1457,23 @@ async function buildUpdatePayload(args, envPath, { dryRun = false, progress = nu
|
|
|
1182
1457
|
if (!artifactMetadata.ok) {
|
|
1183
1458
|
throw new Error(`MyteCody release artifact metadata is ${artifactMetadata.status}.`);
|
|
1184
1459
|
}
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1460
|
+
let installed;
|
|
1461
|
+
let artifactDigest = String(artifact.sha256 || "");
|
|
1462
|
+
let artifactSizeBytes = Number(artifact.size_bytes || 0);
|
|
1463
|
+
const reusable = reusableInstalledArtifact(artifact);
|
|
1464
|
+
if (reusable) {
|
|
1465
|
+
if (progress) progress("reusing installed MyteCody engine");
|
|
1466
|
+
installed = installManifestForReusableArtifact(reusable, manifest, artifact);
|
|
1467
|
+
artifactSizeBytes = reusable.artifactSizeBytes;
|
|
1468
|
+
} else {
|
|
1469
|
+
const bytes = await readArtifactBytes(artifact, { progress });
|
|
1470
|
+
artifactDigest = sha256Hex(bytes);
|
|
1471
|
+
artifactSizeBytes = bytes.length;
|
|
1472
|
+
if (artifactDigest.toLowerCase() !== String(artifact.sha256 || "").toLowerCase()) {
|
|
1473
|
+
throw new Error(`Artifact SHA-256 mismatch: expected ${artifact.sha256}, got ${artifactDigest}`);
|
|
1474
|
+
}
|
|
1475
|
+
installed = installArtifactBytes(bytes, manifest, artifact);
|
|
1189
1476
|
}
|
|
1190
|
-
const installed = installArtifactBytes(bytes, manifest, artifact);
|
|
1191
1477
|
const installedAssets = await installReleaseAssets(manifest, artifact, { progress });
|
|
1192
1478
|
if (installedAssets.length) {
|
|
1193
1479
|
installed.assets = installedAssets;
|
|
@@ -1197,8 +1483,8 @@ async function buildUpdatePayload(args, envPath, { dryRun = false, progress = nu
|
|
|
1197
1483
|
ok: true,
|
|
1198
1484
|
version: installed.version,
|
|
1199
1485
|
executable: installed.executable,
|
|
1200
|
-
sha256:
|
|
1201
|
-
size_bytes:
|
|
1486
|
+
sha256: artifactDigest,
|
|
1487
|
+
size_bytes: artifactSizeBytes,
|
|
1202
1488
|
installed_sha256: installed.artifact.installed_sha256,
|
|
1203
1489
|
installed_size_bytes: installed.artifact.installed_size_bytes,
|
|
1204
1490
|
format: installed.artifact.format,
|
|
@@ -1356,6 +1642,7 @@ module.exports = {
|
|
|
1356
1642
|
codyInferenceBase,
|
|
1357
1643
|
codyGatewayUrl,
|
|
1358
1644
|
currentBridgePath,
|
|
1645
|
+
currentControllerPath,
|
|
1359
1646
|
currentClientManifestPath,
|
|
1360
1647
|
currentEnginePath,
|
|
1361
1648
|
ensureBrandedEngineInstalled,
|