@tutti-os/workspace-app-center 0.0.10 → 0.0.12
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/chunk-2HXFGEJS.js +110 -0
- package/dist/chunk-2HXFGEJS.js.map +1 -0
- package/dist/{chunk-INI5PAWK.js → chunk-O3XCZVHE.js} +157 -27
- package/dist/chunk-O3XCZVHE.js.map +1 -0
- package/dist/{chunk-VLUZD2IT.js → chunk-PD2WLRHE.js} +3 -2
- package/dist/chunk-PD2WLRHE.js.map +1 -0
- package/dist/{chunk-QSAEUGFC.js → chunk-Y63TZ5JT.js} +1 -1
- package/dist/chunk-Y63TZ5JT.js.map +1 -0
- package/dist/contracts/index.d.ts +11 -4
- package/dist/contracts/index.js +2 -2
- package/dist/core/index.d.ts +4 -4
- package/dist/core/index.js +3 -3
- package/dist/i18n/index.js +8 -4
- package/dist/i18n/index.js.map +1 -1
- package/dist/{index-DtpWU9o1.d.ts → index-DT5o9P2u.d.ts} +2 -2
- package/dist/index.d.ts +3 -3
- package/dist/index.js +4 -4
- package/dist/ui/index.d.ts +3 -3
- package/dist/ui/index.js +82 -71
- package/dist/ui/index.js.map +1 -1
- package/dist/{viewModel-D0XZxZmO.d.ts → viewModel-BpgU7_M1.d.ts} +19 -2
- package/package.json +3 -3
- package/dist/chunk-INI5PAWK.js.map +0 -1
- package/dist/chunk-LBSZLLZK.js +0 -94
- package/dist/chunk-LBSZLLZK.js.map +0 -1
- package/dist/chunk-QSAEUGFC.js.map +0 -1
- package/dist/chunk-VLUZD2IT.js.map +0 -1
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// src/core/appCenterAppOrdering.ts
|
|
2
|
+
var installableRecommendedAppIds = [
|
|
3
|
+
["ai-media-canvas", "media-canvas"],
|
|
4
|
+
["vibe-design"],
|
|
5
|
+
["group-chat"],
|
|
6
|
+
["automation"],
|
|
7
|
+
["daily-product-radar", "daily-tech-radar", "radar"]
|
|
8
|
+
];
|
|
9
|
+
var comingSoonRecommendedAppIds = [
|
|
10
|
+
"ai-ppt",
|
|
11
|
+
"ai-document",
|
|
12
|
+
"ai-sheet",
|
|
13
|
+
"open-cut",
|
|
14
|
+
"product-competition",
|
|
15
|
+
"design-review",
|
|
16
|
+
"calendar",
|
|
17
|
+
"document-summarizer"
|
|
18
|
+
];
|
|
19
|
+
var recommendedAppDisplayRankById = buildRecommendedAppDisplayRankById();
|
|
20
|
+
function sortMyAppsByCreatedDesc(apps) {
|
|
21
|
+
return [...apps].sort((left, right) => {
|
|
22
|
+
const createdOrder = (right.createdAtUnixMs ?? 0) - (left.createdAtUnixMs ?? 0);
|
|
23
|
+
if (createdOrder !== 0) {
|
|
24
|
+
return createdOrder;
|
|
25
|
+
}
|
|
26
|
+
const nameOrder = left.name.localeCompare(right.name);
|
|
27
|
+
if (nameOrder !== 0) {
|
|
28
|
+
return nameOrder;
|
|
29
|
+
}
|
|
30
|
+
return left.id.localeCompare(right.id);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
function sortRecommendedApps(apps) {
|
|
34
|
+
return [...apps].sort(compareRecommendedApps);
|
|
35
|
+
}
|
|
36
|
+
function sortRecommendedAppsForAllTab(apps) {
|
|
37
|
+
return [...apps].sort(compareRecommendedApps);
|
|
38
|
+
}
|
|
39
|
+
function compareRecommendedApps(left, right) {
|
|
40
|
+
const sectionOrder = getRecommendedAppSectionRank(left) - getRecommendedAppSectionRank(right);
|
|
41
|
+
if (sectionOrder !== 0) {
|
|
42
|
+
return sectionOrder;
|
|
43
|
+
}
|
|
44
|
+
const displayOrder = getRecommendedAppDisplayRank(left.id) - getRecommendedAppDisplayRank(right.id);
|
|
45
|
+
if (displayOrder !== 0) {
|
|
46
|
+
return displayOrder;
|
|
47
|
+
}
|
|
48
|
+
const comingSoonOrder = getRecommendedAppComingSoonRank(left) - getRecommendedAppComingSoonRank(right);
|
|
49
|
+
if (comingSoonOrder !== 0) {
|
|
50
|
+
return comingSoonOrder;
|
|
51
|
+
}
|
|
52
|
+
return left.name.localeCompare(right.name);
|
|
53
|
+
}
|
|
54
|
+
function buildRecommendedAppDisplayRankById() {
|
|
55
|
+
const rankById = /* @__PURE__ */ new Map();
|
|
56
|
+
let rank = 0;
|
|
57
|
+
for (const aliases of installableRecommendedAppIds) {
|
|
58
|
+
for (const appId of aliases) {
|
|
59
|
+
rankById.set(appId, rank);
|
|
60
|
+
}
|
|
61
|
+
rank += 1;
|
|
62
|
+
}
|
|
63
|
+
for (const appId of comingSoonRecommendedAppIds) {
|
|
64
|
+
rankById.set(appId, rank);
|
|
65
|
+
rank += 1;
|
|
66
|
+
}
|
|
67
|
+
return rankById;
|
|
68
|
+
}
|
|
69
|
+
function getRecommendedAppDisplayRank(appId) {
|
|
70
|
+
return recommendedAppDisplayRankById.get(appId.trim().toLowerCase()) ?? Number.MAX_SAFE_INTEGER;
|
|
71
|
+
}
|
|
72
|
+
function getRecommendedAppSectionRank(app) {
|
|
73
|
+
const normalizedAppId = app.id.trim().toLowerCase();
|
|
74
|
+
if (recommendedAppDisplayRankById.has(normalizedAppId)) {
|
|
75
|
+
return isConfiguredComingSoonApp(normalizedAppId) ? 1 : 0;
|
|
76
|
+
}
|
|
77
|
+
return getRecommendedAppComingSoonRank(app);
|
|
78
|
+
}
|
|
79
|
+
function isConfiguredComingSoonApp(appId) {
|
|
80
|
+
return comingSoonRecommendedAppIds.some(
|
|
81
|
+
(configuredAppId) => configuredAppId === appId
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
function getRecommendedAppComingSoonRank(app) {
|
|
85
|
+
return app.statusLabelKey === "status.comingSoon" || app.tags.some((tag) => tag.trim().toLowerCase() === "coming-soon") ? 1 : 0;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// src/core/appFactoryProviderDefaults.ts
|
|
89
|
+
var DEFAULT_APP_FACTORY_PROVIDER = "codex";
|
|
90
|
+
function resolveDefaultAppFactoryProvider(options, preferredProvider) {
|
|
91
|
+
const normalizedPreferredProvider = preferredProvider?.trim() ?? "";
|
|
92
|
+
return options.find(
|
|
93
|
+
(option) => normalizedPreferredProvider !== "" && option.disabled !== true && option.provider === normalizedPreferredProvider
|
|
94
|
+
)?.provider ?? options.find(
|
|
95
|
+
(option) => option.disabled !== true && option.provider === DEFAULT_APP_FACTORY_PROVIDER
|
|
96
|
+
)?.provider ?? options.find((option) => option.disabled !== true)?.provider ?? options.find((option) => option.provider === DEFAULT_APP_FACTORY_PROVIDER)?.provider ?? options[0]?.provider ?? "";
|
|
97
|
+
}
|
|
98
|
+
function resolveSelectedAppFactoryProvider(currentProvider, options, preferredProvider) {
|
|
99
|
+
return options.some((option) => option.provider === currentProvider) ? currentProvider : resolveDefaultAppFactoryProvider(options, preferredProvider);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export {
|
|
103
|
+
sortMyAppsByCreatedDesc,
|
|
104
|
+
sortRecommendedApps,
|
|
105
|
+
sortRecommendedAppsForAllTab,
|
|
106
|
+
DEFAULT_APP_FACTORY_PROVIDER,
|
|
107
|
+
resolveDefaultAppFactoryProvider,
|
|
108
|
+
resolveSelectedAppFactoryProvider
|
|
109
|
+
};
|
|
110
|
+
//# sourceMappingURL=chunk-2HXFGEJS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/appCenterAppOrdering.ts","../src/core/appFactoryProviderDefaults.ts"],"sourcesContent":["import type { AppCenterViewModel } from \"../contracts/viewModel.ts\";\n\nconst installableRecommendedAppIds = [\n [\"ai-media-canvas\", \"media-canvas\"],\n [\"vibe-design\"],\n [\"group-chat\"],\n [\"automation\"],\n [\"daily-product-radar\", \"daily-tech-radar\", \"radar\"]\n] as const;\n\nconst comingSoonRecommendedAppIds = [\n \"ai-ppt\",\n \"ai-document\",\n \"ai-sheet\",\n \"open-cut\",\n \"product-competition\",\n \"design-review\",\n \"calendar\",\n \"document-summarizer\"\n] as const;\n\nconst recommendedAppDisplayRankById = buildRecommendedAppDisplayRankById();\n\nexport function sortMyAppsByCreatedDesc(\n apps: readonly AppCenterViewModel[\"apps\"][number][]\n): AppCenterViewModel[\"apps\"] {\n return [...apps].sort((left, right) => {\n const createdOrder =\n (right.createdAtUnixMs ?? 0) - (left.createdAtUnixMs ?? 0);\n if (createdOrder !== 0) {\n return createdOrder;\n }\n const nameOrder = left.name.localeCompare(right.name);\n if (nameOrder !== 0) {\n return nameOrder;\n }\n return left.id.localeCompare(right.id);\n });\n}\n\nexport function sortRecommendedApps(\n apps: readonly AppCenterViewModel[\"apps\"][number][]\n): AppCenterViewModel[\"apps\"] {\n return [...apps].sort(compareRecommendedApps);\n}\n\nexport function sortRecommendedAppsForAllTab(\n apps: readonly AppCenterViewModel[\"apps\"][number][]\n): AppCenterViewModel[\"apps\"] {\n return [...apps].sort(compareRecommendedApps);\n}\n\nfunction compareRecommendedApps(\n left: AppCenterViewModel[\"apps\"][number],\n right: AppCenterViewModel[\"apps\"][number]\n): number {\n const sectionOrder =\n getRecommendedAppSectionRank(left) - getRecommendedAppSectionRank(right);\n if (sectionOrder !== 0) {\n return sectionOrder;\n }\n\n const displayOrder =\n getRecommendedAppDisplayRank(left.id) -\n getRecommendedAppDisplayRank(right.id);\n if (displayOrder !== 0) {\n return displayOrder;\n }\n\n const comingSoonOrder =\n getRecommendedAppComingSoonRank(left) -\n getRecommendedAppComingSoonRank(right);\n if (comingSoonOrder !== 0) {\n return comingSoonOrder;\n }\n\n return left.name.localeCompare(right.name);\n}\n\nfunction buildRecommendedAppDisplayRankById(): Map<string, number> {\n const rankById = new Map<string, number>();\n let rank = 0;\n\n for (const aliases of installableRecommendedAppIds) {\n for (const appId of aliases) {\n rankById.set(appId, rank);\n }\n rank += 1;\n }\n\n for (const appId of comingSoonRecommendedAppIds) {\n rankById.set(appId, rank);\n rank += 1;\n }\n\n return rankById;\n}\n\nfunction getRecommendedAppDisplayRank(appId: string): number {\n return (\n recommendedAppDisplayRankById.get(appId.trim().toLowerCase()) ??\n Number.MAX_SAFE_INTEGER\n );\n}\n\nfunction getRecommendedAppSectionRank(\n app: AppCenterViewModel[\"apps\"][number]\n): number {\n const normalizedAppId = app.id.trim().toLowerCase();\n if (recommendedAppDisplayRankById.has(normalizedAppId)) {\n return isConfiguredComingSoonApp(normalizedAppId) ? 1 : 0;\n }\n\n return getRecommendedAppComingSoonRank(app);\n}\n\nfunction isConfiguredComingSoonApp(appId: string): boolean {\n return comingSoonRecommendedAppIds.some(\n (configuredAppId) => configuredAppId === appId\n );\n}\n\nfunction getRecommendedAppComingSoonRank(\n app: AppCenterViewModel[\"apps\"][number]\n): number {\n return app.statusLabelKey === \"status.comingSoon\" ||\n app.tags.some((tag) => tag.trim().toLowerCase() === \"coming-soon\")\n ? 1\n : 0;\n}\n","export interface AppFactoryProviderDefaultOption {\n readonly disabled?: boolean;\n readonly provider: string;\n}\n\nexport const DEFAULT_APP_FACTORY_PROVIDER = \"codex\";\n\nexport function resolveDefaultAppFactoryProvider(\n options: readonly AppFactoryProviderDefaultOption[],\n preferredProvider?: string | null\n): string {\n const normalizedPreferredProvider = preferredProvider?.trim() ?? \"\";\n return (\n options.find(\n (option) =>\n normalizedPreferredProvider !== \"\" &&\n option.disabled !== true &&\n option.provider === normalizedPreferredProvider\n )?.provider ??\n options.find(\n (option) =>\n option.disabled !== true &&\n option.provider === DEFAULT_APP_FACTORY_PROVIDER\n )?.provider ??\n options.find((option) => option.disabled !== true)?.provider ??\n options.find((option) => option.provider === DEFAULT_APP_FACTORY_PROVIDER)\n ?.provider ??\n options[0]?.provider ??\n \"\"\n );\n}\n\nexport function resolveSelectedAppFactoryProvider(\n currentProvider: string,\n options: readonly AppFactoryProviderDefaultOption[],\n preferredProvider?: string | null\n): string {\n return options.some((option) => option.provider === currentProvider)\n ? currentProvider\n : resolveDefaultAppFactoryProvider(options, preferredProvider);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
workspaceAppManifestSchemaVersion
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-Y63TZ5JT.js";
|
|
4
4
|
|
|
5
5
|
// src/core/appCenterControllerHelpers.ts
|
|
6
6
|
function resolveAppRunDurationMs(startedAtUnixMs, now) {
|
|
@@ -24,6 +24,7 @@ function mergeWorkspaceAppCatalogFields(currentApp, snapshotApp) {
|
|
|
24
24
|
localizations: snapshotApp.localizations,
|
|
25
25
|
minimizeBehavior: snapshotApp.minimizeBehavior,
|
|
26
26
|
name: snapshotApp.name,
|
|
27
|
+
references: snapshotApp.references,
|
|
27
28
|
source: snapshotApp.source,
|
|
28
29
|
tags: snapshotApp.tags,
|
|
29
30
|
updateAvailable: snapshotApp.updateAvailable
|
|
@@ -35,10 +36,10 @@ function areWorkspaceAppCenterAppsEqual(left, right) {
|
|
|
35
36
|
}
|
|
36
37
|
return left.every((leftApp, index) => {
|
|
37
38
|
const rightApp = right[index];
|
|
38
|
-
return rightApp !== void 0 && leftApp.appId === rightApp.appId && leftApp.availableIconUrl === rightApp.availableIconUrl && leftApp.availableVersion === rightApp.availableVersion && leftApp.createdAtUnixMs === rightApp.createdAtUnixMs && leftApp.description === rightApp.description && leftApp.enabled === rightApp.enabled && leftApp.exportable === rightApp.exportable && leftApp.iconUrl === rightApp.iconUrl && leftApp.installed === rightApp.installed && areWorkspaceAppCenterLocalizationsEqual(
|
|
39
|
+
return rightApp !== void 0 && leftApp.appId === rightApp.appId && leftApp.availableIconUrl === rightApp.availableIconUrl && leftApp.availableVersion === rightApp.availableVersion && leftApp.createdAtUnixMs === rightApp.createdAtUnixMs && leftApp.description === rightApp.description && leftApp.enabled === rightApp.enabled && leftApp.exportable === rightApp.exportable && leftApp.iconUrl === rightApp.iconUrl && leftApp.installed === rightApp.installed && leftApp.installationId === rightApp.installationId && areWorkspaceAppCenterLocalizationsEqual(
|
|
39
40
|
leftApp.localizations ?? [],
|
|
40
41
|
rightApp.localizations ?? []
|
|
41
|
-
) && leftApp.minimizeBehavior === rightApp.minimizeBehavior && leftApp.name === rightApp.name && leftApp.runtimeStatus === rightApp.runtimeStatus && leftApp.source === rightApp.source && leftApp.stateRevision === rightApp.stateRevision && areStringArraysEqual(leftApp.tags ?? [], rightApp.tags ?? []) && (leftApp.updateAvailable ?? false) === (rightApp.updateAvailable ?? false) && leftApp.
|
|
42
|
+
) && leftApp.minimizeBehavior === rightApp.minimizeBehavior && leftApp.name === rightApp.name && leftApp.references.listSupported === rightApp.references.listSupported && leftApp.runtimeId === rightApp.runtimeId && leftApp.runtimeStatus === rightApp.runtimeStatus && leftApp.source === rightApp.source && leftApp.stateRevision === rightApp.stateRevision && areStringArraysEqual(leftApp.tags ?? [], rightApp.tags ?? []) && (leftApp.updateAvailable ?? false) === (rightApp.updateAvailable ?? false) && leftApp.launchUrl === rightApp.launchUrl && leftApp.version === rightApp.version && leftApp.windowMinHeight === rightApp.windowMinHeight && leftApp.windowMinWidth === rightApp.windowMinWidth;
|
|
42
43
|
});
|
|
43
44
|
}
|
|
44
45
|
function normalizeWorkspaceAppCenterViewState(value) {
|
|
@@ -463,7 +464,7 @@ var WorkspaceAppCenterControllerState = class extends WorkspaceAppCenterControll
|
|
|
463
464
|
const app = this.store.apps.find(
|
|
464
465
|
(candidate) => candidate.appId === input.appId
|
|
465
466
|
);
|
|
466
|
-
return app?.installed && app.runtimeStatus === "running" && app.
|
|
467
|
+
return app?.installed && app.runtimeStatus === "running" && app.launchUrl ? app : null;
|
|
467
468
|
}
|
|
468
469
|
markAppInstalling(appId, options = {}) {
|
|
469
470
|
this.store.apps = this.store.apps.map(
|
|
@@ -481,7 +482,7 @@ var WorkspaceAppCenterControllerState = class extends WorkspaceAppCenterControll
|
|
|
481
482
|
markEnabledAppsStarting() {
|
|
482
483
|
let changed = false;
|
|
483
484
|
this.store.apps = this.store.apps.map((app) => {
|
|
484
|
-
if (!app.enabled || !app.installed || app.runtimeStatus
|
|
485
|
+
if (!app.enabled || !app.installed || app.runtimeStatus !== "idle") {
|
|
485
486
|
return app;
|
|
486
487
|
}
|
|
487
488
|
changed = true;
|
|
@@ -655,14 +656,18 @@ var WorkspaceAppCenterController = class extends WorkspaceAppCenterControllerSta
|
|
|
655
656
|
if (currentLaunchableApp) {
|
|
656
657
|
return currentLaunchableApp;
|
|
657
658
|
}
|
|
659
|
+
const previousApps = this.store.apps;
|
|
658
660
|
this.markAppStarting(input.appId);
|
|
659
661
|
try {
|
|
660
|
-
const snapshot = await this.dependencies.gateway.
|
|
662
|
+
const snapshot = await this.dependencies.gateway.launchWorkspaceApp(
|
|
661
663
|
input.workspaceId,
|
|
662
664
|
input.appId
|
|
663
665
|
);
|
|
664
666
|
this.applySnapshot(input.workspaceId, snapshot);
|
|
665
667
|
} catch (error) {
|
|
668
|
+
if (this.store.workspaceId === input.workspaceId) {
|
|
669
|
+
this.store.apps = previousApps;
|
|
670
|
+
}
|
|
666
671
|
this.setOperationError(error, {
|
|
667
672
|
appId: input.appId,
|
|
668
673
|
operation: "workspace_app.prepare_launch",
|
|
@@ -974,12 +979,31 @@ var WorkspaceAppCenterController = class extends WorkspaceAppCenterControllerSta
|
|
|
974
979
|
}
|
|
975
980
|
}
|
|
976
981
|
async retryApp(input) {
|
|
977
|
-
this.
|
|
978
|
-
|
|
979
|
-
input.workspaceId,
|
|
980
|
-
input.appId
|
|
982
|
+
const app = this.store.apps.find(
|
|
983
|
+
(candidate) => candidate.appId === input.appId
|
|
981
984
|
);
|
|
982
|
-
this.
|
|
985
|
+
if (this.store.workspaceId !== input.workspaceId || !app?.installed || app.runtimeStatus !== "failed") {
|
|
986
|
+
return;
|
|
987
|
+
}
|
|
988
|
+
const previousApps = this.store.apps;
|
|
989
|
+
this.markAppStarting(input.appId);
|
|
990
|
+
try {
|
|
991
|
+
const snapshot = await this.dependencies.gateway.retryWorkspaceApp(
|
|
992
|
+
input.workspaceId,
|
|
993
|
+
input.appId
|
|
994
|
+
);
|
|
995
|
+
this.applySnapshot(input.workspaceId, snapshot);
|
|
996
|
+
} catch (error) {
|
|
997
|
+
if (this.store.workspaceId === input.workspaceId) {
|
|
998
|
+
this.store.apps = previousApps;
|
|
999
|
+
}
|
|
1000
|
+
this.setOperationError(error, {
|
|
1001
|
+
appId: input.appId,
|
|
1002
|
+
operation: "workspace_app.retry",
|
|
1003
|
+
uiAction: "retry_app",
|
|
1004
|
+
workspaceId: input.workspaceId
|
|
1005
|
+
});
|
|
1006
|
+
}
|
|
983
1007
|
}
|
|
984
1008
|
waitForLaunchableApp(input) {
|
|
985
1009
|
const current = this.resolveLaunchableApp(input);
|
|
@@ -1122,6 +1146,7 @@ function validateWorkspaceAppManifest(value) {
|
|
|
1122
1146
|
}
|
|
1123
1147
|
const icon = validateIcon(value.icon, issues);
|
|
1124
1148
|
const runtime = validateRuntime(value.runtime, issues);
|
|
1149
|
+
const references = validateReferences(value.references, issues);
|
|
1125
1150
|
const window = validateWindow(value.window, issues);
|
|
1126
1151
|
const author = validateAuthor(value.author, issues);
|
|
1127
1152
|
const tags = validateTags(value.tags, issues);
|
|
@@ -1145,6 +1170,7 @@ function validateWorkspaceAppManifest(value) {
|
|
|
1145
1170
|
description,
|
|
1146
1171
|
...icon ? { icon } : {},
|
|
1147
1172
|
runtime,
|
|
1173
|
+
...references ? { references } : {},
|
|
1148
1174
|
...window ? { window } : {},
|
|
1149
1175
|
...author ? { author } : {},
|
|
1150
1176
|
...tags ? { tags } : {},
|
|
@@ -1213,6 +1239,40 @@ function validateRuntime(value, issues) {
|
|
|
1213
1239
|
healthcheckPath
|
|
1214
1240
|
};
|
|
1215
1241
|
}
|
|
1242
|
+
function validateReferences(value, issues) {
|
|
1243
|
+
if (value === void 0) {
|
|
1244
|
+
return void 0;
|
|
1245
|
+
}
|
|
1246
|
+
if (!isRecord(value)) {
|
|
1247
|
+
issues.push({
|
|
1248
|
+
code: "manifest.references",
|
|
1249
|
+
message: "references must be an object when provided.",
|
|
1250
|
+
path: "$.references"
|
|
1251
|
+
});
|
|
1252
|
+
return void 0;
|
|
1253
|
+
}
|
|
1254
|
+
const unsupportedKey = Object.keys(value).find(
|
|
1255
|
+
(key) => key !== "listEndpoint"
|
|
1256
|
+
);
|
|
1257
|
+
if (unsupportedKey) {
|
|
1258
|
+
issues.push({
|
|
1259
|
+
code: "manifest.references",
|
|
1260
|
+
message: `references.${unsupportedKey} is unsupported.`,
|
|
1261
|
+
path: `$.references.${unsupportedKey}`
|
|
1262
|
+
});
|
|
1263
|
+
return void 0;
|
|
1264
|
+
}
|
|
1265
|
+
const listEndpoint = readOptionalString(value.listEndpoint);
|
|
1266
|
+
if (!listEndpoint || !isRelativeUrlPath(listEndpoint)) {
|
|
1267
|
+
issues.push({
|
|
1268
|
+
code: "manifest.references",
|
|
1269
|
+
message: "references.listEndpoint must be a relative URL path without query or fragment.",
|
|
1270
|
+
path: "$.references.listEndpoint"
|
|
1271
|
+
});
|
|
1272
|
+
return void 0;
|
|
1273
|
+
}
|
|
1274
|
+
return { listEndpoint };
|
|
1275
|
+
}
|
|
1216
1276
|
function validateWindow(value, issues) {
|
|
1217
1277
|
if (value === void 0) {
|
|
1218
1278
|
return void 0;
|
|
@@ -1402,6 +1462,17 @@ function readOptionalString(value) {
|
|
|
1402
1462
|
function isRelativePackagePath(value) {
|
|
1403
1463
|
return !value.startsWith("/") && !value.split(/[\\/]/u).includes("..");
|
|
1404
1464
|
}
|
|
1465
|
+
function isRelativeUrlPath(value) {
|
|
1466
|
+
if (!value || !value.startsWith("/") || value.startsWith("//") || value.includes("\0")) {
|
|
1467
|
+
return false;
|
|
1468
|
+
}
|
|
1469
|
+
try {
|
|
1470
|
+
const parsed = new URL(value, "http://tutti.local");
|
|
1471
|
+
return parsed.origin === "http://tutti.local" && parsed.pathname === value && parsed.search === "" && parsed.hash === "";
|
|
1472
|
+
} catch {
|
|
1473
|
+
return false;
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1405
1476
|
function isRecord(value) {
|
|
1406
1477
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1407
1478
|
}
|
|
@@ -1422,12 +1493,18 @@ var statusAliases = /* @__PURE__ */ new Map([
|
|
|
1422
1493
|
["preparing", "preparing"],
|
|
1423
1494
|
["ready", "idle"],
|
|
1424
1495
|
["running", "running"],
|
|
1496
|
+
["runner_unavailable", "unavailable"],
|
|
1497
|
+
["runtime_unavailable", "unavailable"],
|
|
1498
|
+
["sandbox_unavailable", "unavailable"],
|
|
1425
1499
|
["started", "running"],
|
|
1426
1500
|
["starting", "starting"],
|
|
1501
|
+
["stale", "unavailable"],
|
|
1427
1502
|
["stopped", "idle"],
|
|
1428
1503
|
["stopping", "stopping"],
|
|
1429
1504
|
["terminated", "idle"],
|
|
1430
|
-
["terminating", "stopping"]
|
|
1505
|
+
["terminating", "stopping"],
|
|
1506
|
+
["unavailable", "unavailable"],
|
|
1507
|
+
["unreachable", "unavailable"]
|
|
1431
1508
|
]);
|
|
1432
1509
|
function mapWorkspaceAppRuntimeStatus(value) {
|
|
1433
1510
|
if (typeof value !== "string") {
|
|
@@ -1479,6 +1556,12 @@ function resolveWorkspaceAppStatusPresentation(status) {
|
|
|
1479
1556
|
pulse: true,
|
|
1480
1557
|
tone: "amber"
|
|
1481
1558
|
};
|
|
1559
|
+
case "unavailable":
|
|
1560
|
+
return {
|
|
1561
|
+
labelKey: "status.unavailable",
|
|
1562
|
+
pulse: false,
|
|
1563
|
+
tone: "amber"
|
|
1564
|
+
};
|
|
1482
1565
|
case "idle":
|
|
1483
1566
|
return {
|
|
1484
1567
|
labelKey: "actions.openApp",
|
|
@@ -1496,21 +1579,20 @@ function createAppCenterViewModel({
|
|
|
1496
1579
|
replaceableIconAppIds = [],
|
|
1497
1580
|
runtimeStates = []
|
|
1498
1581
|
}) {
|
|
1499
|
-
const
|
|
1500
|
-
runtimeStates.map((state) => [
|
|
1501
|
-
state.appId,
|
|
1502
|
-
{
|
|
1503
|
-
...state,
|
|
1504
|
-
status: mapWorkspaceAppRuntimeStatus(state.status)
|
|
1505
|
-
}
|
|
1506
|
-
])
|
|
1507
|
-
);
|
|
1582
|
+
const runtimeStateMaps = createRuntimeStateMaps(runtimeStates);
|
|
1508
1583
|
const appFactoryJobByAppId = createAppFactoryJobByAppId(factoryJobs);
|
|
1509
1584
|
const replaceableIconAppIdSet = new Set(
|
|
1510
1585
|
replaceableIconAppIds.map((appId) => appId.trim()).filter(Boolean)
|
|
1511
1586
|
);
|
|
1512
1587
|
const appCards = apps.map((app) => {
|
|
1513
|
-
const
|
|
1588
|
+
const installationId = normalizeOptionalString(
|
|
1589
|
+
app.install?.installationId
|
|
1590
|
+
);
|
|
1591
|
+
const runtime = findRuntimeStateForApp(
|
|
1592
|
+
runtimeStateMaps,
|
|
1593
|
+
app.manifest.appId,
|
|
1594
|
+
installationId
|
|
1595
|
+
);
|
|
1514
1596
|
const factoryJob = appFactoryJobByAppId.get(app.manifest.appId);
|
|
1515
1597
|
const metadata = resolveWorkspaceAppCatalogMetadata({
|
|
1516
1598
|
catalog: app.catalog,
|
|
@@ -1523,9 +1605,15 @@ function createAppCenterViewModel({
|
|
|
1523
1605
|
const installed = Boolean(app.install);
|
|
1524
1606
|
const sourceKind = resolveCatalogSourceKind(app.catalog);
|
|
1525
1607
|
const localApp = sourceKind === "local";
|
|
1608
|
+
const runtimeId = normalizeOptionalString(runtime?.runtimeId);
|
|
1609
|
+
const launchUrl = normalizeOptionalString(runtime?.launchUrl);
|
|
1610
|
+
const installedVersion = normalizeOptionalString(app.install?.version);
|
|
1611
|
+
const manifestVersion = normalizeOptionalString(app.manifest.version);
|
|
1612
|
+
const displayVersion = installedVersion ?? manifestVersion;
|
|
1526
1613
|
const comingSoon = isComingSoonApp(metadata.tags) || isComingSoonApp(app.manifest.tags ?? []);
|
|
1527
1614
|
const busy = isBusyRuntimeStatus(status);
|
|
1528
|
-
const
|
|
1615
|
+
const unavailable = status === "unavailable";
|
|
1616
|
+
const canUpdate = !comingSoon && !busy && !unavailable && installed && (app.updateAvailable ?? false);
|
|
1529
1617
|
const canOpen = !comingSoon && installed && canOpenInstalledApp(status);
|
|
1530
1618
|
const canRetry = installed && status === "failed";
|
|
1531
1619
|
const primaryAction = resolvePrimaryAction({
|
|
@@ -1538,10 +1626,13 @@ function createAppCenterViewModel({
|
|
|
1538
1626
|
});
|
|
1539
1627
|
return {
|
|
1540
1628
|
id: app.manifest.appId,
|
|
1629
|
+
installationId,
|
|
1630
|
+
runtimeId,
|
|
1631
|
+
launchUrl,
|
|
1541
1632
|
name: metadata.name,
|
|
1542
1633
|
createdAtUnixMs: app.createdAtUnixMs ?? null,
|
|
1543
1634
|
...metadata.description ? { description: metadata.description } : {},
|
|
1544
|
-
...
|
|
1635
|
+
...displayVersion && !comingSoon ? { version: displayVersion } : {},
|
|
1545
1636
|
...app.availableVersion && !comingSoon ? { availableVersion: app.availableVersion } : {},
|
|
1546
1637
|
...app.category?.trim() ? { category: app.category.trim() } : {},
|
|
1547
1638
|
updateAvailable: app.updateAvailable ?? false,
|
|
@@ -1559,7 +1650,7 @@ function createAppCenterViewModel({
|
|
|
1559
1650
|
canDelete: localApp,
|
|
1560
1651
|
canReplaceIcon: replaceableIconAppIdSet.has(app.manifest.appId),
|
|
1561
1652
|
canOpenFolder: installed,
|
|
1562
|
-
canOpenPackageFolder: installed && localApp && Boolean(
|
|
1653
|
+
canOpenPackageFolder: installed && localApp && Boolean(displayVersion),
|
|
1563
1654
|
canOpenFactorySession: Boolean(factoryAgentSessionId),
|
|
1564
1655
|
canPublishFactoryUpdate: installed && factoryJob?.status === "ready" && Boolean(factoryJob.publishedVersion?.trim()),
|
|
1565
1656
|
canUninstall: installed,
|
|
@@ -1580,6 +1671,38 @@ function createAppCenterViewModel({
|
|
|
1580
1671
|
runningCount: appCards.filter((app) => app.status === "running").length
|
|
1581
1672
|
};
|
|
1582
1673
|
}
|
|
1674
|
+
function createRuntimeStateMaps(runtimeStates) {
|
|
1675
|
+
const fallbackByAppId = /* @__PURE__ */ new Map();
|
|
1676
|
+
const byInstallationId = /* @__PURE__ */ new Map();
|
|
1677
|
+
for (const state of runtimeStates) {
|
|
1678
|
+
const runtime = {
|
|
1679
|
+
...state,
|
|
1680
|
+
status: mapWorkspaceAppRuntimeStatus(state.status)
|
|
1681
|
+
};
|
|
1682
|
+
const installationId = normalizeOptionalString(runtime.installationId);
|
|
1683
|
+
if (installationId) {
|
|
1684
|
+
byInstallationId.set(installationId, runtime);
|
|
1685
|
+
continue;
|
|
1686
|
+
}
|
|
1687
|
+
const appId = normalizeOptionalString(runtime.appId);
|
|
1688
|
+
if (appId) {
|
|
1689
|
+
fallbackByAppId.set(appId, runtime);
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
return {
|
|
1693
|
+
fallbackByAppId,
|
|
1694
|
+
byInstallationId
|
|
1695
|
+
};
|
|
1696
|
+
}
|
|
1697
|
+
function findRuntimeStateForApp(maps, appId, installationId) {
|
|
1698
|
+
if (installationId) {
|
|
1699
|
+
const runtime = maps.byInstallationId.get(installationId);
|
|
1700
|
+
if (runtime) {
|
|
1701
|
+
return runtime;
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1704
|
+
return maps.fallbackByAppId.get(appId);
|
|
1705
|
+
}
|
|
1583
1706
|
function resolveCatalogSourceKind(catalog) {
|
|
1584
1707
|
return catalog?.source?.kind ?? "bundled";
|
|
1585
1708
|
}
|
|
@@ -1622,6 +1745,10 @@ function normalizeLocale(value) {
|
|
|
1622
1745
|
const normalized = value?.trim().replace(/_/gu, "-").toLowerCase() ?? "";
|
|
1623
1746
|
return normalized.length > 0 ? normalized : null;
|
|
1624
1747
|
}
|
|
1748
|
+
function normalizeOptionalString(value) {
|
|
1749
|
+
const normalized = value?.trim() ?? "";
|
|
1750
|
+
return normalized.length > 0 ? normalized : null;
|
|
1751
|
+
}
|
|
1625
1752
|
function resolvePrimaryAction(input) {
|
|
1626
1753
|
if (input.comingSoon) {
|
|
1627
1754
|
return "none";
|
|
@@ -1629,6 +1756,9 @@ function resolvePrimaryAction(input) {
|
|
|
1629
1756
|
if (isBusyRuntimeStatus(input.status)) {
|
|
1630
1757
|
return "none";
|
|
1631
1758
|
}
|
|
1759
|
+
if (input.status === "unavailable") {
|
|
1760
|
+
return "none";
|
|
1761
|
+
}
|
|
1632
1762
|
if (!input.installed) {
|
|
1633
1763
|
return "install";
|
|
1634
1764
|
}
|
|
@@ -1704,7 +1834,7 @@ function createFactoryJobViewModel(job) {
|
|
|
1704
1834
|
canFix: canFixValidationFailure,
|
|
1705
1835
|
canOpenAgentSession: Boolean(agentSessionId),
|
|
1706
1836
|
canPublish: job.status === "ready",
|
|
1707
|
-
canRetryValidation:
|
|
1837
|
+
canRetryValidation: false,
|
|
1708
1838
|
failureReason: job.failureReason,
|
|
1709
1839
|
updatedAtUnixMs: job.updatedAtUnixMs
|
|
1710
1840
|
};
|
|
@@ -1739,4 +1869,4 @@ export {
|
|
|
1739
1869
|
resolveWorkspaceAppCatalogMetadata,
|
|
1740
1870
|
createWorkspaceAppRecord
|
|
1741
1871
|
};
|
|
1742
|
-
//# sourceMappingURL=chunk-
|
|
1872
|
+
//# sourceMappingURL=chunk-O3XCZVHE.js.map
|