@ggui-ai/dev-stack 0.2.0-alpha.3 → 0.3.0-rc.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.
package/dist/index.d.ts CHANGED
@@ -21,15 +21,13 @@
21
21
  * adapter seam.
22
22
  */
23
23
  export { LocalUiRegistry, type LocalUiRegistryOptions, type LocalBundleResult, type BundleErrorLocation, } from './local-registry/local-registry.js';
24
- export { discoverLocalUis, discoverFromGguiJsonPath, type DiscoveredUi, type DiscoveryIssue, type DiscoveryResult, type DiscoverOptions, } from '@ggui-ai/project-config/node';
25
- export { compileUiOnDemand, resolveEntryFile, COMPILED_BUNDLE_CONTENT_TYPE, type CompileResult, } from './local-registry/compile-ui.js';
24
+ export { compileUiOnDemand, resolveEntryFile, COMPILED_BUNDLE_CONTENT_TYPE, SANDBOX_EXTERNALS, type CompileResult, } from './local-registry/compile-ui.js';
26
25
  export { createLocalWatcher, statOrNull, type LocalWatcher, type LocalWatcherOptions, type WatchListener, } from './local-registry/watcher.js';
27
26
  export { startDevServer, type DevServerOptions, type DevServerHandle, } from './dev-server/http.js';
28
27
  export { openEventStream, type SseOptions } from './dev-server/events.js';
29
28
  export { renderHubHtml, serveHubShell, type HubShellContext, } from './dev-server/hub.js';
30
29
  export { renderHubPreviewHtml, serveHubPreviewShell, serveHubPreviewBundle, resolveHubPreviewBundlePath, extractSelectedId, type HubPreviewShellContext, } from './dev-server/hub-preview.js';
31
30
  export { createSecurityPolicy, type CreatePolicyOptions, type DevServerSecurityPolicy, type PolicyOutcome, } from './dev-server/auth.js';
32
- export { startSandboxProxyServer, type SandboxProxyServerOptions, type SandboxProxyServerHandle, } from './dev-server/sandbox-proxy.js';
33
31
  export { runDev, GguiDevError, DEFAULT_DEV_PORT, DEFAULT_DEV_HOST, type DevOptions, type DevBootstrap, } from './run-dev.js';
34
32
  export { RuntimeSupervisor, DEFAULT_RUNTIME_BUFFER_SIZE, emptyRuntimeSnapshot, formatRuntimeEventLine, type RuntimeSupervisorOptions, type RuntimeStateSnapshot, type EmptyRuntimeStateSnapshot, type AnyRuntimeStateSnapshot, type RuntimeEventRecord, } from './runtime-supervisor.js';
35
33
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,EACL,eAAe,EACf,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,GACzB,MAAM,oCAAoC,CAAC;AAM5C,OAAO,EACL,gBAAgB,EAChB,wBAAwB,EACxB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,eAAe,GACrB,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,4BAA4B,EAC5B,KAAK,aAAa,GACnB,MAAM,gCAAgC,CAAC;AAGxC,OAAO,EACL,kBAAkB,EAClB,UAAU,EACV,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,aAAa,GACnB,MAAM,6BAA6B,CAAC;AAGrC,OAAO,EACL,cAAc,EACd,KAAK,gBAAgB,EACrB,KAAK,eAAe,GACrB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAAE,eAAe,EAAE,KAAK,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAG1E,OAAO,EACL,aAAa,EACb,aAAa,EACb,KAAK,eAAe,GACrB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,qBAAqB,EACrB,2BAA2B,EAC3B,iBAAiB,EACjB,KAAK,sBAAsB,GAC5B,MAAM,6BAA6B,CAAC;AAGrC,OAAO,EACL,oBAAoB,EACpB,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC5B,KAAK,aAAa,GACnB,MAAM,sBAAsB,CAAC;AAK9B,OAAO,EACL,uBAAuB,EACvB,KAAK,yBAAyB,EAC9B,KAAK,wBAAwB,GAC9B,MAAM,+BAA+B,CAAC;AAGvC,OAAO,EACL,MAAM,EACN,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,KAAK,UAAU,EACf,KAAK,YAAY,GAClB,MAAM,cAAc,CAAC;AAKtB,OAAO,EACL,iBAAiB,EACjB,2BAA2B,EAC3B,oBAAoB,EACpB,sBAAsB,EACtB,KAAK,wBAAwB,EAC7B,KAAK,oBAAoB,EACzB,KAAK,yBAAyB,EAC9B,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,GACxB,MAAM,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,EACL,eAAe,EACf,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,GACzB,MAAM,oCAAoC,CAAC;AAG5C,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,4BAA4B,EAC5B,iBAAiB,EACjB,KAAK,aAAa,GACnB,MAAM,gCAAgC,CAAC;AAGxC,OAAO,EACL,kBAAkB,EAClB,UAAU,EACV,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,aAAa,GACnB,MAAM,6BAA6B,CAAC;AAGrC,OAAO,EACL,cAAc,EACd,KAAK,gBAAgB,EACrB,KAAK,eAAe,GACrB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAAE,eAAe,EAAE,KAAK,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAG1E,OAAO,EACL,aAAa,EACb,aAAa,EACb,KAAK,eAAe,GACrB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,qBAAqB,EACrB,2BAA2B,EAC3B,iBAAiB,EACjB,KAAK,sBAAsB,GAC5B,MAAM,6BAA6B,CAAC;AAGrC,OAAO,EACL,oBAAoB,EACpB,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC5B,KAAK,aAAa,GACnB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EACL,MAAM,EACN,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,KAAK,UAAU,EACf,KAAK,YAAY,GAClB,MAAM,cAAc,CAAC;AAKtB,OAAO,EACL,iBAAiB,EACjB,2BAA2B,EAC3B,oBAAoB,EACpB,sBAAsB,EACtB,KAAK,wBAAwB,EAC7B,KAAK,oBAAoB,EACzB,KAAK,yBAAyB,EAC9B,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,GACxB,MAAM,yBAAyB,CAAC"}
package/dist/index.js CHANGED
@@ -22,13 +22,8 @@
22
22
  */
