@go-go-golems/os-scripting 0.1.0

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.
Files changed (119) hide show
  1. package/README.md +147 -0
  2. package/app/createAppStore.d.ts +89 -0
  3. package/app/createAppStore.js +90 -0
  4. package/app/index.d.ts +2 -0
  5. package/app/index.js +2 -0
  6. package/app/runtimeSessionLifecycleMiddleware.d.ts +6 -0
  7. package/app/runtimeSessionLifecycleMiddleware.js +42 -0
  8. package/features/runtimeSessions/capabilityPolicy.d.ts +12 -0
  9. package/features/runtimeSessions/capabilityPolicy.js +36 -0
  10. package/features/runtimeSessions/index.d.ts +3 -0
  11. package/features/runtimeSessions/index.js +3 -0
  12. package/features/runtimeSessions/runtimeSessionsSlice.d.ts +90 -0
  13. package/features/runtimeSessions/runtimeSessionsSlice.js +210 -0
  14. package/features/runtimeSessions/selectors.d.ts +16 -0
  15. package/features/runtimeSessions/selectors.js +40 -0
  16. package/hypercard/artifacts/artifactProjectionMiddleware.d.ts +1 -0
  17. package/hypercard/artifacts/artifactProjectionMiddleware.js +66 -0
  18. package/hypercard/artifacts/artifactRuntime.d.ts +22 -0
  19. package/hypercard/artifacts/artifactRuntime.js +137 -0
  20. package/hypercard/artifacts/artifactsSelectors.d.ts +10 -0
  21. package/hypercard/artifacts/artifactsSelectors.js +2 -0
  22. package/hypercard/artifacts/artifactsSlice.d.ts +38 -0
  23. package/hypercard/artifacts/artifactsSlice.js +94 -0
  24. package/hypercard/debug/RuntimeSurfaceDebugWindow.d.ts +7 -0
  25. package/hypercard/debug/RuntimeSurfaceDebugWindow.js +181 -0
  26. package/hypercard/debug/jsSessionDebugRegistry.d.ts +11 -0
  27. package/hypercard/debug/jsSessionDebugRegistry.js +43 -0
  28. package/hypercard/debug/runtimeDebugApp.d.ts +19 -0
  29. package/hypercard/debug/runtimeDebugApp.js +25 -0
  30. package/hypercard/debug/runtimeDebugRegistry.d.ts +6 -0
  31. package/hypercard/debug/runtimeDebugRegistry.js +49 -0
  32. package/hypercard/editor/CodeEditorWindow.d.ts +7 -0
  33. package/hypercard/editor/CodeEditorWindow.js +128 -0
  34. package/hypercard/editor/editorLaunch.d.ts +16 -0
  35. package/hypercard/editor/editorLaunch.js +58 -0
  36. package/hypercard/editor/runtimeSurfaceRef.d.ts +8 -0
  37. package/hypercard/editor/runtimeSurfaceRef.js +60 -0
  38. package/hypercard/index.d.ts +12 -0
  39. package/hypercard/index.js +12 -0
  40. package/hypercard/task-manager/TaskManagerWindow.d.ts +1 -0
  41. package/hypercard/task-manager/TaskManagerWindow.js +102 -0
  42. package/hypercard/task-manager/index.d.ts +6 -0
  43. package/hypercard/task-manager/index.js +6 -0
  44. package/hypercard/task-manager/jsSessionSource.d.ts +10 -0
  45. package/hypercard/task-manager/jsSessionSource.js +49 -0
  46. package/hypercard/task-manager/runtimeSessionSource.d.ts +26 -0
  47. package/hypercard/task-manager/runtimeSessionSource.js +123 -0
  48. package/hypercard/task-manager/taskManagerApp.d.ts +16 -0
  49. package/hypercard/task-manager/taskManagerApp.js +25 -0
  50. package/hypercard/task-manager/taskManagerRegistry.d.ts +10 -0
  51. package/hypercard/task-manager/taskManagerRegistry.js +75 -0
  52. package/hypercard/task-manager/types.d.ts +25 -0
  53. package/hypercard/task-manager/types.js +1 -0
  54. package/hypercard/timeline/hypercardCard.d.ts +5 -0
  55. package/hypercard/timeline/hypercardCard.js +104 -0
  56. package/index.d.ts +18 -0
  57. package/index.js +18 -0
  58. package/package.json +72 -0
  59. package/plugin-runtime/contracts.d.ts +116 -0
  60. package/plugin-runtime/contracts.js +32 -0
  61. package/plugin-runtime/fixtures/column-stack.vm.js +19 -0
  62. package/plugin-runtime/fixtures/dynamic-card.vm.js +13 -0
  63. package/plugin-runtime/fixtures/inventory-stack.vm.js +29 -0
  64. package/plugin-runtime/fixtures/kanban-card.vm.js +55 -0
  65. package/plugin-runtime/fixtures/loop-stack.vm.js +16 -0
  66. package/plugin-runtime/fixtures/patched-low-stock-handler.vm.js +3 -0
  67. package/plugin-runtime/fixtures/patched-low-stock-render.vm.js +5 -0
  68. package/plugin-runtime/index.d.ts +6 -0
  69. package/plugin-runtime/index.js +6 -0
  70. package/plugin-runtime/intentSchema.d.ts +3 -0
  71. package/plugin-runtime/intentSchema.js +25 -0
  72. package/plugin-runtime/jsEvalSupport.d.ts +6 -0
  73. package/plugin-runtime/jsEvalSupport.js +93 -0
  74. package/plugin-runtime/jsSessionService.d.ts +55 -0
  75. package/plugin-runtime/jsSessionService.js +136 -0
  76. package/plugin-runtime/quickJsSessionCore.d.ts +24 -0
  77. package/plugin-runtime/quickJsSessionCore.js +92 -0
  78. package/plugin-runtime/runtimeService.d.ts +34 -0
  79. package/plugin-runtime/runtimeService.js +248 -0
  80. package/plugin-runtime/runtimeSurfaceRegistry.d.ts +45 -0
  81. package/plugin-runtime/runtimeSurfaceRegistry.js +73 -0
  82. package/plugin-runtime/stack-bootstrap.vm.js +236 -0
  83. package/repl/attachedJsSessionRegistry.d.ts +25 -0
  84. package/repl/attachedJsSessionRegistry.js +81 -0
  85. package/repl/attachedRuntimeSessionRegistry.d.ts +11 -0
  86. package/repl/attachedRuntimeSessionRegistry.js +107 -0
  87. package/repl/hypercardReplDriver.d.ts +54 -0
  88. package/repl/hypercardReplDriver.js +600 -0
  89. package/repl/jsReplDriver.d.ts +8 -0
  90. package/repl/jsReplDriver.js +348 -0
  91. package/repl/jsSessionBroker.d.ts +21 -0
  92. package/repl/jsSessionBroker.js +75 -0
  93. package/repl/runtimeBroker.d.ts +43 -0
  94. package/repl/runtimeBroker.js +117 -0
  95. package/runtime-host/RuntimeSurfaceSessionHost.d.ts +8 -0
  96. package/runtime-host/RuntimeSurfaceSessionHost.js +384 -0
  97. package/runtime-host/fixtures/CardSessionHost.chat.vm.js +61 -0
  98. package/runtime-host/fixtures/CardSessionHost.list.vm.js +29 -0
  99. package/runtime-host/fixtures/CardSessionHost.nav.vm.js +101 -0
  100. package/runtime-host/fixtures/CardSessionHost.report.vm.js +34 -0
  101. package/runtime-host/pluginIntentRouting.d.ts +13 -0
  102. package/runtime-host/pluginIntentRouting.js +83 -0
  103. package/runtime-packages/index.d.ts +1 -0
  104. package/runtime-packages/index.js +1 -0
  105. package/runtime-packages/runtimePackageRegistry.d.ts +14 -0
  106. package/runtime-packages/runtimePackageRegistry.js +42 -0
  107. package/runtime-packages/ui.package.vm.js +84 -0
  108. package/runtime-packs/index.d.ts +1 -0
  109. package/runtime-packs/index.js +1 -0
  110. package/runtime-packs/runtimeSurfaceTypeRegistry.d.ts +20 -0
  111. package/runtime-packs/runtimeSurfaceTypeRegistry.js +37 -0
  112. package/runtime-session-manager/index.d.ts +2 -0
  113. package/runtime-session-manager/index.js +2 -0
  114. package/runtime-session-manager/runtimeOwnership.d.ts +10 -0
  115. package/runtime-session-manager/runtimeOwnership.js +19 -0
  116. package/runtime-session-manager/runtimeSessionManager.d.ts +47 -0
  117. package/runtime-session-manager/runtimeSessionManager.js +214 -0
  118. package/testRuntimeUi.d.ts +4 -0
  119. package/testRuntimeUi.js +39 -0
