@ggui-ai/cli 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.
Files changed (80) hide show
  1. package/README.md +38 -7
  2. package/dist/api-client.d.ts +42 -1
  3. package/dist/api-client.d.ts.map +1 -1
  4. package/dist/api-client.js +30 -2
  5. package/dist/auth-keys.d.ts +1 -1
  6. package/dist/auth-keys.d.ts.map +1 -1
  7. package/dist/auth-keys.js +22 -7
  8. package/dist/auth-store.d.ts +1 -1
  9. package/dist/auth-store.d.ts.map +1 -1
  10. package/dist/cli.js +112 -30
  11. package/dist/config-push.d.ts +79 -0
  12. package/dist/config-push.d.ts.map +1 -0
  13. package/dist/config-push.js +301 -0
  14. package/dist/create-app-command.d.ts +17 -0
  15. package/dist/create-app-command.d.ts.map +1 -0
  16. package/dist/create-app-command.js +58 -0
  17. package/dist/deploy-command.d.ts +67 -0
  18. package/dist/deploy-command.d.ts.map +1 -0
  19. package/dist/deploy-command.js +386 -0
  20. package/dist/dev-command.d.ts +5 -1
  21. package/dist/dev-command.d.ts.map +1 -1
  22. package/dist/dev-command.js +31 -1
  23. package/dist/export-pool-command.d.ts +25 -0
  24. package/dist/export-pool-command.d.ts.map +1 -0
  25. package/dist/export-pool-command.js +116 -0
  26. package/dist/filesystem-seed-pool-source.d.ts +13 -0
  27. package/dist/filesystem-seed-pool-source.d.ts.map +1 -0
  28. package/dist/filesystem-seed-pool-source.js +22 -0
  29. package/dist/generation-probe.d.ts +53 -7
  30. package/dist/generation-probe.d.ts.map +1 -1
  31. package/dist/generation-probe.js +37 -1
  32. package/dist/internal/artifact-install.d.ts +4 -2
  33. package/dist/internal/artifact-install.d.ts.map +1 -1
  34. package/dist/internal/artifact-install.js +11 -10
  35. package/dist/internal/artifact-publish.d.ts +34 -31
  36. package/dist/internal/artifact-publish.d.ts.map +1 -1
  37. package/dist/internal/artifact-publish.js +133 -241
  38. package/dist/internal/artifact-search.d.ts +2 -28
  39. package/dist/internal/artifact-search.d.ts.map +1 -1
  40. package/dist/internal/artifact-search.js +5 -4
  41. package/dist/internal/auth-strategy.d.ts +21 -31
  42. package/dist/internal/auth-strategy.d.ts.map +1 -1
  43. package/dist/internal/auth-strategy.js +15 -23
  44. package/dist/internal/register-author-key.d.ts +7 -1
  45. package/dist/internal/register-author-key.d.ts.map +1 -1
  46. package/dist/internal/register-author-key.js +56 -19
  47. package/dist/mcp-backend.d.ts +25 -25
  48. package/dist/mcp-backend.d.ts.map +1 -1
  49. package/dist/mcp-backend.js +65 -61
  50. package/dist/paths.d.ts +3 -3
  51. package/dist/paths.js +3 -3
  52. package/dist/persistent-secrets.js +1 -1
  53. package/dist/persistent-stores.d.ts +2 -2
  54. package/dist/persistent-stores.d.ts.map +1 -1
  55. package/dist/persistent-stores.js +5 -5
  56. package/dist/pool-artifact.d.ts +19 -0
  57. package/dist/pool-artifact.d.ts.map +1 -0
  58. package/dist/pool-artifact.js +59 -0
  59. package/dist/provider-key-command.d.ts +51 -0
  60. package/dist/provider-key-command.d.ts.map +1 -0
  61. package/dist/provider-key-command.js +222 -0
  62. package/dist/push-command.d.ts +47 -0
  63. package/dist/push-command.d.ts.map +1 -0
  64. package/dist/push-command.js +230 -0
  65. package/dist/serve-command.d.ts +23 -19
  66. package/dist/serve-command.d.ts.map +1 -1
  67. package/dist/serve-command.js +13 -26
  68. package/dist/theme-command.js +0 -2
  69. package/dist/tunnel-provider.d.ts +8 -7
  70. package/dist/tunnel-provider.d.ts.map +1 -1
  71. package/package.json +25 -21
  72. package/dist/internal/auth-cache.d.ts +0 -40
  73. package/dist/internal/auth-cache.d.ts.map +0 -1
  74. package/dist/internal/auth-cache.js +0 -133
  75. package/dist/persistent-short-code-index.d.ts +0 -14
  76. package/dist/persistent-short-code-index.d.ts.map +0 -1
  77. package/dist/persistent-short-code-index.js +0 -39
  78. package/dist/spawn-cloudflared.d.ts +0 -61
  79. package/dist/spawn-cloudflared.d.ts.map +0 -1
  80. package/dist/spawn-cloudflared.js +0 -167
