@ggui-ai/cli 0.6.2 → 0.7.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 (39) hide show
  1. package/dist/auth-keys.d.ts +3 -1
  2. package/dist/auth-keys.d.ts.map +1 -1
  3. package/dist/auth-keys.js +42 -2
  4. package/dist/blueprint-command.d.ts.map +1 -1
  5. package/dist/blueprint-command.js +13 -13
  6. package/dist/cli.js +10 -0
  7. package/dist/config-push.d.ts +0 -8
  8. package/dist/config-push.d.ts.map +1 -1
  9. package/dist/config-push.js +10 -35
  10. package/dist/gadget-command.d.ts +1 -1
  11. package/dist/gadget-command.d.ts.map +1 -1
  12. package/dist/gadget-command.js +35 -12
  13. package/dist/internal/artifact-install.d.ts.map +1 -1
  14. package/dist/internal/artifact-install.js +125 -100
  15. package/dist/internal/artifact-publish.d.ts +37 -35
  16. package/dist/internal/artifact-publish.d.ts.map +1 -1
  17. package/dist/internal/artifact-publish.js +33 -97
  18. package/dist/internal/artifact-search.d.ts +27 -21
  19. package/dist/internal/artifact-search.d.ts.map +1 -1
  20. package/dist/internal/artifact-search.js +14 -128
  21. package/dist/internal/artifact-uninstall.d.ts +8 -5
  22. package/dist/internal/artifact-uninstall.d.ts.map +1 -1
  23. package/dist/internal/artifact-uninstall.js +133 -26
  24. package/dist/internal/ggui-json.d.ts +35 -4
  25. package/dist/internal/ggui-json.d.ts.map +1 -1
  26. package/dist/internal/ggui-json.js +58 -7
  27. package/dist/internal/register-author-key.d.ts +10 -0
  28. package/dist/internal/register-author-key.d.ts.map +1 -1
  29. package/dist/internal/register-author-key.js +14 -7
  30. package/dist/internal/registry-url.d.ts +49 -0
  31. package/dist/internal/registry-url.d.ts.map +1 -0
  32. package/dist/internal/registry-url.js +137 -0
  33. package/dist/mcp-backend.d.ts +6 -0
  34. package/dist/mcp-backend.d.ts.map +1 -1
  35. package/dist/mcp-backend.js +9 -0
  36. package/dist/serve-command.d.ts +14 -1
  37. package/dist/serve-command.d.ts.map +1 -1
  38. package/dist/serve-command.js +29 -0
  39. package/package.json +17 -17
