@trops/dash-core 0.1.534 → 0.1.536

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.
@@ -3827,6 +3827,110 @@ var manifestScanner = {
3827
3827
  SCAN_FILE_LIMIT,
3828
3828
  };
3829
3829
 
3830
+ /**
3831
+ * dedupeWidgetFolders
3832
+ *
3833
+ * Boot-time pass over the widgets cache directory. Looks for
3834
+ * top-level folders that don't follow the canonical `@scope/name`
3835
+ * shape but whose `package.json` declares a scoped name (e.g.
3836
+ * `widgets/pipeline/` containing `{ "name": "@ai-built/pipeline" }`).
3837
+ * These are stale artifacts from older install paths — they coexist
3838
+ * with the canonical `widgets/@scope/name/` folder and crash
3839
+ * ComponentManager with "missing origin metadata" because the
3840
+ * bare-name registry entry has no scope to derive a 3-segment
3841
+ * `<scope>.<package>.<component>` id from.
3842
+ *
3843
+ * Two outcomes per malformed folder:
3844
+ * - Scoped twin already exists → remove the bare copy (redundant)
3845
+ * - Scoped twin missing → move the folder to the canonical
3846
+ * scoped path
3847
+ *
3848
+ * Pure boundary effects (fs read/write/move/remove). The only
3849
+ * registry-side fixup is left to the caller — once this returns,
3850
+ * `widgetRegistry.reconcileWithDisk` re-walks the directory and
3851
+ * picks up the (now canonical) layout cleanly.
3852
+ *
3853
+ * @param {string} widgetsDir
3854
+ * @returns {{removed: string[], migrated: Array<{from: string, to: string}>, errors: Array<{path: string, error: string}>}}
3855
+ */
3856
+
3857
+ var dedupeWidgetFolders_1;
3858
+ var hasRequiredDedupeWidgetFolders;
3859
+
3860
+ function requireDedupeWidgetFolders () {
3861
+ if (hasRequiredDedupeWidgetFolders) return dedupeWidgetFolders_1;
3862
+ hasRequiredDedupeWidgetFolders = 1;
3863
+
3864
+ const fs = require$$0$2;
3865
+ const path = require$$1$1;
3866
+
3867
+ const RESERVED_TOP_LEVEL = new Set(["registry.json"]);
3868
+
3869
+ function dedupeWidgetFolders(widgetsDir) {
3870
+ const summary = { removed: [], migrated: [], errors: [] };
3871
+ if (typeof widgetsDir !== "string" || !fs.existsSync(widgetsDir)) {
3872
+ return summary;
3873
+ }
3874
+
3875
+ let entries;
3876
+ try {
3877
+ entries = fs.readdirSync(widgetsDir, { withFileTypes: true });
3878
+ } catch (e) {
3879
+ summary.errors.push({ path: widgetsDir, error: e.message });
3880
+ return summary;
3881
+ }
3882
+
3883
+ for (const entry of entries) {
3884
+ if (!entry.isDirectory()) continue;
3885
+ if (RESERVED_TOP_LEVEL.has(entry.name)) continue;
3886
+ // Canonical scoped folders are handled by reconcileWithDisk;
3887
+ // skip them here.
3888
+ if (entry.name.startsWith("@")) continue;
3889
+
3890
+ const bareDir = path.join(widgetsDir, entry.name);
3891
+ const pkgJsonPath = path.join(bareDir, "package.json");
3892
+ if (!fs.existsSync(pkgJsonPath)) continue;
3893
+
3894
+ let pkgName;
3895
+ try {
3896
+ const pkg = JSON.parse(fs.readFileSync(pkgJsonPath, "utf8"));
3897
+ pkgName = typeof pkg?.name === "string" ? pkg.name : null;
3898
+ } catch (e) {
3899
+ summary.errors.push({ path: bareDir, error: e.message });
3900
+ continue;
3901
+ }
3902
+
3903
+ // Truly unscoped package — leave alone.
3904
+ if (!pkgName || !pkgName.startsWith("@")) continue;
3905
+
3906
+ const parts = pkgName.split("/");
3907
+ if (parts.length !== 2) continue; // malformed scoped name; ignore
3908
+ const scope = parts[0]; // e.g. "@ai-built"
3909
+ const name = parts[1];
3910
+ const scopedDir = path.join(widgetsDir, scope, name);
3911
+
3912
+ try {
3913
+ if (fs.existsSync(scopedDir)) {
3914
+ // Redundant bare copy — remove it.
3915
+ fs.rmSync(bareDir, { recursive: true, force: true });
3916
+ summary.removed.push(bareDir);
3917
+ } else {
3918
+ // Migrate the bare folder to the canonical scoped path.
3919
+ fs.mkdirSync(path.dirname(scopedDir), { recursive: true });
3920
+ fs.renameSync(bareDir, scopedDir);
3921
+ summary.migrated.push({ from: bareDir, to: scopedDir });
3922
+ }
3923
+ } catch (e) {
3924
+ summary.errors.push({ path: bareDir, error: e.message });
3925
+ }
3926
+ }
3927
+ return summary;
3928
+ }
3929
+
3930
+ dedupeWidgetFolders_1 = { dedupeWidgetFolders };
3931
+ return dedupeWidgetFolders_1;
3932
+ }
3933
+
3830
3934
  /**
3831
3935
  * scanWidgetPackagePermissions
3832
3936
  *
@@ -4847,6 +4951,37 @@ var schedulerController_1 = schedulerController$2;
4847
4951
  console.error("[WidgetRegistry] Error loading registry:", error);
4848
4952
  }
4849
4953
 
4954
+ // Slice 13f: clean up bare-name folders whose package.json declares
4955
+ // a scoped name (legacy install artifact). Without this, the
4956
+ // `reconcileWithDisk` orphan loop below re-registers them under
4957
+ // the bare folder name and ComponentManager later crashes with
4958
+ // "missing origin metadata" trying to derive a 3-segment id from
4959
+ // a scope-less entry. Runs BEFORE reconcile so the registry's
4960
+ // re-register pass sees a canonical layout.
4961
+ try {
4962
+ const { dedupeWidgetFolders } = requireDedupeWidgetFolders();
4963
+ const dedup = dedupeWidgetFolders(WIDGETS_CACHE_DIR);
4964
+ if (dedup.removed.length > 0 || dedup.migrated.length > 0) {
4965
+ console.log(
4966
+ `[WidgetRegistry] Folder dedupe: removed ${dedup.removed.length}, migrated ${dedup.migrated.length}`,
4967
+ );
4968
+ // Drop any registry entry that pointed at a now-removed bare
4969
+ // folder, so reconcileWithDisk re-registers from the canonical
4970
+ // scoped path on its next pass.
4971
+ const removedSet = new Set(dedup.removed);
4972
+ for (const [key, entry] of Array.from(this.widgets.entries())) {
4973
+ if (entry?.path && removedSet.has(entry.path)) {
4974
+ this.widgets.delete(key);
4975
+ }
4976
+ }
4977
+ }
4978
+ if (dedup.errors.length > 0) {
4979
+ console.warn(`[WidgetRegistry] Folder dedupe errors:`, dedup.errors);
4980
+ }
4981
+ } catch (e) {
4982
+ console.warn("[WidgetRegistry] Folder dedupe failed:", e.message);
4983
+ }
4984
+
4850
4985
  // Reconcile: re-register orphaned widget packages found on disk
4851
4986
  this.reconcileWithDisk();
4852
4987