@@ -1,48 +1,44 @@
1
1
  /**
2
- * Vendor-neutral auth strategy for marketplace CLI verbs
2
+ * Auth strategy for marketplace CLI verbs
3
3
  * (`ggui {gadget,blueprint} publish`).
4
4
  *
5
5
  * Two strategies — explicit `--auth=bearer` for self-hosted and local
6
- * registries, and the (default) hosted-auth flow for the cloud
7
- * registry. The default flow is implemented behind a vendor-neutral
8
- * function name (`acquireHostedAuthJwt`) so this surface never names
9
- * any specific identity provider; the underlying implementation in
10
- * `artifact-publish` calls the cloud's hosted auth provider.
11
- *
12
- * The public surface (this file, its consumers, and the CLI help
13
- * text) stays vendor-neutral.
6
+ * registries, and the (default) `ggui login` session: the CLI reuses
7
+ * the credential the device flow stored at `~/.ggui/auth.json`,
8
+ * refreshing it when expired. The session acquisition itself lives in
9
+ * `artifact-publish` (`acquireLoginSessionToken`) and is injected here
10
+ * as a callback so this router stays IO-free.
14
11
  *
15
12
  * @example
16
13
  * ```ts
17
14
  * import { parseAuthFlags, acquireAuthToken } from './internal/auth-strategy.js';
18
15
  *
19
16
  * const authFlags = parseAuthFlags(args);
20
- * const jwt = await acquireAuthToken({
17
+ * const token = await acquireAuthToken({
21
18
  * flags: authFlags,
22
19
  * env: process.env,
23
- * registryUrl,
24
- * acquireHostedAuthJwt,
20
+ * acquireSessionToken,
25
21
  * });
26
22
  * ```
27
23
  */
28
24
  /**
29
- * Parsed `--auth=<mode>` + `--token <token>` flags. Vendor-neutral.
25
+ * Parsed `--auth=<mode>` + `--token <token>` flags.
30
26
  *
31
- * `auth: undefined` means "use the default (hosted auth via the
32
- * registry)". The only public flag value is `'bearer'`.
27
+ * `auth: undefined` means "use the default (the stored `ggui login`
28
+ * session)". The only public flag value is `'bearer'`.
33
29
  */
34
30
  export interface AuthFlags {
35
31
  /** Auth mode. Only `'bearer'` is admitted as a public value; absent
36
- * means "default = hosted auth via the configured registry". */
32
+ * means "default = the stored `ggui login` session". */
37
33
  readonly auth?: 'bearer';
38
34
  /** Explicit bearer token. Used only when `auth === 'bearer'`. */
39
35
  readonly token?: string;
40
36
  }
41
37
  /**
42
38
  * Help-text fragment for the auth flags, inlined into each subcommand's
43
- * help block. Vendor-neutral copy — never name the identity provider.
39
+ * help block.
44
40
  */
