@ggui-ai/cli 0.1.0-rc.1

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 (117) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +96 -0
  3. package/dist/agent-resolution.d.ts +41 -0
  4. package/dist/agent-resolution.d.ts.map +1 -0
  5. package/dist/agent-resolution.js +80 -0
  6. package/dist/api-client.d.ts +59 -0
  7. package/dist/api-client.d.ts.map +1 -0
  8. package/dist/api-client.js +145 -0
  9. package/dist/auth-keys.d.ts +10 -0
  10. package/dist/auth-keys.d.ts.map +1 -0
  11. package/dist/auth-keys.js +382 -0
  12. package/dist/auth-login.d.ts +11 -0
  13. package/dist/auth-login.d.ts.map +1 -0
  14. package/dist/auth-login.js +231 -0
  15. package/dist/auth-logout.d.ts +3 -0
  16. package/dist/auth-logout.d.ts.map +1 -0
  17. package/dist/auth-logout.js +32 -0
  18. package/dist/auth-store.d.ts +67 -0
  19. package/dist/auth-store.d.ts.map +1 -0
  20. package/dist/auth-store.js +150 -0
  21. package/dist/auth-whoami.d.ts +3 -0
  22. package/dist/auth-whoami.d.ts.map +1 -0
  23. package/dist/auth-whoami.js +52 -0
  24. package/dist/blueprint-command.d.ts +3 -0
  25. package/dist/blueprint-command.d.ts.map +1 -0
  26. package/dist/blueprint-command.js +203 -0
  27. package/dist/blueprint-create.d.ts +71 -0
  28. package/dist/blueprint-create.d.ts.map +1 -0
  29. package/dist/blueprint-create.js +377 -0
  30. package/dist/byok-resolver.d.ts +141 -0
  31. package/dist/byok-resolver.d.ts.map +1 -0
  32. package/dist/byok-resolver.js +89 -0
  33. package/dist/cli.d.ts +3 -0
  34. package/dist/cli.d.ts.map +1 -0
  35. package/dist/cli.js +1066 -0
  36. package/dist/dev-command.d.ts +169 -0
  37. package/dist/dev-command.d.ts.map +1 -0
  38. package/dist/dev-command.js +222 -0
  39. package/dist/gadget-command.d.ts +3 -0
  40. package/dist/gadget-command.d.ts.map +1 -0
  41. package/dist/gadget-command.js +181 -0
  42. package/dist/gadget-create.d.ts +106 -0
  43. package/dist/gadget-create.d.ts.map +1 -0
  44. package/dist/gadget-create.js +492 -0
  45. package/dist/generation-probe.d.ts +135 -0
  46. package/dist/generation-probe.d.ts.map +1 -0
  47. package/dist/generation-probe.js +132 -0
  48. package/dist/internal/artifact-install.d.ts +150 -0
  49. package/dist/internal/artifact-install.d.ts.map +1 -0
  50. package/dist/internal/artifact-install.js +1019 -0
  51. package/dist/internal/artifact-publish.d.ts +204 -0
  52. package/dist/internal/artifact-publish.d.ts.map +1 -0
  53. package/dist/internal/artifact-publish.js +1141 -0
  54. package/dist/internal/artifact-search.d.ts +155 -0
  55. package/dist/internal/artifact-search.d.ts.map +1 -0
  56. package/dist/internal/artifact-search.js +539 -0
  57. package/dist/internal/artifact-uninstall.d.ts +30 -0
  58. package/dist/internal/artifact-uninstall.d.ts.map +1 -0
  59. package/dist/internal/artifact-uninstall.js +205 -0
  60. package/dist/internal/auth-cache.d.ts +40 -0
  61. package/dist/internal/auth-cache.d.ts.map +1 -0
  62. package/dist/internal/auth-cache.js +133 -0
  63. package/dist/internal/auth-strategy.d.ts +89 -0
  64. package/dist/internal/auth-strategy.d.ts.map +1 -0
  65. package/dist/internal/auth-strategy.js +132 -0
  66. package/dist/internal/ggui-json.d.ts +53 -0
  67. package/dist/internal/ggui-json.d.ts.map +1 -0
  68. package/dist/internal/ggui-json.js +92 -0
  69. package/dist/internal/key-store.d.ts +43 -0
  70. package/dist/internal/key-store.d.ts.map +1 -0
  71. package/dist/internal/key-store.js +128 -0
  72. package/dist/internal/oidc-token.d.ts +52 -0
  73. package/dist/internal/oidc-token.d.ts.map +1 -0
  74. package/dist/internal/oidc-token.js +351 -0
  75. package/dist/internal/register-author-key.d.ts +44 -0
  76. package/dist/internal/register-author-key.d.ts.map +1 -0
  77. package/dist/internal/register-author-key.js +212 -0
  78. package/dist/local-keys.d.ts +47 -0
  79. package/dist/local-keys.d.ts.map +1 -0
  80. package/dist/local-keys.js +115 -0
  81. package/dist/mcp-backend.d.ts +356 -0
  82. package/dist/mcp-backend.d.ts.map +1 -0
  83. package/dist/mcp-backend.js +668 -0
  84. package/dist/paths.d.ts +77 -0
  85. package/dist/paths.d.ts.map +1 -0
  86. package/dist/paths.js +119 -0
  87. package/dist/persistent-secrets.d.ts +28 -0
  88. package/dist/persistent-secrets.d.ts.map +1 -0
  89. package/dist/persistent-secrets.js +94 -0
  90. package/dist/persistent-short-code-index.d.ts +14 -0
  91. package/dist/persistent-short-code-index.d.ts.map +1 -0
  92. package/dist/persistent-short-code-index.js +39 -0
  93. package/dist/persistent-stores.d.ts +12 -0
  94. package/dist/persistent-stores.d.ts.map +1 -0
  95. package/dist/persistent-stores.js +42 -0
  96. package/dist/serve-command.d.ts +500 -0
  97. package/dist/serve-command.d.ts.map +1 -0
  98. package/dist/serve-command.js +616 -0
  99. package/dist/serve-fallback.d.ts +64 -0
  100. package/dist/serve-fallback.d.ts.map +1 -0
  101. package/dist/serve-fallback.js +122 -0
  102. package/dist/spawn-cloudflared.d.ts +61 -0
  103. package/dist/spawn-cloudflared.d.ts.map +1 -0
  104. package/dist/spawn-cloudflared.js +167 -0
  105. package/dist/theme-command.d.ts +4 -0
  106. package/dist/theme-command.d.ts.map +1 -0
  107. package/dist/theme-command.js +154 -0
  108. package/dist/theme-file-uploader.d.ts +8 -0
  109. package/dist/theme-file-uploader.d.ts.map +1 -0
  110. package/dist/theme-file-uploader.js +58 -0
  111. package/dist/theme-writer.d.ts +8 -0
  112. package/dist/theme-writer.d.ts.map +1 -0
  113. package/dist/theme-writer.js +103 -0
  114. package/dist/tunnel-provider.d.ts +273 -0
  115. package/dist/tunnel-provider.d.ts.map +1 -0
  116. package/dist/tunnel-provider.js +142 -0
  117. package/package.json +81 -0
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Local-file key management for self-host operators — mirrors the
3
+ * `--keys-file` JSON written by `InMemoryPairingService.persistencePath`.
4
+ *
5
+ * `ggui keys <list|create|revoke>` defaults to the cloud-backed
6
+ * `api.ggui.ai` path. Pass `--keys-file <path>` to switch each
7
+ * subcommand to operate on the LOCAL JSON file instead — useful for
8
+ * production-grade self-hosting where operators want to mint /
9
+ * inspect / revoke bearers without depending on api.ggui.ai.
10
+ *
11
+ * Schema is identical to what `InMemoryPairingService` writes (v=1)
12
+ * so `ggui keys` and `ggui serve --keys-file` operate on the same
13
+ * file with no migration step.
14
+ */
15
+ import { randomBytes } from 'node:crypto';
16
+ import { chmodSync, closeSync, existsSync, mkdirSync, openSync, readFileSync, renameSync, unlinkSync, writeSync, } from 'node:fs';
17
+ import { dirname } from 'node:path';
18
+ /**
19
+ * Read + parse the keys file, or return empty state when the file is
20
+ * missing / empty (first-boot path). Throws on malformed JSON or
21
+ * unsupported schema — loud failure beats silent overwrite.
22
+ */
23
+ export function loadLocalKeys(path) {
24
+ if (!existsSync(path)) {
25
+ return { v: 1, pairings: [], idCounter: 0 };
26
+ }
27
+ const raw = readFileSync(path, 'utf8');
28
+ if (raw.trim().length === 0) {
29
+ return { v: 1, pairings: [], idCounter: 0 };
30
+ }
31
+ const parsed = JSON.parse(raw);
32
+ if (parsed.v !== 1) {
33
+ throw new Error(`ggui keys: unsupported schema v=${String(parsed.v)} at ${path} (expected v=1)`);
34
+ }
35
+ return parsed;
36
+ }
37
+ /**
38
+ * Atomic write — temp file + rename, `0600` perms, parent dir created
39
+ * with `0700` if missing. Mirrors `InMemoryPairingService.persistToDisk`
40
+ * so the two writers can't disagree on file shape.
41
+ */
42
+ export function saveLocalKeys(path, state) {
43
+ const dir = dirname(path);
44
+ if (!existsSync(dir))
45
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
46
+ const tmp = `${path}.tmp.${process.pid}`;
47
+ const fd = openSync(tmp, 'w', 0o600);
48
+ try {
49
+ writeSync(fd, JSON.stringify(state, null, 2));
50
+ }
51
+ finally {
52
+ closeSync(fd);
53
+ }
54
+ try {
55
+ renameSync(tmp, path);
56
+ chmodSync(path, 0o600);
57
+ }
58
+ catch (err) {
59
+ try {
60
+ unlinkSync(tmp);
61
+ }
62
+ catch {
63
+ /* swallow — original error is the real one */
64
+ }
65
+ throw err;
66
+ }
67
+ }
68
+ /**
69
+ * Mint a new `ggui_user_*` token and append it to `state`. Returns
70
+ * the appended row (caller surfaces the plaintext token to the
71
+ * operator — one-time reveal, exactly like cloud-side `keys create`).
72
+ */
73
+ export function mintLocalKey(state, opts) {
74
+ const now = (opts.now ?? Date.now)();
75
+ const pairingId = `pair-${++state.idCounter}`;
76
+ const token = `ggui_user_${randomBytes(9).toString('base64url')}`;
77
+ const row = {
78
+ pairingId,
79
+ deviceName: opts.deviceName,
80
+ createdAt: now,
81
+ token,
82
+ };
83
+ state.pairings.push(row);
84
+ return row;
85
+ }
86
+ /**
87
+ * Remove the row with `pairingId`. Idempotent — revoking a missing
88
+ * id is not an error. Returns `true` when a row was removed.
89
+ */
90
+ export function revokeLocalKey(state, pairingId) {
91
+ const before = state.pairings.length;
92
+ state.pairings = state.pairings.filter((p) => p.pairingId !== pairingId);
93
+ return state.pairings.length < before;
94
+ }
95
+ /**
96
+ * Render a fixed-width table to stdout. Columns chosen to match the
97
+ * cloud-side `keys list` shape so operators recognize the layout
98
+ * regardless of which mode they're in.
99
+ */
100
+ export function formatLocalKeyTable(state) {
101
+ if (state.pairings.length === 0) {
102
+ return 'No local keys. Run `ggui keys create --keys-file <path> --name <label>` to mint one.\n';
103
+ }
104
+ const headers = ['ID', 'PREFIX', 'NAME', 'CREATED', 'LAST USED'];
105
+ const rows = state.pairings.map((p) => [
106
+ p.pairingId,
107
+ `${p.token.slice(0, 14)}…`,
108
+ p.deviceName,
109
+ new Date(p.createdAt).toISOString(),
110
+ p.lastUsedAt ? new Date(p.lastUsedAt).toISOString() : '—',
111
+ ]);
112
+ const widths = headers.map((h, i) => Math.max(h.length, ...rows.map((r) => (r[i] ?? '').length)));
113
+ const fmt = (cells) => cells.map((c, i) => c.padEnd(widths[i] ?? 0)).join(' ');
114
+ return [fmt(headers), ...rows.map(fmt)].join('\n') + '\n';
115
+ }
@@ -0,0 +1,356 @@
1
+ import { type BlueprintProvider, type GadgetDescriptor, type McpAppsMode, type DiscoveredPrimitiveCatalog, type GenerationDeps, type LoadedTheme, type McpServerMount, type OperatorConfig, type ResolvedStorageStores, type ShortCodeIndex, type ThemeWriter } from '@ggui-ai/mcp-server';
2
+ import type { UiRegistry } from '@ggui-ai/ui-registry';
3
+ import type { UiManifest } from '@ggui-ai/project-config';
4
+ import type { ServeBackend } from './serve-command.js';
5
+ export interface BuildMcpServerBackendOptions {
6
+ /**
7
+ * Pre-resolved storage from `ggui.json#storage`. Threaded straight
8
+ * through to `createGguiServer`. Omit / leave fields undefined to
9
+ * keep the server's in-memory defaults — no silent file creation
10
+ * without an explicit declaration.
11
+ */
12
+ readonly storage?: ResolvedStorageStores;
13
+ /**
14
+ * Version string echoed in the CLI banner. Deliberately separate
15
+ * from the server's own `info.version` (which still comes out of
16
+ * `@ggui-ai/mcp-server`'s package.json) so the user sees which CLI
17
+ * build launched the server.
18
+ */
19
+ readonly cliVersion: string;
20
+ /**
21
+ * Bind host used to compose the MCP Apps `renderBaseUrl` + `wsUrl`.
22
+ * Must be the same host the CLI then passes to `listen()`; otherwise
23
+ * the shortCode URLs the agent receives will point somewhere the
24
+ * browser can't reach.
25
+ */
26
+ readonly host: string;
27
+ /**
28
+ * Bind port used to compose the MCP Apps URLs. MUST be a concrete
29
+ * port (not `0`) — the agent-returned URL is captured at composition
30
+ * time, so deferring to an OS-assigned port would leave `ggui_push`
31
+ * emitting a broken link. Callers that started with `--port 0`
32
+ * should pre-resolve a free port via {@link pickFreePort} before
33
+ * constructing the backend.
34
+ */
35
+ readonly port: number;
36
+ /**
37
+ * Pre-constructed blueprint provider — the CLI builds one from
38
+ * `ggui.json#blueprints.include` (via `discoverLocalUis` +
39
+ * `ManifestBlueprintProvider`) and threads it through so
40
+ * `ggui_list_featured_blueprints` surfaces every declared UI.
41
+ * Omitted = provider-less server (`ggui_list_featured_blueprints`
42
+ * returns an empty catalog, matching pre-Phase-4 behavior).
43
+ */
44
+ readonly blueprintProvider?: BlueprintProvider;
45
+ /**
46
+ * UI registry consulted by `ggui_render_blueprint`. The CLI pairs
47
+ * this with `blueprintProvider` at boot — same manifest source,
48
+ * two complementary seams (provider for metadata / list / search,
49
+ * registry for compiled bundle resolution). OSS uses
50
+ * `@ggui-ai/dev-stack::LocalUiRegistry` (compile-on-demand via
51
+ * esbuild). Omitted = `ggui_render_blueprint` is NOT registered on
52
+ * this server (no throwing shim; the tool is simply absent from
53
+ * `tools/list`).
54
+ */
55
+ readonly uiRegistry?: UiRegistry;
56
+ /**
57
+ * Primitive catalogs resolved from
58
+ * `ggui.json#primitives.{packages,local}` by
59
+ * `discoverPrimitives()` in `@ggui-ai/project-config/node`. Passed
60
+ * through to `createGguiServer` so `server.primitiveCatalogs`
61
+ * reflects what the operator declared. Omitted = programmatic hosts
62
+ * / tests that don't need a primitive index — the server handle
63
+ * exposes an empty array in that case.
64
+ */
65
+ readonly primitiveCatalogs?: readonly DiscoveredPrimitiveCatalog[];
66
+ /**
67
+ * Theme resolved from `ggui.json#theme` by `loadTheme()` in
68
+ * `@ggui-ai/project-config/node`. Threaded through to
69
+ * `createGguiServer({ theme })` so `server.theme` reflects what
70
+ * the operator declared. Omitted = programmatic hosts / tests
71
+ * that didn't load a theme — the server handle surfaces its own
72
+ * `lightTheme`-backed `LoadedTheme` default in that case.
73
+ */
74
+ readonly theme?: LoadedTheme;
75
+ /**
76
+ * Theme writer for the admin-gated `/ggui/console/theme` POST.
77
+ * Mounted only when present — the server returns 501 on Save when
78
+ * the writer is omitted (programmatic hosts / `--mcp-only` mode
79
+ * with no manifest). The CLI builds this from
80
+ * `manifestPath` via {@link createThemeWriter} when a `ggui.json`
81
+ * is on disk.
82
+ */
83
+ readonly themeWriter?: ThemeWriter;
84
+ /**
85
+ * Live theme getter — when set, supersedes the static `theme`
86
+ * resolution for every `ggui_push` bootstrap envelope. The CLI
87
+ * pairs this with `onThemeConfigChange` so a console save
88
+ * reaches the next push without a server restart.
89
+ */
90
+ readonly themeProvider?: () => {
91
+ readonly id?: string;
92
+ readonly mode?: 'light' | 'dark';
93
+ } | undefined;
94
+ /**
95
+ * Optional change notifier — fires from
96
+ * `mountDevtoolThemeRoutes`'s POST handlers when the operator
97
+ * saves a new theme via the picker. Pair with `themeProvider` so
98
+ * the push handler reads the live theme on every call.
99
+ */
100
+ readonly onThemeConfigChange?: (next: string | {
101
+ preset: string;
102
+ mode?: 'light' | 'dark';
103
+ overrides?: Record<string, string>;
104
+ } | {
105
+ file: string;
106
+ mode?: 'light' | 'dark';
107
+ } | null) => void;
108
+ /**
109
+ * Generation wiring for `ggui_push`. When present, the OSS push
110
+ * handler invokes the bound `UiGenerator` on every story-path
111
+ * call and appends real componentCode as a `StackItem`. Absent =
112
+ * placeholder mode: push creates sessions + shortCodes but does
113
+ * not produce componentCode.
114
+ *
115
+ * The CLI resolves this from the operator's BYOK state at boot via
116
+ * {@link probeGenerationBinding} — env (`ANTHROPIC_API_KEY` etc.)
117
+ * first, then `~/.ggui/credentials.json`. Programmatic hosts
118
+ * embedding `buildMcpServerBackend` directly supply their own
119
+ * `GenerationDeps` bundle (real BYOK in a hosted multi-tenant
120
+ * setting, a test double, etc.).
121
+ */
122
+ readonly generation?: GenerationDeps;
123
+ /**
124
+ * Marketplace-install bridge data. When set, the backend
125
+ * constructs an
126
+ * {@link InstalledBlueprintsProvider} rooted on the same
127
+ * `embedding` + `vectorStore` the matcher consumes, and merges it
128
+ * into `generation.installedBlueprints`. On the first
129
+ * `matchBlueprint` call per scope, every entry with a contract is
130
+ * compiled (esbuild) and registered into the cache with
131
+ * `provenance: 'install'` — so installed blueprints accelerate
132
+ * render the way synth-cached ones do.
133
+ *
134
+ * Caller is responsible for filtering `entries` to actual
135
+ * marketplace installs (typically: discovered UIs whose
136
+ * `manifestPath` lives under `.ggui/installed-blueprints/`). Hand-
137
+ * authored UIs are intentionally excluded today.
138
+ */
139
+ readonly installedBlueprints?: {
140
+ readonly projectRoot: string;
141
+ readonly entries: ReadonlyArray<{
142
+ readonly id: string;
143
+ readonly manifestPath: string;
144
+ readonly manifest: UiManifest;
145
+ }>;
146
+ };
147
+ /**
148
+ * External MCP tool-handler bundles to aggregate onto `/mcp`.
149
+ * Threaded straight through to `createGguiServer({ mcpMounts })`;
150
+ * see that option's JSDoc for shape + collision rules.
151
+ *
152
+ * The `ggui serve` CLI today does NOT surface a `ggui.json` field
153
+ * for this — there's no config loader yet. Programmatic hosts and
154
+ * integration-test fixtures compose mounts directly via
155
+ * `buildMcpServerBackend({ mcpMounts: [...] })`.
156
+ */
157
+ readonly mcpMounts?: ReadonlyArray<McpServerMount>;
158
+ /**
159
+ * Switch the in-memory auth adapter to `devAllowAll: true`. Every
160
+ * non-empty bearer (including the no-bearer probe MCP custom
161
+ * connectors send) authenticates as builder. Local-dev / tunnel-
162
+ * smoke escape hatch only — pairing or a custom `AuthAdapter` is
163
+ * the production answer. Surface = `--dev-allow-all` CLI flag.
164
+ *
165
+ * Default `false` keeps the strict-auth posture (every bearer
166
+ * must be pair-minted).
167
+ */
168
+ readonly devAllowAll?: boolean;
169
+ /**
170
+ * Public-demo posture. Same auth-adapter shape as `devAllowAll`
171
+ * (every bearer authenticates as builder) but additionally:
172
+ * - Wires a per-remote-IP `FixedWindowRateLimiter` over an
173
+ * `InMemoryQuotaStore` (default 30 generations / 10 minutes per
174
+ * IP). The limiter binds at `ggui_push` so end-user generations
175
+ * can't burn the operator's BYOK budget.
176
+ * - The CLI banner displays "PUBLIC DEMO" copy with a cost-
177
+ * attribution + rate-limit note (vs. "DEV ALLOW-ALL" warning).
178
+ *
179
+ * Mutually exclusive with `devAllowAll`; the CLI rejects both at
180
+ * parse time. Surface = `--public-demo` CLI flag.
181
+ */
182
+ readonly publicDemo?: boolean;
183
+ /**
184
+ * Multi-tenant posture. Switches the `/ggui/console/llm-keys` gate
185
+ * from admin-token to auth-adapter — each authenticated end-user
186
+ * manages their OWN provider keys (scope = `userId` for `kind:'user'`
187
+ * identities, `appId` for `kind:'app'`). `kind:'builder'` identities
188
+ * are rejected at the gate; multi-tenant is meaningless without a
189
+ * real per-caller id.
190
+ *
191
+ * Strict-auth shape — every bearer must clear the `AuthAdapter`
192
+ * (pairing-minted, OIDC, Cognito, or whatever the embedding host
193
+ * binds). Mutually exclusive with `devAllowAll` and `publicDemo`;
194
+ * the CLI rejects combinations at parse time. Surface =
195
+ * `--multi-tenant` CLI flag.
196
+ */
197
+ readonly multiTenant?: boolean;
198
+ /**
199
+ * Public base URL that replaces `http://<host>:<port>` when
200
+ * composing `mcpApps.renderBaseUrl`, `mcpApps.wsUrl`, and
201
+ * `runtime.url`. Set this when the server is being reached
202
+ * through a tunnel (cloudflare, ngrok, …) so URLs the agent
203
+ * receives resolve from the MCP host's perspective rather than
204
+ * `localhost`.
205
+ *
206
+ * Required shape: `http://…` or `https://…`, no trailing slash.
207
+ * The `wsUrl` is derived by replacing the scheme with `ws`/`wss`.
208
+ * Surface = `--public-base-url <url>` CLI flag.
209
+ */
210
+ readonly publicBaseUrl?: string;
211
+ /**
212
+ * Path to a JSON file backing the in-memory pairing service. When
213
+ * set, paired bearer tokens survive `ggui serve` restarts — claude.ai
214
+ * (and any other MCP client) stays connected without re-pairing.
215
+ * Stored in plaintext at the path with `0600` perms; assume the
216
+ * file lives on operator-controlled disk.
217
+ *
218
+ * Surface = `--keys-file <path>` CLI flag. Default ephemeral when
219
+ * absent (current behavior).
220
+ */
221
+ readonly keysFile?: string;
222
+ /**
223
+ * Mount the OAuth 2.1 + PKCE + Dynamic Client Registration routes.
224
+ * Required for MCP custom-connector hosts (claude.ai, ChatGPT) whose
225
+ * "Add connector" form has no field for a pre-shared bearer.
226
+ *
227
+ * The full flow lives in `@ggui-ai/mcp-server::oauth.ts`; here we
228
+ * just forward `oauth: true` to `createGguiServer` so the server
229
+ * mounts `.well-known/oauth-*` + `/oauth/{authorize,token,register}`.
230
+ * Defaults (in-memory storage, paste-key consent page) are right for
231
+ * single-replica dev. Programmatic embedders that need a custom
232
+ * `OAuthConfig` (storage seam, external consent UI) compose
233
+ * `createGguiServer({oauth: <config>})` directly.
234
+ *
235
+ * Surface = `--oauth` CLI flag.
236
+ */
237
+ readonly oauth?: boolean;
238
+ /**
239
+ * Server-level MCP instructions preset. Threaded straight through
240
+ * to `createGguiServer({mcpInstructions})`. Falls back to the
241
+ * `GGUI_MCP_INSTRUCTIONS` env var when absent. Both absent =
242
+ * `createGguiServer`'s no-preset default (`'aggressive'`).
243
+ *
244
+ * Surface = `--mcp-instructions <preset>` CLI flag or
245
+ * `GGUI_MCP_INSTRUCTIONS` env var (CLI flag wins).
246
+ */
247
+ readonly mcpInstructions?: 'default' | 'aggressive' | 'always' | 'minimal' | 'off';
248
+ /**
249
+ * Directory backing the cross-restart persistence bundle. When set,
250
+ * `bootstrapSecret` + `renderSigning.secret` are read from / minted
251
+ * into 0600-mode files there so the HMAC keys survive `ggui serve`
252
+ * restart — claude.ai chat-history revisits keep their cached
253
+ * `_meta.ggui.bootstrap.token` + `/r/<code>?sig=&exp=` URLs valid.
254
+ *
255
+ * Absent / undefined = the legacy ephemeral behavior (every restart
256
+ * mints fresh secrets; cached tokens fail HMAC verify). The CLI sets
257
+ * this to `getPersistentDir(projectRoot)` by default and skips when
258
+ * `--ephemeral` is passed.
259
+ */
260
+ readonly persistentDir?: string;
261
+ /**
262
+ * Pre-resolved `ShortCodeIndex` implementation. When set, replaces
263
+ * the default `InMemoryShortCodeIndex` — typically the caller passes
264
+ * `SqliteShortCodeIndex` rooted under `persistentDir` so cached
265
+ * `/api/bootstrap/<code>` URLs (and the `/r/<code>` viewer) keep
266
+ * resolving after a `ggui serve` restart. Without that, the index
267
+ * is process-local and every restart turns prior shortCodes into
268
+ * 404s — defeating the bootstrap-secret persistence above.
269
+ *
270
+ * Absent = `InMemoryShortCodeIndex` (the legacy default, fine for
271
+ * tests + `--ephemeral`). The CLI composes this via
272
+ * `createPersistentShortCodeIndex(persistentDir)` in cli.ts so the
273
+ * sqlite peer-dep loads lazily.
274
+ */
275
+ readonly shortCodeIndex?: ShortCodeIndex;
276
+ /**
277
+ * Operator-pinned admin token gating the console `/keys` plane.
278
+ * When omitted, the server mints a fresh `ggui_admin_*` token on
279
+ * boot and surfaces it via `GguiServer.adminToken`. The CLI banner
280
+ * prints whichever value ended up in effect so the operator can
281
+ * paste it into `/admin-login`.
282
+ *
283
+ * Surface = `--admin-token <token>` CLI flag.
284
+ */
285
+ readonly adminToken?: string;
286
+ /**
287
+ * Server-rendered public welcome page at `/`. Identifies who runs
288
+ * the server (operator block, hidden when nothing configured)
289
+ * and links to the public deep-link surfaces + operator login.
290
+ *
291
+ * The CLI's `serve-command.ts` resolves this from
292
+ * `ggui.json#operator` + `ggui.json#app.name`. Programmatic hosts
293
+ * pass whatever fits their context. Omitted = no welcome page;
294
+ * the SPA index handler still owns `/`.
295
+ */
296
+ readonly welcomePage?: {
297
+ readonly operator?: OperatorConfig;
298
+ readonly appName?: string;
299
+ };
300
+ /**
301
+ * Per-app gadget catalog from `ggui.json#app.gadgets`.
302
+ * Gadgets (Leaflet, Mapbox, …) declared
303
+ * here populate `App.gadgets` so the
304
+ * `assertGadgetsRegistered` validator (push, ops_register,
305
+ * ops_generate) accepts contracts that reference them.
306
+ *
307
+ * Omitted ⇒ `STDLIB_GADGETS` defaults from
308
+ * `@ggui-ai/protocol` apply (the 7 first-party hooks).
309
+ */
310
+ readonly gadgets?: readonly GadgetDescriptor[];
311
+ /**
312
+ * Operator-stamped public env channel from
313
+ * `ggui.json#app.publicEnv`. Each key MUST match
314
+ * `^GGUI_PUBLIC_APP_[A-Z0-9_]+$`. The server projects only the keys
315
+ * that some registered wrapper's `requires` references, onto
316
+ * `_meta.ggui.bootstrap.publicEnv` and ultimately
317
+ * `globalThis.__ggui__.publicEnv` for `getPublicEnv()` to read.
318
+ *
319
+ * Omitted ⇒ field absent on the App record (no values projected;
320
+ * wrappers without `requires` still mount, wrappers with `requires`
321
+ * fail at push-gate validation).
322
+ */
323
+ readonly publicEnv?: Readonly<Record<string, string>>;
324
+ /**
325
+ * Per-app MCP-Apps presentation mode from
326
+ * `ggui.json#app.defaultMcpAppsMode`. `'canvas'` makes
327
+ * `ggui_new_session` mint a session-scoped iframe
328
+ * (`ui://ggui/session/<sessionId>`) and route subsequent pushes
329
+ * through the session channel; `'inline'` (or omitted) preserves
330
+ * the per-push-iframe legacy behavior.
331
+ */
332
+ readonly defaultMcpAppsMode?: McpAppsMode;
333
+ }
334
+ /**
335
+ * Pick a free localhost TCP port by letting the OS assign one on a
336
+ * throwaway listener. Close the listener immediately and return the
337
+ * chosen number. Exported so the CLI (`cli.ts::runServeCommand`) and
338
+ * the integration tests can resolve `--port 0` to a concrete port
339
+ * BEFORE constructing the backend — {@link buildMcpServerBackend}
340
+ * captures the port in the composed `mcpApps.renderBaseUrl` / `wsUrl`
341
+ * at construction time, so the caller must know it up-front.
342
+ *
343
+ * Tiny race window: another process could claim the port between our
344
+ * `close()` and the caller's `listen()`. The CLI surfaces bind errors
345
+ * as a fatal exit; the OSS first-run path recovers by re-running.
346
+ */
347
+ export declare function pickFreePort(host?: string): Promise<number>;
348
+ /**
349
+ * Build the `ServeBackend` that `runServe` drives. Returns a thin
350
+ * adapter around `createGguiServer` — the factory is invoked here so
351
+ * preconditions that throw (e.g. missing auth bridge support for
352
+ * `pairing: true`) surface synchronously, before `runServe` bothers
353
+ * binding a port.
354
+ */
355
+ export declare function buildMcpServerBackend(opts: BuildMcpServerBackendOptions): ServeBackend;
356
+ //# sourceMappingURL=mcp-backend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-backend.d.ts","sourceRoot":"","sources":["../src/mcp-backend.ts"],"names":[],"mappings":"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"}