@@ -22,6 +22,14 @@ export type RegisterKeyOutcome = {
22
22
  readonly registryUrl: string;
23
23
  readonly subject: string;
24
24
  readonly keyId: string;
25
+ /**
26
+ * The STORED row's enrichment fields as echoed by the registry.
27
+ * On an idempotent 200 these are the existing row's values — a
28
+ * `label` differing from the flag means the registry kept the
29
+ * stored one (the output layer prints the kept-label notice).
30
+ */
31
+ readonly createdAt?: string;
32
+ readonly label?: string;
25
33
  } | {
26
34
  readonly ok: false;
27
35
  readonly code: 'no-registry' | 'invalid-registry' | 'no-keypair' | 'auth_failed' | 'auth_config_missing' | 'network-error' | 'unauthorized' | 'invalid_request' | 'key_conflict' | 'http-error' | 'bad-response';
@@ -30,6 +38,8 @@ export type RegisterKeyOutcome = {
30
38
  export interface RunRegisterKeyFlags {
31
39
  readonly scope: string;
32
40
  readonly registry?: string;
41
+ /** Optional display name stored on the registered key ([E]). */
42
+ readonly label?: string;
33
43
  /** Auth strategy + bearer token. `undefined` → the stored `ggui
34
44
  * login` session; `{ auth: 'bearer', token? }` → explicit bearer
35
45
  * (self-hosted registries), token from the flag or
@@ -1 +1 @@
1
- {"version":3,"file":"register-author-key.d.ts","sourceRoot":"","sources":["../../src/internal/register-author-key.ts"],"names":[],"mappings":"AA0BA,OAAO,EAAoB,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAGtE;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,kBAAkB,GAC1B;IACE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAClB,QAAQ,CAAC,MAAM,EAAE,GAAG,GAAG,GAAG,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB,GACD;IACE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IACnB,QAAQ,CAAC,IAAI,EACT,aAAa,GACb,kBAAkB,GAClB,YAAY,GACZ,aAAa,GACb,qBAAqB,GACrB,eAAe,GACf,cAAc,GACd,iBAAiB,GACjB,cAAc,GACd,YAAY,GACZ,cAAc,CAAC;IACnB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEN,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;;yEAGqE;IACrE,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC;CAC3B;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,OAAO,KAAK,CAAC;IAC7B,QAAQ,CAAC,GAAG,EAAE,MAAM,MAAM,CAAC;CAC5B;AAcD;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,mBAAmB,EAC1B,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,kBAAkB,CAAC,CA6K7B"}
1
+ {"version":3,"file":"register-author-key.d.ts","sourceRoot":"","sources":["../../src/internal/register-author-key.ts"],"names":[],"mappings":"AA0BA,OAAO,EAAoB,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAGtE;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,kBAAkB,GAC1B;IACE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAClB,QAAQ,CAAC,MAAM,EAAE,GAAG,GAAG,GAAG,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB,GACD;IACE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IACnB,QAAQ,CAAC,IAAI,EACT,aAAa,GACb,kBAAkB,GAClB,YAAY,GACZ,aAAa,GACb,qBAAqB,GACrB,eAAe,GACf,cAAc,GACd,iBAAiB,GACjB,cAAc,GACd,YAAY,GACZ,cAAc,CAAC;IACnB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEN,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,gEAAgE;IAChE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;;;yEAGqE;IACrE,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC;CAC3B;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,OAAO,KAAK,CAAC;IAC7B,QAAQ,CAAC,GAAG,EAAE,MAAM,MAAM,CAAC;CAC5B;AAcD;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,mBAAmB,EAC1B,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,kBAAkB,CAAC,CAsL7B"}
@@ -20,7 +20,7 @@
20
20
  import { readFileSync } from 'node:fs';
21
21
  import { REGISTER_AUTHOR_KEY_ERROR_CODES } from '@ggui-ai/registry-core';
22
22
  import { acquireLoginSessionToken, } from './artifact-publish.js';
23
- import { resolveRegistryUrl } from './artifact-search.js';
23
+ import { resolveRegistryUrl } from './registry-url.js';
24
24
  import { acquireAuthToken } from './auth-strategy.js';
25
25
  import { getPublicKeyPath, hasKeypair } from './key-store.js';
26
26
  /**
@@ -41,7 +41,8 @@ class SessionOutcomeError extends Error {
41
41
  * returns a structured outcome.
42
42
  */
43
43
  export async function runRegisterAuthorKey(flags, deps) {
44
- // 1. Registry URL — same resolver as publish/search.
44
+ // 1. Registry URL — shared resolver, WRITE-verb posture (no default:
45
+ // registering a key is a write, so the target must be explicit).
45
46
  const resolved = resolveRegistryUrl({
46
47
  ...(flags.registry !== undefined ? { flag: flags.registry } : {}),
47
48
  cwd: deps.cwd,
@@ -49,12 +50,11 @@ export async function runRegisterAuthorKey(flags, deps) {
49
50
  GGUI_REGISTRY: typeof deps.env['GGUI_REGISTRY'] === 'string' ? deps.env['GGUI_REGISTRY'] : undefined,
50
51
  },
51
52
  });
52
- if ('error' in resolved) {
53
- const isNoRegistry = resolved.error.startsWith('no registry');
53
+ if (!resolved.ok) {
54
54
  return {
55
55
  ok: false,
56
- code: isNoRegistry ? 'no-registry' : 'invalid-registry',
57
- message: resolved.error,
56
+ code: resolved.code,
57
+ message: resolved.message,
58
58
  };
59
59
  }
60
60
  // 2. Read the local public key. Same per-scope keystore the publish
@@ -136,7 +136,10 @@ export async function runRegisterAuthorKey(flags, deps) {
136
136
  'content-type': 'application/json',
137
137
  authorization: `Bearer ${accessToken}`,
138
138
  },
139
- body: JSON.stringify({ publicKeyBase64 }),
139
+ body: JSON.stringify({
140
+ publicKeyBase64,
141
+ ...(flags.label !== undefined ? { label: flags.label } : {}),
142
+ }),
140
143
  });
141
144
  }
142
145
  catch (err) {
@@ -179,6 +182,10 @@ export async function runRegisterAuthorKey(flags, deps) {
179
182
  registryUrl: resolved.url,
180
183
  subject: okBody.subject,
181
184
  keyId: okBody.keyId,
185
+ ...(typeof okBody.createdAt === 'string'
186
+ ? { createdAt: okBody.createdAt }
187
+ : {}),
188
+ ...(typeof okBody.label === 'string' ? { label: okBody.label } : {}),
182
189
  };
183
190
  }
184
191
  // Defend against `null` / non-object JSON (e.g. `body === null` or
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Fallback registry for READ verbs when no explicit config is present:
3
+ * the public ggui marketplace registry (the same role
4
+ * registry.npmjs.org plays for npm). Point `--registry` /
5
+ * `GGUI_REGISTRY` / `ggui.json#registry` at your own registry to
6
+ * override it — self-hosted registries are first-class (see
7
+ * `@ggui-ai/registry-server`).
8
+ */
9
+ export declare const DEFAULT_REGISTRY_URL = "https://registry.ggui.ai";
10
+ /** Which layer of the chain produced the URL. Surfaced in publish's
11
+ * `registry: <url> (<source>)` status line. */
12
+ export type RegistryUrlSource = 'flag' | 'env' | 'ggui.json' | 'default';
13
+ export type RegistryUrlResolution = {
14
+ readonly ok: true;
15
+ readonly url: string;
16
+ readonly source: RegistryUrlSource;
17
+ } | {
18
+ readonly ok: false;
19
+ /** `no-registry` = nothing configured and no default supplied;
20
+ * `invalid-registry` = something WAS configured but is not a
21
+ * usable http(s) URL (or a ggui.json on the walk is unreadable). */
22
+ readonly code: 'no-registry' | 'invalid-registry';
23
+ /** Operator-facing diagnostic, safe to write to stderr verbatim. */
24
+ readonly message: string;
25
+ };
26
+ export interface ResolveRegistryUrlOptions {
27
+ /** `--registry <url>` flag value — highest precedence. */
28
+ readonly flag?: string;
29
+ /** Directory the `ggui.json` walk starts from. */
30
+ readonly cwd: string;
31
+ /** Environment view — injectable for tests. */
32
+ readonly env: {
33
+ readonly GGUI_REGISTRY?: string | undefined;
34
+ };
35
+ /**
36
+ * Fallback when the whole chain misses. READ verbs pass
37
+ * {@link DEFAULT_REGISTRY_URL}; WRITE verbs omit it and receive a
38
+ * `no-registry` error instead.
39
+ */
40
+ readonly defaultUrl?: string;
41
+ }
42
+ /**
43
+ * Resolve the registry URL for a verb. Pure lookup + validation — no
44
+ * network. Returned URLs are normalized (trailing slashes stripped) so
45
+ * callers can append routes (`/search`, `/pkg/…`, `/publish`)
46
+ * deterministically.
47
+ */
48
+ export declare function resolveRegistryUrl(opts: ResolveRegistryUrlOptions): RegistryUrlResolution;
49
+ //# sourceMappingURL=registry-url.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry-url.d.ts","sourceRoot":"","sources":["../../src/internal/registry-url.ts"],"names":[],"mappings":"AAqCA;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,6BAA6B,CAAC;AAE/D;+CAC+C;AAC/C,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,KAAK,GAAG,WAAW,GAAG,SAAS,CAAC;AAEzE,MAAM,MAAM,qBAAqB,GAC7B;IACE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAClB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;CACpC,GACD;IACE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IACnB;;wEAEoE;IACpE,QAAQ,CAAC,IAAI,EAAE,aAAa,GAAG,kBAAkB,CAAC;IAClD,oEAAoE;IACpE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEN,MAAM,WAAW,yBAAyB;IACxC,0DAA0D;IAC1D,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,kDAAkD;IAClD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,+CAA+C;IAC/C,QAAQ,CAAC,GAAG,EAAE;QAAE,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC;IAC9D;;;;OAIG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,yBAAyB,GAC9B,qBAAqB,CA2CvB"}
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Shared registry-URL resolution for every CLI verb that talks to a
3
+ * marketplace registry (`gadget`/`blueprint` `publish` / `install` /
4
+ * `search`, `keys register`).
5
+ *
6
+ * One precedence chain for every verb (npm model — highest wins):
7
+ *
8
+ * 1. `--registry <url>` flag
9
+ * 2. `GGUI_REGISTRY` env var
10
+ * 3. `ggui.json#registry` — the nearest ggui.json that CARRIES the
11
+ * field, walking up from cwd (see {@link findRegistryField}).
12
+ *
13
+ * Verbs differ only in what happens on a full miss:
14
+ *
15
+ * - **READ verbs** (install, search) pass {@link DEFAULT_REGISTRY_URL}
16
+ * as `defaultUrl` and fall back to the public registry — a consumer
17
+ * with zero config can still search + install, exactly like `npm
18
+ * install` reaching registry.npmjs.org.
19
+ * - **WRITE verbs** (publish, keys register) omit `defaultUrl` and get
20
+ * a `no-registry` error — operators must opt into a publish target
21
+ * explicitly so a typo can't push to an unintended registry.
22
+ *
23
+ * This module is the ONLY place the chain is implemented. Per-verb
24
+ * copies drifted once (install put `ggui.json` ahead of the env var
25
+ * while publish/search did the reverse); a single resolver makes that
26
+ * class of drift impossible. File IO rides the shared `./ggui-json.ts`
27
+ * helpers (`readGguiJson` + the `FIND_MAX_DEPTH` walk budget) — only
28
+ * the registry-field narrowing lives here.
29
+ */
30
+ import { existsSync } from 'node:fs';
31
+ import { dirname, join, resolve } from 'node:path';
32
+ import { FIND_MAX_DEPTH, GGUI_JSON_FILENAME, readGguiJson, } from './ggui-json.js';
33
+ /**
34
+ * Fallback registry for READ verbs when no explicit config is present:
35
+ * the public ggui marketplace registry (the same role
36
+ * registry.npmjs.org plays for npm). Point `--registry` /
37
+ * `GGUI_REGISTRY` / `ggui.json#registry` at your own registry to
38
+ * override it — self-hosted registries are first-class (see
39
+ * `@ggui-ai/registry-server`).
40
+ */
41
+ export const DEFAULT_REGISTRY_URL = 'https://registry.ggui.ai';
42
+ /**
43
+ * Resolve the registry URL for a verb. Pure lookup + validation — no
44
+ * network. Returned URLs are normalized (trailing slashes stripped) so
45
+ * callers can append routes (`/search`, `/pkg/…`, `/publish`)
46
+ * deterministically.
47
+ */
48
+ export function resolveRegistryUrl(opts) {
49
+ if (opts.flag !== undefined && opts.flag.length > 0) {
50
+ return validateUrl(opts.flag, 'flag', `--registry value is not a valid URL: ${opts.flag}`);
51
+ }
52
+ const envValue = opts.env.GGUI_REGISTRY;
53
+ if (typeof envValue === 'string' && envValue.length > 0) {
54
+ return validateUrl(envValue, 'env', `GGUI_REGISTRY is not a valid URL: ${envValue}`);
55
+ }
56
+ const field = findRegistryField(opts.cwd);
57
+ if (field.hit === 'error') {
58
+ return { ok: false, code: 'invalid-registry', message: field.message };
59
+ }
60
+ if (field.hit === 'found') {
61
+ return validateUrl(field.registry, 'ggui.json', `ggui.json#registry at ${field.path} is not a valid URL: ${field.registry}`);
62
+ }
63
+ if (opts.defaultUrl !== undefined) {
64
+ return validateUrl(opts.defaultUrl, 'default', `default registry URL is not a valid URL: ${opts.defaultUrl}`);
65
+ }
66
+ return {
67
+ ok: false,
68
+ code: 'no-registry',
69
+ message: 'no registry resolved. Set one of:\n' +
70
+ ' --registry <url>\n' +
71
+ ' GGUI_REGISTRY env var\n' +
72
+ ' "registry": "<url>" in the nearest ggui.json',
73
+ };
74
+ }
75
+ /**
76
+ * Field-seeking walk: climb up to {@link FIND_MAX_DEPTH} parent
77
+ * directories looking for the nearest `ggui.json` that CARRIES a
78
+ * usable `registry` field.
79
+ *
80
+ * Deliberately NOT `findGguiJson` (nearest FILE wins): a nested
81
+ * project's field-less ggui.json must not shadow a monorepo root that
82
+ * pins the registry — stopping at the first file would silently route
83
+ * READ verbs to the public default past the operator's config.
84
+ *
85
+ * Tolerance rules per file on the walk:
86
+ * - absent / empty / non-string `registry` → keep walking. The file
87
+ * is valid, just silent on this question; an ancestor may answer.
88
+ * - unreadable / unparseable ggui.json → hard error. Silently
89
+ * walking past a corrupt config could reroute a read to the
90
+ * public default when the operator's (unparseable) file named
91
+ * their own registry.
92
+ *
93
+ * Reads ride `readGguiJson` (shared IO + structural validation); this
94
+ * function adds only the field narrowing.
95
+ */
96
+ function findRegistryField(startDir) {
97
+ let dir = resolve(startDir);
98
+ for (let i = 0; i <= FIND_MAX_DEPTH; i++) {
99
+ const candidate = join(dir, GGUI_JSON_FILENAME);
100
+ if (existsSync(candidate)) {
101
+ const loaded = readGguiJson(candidate);
102
+ if ('error' in loaded) {
103
+ return { hit: 'error', message: loaded.error };
104
+ }
105
+ const registry = loaded.value['registry'];
106
+ if (typeof registry === 'string' && registry.length > 0) {
107
+ return { hit: 'found', registry, path: candidate };
108
+ }
109
+ }
110
+ const parent = dirname(dir);
111
+ if (parent === dir)
112
+ return { hit: 'none' };
113
+ dir = parent;
114
+ }
115
+ return { hit: 'none' };
116
+ }
117
+ /** Parse + validate an http(s) URL and strip trailing slashes. */
118
+ function validateUrl(raw, source, invalidMessage) {
119
+ let parsed;
120
+ try {
121
+ parsed = new URL(raw);
122
+ }
123
+ catch {
124
+ return { ok: false, code: 'invalid-registry', message: invalidMessage };
125
+ }
126
+ if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
127
+ return {
128
+ ok: false,
129
+ code: 'invalid-registry',
130
+ message: `${invalidMessage} (must be http or https)`,
131
+ };
132
+ }
133
+ let serialized = parsed.toString();
134
+ while (serialized.endsWith('/'))
135
+ serialized = serialized.slice(0, -1);
136
+ return { ok: true, url: serialized, source };
137
+ }
@@ -120,6 +120,12 @@ export interface BuildMcpServerBackendOptions {
120
120
  * CLI from `--seed-pool` artifacts; absent ⇒ no shared pool.
121
121
  */
122
122
  readonly seedPools?: readonly BlueprintPool[];
123
+ /**
124
+ * Effective browser-origin allowlist (`--browser-origin` flags or
125
+ * GGUI_BROWSER_ORIGINS, resolved by the CLI). Drives BOTH MCP-wire
126
+ * Origin validation and (from #438b) the CORS response headers.
127
+ */
128
+ readonly browserOrigins?: ReadonlyArray<string>;
123
129
  /**
124
130
  * Marketplace-install bridge data. When set, the backend
125
131
  * constructs an
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-backend.d.ts","sourceRoot":"","sources":["../src/mcp-backend.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mcp-backend.d.ts","sourceRoot":"","sources":["../src/mcp-backend.ts"],"names":[],"mappings":"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"}
@@ -371,6 +371,15 @@ export function buildMcpServerBackend(opts) {
371
371
  auth,
372
372
  embedding,
373
373
  providerKeys,
374
+ // Declared bind host (ggui#438a) — the Origin/Host validation
375
+ // policy must see the address `listen()` will actually bind.
376
+ // `opts.host` already exists on this options type with exactly
377
+ // that contract ("Must be the same host the CLI then passes to
378
+ // listen()").
379
+ host: opts.host,
380
+ ...(opts.browserOrigins && opts.browserOrigins.length > 0
381
+ ? { browserOrigins: opts.browserOrigins }
382
+ : {}),
374
383
  // Seeded per-app metadata store. Threaded so the in-process
375
384
  // singleton is shared across `ggui_list_gadgets`,
376
385
  // `ggui_list_themes`, and the handshake (gadgets + theme default
@@ -214,6 +214,14 @@ export interface ParsedServeFlags {
214
214
  * Surface = `--seed-pool <dir>` (repeatable).
215
215
  */
216
216
  seedPools: string[];
217
+ /**
218
+ * Page origins allowed past MCP-wire Origin validation (and, once
219
+ * the CORS layer ships, readable by browser pages at those origins).
220
+ * Loopback origins are always allowed and need no entry.
221
+ *
222
+ * Surface = `--browser-origin <origin>` (repeatable).
223
+ */
224
+ browserOrigins: string[];
217
225
  /** Populated when parsing failed; caller renders + bails with exit code 1. */
218
226
  error?: string;
219
227
  }
@@ -333,6 +341,11 @@ export interface ServeBannerInputs {
333
341
  * fall back to MockEmbeddingProvider).
334
342
  */
335
343
  readonly embeddingModel?: string;
344
+ /**
345
+ * Effective browser-origin allowlist (flag or GGUI_BROWSER_ORIGINS).
346
+ * Absent/empty = loopback-only default.
347
+ */
348
+ readonly browserOrigins?: ReadonlyArray<string>;
336
349
  }
