@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.
- package/LICENSE +201 -0
- package/README.md +96 -0
- package/dist/agent-resolution.d.ts +41 -0
- package/dist/agent-resolution.d.ts.map +1 -0
- package/dist/agent-resolution.js +80 -0
- package/dist/api-client.d.ts +59 -0
- package/dist/api-client.d.ts.map +1 -0
- package/dist/api-client.js +145 -0
- package/dist/auth-keys.d.ts +10 -0
- package/dist/auth-keys.d.ts.map +1 -0
- package/dist/auth-keys.js +382 -0
- package/dist/auth-login.d.ts +11 -0
- package/dist/auth-login.d.ts.map +1 -0
- package/dist/auth-login.js +231 -0
- package/dist/auth-logout.d.ts +3 -0
- package/dist/auth-logout.d.ts.map +1 -0
- package/dist/auth-logout.js +32 -0
- package/dist/auth-store.d.ts +67 -0
- package/dist/auth-store.d.ts.map +1 -0
- package/dist/auth-store.js +150 -0
- package/dist/auth-whoami.d.ts +3 -0
- package/dist/auth-whoami.d.ts.map +1 -0
- package/dist/auth-whoami.js +52 -0
- package/dist/blueprint-command.d.ts +3 -0
- package/dist/blueprint-command.d.ts.map +1 -0
- package/dist/blueprint-command.js +203 -0
- package/dist/blueprint-create.d.ts +71 -0
- package/dist/blueprint-create.d.ts.map +1 -0
- package/dist/blueprint-create.js +377 -0
- package/dist/byok-resolver.d.ts +141 -0
- package/dist/byok-resolver.d.ts.map +1 -0
- package/dist/byok-resolver.js +89 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +1066 -0
- package/dist/dev-command.d.ts +169 -0
- package/dist/dev-command.d.ts.map +1 -0
- package/dist/dev-command.js +222 -0
- package/dist/gadget-command.d.ts +3 -0
- package/dist/gadget-command.d.ts.map +1 -0
- package/dist/gadget-command.js +181 -0
- package/dist/gadget-create.d.ts +106 -0
- package/dist/gadget-create.d.ts.map +1 -0
- package/dist/gadget-create.js +492 -0
- package/dist/generation-probe.d.ts +135 -0
- package/dist/generation-probe.d.ts.map +1 -0
- package/dist/generation-probe.js +132 -0
- package/dist/internal/artifact-install.d.ts +150 -0
- package/dist/internal/artifact-install.d.ts.map +1 -0
- package/dist/internal/artifact-install.js +1019 -0
- package/dist/internal/artifact-publish.d.ts +204 -0
- package/dist/internal/artifact-publish.d.ts.map +1 -0
- package/dist/internal/artifact-publish.js +1141 -0
- package/dist/internal/artifact-search.d.ts +155 -0
- package/dist/internal/artifact-search.d.ts.map +1 -0
- package/dist/internal/artifact-search.js +539 -0
- package/dist/internal/artifact-uninstall.d.ts +30 -0
- package/dist/internal/artifact-uninstall.d.ts.map +1 -0
- package/dist/internal/artifact-uninstall.js +205 -0
- package/dist/internal/auth-cache.d.ts +40 -0
- package/dist/internal/auth-cache.d.ts.map +1 -0
- package/dist/internal/auth-cache.js +133 -0
- package/dist/internal/auth-strategy.d.ts +89 -0
- package/dist/internal/auth-strategy.d.ts.map +1 -0
- package/dist/internal/auth-strategy.js +132 -0
- package/dist/internal/ggui-json.d.ts +53 -0
- package/dist/internal/ggui-json.d.ts.map +1 -0
- package/dist/internal/ggui-json.js +92 -0
- package/dist/internal/key-store.d.ts +43 -0
- package/dist/internal/key-store.d.ts.map +1 -0
- package/dist/internal/key-store.js +128 -0
- package/dist/internal/oidc-token.d.ts +52 -0
- package/dist/internal/oidc-token.d.ts.map +1 -0
- package/dist/internal/oidc-token.js +351 -0
- package/dist/internal/register-author-key.d.ts +44 -0
- package/dist/internal/register-author-key.d.ts.map +1 -0
- package/dist/internal/register-author-key.js +212 -0
- package/dist/local-keys.d.ts +47 -0
- package/dist/local-keys.d.ts.map +1 -0
- package/dist/local-keys.js +115 -0
- package/dist/mcp-backend.d.ts +356 -0
- package/dist/mcp-backend.d.ts.map +1 -0
- package/dist/mcp-backend.js +668 -0
- package/dist/paths.d.ts +77 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +119 -0
- package/dist/persistent-secrets.d.ts +28 -0
- package/dist/persistent-secrets.d.ts.map +1 -0
- package/dist/persistent-secrets.js +94 -0
- package/dist/persistent-short-code-index.d.ts +14 -0
- package/dist/persistent-short-code-index.d.ts.map +1 -0
- package/dist/persistent-short-code-index.js +39 -0
- package/dist/persistent-stores.d.ts +12 -0
- package/dist/persistent-stores.d.ts.map +1 -0
- package/dist/persistent-stores.js +42 -0
- package/dist/serve-command.d.ts +500 -0
- package/dist/serve-command.d.ts.map +1 -0
- package/dist/serve-command.js +616 -0
- package/dist/serve-fallback.d.ts +64 -0
- package/dist/serve-fallback.d.ts.map +1 -0
- package/dist/serve-fallback.js +122 -0
- package/dist/spawn-cloudflared.d.ts +61 -0
- package/dist/spawn-cloudflared.d.ts.map +1 -0
- package/dist/spawn-cloudflared.js +167 -0
- package/dist/theme-command.d.ts +4 -0
- package/dist/theme-command.d.ts.map +1 -0
- package/dist/theme-command.js +154 -0
- package/dist/theme-file-uploader.d.ts +8 -0
- package/dist/theme-file-uploader.d.ts.map +1 -0
- package/dist/theme-file-uploader.js +58 -0
- package/dist/theme-writer.d.ts +8 -0
- package/dist/theme-writer.d.ts.map +1 -0
- package/dist/theme-writer.js +103 -0
- package/dist/tunnel-provider.d.ts +273 -0
- package/dist/tunnel-provider.d.ts.map +1 -0
- package/dist/tunnel-provider.js +142 -0
- 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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"}
|