45
- export declare const AUTH_HELP_FRAGMENT = "Auth:\n --auth=bearer Use a bearer token (for self-hosted or local\n registries). Pair with --token <token> or set\n GGUI_REGISTRY_TOKEN in the environment.\n --token <token> Bearer token (paired with --auth=bearer).\n (default) Hosted auth via the configured registry \u2014\n no flag needed; the CLI prompts for credentials\n on first publish and caches the resulting\n session at ~/.ggui/auth/<registry-host>/token.json.\n";
41
+ export declare const AUTH_HELP_FRAGMENT = "Auth:\n --auth=bearer Use a bearer token (for self-hosted or local\n registries). Pair with --token <token> or set\n GGUI_REGISTRY_TOKEN in the environment.\n --token <token> Bearer token (paired with --auth=bearer).\n (default) Your `ggui login` session \u2014 the CLI reads\n ~/.ggui/auth.json and refreshes the token\n automatically when it has expired. Run\n `ggui login` first.\n";
46
42
  /**
47
43
  * Pop the auth-related flags out of an argv-like list, returning the
48
44
  * parsed flags + the residual args (so subcommand parsers can keep
@@ -58,22 +54,18 @@ export declare function parseAuthFlags(args: readonly string[]): {
58
54
  error: string;
59
55
  };
60
56
  /**
61
- * Hosted-auth callback shape. Vendor-neutral by design — the caller
62
- * injects the actual implementation (which today calls the cloud
63
- * registry's hosted auth vendor).
57
+ * Login-session callback shape. The caller injects the actual
58
+ * implementation (`acquireLoginSessionToken` in `artifact-publish`,
59
+ * which reads `~/.ggui/auth.json` + refreshes when expired).
64
60
  *
65
- * Returns the bearer JWT the CLI sends as `Authorization: Bearer <jwt>`.
61
+ * Returns the bearer token the CLI sends as `Authorization: Bearer <token>`.
66
62
  */
67
- export type HostedAuthAcquirer = (deps: {
68
- readonly registryUrl: string;
69
- readonly env: NodeJS.ProcessEnv;
70
- readonly cwd: string;
71
- }) => Promise<string>;
63
+ export type SessionTokenAcquirer = () => Promise<string>;
72
64
  /**
73
65
  * Acquire the auth token to send to the registry. Routes:
74
66
  *
75
67
  * - `flags.auth === 'bearer'` → use `flags.token` || `GGUI_REGISTRY_TOKEN`
76
- * - otherwise → call `acquireHostedAuthJwt`
68
+ * - otherwise → call `acquireSessionToken` (the stored `ggui login` session)
77
69
  *
78
70
  * Throws (with an operator-readable message) when bearer auth is
79
71
  * selected but no token is supplied; the message names the env var so
@@ -82,8 +74,6 @@ export type HostedAuthAcquirer = (deps: {
82
74
  export declare function acquireAuthToken(deps: {
83
75
  readonly flags: AuthFlags;
84
76
  readonly env: NodeJS.ProcessEnv;
85
- readonly cwd: string;
86
- readonly registryUrl: string;
87
- readonly acquireHostedAuthJwt: HostedAuthAcquirer;
77
+ readonly acquireSessionToken: SessionTokenAcquirer;
88
78
  }): Promise<string>;
89
79
  //# sourceMappingURL=auth-strategy.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth-strategy.d.ts","sourceRoot":"","sources":["../../src/internal/auth-strategy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACxB;oEACgE;IAChE,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC;IACzB,iEAAiE;IACjE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,sjBAS9B,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,SAAS,MAAM,EAAE,GACtB;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAuDnE;AAED;;;;;;GAMG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,IAAI,EAAE;IACtC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IAChC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAEtB;;;;;;;;;GASG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IAChC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,oBAAoB,EAAE,kBAAkB,CAAC;CACnD,GAAG,OAAO,CAAC,MAAM,CAAC,CAsBlB"}
1
+ {"version":3,"file":"auth-strategy.d.ts","sourceRoot":"","sources":["../../src/internal/auth-strategy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACxB;4DACwD;IACxD,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC;IACzB,iEAAiE;IACjE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,6gBAS9B,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,SAAS,MAAM,EAAE,GACtB;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAuDnE;AAED;;;;;;GAMG;AACH,MAAM,MAAM,oBAAoB,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;AAEzD;;;;;;;;;GASG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IAChC,QAAQ,CAAC,mBAAmB,EAAE,oBAAoB,CAAC;CACpD,GAAG,OAAO,CAAC,MAAM,CAAC,CAkBlB"}
@@ -1,43 +1,39 @@
1
1
  /**
2
- * Vendor-neutral auth strategy for marketplace CLI verbs
2
+ * Auth strategy for marketplace CLI verbs
3
3
  * (`ggui {gadget,blueprint} publish`).
4
4
  *
5
5
  * Two strategies — explicit `--auth=bearer` for self-hosted and local
6
- * registries, and the (default) hosted-auth flow for the cloud
7
- * registry. The default flow is implemented behind a vendor-neutral
8
- * function name (`acquireHostedAuthJwt`) so this surface never names
9
- * any specific identity provider; the underlying implementation in
10
- * `artifact-publish` calls the cloud's hosted auth provider.
11
- *
12
- * The public surface (this file, its consumers, and the CLI help
13
- * text) stays vendor-neutral.
6
+ * registries, and the (default) `ggui login` session: the CLI reuses
7
+ * the credential the device flow stored at `~/.ggui/auth.json`,
8
+ * refreshing it when expired. The session acquisition itself lives in
9
+ * `artifact-publish` (`acquireLoginSessionToken`) and is injected here
10
+ * as a callback so this router stays IO-free.
14
11
  *
15
12
  * @example
16
13
  * ```ts
17
14
  * import { parseAuthFlags, acquireAuthToken } from './internal/auth-strategy.js';
18
15
  *
19
16
  * const authFlags = parseAuthFlags(args);
20
- * const jwt = await acquireAuthToken({
17
+ * const token = await acquireAuthToken({
21
18
  * flags: authFlags,
22
19
  * env: process.env,
23
- * registryUrl,
24
- * acquireHostedAuthJwt,
20
+ * acquireSessionToken,
25
21
  * });
26
22
  * ```
27
23
  */