337
350
  export declare function describeServeBanner(input: ServeBannerInputs): string[];
338
351
  /**
@@ -500,5 +513,5 @@ export interface RunServeOptions {
500
513
  * {@link describeServeBanner} / {@link describeAgentStatus}.
501
514
  */
502
515
  export declare function runServe(opts: RunServeOptions): Promise<number>;
503
- export declare const SERVE_HELP = "ggui serve \u2014 run the open self-hosted personal-mode app\n\nBoots the @ggui-ai/mcp-server binding with persistent defaults AND\n(by default) supervises your agent alongside it. The current MCP\nhandler surface is the blueprint-read family (search / list_featured\n/ render); more tools come online as @ggui-ai/mcp-server-handlers\ngrows.\n\nFirst-run bundle (all on by default):\n - Landing page at / \u2014 operator opens a browser and sees\n server identity + pair-code card.\n - Render viewer at /r/<code> \u2014 same-origin viewer for renders\n minted by ggui_render; same-origin\n HTTP-only cookie authenticates the\n live-channel /ws upgrade.\n - POST /pair + POST /admin/pair/init \u2014 pairing endpoint for MCP\n hosts and third-party clients.\n - Live-channel /ws \u2014 live render plane for MCP Apps\n iframes and the console.\n\nEmbedding hosts that want a different shape (no landing page, no\npairing, programmatic control) should compose createGguiServer()\ndirectly in code rather than invoking `ggui serve`.\n\nUsage:\n ggui serve [options]\n\nOptions:\n --port <n> Bind port (default: 6781, 0 = OS-assigned).\n --host <addr> Bind host (default: 127.0.0.1).\n --mcp-only Run just the MCP server; do not supervise an agent.\n --dev-allow-all Accept any non-empty bearer (incl. no bearer) as\n builder. Local-dev / tunnel smoke ONLY \u2014 never\n expose to the open internet.\n --public-demo Public-facing demo posture: same any-bearer auth\n as --dev-allow-all, plus per-IP rate limit on\n ggui_render (30 generations / 10 min) and a\n \"PUBLIC DEMO \u2014 operator pays\" banner. Mutually\n exclusive with --dev-allow-all.\n --multi-tenant Multi-tenant posture: switches the /settings LLM-\n keys gate from admin-token to auth-adapter so\n each authenticated end-user manages their OWN\n key plane (scope = userId/appId). kind:'builder'\n identities are rejected at the gate. Strict-auth\n only; mutually exclusive with --dev-allow-all\n and --public-demo. (Generation-time BYOK still\n resolves at the operator 'global' scope \u2014 a\n follow-up will thread per-user BYOK through\n ggui_render.)\n --public-base-url <u> Override the public base URL used to compose\n iframe-runtime + shortCode URLs. Set this to a\n tunnel URL (https://<random>.trycloudflare.com)\n when testing against a remote MCP host so URLs\n resolve from the host's perspective. Without\n this, URLs derive from --host:--port and only\n work from the same machine.\n --oauth Mount OAuth 2.1 + PKCE + Dynamic Client\n Registration routes (.well-known/oauth-* +\n /oauth/{authorize,token,register}). Required\n for MCP custom-connector hosts (claude.ai,\n ChatGPT) whose Add Connector form has no field\n for a pre-shared bearer; OAuth lets them do\n a discovery \u2192 DCR \u2192 consent dance ending in\n the same paired bearer the strict-auth flow\n already mints. Pure-bearer clients (Claude\n Desktop with bearer in config) work without it.\n --admin-token <t> Pin the admin bearer that gates the console\n /keys plane (list / mint / revoke pairings +\n /admin-login route). Without this, the server\n mints a fresh ggui_admin_* token per boot and\n prints it on the banner. Pin a stable value\n when you want the bearer to survive restarts\n (e.g. paste once into a password manager).\n --ephemeral Disable cross-restart persistence. Without\n this flag, the HMAC secrets that sign MCP\n Apps bootstrap tokens and signed render URLs\n are read or minted under .ggui/persistent/\n (project-local if a ggui.json was resolved,\n else ~/.ggui/persistent/) so cached tokens\n survive a server restart. Pass this flag to\n keep restarts ephemeral (tests / CI / nuclear-\n revoke). Override the dir via GGUI_PERSISTENT_DIR.\n --seed-pool <dir> Load a read-only shared blueprint pool from a\n directory artifact (repeatable). Blueprints in it\n are reused by exact contract match, after your own.\n --help, -h Show this help.\n\nAgent runtime:\n The default boots your agent alongside MCP. The agent's entry file\n comes from ggui.json:\n\n { \"agent\": { \"entry\": \"./agent.ts\" } }\n\n Supported extensions: .js / .mjs / .cjs (node), .ts / .tsx / .mts\n (node --import=tsx). No ggui.json, or no agent.entry, falls back\n to MCP-only with a warning. Malformed ggui.json or a bad entry\n is a hard error.\n\n Agent crashes after startup are logged; the MCP server keeps\n running. No auto-restart \u2014 compose that with your own supervisor.\n\nPersistent storage (default-on; opt-out via --ephemeral):\n By default `ggui serve` writes a small bundle under .ggui/persistent/\n (project-local if a ggui.json was resolved, else ~/.ggui/persistent/)\n so cached MCP Apps tokens, signed render URLs, shortCodes, renders,\n vectors, and paired bearers survive a restart \u2014 claude.ai chat-history\n revisits keep working.\n\n Bundle layout:\n\n .ggui/persistent/\n \u251C\u2500\u2500 ws-token-secret.hex (HMAC, 0600)\n \u251C\u2500\u2500 render-signer-secret.hex (HMAC, 0600)\n \u251C\u2500\u2500 short-codes.sqlite (signed render-URL resolution)\n \u251C\u2500\u2500 sessions.sqlite (GguiSessionStore \u2014 renders + event history)\n \u251C\u2500\u2500 vectors.sqlite (RAG corpus)\n \u2514\u2500\u2500 keys.json (paired bearers)\n\n Override the dir with `GGUI_PERSISTENT_DIR`. Pass `--ephemeral` to\n skip the bundle entirely (tests, CI loops, nuclear-revoke).\n\n Explicit ggui.json#storage declarations always win \u2014 declare\n `{ \"renders\": { \"driver\": \"memory\" } }` to opt renders back to\n in-memory while keeping other surfaces persistent. Custom sqlite\n paths via ggui.json#storage are honored verbatim:\n\n {\n \"storage\": {\n \"renders\": { \"driver\": \"sqlite\", \"path\": \"./ggui-sessions.sqlite\" },\n \"vectors\": { \"driver\": \"sqlite\", \"path\": \"./ggui-vectors.sqlite\" },\n \"threads\": { \"driver\": \"sqlite\", \"path\": \"./ggui-threads.sqlite\" }\n }\n }\n\n Threads: the persistent-chat route family (/threads) is opt-in.\n Absent `storage.threads` leaves the routes unmounted \u2014 pairs\n with Portal's self-hosted origins only when declared. Driver\n semantics:\n - `driver: \"sqlite\"` \u2014 durable. Threads survive restart.\n /ggui/health reports `threads.durability: \"durable\"`;\n Portal hides its non-durable caveat.\n - `driver: \"memory\"` \u2014 routes mount but data is lost on\n restart. /ggui/health reports `threads.durability:\n \"ephemeral\"`; Portal shows its caveat.\n\n Paths resolve relative to the ggui.json directory. The sqlite\n driver needs `better-sqlite3` installed in your project.\n\nRecommended setups:\n\n Local-only smoke (no tunnel, no remote MCP host):\n ggui serve\n\n claude.ai custom connector (over a public tunnel):\n 1. Tunnel: cloudflared tunnel --url http://localhost:6781\n 2. ggui serve --oauth \\\n --public-base-url https://<tunnel>.trycloudflare.com\n 3. Note PAIR_CODE from boot. Visit the landing page (the public URL\n above), complete pairing, save the bearer.\n 4. claude.ai \u2192 Settings \u2192 Connectors \u2192 Add custom connector.\n URL: https://<tunnel>.trycloudflare.com/mcp\n Client ID / Secret: leave empty (server uses Dynamic Client\n Registration; no pre-shared secret needed).\n 5. Click Connect \u2192 claude.ai redirects you to a paste-key page.\n Paste the bearer from step 3. Done.\n\n Quick local-dev WITHOUT auth (NEVER over a public tunnel):\n ggui serve --dev-allow-all\n\nCurrent limits:\n - Strict-auth only: /mcp rejects any bearer that isn't pair-minted.\n The CLI pre-mints one pairing code on boot (printed as\n `PAIR_CODE <code>` and shown in the banner + on the landing\n page). Complete `POST /pair {code, deviceName}` to receive a\n bearer you can use with MCP. Embed @ggui-ai/mcp-server in your\n own entrypoint to inject a different AuthAdapter (OIDC, Cognito,\n etc.) for production.\n - Single-tenant: every request scopes to one `builder` app id.\n";
516
+ export declare const SERVE_HELP = "ggui serve \u2014 run the open self-hosted personal-mode app\n\nBoots the @ggui-ai/mcp-server binding with persistent defaults AND\n(by default) supervises your agent alongside it. The current MCP\nhandler surface is the blueprint-read family (search / list_featured\n/ render); more tools come online as @ggui-ai/mcp-server-handlers\ngrows.\n\nFirst-run bundle (all on by default):\n - Landing page at / \u2014 operator opens a browser and sees\n server identity + pair-code card.\n - Render viewer at /r/<code> \u2014 same-origin viewer for renders\n minted by ggui_render; same-origin\n HTTP-only cookie authenticates the\n live-channel /ws upgrade.\n - POST /pair + POST /admin/pair/init \u2014 pairing endpoint for MCP\n hosts and third-party clients.\n - Live-channel /ws \u2014 live render plane for MCP Apps\n iframes and the console.\n\nEmbedding hosts that want a different shape (no landing page, no\npairing, programmatic control) should compose createGguiServer()\ndirectly in code rather than invoking `ggui serve`.\n\nUsage:\n ggui serve [options]\n\nOptions:\n --port <n> Bind port (default: 6781, 0 = OS-assigned).\n --host <addr> Bind host (default: 127.0.0.1).\n --mcp-only Run just the MCP server; do not supervise an agent.\n --dev-allow-all Accept any non-empty bearer (incl. no bearer) as\n builder. Local-dev / tunnel smoke ONLY \u2014 never\n expose to the open internet.\n --public-demo Public-facing demo posture: same any-bearer auth\n as --dev-allow-all, plus per-IP rate limit on\n ggui_render (30 generations / 10 min) and a\n \"PUBLIC DEMO \u2014 operator pays\" banner. Mutually\n exclusive with --dev-allow-all.\n --multi-tenant Multi-tenant posture: switches the /settings LLM-\n keys gate from admin-token to auth-adapter so\n each authenticated end-user manages their OWN\n key plane (scope = userId/appId). kind:'builder'\n identities are rejected at the gate. Strict-auth\n only; mutually exclusive with --dev-allow-all\n and --public-demo. (Generation-time BYOK still\n resolves at the operator 'global' scope \u2014 a\n follow-up will thread per-user BYOK through\n ggui_render.)\n --public-base-url <u> Override the public base URL used to compose\n iframe-runtime + shortCode URLs. Set this to a\n tunnel URL (https://<random>.trycloudflare.com)\n when testing against a remote MCP host so URLs\n resolve from the host's perspective. Without\n this, URLs derive from --host:--port and only\n work from the same machine.\n --browser-origin <o> Allow pages at this origin past MCP-wire Origin\n validation (repeatable; env GGUI_BROWSER_ORIGINS,\n comma-separated). Pages on localhost need no\n entry. NOT authentication \u2014 /mcp still requires\n a bearer. Non-browser clients are unaffected.\n --oauth Mount OAuth 2.1 + PKCE + Dynamic Client\n Registration routes (.well-known/oauth-* +\n /oauth/{authorize,token,register}). Required\n for MCP custom-connector hosts (claude.ai,\n ChatGPT) whose Add Connector form has no field\n for a pre-shared bearer; OAuth lets them do\n a discovery \u2192 DCR \u2192 consent dance ending in\n the same paired bearer the strict-auth flow\n already mints. Pure-bearer clients (Claude\n Desktop with bearer in config) work without it.\n --admin-token <t> Pin the admin bearer that gates the console\n /keys plane (list / mint / revoke pairings +\n /admin-login route). Without this, the server\n mints a fresh ggui_admin_* token per boot and\n prints it on the banner. Pin a stable value\n when you want the bearer to survive restarts\n (e.g. paste once into a password manager).\n --ephemeral Disable cross-restart persistence. Without\n this flag, the HMAC secrets that sign MCP\n Apps bootstrap tokens and signed render URLs\n are read or minted under .ggui/persistent/\n (project-local if a ggui.json was resolved,\n else ~/.ggui/persistent/) so cached tokens\n survive a server restart. Pass this flag to\n keep restarts ephemeral (tests / CI / nuclear-\n revoke). Override the dir via GGUI_PERSISTENT_DIR.\n --seed-pool <dir> Load a read-only shared blueprint pool from a\n directory artifact (repeatable). Blueprints in it\n are reused by exact contract match, after your own.\n --help, -h Show this help.\n\nAgent runtime:\n The default boots your agent alongside MCP. The agent's entry file\n comes from ggui.json:\n\n { \"agent\": { \"entry\": \"./agent.ts\" } }\n\n Supported extensions: .js / .mjs / .cjs (node), .ts / .tsx / .mts\n (node --import=tsx). No ggui.json, or no agent.entry, falls back\n to MCP-only with a warning. Malformed ggui.json or a bad entry\n is a hard error.\n\n Agent crashes after startup are logged; the MCP server keeps\n running. No auto-restart \u2014 compose that with your own supervisor.\n\nPersistent storage (default-on; opt-out via --ephemeral):\n By default `ggui serve` writes a small bundle under .ggui/persistent/\n (project-local if a ggui.json was resolved, else ~/.ggui/persistent/)\n so cached MCP Apps tokens, signed render URLs, shortCodes, renders,\n vectors, and paired bearers survive a restart \u2014 claude.ai chat-history\n revisits keep working.\n\n Bundle layout:\n\n .ggui/persistent/\n \u251C\u2500\u2500 ws-token-secret.hex (HMAC, 0600)\n \u251C\u2500\u2500 render-signer-secret.hex (HMAC, 0600)\n \u251C\u2500\u2500 short-codes.sqlite (signed render-URL resolution)\n \u251C\u2500\u2500 sessions.sqlite (GguiSessionStore \u2014 renders + event history)\n \u251C\u2500\u2500 vectors.sqlite (RAG corpus)\n \u2514\u2500\u2500 keys.json (paired bearers)\n\n Override the dir with `GGUI_PERSISTENT_DIR`. Pass `--ephemeral` to\n skip the bundle entirely (tests, CI loops, nuclear-revoke).\n\n Explicit ggui.json#storage declarations always win \u2014 declare\n `{ \"renders\": { \"driver\": \"memory\" } }` to opt renders back to\n in-memory while keeping other surfaces persistent. Custom sqlite\n paths via ggui.json#storage are honored verbatim:\n\n {\n \"storage\": {\n \"renders\": { \"driver\": \"sqlite\", \"path\": \"./ggui-sessions.sqlite\" },\n \"vectors\": { \"driver\": \"sqlite\", \"path\": \"./ggui-vectors.sqlite\" },\n \"threads\": { \"driver\": \"sqlite\", \"path\": \"./ggui-threads.sqlite\" }\n }\n }\n\n Threads: the persistent-chat route family (/threads) is opt-in.\n Absent `storage.threads` leaves the routes unmounted \u2014 pairs\n with Portal's self-hosted origins only when declared. Driver\n semantics:\n - `driver: \"sqlite\"` \u2014 durable. Threads survive restart.\n /ggui/health reports `threads.durability: \"durable\"`;\n Portal hides its non-durable caveat.\n - `driver: \"memory\"` \u2014 routes mount but data is lost on\n restart. /ggui/health reports `threads.durability:\n \"ephemeral\"`; Portal shows its caveat.\n\n Paths resolve relative to the ggui.json directory. The sqlite\n driver needs `better-sqlite3` installed in your project.\n\nRecommended setups:\n\n Local-only smoke (no tunnel, no remote MCP host):\n ggui serve\n\n claude.ai custom connector (over a public tunnel):\n 1. Tunnel: cloudflared tunnel --url http://localhost:6781\n 2. ggui serve --oauth \\\n --public-base-url https://<tunnel>.trycloudflare.com\n 3. Note PAIR_CODE from boot. Visit the landing page (the public URL\n above), complete pairing, save the bearer.\n 4. claude.ai \u2192 Settings \u2192 Connectors \u2192 Add custom connector.\n URL: https://<tunnel>.trycloudflare.com/mcp\n Client ID / Secret: leave empty (server uses Dynamic Client\n Registration; no pre-shared secret needed).\n 5. Click Connect \u2192 claude.ai redirects you to a paste-key page.\n Paste the bearer from step 3. Done.\n\n Quick local-dev WITHOUT auth (NEVER over a public tunnel):\n ggui serve --dev-allow-all\n\nCurrent limits:\n - Strict-auth only: /mcp rejects any bearer that isn't pair-minted.\n The CLI pre-mints one pairing code on boot (printed as\n `PAIR_CODE <code>` and shown in the banner + on the landing\n page). Complete `POST /pair {code, deviceName}` to receive a\n bearer you can use with MCP. Embed @ggui-ai/mcp-server in your\n own entrypoint to inject a different AuthAdapter (OIDC, Cognito,\n etc.) for production.\n - Single-tenant: every request scopes to one `builder` app id.\n";
504
517
  //# sourceMappingURL=serve-command.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"serve-command.d.ts","sourceRoot":"","sources":["../src/serve-command.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"serve-command.d.ts","sourceRoot":"","sources":["../src/serve-command.ts"],"names":[],"mappings":"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"}
