@ctxo/cli 0.9.1 → 0.9.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.
@@ -494,6 +494,39 @@ function detectFromLockfileWalkUp(startDir) {
494
494
  }
495
495
  return null;
496
496
  }
497
+ function readWorkspaceLinks(projectRoot) {
498
+ const links = /* @__PURE__ */ new Set();
499
+ const pkgPath = join3(projectRoot, "package.json");
500
+ if (!existsSync4(pkgPath)) return links;
501
+ try {
502
+ const pkg = JSON.parse(readFileSync3(pkgPath, "utf-8"));
503
+ for (const group of [pkg.dependencies, pkg.devDependencies, pkg.peerDependencies, pkg.optionalDependencies]) {
504
+ if (!group) continue;
505
+ for (const [name, spec] of Object.entries(group)) {
506
+ if (typeof spec === "string" && spec.startsWith("workspace:")) {
507
+ links.add(name);
508
+ }
509
+ }
510
+ }
511
+ return links;
512
+ } catch {
513
+ return links;
514
+ }
515
+ }
516
+ function isWorkspaceRoot(projectRoot) {
517
+ if (existsSync4(join3(projectRoot, "pnpm-workspace.yaml"))) return true;
518
+ const pkgPath = join3(projectRoot, "package.json");
519
+ if (!existsSync4(pkgPath)) return false;
520
+ try {
521
+ const pkg = JSON.parse(readFileSync3(pkgPath, "utf-8"));
522
+ const ws = pkg.workspaces;
523
+ if (Array.isArray(ws) && ws.length > 0) return true;
524
+ if (ws && typeof ws === "object" && Array.isArray(ws.packages)) return true;
525
+ return false;
526
+ } catch {
527
+ return false;
528
+ }
529
+ }
497
530
  function buildInstallCommand(manager, packages, options = {}) {
498
531
  if (packages.length === 0) {
499
532
  throw new Error("buildInstallCommand requires at least one package");
@@ -505,10 +538,13 @@ function buildInstallCommand(manager, packages, options = {}) {
505
538
  args: options.global ? ["install", "-g", ...packages] : ["install", "-D", ...packages]
506
539
  };
507
540
  case "pnpm":
508
- return {
509
- command: "pnpm",
510
- args: options.global ? ["add", "-g", ...packages] : ["add", "-D", ...packages]
511
- };
541
+ if (options.global) {
542
+ return { command: "pnpm", args: ["add", "-g", ...packages] };
543
+ }
544
+ if (options.workspaceRoot) {
545
+ return { command: "pnpm", args: ["add", "-D", "-w", ...packages] };
546
+ }
547
+ return { command: "pnpm", args: ["add", "-D", ...packages] };
512
548
  case "yarn":
513
549
  return {
514
550
  command: "yarn",
@@ -525,12 +561,18 @@ function buildInstallCommand(manager, packages, options = {}) {
525
561
  // src/core/install/run-package-manager.ts
526
562
  import { spawn } from "child_process";
527
563
  function runPackageManager(command, args, cwd) {
564
+ const resolved = resolveBinary(command);
528
565
  return new Promise((resolve4, reject) => {
529
- const child = spawn(command, [...args], { cwd, stdio: "inherit", shell: process.platform === "win32" });
566
+ const child = spawn(resolved, [...args], { cwd, stdio: "inherit", shell: false });
530
567
  child.on("exit", (code) => resolve4(code ?? 0));
531
568
  child.on("error", (err) => reject(err));
532
569
  });
533
570
  }
571
+ function resolveBinary(command) {
572
+ if (process.platform !== "win32") return command;
573
+ if (command === "bun") return "bun.exe";
574
+ return `${command}.cmd`;
575
+ }
534
576
 
535
577
  // src/cli/install-command.ts
536
578
  var InstallCommand = class {
@@ -570,7 +612,8 @@ var InstallCommand = class {
570
612
  (lang) => options.version ? `${officialPluginFor(lang)}@${options.version}` : officialPluginFor(lang)
571
613
  );
572
614
  const invocation = buildInstallCommand(resolution.manager, specifiers, {
573
- global: options.global
615
+ global: options.global,
616
+ workspaceRoot: !options.global && isWorkspaceRoot(this.projectRoot)
574
617
  });
575
618
  const plan = {
576
619
  languages: resolvedLangs,
@@ -3608,7 +3651,7 @@ var DoctorCommand = class {
3608
3651
  this.ctxoRoot = join22(projectRoot, ".ctxo");
3609
3652
  }
3610
3653
  async run(options = {}) {
3611
- const { getVersion: getVersion2 } = await import("./cli-router-T4ZG2G2Z.js");
3654
+ const { getVersion: getVersion2 } = await import("./cli-router-CQJ7CN6E.js");
3612
3655
  console.error(`ctxo v${getVersion2()} \u2014 health check
3613
3656
  `);
3614
3657
  const checks = [
@@ -4014,6 +4057,11 @@ function computePackageStates(installed, results) {
4014
4057
  function selectInstallTargets(states) {
4015
4058
  return states.filter((s) => s.status === "update" && typeof s.latest === "string").filter((s) => isSafeVersionSpecifier(s.latest)).map((s) => ({ name: s.name, version: s.latest }));
4016
4059
  }
4060
+ function markWorkspaceLinks(states, workspaceLinkNames) {
4061
+ return states.map(
4062
+ (s) => workspaceLinkNames.has(s.name) ? { ...s, status: "workspace", latest: null } : s
4063
+ );
4064
+ }
4017
4065
  var SAFE_SPECIFIER_RE = /^[0-9A-Za-z.+-]+$/;
4018
4066
  function isSafeVersionSpecifier(version) {
4019
4067
  return SAFE_SPECIFIER_RE.test(version);
@@ -4032,17 +4080,20 @@ function formatText(report) {
4032
4080
  lines.push(`All ${total} package${total === 1 ? "" : "s"} are up to date.`);
4033
4081
  return lines.join("\n");
4034
4082
  }
4083
+ const latestCell = (p) => {
4084
+ if (p.status === "workspace") return "(local)";
4085
+ return p.latest ?? "(not found)";
4086
+ };
4035
4087
  const nameCol = Math.max(7, ...report.packages.map((p) => p.name.length));
4036
4088
  const curCol = Math.max(7, ...report.packages.map((p) => p.current.length));
4037
- const latestCol = Math.max(15, ...report.packages.map((p) => (p.latest ?? "(not found)").length));
4089
+ const latestCol = Math.max(15, ...report.packages.map((p) => latestCell(p).length));
4038
4090
  lines.push(
4039
4091
  `${"PACKAGE".padEnd(nameCol)} ${"CURRENT".padEnd(curCol)} ${`LATEST (${report.channel})`.padEnd(latestCol)} STATUS`
4040
4092
  );
4041
4093
  for (const pkg of report.packages) {
4042
- const latestText = pkg.latest ?? "(not found)";
4043
4094
  const statusText = renderStatus(pkg, report.channel);
4044
4095
  lines.push(
4045
- `${pkg.name.padEnd(nameCol)} ${pkg.current.padEnd(curCol)} ${latestText.padEnd(latestCol)} ${statusText}`
4096
+ `${pkg.name.padEnd(nameCol)} ${pkg.current.padEnd(curCol)} ${latestCell(pkg).padEnd(latestCol)} ${statusText}`
4046
4097
  );
4047
4098
  }
4048
4099
  if (report.plan && report.strategy === "execute") {
@@ -4064,6 +4115,8 @@ function renderStatus(pkg, reportChannel) {
4064
4115
  return "up to date";
4065
4116
  case "ahead":
4066
4117
  return "ahead of registry";
4118
+ case "workspace":
4119
+ return "workspace link";
4067
4120
  case "unknown":
4068
4121
  return pkg.reason === "registry-404" ? "skipped" : `error${pkg.reason ? ` (${pkg.reason})` : ""}`;
4069
4122
  case "update":
@@ -4114,7 +4167,8 @@ var UpdateCommand = class {
4114
4167
  this.deps.setExitCode?.(1);
4115
4168
  return;
4116
4169
  }
4117
- const states = computePackageStates(installed, results);
4170
+ const rawStates = computePackageStates(installed, results);
4171
+ const states = markWorkspaceLinks(rawStates, readWorkspaceLinks(this.projectRoot));
4118
4172
  const targets = selectInstallTargets(states);
4119
4173
  const cliVersion = getVersion();
4120
4174
  const channel = detectChannel(cliVersion);
@@ -4158,7 +4212,10 @@ var UpdateCommand = class {
4158
4212
  });
4159
4213
  const specifiers = targets.map((t) => `${t.name}@${t.version}`);
4160
4214
  const useGlobal = options.global || !this.projectHasCtxoDep();
4161
- const invocation = buildInstallCommand(resolution.manager, specifiers, { global: useGlobal });
4215
+ const invocation = buildInstallCommand(resolution.manager, specifiers, {
4216
+ global: useGlobal,
4217
+ workspaceRoot: !useGlobal && isWorkspaceRoot(this.projectRoot)
4218
+ });
4162
4219
  return {
4163
4220
  manager: resolution.manager,
4164
4221
  managerSource: resolution.source,
@@ -4491,4 +4548,4 @@ export {
4491
4548
  getVersion,
4492
4549
  locateGitRoot
4493
4550
  };
4494
- //# sourceMappingURL=cli-router-T4ZG2G2Z.js.map
4551
+ //# sourceMappingURL=cli-router-CQJ7CN6E.js.map