@mytegroupinc/myte-core 0.0.39 → 0.0.41

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
@@ -28,16 +28,17 @@ This package exists so the public wrapper can stay small and versioned cleanly.
28
28
  - Public package documentation is intentionally minimal. Internal rollout and design notes are not part of the npm package contract.
29
29
  - `mytecody` is a model-agnostic MyteCody team launcher. It supports `doctor`,
30
30
  `doctor --probe-gateway`, `update --dry-run`, and `update`. On first coding
31
- run, it installs the branded MyteCody engine from the Myte release manifest
32
- into a user-local Myte cache after signature/hash checks. Coding execution
33
- requires that engine, a reachable Myte AI Cody gateway, and `MYTEAI_API_KEY`.
31
+ run, it installs the branded MyteCody engine and signed client assets from
32
+ the Myte release manifest into a user-local Myte cache after signature/hash
33
+ checks. Coding execution requires those assets, a reachable Myte AI Cody
34
+ gateway, and `MYTEAI_API_KEY`.
34
35
  - `mytecody doctor` reports both the signed MyteCody engine state and this npm
35
36
  package version. `mytecody update` updates the engine only. Use
36
37
  `npm install -g myte@latest` to update the launcher and the Myte API CLI
37
38
  commands shipped by npm.
38
- - The package does not bundle the large MyteCody engine binary. See
39
- `THIRD_PARTY_NOTICES.md` and `TRADEMARKS.md` for Codex lineage and Myte brand
40
- notices.
39
+ - The package does not bundle the large MyteCody engine binary or the async
40
+ Responses bridge implementation. See `THIRD_PARTY_NOTICES.md` and
41
+ `TRADEMARKS.md` for Codex lineage and Myte brand notices.
41
42
 
42
43
  ## Agent Usage Contract
43
44
 
@@ -13,9 +13,9 @@ Source lineage tracked for this slice:
13
13
  - License: Apache-2.0
14
14
  - Upstream: https://github.com/openai/codex
15
15
 
16
- The MyteCody engine artifact is distributed separately from this npm package
17
- through a Myte release manifest. This package verifies the release artifact
18
- before installing it into the user's Myte-owned local cache.
16
+ The MyteCody engine and signed client assets are distributed separately from
17
+ this npm package through a Myte release manifest. This package verifies release
18
+ artifacts before installing them into the user's Myte-owned local cache.
19
19
 
20
20
  Myte names, marks, logos, terminal branding, and product design are not part of
21
21
  the OpenAI Codex project and remain Myte-owned brand assets.
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
  }
@@ -192,6 +196,15 @@ function installedClientCommand() {
192
196
  return { cmd: enginePath, args: [], source: "myte-installed-engine" };
193
197
  }
194
198
 