@@ -27,6 +27,7 @@ export function parseServeFlags(args) {
27
27
  multiTenant: false,
28
28
  oauth: false,
29
29
  seedPools: [],
30
+ browserOrigins: [],
30
31
  };
31
32
  for (let i = 0; i < args.length; i++) {
32
33
  const arg = args[i];
@@ -138,6 +139,17 @@ export function parseServeFlags(args) {
138
139
  out.seedPools.push(value);
139
140
  continue;
140
141
  }
142
+ if (arg === '--browser-origin') {
143
+ const value = args[++i];
144
+ if (value === undefined) {
145
+ return {
146
+ ...out,
147
+ error: '--browser-origin requires an origin (e.g. https://app.example.com)',
148
+ };
149
+ }
150
+ out.browserOrigins.push(value);
151
+ continue;
152
+ }
141
153
  if (arg === '--all') {
142
154
  // §10.2a lock: --all is NOT a first-class flag. The default
143
155
  // already runs everything. Reject with a pointer so users
@@ -246,6 +258,15 @@ export function describeServeBanner(input) {
246
258
  lines.push(``, ` oauth: enabled — MCP custom-connector hosts (claude.ai etc.)`, ` can discover via /.well-known/oauth-* and complete the`, ` auth dance against /oauth/{authorize,token,register}.`, ` Paste the paired bearer on the consent page.`);
247
259
  }
248
260
  }
261
+ lines.push(input.browserOrigins && input.browserOrigins.length > 0
262
+ ? ` browser origins → loopback (auto) + ${input.browserOrigins.length} allowed`
263
+ : ` browser origins → loopback only (add with --browser-origin <origin>)`);
264
+ if (input.devAllowAll && !['localhost', '127.0.0.1', '::1', '[::1]'].includes(input.host)) {
265
+ // Documented residual (ggui#438a): wide bind disables the Host
266
+ // check by design, and --dev-allow-all removes the bearer. The
267
+ // combination must never be silent.
268
+ lines.push('', ` ⚠ --dev-allow-all on a non-loopback bind (${input.host}): no bearer AND no`, ' Host check — anything that can reach this address (including a DNS-', ' rebound page) has full tool access. Use only on trusted networks.');
269
+ }
249
270
  lines.push('', ` Ctrl-C to stop.`, '');
250
271
  return lines;
251
272
  }