@@ -0,0 +1,384 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useMemo, useRef } from 'react';
3
+ import { shallowEqual, useDispatch, useSelector, useStore } from 'react-redux';
4
+ import { showToast } from '@go-go-golems/os-core';
5
+ import { registerRuntimeSession, resolveCapabilityPolicy, selectRuntimeSurfaceState, selectProjectedRuntimeDomains, selectRuntimeSession, selectRuntimeSessionState, setRuntimeSessionStatus, } from '../features/runtimeSessions';
6
+ import { selectFocusedWindowId, selectSessionCurrentNav, selectSessionNavDepth } from '@go-go-golems/os-core/desktop-core';
7
+ import { markRuntimeSurfaceInjectionResults } from '../hypercard/artifacts/artifactsSlice';
8
+ import { getPendingRuntimeSurfaces, hasRuntimeSurface, injectPendingRuntimeSurfacesWithReport, onRegistryChange } from '../plugin-runtime/runtimeSurfaceRegistry';
9
+ import { DEFAULT_RUNTIME_SESSION_MANAGER } from '../runtime-session-manager';
10
+ import { dispatchRuntimeAction } from './pluginIntentRouting';
11
+ import { normalizeRuntimeSurfaceTypeId, renderRuntimeSurfaceTree, validateRuntimeSurfaceTree, } from '../runtime-packs';
12
+ function getPluginConfig(bundle) {
13
+ if (bundle.plugin && bundle.plugin.bundleCode.length > 0) {
14
+ return bundle.plugin;
15
+ }
16
+ return null;
17
+ }
18
+ function isRecord(value) {
19
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
20
+ }
21
+ function asArray(value) {
22
+ return Array.isArray(value) ? value : [];
23
+ }
24
+ function projectRuntimeState(domains, opts) {
25
+ const projectedDomains = { ...domains };
26
+ const inventory = isRecord(projectedDomains.inventory) ? projectedDomains.inventory : null;
27
+ const sales = isRecord(projectedDomains.sales) ? projectedDomains.sales : null;
28
+ if (inventory) {
29
+ projectedDomains.inventory = {
30
+ ...inventory,
31
+ items: asArray(inventory.items),
32
+ selectedSku: typeof opts.currentNavParam === 'string' ? opts.currentNavParam : undefined,
33
+ };
34
+ }
35
+ if (sales) {
36
+ projectedDomains.sales = {
37
+ ...sales,
38
+ log: asArray(sales.log),
39
+ };
40
+ }
41
+ return {
42
+ self: {
43
+ bundleId: opts.bundleId,
44
+ sessionId: opts.sessionId,
45
+ surfaceId: opts.surfaceId,
46
+ windowId: opts.windowId,
47
+ },
48
+ nav: {
49
+ current: opts.surfaceId,
50
+ param: opts.currentNavParam,
51
+ depth: opts.navDepth,
52
+ canBack: opts.navDepth > 1,
53
+ },
54
+ ui: {
55
+ focusedWindowId: opts.focusedWindowId,
56
+ runtimeStatus: opts.runtimeStatus,
57
+ },
58
+ filters: opts.sessionState,
59
+ draft: opts.surfaceState,
60
+ ...projectedDomains,
61
+ };
62
+ }
63
+ export function RuntimeSurfaceSessionHost({ windowId, sessionId, bundle, mode = 'interactive', }) {
64
+ const dispatch = useDispatch();
65
+ const store = useStore();
66
+ const pluginConfig = useMemo(() => getPluginConfig(bundle), [bundle]);
67
+ const currentNav = useSelector((state) => selectSessionCurrentNav(state, sessionId));
68
+ const navDepth = useSelector((state) => selectSessionNavDepth(state, sessionId));
69
+ const focusedWindowId = useSelector((state) => selectFocusedWindowId(state));
70
+ // Accept surfaces from the static bundle definition OR runtime-injected surfaces.
71
+ const currentSurfaceId = currentNav?.surface && (bundle.surfaces[currentNav.surface] || hasRuntimeSurface(currentNav.surface))
72
+ ? currentNav.surface
73
+ : bundle.homeSurface;
74
+ const runtimeSession = useSelector((state) => selectRuntimeSession(state, sessionId));
75
+ const sessionState = useSelector((state) => selectRuntimeSessionState(state, sessionId));
76
+ const surfaceState = useSelector((state) => selectRuntimeSurfaceState(state, sessionId, currentSurfaceId));
77
+ const projectedDomainAccess = useMemo(() => runtimeSession?.capabilities.domain ?? resolveCapabilityPolicy(pluginConfig?.capabilities).domain, [pluginConfig, runtimeSession?.capabilities.domain]);
78
+ const projectedDomains = useSelector((state) => selectProjectedRuntimeDomains(state, projectedDomainAccess), shallowEqual);
79
+ const loadedBundleRef = useRef(null);
80
+ const isPreview = mode === 'preview';
81
+ const localRuntimeReady = DEFAULT_RUNTIME_SESSION_MANAGER.getSession(sessionId) !== null;
82
+ const readRuntimeBundleMeta = useCallback((runtimeHandle) => {
83
+ if (loadedBundleRef.current) {
84
+ return loadedBundleRef.current;
85
+ }
86
+ if (!runtimeHandle) {
87
+ return null;
88
+ }
89
+ try {
90
+ const runtimeBundle = runtimeHandle.getBundleMeta();
91
+ loadedBundleRef.current = runtimeBundle;
92
+ return runtimeBundle;
93
+ }
94
+ catch {
95
+ return null;
96
+ }
97
+ }, []);
98
+ const resolveSurfacePackId = useCallback((surfaceId, runtimeHandle) => {
99
+ const runtimeSurface = getPendingRuntimeSurfaces().find((surface) => surface.surfaceId === surfaceId);
100
+ const runtimeBundle = readRuntimeBundleMeta(runtimeHandle);
101
+ return normalizeRuntimeSurfaceTypeId(runtimeSurface?.packId ?? runtimeBundle?.surfaceTypes?.[surfaceId]);
102
+ }, [readRuntimeBundleMeta]);
103
+ useEffect(() => {
104
+ if (!pluginConfig) {
105
+ return;
106
+ }
107
+ if (runtimeSession) {
108
+ return;
109
+ }
110
+ dispatch(registerRuntimeSession({
111
+ sessionId,
112
+ bundleId: bundle.id,
113
+ status: 'loading',
114
+ capabilities: pluginConfig.capabilities,
115
+ }));
116
+ }, [dispatch, pluginConfig, runtimeSession, sessionId, bundle.id]);
117
+ useEffect(() => {
118
+ if (!pluginConfig || !runtimeSession) {
119
+ return;
120
+ }
121
+ const runtimeStatus = runtimeSession.status;
122
+ const recoveringReadySession = runtimeStatus === 'ready' && !localRuntimeReady;
123
+ if (runtimeStatus !== 'loading' && !recoveringReadySession) {
124
+ return;
125
+ }
126
+ let cancelled = false;
127
+ const config = pluginConfig;
128
+ async function loadBundle() {
129
+ try {
130
+ if (recoveringReadySession) {
131
+ console.warn('[RuntimeSurfaceSessionHost] Recovering ready runtime session into fresh service', {
132
+ sessionId,
133
+ bundleId: bundle.id,
134
+ currentSurfaceId,
135
+ serviceSessions: DEFAULT_RUNTIME_SESSION_MANAGER.listSessions().map((session) => session.sessionId),
136
+ });
137
+ }
138
+ const runtimeHandle = await DEFAULT_RUNTIME_SESSION_MANAGER.ensureSession({
139
+ bundleId: bundle.id,
140
+ sessionId,
141
+ packageIds: config.packageIds,
142
+ bundleCode: config.bundleCode,
143
+ });
144
+ if (cancelled) {
145
+ return;
146
+ }
147
+ const runtimeBundle = runtimeHandle.getBundleMeta();
148
+ loadedBundleRef.current = runtimeBundle;
149
+ if (runtimeStatus === 'loading') {
150
+ dispatch(setRuntimeSessionStatus({ sessionId, status: 'ready' }));
151
+ }
152
+ // Inject any runtime surfaces that were registered before the session loaded
153
+ const report = injectPendingRuntimeSurfacesWithReport({
154
+ defineRuntimeSurface(_runtimeSessionId, surfaceId, code, packId) {
155
+ return runtimeHandle.defineSurface(surfaceId, code, packId);
156
+ },
157
+ }, sessionId);
158
+ if (report.injected.length > 0 || report.failed.length > 0) {
159
+ dispatch(markRuntimeSurfaceInjectionResults({
160
+ injectedSurfaceIds: report.injected,
161
+ failed: report.failed.map((item) => ({ surfaceId: item.surfaceId, error: item.error })),
162
+ }));
163
+ }
164
+ if (report.injected.length > 0) {
165
+ console.log(`[RuntimeSurfaceSessionHost] Injected ${report.injected.length} runtime surfaces into ${sessionId}:`, report.injected);
166
+ }
167
+ if (runtimeStatus === 'loading' &&
168
+ runtimeBundle.initialSessionState &&
169
+ typeof runtimeBundle.initialSessionState === 'object') {
170
+ dispatchRuntimeAction({
171
+ type: 'filters.patch',
172
+ payload: runtimeBundle.initialSessionState,
173
+ }, {
174
+ dispatch: (action) => dispatch(action),
175
+ getState: () => store.getState(),
176
+ sessionId,
177
+ surfaceId: currentSurfaceId,
178
+ windowId,
179
+ });
180
+ }
181
+ if (runtimeStatus === 'loading' &&
182
+ runtimeBundle.initialSurfaceState &&
183
+ typeof runtimeBundle.initialSurfaceState === 'object') {
184
+ for (const [surfaceId, value] of Object.entries(runtimeBundle.initialSurfaceState)) {
185
+ if (typeof value === 'object' && value !== null) {
186
+ dispatchRuntimeAction({
187
+ type: 'draft.patch',
188
+ payload: value,
189
+ }, {
190
+ dispatch: (action) => dispatch(action),
191
+ getState: () => store.getState(),
192
+ sessionId,
193
+ surfaceId,
194
+ windowId,
195
+ });
196
+ }
197
+ }
198
+ }
199
+ }
200
+ catch (error) {
201
+ if (cancelled) {
202
+ return;
203
+ }
204
+ const message = error instanceof Error ? error.message : String(error);
205
+ loadedBundleRef.current = null;
206
+ console.error('[RuntimeSurfaceSessionHost] Failed to load or recover runtime session', {
207
+ sessionId,
208
+ bundleId: bundle.id,
209
+ recoveringReadySession,
210
+ message,
211
+ });
212
+ dispatch(setRuntimeSessionStatus({ sessionId, status: 'error', error: message }));
213
+ }
214
+ }
215
+ void loadBundle();
216
+ return () => {
217
+ cancelled = true;
218
+ };
219
+ }, [bundle.id, currentSurfaceId, dispatch, localRuntimeReady, pluginConfig, runtimeSession, sessionId, store, windowId]);
220
+ // Subscribe to the runtime surface registry and inject new surfaces as they arrive.
221
+ useEffect(() => {
222
+ if (!pluginConfig || !runtimeSession || runtimeSession.status !== 'ready' || !localRuntimeReady) {
223
+ return;
224
+ }
225
+ const runtimeHandle = DEFAULT_RUNTIME_SESSION_MANAGER.getSession(sessionId);
226
+ if (!runtimeHandle) {
227
+ return;
228
+ }
229
+ return onRegistryChange(() => {
230
+ const report = injectPendingRuntimeSurfacesWithReport({
231
+ defineRuntimeSurface(_runtimeSessionId, surfaceId, code, packId) {
232
+ return runtimeHandle.defineSurface(surfaceId, code, packId);
233
+ },
234
+ }, sessionId);
235
+ if (report.injected.length > 0 || report.failed.length > 0) {
236
+ dispatch(markRuntimeSurfaceInjectionResults({
237
+ injectedSurfaceIds: report.injected,
238
+ failed: report.failed.map((item) => ({ surfaceId: item.surfaceId, error: item.error })),
239
+ }));
240
+ }
241
+ if (report.injected.length > 0) {
242
+ console.log(`[RuntimeSurfaceSessionHost] Live-injected ${report.injected.length} runtime surfaces into ${sessionId}:`, report.injected);
243
+ }
244
+ });
245
+ }, [dispatch, localRuntimeReady, pluginConfig, runtimeSession, sessionId]);
246
+ useEffect(() => {
247
+ if (!pluginConfig || !runtimeSession || runtimeSession.status !== 'ready' || !localRuntimeReady) {
248
+ return;
249
+ }
250
+ const runtimeHandle = DEFAULT_RUNTIME_SESSION_MANAGER.getSession(sessionId);
251
+ if (!runtimeHandle) {
252
+ return;
253
+ }
254
+ return runtimeHandle.attachView(windowId);
255
+ }, [localRuntimeReady, pluginConfig, runtimeSession, sessionId, windowId]);
256
+ useEffect(() => {
257
+ return () => {
258
+ loadedBundleRef.current = null;
259
+ };
260
+ }, []);
261
+ const projectState = useCallback(() => projectRuntimeState(projectedDomains, {
262
+ bundleId: bundle.id,
263
+ sessionId,
264
+ surfaceId: currentSurfaceId,
265
+ windowId,
266
+ navDepth,
267
+ currentNavParam: currentNav?.param,
268
+ focusedWindowId,
269
+ runtimeStatus: runtimeSession?.status ?? 'missing',
270
+ sessionState,
271
+ surfaceState,
272
+ }), [
273
+ projectedDomains,
274
+ bundle.id,
275
+ sessionId,
276
+ currentSurfaceId,
277
+ windowId,
278
+ navDepth,
279
+ currentNav?.param,
280
+ focusedWindowId,
281
+ runtimeSession?.status,
282
+ sessionState,
283
+ surfaceState,
284
+ ]);
285
+ const renderOutcome = useMemo(() => {
286
+ if (!pluginConfig || !runtimeSession || runtimeSession.status !== 'ready' || !localRuntimeReady) {
287
+ return { tree: null, packId: null, error: null };
288
+ }
289
+ const projectedState = projectState();
290
+ try {
291
+ const runtimeHandle = DEFAULT_RUNTIME_SESSION_MANAGER.getSession(sessionId);
292
+ if (!runtimeHandle) {
293
+ return { tree: null, packId: null, error: null };
294
+ }
295
+ const packId = resolveSurfacePackId(currentSurfaceId, runtimeHandle);
296
+ return {
297
+ tree: (() => {
298
+ const rawTree = runtimeHandle.renderSurface(currentSurfaceId, projectedState);
299
+ return rawTree === null ? null : validateRuntimeSurfaceTree(packId, rawTree);
300
+ })(),
301
+ packId,
302
+ error: null,
303
+ };
304
+ }
305
+ catch (error) {
306
+ return {
307
+ tree: null,
308
+ packId: null,
309
+ error: error instanceof Error ? error.message : String(error),
310
+ };
311
+ }
312
+ }, [currentSurfaceId, localRuntimeReady, pluginConfig, projectState, resolveSurfacePackId, runtimeSession, sessionId]);
313
+ const tree = renderOutcome.tree;
314
+ const packId = renderOutcome.packId;
315
+ const renderError = renderOutcome.error;
316
+ const lastRenderErrorRef = useRef(null);
317
+ useEffect(() => {
318
+ if (!renderError) {
319
+ lastRenderErrorRef.current = null;
320
+ return;
321
+ }
322
+ if (lastRenderErrorRef.current === renderError) {
323
+ return;
324
+ }
325
+ lastRenderErrorRef.current = renderError;
326
+ dispatch(showToast(renderError));
327
+ }, [dispatch, renderError]);
328
+ const emitRuntimeEvent = useCallback((handler, args) => {
329
+ if (!pluginConfig || !runtimeSession || runtimeSession.status !== 'ready' || !localRuntimeReady) {
330
+ return;
331
+ }
332
+ let actions;
333
+ try {
334
+ const projectedState = projectState();
335
+ const runtimeHandle = DEFAULT_RUNTIME_SESSION_MANAGER.getSession(sessionId);
336
+ if (!runtimeHandle) {
337
+ return;
338
+ }
339
+ actions = runtimeHandle.eventSurface(currentSurfaceId, handler, args, projectedState) ?? [];
340
+ }
341
+ catch (error) {
342
+ dispatch(showToast(error instanceof Error ? error.message : String(error)));
343
+ return;
344
+ }
345
+ actions.forEach((runtimeAction) => {
346
+ dispatchRuntimeAction(runtimeAction, {
347
+ dispatch: (action) => dispatch(action),
348
+ getState: () => store.getState(),
349
+ sessionId,
350
+ surfaceId: currentSurfaceId,
351
+ windowId,
352
+ });
353
+ });
354
+ }, [
355
+ currentSurfaceId,
356
+ dispatch,
357
+ localRuntimeReady,
358
+ pluginConfig,
359
+ projectState,
360
+ runtimeSession,
361
+ sessionId,
362
+ windowId,
363
+ store,
364
+ ]);
365
+ if (!pluginConfig) {
366
+ return _jsx("div", { style: { padding: 12, color: '#9f1d1d' }, children: "Plugin bundle configuration is required for this host." });
367
+ }
368
+ if (!runtimeSession || runtimeSession.status === 'loading' || (runtimeSession.status === 'ready' && !localRuntimeReady)) {
369
+ return _jsx("div", { style: { padding: 12 }, children: isPreview ? 'Loading plugin preview…' : 'Loading plugin runtime…' });
370
+ }
371
+ if (runtimeSession.status === 'error') {
372
+ return _jsxs("div", { style: { padding: 12, color: '#9f1d1d' }, children: ["Runtime error: ", runtimeSession.error] });
373
+ }
374
+ if (!tree) {
375
+ if (renderError) {
376
+ return _jsxs("div", { style: { padding: 12, color: '#9f1d1d' }, children: ["Runtime render error: ", renderError] });
377
+ }
378
+ return _jsxs("div", { style: { padding: 12 }, children: ["No plugin output for surface: ", currentSurfaceId] });
379
+ }
380
+ if (!packId) {
381
+ return _jsxs("div", { style: { padding: 12, color: '#9f1d1d' }, children: ["Runtime render error: Missing runtime surface type id for ", currentSurfaceId] });
382
+ }
383
+ return _jsx(_Fragment, { children: renderRuntimeSurfaceTree(packId, tree, emitRuntimeEvent) });
384
+ }
@@ -0,0 +1,61 @@
1
+ defineRuntimeBundle(({ ui }) => {
2
+ function asRecord(value) {
3
+ return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
4
+ }
5
+
6
+ return {
7
+ id: 'chat-demo',
8
+ title: 'Chat Demo',
9
+ packageIds: ["ui"],
10
+ initialSurfaceState: {
11
+ chat: {
12
+ draft: '',
13
+ messages: [
14
+ 'Hello! How can I help you today?',
15
+ 'Try asking about report export or low stock alerts.',
16
+ ],
17
+ },
18
+ },
19
+ surfaces: {
20
+ chat: {
21
+ packId: 'ui.card.v1',
22
+ render({ state }) {
23
+ const draftState = asRecord(state?.draft);
24
+ const messages = Array.isArray(draftState.messages) ? draftState.messages : [];
25
+ const draft = String(draftState.draft || '');
26
+
27
+ return ui.panel([
28
+ ui.text('Assistant'),
29
+ ui.column(messages.map((message) => ui.text('• ' + String(message)))),
30
+ ui.input(draft, { onChange: { handler: 'changeDraft' } }),
31
+ ui.row([
32
+ ui.button('Send', { onClick: { handler: 'send' } }),
33
+ ui.button('Clear', { onClick: { handler: 'clear' } }),
34
+ ]),
35
+ ]);
36
+ },
37
+ handlers: {
38
+ changeDraft({ dispatch }, args) {
39
+ dispatch({ type: 'draft.set', payload: { path: 'draft', value: asRecord(args).value } });
40
+ },
41
+ send({ state, dispatch }) {
42
+ const draftState = asRecord(state?.draft);
43
+ const draft = String(draftState.draft || '').trim();
44
+ if (!draft) return;
45
+ const messages = Array.isArray(draftState.messages) ? draftState.messages : [];
46
+ dispatch({
47
+ type: 'draft.patch',
48
+ payload: {
49
+ draft: '',
50
+ messages: messages.concat(['You: ' + draft, 'Assistant: Thanks, received.']).slice(-10),
51
+ },
52
+ });
53
+ },
54
+ clear({ dispatch }) {
55
+ dispatch({ type: 'draft.patch', payload: { draft: '', messages: [] } });
56
+ },
57
+ },
58
+ },
59
+ },
60
+ };
61
+ });
@@ -0,0 +1,29 @@
1
+ defineRuntimeBundle(({ ui }) => {
2
+ const ITEMS = [
3
+ ['W-1001', 'Widget A', 'Widgets', '$12.00', '45'],
4
+ ['G-2001', 'Gadget B', 'Gadgets', '$25.50', '38'],
5
+ ['P-3001', 'Doohickey C', 'Parts', '$8.75', '73'],
6
+ ['W-1002', 'Widget D', 'Widgets', '$15.00', '12'],
7
+ ['G-2002', 'Gizmo E', 'Gadgets', '$42.00', '5'],
8
+ ['P-3002', 'Thingamajig F', 'Parts', '$3.25', '120'],
9
+ ];
10
+
11
+ return {
12
+ id: 'list-demo',
13
+ title: 'List Demo',
14
+ packageIds: ["ui"],
15
+ surfaces: {
16
+ browse: {
17
+ packId: 'ui.card.v1',
18
+ render() {
19
+ return ui.panel([
20
+ ui.text('Browse Items'),
21
+ ui.table(ITEMS, { headers: ['SKU', 'Name', 'Category', 'Price', 'Qty'] }),
22
+ ui.text('Use Desktop Shell stories for richer interactions.'),
23
+ ]);
24
+ },
25
+ handlers: {},
26
+ },
27
+ },
28
+ };
29
+ });
@@ -0,0 +1,101 @@
1
+ defineRuntimeBundle(({ ui }) => {
2
+ function asRecord(value) {
3
+ return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
4
+ }
5
+
6
+ function navParam(state) {
7
+ const param = asRecord(asRecord(state).nav).param;
8
+ return typeof param === 'string' ? param : '';
9
+ }
10
+
11
+ function item(id) {
12
+ const records = {
13
+ 'widget-a': {
14
+ name: 'Widget A',
15
+ sku: 'W-1001',
16
+ category: 'Widgets',
17
+ price: '$12.00',
18
+ stock: '45 units',
19
+ supplier: 'Acme Corp',
20
+ lastRestock: 'Feb 10, 2026',
21
+ },
22
+ 'widget-b': {
23
+ name: 'Widget B',
24
+ sku: 'W-1002',
25
+ category: 'Widgets',
26
+ price: '$15.00',
27
+ stock: '12 units',
28
+ supplier: 'Acme Corp',
29
+ lastRestock: 'Feb 12, 2026',
30
+ },
31
+ 'widget-c': {
32
+ name: 'Widget C',
33
+ sku: 'W-1003',
34
+ category: 'Widgets',
35
+ price: '$19.00',
36
+ stock: '9 units',
37
+ supplier: 'Globex',
38
+ lastRestock: 'Feb 14, 2026',
39
+ },
40
+ };
41
+ return records[id] || records['widget-a'];
42
+ }
43
+
44
+ return {
45
+ id: 'nav-demo',
46
+ title: 'Nav Demo',
47
+ packageIds: ["ui"],
48
+ surfaces: {
49
+ list: {
50
+ packId: 'ui.card.v1',
51
+ render() {
52
+ return ui.panel([
53
+ ui.text('Items'),
54
+ ui.button('🔍 View Widget A', { onClick: { handler: 'go', args: { surfaceId: 'detail', param: 'widget-a' } } }),
55
+ ui.button('🔍 View Widget B', { onClick: { handler: 'go', args: { surfaceId: 'detail', param: 'widget-b' } } }),
56
+ ui.button('🔍 View Widget C', { onClick: { handler: 'go', args: { surfaceId: 'detail', param: 'widget-c' } } }),
57
+ ]);
58
+ },
59
+ handlers: {
60
+ go({ dispatch }, args) {
61
+ const payload = asRecord(args);
62
+ dispatch({ type: 'nav.go', payload: { surfaceId: String(payload.surfaceId || 'list'), param: String(payload.param || '') } });
63
+ },
64
+ },
65
+ },
66
+ detail: {
67
+ packId: 'ui.card.v1',
68
+ render({ state }) {
69
+ const current = item(navParam(state));
70
+ return ui.panel([
71
+ ui.text('Item Detail'),
72
+ ui.table(
73
+ [
74
+ ['Name', current.name],
75
+ ['SKU', current.sku],
76
+ ['Category', current.category],
77
+ ['Price', current.price],
78
+ ['Stock', current.stock],
79
+ ['Supplier', current.supplier],
80
+ ['Last Restock', current.lastRestock],
81
+ ],
82
+ { headers: ['Field', 'Value'] }
83
+ ),
84
+ ui.row([
85
+ ui.button('← Back', { onClick: { handler: 'back' } }),
86
+ ui.button('🛒 Reorder', { onClick: { handler: 'notify', args: { message: 'Reorder placed' } } }),
87
+ ]),
88
+ ]);
89
+ },
90
+ handlers: {
91
+ back({ dispatch }) {
92
+ dispatch({ type: 'nav.back' });
93
+ },
94
+ notify({ dispatch }, args) {
95
+ dispatch({ type: 'notify.show', payload: { message: String(asRecord(args).message || '') } });
96
+ },
97
+ },
98
+ },
99
+ },
100
+ };
101
+ });
@@ -0,0 +1,34 @@
1
+ defineRuntimeBundle(({ ui }) => {
2
+ return {
3
+ id: 'report-demo',
4
+ title: 'Report Demo',
5
+ packageIds: ["ui"],
6
+ surfaces: {
7
+ report: {
8
+ packId: 'ui.card.v1',
9
+ render() {
10
+ return ui.panel([
11
+ ui.text('Monthly Report'),
12
+ ui.table(
13
+ [
14
+ ['Gross Revenue', '$12,450.00'],
15
+ ['Net Revenue', '$10,830.00'],
16
+ ['Refunds', '$620.00'],
17
+ ['Items in Stock', '156'],
18
+ ['Low Stock Alerts', '3'],
19
+ ['Out of Stock', '0'],
20
+ ],
21
+ { headers: ['Metric', 'Value'] }
22
+ ),
23
+ ui.button('📄 Export CSV', { onClick: { handler: 'notify' } }),
24
+ ]);
25
+ },
26
+ handlers: {
27
+ notify({ dispatch }) {
28
+ dispatch({ type: 'notify.show', payload: { message: 'Export not available in demo' } });
29
+ },
30
+ },
31
+ },
32
+ },
33
+ };
34
+ });
@@ -0,0 +1,13 @@
1
+ import type { RuntimeAction } from '../plugin-runtime/contracts';
2
+ interface DispatchLike {
3
+ (action: unknown): unknown;
4
+ }
5
+ interface ActionDispatchContext {
6
+ dispatch: DispatchLike;
7
+ getState?: () => unknown;
8
+ sessionId: string;
9
+ surfaceId: string;
10
+ windowId: string;
11
+ }
12
+ export declare function dispatchRuntimeAction(action: RuntimeAction, context: ActionDispatchContext): void;
13
+ export {};