@trops/dash-core 0.1.416 → 0.1.417
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/electron/index.js +443 -125
- package/dist/electron/index.js.map +1 -1
- package/dist/index.esm.js +46 -6
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +78 -47
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/electron/index.js
CHANGED
|
@@ -63840,7 +63840,13 @@ function generateRegistryManifest(dashboardConfig, options = {}) {
|
|
|
63840
63840
|
.toLowerCase();
|
|
63841
63841
|
|
|
63842
63842
|
const githubUser = options.githubUser || "";
|
|
63843
|
-
|
|
63843
|
+
// Prefer an explicitly-passed version (caller resolved it already,
|
|
63844
|
+
// e.g. via resolveNextVersion + bump). Fall back to the dashboard's
|
|
63845
|
+
// own version, then a 1.0.0 baseline. The previous hardcoded
|
|
63846
|
+
// "1.0.0" meant every republish looked identical to the registry;
|
|
63847
|
+
// latestVersion never advanced, so downstream update-check never
|
|
63848
|
+
// saw a diff and no notification fired.
|
|
63849
|
+
const version = options.version || dashboardConfig.version || "1.0.0";
|
|
63844
63850
|
const visibility = options.visibility === "private" ? "private" : "public";
|
|
63845
63851
|
|
|
63846
63852
|
const manifest = {
|
|
@@ -64000,11 +64006,27 @@ function buildDashboardPreview(source) {
|
|
|
64000
64006
|
* @returns {Array} Update records with workspace info and version comparison
|
|
64001
64007
|
*/
|
|
64002
64008
|
function checkDashboardUpdates(workspaces = [], registryPackages = []) {
|
|
64003
|
-
|
|
64009
|
+
// Index the registry by canonical `@scope/name` so the lookup
|
|
64010
|
+
// survives installs that capture scope differently from the
|
|
64011
|
+
// registry's raw `name` field. The previous map was keyed by bare
|
|
64012
|
+
// `pkg.name`, which misses anytime the installed config recorded
|
|
64013
|
+
// `@scope/name` (our new publish flow writes that) or when two
|
|
64014
|
+
// users publish the same bare name. Key both forms for safety.
|
|
64015
|
+
const registryByKey = new Map();
|
|
64016
|
+
const asKey = (scope, name) => {
|
|
64017
|
+
if (!name) return null;
|
|
64018
|
+
if (!scope) return name;
|
|
64019
|
+
const bareScope = String(scope).replace(/^@/, "");
|
|
64020
|
+
return `@${bareScope}/${name}`;
|
|
64021
|
+
};
|
|
64004
64022
|
for (const pkg of registryPackages) {
|
|
64005
|
-
if (pkg.name
|
|
64006
|
-
|
|
64007
|
-
|
|
64023
|
+
if (!pkg.name) continue;
|
|
64024
|
+
if ((pkg.type || "widget") !== "dashboard") continue;
|
|
64025
|
+
const scoped = asKey(pkg.scope, pkg.name);
|
|
64026
|
+
if (scoped) registryByKey.set(scoped, pkg);
|
|
64027
|
+
// Back-compat: also store under bare name so installed configs
|
|
64028
|
+
// that predate the scope-aware write continue to match.
|
|
64029
|
+
registryByKey.set(pkg.name, pkg);
|
|
64008
64030
|
}
|
|
64009
64031
|
|
|
64010
64032
|
const updates = [];
|
|
@@ -64013,7 +64035,24 @@ function checkDashboardUpdates(workspaces = [], registryPackages = []) {
|
|
|
64013
64035
|
const config = ws._dashboardConfig;
|
|
64014
64036
|
if (!config || !config.registryPackage) continue;
|
|
64015
64037
|
|
|
64016
|
-
|
|
64038
|
+
// Lookup chain: try the scoped form first, fall back to bare. The
|
|
64039
|
+
// installed config may record either. Scope is stored on the
|
|
64040
|
+
// config by the install flow (or set here by the publish persist
|
|
64041
|
+
// step we just added).
|
|
64042
|
+
const installedScope =
|
|
64043
|
+
config.registryScope ||
|
|
64044
|
+
(config.registryPackage.startsWith("@")
|
|
64045
|
+
? config.registryPackage.slice(1).split("/")[0]
|
|
64046
|
+
: null);
|
|
64047
|
+
const installedName = config.registryPackage.includes("/")
|
|
64048
|
+
? config.registryPackage.split("/").pop()
|
|
64049
|
+
: config.registryPackage;
|
|
64050
|
+
const scopedKey = asKey(installedScope, installedName);
|
|
64051
|
+
|
|
64052
|
+
const registryPkg =
|
|
64053
|
+
(scopedKey && registryByKey.get(scopedKey)) ||
|
|
64054
|
+
registryByKey.get(config.registryPackage) ||
|
|
64055
|
+
registryByKey.get(installedName);
|
|
64017
64056
|
if (!registryPkg) continue;
|
|
64018
64057
|
|
|
64019
64058
|
const installedVersion = config.installedVersion || "0.0.0";
|
|
@@ -64024,6 +64063,7 @@ function checkDashboardUpdates(workspaces = [], registryPackages = []) {
|
|
|
64024
64063
|
workspaceId: ws.id,
|
|
64025
64064
|
workspaceName: ws.name || ws.label || "",
|
|
64026
64065
|
registryPackage: config.registryPackage,
|
|
64066
|
+
registryScope: installedScope,
|
|
64027
64067
|
installedVersion,
|
|
64028
64068
|
latestVersion,
|
|
64029
64069
|
importedAt: config.importedAt || null,
|
|
@@ -64395,6 +64435,128 @@ var registryApiController$3 = {
|
|
|
64395
64435
|
REGISTRY_BASE_URL,
|
|
64396
64436
|
};
|
|
64397
64437
|
|
|
64438
|
+
/**
|
|
64439
|
+
* widgetPublishManifest.js
|
|
64440
|
+
*
|
|
64441
|
+
* Pure helpers for widget-publish flow — version bumping, package-name
|
|
64442
|
+
* parsing, and manifest generation. No electron / fs / adm-zip deps so
|
|
64443
|
+
* these can be unit-tested directly.
|
|
64444
|
+
*/
|
|
64445
|
+
|
|
64446
|
+
var widgetPublishManifest;
|
|
64447
|
+
var hasRequiredWidgetPublishManifest;
|
|
64448
|
+
|
|
64449
|
+
function requireWidgetPublishManifest () {
|
|
64450
|
+
if (hasRequiredWidgetPublishManifest) return widgetPublishManifest;
|
|
64451
|
+
hasRequiredWidgetPublishManifest = 1;
|
|
64452
|
+
const SEMVER_RE =
|
|
64453
|
+
/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/;
|
|
64454
|
+
|
|
64455
|
+
function bumpVersion(current, type) {
|
|
64456
|
+
if (!current || typeof current !== "string") return "1.0.0";
|
|
64457
|
+
const match = current.match(SEMVER_RE);
|
|
64458
|
+
if (!match) return current;
|
|
64459
|
+
let [, major, minor, patch] = match;
|
|
64460
|
+
major = Number(major);
|
|
64461
|
+
minor = Number(minor);
|
|
64462
|
+
patch = Number(patch);
|
|
64463
|
+
switch (type) {
|
|
64464
|
+
case "major":
|
|
64465
|
+
return `${major + 1}.0.0`;
|
|
64466
|
+
case "minor":
|
|
64467
|
+
return `${major}.${minor + 1}.0`;
|
|
64468
|
+
case "patch":
|
|
64469
|
+
default:
|
|
64470
|
+
return `${major}.${minor}.${patch + 1}`;
|
|
64471
|
+
}
|
|
64472
|
+
}
|
|
64473
|
+
|
|
64474
|
+
function resolveNextVersion(currentVersion, options = {}) {
|
|
64475
|
+
if (options.version) return options.version;
|
|
64476
|
+
if (options.bump) return bumpVersion(currentVersion, options.bump);
|
|
64477
|
+
return currentVersion;
|
|
64478
|
+
}
|
|
64479
|
+
|
|
64480
|
+
function parsePackageName(pkgName) {
|
|
64481
|
+
if (!pkgName) return { scope: null, name: "" };
|
|
64482
|
+
const m = pkgName.match(/^@([^/]+)\/(.+)$/);
|
|
64483
|
+
if (m) return { scope: m[1], name: m[2] };
|
|
64484
|
+
return { scope: null, name: pkgName };
|
|
64485
|
+
}
|
|
64486
|
+
|
|
64487
|
+
function generateWidgetRegistryManifest(
|
|
64488
|
+
packageJson,
|
|
64489
|
+
widgetConfigs,
|
|
64490
|
+
options = {},
|
|
64491
|
+
) {
|
|
64492
|
+
const parsed = parsePackageName(packageJson.name || "");
|
|
64493
|
+
const scope = options.scope || parsed.scope || "";
|
|
64494
|
+
const name = options.name || parsed.name || packageJson.name || "";
|
|
64495
|
+
const version = options.version || packageJson.version || "1.0.0";
|
|
64496
|
+
const visibility = options.visibility === "private" ? "private" : "public";
|
|
64497
|
+
|
|
64498
|
+
const providerKeys = new Set();
|
|
64499
|
+
const providers = [];
|
|
64500
|
+
for (const cfg of widgetConfigs || []) {
|
|
64501
|
+
if (!Array.isArray(cfg.providers)) continue;
|
|
64502
|
+
for (const p of cfg.providers) {
|
|
64503
|
+
const key = `${p.type}:${p.providerClass || "mcp"}`;
|
|
64504
|
+
if (providerKeys.has(key)) continue;
|
|
64505
|
+
providerKeys.add(key);
|
|
64506
|
+
providers.push({
|
|
64507
|
+
type: p.type,
|
|
64508
|
+
required: p.required !== false,
|
|
64509
|
+
providerClass: p.providerClass || "mcp",
|
|
64510
|
+
});
|
|
64511
|
+
}
|
|
64512
|
+
}
|
|
64513
|
+
|
|
64514
|
+
const widgets = (widgetConfigs || []).map((cfg) => ({
|
|
64515
|
+
name: cfg.component || cfg.name,
|
|
64516
|
+
displayName: cfg.name || cfg.component,
|
|
64517
|
+
description: cfg.description || "",
|
|
64518
|
+
icon: cfg.icon || "square",
|
|
64519
|
+
providers: Array.isArray(cfg.providers)
|
|
64520
|
+
? cfg.providers.map((p) => ({
|
|
64521
|
+
type: p.type,
|
|
64522
|
+
required: p.required !== false,
|
|
64523
|
+
providerClass: p.providerClass || "mcp",
|
|
64524
|
+
}))
|
|
64525
|
+
: [],
|
|
64526
|
+
}));
|
|
64527
|
+
|
|
64528
|
+
return {
|
|
64529
|
+
scope,
|
|
64530
|
+
name,
|
|
64531
|
+
displayName: options.displayName || packageJson.displayName || name,
|
|
64532
|
+
version,
|
|
64533
|
+
type: "widget",
|
|
64534
|
+
visibility,
|
|
64535
|
+
description: options.description || packageJson.description || "",
|
|
64536
|
+
author:
|
|
64537
|
+
options.authorName ||
|
|
64538
|
+
(typeof packageJson.author === "string"
|
|
64539
|
+
? packageJson.author
|
|
64540
|
+
: packageJson.author?.name || ""),
|
|
64541
|
+
category: options.category || "general",
|
|
64542
|
+
tags: Array.isArray(options.tags) ? options.tags : [],
|
|
64543
|
+
icon: options.icon || "puzzle-piece",
|
|
64544
|
+
providers,
|
|
64545
|
+
widgets,
|
|
64546
|
+
appOrigin: options.appOrigin || "",
|
|
64547
|
+
publishedAt: new Date().toISOString(),
|
|
64548
|
+
};
|
|
64549
|
+
}
|
|
64550
|
+
|
|
64551
|
+
widgetPublishManifest = {
|
|
64552
|
+
bumpVersion,
|
|
64553
|
+
resolveNextVersion,
|
|
64554
|
+
parsePackageName,
|
|
64555
|
+
generateWidgetRegistryManifest,
|
|
64556
|
+
};
|
|
64557
|
+
return widgetPublishManifest;
|
|
64558
|
+
}
|
|
64559
|
+
|
|
64398
64560
|
/**
|
|
64399
64561
|
* themeRegistryController.js
|
|
64400
64562
|
*
|
|
@@ -64439,14 +64601,20 @@ function generateThemeRegistryManifest(themeData, themeKey, options = {}) {
|
|
|
64439
64601
|
const sanitizedName = sanitizeName(humanName);
|
|
64440
64602
|
const colors = extractColors(themeData);
|
|
64441
64603
|
const visibility = options.visibility === "private" ? "private" : "public";
|
|
64604
|
+
// Prefer an explicitly-resolved version (caller already bumped),
|
|
64605
|
+
// then the theme's own stored version, then the 1.0.0 baseline.
|
|
64606
|
+
// The old hardcoded 1.0.0 meant republishes silently clobbered the
|
|
64607
|
+
// registry record — update notifications never fired downstream.
|
|
64608
|
+
const version = options.version || themeData.version || "1.0.0";
|
|
64442
64609
|
|
|
64443
64610
|
return {
|
|
64444
64611
|
scope: options.scope || "",
|
|
64445
64612
|
name: sanitizedName,
|
|
64446
64613
|
displayName: humanName,
|
|
64447
|
-
author:
|
|
64614
|
+
author:
|
|
64615
|
+
options.authorName || themeData.author || options.fallbackAuthor || "",
|
|
64448
64616
|
description: options.description || "",
|
|
64449
|
-
version
|
|
64617
|
+
version,
|
|
64450
64618
|
visibility,
|
|
64451
64619
|
type: "theme",
|
|
64452
64620
|
category: "general",
|
|
@@ -64516,6 +64684,7 @@ function extractColors(themeData) {
|
|
|
64516
64684
|
*/
|
|
64517
64685
|
async function prepareThemeForPublish$1(win, appId, themeKey, options = {}) {
|
|
64518
64686
|
try {
|
|
64687
|
+
const { resolveNextVersion } = requireWidgetPublishManifest();
|
|
64519
64688
|
// Read the theme data
|
|
64520
64689
|
const themesResult = themeController$3.listThemesForApplication(win, appId);
|
|
64521
64690
|
if (themesResult.error) {
|
|
@@ -64549,11 +64718,33 @@ async function prepareThemeForPublish$1(win, appId, themeKey, options = {}) {
|
|
|
64549
64718
|
};
|
|
64550
64719
|
}
|
|
64551
64720
|
|
|
64721
|
+
// Resolve version: prefer explicit, then bump the theme's stored
|
|
64722
|
+
// version, then start at 1.0.0. Without this themes always
|
|
64723
|
+
// published as 1.0.0 and update-check could never diff.
|
|
64724
|
+
const previousVersion = themeData.version || "1.0.0";
|
|
64725
|
+
const nextVersion = resolveNextVersion(previousVersion, {
|
|
64726
|
+
bump: options.bump,
|
|
64727
|
+
version: options.version,
|
|
64728
|
+
});
|
|
64729
|
+
|
|
64730
|
+
// Author fallback chain (F7): explicit → theme data → registry
|
|
64731
|
+
// profile displayName/username → blank. Matches the widget
|
|
64732
|
+
// author-normalization shape so ai-built / scaffolded themes
|
|
64733
|
+
// don't ship to the registry with a blank author field.
|
|
64734
|
+
const resolvedAuthor =
|
|
64735
|
+
options.authorName ||
|
|
64736
|
+
themeData.author ||
|
|
64737
|
+
profile?.displayName ||
|
|
64738
|
+
profile?.username ||
|
|
64739
|
+
"";
|
|
64740
|
+
|
|
64552
64741
|
// Generate manifest
|
|
64553
64742
|
const manifest = generateThemeRegistryManifest(themeData, themeKey, {
|
|
64554
64743
|
...options,
|
|
64555
64744
|
scope,
|
|
64556
64745
|
appOrigin: appId,
|
|
64746
|
+
version: nextVersion,
|
|
64747
|
+
authorName: resolvedAuthor,
|
|
64557
64748
|
});
|
|
64558
64749
|
|
|
64559
64750
|
// Validate colors
|
|
@@ -64610,6 +64801,35 @@ async function prepareThemeForPublish$1(win, appId, themeKey, options = {}) {
|
|
|
64610
64801
|
"[ThemeRegistryController] Registry publish result:",
|
|
64611
64802
|
registryResult,
|
|
64612
64803
|
);
|
|
64804
|
+
// Persist the resolved version + author back onto the theme so
|
|
64805
|
+
// the NEXT publish picks up from here. Without this, the
|
|
64806
|
+
// publisher would be bumping from 1.0.0 every time and the
|
|
64807
|
+
// manifest's author normalization would be re-applied every
|
|
64808
|
+
// run (OK but confusing).
|
|
64809
|
+
if (registryResult?.success) {
|
|
64810
|
+
try {
|
|
64811
|
+
const updatedTheme = {
|
|
64812
|
+
...themeData,
|
|
64813
|
+
version: nextVersion,
|
|
64814
|
+
author: resolvedAuthor || themeData.author,
|
|
64815
|
+
_registryMeta: {
|
|
64816
|
+
...(themeData._registryMeta || {}),
|
|
64817
|
+
packageName: `${scope}/${manifest.name}`,
|
|
64818
|
+
scope,
|
|
64819
|
+
lastPublishedAt: new Date().toISOString(),
|
|
64820
|
+
lastPublishedVersion: nextVersion,
|
|
64821
|
+
},
|
|
64822
|
+
};
|
|
64823
|
+
themeController$3.saveThemeForApplication(win, appId, {
|
|
64824
|
+
key: themeKey,
|
|
64825
|
+
theme: updatedTheme,
|
|
64826
|
+
});
|
|
64827
|
+
} catch (persistErr) {
|
|
64828
|
+
console.warn(
|
|
64829
|
+
`[ThemeRegistryController] Version persist failed (continuing): ${persistErr.message}`,
|
|
64830
|
+
);
|
|
64831
|
+
}
|
|
64832
|
+
}
|
|
64613
64833
|
}
|
|
64614
64834
|
|
|
64615
64835
|
return {
|
|
@@ -64950,12 +65170,120 @@ function getThemePublishPreview$1(appId, themeKey) {
|
|
|
64950
65170
|
}
|
|
64951
65171
|
}
|
|
64952
65172
|
|
|
65173
|
+
/**
|
|
65174
|
+
* Check installed themes for available updates against the registry.
|
|
65175
|
+
*
|
|
65176
|
+
* Reads every theme from the app's theme file, picks the ones that
|
|
65177
|
+
* carry a `_registryMeta.packageName` (i.e. were installed from the
|
|
65178
|
+
* registry, not locally created), resolves each against the registry
|
|
65179
|
+
* index by `@scope/name` (with a bare-name fallback), and returns a
|
|
65180
|
+
* diff record for each stale theme.
|
|
65181
|
+
*
|
|
65182
|
+
* Mirrors `checkDashboardUpdatesForApp` — callable standalone, works
|
|
65183
|
+
* the same way on the renderer side.
|
|
65184
|
+
*
|
|
65185
|
+
* @param {BrowserWindow} win
|
|
65186
|
+
* @param {string} appId
|
|
65187
|
+
* @returns {Promise<{success, updates, totalInstalled, error?}>}
|
|
65188
|
+
*/
|
|
65189
|
+
async function checkThemeUpdatesForApp$1(win, appId) {
|
|
65190
|
+
try {
|
|
65191
|
+
const { fetchRegistryIndex } = registryController$3;
|
|
65192
|
+
const themesResult = themeController$3.listThemesForApplication(win, appId);
|
|
65193
|
+
if (themesResult.error) {
|
|
65194
|
+
return {
|
|
65195
|
+
success: false,
|
|
65196
|
+
error: themesResult.message || "Failed to read themes",
|
|
65197
|
+
updates: [],
|
|
65198
|
+
};
|
|
65199
|
+
}
|
|
65200
|
+
const themes = themesResult.themes || {};
|
|
65201
|
+
|
|
65202
|
+
// Filter to registry-installed themes only.
|
|
65203
|
+
const installed = [];
|
|
65204
|
+
for (const [themeKey, themeData] of Object.entries(themes)) {
|
|
65205
|
+
const meta = themeData?._registryMeta;
|
|
65206
|
+
if (!meta?.packageName) continue;
|
|
65207
|
+
installed.push({
|
|
65208
|
+
themeKey,
|
|
65209
|
+
packageName: meta.packageName,
|
|
65210
|
+
scope: meta.scope || null,
|
|
65211
|
+
version: themeData.version || meta.lastPublishedVersion || "0.0.0",
|
|
65212
|
+
});
|
|
65213
|
+
}
|
|
65214
|
+
|
|
65215
|
+
if (installed.length === 0) {
|
|
65216
|
+
return { success: true, updates: [], totalInstalled: 0 };
|
|
65217
|
+
}
|
|
65218
|
+
|
|
65219
|
+
const index = await fetchRegistryIndex();
|
|
65220
|
+
const packages = (index.packages || []).filter(
|
|
65221
|
+
(p) => (p.type || "widget") === "theme",
|
|
65222
|
+
);
|
|
65223
|
+
|
|
65224
|
+
// Index registry packages by scoped + bare key, same pattern as
|
|
65225
|
+
// dashboard update check.
|
|
65226
|
+
const registryByKey = new Map();
|
|
65227
|
+
for (const pkg of packages) {
|
|
65228
|
+
if (!pkg.name) continue;
|
|
65229
|
+
if (pkg.scope) {
|
|
65230
|
+
const bareScope = String(pkg.scope).replace(/^@/, "");
|
|
65231
|
+
registryByKey.set(`@${bareScope}/${pkg.name}`, pkg);
|
|
65232
|
+
}
|
|
65233
|
+
registryByKey.set(pkg.name, pkg);
|
|
65234
|
+
}
|
|
65235
|
+
|
|
65236
|
+
const updates = [];
|
|
65237
|
+
for (const inst of installed) {
|
|
65238
|
+
const scope = inst.scope
|
|
65239
|
+
? String(inst.scope).replace(/^@/, "")
|
|
65240
|
+
: inst.packageName.startsWith("@")
|
|
65241
|
+
? inst.packageName.slice(1).split("/")[0]
|
|
65242
|
+
: null;
|
|
65243
|
+
const bareName = inst.packageName.includes("/")
|
|
65244
|
+
? inst.packageName.split("/").pop()
|
|
65245
|
+
: inst.packageName;
|
|
65246
|
+
const scopedKey = scope ? `@${scope}/${bareName}` : null;
|
|
65247
|
+
const registryPkg =
|
|
65248
|
+
(scopedKey && registryByKey.get(scopedKey)) ||
|
|
65249
|
+
registryByKey.get(inst.packageName) ||
|
|
65250
|
+
registryByKey.get(bareName);
|
|
65251
|
+
if (!registryPkg) continue;
|
|
65252
|
+
|
|
65253
|
+
const latestVersion = registryPkg.version || "0.0.0";
|
|
65254
|
+
if (inst.version !== latestVersion) {
|
|
65255
|
+
updates.push({
|
|
65256
|
+
themeKey: inst.themeKey,
|
|
65257
|
+
packageName: inst.packageName,
|
|
65258
|
+
scope,
|
|
65259
|
+
installedVersion: inst.version,
|
|
65260
|
+
latestVersion,
|
|
65261
|
+
downloadUrl: registryPkg.downloadUrl || null,
|
|
65262
|
+
});
|
|
65263
|
+
}
|
|
65264
|
+
}
|
|
65265
|
+
|
|
65266
|
+
return {
|
|
65267
|
+
success: true,
|
|
65268
|
+
updates,
|
|
65269
|
+
totalInstalled: installed.length,
|
|
65270
|
+
};
|
|
65271
|
+
} catch (err) {
|
|
65272
|
+
console.error(
|
|
65273
|
+
"[ThemeRegistryController] Error checking theme updates:",
|
|
65274
|
+
err,
|
|
65275
|
+
);
|
|
65276
|
+
return { success: false, error: err.message, updates: [] };
|
|
65277
|
+
}
|
|
65278
|
+
}
|
|
65279
|
+
|
|
64953
65280
|
var themeRegistryController$1 = {
|
|
64954
65281
|
prepareThemeForPublish: prepareThemeForPublish$1,
|
|
64955
65282
|
installThemeFromRegistry: installThemeFromRegistry$1,
|
|
64956
65283
|
getThemePublishPreview: getThemePublishPreview$1,
|
|
64957
65284
|
generateThemeRegistryManifest,
|
|
64958
65285
|
extractColors,
|
|
65286
|
+
checkThemeUpdatesForApp: checkThemeUpdatesForApp$1,
|
|
64959
65287
|
};
|
|
64960
65288
|
|
|
64961
65289
|
/**
|
|
@@ -65420,7 +65748,30 @@ async function processDashboardConfig(
|
|
|
65420
65748
|
dashboardConfig.widgets.length
|
|
65421
65749
|
) {
|
|
65422
65750
|
const installedWidgets = widgetRegistry.getWidgets();
|
|
65423
|
-
|
|
65751
|
+
// Build a canonical id set — `@scope/name` — so lookups survive
|
|
65752
|
+
// the publisher/installer having the widget under different
|
|
65753
|
+
// keys. The widget-registry entry carries `w.packageId`,
|
|
65754
|
+
// `w.name`, and `w.scope`; the dashboard dep carries
|
|
65755
|
+
// `dep.package` (now scope-remapped at publish time). Seeding
|
|
65756
|
+
// every form we've seen avoids silent "missing widget" misses
|
|
65757
|
+
// on bare-vs-scoped mismatch.
|
|
65758
|
+
const canonicalId = (w) => {
|
|
65759
|
+
if (w?.packageId) return w.packageId;
|
|
65760
|
+
if (w?.scope && w?.name) {
|
|
65761
|
+
const scope = String(w.scope).replace(/^@/, "");
|
|
65762
|
+
const bareName = String(w.name).replace(new RegExp(`^@?${scope}/`), "");
|
|
65763
|
+
return `@${scope}/${bareName}`;
|
|
65764
|
+
}
|
|
65765
|
+
return w?.name || null;
|
|
65766
|
+
};
|
|
65767
|
+
const installedPackages = new Set();
|
|
65768
|
+
for (const w of installedWidgets) {
|
|
65769
|
+
const id = canonicalId(w);
|
|
65770
|
+
if (id) installedPackages.add(id);
|
|
65771
|
+
// Back-compat: keep bare name in the set too, so older
|
|
65772
|
+
// dashboard configs (pre-scope-remap) still match.
|
|
65773
|
+
if (w?.name) installedPackages.add(w.name);
|
|
65774
|
+
}
|
|
65424
65775
|
|
|
65425
65776
|
// Emit initial "pending" state for all widgets
|
|
65426
65777
|
for (let i = 0; i < widgetTotal; i++) {
|
|
@@ -65458,7 +65809,20 @@ async function processDashboardConfig(
|
|
|
65458
65809
|
const displayName =
|
|
65459
65810
|
widgetDep.displayName || widgetDep.name || packageName;
|
|
65460
65811
|
|
|
65461
|
-
|
|
65812
|
+
// Try both the fully-scoped id and a bare-name fallback — the
|
|
65813
|
+
// installed set holds both forms, but the dashboard dep may
|
|
65814
|
+
// carry either shape. Without this, a widget stored locally as
|
|
65815
|
+
// `@trops/pipeline` and referenced as `pipeline` (or vice
|
|
65816
|
+
// versa) silently flagged as "failed" even though it was
|
|
65817
|
+
// installed.
|
|
65818
|
+
const isInstalled =
|
|
65819
|
+
installedPackages.has(packageName) ||
|
|
65820
|
+
(packageName?.includes("/") &&
|
|
65821
|
+
installedPackages.has(packageName.split("/").pop())) ||
|
|
65822
|
+
(packageName &&
|
|
65823
|
+
!packageName.startsWith("@") &&
|
|
65824
|
+
installedPackages.has(`@${packageName}`));
|
|
65825
|
+
if (isInstalled) {
|
|
65462
65826
|
installSummary.alreadyInstalled.push(packageName);
|
|
65463
65827
|
win.webContents.send(DASHBOARD_CONFIG_INSTALL_PROGRESS, {
|
|
65464
65828
|
packageName,
|
|
@@ -65490,6 +65854,10 @@ async function processDashboardConfig(
|
|
|
65490
65854
|
);
|
|
65491
65855
|
installSummary.installed.push({ packageName, config });
|
|
65492
65856
|
installedPackages.add(packageName);
|
|
65857
|
+
// Also add the canonical form so a subsequent dep that
|
|
65858
|
+
// references it under a different shape still hits.
|
|
65859
|
+
const installedCanonical = canonicalId(config);
|
|
65860
|
+
if (installedCanonical) installedPackages.add(installedCanonical);
|
|
65493
65861
|
win.webContents.send(DASHBOARD_CONFIG_INSTALL_PROGRESS, {
|
|
65494
65862
|
packageName,
|
|
65495
65863
|
displayName,
|
|
@@ -66227,16 +66595,30 @@ async function getDashboardPublishPlan$1(
|
|
|
66227
66595
|
}
|
|
66228
66596
|
}
|
|
66229
66597
|
|
|
66598
|
+
// Scopes that only exist on the publisher's machine and aren't
|
|
66599
|
+
// resolvable from the registry as-is. Any dep under one of these
|
|
66600
|
+
// scopes MUST be republished under the caller's scope for the
|
|
66601
|
+
// dashboard's widget refs to work on another machine. The modal
|
|
66602
|
+
// uses this flag to auto-check + lock such rows.
|
|
66603
|
+
const LOCAL_ONLY_SCOPES = new Set(["ai-built", "@ai-built"]);
|
|
66604
|
+
|
|
66230
66605
|
const widgets = deps.widgets.map((w) => {
|
|
66231
66606
|
const publishScope = publishScopeFor(w);
|
|
66232
66607
|
const key =
|
|
66233
66608
|
publishScope && w.packageName
|
|
66234
66609
|
? `${publishScope}/${w.packageName}`
|
|
66235
66610
|
: null;
|
|
66611
|
+
const isLocalOnlyScope =
|
|
66612
|
+
!!w.scope && LOCAL_ONLY_SCOPES.has(String(w.scope).replace(/^@/, ""));
|
|
66236
66613
|
return {
|
|
66237
66614
|
...w,
|
|
66238
66615
|
publishScope,
|
|
66239
66616
|
registry: key ? resolvedByKey.get(key) || null : null,
|
|
66617
|
+
// True when this widget cannot be installed as-is under its
|
|
66618
|
+
// local scope — the dashboard publish MUST republish it under
|
|
66619
|
+
// the caller's scope alongside the dashboard itself. The
|
|
66620
|
+
// modal treats this as mandatory rather than opt-in.
|
|
66621
|
+
requiresRepublish: isLocalOnlyScope,
|
|
66240
66622
|
};
|
|
66241
66623
|
});
|
|
66242
66624
|
|
|
@@ -66300,6 +66682,7 @@ async function prepareDashboardForPublish$1(
|
|
|
66300
66682
|
const {
|
|
66301
66683
|
generateRegistryManifest,
|
|
66302
66684
|
} = dashboardConfigUtils$1;
|
|
66685
|
+
const { resolveNextVersion } = requireWidgetPublishManifest();
|
|
66303
66686
|
|
|
66304
66687
|
// 1. Read workspace
|
|
66305
66688
|
const filename = path$2.join(
|
|
@@ -66332,6 +66715,19 @@ async function prepareDashboardForPublish$1(
|
|
|
66332
66715
|
};
|
|
66333
66716
|
}
|
|
66334
66717
|
|
|
66718
|
+
// Resolve the version this publish will ship. Previous publishes
|
|
66719
|
+
// store the last version on workspace._dashboardConfig.version; new
|
|
66720
|
+
// dashboards start at 1.0.0. Caller may pass `options.version`
|
|
66721
|
+
// (explicit) or `options.bump` ("patch"/"minor"/"major"). Without
|
|
66722
|
+
// this, every dashboard republish used a hardcoded 1.0.0 — the
|
|
66723
|
+
// registry never saw a new version, so the update-check never
|
|
66724
|
+
// fired a notification for installers.
|
|
66725
|
+
const previousVersion = workspace._dashboardConfig?.version || "1.0.0";
|
|
66726
|
+
const nextVersion = resolveNextVersion(previousVersion, {
|
|
66727
|
+
bump: options.bump,
|
|
66728
|
+
version: options.version,
|
|
66729
|
+
});
|
|
66730
|
+
|
|
66335
66731
|
// Strip publisher-specific personalization (userPrefs,
|
|
66336
66732
|
// selectedProviders) from every widget instance before we snapshot
|
|
66337
66733
|
// the workspace into the dashboardConfig. Without this, every
|
|
@@ -66368,6 +66764,10 @@ async function prepareDashboardForPublish$1(
|
|
|
66368
66764
|
schemaVersion: CURRENT_SCHEMA_VERSION,
|
|
66369
66765
|
name: workspace.name || workspace.label || "Dashboard",
|
|
66370
66766
|
description: options.description || "",
|
|
66767
|
+
// Package version (semver). Distinct from workspace.version
|
|
66768
|
+
// (schema revision, integer). Persisted on the workspace after a
|
|
66769
|
+
// successful publish so the next publish resolves from here.
|
|
66770
|
+
version: nextVersion,
|
|
66371
66771
|
...(options.authorName
|
|
66372
66772
|
? { author: { name: options.authorName, id: options.authorId || "" } }
|
|
66373
66773
|
: {}),
|
|
@@ -66522,6 +66922,7 @@ async function prepareDashboardForPublish$1(
|
|
|
66522
66922
|
repository: options.repository || "",
|
|
66523
66923
|
appOrigin: appId,
|
|
66524
66924
|
visibility: options.visibility || "public",
|
|
66925
|
+
version: nextVersion,
|
|
66525
66926
|
});
|
|
66526
66927
|
|
|
66527
66928
|
// 9. Show save dialog for the publish package
|
|
@@ -66569,6 +66970,35 @@ async function prepareDashboardForPublish$1(
|
|
|
66569
66970
|
console.log(
|
|
66570
66971
|
`[DashboardConfigController] Published to registry: ${registrySubmission.registryUrl}`,
|
|
66571
66972
|
);
|
|
66973
|
+
// Persist the resolved next version back onto the workspace
|
|
66974
|
+
// so the NEXT publish resolves from it. Without this, the
|
|
66975
|
+
// publisher would have to re-enter the same version every
|
|
66976
|
+
// time (or keep bumping from 1.0.0, masking that the
|
|
66977
|
+
// registry already advanced).
|
|
66978
|
+
try {
|
|
66979
|
+
const workspaceController = workspaceController_1;
|
|
66980
|
+
const nextWorkspace = {
|
|
66981
|
+
...workspace,
|
|
66982
|
+
_dashboardConfig: {
|
|
66983
|
+
...(workspace._dashboardConfig || {}),
|
|
66984
|
+
version: nextVersion,
|
|
66985
|
+
registryPackage: manifest.name,
|
|
66986
|
+
registryScope: manifest.scope || manifest.githubUser,
|
|
66987
|
+
},
|
|
66988
|
+
};
|
|
66989
|
+
workspaceController.saveWorkspaceForApplication(
|
|
66990
|
+
win,
|
|
66991
|
+
appId,
|
|
66992
|
+
nextWorkspace,
|
|
66993
|
+
);
|
|
66994
|
+
} catch (persistErr) {
|
|
66995
|
+
// Non-fatal — registry is the source of truth for
|
|
66996
|
+
// latestVersion, so the next publish can still resolve
|
|
66997
|
+
// against it if this workspace write fails.
|
|
66998
|
+
console.warn(
|
|
66999
|
+
`[DashboardConfigController] Version persistence failed (continuing): ${persistErr.message}`,
|
|
67000
|
+
);
|
|
67001
|
+
}
|
|
66572
67002
|
} else {
|
|
66573
67003
|
console.warn(
|
|
66574
67004
|
`[DashboardConfigController] Registry publish failed: ${registrySubmission.error}`,
|
|
@@ -73033,120 +73463,6 @@ var dashboardRatingsController = {
|
|
|
73033
73463
|
enrichPackagesWithRatings: enrichPackagesWithRatings$1,
|
|
73034
73464
|
};
|
|
73035
73465
|
|
|
73036
|
-
/**
|
|
73037
|
-
* widgetPublishManifest.js
|
|
73038
|
-
*
|
|
73039
|
-
* Pure helpers for widget-publish flow — version bumping, package-name
|
|
73040
|
-
* parsing, and manifest generation. No electron / fs / adm-zip deps so
|
|
73041
|
-
* these can be unit-tested directly.
|
|
73042
|
-
*/
|
|
73043
|
-
|
|
73044
|
-
const SEMVER_RE =
|
|
73045
|
-
/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/;
|
|
73046
|
-
|
|
73047
|
-
function bumpVersion(current, type) {
|
|
73048
|
-
if (!current || typeof current !== "string") return "1.0.0";
|
|
73049
|
-
const match = current.match(SEMVER_RE);
|
|
73050
|
-
if (!match) return current;
|
|
73051
|
-
let [, major, minor, patch] = match;
|
|
73052
|
-
major = Number(major);
|
|
73053
|
-
minor = Number(minor);
|
|
73054
|
-
patch = Number(patch);
|
|
73055
|
-
switch (type) {
|
|
73056
|
-
case "major":
|
|
73057
|
-
return `${major + 1}.0.0`;
|
|
73058
|
-
case "minor":
|
|
73059
|
-
return `${major}.${minor + 1}.0`;
|
|
73060
|
-
case "patch":
|
|
73061
|
-
default:
|
|
73062
|
-
return `${major}.${minor}.${patch + 1}`;
|
|
73063
|
-
}
|
|
73064
|
-
}
|
|
73065
|
-
|
|
73066
|
-
function resolveNextVersion$1(currentVersion, options = {}) {
|
|
73067
|
-
if (options.version) return options.version;
|
|
73068
|
-
if (options.bump) return bumpVersion(currentVersion, options.bump);
|
|
73069
|
-
return currentVersion;
|
|
73070
|
-
}
|
|
73071
|
-
|
|
73072
|
-
function parsePackageName$1(pkgName) {
|
|
73073
|
-
if (!pkgName) return { scope: null, name: "" };
|
|
73074
|
-
const m = pkgName.match(/^@([^/]+)\/(.+)$/);
|
|
73075
|
-
if (m) return { scope: m[1], name: m[2] };
|
|
73076
|
-
return { scope: null, name: pkgName };
|
|
73077
|
-
}
|
|
73078
|
-
|
|
73079
|
-
function generateWidgetRegistryManifest$1(
|
|
73080
|
-
packageJson,
|
|
73081
|
-
widgetConfigs,
|
|
73082
|
-
options = {},
|
|
73083
|
-
) {
|
|
73084
|
-
const parsed = parsePackageName$1(packageJson.name || "");
|
|
73085
|
-
const scope = options.scope || parsed.scope || "";
|
|
73086
|
-
const name = options.name || parsed.name || packageJson.name || "";
|
|
73087
|
-
const version = options.version || packageJson.version || "1.0.0";
|
|
73088
|
-
const visibility = options.visibility === "private" ? "private" : "public";
|
|
73089
|
-
|
|
73090
|
-
const providerKeys = new Set();
|
|
73091
|
-
const providers = [];
|
|
73092
|
-
for (const cfg of widgetConfigs || []) {
|
|
73093
|
-
if (!Array.isArray(cfg.providers)) continue;
|
|
73094
|
-
for (const p of cfg.providers) {
|
|
73095
|
-
const key = `${p.type}:${p.providerClass || "mcp"}`;
|
|
73096
|
-
if (providerKeys.has(key)) continue;
|
|
73097
|
-
providerKeys.add(key);
|
|
73098
|
-
providers.push({
|
|
73099
|
-
type: p.type,
|
|
73100
|
-
required: p.required !== false,
|
|
73101
|
-
providerClass: p.providerClass || "mcp",
|
|
73102
|
-
});
|
|
73103
|
-
}
|
|
73104
|
-
}
|
|
73105
|
-
|
|
73106
|
-
const widgets = (widgetConfigs || []).map((cfg) => ({
|
|
73107
|
-
name: cfg.component || cfg.name,
|
|
73108
|
-
displayName: cfg.name || cfg.component,
|
|
73109
|
-
description: cfg.description || "",
|
|
73110
|
-
icon: cfg.icon || "square",
|
|
73111
|
-
providers: Array.isArray(cfg.providers)
|
|
73112
|
-
? cfg.providers.map((p) => ({
|
|
73113
|
-
type: p.type,
|
|
73114
|
-
required: p.required !== false,
|
|
73115
|
-
providerClass: p.providerClass || "mcp",
|
|
73116
|
-
}))
|
|
73117
|
-
: [],
|
|
73118
|
-
}));
|
|
73119
|
-
|
|
73120
|
-
return {
|
|
73121
|
-
scope,
|
|
73122
|
-
name,
|
|
73123
|
-
displayName: options.displayName || packageJson.displayName || name,
|
|
73124
|
-
version,
|
|
73125
|
-
type: "widget",
|
|
73126
|
-
visibility,
|
|
73127
|
-
description: options.description || packageJson.description || "",
|
|
73128
|
-
author:
|
|
73129
|
-
options.authorName ||
|
|
73130
|
-
(typeof packageJson.author === "string"
|
|
73131
|
-
? packageJson.author
|
|
73132
|
-
: packageJson.author?.name || ""),
|
|
73133
|
-
category: options.category || "general",
|
|
73134
|
-
tags: Array.isArray(options.tags) ? options.tags : [],
|
|
73135
|
-
icon: options.icon || "puzzle-piece",
|
|
73136
|
-
providers,
|
|
73137
|
-
widgets,
|
|
73138
|
-
appOrigin: options.appOrigin || "",
|
|
73139
|
-
publishedAt: new Date().toISOString(),
|
|
73140
|
-
};
|
|
73141
|
-
}
|
|
73142
|
-
|
|
73143
|
-
var widgetPublishManifest = {
|
|
73144
|
-
bumpVersion,
|
|
73145
|
-
resolveNextVersion: resolveNextVersion$1,
|
|
73146
|
-
parsePackageName: parsePackageName$1,
|
|
73147
|
-
generateWidgetRegistryManifest: generateWidgetRegistryManifest$1,
|
|
73148
|
-
};
|
|
73149
|
-
|
|
73150
73466
|
/**
|
|
73151
73467
|
* widgetRegistryController.js
|
|
73152
73468
|
*
|
|
@@ -73176,7 +73492,7 @@ const {
|
|
|
73176
73492
|
resolveNextVersion,
|
|
73177
73493
|
parsePackageName,
|
|
73178
73494
|
generateWidgetRegistryManifest,
|
|
73179
|
-
} =
|
|
73495
|
+
} = requireWidgetPublishManifest();
|
|
73180
73496
|
|
|
73181
73497
|
/**
|
|
73182
73498
|
* Resilient widget lookup. Callers pass identifiers in different shapes —
|
|
@@ -73652,6 +73968,7 @@ const {
|
|
|
73652
73968
|
prepareThemeForPublish,
|
|
73653
73969
|
installThemeFromRegistry,
|
|
73654
73970
|
getThemePublishPreview,
|
|
73971
|
+
checkThemeUpdatesForApp,
|
|
73655
73972
|
} = themeRegistryController$1;
|
|
73656
73973
|
const {
|
|
73657
73974
|
prepareWidgetForPublish,
|
|
@@ -73745,6 +74062,7 @@ var controller = {
|
|
|
73745
74062
|
prepareThemeForPublish,
|
|
73746
74063
|
installThemeFromRegistry,
|
|
73747
74064
|
getThemePublishPreview,
|
|
74065
|
+
checkThemeUpdatesForApp,
|
|
73748
74066
|
prepareWidgetForPublish,
|
|
73749
74067
|
inspectWidgetPackage,
|
|
73750
74068
|
assignRoles,
|