@@ -369,6 +390,9 @@ export async function runServe(opts) {
369
390
  ...(backend.adminToken ? { adminToken: backend.adminToken } : {}),
370
391
  ...(opts.noLlmKey ? { noLlmKey: true } : {}),
371
392
  ...(backend.embeddingModel ? { embeddingModel: backend.embeddingModel } : {}),
393
+ ...(opts.flags.browserOrigins.length > 0
394
+ ? { browserOrigins: opts.flags.browserOrigins }
395
+ : {}),
372
396
  });
373
397
  opts.stdout.write(`${bannerLines.join('\n')}\n`);
374
398
  // Auto-open the operator's browser at the local URL. The server's
@@ -478,6 +502,11 @@ Options:
478
502
  resolve from the host's perspective. Without
479
503
  this, URLs derive from --host:--port and only
480
504
  work from the same machine.
505
+ --browser-origin <o> Allow pages at this origin past MCP-wire Origin
506
+ validation (repeatable; env GGUI_BROWSER_ORIGINS,
507
+ comma-separated). Pages on localhost need no
508
+ entry. NOT authentication — /mcp still requires
509
+ a bearer. Non-browser clients are unaffected.
481
510
  --oauth Mount OAuth 2.1 + PKCE + Dynamic Client
482
511
  Registration routes (.well-known/oauth-* +
483
512
  /oauth/{authorize,token,register}). Required
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ggui-ai/cli",
3
- "version": "0.6.2",
3
+ "version": "0.7.0",
4
4
  "description": "The `ggui` CLI — run the ggui protocol locally: dev server, self-hosted MCP server, and gadget / blueprint authoring. End-to-end OSS and self-hosted workflows; no account required.",