28
24
  /**
29
25
  * Help-text fragment for the auth flags, inlined into each subcommand's
30
- * help block. Vendor-neutral copy — never name the identity provider.
26
+ * help block.
31
27
  */
32
28
  export const AUTH_HELP_FRAGMENT = `Auth:
33
29
  --auth=bearer Use a bearer token (for self-hosted or local
34
30
  registries). Pair with --token <token> or set
35
31
  GGUI_REGISTRY_TOKEN in the environment.
36
32
  --token <token> Bearer token (paired with --auth=bearer).
37
- (default) Hosted auth via the configured registry —
38
- no flag needed; the CLI prompts for credentials
39
- on first publish and caches the resulting
40
- session at ~/.ggui/auth/<registry-host>/token.json.
33
+ (default) Your \`ggui login\` session — the CLI reads
34
+ ~/.ggui/auth.json and refreshes the token
35
+ automatically when it has expired. Run
36
+ \`ggui login\` first.
41
37
  `;
42
38
  /**
43
39
  * Pop the auth-related flags out of an argv-like list, returning the
@@ -104,7 +100,7 @@ export function parseAuthFlags(args) {
104
100
  * Acquire the auth token to send to the registry. Routes:
105
101
  *
106
102
  * - `flags.auth === 'bearer'` → use `flags.token` || `GGUI_REGISTRY_TOKEN`
107
- * - otherwise → call `acquireHostedAuthJwt`
103
+ * - otherwise → call `acquireSessionToken` (the stored `ggui login` session)
108
104
  *
109
105
  * Throws (with an operator-readable message) when bearer auth is
110
106
  * selected but no token is supplied; the message names the env var so
@@ -124,9 +120,5 @@ export async function acquireAuthToken(deps) {
124
120
  }
125
121
  return token;
126
122
  }
127
- return deps.acquireHostedAuthJwt({
128
- registryUrl: deps.registryUrl,
129
- env: deps.env,
130
- cwd: deps.cwd,
131
- });
123
+ return deps.acquireSessionToken();
132
124
  }
@@ -1,10 +1,11 @@
1
+ import { type AuthFlags } from './auth-strategy.js';
1
2
  /**
2
3
  * Outcome discriminator. The `ok: false` `code` union surfaces specific
3
4
  * HTTP failure modes so callers (notably a future `--json` flag) can
4
5
  * branch on the registry's closed error set without parsing the human-
5
6
  * readable message:
6
7
  *
7
- * - `unauthorized` ← HTTP 401 (missing/invalid Cognito JWT).
8
+ * - `unauthorized` ← HTTP 401 (missing/invalid bearer credential).
8
9
  * - `invalid_request` ← HTTP 400 (malformed body or wrong key length).
9
10
  * - `key_conflict` ← HTTP 409 (collision against an existing row).
10
11
  * - `http-error` ← any other non-2xx (5xx or unexpected status).
@@ -29,6 +30,11 @@ export type RegisterKeyOutcome = {
29
30
  export interface RunRegisterKeyFlags {
30
31
  readonly scope: string;
31
32
  readonly registry?: string;
33
+ /** Auth strategy + bearer token. `undefined` → the stored `ggui
34
+ * login` session; `{ auth: 'bearer', token? }` → explicit bearer
35
+ * (self-hosted registries), token from the flag or
36
+ * `GGUI_REGISTRY_TOKEN`. Mirrors the publish flow's `AuthFlags`. */
37
+ readonly auth?: AuthFlags;
32
38
  }
