@dexlyai/dexly 0.1.2 → 0.1.3

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.
Files changed (4) hide show
  1. package/README.md +4 -2
  2. package/dist/cli.js +611 -299
  3. package/dist/host.js +332 -110
  4. package/package.json +1 -1
package/dist/host.js CHANGED
@@ -117,33 +117,22 @@ var require_companion = __commonJS({
117
117
  });
118
118
 
119
119
  // src/host.ts
120
- var import_node_process4 = __toESM(require("node:process"));
120
+ var import_node_process5 = __toESM(require("node:process"));
121
121
 
122
122
  // src/host-runtime.ts
123
- var import_node_process3 = __toESM(require("node:process"));
123
+ var import_node_process4 = __toESM(require("node:process"));
124
124
 
125
125
  // src/codex-host.ts
126
- var import_node_process2 = __toESM(require("node:process"));
127
- var import_node_child_process2 = require("node:child_process");
126
+ var import_node_process3 = __toESM(require("node:process"));
128
127
  var import_node_readline = __toESM(require("node:readline"));
129
- var import_companion4 = __toESM(require_companion());
128
+ var import_companion5 = __toESM(require_companion());
130
129
 
131
130
  // src/constants.ts
132
- var import_node_os = __toESM(require("node:os"));
133
131
  var import_node_path = __toESM(require("node:path"));
134
132
  var import_companion = __toESM(require_companion());
135
- var DEXLY_COMPANION_VERSION = true ? "0.1.2" : packageJson.version;
133
+ var DEXLY_COMPANION_VERSION = true ? "0.1.3" : packageJson.version;
136
134
  var DEXLY_COMPANION_DESCRIPTION = "Dexly native bridge for Codex";
137
135
  var DEXLY_COMPANION_METADATA_FILE_NAME = "install-metadata.json";
138
- function defaultInstallRoot(homeDir = import_node_os.default.homedir()) {
139
- return import_node_path.default.join(homeDir, "Library", "Application Support", "Dexly", "companion");
140
- }
141
- function defaultChromeHostManifestDir(homeDir = import_node_os.default.homedir()) {
142
- return import_node_path.default.join(homeDir, "Library", "Application Support", "Google", "Chrome", "NativeMessagingHosts");
143
- }
144
- function defaultChromeAllowedOrigins() {
145
- return [...import_companion.DEXLY_FIXED_ALLOWED_ORIGINS];
146
- }
147
136
  function currentInstallPath(installRoot) {
148
137
  return import_node_path.default.join(installRoot, "current");
149
138
  }