23
23
  // Local UI registry
24
24
  export { LocalUiRegistry, } from './local-registry/local-registry.js';
25
- // Discovery — re-export from @ggui-ai/project-config/node for
26
- // consumers that have historically imported these symbols from the
27
- // dev-stack barrel. The canonical home is the schema-owner package;
28
- // dev-stack's `LocalUiRegistry` consumes the same helper directly.
29
- export { discoverLocalUis, discoverFromGguiJsonPath, } from '@ggui-ai/project-config/node';
30
25
  // Compile-on-demand
31
- export { compileUiOnDemand, resolveEntryFile, COMPILED_BUNDLE_CONTENT_TYPE, } from './local-registry/compile-ui.js';
26
+ export { compileUiOnDemand, resolveEntryFile, COMPILED_BUNDLE_CONTENT_TYPE, SANDBOX_EXTERNALS, } from './local-registry/compile-ui.js';
32
27
  // Watcher
33
28
  export { createLocalWatcher, statOrNull, } from './local-registry/watcher.js';
34
29
  // HTTP dev server
@@ -41,10 +36,6 @@ export { renderHubHtml, serveHubShell, } from './dev-server/hub.js';
41
36
  export { renderHubPreviewHtml, serveHubPreviewShell, serveHubPreviewBundle, resolveHubPreviewBundlePath, extractSelectedId, } from './dev-server/hub-preview.js';
42
37
  // Auth / CORS policy
43
38
  export { createSecurityPolicy, } from './dev-server/auth.js';
44
- // MCP-Apps sandbox proxy — second HTTP server on a different origin
45
- // that serves `sandbox.html` for `<AppRenderer>`'s two-iframe
46
- // sandboxing pattern (R5; see ./dev-server/sandbox-proxy.ts).
47
- export { startSandboxProxyServer, } from './dev-server/sandbox-proxy.js';
48
39
  // Orchestration — the seam every local-dev host composes against.
49
40
  export { runDev, GguiDevError, DEFAULT_DEV_PORT, DEFAULT_DEV_HOST, } from './run-dev.js';
50
41
  // Runtime supervision — ring-buffered view of the supervised agent
@@ -1,5 +1,13 @@
1
1
  import { type Message } from 'esbuild';
2
2
  import type { UiManifest } from '@ggui-ai/project-config';
3
+ /**
4
+ * Packages the runtime renderer already resolves from its
5
+ * own bundle (via `@ggui-ai/design/module-loader`'s import-map).
6
+ * Keeping them out of the compiled bundle keeps the artifact small
7
+ * and lets the rendering host's in-tree React instance be shared
8
+ * across every rendered UI.
9
+ */
10
+ export declare const SANDBOX_EXTERNALS: string[];
3
11
  /** Content type the compiled bundle is served with. Matches the
4
12
  * precompiled path for consistency. */
5
13
  export declare const COMPILED_BUNDLE_CONTENT_TYPE = "application/javascript+react";
