@mytegroupinc/myte-core 0.0.37 → 0.0.39
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 +184 -19
- package/package.json +1 -1
package/mytecody-cli.js
CHANGED
|
@@ -151,13 +151,21 @@ function installRoot() {
|
|
|
151
151
|
return path.join(os.homedir(), ".myte", "cody");
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
+
function currentInstallRoot() {
|
|
155
|
+
return path.join(installRoot(), "current");
|
|
156
|
+
}
|
|
157
|
+
|
|
154
158
|
function currentClientManifestPath() {
|
|
155
|
-
return path.join(
|
|
159
|
+
return path.join(currentInstallRoot(), "manifest.json");
|
|
156
160
|
}
|
|
157
161
|
|
|
158
162
|
function currentEnginePath() {
|
|
159
163
|
const executable = process.platform === "win32" ? "mytecody-engine.exe" : "mytecody-engine";
|
|
160
|
-
return path.join(
|
|
164
|
+
return path.join(currentInstallRoot(), "bin", executable);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function currentBridgePath() {
|
|
168
|
+
return path.join(currentInstallRoot(), "lib", "mytecody-async-responses-bridge.js");
|
|
161
169
|
}
|
|
162
170
|
|
|
163
171
|
function codexHome() {
|
|
@@ -184,6 +192,96 @@ function installedClientCommand() {
|
|
|
184
192
|
return { cmd: enginePath, args: [], source: "myte-installed-engine" };
|
|
185
193
|
}
|
|
186
194
|
|
|
195
|
+
function loadSignedBridge() {
|
|
196
|
+
const bridgePath = currentBridgePath();
|
|
197
|
+
if (!fs.existsSync(bridgePath)) {
|
|
198
|
+
throw new Error("signed MyteCody inference bridge asset is missing; run `mytecody update`.");
|
|
199
|
+
}
|
|
200
|
+
const bridge = require(bridgePath);
|
|
201
|
+
if (!bridge || typeof bridge.startMyteCodyAsyncResponsesBridge !== "function") {
|
|
202
|
+
throw new Error("signed MyteCody inference bridge asset is invalid.");
|
|
203
|
+
}
|
|
204
|
+
return bridge;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function releaseAssetsForPlatform(manifest, artifact) {
|
|
208
|
+
const assets = [];
|
|
209
|
+
const collect = (value, source) => {
|
|
210
|
+
if (!value) return;
|
|
211
|
+
if (Array.isArray(value)) {
|
|
212
|
+
value.forEach((item, index) => {
|
|
213
|
+
if (item && typeof item === "object") {
|
|
214
|
+
assets.push({ ...item, source, index });
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
if (typeof value === "object") {
|
|
220
|
+
Object.entries(value).forEach(([name, item], index) => {
|
|
221
|
+
if (item && typeof item === "object") {
|
|
222
|
+
assets.push({ name: item.name || name, ...item, source, index });
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
collect(manifest && manifest.client_assets, "manifest.client_assets");
|
|
229
|
+
collect(artifact && artifact.assets, "artifact.assets");
|
|
230
|
+
|
|
231
|
+
return assets
|
|
232
|
+
.map((asset) => ({
|
|
233
|
+
...asset,
|
|
234
|
+
install_path: asset.install_path || asset.path || "",
|
|
235
|
+
}))
|
|
236
|
+
.filter((asset) => asset && asset.url && asset.sha256 && asset.install_path);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function assertSafeReleaseAssetInstallPath(installPath) {
|
|
240
|
+
const raw = String(installPath || "").replace(/\\/g, "/").trim();
|
|
241
|
+
if (!raw) throw new Error("release asset install_path is required");
|
|
242
|
+
if (path.isAbsolute(raw) || /^[A-Za-z]:/.test(raw)) {
|
|
243
|
+
throw new Error(`release asset install_path must be relative: ${installPath}`);
|
|
244
|
+
}
|
|
245
|
+
const parts = raw.split("/").filter(Boolean);
|
|
246
|
+
if (!parts.length || parts.includes("..")) {
|
|
247
|
+
throw new Error(`release asset install_path is unsafe: ${installPath}`);
|
|
248
|
+
}
|
|
249
|
+
return path.join(currentInstallRoot(), ...parts);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function currentReleaseAssetRecordByPath(current) {
|
|
253
|
+
const map = new Map();
|
|
254
|
+
for (const asset of Array.isArray(current && current.assets) ? current.assets : []) {
|
|
255
|
+
if (asset && asset.install_path) {
|
|
256
|
+
map.set(String(asset.install_path).replace(/\\/g, "/"), asset);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return map;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function installedReleaseAssetsMatchManifest(manifest, artifact) {
|
|
263
|
+
const assets = releaseAssetsForPlatform(manifest, artifact);
|
|
264
|
+
if (!assets.length) return true;
|
|
265
|
+
const current = readCurrentClientManifest();
|
|
266
|
+
const currentAssets = currentReleaseAssetRecordByPath(current);
|
|
267
|
+
|
|
268
|
+
for (const asset of assets) {
|
|
269
|
+
const installPath = String(asset.install_path || "").replace(/\\/g, "/");
|
|
270
|
+
const currentAsset = currentAssets.get(installPath);
|
|
271
|
+
if (!currentAsset) return false;
|
|
272
|
+
if (String(currentAsset.sha256 || "").toLowerCase() !== String(asset.sha256 || "").toLowerCase()) {
|
|
273
|
+
return false;
|
|
274
|
+
}
|
|
275
|
+
const targetPath = assertSafeReleaseAssetInstallPath(asset.install_path);
|
|
276
|
+
if (!fs.existsSync(targetPath)) return false;
|
|
277
|
+
const installedSha = sha256Hex(fs.readFileSync(targetPath));
|
|
278
|
+
if (installedSha.toLowerCase() !== String(asset.installed_sha256 || asset.sha256).toLowerCase()) {
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return true;
|
|
283
|
+
}
|
|
284
|
+
|
|
187
285
|
function installedClientMatchesManifest(manifest, artifact) {
|
|
188
286
|
const current = readCurrentClientManifest();
|
|
189
287
|
if (!current || !installedClientCommand()) return false;
|
|
@@ -204,6 +302,8 @@ function installedClientMatchesManifest(manifest, artifact) {
|
|
|
204
302
|
}
|
|
205
303
|
}
|
|
206
304
|
|
|
305
|
+
if (!installedReleaseAssetsMatchManifest(manifest, artifact)) return false;
|
|
306
|
+
|
|
207
307
|
return true;
|
|
208
308
|
}
|
|
209
309
|
|
|
@@ -249,6 +349,7 @@ function commonStatus(args, envPath) {
|
|
|
249
349
|
gateway: {
|
|
250
350
|
base_url: gatewayBase(args),
|
|
251
351
|
inference_base_url: codyInferenceBase(args),
|
|
352
|
+
responses_transport: "async-job-bridge",
|
|
252
353
|
network_required_for_coding: true,
|
|
253
354
|
},
|
|
254
355
|
instruction_pack: {
|
|
@@ -267,8 +368,10 @@ function commonStatus(args, envPath) {
|
|
|
267
368
|
platform: platformKey(),
|
|
268
369
|
install_root: installRoot(),
|
|
269
370
|
engine_path: currentEnginePath(),
|
|
371
|
+
bridge_path: currentBridgePath(),
|
|
270
372
|
client_manifest: currentClientManifestPath(),
|
|
271
373
|
client_installed: Boolean(current && installedClientCommand()),
|
|
374
|
+
bridge_installed: fs.existsSync(currentBridgePath()),
|
|
272
375
|
client_version: current && current.version ? current.version : null,
|
|
273
376
|
},
|
|
274
377
|
};
|
|
@@ -513,11 +616,11 @@ function localPathFromArtifactUrl(urlValue) {
|
|
|
513
616
|
return null;
|
|
514
617
|
}
|
|
515
618
|
|
|
516
|
-
async function readArtifactBytes(artifact, { progress } = {}) {
|
|
619
|
+
async function readArtifactBytes(artifact, { progress, label = "MyteCody engine" } = {}) {
|
|
517
620
|
const urlValue = artifact && artifact.url ? String(artifact.url) : "";
|
|
518
621
|
const localPath = localPathFromArtifactUrl(urlValue);
|
|
519
622
|
if (localPath) {
|
|
520
|
-
if (progress) progress(
|
|
623
|
+
if (progress) progress(`reading local ${label} artifact`);
|
|
521
624
|
return fs.readFileSync(localPath);
|
|
522
625
|
}
|
|
523
626
|
const headers = {};
|
|
@@ -525,7 +628,7 @@ async function readArtifactBytes(artifact, { progress } = {}) {
|
|
|
525
628
|
if (token) headers.Authorization = `Bearer ${token}`;
|
|
526
629
|
if (progress) {
|
|
527
630
|
const expectedSize = Number(artifact && artifact.size_bytes ? artifact.size_bytes : 0);
|
|
528
|
-
progress(`downloading
|
|
631
|
+
progress(`downloading ${label} (${formatBytes(expectedSize)})`);
|
|
529
632
|
}
|
|
530
633
|
const response = await fetch(urlValue, { method: "GET", headers });
|
|
531
634
|
if (!response.ok) {
|
|
@@ -534,7 +637,7 @@ async function readArtifactBytes(artifact, { progress } = {}) {
|
|
|
534
637
|
}
|
|
535
638
|
if (!response.body || typeof response.body.getReader !== "function") {
|
|
536
639
|
const bytes = Buffer.from(await response.arrayBuffer());
|
|
537
|
-
if (progress) progress(`downloaded
|
|
640
|
+
if (progress) progress(`downloaded ${label} (${formatBytes(bytes.length)})`);
|
|
538
641
|
return bytes;
|
|
539
642
|
}
|
|
540
643
|
|
|
@@ -552,13 +655,13 @@ async function readArtifactBytes(artifact, { progress } = {}) {
|
|
|
552
655
|
if (progress && total > 0) {
|
|
553
656
|
const pct = Math.min(100, Math.floor((received / total) * 100));
|
|
554
657
|
if (pct >= lastPct + 10 || pct === 100) {
|
|
555
|
-
progress(`downloading
|
|
658
|
+
progress(`downloading ${label} ${pct}% (${formatBytes(received)} / ${formatBytes(total)})`);
|
|
556
659
|
lastPct = pct;
|
|
557
660
|
}
|
|
558
661
|
}
|
|
559
662
|
}
|
|
560
663
|
const bytes = Buffer.concat(chunks);
|
|
561
|
-
if (progress) progress(`downloaded
|
|
664
|
+
if (progress) progress(`downloaded ${label} (${formatBytes(bytes.length)})`);
|
|
562
665
|
return bytes;
|
|
563
666
|
}
|
|
564
667
|
|
|
@@ -617,6 +720,34 @@ function installArtifactBytes(bytes, manifest, artifact) {
|
|
|
617
720
|
return installedManifest;
|
|
618
721
|
}
|
|
619
722
|
|
|
723
|
+
async function installReleaseAssets(manifest, artifact, { progress } = {}) {
|
|
724
|
+
const assets = releaseAssetsForPlatform(manifest, artifact);
|
|
725
|
+
const installed = [];
|
|
726
|
+
for (const asset of assets) {
|
|
727
|
+
const name = String(asset.name || path.basename(String(asset.install_path || "")) || "client asset");
|
|
728
|
+
const bytes = await readArtifactBytes(asset, { progress, label: `MyteCody ${name}` });
|
|
729
|
+
const digest = sha256Hex(bytes);
|
|
730
|
+
if (digest.toLowerCase() !== String(asset.sha256 || "").toLowerCase()) {
|
|
731
|
+
throw new Error(`Release asset SHA-256 mismatch for ${name}: expected ${asset.sha256}, got ${digest}`);
|
|
732
|
+
}
|
|
733
|
+
const installBytes = artifactBytesForInstall(bytes, asset);
|
|
734
|
+
const targetPath = assertSafeReleaseAssetInstallPath(asset.install_path);
|
|
735
|
+
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
|
|
736
|
+
fs.writeFileSync(targetPath, installBytes);
|
|
737
|
+
installed.push({
|
|
738
|
+
name,
|
|
739
|
+
install_path: String(asset.install_path || "").replace(/\\/g, "/"),
|
|
740
|
+
url: asset.url,
|
|
741
|
+
sha256: asset.sha256,
|
|
742
|
+
format: artifactFormat(asset),
|
|
743
|
+
size_bytes: bytes.length,
|
|
744
|
+
installed_sha256: sha256Hex(installBytes),
|
|
745
|
+
installed_size_bytes: installBytes.length,
|
|
746
|
+
});
|
|
747
|
+
}
|
|
748
|
+
return installed;
|
|
749
|
+
}
|
|
750
|
+
|
|
620
751
|
async function fetchJson(url, { headers = {}, timeoutMs = 8000 } = {}) {
|
|
621
752
|
const controller = typeof AbortController !== "undefined" ? new AbortController() : undefined;
|
|
622
753
|
const timeoutId =
|
|
@@ -765,7 +896,7 @@ function writeCodexModelCatalog() {
|
|
|
765
896
|
return catalogPath;
|
|
766
897
|
}
|
|
767
898
|
|
|
768
|
-
function writeCodexConfig(args = {}) {
|
|
899
|
+
function writeCodexConfig(args = {}, providerBaseUrl = codyInferenceBase(args)) {
|
|
769
900
|
fs.mkdirSync(codexHome(), { recursive: true });
|
|
770
901
|
const catalogPath = writeCodexModelCatalog();
|
|
771
902
|
const config = `model = ${tomlString(DEFAULT_MODEL_ALIAS)}
|
|
@@ -786,7 +917,7 @@ terminal_title = ["project"]
|
|
|
786
917
|
|
|
787
918
|
[model_providers.myte_ai]
|
|
788
919
|
name = "Myte AI"
|
|
789
|
-
base_url = ${tomlString(
|
|
920
|
+
base_url = ${tomlString(providerBaseUrl)}
|
|
790
921
|
env_key = "MYTE_CODY_AUTH_TOKEN"
|
|
791
922
|
wire_api = "responses"
|
|
792
923
|
requires_openai_auth = false
|
|
@@ -826,14 +957,14 @@ function resolveCodexCommand() {
|
|
|
826
957
|
return null;
|
|
827
958
|
}
|
|
828
959
|
|
|
829
|
-
function codexProviderArgs(args = {}) {
|
|
960
|
+
function codexProviderArgs(args = {}, providerBaseUrl = codyInferenceBase(args)) {
|
|
830
961
|
return [
|
|
831
962
|
"-c",
|
|
832
963
|
'model_provider="myte_ai"',
|
|
833
964
|
"-c",
|
|
834
965
|
'model_providers.myte_ai.name="Myte AI"',
|
|
835
966
|
"-c",
|
|
836
|
-
`model_providers.myte_ai.base_url="${
|
|
967
|
+
`model_providers.myte_ai.base_url="${providerBaseUrl}"`,
|
|
837
968
|
"-c",
|
|
838
969
|
'model_providers.myte_ai.env_key="MYTE_CODY_AUTH_TOKEN"',
|
|
839
970
|
"-c",
|
|
@@ -863,8 +994,8 @@ function codexProviderArgs(args = {}) {
|
|
|
863
994
|
];
|
|
864
995
|
}
|
|
865
996
|
|
|
866
|
-
function codexLaunchArgs(rawArgs, args = {}) {
|
|
867
|
-
const providerArgs = codexProviderArgs(args);
|
|
997
|
+
function codexLaunchArgs(rawArgs, args = {}, providerBaseUrl = codyInferenceBase(args)) {
|
|
998
|
+
const providerArgs = codexProviderArgs(args, providerBaseUrl);
|
|
868
999
|
if (!rawArgs.length) return providerArgs;
|
|
869
1000
|
if (rawArgs[0] === "exec") return [...providerArgs, "exec", "--skip-git-repo-check", ...rawArgs.slice(1)];
|
|
870
1001
|
return [...providerArgs, ...rawArgs];
|
|
@@ -880,7 +1011,6 @@ async function runCodex(rawArgs, args = {}, envPath = null) {
|
|
|
880
1011
|
const progress = setupProgress(splash);
|
|
881
1012
|
splash.start("preparing trusted workspace");
|
|
882
1013
|
progress("preparing trusted workspace");
|
|
883
|
-
writeCodexConfig(args);
|
|
884
1014
|
try {
|
|
885
1015
|
const install = await ensureBrandedEngineInstalled(args, envPath, { progress });
|
|
886
1016
|
if (install.ok && install.installed) {
|
|
@@ -914,12 +1044,28 @@ async function runCodex(rawArgs, args = {}, envPath = null) {
|
|
|
914
1044
|
console.error("Run `mytecody update` with access to the Myte release manifest.");
|
|
915
1045
|
return 1;
|
|
916
1046
|
}
|
|
917
|
-
|
|
1047
|
+
let bridge = null;
|
|
1048
|
+
try {
|
|
1049
|
+
progress("opening Myte inference bridge");
|
|
1050
|
+
const signedBridge = loadSignedBridge();
|
|
1051
|
+
bridge = await signedBridge.startMyteCodyAsyncResponsesBridge({
|
|
1052
|
+
gatewayRoot: gatewayRoot(args),
|
|
1053
|
+
token,
|
|
1054
|
+
});
|
|
1055
|
+
writeCodexConfig(args, bridge.baseUrl);
|
|
1056
|
+
} catch (error) {
|
|
1057
|
+
await splash.stop();
|
|
1058
|
+
console.error(`MyteCody inference bridge failed to start: ${error && error.message ? error.message : error}`);
|
|
1059
|
+
return 1;
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
const launchArgs = [...command.args, ...codexLaunchArgs(rawArgs, args, bridge.baseUrl)];
|
|
918
1063
|
const env = {
|
|
919
1064
|
...process.env,
|
|
920
1065
|
CODEX_HOME: codexHome(),
|
|
921
1066
|
MYTE_CODY_AUTH_TOKEN: token,
|
|
922
1067
|
MYTE_CODY_BRAND: "1",
|
|
1068
|
+
MYTE_CODY_BRIDGE_BASE_URL: bridge.baseUrl,
|
|
923
1069
|
};
|
|
924
1070
|
progress("opening MyteCody workspace");
|
|
925
1071
|
await splash.stop();
|
|
@@ -933,9 +1079,11 @@ async function runCodex(rawArgs, args = {}, envPath = null) {
|
|
|
933
1079
|
});
|
|
934
1080
|
child.on("error", (error) => {
|
|
935
1081
|
console.error(`Unable to launch MyteCody engine: ${error.message || error}`);
|
|
936
|
-
resolve(1);
|
|
1082
|
+
bridge.close().finally(() => resolve(1));
|
|
1083
|
+
});
|
|
1084
|
+
child.on("close", (code) => {
|
|
1085
|
+
bridge.close().finally(() => resolve(Number.isInteger(code) ? code : 1));
|
|
937
1086
|
});
|
|
938
|
-
child.on("close", (code) => resolve(Number.isInteger(code) ? code : 1));
|
|
939
1087
|
});
|
|
940
1088
|
}
|
|
941
1089
|
|
|
@@ -949,7 +1097,8 @@ async function runDoctor(args, envPath) {
|
|
|
949
1097
|
if (args["probe-gateway"]) {
|
|
950
1098
|
payload.gateway.probe = await probeGateway(args);
|
|
951
1099
|
}
|
|
952
|
-
payload.ready_for_coding =
|
|
1100
|
+
payload.ready_for_coding =
|
|
1101
|
+
payload.auth.present && payload.release.client_installed && payload.release.bridge_installed;
|
|
953
1102
|
if (payload.gateway.probe) {
|
|
954
1103
|
payload.ready_for_coding = Boolean(payload.ready_for_coding && payload.gateway.probe.ok);
|
|
955
1104
|
}
|
|
@@ -978,6 +1127,7 @@ async function runDoctor(args, envPath) {
|
|
|
978
1127
|
console.log(`package update: ${payload.package.check_status}`);
|
|
979
1128
|
}
|
|
980
1129
|
console.log(`client: ${payload.release.client_installed ? payload.release.client_version : "not installed"}`);
|
|
1130
|
+
console.log(`bridge: ${payload.release.bridge_installed ? "installed" : "not installed"}`);
|
|
981
1131
|
console.log(`install: ${payload.release.install_root}`);
|
|
982
1132
|
console.log("");
|
|
983
1133
|
console.log("Coding requires the Myte AI gateway and a Myte AI key.");
|
|
@@ -995,6 +1145,7 @@ async function buildUpdatePayload(args, envPath, { dryRun = false, progress = nu
|
|
|
995
1145
|
const artifact = manifest ? artifactForPlatform(manifest) : null;
|
|
996
1146
|
const signature = manifest ? signatureAccepted(manifest, args) : { ok: false, signature: { status: "not-checked", verified: false } };
|
|
997
1147
|
const artifactMetadata = manifest ? validateArtifactMetadata(artifact) : { status: "not-checked", ok: false };
|
|
1148
|
+
const releaseAssets = manifest ? releaseAssetsForPlatform(manifest, artifact) : [];
|
|
998
1149
|
const payload = {
|
|
999
1150
|
ok: true,
|
|
1000
1151
|
dry_run: isDryRun,
|
|
@@ -1008,6 +1159,13 @@ async function buildUpdatePayload(args, envPath, { dryRun = false, progress = nu
|
|
|
1008
1159
|
trusted_unsigned: Boolean(signature.trusted_unsigned),
|
|
1009
1160
|
},
|
|
1010
1161
|
artifact: artifactMetadata,
|
|
1162
|
+
release_assets: releaseAssets.map((asset) => ({
|
|
1163
|
+
name: asset.name || null,
|
|
1164
|
+
install_path: asset.install_path,
|
|
1165
|
+
url: asset.url || null,
|
|
1166
|
+
format: asset.format || null,
|
|
1167
|
+
sha256_present: Boolean(asset.sha256),
|
|
1168
|
+
})),
|
|
1011
1169
|
};
|
|
1012
1170
|
|
|
1013
1171
|
if (!isDryRun) {
|
|
@@ -1026,6 +1184,11 @@ async function buildUpdatePayload(args, envPath, { dryRun = false, progress = nu
|
|
|
1026
1184
|
throw new Error(`Artifact SHA-256 mismatch: expected ${artifact.sha256}, got ${digest}`);
|
|
1027
1185
|
}
|
|
1028
1186
|
const installed = installArtifactBytes(bytes, manifest, artifact);
|
|
1187
|
+
const installedAssets = await installReleaseAssets(manifest, artifact, { progress });
|
|
1188
|
+
if (installedAssets.length) {
|
|
1189
|
+
installed.assets = installedAssets;
|
|
1190
|
+
fs.writeFileSync(currentClientManifestPath(), JSON.stringify(installed, null, 2), "utf8");
|
|
1191
|
+
}
|
|
1029
1192
|
payload.installed = {
|
|
1030
1193
|
ok: true,
|
|
1031
1194
|
version: installed.version,
|
|
@@ -1035,6 +1198,7 @@ async function buildUpdatePayload(args, envPath, { dryRun = false, progress = nu
|
|
|
1035
1198
|
installed_sha256: installed.artifact.installed_sha256,
|
|
1036
1199
|
installed_size_bytes: installed.artifact.installed_size_bytes,
|
|
1037
1200
|
format: installed.artifact.format,
|
|
1201
|
+
assets: installedAssets,
|
|
1038
1202
|
};
|
|
1039
1203
|
payload.release = {
|
|
1040
1204
|
...payload.release,
|
|
@@ -1165,6 +1329,7 @@ module.exports = {
|
|
|
1165
1329
|
codexProviderArgs,
|
|
1166
1330
|
codyInferenceBase,
|
|
1167
1331
|
codyGatewayUrl,
|
|
1332
|
+
currentBridgePath,
|
|
1168
1333
|
currentClientManifestPath,
|
|
1169
1334
|
currentEnginePath,
|
|
1170
1335
|
ensureBrandedEngineInstalled,
|