@theholocron/cli 5.0.0-alpha.32 → 5.0.0-alpha.34

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/dist/cli.mjs CHANGED
@@ -6581,13 +6581,16 @@ async function runSync(input) {
6581
6581
  } else {
6582
6582
  const tasksConfig = { tasks: config.tasks };
6583
6583
  if (config.holocronScript !== void 0) tasksConfig.holocronScript = config.holocronScript;
6584
- const desired = createAstromech({
6584
+ const astromechScripts = createAstromech({
6585
6585
  cwd: input.context.repoRoot,
6586
6586
  config: tasksConfig,
6587
6587
  logger
6588
- }).packageScripts();
6588
+ });
6589
+ const desired = astromechScripts.packageScripts();
6590
+ const turboContent = astromechScripts.turboConfig();
6591
+ const turboEligible = new Set(turboContent ? Object.keys(JSON.parse(turboContent).tasks) : []);
6589
6592
  steps.push(await runSyncStep("local", "sync scripts", dryRun, async () => {
6590
- const changed = await mergePackageJsonScripts(input.context.repoRoot, desired);
6593
+ const changed = await mergePackageJsonScripts(input.context.repoRoot, desired, turboEligible);
6591
6594
  if (changed === null) return "no package.json";
6592
6595
  if (changed.length === 0) return `${Object.keys(desired).length} scripts already current`;
6593
6596
  return `${changed.join(", ")} set`;
@@ -6717,8 +6720,21 @@ async function writePackageJsonField(repoRoot, field, value) {
6717
6720
  * Merge `desired` script entries into `package.json#scripts` — sets only the
6718
6721
  * listed keys, never touches the rest. Returns the sorted list of keys that
6719
6722
  * drifted (empty when all current), or `null` when there is no `package.json`.
6723
+ *
6724
+ * `turboEligible` (#747): task names `turbo.json` fans out — the same set
6725
+ * {@link EnsureRootWorkspaceMemberResult} above already keys off. For those
6726
+ * only, an *existing* script that isn't the generated `holocron run <task>
6727
+ * --` wrapper is left untouched: root may genuinely be a directly-buildable
6728
+ * package (not an orchestrator) with its own real command (`tsc --noEmit`,
6729
+ * `vitest run`, …) for that task. Overwriting it would silently discard the
6730
+ * real command and, once `turbo.json` exists and root is a real workspace
6731
+ * member (#692), reintroduce infinite recursion — `turbo run <task>` →
6732
+ * root's own `<task>` script → the wrapper → `holocron run <task>` sees
6733
+ * `turbo.json` still defines the task → `turbo run <task>` again, forever.
6734
+ * Every other key (non-turbo tasks, `holocron`, `prepare`, …) has no
6735
+ * legitimate direct-command alternative and stays fully generator-owned.
6720
6736
  */
6721
- async function mergePackageJsonScripts(repoRoot, desired) {
6737
+ async function mergePackageJsonScripts(repoRoot, desired, turboEligible) {
6722
6738
  const pkgPath = join(repoRoot, "package.json");
6723
6739
  let content;
6724
6740
  try {
@@ -6729,15 +6745,31 @@ async function mergePackageJsonScripts(repoRoot, desired) {
6729
6745
  const pkg = JSON.parse(content);
6730
6746
  const scripts = pkg.scripts ?? {};
6731
6747
  const changed = [];
6732
- for (const [name, command] of Object.entries(desired)) if (scripts[name] !== command) {
6733
- scripts[name] = command;
6734
- changed.push(name);
6748
+ for (const [name, command] of Object.entries(desired)) {
6749
+ const existing = scripts[name];
6750
+ if (turboEligible.has(name) && existing !== void 0 && !isGeneratedRunWrapper(existing, name)) continue;
6751
+ if (existing !== command) {
6752
+ scripts[name] = command;
6753
+ changed.push(name);
6754
+ }
6735
6755
  }
6736
6756
  if (changed.length === 0) return [];
6737
6757
  pkg.scripts = scripts;
6738
6758
  await writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8");
6739
6759
  return changed.sort();
6740
6760
  }
6761
+ /**
6762
+ * Matches the exact shape `packageScripts()` generates for `taskName` —
6763
+ * `<bin> run <taskName> --`, `<bin>` normally `holocron` but substitutable
6764
+ * (`holocronScript`, itself allowed to be multi-word, e.g. `"node
6765
+ packages/cli/dist/cli.mjs"` — see its own test). Checking the *suffix*
6766
+ * rather than the whole string means an old wrapper survives a
6767
+ * `holocronScript` rename intact — it's still recognized as a wrapper (safe
6768
+ * to update to the new one), not mistaken for a real command.
6769
+ */
6770
+ function isGeneratedRunWrapper(command, taskName) {
6771
+ return command.endsWith(` run ${taskName} --`);
6772
+ }
6741
6773
  const README_DESC_START = "<!-- holocron:description -->";
6742
6774
  const README_DESC_END = "<!-- /holocron:description -->";
6743
6775
  async function updateReadmeDescription(repoRoot, description) {