@@ -1 +1 @@
1
- {"version":3,"file":"compile-ui.d.ts","sourceRoot":"","sources":["../../src/local-registry/compile-ui.ts"],"names":[],"mappings":"AAoCA,OAAO,EAA4B,KAAK,OAAO,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AA6B1D;uCACuC;AACvC,eAAO,MAAM,4BAA4B,iCAAiC,CAAC;AAE3E,MAAM,WAAW,aAAa;IAC5B,gEAAgE;IAChE,WAAW,EAAE,MAAM,CAAC;IACpB,+DAA+D;IAC/D,YAAY,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,QAAQ,EAAE,UAAU,CAAC;CACtB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,IAAI,CAAC;IACX,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,eAAe,CAAC;IACtB;;;;OAIG;IACH,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,EAAE,CAAC;IAClB,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,mBAAmB,GAAG,cAAc,CAAC;AAE7E;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,CAkB/F;AAED;;;;;;;;;GASG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAqCrF"}
1
+ {"version":3,"file":"compile-ui.d.ts","sourceRoot":"","sources":["../../src/local-registry/compile-ui.ts"],"names":[],"mappings":"AAqCA,OAAO,EAA4B,KAAK,OAAO,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAE1D;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,UAW7B,CAAC;AASF;uCACuC;AACvC,eAAO,MAAM,4BAA4B,iCAAiC,CAAC;AAE3E,MAAM,WAAW,aAAa;IAC5B,gEAAgE;IAChE,WAAW,EAAE,MAAM,CAAC;IACpB,+DAA+D;IAC/D,YAAY,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,QAAQ,EAAE,UAAU,CAAC;CACtB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,IAAI,CAAC;IACX,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,eAAe,CAAC;IACtB;;;;OAIG;IACH,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,EAAE,CAAC;IAClB,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,mBAAmB,GAAG,cAAc,CAAC;AAE7E;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,CAkB/F;AAED;;;;;;;;;GASG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAqCrF"}
@@ -2,10 +2,11 @@
2
2
  * Compile-on-demand for local `ggui dev` UIs.
3
3
  *
4
4
  * Resolves the authored TSX entry for a `ggui.ui.json` and runs
5
- * esbuild against it, producing an ESM bundle Studio can hand to
6
- * `DynamicComponent`. This replaces the "must pre-compile" state
7
- * the foundation slice left behind — `ggui dev` now feels like a
8
- * real dev server: start it, open Studio, see the render.
5
+ * esbuild against it, producing an ESM bundle an authoring UI can
6
+ * hand to `DynamicComponent`. This replaces the "must pre-compile"
7
+ * state the foundation slice left behind — `ggui dev` now feels
8
+ * like a real dev server: start it, open the authoring UI, see the
9
+ * render.
9
10
  *
10
11
  * Trust model:
11
12
  *
@@ -23,11 +24,11 @@
23
24
  *
24
25
  * - esbuild `build` mode with bundle: true, so multi-file UIs
25
26
  * work (import sibling helpers, theme tokens, wire hooks).
26
- * - Sandbox externals match the runtime Studio renderer
27
+ * - Sandbox externals match the runtime renderer
27
28
  * (`DynamicComponent` in `@ggui-ai/react`). React, the design
28
29
  * system, `@ggui-ai/wire`, and `@ggui-ai/react` stay external
29
- * and resolve against the import map Studio provides at
30
- * render time.
30
+ * and resolve against the import map the rendering host
31
+ * provides at render time.
31
32
  * - No caching. Every request recompiles. esbuild TSX transform
32
33
  * is ~50-200ms for a typical single-screen UI — fine for the
33
34
  * dev loop. A watcher-driven cache lands with HMR, not here.
@@ -36,13 +37,13 @@ import { existsSync } from 'node:fs';
36
37
  import { dirname, isAbsolute, resolve } from 'node:path';
37
38
  import { build } from 'esbuild';
38
39
  /**
39
- * Packages the Studio runtime renderer already resolves from its
40
+ * Packages the runtime renderer already resolves from its
40
41
  * own bundle (via `@ggui-ai/design/module-loader`'s import-map).
41
42
  * Keeping them out of the compiled bundle keeps the artifact small
42
- * and lets Studio's in-tree React instance be shared across every
43
- * rendered UI.
43
+ * and lets the rendering host's in-tree React instance be shared
44
+ * across every rendered UI.
44
45
  */