33
39
  export interface RunRegisterKeyDeps {
34
40
  readonly cwd: string;
@@ -1 +1 @@
1
- {"version":3,"file":"register-author-key.d.ts","sourceRoot":"","sources":["../../src/internal/register-author-key.ts"],"names":[],"mappings":"AA2BA;;;;;;;;;;;;;;;;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;CAC5B;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;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,mBAAmB,EAC1B,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,kBAAkB,CAAC,CA0J7B"}
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"}
@@ -6,20 +6,36 @@
6
6
  * `aws dynamodb put-item` workflow that previously required raw IAM
7
7
  * credentials + registry table knowledge.
8
8
  *
9
- * The publisher's identity is the Cognito JWT's `sub` (server-side);
10
- * the body carries only `publicKeyBase64`. `keyId` is derived from the
11
- * public-key bytes on the server, so re-running with the same key is
12
- * idempotent (200 OK).
9
+ * The publisher's identity is derived server-side from the verified
10
+ * bearer credential; the body carries only `publicKeyBase64`. `keyId`
11
+ * is derived from the public-key bytes on the server, so re-running
12
+ * with the same key is idempotent (200 OK).
13
13
  *
14
- * Auth + registry-URL resolution match the publish flow (so the
15
- * cached token / `GGUI_REGISTRY` env / `ggui.json#registry` chain
16
- * works the same way operators are used to).
14
+ * Auth + registry-URL resolution match the publish flow (the stored
15
+ * `ggui login` session by default, `--auth=bearer --token <token>` /
16
+ * `GGUI_REGISTRY_TOKEN` for self-hosted registries; `GGUI_REGISTRY`
17
+ * env / `ggui.json#registry` URL chain works the same way operators
18
+ * are used to).
17
19
  */
18
20
  import { readFileSync } from 'node:fs';
19
21
  import { REGISTER_AUTHOR_KEY_ERROR_CODES } from '@ggui-ai/registry-core';
20
- import { acquireHostedAuthJwt, } from './artifact-publish.js';
22
+ import { acquireLoginSessionToken, } from './artifact-publish.js';
21
23
  import { resolveRegistryUrl } from './artifact-search.js';
24
+ import { acquireAuthToken } from './auth-strategy.js';
22
25
  import { getPublicKeyPath, hasKeypair } from './key-store.js';
26
+ /**
27
+ * Sentinel that carries the structured {@link AuthFailed} payload
28
+ * through `acquireAuthToken`'s throwing session callback — the
29
+ * register flow's never-throws contract maps it back to an outcome.
30
+ * Mirrors `SessionAuthError` in `artifact-publish.ts`.
31
+ */
32
+ class SessionOutcomeError extends Error {
33
+ payload;
34
+ constructor(payload) {
35
+ super(payload.error.message);
36
+ this.payload = payload;
37
+ }
38
+ }
23
39
  /**
24
40
  * Run the register flow end-to-end. Never throws — every error path
25
41
  * returns a structured outcome.
@@ -75,18 +91,39 @@ export async function runRegisterAuthorKey(flags, deps) {
75
91
  };
76
92
  }
77
93
  const publicKeyBase64 = publicKeyBytes.toString('base64');
78
- // 3. Hosted-auth Cognito JWT — same chain as publish.
79
- const auth = await acquireHostedAuthJwt({
80
- registryUrl: resolved.url,
81
- env: deps.env,
82
- cwd: deps.cwd,
83
- now: deps.now,
84
- });
85
- if (!auth.ok) {
94
+ // 3. Credential — same two-path strategy as publish:
95
+ // --auth=bearer → token from the flag or GGUI_REGISTRY_TOKEN
96
+ // default → the stored `ggui login` session.
97
+ let accessToken;
98
+ try {
99
+ accessToken = await acquireAuthToken({
100
+ flags: flags.auth ?? {},
101
+ env: deps.env,
102
+ acquireSessionToken: async () => {
103
+ const auth = await acquireLoginSessionToken({
104
+ now: deps.now,
105
+ fetchImpl: deps.fetch,
106
+ });
107
+ if (!auth.ok)
108
+ throw new SessionOutcomeError(auth);
109
+ return auth.accessToken;
110
+ },
111
+ });
112
+ }
113
+ catch (err) {
114
+ if (err instanceof SessionOutcomeError) {
115
+ return {
116
+ ok: false,
117
+ code: err.payload.error.code,
118
+ message: err.payload.error.message,
119
+ };
120
+ }
121
+ // Bearer selected but no token supplied — `acquireAuthToken`
122
+ // throws with an operator-readable message naming the env var.
86
123
  return {
87
124
  ok: false,
88
- code: auth.error.code,
89
- message: auth.error.message,
125
+ code: 'auth_config_missing',
126
+ message: err instanceof Error ? err.message : String(err),
90
127
  };
91
128
  }
92
129
  // 4. POST /author-keys
@@ -97,7 +134,7 @@ export async function runRegisterAuthorKey(flags, deps) {
97
134
  method: 'POST',
98
135
  headers: {
99
136
  'content-type': 'application/json',
100
- authorization: `Bearer ${auth.token.idToken}`,
137
+ authorization: `Bearer ${accessToken}`,
101
138
  },
102
139
  body: JSON.stringify({ publicKeyBase64 }),
103
140
  });
@@ -1,5 +1,6 @@
1
1
  import { type BlueprintProvider, type DiscoveredPrimitiveCatalog, type GadgetDescriptor, type GenerationDeps, type LoadedTheme, type McpServerMount, type McpUiDisplayMode, type OperatorConfig, type ResolvedStorageStores, type ShortCodeIndex, type ThemeWriter } from "@ggui-ai/mcp-server";
2
- import type { UiManifest } from "@ggui-ai/project-config";
2
+ import { type BlueprintPool } from "@ggui-ai/mcp-server-handlers/renders";
3
+ import type { ThemeConfig, UiManifest } from "@ggui-ai/project-config";
3
4
  import type { UiRegistry } from "@ggui-ai/ui-registry";
4
5
  import type { ServeBackend } from "./serve-command.js";
5
6
  export interface BuildMcpServerBackendOptions {
@@ -94,21 +95,15 @@ export interface BuildMcpServerBackendOptions {
94
95
  * Optional change notifier — fires from
95
96
  * `mountDevtoolThemeRoutes`'s POST handlers when the operator
96
97
  * saves a new theme via the picker. Pair with `themeProvider` so
97
- * the push handler reads the live theme on every call.
98
+ * the render handler reads the live theme on every call.
99
+ * `null` = cleared.
98
100
  */
99
- readonly onThemeConfigChange?: (next: string | {
100
- preset: string;
101
- mode?: "light" | "dark";
102
- overrides?: Record<string, string>;
103
- } | {
104
- file: string;
105
- mode?: "light" | "dark";
106
- } | null) => void;
101
+ readonly onThemeConfigChange?: (next: ThemeConfig | null) => void;
107
102
  /**
108
103
  * Generation wiring for `ggui_render`. When present, the OSS render
109
104
  * handler invokes the bound `UiGenerator` on every story-path
110
- * call and commits real componentCode as a `Render`. Absent =
111
- * placeholder mode: render mints renderIds + shortCodes but does
105
+ * call and commits real componentCode as a `GguiSession`. Absent =
106
+ * placeholder mode: render mints sessionIds + shortCodes but does
112
107
  * not produce componentCode.
113
108
  *
114
109
  * The CLI resolves this from the operator's BYOK state at boot via
@@ -119,6 +114,12 @@ export interface BuildMcpServerBackendOptions {
119
114
  * setting, a test double, etc.).
120
115
  */
121
116
  readonly generation?: GenerationDeps;
117
+ /**
118
+ * Read-only shared/seed blueprint pools for cross-deployment reuse.
119
+ * Threaded into the handshake negotiator's `seedPools`. Built by the
120
+ * CLI from `--seed-pool` artifacts; absent ⇒ no shared pool.
121
+ */
122
+ readonly seedPools?: readonly BlueprintPool[];
122
123
  /**
123
124
  * Marketplace-install bridge data. When set, the backend
124
125
  * constructs an
@@ -127,8 +128,9 @@ export interface BuildMcpServerBackendOptions {
127
128
  * into `generation.installedBlueprints`. On the first
128
129
  * `matchBlueprint` call per scope, every entry with a contract is
129
130
  * compiled (esbuild) and registered into the cache with
130
- * `provenance: 'install'` — so installed blueprints accelerate
131
- * render the way synth-cached ones do.
131
+ * `source: {kind: 'user'}` + the `installed` lifecycle marker — so
132
+ * installed blueprints accelerate render the way cold-gen-cached
133
+ * ones do.
132
134
  *
133
135
  * Caller is responsible for filtering `entries` to actual
134
136
  * marketplace installs (typically: discovered UIs whose
@@ -258,17 +260,15 @@ export interface BuildMcpServerBackendOptions {
258
260
  readonly persistentDir?: string;
259
261
  /**
260
262
  * Pre-resolved `ShortCodeIndex` implementation. When set, replaces
261
- * the default `InMemoryShortCodeIndex` — typically the caller passes
262
- * `SqliteShortCodeIndex` rooted under `persistentDir` so cached
263
- * `/api/bootstrap/<code>` URLs (and the `/r/<code>` viewer) keep
264
- * resolving after a `ggui serve` restart. Without that, the index
265
- * is process-local and every restart turns prior shortCodes into
266
- * 404s — defeating the bootstrap-secret persistence above.
263
+ * the default `InMemoryShortCodeIndex` — e.g. a `SqliteShortCodeIndex`
264
+ * rooted under `persistentDir` so cached `/api/bootstrap/<code>` URLs
265
+ * keep resolving after a `ggui serve` restart. With the in-memory
266
+ * default the index is process-local and every restart turns prior
267
+ * shortCodes into 404s — defeating the bootstrap-secret persistence
268
+ * above.
267
269
  *
268
- * Absent = `InMemoryShortCodeIndex` (the legacy default, fine for
269
- * tests + `--ephemeral`). The CLI composes this via
270
- * `createPersistentShortCodeIndex(persistentDir)` in cli.ts so the
271
- * sqlite peer-dep loads lazily.
270
+ * Absent = `InMemoryShortCodeIndex` (the default, fine for tests +
271
+ * `--ephemeral`).
272
272
  */
273
273
  readonly shortCodeIndex?: ShortCodeIndex;
274
274
  /**
@@ -299,7 +299,7 @@ export interface BuildMcpServerBackendOptions {
299
299
  * Per-app gadget catalog from `ggui.json#app.gadgets`.
300
300
  * Gadgets (Leaflet, Mapbox, …) declared
301
301
  * here populate `App.gadgets` so the
302
- * `assertGadgetsRegistered` validator (push, ops_register,
302
+ * `assertGadgetsRegistered` validator (render, ops_register,
303
303
  * ops_generate) accepts contracts that reference them.
304
304
  *
305
305
  * Omitted ⇒ `STDLIB_GADGETS` defaults from
@@ -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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"}