@@ -153,11 +142,8 @@ function installMetadataPath(installRoot) {
153
142
  function installedHostScriptPath(installRoot) {
154
143
  return import_node_path.default.join(currentInstallPath(installRoot), "dist", "host.js");
155
144
  }
156
- function installedHostLauncherPath(installRoot) {
157
- return import_node_path.default.join(currentInstallPath(installRoot), "bin", "dexly-companion-host");
158
- }
159
- function installedHostManifestPath(manifestDir) {
160
- return import_node_path.default.join(manifestDir, `${import_companion.DEXLY_COMPANION_HOST_NAME}.json`);
145
+ function installedHostLauncherPath(installRoot, platform = process.platform) {
146
+ return import_node_path.default.join(currentInstallPath(installRoot), "bin", resolveLauncherFileName(platform));
161
147
  }
162
148
  function buildChromeHostManifest(hostPath, allowedOrigins) {
163
149
  return {
@@ -168,9 +154,12 @@ function buildChromeHostManifest(hostPath, allowedOrigins) {
168
154
  allowed_origins: allowedOrigins
169
155
  };
170
156
  }
157
+ function resolveLauncherFileName(platform) {
158
+ return platform === "win32" ? "dexly-companion-host.cmd" : "dexly-companion-host";
159
+ }
171
160
 
172
161
  // src/management.ts
173
- var import_companion3 = __toESM(require_companion());
162
+ var import_companion4 = __toESM(require_companion());
174
163
 
175
164
  // src/install-metadata.ts
176
165
  var import_promises = require("node:fs/promises");
@@ -233,14 +222,171 @@ async function saveInstallMetadata(installRoot, metadata) {
233
222
 
234
223
  // src/install.ts
235
224
  var import_promises2 = require("node:fs/promises");
236
- var import_node_path3 = __toESM(require("node:path"));
225
+ var import_node_path4 = __toESM(require("node:path"));
237
226
 
238
- // src/tooling.ts
227
+ // src/platform.ts
228
+ var import_node_os = __toESM(require("node:os"));
239
229
  var import_node_path2 = __toESM(require("node:path"));
240
230
  var import_node_process = __toESM(require("node:process"));
231
+ var import_companion3 = __toESM(require_companion());
232
+ function assertSupportedPlatform(platform = import_node_process.default.platform) {
233
+ switch (platform) {
234
+ case "darwin":
235
+ case "linux":
236
+ case "win32":
237
+ return platform;
238
+ default:
239
+ throw new Error(
240
+ `Dexly Companion currently supports macOS, Windows, and Linux only. Unsupported platform: ${platform}.`
241
+ );
242
+ }
243
+ }
244
+ function defaultChromeAllowedOrigins() {
245
+ return [...import_companion3.DEXLY_FIXED_ALLOWED_ORIGINS];
246
+ }
247
+ function defaultInstallRoot(options = {}) {
248
+ const platform = assertSupportedPlatform(options.platform);
249
+ const homeDir = options.homeDir ?? import_node_os.default.homedir();
250
+ const env = options.env ?? import_node_process.default.env;
251
+ switch (platform) {
252
+ case "darwin":
253
+ return import_node_path2.default.join(homeDir, "Library", "Application Support", "Dexly", "companion");
254
+ case "linux": {
255
+ const dataHome = env.XDG_DATA_HOME?.trim() || import_node_path2.default.join(homeDir, ".local", "share");
256
+ return import_node_path2.default.join(dataHome, "Dexly", "companion");
257
+ }
258
+ case "win32": {
259
+ const localAppData = env.LOCALAPPDATA?.trim() || import_node_path2.default.join(homeDir, "AppData", "Local");
260
+ return import_node_path2.default.join(localAppData, "Dexly", "companion");
261
+ }
262
+ }
263
+ }
264
+ function resolveChromeHostRegistration(options = {}) {
265
+ const platform = assertSupportedPlatform(options.platform);
266
+ const homeDir = options.homeDir ?? import_node_os.default.homedir();
267
+ const env = options.env ?? import_node_process.default.env;
268
+ const installRoot = options.installRoot ?? defaultInstallRoot({
269
+ platform,
270
+ homeDir,
271
+ env
272
+ });
273
+ const manifestPath = options.manifestDir ? import_node_path2.default.join(options.manifestDir, `${import_companion3.DEXLY_COMPANION_HOST_NAME}.json`) : defaultChromeManifestPath({
274
+ platform,
275
+ homeDir,
276
+ env,
277
+ installRoot
278
+ });
279
+ if (platform === "win32") {
280
+ return {
281
+ kind: "windows-registry",
282
+ manifestPath,
283
+ allowedOrigins: defaultChromeAllowedOrigins(),
284
+ registryKey: options.windowsRegistryKey ?? `HKCU\\Software\\Google\\Chrome\\NativeMessagingHosts\\${import_companion3.DEXLY_COMPANION_HOST_NAME}`
285
+ };
286
+ }
287
+ return {
288
+ kind: "manifest-file",
289
+ manifestPath,
290
+ allowedOrigins: defaultChromeAllowedOrigins(),
291
+ registryKey: null
292
+ };
293
+ }
294
+ function resolvePlatformLayout(options = {}) {
295
+ const platform = assertSupportedPlatform(options.platform);
296
+ const installRoot = options.installRoot ?? defaultInstallRoot(options);
297
+ return {
298
+ platform,
299
+ installRoot,
300
+ activationStrategy: platform === "win32" ? "copy" : "symlink",
301
+ launcherKind: platform === "win32" ? "windows-cmd" : "posix",
302
+ launcherFileName: platform === "win32" ? "dexly-companion-host.cmd" : "dexly-companion-host",
303
+ hostRegistration: resolveChromeHostRegistration({
304
+ ...options,
305
+ platform,
306
+ installRoot
307
+ })
308
+ };
309
+ }
310
+ function defaultLauncherPathEntries(platform = import_node_process.default.platform, env = import_node_process.default.env) {
311
+ switch (assertSupportedPlatform(platform)) {
312
+ case "darwin":
313
+ return ["/usr/local/bin", "/opt/homebrew/bin", "/usr/bin", "/bin", "/usr/sbin", "/sbin"];
314
+ case "linux":
315
+ return ["/usr/local/bin", "/usr/bin", "/bin", "/usr/sbin", "/sbin"];
316
+ case "win32": {
317
+ const systemRoot = env.SystemRoot?.trim() || "C:\\Windows";
318
+ return [import_node_path2.default.join(systemRoot, "System32"), systemRoot];
319
+ }
320
+ }
321
+ }
322
+ function renderHostLauncher(options) {
323
+ const platform = assertSupportedPlatform(options.platform);
324
+ const pathEntries = [
325
+ import_node_path2.default.dirname(options.nodePath),
326
+ options.codexPath ? import_node_path2.default.dirname(options.codexPath) : null,
327
+ ...defaultLauncherPathEntries(platform, options.env ?? import_node_process.default.env)
328
+ ].filter((entry, index, entries) => typeof entry === "string" && entries.indexOf(entry) === index);
329
+ if (platform === "win32") {
330
+ const lines2 = [
331
+ "@echo off",
332
+ "setlocal",
333
+ `set "PATH=${toBatchLiteral(pathEntries.join(import_node_path2.default.delimiter))};%PATH%"`,
334
+ options.codexPath ? `set "DEXLY_COMPANION_CODEX_PATH=${toBatchLiteral(options.codexPath)}"` : null,
335
+ `set "DEXLY_COMPANION_NODE_PATH=${toBatchLiteral(options.nodePath)}"`,
336
+ `set "DEXLY_COMPANION_HOST_SCRIPT=${toBatchLiteral(options.hostScriptPath)}"`,
337
+ '"%DEXLY_COMPANION_NODE_PATH%" "%DEXLY_COMPANION_HOST_SCRIPT%" %*'
338
+ ].filter((line) => typeof line === "string");
339
+ return `${lines2.join("\r\n")}\r
340
+ `;
341
+ }
342
+ const lines = [
343
+ "#!/bin/sh",
344
+ "set -eu",
345
+ `export PATH=${toShellLiteral(pathEntries.join(import_node_path2.default.delimiter))}`,
346
+ options.codexPath ? `export DEXLY_COMPANION_CODEX_PATH=${toShellLiteral(options.codexPath)}` : null,
347
+ `exec ${toShellLiteral(options.nodePath)} ${toShellLiteral(options.hostScriptPath)} "$@"`
348
+ ].filter((line) => typeof line === "string");
349
+ return `${lines.join("\n")}
350
+ `;
351
+ }
352
+ function defaultChromeManifestPath(options) {
353
+ switch (options.platform) {
354
+ case "darwin":
355
+ return import_node_path2.default.join(
356
+ options.homeDir,
357
+ "Library",
358
+ "Application Support",
359
+ "Google",
360
+ "Chrome",
361
+ "NativeMessagingHosts",
362
+ `${import_companion3.DEXLY_COMPANION_HOST_NAME}.json`
363
+ );
364
+ case "linux": {
365
+ const configHome = options.env.XDG_CONFIG_HOME?.trim() || import_node_path2.default.join(options.homeDir, ".config");
366
+ return import_node_path2.default.join(
367
+ configHome,
368
+ "google-chrome",
369
+ "NativeMessagingHosts",
370
+ `${import_companion3.DEXLY_COMPANION_HOST_NAME}.json`
371
+ );
372
+ }
373
+ case "win32":
374
+ return import_node_path2.default.join(options.installRoot, "native-host", `${import_companion3.DEXLY_COMPANION_HOST_NAME}.json`);
375
+ }
376
+ }
377
+ function toShellLiteral(value) {
378
+ return `'${value.replace(/'/g, `'"'"'`)}'`;
379
+ }
380
+ function toBatchLiteral(value) {
381
+ return value.replace(/%/g, "%%").replace(/"/g, '""');
382
+ }
383
+
384
+ // src/tooling.ts
385
+ var import_node_path3 = __toESM(require("node:path"));
386
+ var import_node_process2 = __toESM(require("node:process"));
241
387
  var import_node_child_process = require("node:child_process");
242
388
  function detectToolPaths() {
243
- const nodePath = import_node_process.default.execPath;
389
+ const nodePath = import_node_process2.default.execPath;
244
390
  const npmPath = resolveExecutablePath("npm") ?? "npm";
245
391
  const codexPath = resolveExecutablePath("codex");
246
392
  return {
@@ -249,40 +395,38 @@ function detectToolPaths() {
249
395
  codexPath
250
396
  };
251
397
  }
252
- function resolveExecutablePath(command, env = import_node_process.default.env) {
253
- const result = (0, import_node_child_process.spawnSync)("which", [command], {
398
+ function resolveExecutablePath(command, env = import_node_process2.default.env, platform = import_node_process2.default.platform) {
399
+ const lookupCommand = platform === "win32" ? "where" : "which";
400
+ const result = (0, import_node_child_process.spawnSync)(lookupCommand, [command], {
254
401
  encoding: "utf8",
255
402
  env
256
403
  });
257
- if (result.status !== 0) {
404
+ if (result.error || result.status !== 0) {
258
405
  return null;
259
406
  }
260
- const executablePath = result.stdout.trim();
261
- return executablePath.length > 0 ? executablePath : null;
407
+ const executablePath = result.stdout.split(/\r?\n/).map((value) => value.trim()).find((value) => value.length > 0);
408
+ return executablePath ?? null;
262
409
  }
263
- function buildToolEnv(toolPaths, extraPaths = []) {
410
+ function buildToolEnv(toolPaths, extraPaths = [], platform = import_node_process2.default.platform) {
411
+ const supportedPlatform = assertSupportedPlatform(platform);
412
+ const pathSeparator = supportedPlatform === "win32" ? ";" : ":";
264
413
  const pathEntries = [
265
- import_node_path2.default.dirname(toolPaths.nodePath),
266
- import_node_path2.default.dirname(toolPaths.npmPath),
267
- toolPaths.codexPath ? import_node_path2.default.dirname(toolPaths.codexPath) : null,
414
+ import_node_path3.default.dirname(toolPaths.nodePath),
415
+ import_node_path3.default.dirname(toolPaths.npmPath),
416
+ toolPaths.codexPath ? import_node_path3.default.dirname(toolPaths.codexPath) : null,
268
417
  ...extraPaths,
269
- "/usr/local/bin",
270
- "/opt/homebrew/bin",
271
- "/usr/bin",
272
- "/bin",
273
- "/usr/sbin",
274
- "/sbin",
275
- import_node_process.default.env.PATH ?? null
418
+ ...defaultLauncherPathEntries(supportedPlatform, import_node_process2.default.env),
419
+ import_node_process2.default.env.PATH ?? null
276
420
  ].filter((entry, index, entries) => typeof entry === "string" && entries.indexOf(entry) === index);
277
421
  return {
278
- ...import_node_process.default.env,
279
- PATH: pathEntries.join(":"),
422
+ ...import_node_process2.default.env,
423
+ PATH: pathEntries.join(pathSeparator),
280
424
  ...toolPaths.codexPath ? { DEXLY_COMPANION_CODEX_PATH: toolPaths.codexPath } : {}
281
425
  };
282
426
  }
283
427
  async function runCommand(command, args, options = {}) {
284
428
  return await new Promise((resolve, reject) => {
285
- const child = (0, import_node_child_process.spawn)(command, args, {
429
+ const child = spawnManaged(command, args, {
286
430
  cwd: options.cwd,
287
431
  env: options.env,
288
432
  stdio: "pipe"
@@ -310,8 +454,8 @@ async function runCommand(command, args, options = {}) {
310
454
  });
311
455
  });
312
456
  }
313
- function resolveCodexVersion(codexCommand = import_node_process.default.env.DEXLY_COMPANION_CODEX_PATH ?? "codex", env = import_node_process.default.env) {
314
- const result = (0, import_node_child_process.spawnSync)(codexCommand, ["--version"], {
457
+ function resolveCodexVersion(codexCommand = import_node_process2.default.env.DEXLY_COMPANION_CODEX_PATH ?? "codex", env = import_node_process2.default.env) {
458
+ const result = spawnManagedSync(codexCommand, ["--version"], {
315
459
  encoding: "utf8",
316
460
  env
317
461
  });
@@ -320,8 +464,8 @@ function resolveCodexVersion(codexCommand = import_node_process.default.env.DEXL
320
464
  }
321
465
  return result.stdout.trim() || null;
322
466
  }
323
- function resolveNpmGlobalBinDir(npmPath, env = import_node_process.default.env) {
324
- const result = (0, import_node_child_process.spawnSync)(npmPath, ["config", "get", "prefix"], {
467
+ function resolveNpmGlobalBinDir(npmPath, env = import_node_process2.default.env, platform = import_node_process2.default.platform) {
468
+ const result = spawnManagedSync(npmPath, ["config", "get", "prefix"], {
325
469
  encoding: "utf8",
326
470
  env
327
471
  });
@@ -329,76 +473,151 @@ function resolveNpmGlobalBinDir(npmPath, env = import_node_process.default.env)
329
473
  return null;
330
474
  }
331
475
  const prefix = result.stdout.trim();
332
- return prefix.length > 0 ? import_node_path2.default.join(prefix, "bin") : null;
476
+ if (prefix.length === 0) {
477
+ return null;
478
+ }
479
+ return npmGlobalBinDirFromPrefix(prefix, platform);
480
+ }
481
+ function spawnManaged(command, args, options = {}) {
482
+ const invocation = buildSpawnInvocation(command, args, options.env);
483
+ return (0, import_node_child_process.spawn)(invocation.command, invocation.args, {
484
+ ...options,
485
+ windowsVerbatimArguments: invocation.windowsVerbatimArguments
486
+ });
487
+ }
488
+ function spawnManagedSync(command, args, options = {}) {
489
+ const invocation = buildSpawnInvocation(command, args, options.env);
490
+ return (0, import_node_child_process.spawnSync)(invocation.command, invocation.args, {
491
+ ...options,
492
+ windowsVerbatimArguments: invocation.windowsVerbatimArguments
493
+ });
494
+ }
495
+ function buildSpawnInvocation(command, args, env = import_node_process2.default.env, platform = import_node_process2.default.platform) {
496
+ if (platform !== "win32" || !isWindowsCommandScript(command, platform)) {
497
+ return {
498
+ command,
499
+ args
500
+ };
501
+ }
502
+ return {
503
+ command: resolveWindowsCommandShell(env),
504
+ args: ["/d", "/s", "/c", quoteWindowsCommand([command, ...args])],
505
+ windowsVerbatimArguments: false
506
+ };
507
+ }
508
+ function isWindowsCommandScript(command, platform = import_node_process2.default.platform) {
509
+ if (platform !== "win32") {
510
+ return false;
511
+ }
512
+ const normalized = command.trim().toLowerCase();
513
+ return normalized.endsWith(".cmd") || normalized.endsWith(".bat");
514
+ }
515
+ function resolveWindowsCommandShell(env = import_node_process2.default.env) {
516
+ const comSpec = env.ComSpec?.trim();
517
+ if (comSpec) {
518
+ return comSpec;
519
+ }
520
+ const systemRoot = env.SystemRoot?.trim() || "C:\\Windows";
521
+ return import_node_path3.default.join(systemRoot, "System32", "cmd.exe");
522
+ }
523
+ function quoteWindowsCommand(parts) {
524
+ return parts.map(quoteWindowsArgument).join(" ");
525
+ }
526
+ function quoteWindowsArgument(value) {
527
+ if (value.length === 0) {
528
+ return '""';
529
+ }
530
+ if (!/[ \t"&()^<>|]/.test(value)) {
531
+ return value;
532
+ }
533
+ return `"${value.replace(/"/g, '""')}"`;
534
+ }
535
+ function npmGlobalBinDirFromPrefix(prefix, platform = import_node_process2.default.platform) {
536
+ return platform === "win32" ? prefix : import_node_path3.default.join(prefix, "bin");
333
537
  }
334
538
 
335
539
  // src/install.ts
336
- async function rewriteCurrentLauncher(installRoot, toolPaths) {
337
- const launcherPath = installedHostLauncherPath(installRoot);
338
- await (0, import_promises2.mkdir)(import_node_path3.default.dirname(launcherPath), { recursive: true });
540
+ async function rewriteCurrentLauncher(installRoot, toolPaths, options = {}) {
541
+ const layout = resolvePlatformLayout({
542
+ installRoot,
543
+ platform: options.platform
544
+ });
545
+ const launcherPath = installedHostLauncherPath(installRoot, layout.platform);
546
+ await (0, import_promises2.mkdir)(import_node_path4.default.dirname(launcherPath), { recursive: true });
339
547
  await (0, import_promises2.writeFile)(
340
548
  launcherPath,
341
549
  renderHostLauncher({
550
+ platform: layout.platform,
342
551
  nodePath: toolPaths.nodePath,
343
552
  hostScriptPath: installedHostScriptPath(installRoot),
344
553
  codexPath: toolPaths.codexPath
345
554
  }),
346
555
  "utf8"
347
556
  );
348
- await (0, import_promises2.chmod)(launcherPath, 493);
557
+ await chmodIfSupported(layout.platform, launcherPath);
349
558
  return launcherPath;
350
559
  }
351
- async function ensureChromeHostManifest(installRoot, manifestDir) {
352
- const manifestPath = installedHostManifestPath(manifestDir);
353
- await (0, import_promises2.mkdir)(manifestDir, { recursive: true });
560
+ async function ensureChromeHostRegistration(installRoot, options = {}) {
561
+ const layout = resolvePlatformLayout({
562
+ installRoot,
563
+ platform: options.platform,
564
+ manifestDir: options.manifestDir,
565
+ windowsRegistryKey: options.windowsRegistryKey
566
+ });
567
+ const manifestPath = layout.hostRegistration.manifestPath;
568
+ await (0, import_promises2.mkdir)(import_node_path4.default.dirname(manifestPath), { recursive: true });
354
569
  await (0, import_promises2.writeFile)(
355
570
  manifestPath,
356
- `${JSON.stringify(buildChromeHostManifest(installedHostLauncherPath(installRoot), defaultChromeAllowedOrigins()), null, 2)}
571
+ `${JSON.stringify(
572
+ buildChromeHostManifest(installedHostLauncherPath(installRoot, layout.platform), layout.hostRegistration.allowedOrigins),
573
+ null,
574
+ 2
575
+ )}
357
576
  `,
358
577
  "utf8"
359
578
  );
579
+ if (layout.hostRegistration.kind === "windows-registry" && layout.hostRegistration.registryKey) {
580
+ await (options.registryWriter ?? writeWindowsRegistryManifestPath)(
581
+ layout.hostRegistration.registryKey,
582
+ manifestPath
583
+ );
584
+ }
360
585
  return manifestPath;
361
586
  }
362
- function renderHostLauncher(options) {
363
- const pathEntries = [
364
- import_node_path3.default.dirname(options.nodePath),
365
- options.codexPath ? import_node_path3.default.dirname(options.codexPath) : null,
366
- "/usr/local/bin",
367
- "/opt/homebrew/bin",
368
- "/usr/bin",
369
- "/bin",
370
- "/usr/sbin",
371
- "/sbin"
372
- ].filter((entry, index, entries) => typeof entry === "string" && entries.indexOf(entry) === index);
373
- const lines = [
374
- "#!/bin/sh",
375
- "set -eu",
376
- `export PATH=${toShellLiteral(pathEntries.join(":"))}`,
377
- options.codexPath ? `export DEXLY_COMPANION_CODEX_PATH=${toShellLiteral(options.codexPath)}` : null,
378
- `exec ${toShellLiteral(options.nodePath)} ${toShellLiteral(options.hostScriptPath)} "$@"`
379
- ].filter((line) => typeof line === "string");
380
- return `${lines.join("\n")}
381
- `;
587
+ async function chmodIfSupported(platform, targetPath) {
588
+ if (platform === "win32") {
589
+ return;
590
+ }
591
+ await (0, import_promises2.chmod)(targetPath, 493);
382
592
  }
383
- function toShellLiteral(value) {
384
- return `'${value.replace(/'/g, `'"'"'`)}'`;
593
+ async function writeWindowsRegistryManifestPath(registryKey, manifestPath) {
594
+ await runCommand("reg.exe", [
595
+ "add",
596
+ registryKey,
597
+ "/ve",
598
+ "/t",
599
+ "REG_SZ",
600
+ "/d",
601
+ manifestPath,
602
+ "/f"
603
+ ]);
385
604
  }
386
605
 
387
606
  // src/management.ts
388
607
  async function upgradeInstalledCompanion(options) {
389
- const installRoot = options.installRoot ?? defaultInstallRoot();
608
+ const installRoot = options.installRoot ?? defaultInstallRoot({ platform: options.platform });
390
609
  const metadata = await loadInstallMetadata(installRoot);
391
610
  if (!metadata) {
392
611
  throw new Error("Dexly Companion install metadata is missing. Reinstall Dexly Companion first.");
393
612
  }
394
613
  const specifier = options.version?.trim() ? options.version.trim() : options.distTag.trim();
395
- const targetSpecifier = `${import_companion3.DEXLY_COMPANION_PACKAGE_NAME}@${specifier}`;
396
- const env = buildToolEnv(metadata.tools);
614
+ const targetSpecifier = `${import_companion4.DEXLY_COMPANION_PACKAGE_NAME}@${specifier}`;
615
+ const env = buildToolEnv(metadata.tools, [], options.platform);
397
616
  await runCommand(metadata.tools.npmPath, [
398
617
  "exec",
399
618
  "--yes",
400
619
  `--package=${targetSpecifier}`,
401
- import_companion3.DEXLY_COMPANION_EXECUTABLE_NAME,
620
+ import_companion4.DEXLY_COMPANION_EXECUTABLE_NAME,
402
621
  "install",
403
622
  "--channel",
404
623
  options.distTag
@@ -414,15 +633,14 @@ async function upgradeInstalledCompanion(options) {
414
633
  };
415
634
  }
416
635
  async function installCodexWithCompanion(options) {
417
- const installRoot = options?.installRoot ?? defaultInstallRoot();
418
- const manifestDir = options?.manifestDir ?? defaultChromeHostManifestDir();
636
+ const installRoot = options?.installRoot ?? defaultInstallRoot({ platform: options?.platform });
419
637
  const existingMetadata = await loadInstallMetadata(installRoot);
420
638
  const toolPaths = existingMetadata?.tools ?? detectToolPaths();
421
- const env = buildToolEnv(toolPaths);
639
+ const env = buildToolEnv(toolPaths, [], options?.platform);
422
640
  await runCommand(toolPaths.npmPath, ["install", "-g", "@openai/codex"], { env });
423
- const globalBinDir = resolveNpmGlobalBinDir(toolPaths.npmPath, env);
424
- const nextEnv = buildToolEnv(toolPaths, globalBinDir ? [globalBinDir] : []);
425
- const codexPath = resolveExecutablePath("codex", nextEnv);
641
+ const globalBinDir = resolveNpmGlobalBinDir(toolPaths.npmPath, env, options?.platform);
642
+ const nextEnv = buildToolEnv(toolPaths, globalBinDir ? [globalBinDir] : [], options?.platform);
643
+ const codexPath = resolveExecutablePath("codex", nextEnv, options?.platform);
426
644
  const codexVersion = resolveCodexVersion(codexPath ?? void 0, nextEnv);
427
645
  if (!codexPath || !codexVersion) {
428
646
  throw new Error("Codex install completed, but Dexly Companion could not resolve the installed codex binary.");
@@ -431,8 +649,12 @@ async function installCodexWithCompanion(options) {
431
649
  ...toolPaths,
432
650
  codexPath
433
651
  };
434
- await rewriteCurrentLauncher(installRoot, nextToolPaths);
435
- await ensureChromeHostManifest(installRoot, manifestDir);
652
+ await rewriteCurrentLauncher(installRoot, nextToolPaths, { platform: options?.platform });
653
+ await ensureChromeHostRegistration(installRoot, {
654
+ platform: options?.platform,
655
+ manifestDir: options?.manifestDir,
656
+ windowsRegistryKey: options?.windowsRegistryKey
657
+ });
436
658
  if (existingMetadata) {
437
659
  await saveInstallMetadata(installRoot, {
438
660
  ...existingMetadata,
@@ -443,7 +665,7 @@ async function installCodexWithCompanion(options) {
443
665
  return {
444
666
  codexPath,
445
667
  codexVersion,
446
- installCommand: import_companion3.DEXLY_CODEX_INSTALL_COMMAND
668
+ installCommand: import_companion4.DEXLY_CODEX_INSTALL_COMMAND
447
669
  };
448
670
  }
449
671
 
@@ -461,9 +683,9 @@ var DexlyNativeHost = class {
461
683
  stderrLines = [];
462
684
  constructor(options) {
463
685
  this.send = options.send;
464
- this.spawnProcess = options.spawnProcess ?? import_node_child_process2.spawn;
465
- this.spawnProcessSync = options.spawnProcessSync ?? import_node_child_process2.spawnSync;
466
- this.codexCommand = options.codexCommand ?? import_node_process2.default.env.DEXLY_COMPANION_CODEX_PATH ?? "codex";
686
+ this.spawnProcess = options.spawnProcess ?? ((command, args, spawnOptions) => spawnManaged(command, [...args], spawnOptions));
687
+ this.spawnProcessSync = options.spawnProcessSync ?? ((command, args, spawnOptions) => spawnManagedSync(command, [...args], spawnOptions));
688
+ this.codexCommand = options.codexCommand ?? import_node_process3.default.env.DEXLY_COMPANION_CODEX_PATH ?? "codex";
467
689
  this.requestProcessExit = options.requestProcessExit ?? null;
468
690
  }
469
691
  async handleMessage(message) {
@@ -723,7 +945,7 @@ var DexlyNativeHost = class {
723
945
  null,
724
946
  null,
725
947
  "codex_not_connected",
726
- `${import_companion4.DEXLY_COMPANION_DISPLAY_NAME} is not connected to Codex app-server.`
948
+ `${import_companion5.DEXLY_COMPANION_DISPLAY_NAME} is not connected to Codex app-server.`
727
949
  ));
728
950
  return;
729
951
  }
@@ -813,19 +1035,19 @@ function writeNativeMessage(output, message) {
813
1035
  // src/host-runtime.ts
814
1036
  async function runNativeHost() {
815
1037
  const host = new DexlyNativeHost({
816
- send: (message) => writeNativeMessage(import_node_process3.default.stdout, message),
1038
+ send: (message) => writeNativeMessage(import_node_process4.default.stdout, message),
817
1039
  requestProcessExit: () => {
818
- setTimeout(() => import_node_process3.default.exit(0), 25);
1040
+ setTimeout(() => import_node_process4.default.exit(0), 25);
819
1041
  }
820
1042
  });
821
- import_node_process3.default.stdout.on("error", (error) => {
1043
+ import_node_process4.default.stdout.on("error", (error) => {
822
1044
  if ("code" in error && error.code === "EPIPE") {
823
- void host.close().finally(() => import_node_process3.default.exit(0));
1045
+ void host.close().finally(() => import_node_process4.default.exit(0));
824
1046
  }
825
1047
  });
826
- const detachReader = createNativeMessageReader(import_node_process3.default.stdin, (message) => {
1048
+ const detachReader = createNativeMessageReader(import_node_process4.default.stdin, (message) => {
827
1049
  void host.handleMessage(message).catch((error) => {
828
- writeNativeMessage(import_node_process3.default.stdout, {
1050
+ writeNativeMessage(import_node_process4.default.stdout, {
829
1051
  kind: "host/error",
830
1052
  action: null,
831
1053
  requestId: null,
@@ -838,21 +1060,21 @@ async function runNativeHost() {
838
1060
  detachReader();
839
1061
  await host.close();
840
1062
  };
841
- import_node_process3.default.stdin.on("end", () => {
842
- void shutdown().finally(() => import_node_process3.default.exit(0));
1063
+ import_node_process4.default.stdin.on("end", () => {
1064
+ void shutdown().finally(() => import_node_process4.default.exit(0));
843
1065
  });
844
- import_node_process3.default.on("SIGINT", () => {
845
- void shutdown().finally(() => import_node_process3.default.exit(0));
1066
+ import_node_process4.default.on("SIGINT", () => {
1067
+ void shutdown().finally(() => import_node_process4.default.exit(0));
846
1068
  });
847
- import_node_process3.default.on("SIGTERM", () => {
848
- void shutdown().finally(() => import_node_process3.default.exit(0));
1069
+ import_node_process4.default.on("SIGTERM", () => {
1070
+ void shutdown().finally(() => import_node_process4.default.exit(0));
849
1071
  });
850
1072
  }
851
1073
 
852
1074
  // src/host.ts
853
1075
  void runNativeHost().catch((error) => {
854
1076
  const message = error instanceof Error ? error.message : "Dexly Companion host failed.";
855
- import_node_process4.default.stderr.write(`${message}
1077
+ import_node_process5.default.stderr.write(`${message}
856
1078
  `);
857
- import_node_process4.default.exit(1);
1079
+ import_node_process5.default.exit(1);
858
1080
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dexlyai/dexly",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "type": "commonjs",
5
5
  "bin": {
6
6
  "dexly": "dist/cli.js"