45
- const SANDBOX_EXTERNALS = [
46
+ export const SANDBOX_EXTERNALS = [
46
47
  'react',
47
48
  'react/*',
48
49
  'react-dom',
@@ -1 +1 @@
1
- {"version":3,"file":"local-registry.d.ts","sourceRoot":"","sources":["../../src/local-registry/local-registry.ts"],"names":[],"mappings":"AAmCA,OAAO,KAAK,EACV,QAAQ,EACR,eAAe,EACf,UAAU,EACV,sBAAsB,EACvB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,UAAU,EAChB,MAAM,8BAA8B,CAAC;AAOtC,OAAO,EAAyC,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAQzF,MAAM,WAAW,sBAAsB;IACrC,gEAAgE;IAChE,WAAW,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,QAAQ,EAAE,UAAU,CAAC;CACtB;AAED;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GACzB;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,aAAa,GAAG,UAAU,CAAA;CAAE,GACpE;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,GAC1C;IACE,IAAI,EAAE,gBAAgB,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;IACtE,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;CACzE,CAAC;AAEN,0DAA0D;AAC1D,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,eAAgB,YAAW,UAAU;IAChD,QAAQ,CAAC,YAAY,EAAE,sBAAsB,CAG3C;IAEF,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAa;IACtC,OAAO,CAAC,WAAW,CAAmC;IACtD;oEACgE;IAChE,OAAO,CAAC,gBAAgB,CAA6B;IACrD,OAAO,CAAC,UAAU,CAAwB;IAC1C,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAA6B;gBAEhC,OAAO,EAAE,sBAAsB;IAK3C;;;;;OAKG;IACG,OAAO,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,cAAc,EAAE,CAAA;KAAE,CAAC;IAkBvE;;;;;;;OAOG;IACH,SAAS,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,IAAI;IAU9C,yDAAyD;IACnD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAO5B,OAAO,CAAC,aAAa;IAYrB,kEAAkE;IAClE,SAAS,IAAI,SAAS,cAAc,EAAE;IAIhC,IAAI,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;IAKlC,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC;IAMrD,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC;IAK1D;;;;;OAKG;IACG,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;YA0D3C,YAAY;CAK3B"}
1
+ {"version":3,"file":"local-registry.d.ts","sourceRoot":"","sources":["../../src/local-registry/local-registry.ts"],"names":[],"mappings":"AAkCA,OAAO,KAAK,EACV,QAAQ,EACR,eAAe,EACf,UAAU,EACV,sBAAsB,EACvB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,UAAU,EAChB,MAAM,8BAA8B,CAAC;AAOtC,OAAO,EAAyC,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAQzF,MAAM,WAAW,sBAAsB;IACrC,gEAAgE;IAChE,WAAW,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,QAAQ,EAAE,UAAU,CAAC;CACtB;AAED;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GACzB;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,aAAa,GAAG,UAAU,CAAA;CAAE,GACpE;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,GAC1C;IACE,IAAI,EAAE,gBAAgB,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;IACtE,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;CACzE,CAAC;AAEN,0DAA0D;AAC1D,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,eAAgB,YAAW,UAAU;IAChD,QAAQ,CAAC,YAAY,EAAE,sBAAsB,CAE3C;IAEF,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAa;IACtC,OAAO,CAAC,WAAW,CAAmC;IACtD;oEACgE;IAChE,OAAO,CAAC,gBAAgB,CAA6B;IACrD,OAAO,CAAC,UAAU,CAAwB;IAC1C,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAA6B;gBAEhC,OAAO,EAAE,sBAAsB;IAK3C;;;;;OAKG;IACG,OAAO,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,cAAc,EAAE,CAAA;KAAE,CAAC;IAkBvE;;;;;;;OAOG;IACH,SAAS,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,IAAI;IAU9C,yDAAyD;IACnD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAO5B,OAAO,CAAC,aAAa;IAYrB,kEAAkE;IAClE,SAAS,IAAI,SAAS,cAAc,EAAE;IAIhC,IAAI,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;IAKlC,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC;IAMrD,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC;IAK1D;;;;;OAKG;IACG,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;YA0D3C,YAAY;CAK3B"}
@@ -4,13 +4,12 @@
4
4
  *
5
5
  * Scope (compile-on-demand slice, 2026-04-18):
6
6
  *
7
- * - Read-only. `capabilities.writable === false`;
8
- * `capabilities.observable === false`.
7
+ * - Read-only — the `UiRegistry` contract has no write arm;
8
+ * `capabilities.observable === true` (watcher-backed).
9
9
  * - Manifest-backed. Discovery runs against `ggui.json` +
10
10
  * `blueprints.include` globs via `./discovery.js` and is
11
11
  * cached in memory. `refresh()` re-runs discovery on demand;
12
- * file watching / `subscribe()` lands with a follow-up
13
- * HMR slice.
12
+ * `subscribe()` is watcher-backed (see `./watcher.ts`).
14
13
  * - `getBundle(id)` resolution order:
15
14
  * 1. **Precompiled fast-path** — colocated `ggui.ui.js` or
16
15
  * `ggui.ui.mjs` beside the manifest. Lets a project with
@@ -42,7 +41,6 @@ const BUNDLE_FILENAMES = ['ggui.ui.js', 'ggui.ui.mjs'];
42
41
  const BUNDLE_CONTENT_TYPE = 'application/javascript+react';
43
42
  export class LocalUiRegistry {
44
43
  capabilities = {
45
- writable: false,
46
44
  observable: true,
47
45
  };
48
46
  projectRoot;
@@ -2,8 +2,8 @@ import type { UiRegistryEvent } from '@ggui-ai/ui-registry';
2
2
  /**
3
3
  * Listener for raw events the watcher emits. Delivery is
4
4
  * at-least-once — consumers dedupe where needed (e.g. the SSE
5
- * handler just forwards; Studio's subscription logic bumps a
6
- * counter and doesn't care about dupes).
5
+ * handler just forwards; a subscribing UI bumps a counter and
6
+ * doesn't care about dupes).
7
7
  */
8
8
  export type WatchListener = (event: UiRegistryEvent) => void;
9
9
  export interface LocalWatcherOptions {
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Maps raw chokidar events to the contract's `UiRegistryEvent`
5
5
  * union (`added` / `changed` / `removed`). The watcher is scoped
6
- * to what actually affects what Studio can see:
6
+ * to what actually affects what a registry consumer can see:
7
7
  *
8
8
  * - Any `ggui.ui.json` under the project tree → affects the
9
9
  * manifest itself. A new one means `added`, a deletion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ggui-ai/dev-stack",
3
- "version": "0.2.0-alpha.3",
3
+ "version": "0.3.0-rc.0",
4
4
  "description": "Shared local dev engine for the ggui protocol: local UI registry discovery, compile-on-demand, filesystem watcher with SSE, and a read-only HTTP surface for dev tooling. Framework-neutral — agent runtime supervision plugs in via an adapter seam, so no agent SDK is hardcoded.",
5
5
  "keywords": [
6
6
  "ggui",
@@ -28,10 +28,9 @@
28
28
  "dependencies": {
29
29
  "chokidar": "^4.0.3",
30
30
  "esbuild": "^0.25.12",
31
- "tinyglobby": "^0.2.16",
32
- "@ggui-ai/agent-runtime": "0.2.0-alpha.3",
33
- "@ggui-ai/ui-registry": "0.2.0-alpha.3",
34
- "@ggui-ai/project-config": "0.2.0-alpha.3"
31
+ "@ggui-ai/agent-runtime": "0.3.0-rc.0",
32
+ "@ggui-ai/project-config": "0.3.0-rc.0",
33
+ "@ggui-ai/ui-registry": "0.3.0-rc.0"
35
34
  },
36
35
  "devDependencies": {
37
36
  "@types/node": "^24.0.0",
@@ -41,9 +40,9 @@
41
40
  "react-dom": "^19.0.0",
42
41
  "typescript": "^5.0.0",
43
42
  "vitest": "^3.0.0",
44
- "@ggui-ai/design": "0.2.0-alpha.3",
45
- "@ggui-ai/react": "0.2.0-alpha.3",
46
- "@ggui-ai/wire": "0.2.0-alpha.3"
43
+ "@ggui-ai/design": "0.3.0-rc.0",
44
+ "@ggui-ai/react": "0.3.0-rc.0",
45
+ "@ggui-ai/wire": "0.3.0-rc.0"
47
46
  },
48
47
  "repository": {
49
48
  "type": "git",
@@ -62,7 +61,7 @@
62
61
  },
63
62
  "author": "ggui contributors <hello@ggui.ai>",
64
63
  "scripts": {
65
- "build": "tsc -p tsconfig.build.json && node scripts/build-hub-preview.mjs",
64
+ "build": "rm -rf dist && tsc -p tsconfig.build.json && node scripts/build-hub-preview.mjs",
66
65
  "build:hub-preview": "node scripts/build-hub-preview.mjs",
67
66
  "dev": "tsc --watch",
68
67
  "typecheck": "tsc --noEmit && tsc -p hub-preview-client/tsconfig.json --noEmit",
@@ -1,46 +0,0 @@
1
- /**
2
- * Options for {@link startSandboxProxyServer}.
3
- */
4
- export interface SandboxProxyServerOptions {
5
- /**
6
- * Port to bind. `0` asks the OS for a free port — the chosen port
7
- * is reflected in the returned `url`. Tests pass `0`; samples pass
8
- * a fixed port so the AppRenderer config is static.
9
- */
10
- readonly port: number;
11
- /**
12
- * Bind address. Defaults to `127.0.0.1` — loopback-only. Pass
13
- * `'0.0.0.0'` only if LAN access is required.
14
- */
15
- readonly host?: string;
16
- }
17
- /**
18
- * Handle to a running sandbox proxy server.
19
- */
20
- export interface SandboxProxyServerHandle {
21
- /**
22
- * Absolute URL the AppRenderer's `sandbox.url` prop should point at.
23
- * Includes scheme, host, and port. Path is `/sandbox.html` — the
24
- * spec-canonical sandbox entry point.
25
- */
26
- readonly url: string;
27
- /** Actual bound port (resolved when `options.port` was `0`). */
28
- readonly port: number;
29
- /** Stops the server and releases the port. */
30
- readonly close: () => Promise<void>;
31
- }
32
- /**
33
- * Start an HTTP server serving `sandbox.html` for use as
34
- * `<AppRenderer>`'s `sandbox.url`. The server has exactly two
35
- * behaviors:
36
- *
37
- * - `GET /` and `GET /sandbox.html` → sandbox HTML + CSP header
38
- * derived from `?csp=<urlencoded-json>` (mirrors upstream
39
- * basic-host serve.ts).
40
- * - Anything else → 404.
41
- *
42
- * Returns immediately once the server is listening; the handle's
43
- * `close()` releases the port.
44
- */
45
- export declare function startSandboxProxyServer(options: SandboxProxyServerOptions): Promise<SandboxProxyServerHandle>;
46
- //# sourceMappingURL=sandbox-proxy.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"sandbox-proxy.d.ts","sourceRoot":"","sources":["../../src/dev-server/sandbox-proxy.ts"],"names":[],"mappings":"AAoDA;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC;;;;OAIG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,gEAAgE;IAChE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,8CAA8C;IAC9C,QAAQ,CAAC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACrC;AAuKD;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,wBAAwB,CAAC,CAuEnC"}
@@ -1,270 +0,0 @@
1
- /**
2
- * `startSandboxProxyServer` — MCP-Apps spec-compliant sandbox proxy host
3
- * for `<AppRenderer>`.
4
- *
5
- * # Why this exists
6
- *
7
- * The MCP Apps spec (specification/2026-01-26/apps.mdx, double-iframe
8
- * sandbox architecture) mandates that the host and the sandbox iframe
9
- * live on DIFFERENT origins. The host wraps the sandbox iframe; the
10
- * sandbox iframe wraps the untrusted app HTML. Separating origins
11
- * means a compromise of the app cannot reach host APIs via
12
- * same-origin DOM access.
13
- *
14
- * `@mcp-ui/client`'s `<AppRenderer>` accepts a `sandbox: { url }` prop
15
- * pointing at a public URL serving `sandbox.html`. We ship that file +
16
- * its message-relay JS as a self-contained HTML string and serve it
17
- * over plain Node `http` on a separate port. Samples (and any consumer
18
- * of the dev-stack) boot this alongside their agent server.
19
- *
20
- * # Reference impl
21
- *
22
- * Adapted from
23
- * `github.com/modelcontextprotocol/ext-apps/examples/basic-host/`
24
- * (sandbox.html + src/sandbox.ts + serve.ts). Inlined into a single
25
- * HTML so the dev-stack doesn't need to bundle a static asset.
26
- *
27
- * # Security
28
- *
29
- * - CSP set via HTTP headers per `?csp=<urlencoded-json>` query
30
- * (tamper-proof; meta tags can be overridden by inline scripts).
31
- * - Sanitizes CSP domain entries to block `;`, newlines, quotes,
32
- * spaces — defends against directive injection.
33
- * - Binds to `127.0.0.1` by default. Pass `host: '0.0.0.0'` only
34
- * when LAN exposure is required.
35
- *
36
- * # Caller pattern
37
- *
38
- * ```ts
39
- * import { startSandboxProxyServer } from '@ggui-ai/dev-stack';
40
- * const proxy = await startSandboxProxyServer({ port: 7790 });
41
- * console.log('Sandbox proxy:', proxy.url);
42
- * // ... pass proxy.url to AppRenderer's sandbox.url prop ...
43
- * await proxy.close();
44
- * ```
45
- */
46
- import { createServer, } from 'node:http';
47
- /**
48
- * Reject CSP entries containing directive-injection characters
49
- * (`;`, newlines, quotes, spaces). Returns the kept entries.
50
- */
51
- function sanitizeCspDomains(domains) {
52
- if (!domains)
53
- return [];
54
- return domains.filter((d) => typeof d === 'string' && !/[;\r\n'" ]/.test(d));
55
- }
56
- /**
57
- * Build the `Content-Security-Policy` header value from an
58
- * (already-sanitized) CSP record. Mirrors `serve.ts` in the upstream
59
- * basic-host example so behavior matches the spec reference.
60
- */
61
- function buildCspHeader(csp) {
62
- const resourceDomains = sanitizeCspDomains(csp?.resourceDomains).join(' ');
63
- const connectDomains = sanitizeCspDomains(csp?.connectDomains).join(' ');
64
- const frameDomains = sanitizeCspDomains(csp?.frameDomains).join(' ');
65
- const baseUriDomains = sanitizeCspDomains(csp?.baseUriDomains).join(' ');
66
- const directives = [
67
- "default-src 'self' 'unsafe-inline'",
68
- `script-src 'self' 'unsafe-inline' 'unsafe-eval' blob: data: ${resourceDomains}`.trim(),
69
- `style-src 'self' 'unsafe-inline' blob: data: ${resourceDomains}`.trim(),
70
- `img-src 'self' data: blob: ${resourceDomains}`.trim(),
71
- `font-src 'self' data: blob: ${resourceDomains}`.trim(),
72
- `media-src 'self' data: blob: ${resourceDomains}`.trim(),
73
- `connect-src 'self' ${connectDomains}`.trim(),
74
- `worker-src 'self' blob: ${resourceDomains}`.trim(),
75
- frameDomains.length > 0
76
- ? `frame-src ${frameDomains}`
77
- : "frame-src 'none'",
78
- "object-src 'none'",
79
- baseUriDomains.length > 0
80
- ? `base-uri ${baseUriDomains}`
81
- : "base-uri 'none'",
82
- ];
83
- return directives.join('; ');
84
- }
85
- /**
86
- * The self-contained sandbox.html body. Inlines the message-relay JS
87
- * from `examples/basic-host/src/sandbox.ts` so we ship one file and
88
- * don't need a build step. The script is a verbatim port that:
89
- *
90
- * 1. Asserts iframe isolation (throws if it can reach `window.top`).
91
- * 2. Creates an inner iframe sandboxed with `allow-scripts
92
- * allow-same-origin allow-forms`.
93
- * 3. Intercepts `ui/notifications/sandbox-resource-ready` from the
94
- * parent to write the app HTML into the inner iframe.
95
- * 4. Relays every other postMessage bidirectionally between parent
96
- * and inner.
97
- * 5. Posts `ui/notifications/sandbox-proxy-ready` once attached.
98
- */
99
- const SANDBOX_HTML = `<!doctype html>
100
- <html>
101
- <head>
102
- <meta charset="utf-8" />
103
- <meta name="color-scheme" content="light dark">
104
- <title>ggui sandbox proxy</title>
105
- <style>
106
- html, body { margin: 0; height: 100vh; width: 100vw; background-color: transparent; }
107
- body { display: flex; flex-direction: column; }
108
- * { box-sizing: border-box; }
109
- iframe {
110
- background-color: transparent;
111
- border: 0px none transparent;
112
- padding: 0px;
113
- overflow: hidden;
114
- flex-grow: 1;
115
- color-scheme: inherit;
116
- }
117
- </style>
118
- </head>
119
- <body>
120
- <script>
121
- (function(){
122
- 'use strict';
123
- if (window.self === window.top) {
124
- throw new Error('This file is only to be used in an iframe sandbox.');
125
- }
126
- if (!document.referrer) {
127
- throw new Error('No referrer, cannot validate embedding site.');
128
- }
129
- var EXPECTED_HOST_ORIGIN = new URL(document.referrer).origin;
130
- var OWN_ORIGIN = new URL(window.location.href).origin;
131
- // Security self-test: top access MUST throw (sandbox attribute strips same-origin).
132
- try {
133
- window.top.alert('If you see this, the sandbox is not setup securely.');
134
- throw 'FAIL';
135
- } catch (e) {
136
- if (e === 'FAIL') {
137
- throw new Error('The sandbox is not setup securely.');
138
- }
139
- }
140
- // Inner iframe — the untrusted app HTML lands here.
141
- var inner = document.createElement('iframe');
142
- inner.style = 'width:100%; height:100%; border:none;';
143
- inner.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-forms');
144
- document.body.appendChild(inner);
145
- var RESOURCE_READY = 'ui/notifications/sandbox-resource-ready';
146
- var PROXY_READY = 'ui/notifications/sandbox-proxy-ready';
147
- window.addEventListener('message', function(event) {
148
- if (event.source === window.parent) {
149
- if (event.origin !== EXPECTED_HOST_ORIGIN) {
150
- console.error('[Sandbox] Rejecting parent message from unexpected origin:', event.origin);
151
- return;
152
- }
153
- if (event.data && event.data.method === RESOURCE_READY) {
154
- var params = event.data.params || {};
155
- var html = params.html;
156
- var sandboxAttr = params.sandbox;
157
- if (typeof sandboxAttr === 'string') {
158
- inner.setAttribute('sandbox', sandboxAttr);
159
- }
160
- if (typeof html === 'string') {
161
- var doc = inner.contentDocument || (inner.contentWindow && inner.contentWindow.document);
162
- if (doc) {
163
- doc.open();
164
- doc.write(html);
165
- doc.close();
166
- } else {
167
- inner.srcdoc = html;
168
- }
169
- }
170
- } else {
171
- if (inner && inner.contentWindow) {
172
- inner.contentWindow.postMessage(event.data, '*');
173
- }
174
- }
175
- } else if (event.source === inner.contentWindow) {
176
- if (event.origin !== OWN_ORIGIN) {
177
- console.error('[Sandbox] Rejecting inner message from unexpected origin:', event.origin);
178
- return;
179
- }
180
- window.parent.postMessage(event.data, EXPECTED_HOST_ORIGIN);
181
- }
182
- });
183
- window.parent.postMessage({
184
- jsonrpc: '2.0',
185
- method: PROXY_READY,
186
- params: {},
187
- }, EXPECTED_HOST_ORIGIN);
188
- })();
189
- </script>
190
- </body>
191
- </html>`;
192
- /**
193
- * Start an HTTP server serving `sandbox.html` for use as
194
- * `<AppRenderer>`'s `sandbox.url`. The server has exactly two
195
- * behaviors:
196
- *
197
- * - `GET /` and `GET /sandbox.html` → sandbox HTML + CSP header
198
- * derived from `?csp=<urlencoded-json>` (mirrors upstream
199
- * basic-host serve.ts).
200
- * - Anything else → 404.
201
- *
202
- * Returns immediately once the server is listening; the handle's
203
- * `close()` releases the port.
204
- */
205
- export function startSandboxProxyServer(options) {
206
- const host = options.host ?? '127.0.0.1';
207
- const server = createServer((req, res) => {
208
- // Resolve URL relative to a synthetic base so we can use
209
- // URL parsing (req.url is path+query only).
210
- const url = new URL(req.url ?? '/', 'http://placeholder');
211
- if (req.method === 'GET' &&
212
- (url.pathname === '/' || url.pathname === '/sandbox.html')) {
213
- let csp;
214
- const cspParam = url.searchParams.get('csp');
215
- if (cspParam !== null) {
216
- try {
217
- const parsed = JSON.parse(cspParam);
218
- if (parsed !== null && typeof parsed === 'object') {
219
- csp = parsed;
220
- }
221
- }
222
- catch {
223
- // Ignore malformed CSP — fall through to the default
224
- // (`'self' 'unsafe-inline'`) header. Visible in the
225
- // browser's console as a CSP violation if the app loads
226
- // external resources.
227
- }
228
- }
229
- res.setHeader('Content-Security-Policy', buildCspHeader(csp));
230
- res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
231
- res.setHeader('Pragma', 'no-cache');
232
- res.setHeader('Expires', '0');
233
- res.setHeader('Content-Type', 'text/html; charset=utf-8');
234
- // CORS: AppRenderer fetches the sandbox HTML cross-origin
235
- // (parent vs. sandbox-proxy origin); the browser still
236
- // navigates the iframe even without explicit CORS, but the
237
- // header is harmless and unblocks any future fetch() probes.
238
- res.setHeader('Access-Control-Allow-Origin', '*');
239
- res.statusCode = 200;
240
- res.end(SANDBOX_HTML);
241
- return;
242
- }
243
- res.statusCode = 404;
244
- res.setHeader('Content-Type', 'text/plain; charset=utf-8');
245
- res.end('sandbox proxy: only GET /sandbox.html is served here\n');
246
- });
247
- return new Promise((resolve, reject) => {
248
- server.once('error', reject);
249
- server.listen(options.port, host, () => {
250
- const addr = server.address();
251
- if (addr === null || typeof addr === 'string') {
252
- reject(new Error(`startSandboxProxyServer: address() returned ${String(addr)}; expected AddressInfo`));
253
- return;
254
- }
255
- const url = `http://${host}:${addr.port}/sandbox.html`;
256
- resolve({
257
- url,
258
- port: addr.port,
259
- close: () => new Promise((resolveClose, rejectClose) => {
260
- server.close((err) => {
261
- if (err)
262
- rejectClose(err);
263
- else
264
- resolveClose();
265
- });
266
- }),
267
- });
268
- });
269
- });
270
- }