5
5
  "keywords": [
6
6
  "ggui",
@@ -37,22 +37,22 @@
37
37
  "@noble/hashes": "^1.6.0",
38
38
  "esbuild": "^0.25.12",
39
39
  "zod": "^4.3.6",
40
- "@ggui-ai/artifact-manifest": "0.6.2",
41
- "@ggui-ai/design": "0.6.2",
42
- "@ggui-ai/agent-runtime": "0.6.2",
43
- "@ggui-ai/dev-stack": "0.6.2",
44
- "@ggui-ai/gadget-signing": "0.6.2",
45
- "@ggui-ai/embedding-local": "0.6.2",
46
- "@ggui-ai/mcp-server": "0.6.2",
47
- "@ggui-ai/mcp-server-core": "0.6.2",
48
- "@ggui-ai/mcp-server-handlers": "0.6.2",
49
- "@ggui-ai/preview-a2ui": "0.6.2",
50
- "@ggui-ai/project-config": "0.6.2",
51
- "@ggui-ai/registry-core": "0.6.2",
52
- "@ggui-ai/iframe-runtime": "0.6.2",
53
- "@ggui-ai/ui-gen": "0.6.2",
54
- "@ggui-ai/protocol": "0.6.2",
55
- "@ggui-ai/ui-registry": "0.6.2"
40
+ "@ggui-ai/agent-runtime": "0.7.0",
41
+ "@ggui-ai/artifact-manifest": "0.7.0",
42
+ "@ggui-ai/design": "0.7.0",
43
+ "@ggui-ai/dev-stack": "0.7.0",
44
+ "@ggui-ai/gadget-signing": "0.7.0",
45
+ "@ggui-ai/embedding-local": "0.7.0",
46
+ "@ggui-ai/mcp-server": "0.7.0",
47
+ "@ggui-ai/mcp-server-core": "0.7.0",
48
+ "@ggui-ai/preview-a2ui": "0.7.0",
49
+ "@ggui-ai/mcp-server-handlers": "0.7.0",
50
+ "@ggui-ai/project-config": "0.7.0",
51
+ "@ggui-ai/registry-core": "0.7.0",
52
+ "@ggui-ai/protocol": "0.7.0",
53
+ "@ggui-ai/iframe-runtime": "0.7.0",
54
+ "@ggui-ai/ui-gen": "0.7.0",
55
+ "@ggui-ai/ui-registry": "0.7.0"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@types/node": "^24.0.0",