199
+ function installedClientUsable() {
200
+ return Boolean(
201
+ installedClientCommand() &&
202
+ fs.existsSync(currentBridgePath()) &&
203
+ fs.existsSync(currentControllerPath()) &&
204
+ readCurrentClientManifest(),
205
+ );
206
+ }
207
+
195
208
  function loadSignedBridge() {
196
209
  const bridgePath = currentBridgePath();
197
210
  if (!fs.existsSync(bridgePath)) {
@@ -204,6 +217,18 @@ function loadSignedBridge() {
204
217
  return bridge;
205
218
  }
206
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
+
207
232
  function releaseAssetsForPlatform(manifest, artifact) {
208
233
  const assets = [];
209
234
  const collect = (value, source) => {
@@ -369,9 +394,11 @@ function commonStatus(args, envPath) {
369
394
  install_root: installRoot(),
370
395
  engine_path: currentEnginePath(),
371
396
  bridge_path: currentBridgePath(),
397
+ controller_path: currentControllerPath(),
372
398
  client_manifest: currentClientManifestPath(),
373
399
  client_installed: Boolean(current && installedClientCommand()),
374
400
  bridge_installed: fs.existsSync(currentBridgePath()),
401
+ controller_installed: fs.existsSync(currentControllerPath()),
375
402
  client_version: current && current.version ? current.version : null,
376
403
  },
377
404
  };
@@ -1001,6 +1028,157 @@ function codexLaunchArgs(rawArgs, args = {}, providerBaseUrl = codyInferenceBase
1001
1028
  return [...providerArgs, ...rawArgs];
1002
1029
  }
1003
1030
 
1031
+ function execArgsAndStdin(rawArgs) {
1032
+ if (!rawArgs.length) return { args: [], stdin: null };
1033
+ const valueOptions = new Set([
1034
+ "-a",
1035
+ "--ask-for-approval",
1036
+ "-C",
1037
+ "--cd",
1038
+ "-c",
1039
+ "--config",
1040
+ "-i",
1041
+ "--image",
1042
+ "-m",
1043
+ "--model",
1044
+ "-o",
1045
+ "--output-last-message",
1046
+ "-p",
1047
+ "--profile",
1048
+ "-s",
1049
+ "--sandbox",
1050
+ "--color",
1051
+ "--local-provider",
1052
+ "--output-schema",
1053
+ ]);
1054
+ const forwarded = [];
1055
+ let index = 0;
1056
+ while (index < rawArgs.length) {
1057
+ const arg = rawArgs[index];
1058
+ if (arg === "--") {
1059
+ index += 1;
1060
+ break;
1061
+ }
1062
+ if (arg === "-") break;
1063
+ if (!arg.startsWith("-")) break;
1064
+ forwarded.push(arg);
1065
+ index += 1;
1066
+ if (valueOptions.has(arg) && index < rawArgs.length) {
1067
+ forwarded.push(rawArgs[index]);
1068
+ index += 1;
1069
+ }
1070
+ }
1071
+ const promptParts = rawArgs.slice(index);
1072
+ if (!promptParts.length) return { args: forwarded, stdin: null };
1073
+ if (promptParts.length === 1 && promptParts[0] === "-") {
1074
+ return { args: [...forwarded, "-"], stdin: fs.readFileSync(0, "utf8") };
1075
+ }
1076
+ const prompt = promptParts.join(" ");
1077
+ if (prompt.includes("\n") || prompt.includes("\r") || promptParts.length > 1) {
1078
+ return { args: [...forwarded, "-"], stdin: prompt };
1079
+ }
1080
+ return { args: [...forwarded, prompt], stdin: null };
1081
+ }
1082
+
1083
+ function stripControllerArgs(rawArgs) {
1084
+ const kept = [];
1085
+ let enabled = process.env.MYTE_CODY_CONTROLLER !== "0";
1086
+ for (let i = 0; i < rawArgs.length; i += 1) {
1087
+ const arg = rawArgs[i];
1088
+ if (arg === "--controller") {
1089
+ const next = rawArgs[i + 1];
1090
+ if (next !== undefined && !next.startsWith("-")) {
1091
+ enabled = !["0", "false", "off", "raw"].includes(String(next).toLowerCase());
1092
+ i += 1;
1093
+ } else {
1094
+ enabled = true;
1095
+ }
1096
+ continue;
1097
+ }
1098
+ if (arg.startsWith("--controller=")) {
1099
+ const value = arg.slice("--controller=".length);
1100
+ enabled = !["0", "false", "off", "raw"].includes(String(value).toLowerCase());
1101
+ continue;
1102
+ }
1103
+ if (arg === "--no-controller") {
1104
+ enabled = false;
1105
+ continue;
1106
+ }
1107
+ kept.push(arg);
1108
+ }
1109
+ return { enabled, args: kept };
1110
+ }
1111
+
1112
+ function controllerPromptFromExecArgs(rawArgs) {
1113
+ const execInput = execArgsAndStdin(rawArgs);
1114
+ if (execInput.stdin != null) return { prompt: execInput.stdin, forwardedArgs: [] };
1115
+ const prompt = execInput.args.length ? execInput.args[execInput.args.length - 1] : "";
1116
+ if (!prompt || prompt.startsWith("-")) {
1117
+ return { prompt: "", forwardedArgs: execInput.args };
1118
+ }
1119
+ return { prompt, forwardedArgs: execInput.args.slice(0, -1) };
1120
+ }
1121
+
1122
+ function runEngineExecWorker({ command, args, providerBaseUrl, token, prompt, timeoutMs }) {
1123
+ return new Promise((resolve) => {
1124
+ const started = Date.now();
1125
+ const env = {
1126
+ ...process.env,
1127
+ CODEX_HOME: codexHome(),
1128
+ MYTE_CODY_AUTH_TOKEN: token,
1129
+ MYTE_CODY_BRAND: "1",
1130
+ MYTE_CODY_CONTROLLER: "0",
1131
+ MYTE_CODY_BRIDGE_BASE_URL: providerBaseUrl,
1132
+ };
1133
+ const launchArgs = [...command.args, ...codexLaunchArgs(["exec", "--json", "-"], args, providerBaseUrl)];
1134
+ const child = spawn(command.cmd, launchArgs, {
1135
+ cwd: process.cwd(),
1136
+ env,
1137
+ stdio: ["pipe", "pipe", "pipe"],
1138
+ shell: process.platform === "win32" && command.cmd === "codex",
1139
+ });
1140
+ let stdout = "";
1141
+ let stderr = "";
1142
+ let settled = false;
1143
+ const timer = setTimeout(() => {
1144
+ if (settled) return;
1145
+ try {
1146
+ child.kill();
1147
+ } catch {}
1148
+ }, timeoutMs || 180000);
1149
+ child.stdout.on("data", (chunk) => {
1150
+ stdout += chunk.toString();
1151
+ });
1152
+ child.stderr.on("data", (chunk) => {
1153
+ stderr += chunk.toString();
1154
+ });
1155
+ child.on("error", (error) => {
1156
+ settled = true;
1157
+ clearTimeout(timer);
1158
+ resolve({
1159
+ status: 1,
1160
+ stdout,
1161
+ stderr,
1162
+ error: error.message || String(error),
1163
+ durationMs: Date.now() - started,
1164
+ });
1165
+ });
1166
+ child.on("exit", (code, signal) => {
1167
+ settled = true;
1168
+ clearTimeout(timer);
1169
+ resolve({
1170
+ status: code == null ? 1 : code,
1171
+ signal: signal || null,
1172
+ stdout,
1173
+ stderr,
1174
+ error: null,
1175
+ durationMs: Date.now() - started,
1176
+ });
1177
+ });
1178
+ child.stdin.end(prompt);
1179
+ });
1180
+ }
1181
+
1004
1182
  async function runCodex(rawArgs, args = {}, envPath = null) {
1005
1183
  const token = getAuthToken();
1006
1184
  if (!token) {
@@ -1059,7 +1237,48 @@ async function runCodex(rawArgs, args = {}, envPath = null) {
1059
1237
  return 1;
1060
1238
  }
1061
1239
 
1062
- const launchArgs = [...command.args, ...codexLaunchArgs(rawArgs, args, bridge.baseUrl)];
1240
+ const normalizedRawArgs = rawArgs[0] === "exec" ? ["exec", ...stripControllerArgs(rawArgs.slice(1)).args] : rawArgs;
1241
+ const controllerState = rawArgs[0] === "exec" ? stripControllerArgs(rawArgs.slice(1)) : { enabled: false, args: [] };
1242
+ if (rawArgs[0] === "exec" && controllerState.enabled) {
1243
+ try {
1244
+ progress("opening MyteCody controller");
1245
+ const signedController = loadSignedController();
1246
+ const promptInfo = controllerPromptFromExecArgs(controllerState.args);
1247
+ if (!promptInfo.prompt.trim()) {
1248
+ await splash.stop();
1249
+ await bridge.close();
1250
+ console.error("MyteCody controller exec requires a prompt or stdin via exec -.");
1251
+ return 1;
1252
+ }
1253
+ await splash.stop();
1254
+ if (packageNotice) statusLine(packageNotice);
1255
+ const summary = await signedController.runMyteCodyController({
1256
+ prompt: promptInfo.prompt,
1257
+ workspace: process.cwd(),
1258
+ artifactRoot: path.join(installRoot(), "controller-runs"),
1259
+ runWorker: (workerPrompt, workerOptions = {}) =>
1260
+ runEngineExecWorker({
1261
+ command,
1262
+ args,
1263
+ providerBaseUrl: bridge.baseUrl,
1264
+ token,
1265
+ prompt: workerPrompt,
1266
+ timeoutMs: workerOptions.timeoutMs || 180000,
1267
+ }),
1268
+ });
1269
+ console.error(`[MYTE CODY] controller run: ${summary.artifact_dir}`);
1270
+ console.error(`[MYTE CODY] controller status: ${summary.status}`);
1271
+ await bridge.close();
1272
+ return summary.status === "pass" ? 0 : 1;
1273
+ } catch (error) {
1274
+ await splash.stop();
1275
+ await bridge.close();
1276
+ console.error(`MyteCody controller failed: ${error && error.message ? error.message : error}`);
1277
+ return 1;
1278
+ }
1279
+ }
1280
+
1281
+ const launchArgs = [...command.args, ...codexLaunchArgs(normalizedRawArgs, args, bridge.baseUrl)];
1063
1282
  const env = {
1064
1283
  ...process.env,
1065
1284
  CODEX_HOME: codexHome(),
@@ -1098,7 +1317,10 @@ async function runDoctor(args, envPath) {
1098
1317
  payload.gateway.probe = await probeGateway(args);
1099
1318
  }
1100
1319
  payload.ready_for_coding =
1101
- payload.auth.present && payload.release.client_installed && payload.release.bridge_installed;
1320
+ payload.auth.present &&
1321
+ payload.release.client_installed &&
1322
+ payload.release.bridge_installed &&
1323
+ payload.release.controller_installed;
1102
1324
  if (payload.gateway.probe) {
1103
1325
  payload.ready_for_coding = Boolean(payload.ready_for_coding && payload.gateway.probe.ok);
1104
1326
  }
@@ -1226,9 +1448,31 @@ async function ensureBrandedEngineInstalled(args = {}, envPath = null, { progres
1226
1448
  delete updateArgs.json;
1227
1449
 
1228
1450
  const source = manifestUrl(updateArgs);
1229
- const manifestResult = await readManifest(source, { fetchManifest: true, progress });
1451
+ let manifestResult;
1452
+ try {
1453
+ manifestResult = await readManifest(source, { fetchManifest: true, progress });
1454
+ } catch (error) {
1455
+ if (isUrl(source) && installedClientUsable()) {
1456
+ return {
1457
+ ok: true,
1458
+ installed: false,
1459
+ reason: "cached-engine-manifest-unavailable",
1460
+ manifest_status: "fetch-failed",
1461
+ error: error && error.message ? error.message : String(error),
1462
+ };
1463
+ }
1464
+ throw error;
1465
+ }
1230
1466
  const manifest = manifestResult.manifest;
1231
1467
  if (!manifest) {
1468
+ if (isUrl(source) && installedClientUsable()) {
1469
+ return {
1470
+ ok: true,
1471
+ installed: false,
1472
+ reason: "cached-engine-manifest-unavailable",
1473
+ manifest_status: manifestResult.status,
1474
+ };
1475
+ }
1232
1476
  return { ok: false, installed: false, reason: "manifest-unavailable", manifest_status: manifestResult.status };
1233
1477
  }
1234
1478
  const signature = signatureAccepted(manifest, updateArgs);
@@ -1330,6 +1574,7 @@ module.exports = {
1330
1574
  codyInferenceBase,
1331
1575
  codyGatewayUrl,
1332
1576
  currentBridgePath,
1577
+ currentControllerPath,
1333
1578
  currentClientManifestPath,
1334
1579
  currentEnginePath,
1335
1580
  ensureBrandedEngineInstalled,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mytegroupinc/myte-core",
3
- "version": "0.0.39",
3
+ "version": "0.0.41",
4
4
  "description": "Myte CLI core implementation.",
5
5
  "type": "commonjs",
6
6
  "main": "cli.js",