@ggui-ai/cli 0.15.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/api-client.d.ts +1 -1
- package/dist/byok-resolver.d.ts +1 -1
- package/dist/byok-resolver.js +1 -1
- package/dist/cli.js +22 -3
- package/dist/config-push.d.ts +13 -1
- package/dist/config-push.d.ts.map +1 -1
- package/dist/config-push.js +27 -51
- package/dist/deploy-command.d.ts +2 -2
- package/dist/deploy-command.js +3 -3
- package/dist/drain-deadline.d.ts +27 -0
- package/dist/drain-deadline.d.ts.map +1 -0
- package/dist/drain-deadline.js +22 -0
- package/dist/generation-probe.d.ts +2 -2
- package/dist/generation-probe.js +1 -1
- package/dist/mcp-backend.d.ts +5 -5
- package/dist/mcp-backend.d.ts.map +1 -1
- package/dist/mcp-backend.js +19 -4
- package/dist/push-command.d.ts +1 -1
- package/dist/push-command.d.ts.map +1 -1
- package/dist/serve-command.d.ts +8 -8
- package/dist/serve-command.d.ts.map +1 -1
- package/dist/serve-command.js +12 -12
- package/dist/theme-command.d.ts +1 -1
- package/dist/theme-command.js +2 -2
- package/package.json +17 -17
package/README.md
CHANGED
|
@@ -46,7 +46,7 @@ ggui serve --mcp-only # skip agent supervision
|
|
|
46
46
|
- ✅ Local server, viewer, cookie-authenticated WebSocket subscribe/ack all work end-to-end.
|
|
47
47
|
- ✅ `ggui_render` mints shortCodes and lands on the same-origin viewer.
|
|
48
48
|
- ✅ Component-code generation is wired on the OSS path via `createUiGenerator()` from `@ggui-ai/ui-gen` — the same harness the hosted runtime uses. When no LLM credentials resolve (no `ANTHROPIC_API_KEY` / `OPENAI_API_KEY` / etc.), `ggui_render` returns an `isError: true` tool result whose `structuredContent.error.code` is `NO_CREDENTIALS`, with a message naming which key to set; supply a key to get full generation locally.
|
|
49
|
-
- 🔒 Default auth is strict pairing — only pair-minted bearer tokens authenticate `/mcp` (pair via the landing page or `POST /pair`). `--dev-allow-all` (local dev / tunnel smoke) and `--public-demo` (rate-limited, operator-paid public demo) relax `/mcp` to any-bearer; `--multi-
|
|
49
|
+
- 🔒 Default auth is strict pairing — only pair-minted bearer tokens authenticate `/mcp` (pair via the landing page or `POST /pair`). `--dev-allow-all` (local dev / tunnel smoke) and `--public-demo` (rate-limited, operator-paid public demo) relax `/mcp` to any-bearer; `--multi-user` keeps strict auth with per-user provider-key scoping; `--oauth` mounts the OAuth 2.1 + DCR routes MCP custom-connector hosts (claude.ai, ChatGPT) need. Custom adapters via `createGguiServer({ auth })`.
|
|
50
50
|
|
|
51
51
|
### `ggui dev`
|
|
52
52
|
|
package/dist/api-client.d.ts
CHANGED
|
@@ -61,7 +61,7 @@ export interface AppsCreateResponse {
|
|
|
61
61
|
appId: string;
|
|
62
62
|
/**
|
|
63
63
|
* The app's MCP endpoint, used VERBATIM as `GGUI_MCP_URL` — `<base>/apps/<appId>`,
|
|
64
|
-
* with NO `/mcp` suffix. The per-app
|
|
64
|
+
* with NO `/mcp` suffix. The hosted per-app server serves the MCP transport at this
|
|
65
65
|
* bare path; appending `/mcp` (a local `ggui serve` convention) 404s. Carries
|
|
66
66
|
* the deployment-correct host (prod `mcp.ggui.ai`, sandbox `<env>.mcp.sandbox…`),
|
|
67
67
|
* so prefer it over any reconstructed/hardcoded URL. See `resolveDeployMcpUrl`.
|
package/dist/byok-resolver.d.ts
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
* 2. **`~/.ggui/credentials.json`** — operator-persistent personal
|
|
30
30
|
* store. Backed by `PlaintextFileProviderKeyStore` from
|
|
31
31
|
* `@ggui-ai/mcp-server-core/plaintext` at the **global** app
|
|
32
|
-
* scope. Single-user, single-
|
|
32
|
+
* scope. Single-user, single-app; multi-app or multi-user
|
|
33
33
|
* deployments swap in a different `ProviderKeyStore` binding at
|
|
34
34
|
* composition time and bypass this resolver entirely.
|
|
35
35
|
*
|
package/dist/byok-resolver.js
CHANGED
|
@@ -75,7 +75,7 @@ export function createByokResolver(opts = {}) {
|
|
|
75
75
|
return globalHit;
|
|
76
76
|
// Step 3: credentials file at the end-user's identity scope.
|
|
77
77
|
// Only consulted when the operator opted out of paying (no
|
|
78
|
-
// global key). The /settings UI under --multi-
|
|
78
|
+
// global key). The /settings UI under --multi-user writes
|
|
79
79
|
// here.
|
|
80
80
|
if (resolveOpts?.userScope &&
|
|
81
81
|
resolveOpts.userScope !== BYOK_GLOBAL_APP_SCOPE) {
|
package/dist/cli.js
CHANGED
|
@@ -12,6 +12,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
12
12
|
import { GguiDevError, LocalUiRegistry, runDev } from '@ggui-ai/dev-stack';
|
|
13
13
|
import { discoverLocalUis, discoverMcpMounts, discoverPrimitives, GguiJsonLoadError, loadTheme, } from '@ggui-ai/project-config/node';
|
|
14
14
|
import { resolveAgentPlan } from './serve-fallback.js';
|
|
15
|
+
import { DRAIN_DEADLINE_MS, armDrainDeadline } from './drain-deadline.js';
|
|
15
16
|
import { buildAgentRuntime, describeTunnelSession, DEV_HELP, launchBrowser, openTunnel, parseDevFlags, resolveAgentCommand, resolveHubUrl, shouldAutoOpen, } from './dev-command.js';
|
|
16
17
|
import { createNullTunnelProvider, discoverTunnelProvider, } from './tunnel-provider.js';
|
|
17
18
|
import { ManifestBlueprintProvider, resolveStorageFromConfig, buildNoCredentialsGguiSession, } from '@ggui-ai/mcp-server';
|
|
@@ -632,7 +633,7 @@ async function runServeCommand(args) {
|
|
|
632
633
|
devAllowAll: parsed.devAllowAll,
|
|
633
634
|
withholdResultMeta: parsed.withholdResultMeta,
|
|
634
635
|
publicDemo: parsed.publicDemo,
|
|
635
|
-
|
|
636
|
+
multiUser: parsed.multiUser,
|
|
636
637
|
oauth: parsed.oauth,
|
|
637
638
|
browserOrigins,
|
|
638
639
|
...(parsed.publicBaseUrl !== undefined
|
|
@@ -650,7 +651,7 @@ async function runServeCommand(args) {
|
|
|
650
651
|
port: effectivePort,
|
|
651
652
|
devAllowAll: parsed.devAllowAll,
|
|
652
653
|
publicDemo: parsed.publicDemo,
|
|
653
|
-
|
|
654
|
+
multiUser: parsed.multiUser,
|
|
654
655
|
oauth: parsed.oauth,
|
|
655
656
|
...(parsed.publicBaseUrl !== undefined
|
|
656
657
|
? { publicBaseUrl: parsed.publicBaseUrl }
|
|
@@ -1203,7 +1204,25 @@ function readVersion() {
|
|
|
1203
1204
|
}
|
|
1204
1205
|
}
|
|
1205
1206
|
main(process.argv).then((code) => {
|
|
1206
|
-
process.exit(
|
|
1207
|
+
// Set the code and let the event loop drain — never `process.exit()`
|
|
1208
|
+
// here. Every command closes its own handles before resolving, so the
|
|
1209
|
+
// process ends on its own; a hard exit while the local embedding
|
|
1210
|
+
// model is loaded runs ONNX Runtime's static teardown under its
|
|
1211
|
+
// still-parked worker threads and aborts (`libc++abi … mutex lock
|
|
1212
|
+
// failed`, SIGABRT on every Ctrl-C — #855). The journeys spec
|
|
1213
|
+
// `serve-teardown.spec.ts` pins the clean exit on every serve shape.
|
|
1214
|
+
process.exitCode = code;
|
|
1215
|
+
// Bounded: a leaked handle must not turn Ctrl-C into a hang. If the
|
|
1216
|
+
// loop has not drained by the deadline, the live resources are named
|
|
1217
|
+
// on stderr and the process hard-exits with the same code.
|
|
1218
|
+
armDrainDeadline({
|
|
1219
|
+
exitCode: code,
|
|
1220
|
+
deadlineMs: DRAIN_DEADLINE_MS,
|
|
1221
|
+
exit: (c) => process.exit(c),
|
|
1222
|
+
stderr: (line) => process.stderr.write(line),
|
|
1223
|
+
setTimer: (fn, ms) => setTimeout(fn, ms),
|
|
1224
|
+
liveResources: () => process.getActiveResourcesInfo(),
|
|
1225
|
+
});
|
|
1207
1226
|
}, (error) => {
|
|
1208
1227
|
const message = error instanceof Error ? (error.stack ?? error.message) : String(error);
|
|
1209
1228
|
process.stderr.write(`ggui: ${message}\n`);
|
package/dist/config-push.d.ts
CHANGED
|
@@ -39,7 +39,19 @@ export declare function readGenerationFromGguiJson(gguiJson: unknown): {
|
|
|
39
39
|
* backend enforces, so a deploy fails loud LOCALLY rather than with a
|
|
40
40
|
* confusing 422.
|
|
41
41
|
*/
|
|
42
|
-
|
|
42
|
+
/** What `ggui.json#theme` resolves to for a deploy. */
|
|
43
|
+
export interface ThemeRead {
|
|
44
|
+
/** The projection the PATCH ships. */
|
|
45
|
+
readonly theme: AppTheme;
|
|
46
|
+
/**
|
|
47
|
+
* The families the document's `typography.faces` declare, deduped in
|
|
48
|
+
* declaration order. The hosted path does not deliver them yet
|
|
49
|
+
* (ggui#990): the deploy names them so the fallback is visible, not
|
|
50
|
+
* silent.
|
|
51
|
+
*/
|
|
52
|
+
readonly declaredFaceFamilies: readonly string[];
|
|
53
|
+
}
|
|
54
|
+
export declare function readThemeFromGguiJson(projectRoot: string, gguiJson: unknown): Promise<ThemeRead | undefined>;
|
|
43
55
|
/**
|
|
44
56
|
* Assert that none of the gadget bundle references point at a loopback host.
|
|
45
57
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-push.d.ts","sourceRoot":"","sources":["../src/config-push.ts"],"names":[],"mappings":"AAUA,OAAO,
|
|
1
|
+
{"version":3,"file":"config-push.d.ts","sourceRoot":"","sources":["../src/config-push.ts"],"names":[],"mappings":"AAUA,OAAO,EAKL,KAAK,gBAAgB,EACrB,KAAK,QAAQ,EACd,MAAM,mBAAmB,CAAC;AAmB3B;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAmBnF;AAED;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,OAAO,GAChB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,KAAK,GAAG,SAAS,CAAA;CAAE,GAAG,SAAS,CAkB7D;AAGD;;;;;;;;;;;;;;;;;GAiBG;AACH,uDAAuD;AACvD,MAAM,WAAW,SAAS;IACxB,sCAAsC;IACtC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB;;;;;OAKG;IACH,QAAQ,CAAC,oBAAoB,EAAE,SAAS,MAAM,EAAE,CAAC;CAClD;AAED,wBAAsB,qBAAqB,CACzC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,OAAO,GAChB,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CA0DhC;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,gBAAgB,EAAE,GAAG,IAAI,CAiB9E;AAMD;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,MAAM,EACb,QAAQ,GAAE,MAAsB,GAC/B,OAAO,CAAC,MAAM,CAAC,CAqGjB"}
|
package/dist/config-push.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import process from 'node:process';
|
|
10
10
|
import { dirname } from 'node:path';
|
|
11
|
-
import { appPublicEnvSchema, appThemeSchema, LOOPBACK_HOST_RE, } from '@ggui-ai/protocol';
|
|
11
|
+
import { appPublicEnvSchema, appThemeSchema, canonicalOverlayHash, LOOPBACK_HOST_RE, } from '@ggui-ai/protocol';
|
|
12
12
|
import { loadTheme, parseGguiJson } from '@ggui-ai/project-config/node';
|
|
13
13
|
import { z } from 'zod';
|
|
14
14
|
import { patchAppConfig } from './api-client.js';
|
|
@@ -73,53 +73,7 @@ export function readGenerationFromGguiJson(gguiJson) {
|
|
|
73
73
|
return undefined;
|
|
74
74
|
return { model, keySource: result.data.generation?.keySource ?? 'managed' };
|
|
75
75
|
}
|
|
76
|
-
|
|
77
|
-
* Parse a generated `:root { --ggui-x: val; … }` block into a flat
|
|
78
|
-
* `{ '--ggui-x': 'val' }` map.
|
|
79
|
-
*
|
|
80
|
-
* The block is machine-generated by `@ggui-ai/design`'s theme parser
|
|
81
|
-
* (one `--ggui-*: value;` declaration per line, wrapped in a `:root {…}`
|
|
82
|
-
* selector), so a line-based parse is deterministic:
|
|
83
|
-
* - split on newlines;
|
|
84
|
-
* - on each line, split at the FIRST `:` (custom-property names never
|
|
85
|
-
* contain `:`, so the key is unambiguous even when the value does);
|
|
86
|
-
* - keep only `--ggui-*`-prefixed keys with a non-empty value. The
|
|
87
|
-
* `:root {` and `}` wrapper lines have no such key and drop out.
|
|
88
|
-
*/
|
|
89
|
-
function parseCssVarBlock(css) {
|
|
90
|
-
const out = {};
|
|
91
|
-
for (const line of css.split('\n')) {
|
|
92
|
-
const i = line.indexOf(':');
|
|
93
|
-
if (i === -1)
|
|
94
|
-
continue;
|
|
95
|
-
const key = line.slice(0, i).trim();
|
|
96
|
-
let val = line.slice(i + 1).trim();
|
|
97
|
-
if (val.endsWith(';'))
|
|
98
|
-
val = val.slice(0, -1).trim();
|
|
99
|
-
if (key.startsWith('--ggui-') && val.length > 0)
|
|
100
|
-
out[key] = val;
|
|
101
|
-
}
|
|
102
|
-
return out;
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* Resolve the developer's local `ggui.json#theme` into a concrete,
|
|
106
|
-
* injection-safe {@link AppTheme} ready to PATCH to the cloud.
|
|
107
|
-
*
|
|
108
|
-
* Returns `undefined` when no `theme` field is declared (deploy leaves the
|
|
109
|
-
* app's theme untouched).
|
|
110
|
-
*
|
|
111
|
-
* When a theme IS declared we parse the FULL manifest (via `parseGguiJson`)
|
|
112
|
-
* — `loadTheme` requires the typed `GguiJsonV1` shape and resolves relative
|
|
113
|
-
* `theme.file` paths against `projectRoot`, so a partial slice will not do.
|
|
114
|
-
*
|
|
115
|
-
* Throws with a clear, local message when:
|
|
116
|
-
* - the manifest is structurally invalid (so deploy fails before the wire);
|
|
117
|
-
* - the theme cannot be loaded (e.g. an unregistered preset id);
|
|
118
|
-
* - the resolved overlay fails `appThemeSchema` — the SAME validator the
|
|
119
|
-
* backend enforces, so a deploy fails loud LOCALLY rather than with a
|
|
120
|
-
* confusing 422.
|
|
121
|
-
*/
|
|
122
|
-
export function readThemeFromGguiJson(projectRoot, gguiJson) {
|
|
76
|
+
export async function readThemeFromGguiJson(projectRoot, gguiJson) {
|
|
123
77
|
// Cheap pre-check on the raw value: no `theme` field → nothing to push,
|
|
124
78
|
// and we avoid forcing a full-manifest parse on theme-less deploys.
|
|
125
79
|
const presence = z
|
|
@@ -140,9 +94,20 @@ export function readThemeFromGguiJson(projectRoot, gguiJson) {
|
|
|
140
94
|
throw new Error(`ggui.json: ${result.issue.message}`);
|
|
141
95
|
}
|
|
142
96
|
const loaded = result.theme;
|
|
97
|
+
// The wire's theme is the PROJECTION (ggui#987 §3): both modes'
|
|
98
|
+
// derived sets, attested; the declared mode is the default the card
|
|
99
|
+
// paints when no host announces one; the preset id is the label.
|
|
100
|
+
const overlays = loaded.overlays;
|
|
101
|
+
// The document's declared faces ride the wire verbatim (ggui#1093):
|
|
102
|
+
// `typography.faces` and `AppTheme.fonts` are ONE grammar now, so the
|
|
103
|
+
// deploy carries what the author declared instead of dropping it.
|
|
104
|
+
// Absence stays absence — no faces, no `fonts` member.
|
|
105
|
+
const fonts = loaded.document.typography?.faces ?? [];
|
|
143
106
|
const theme = {
|
|
107
|
+
overlayHash: await canonicalOverlayHash({ overlays }),
|
|
108
|
+
overlays,
|
|
144
109
|
mode: loaded.mode,
|
|
145
|
-
|
|
110
|
+
...(fonts.length > 0 ? { fonts: [...fonts] } : {}),
|
|
146
111
|
...(loaded.source === 'preset' ? { name: loaded.preset } : {}),
|
|
147
112
|
};
|
|
148
113
|
// Defense + clear local error: the resolved overlay must satisfy the same
|
|
@@ -152,7 +117,10 @@ export function readThemeFromGguiJson(projectRoot, gguiJson) {
|
|
|
152
117
|
if (!parsed.success) {
|
|
153
118
|
throw new Error(`ggui.json: resolved theme is invalid — ${parsed.error.issues[0]?.message ?? 'unexpected css value'}`);
|
|
154
119
|
}
|
|
155
|
-
|
|
120
|
+
const declaredFaceFamilies = [
|
|
121
|
+
...new Set((loaded.document.typography?.faces ?? []).map((face) => face.family)),
|
|
122
|
+
];
|
|
123
|
+
return { theme: parsed.data, declaredFaceFamilies };
|
|
156
124
|
}
|
|
157
125
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
158
126
|
// Loopback guard
|
|
@@ -238,7 +206,15 @@ export async function runConfigPushStep(appId, startDir = process.cwd()) {
|
|
|
238
206
|
try {
|
|
239
207
|
// `loadTheme` resolves relative `theme.file` paths against the directory
|
|
240
208
|
// containing ggui.json — the same root convention `storage.*.path` uses.
|
|
241
|
-
|
|
209
|
+
const read = await readThemeFromGguiJson(dirname(gguiJsonPath), readResult.value);
|
|
210
|
+
theme = read?.theme;
|
|
211
|
+
if (read !== undefined && read.declaredFaceFamilies.length > 0) {
|
|
212
|
+
// ggui#990/#1093: the PATCH now CARRIES the faces (`AppTheme.fonts`)
|
|
213
|
+
// and a server on this release inlines them in the shell it serves.
|
|
214
|
+
// A deployment still running an older release cannot — so the deploy
|
|
215
|
+
// names the families once, as the version-skew line it is.
|
|
216
|
+
process.stderr.write(`ggui deploy: theme declares font faces (${read.declaredFaceFamilies.join(', ')}) — carried on the wire; a deployment older than this release paints the fallback stack until it rolls (ggui-ai/ggui#990).\n`);
|
|
217
|
+
}
|
|
242
218
|
}
|
|
243
219
|
catch (err) {
|
|
244
220
|
process.stderr.write(`ggui deploy: ${err instanceof Error ? err.message : String(err)}\n`);
|
package/dist/deploy-command.d.ts
CHANGED
|
@@ -28,10 +28,10 @@ export declare function planDeploySteps(input: DeployInput): DeployStep[];
|
|
|
28
28
|
/**
|
|
29
29
|
* Resolve the `GGUI_MCP_URL` value `ggui deploy` wires into `.env.local`.
|
|
30
30
|
*
|
|
31
|
-
* The per-app
|
|
31
|
+
* The hosted per-app server serves the MCP transport at the BARE per-app endpoint
|
|
32
32
|
* `<base>/apps/<appId>` (the `connectUrl` the backend advertises) — NOT a
|
|
33
33
|
* `/mcp` sub-path. The `/mcp` suffix is the LOCAL `ggui serve` convention;
|
|
34
|
-
* appending it here produced a URL the per-app
|
|
34
|
+
* appending it here produced a URL the per-app server 404s, so the agent (which
|
|
35
35
|
* reads GGUI_MCP_URL verbatim) could never connect to a deployed app.
|
|
36
36
|
*
|
|
37
37
|
* - `connectUrl` present (a create-app ran this session) → use it VERBATIM —
|
package/dist/deploy-command.js
CHANGED
|
@@ -52,10 +52,10 @@ export function planDeploySteps(input) {
|
|
|
52
52
|
/**
|
|
53
53
|
* Resolve the `GGUI_MCP_URL` value `ggui deploy` wires into `.env.local`.
|
|
54
54
|
*
|
|
55
|
-
* The per-app
|
|
55
|
+
* The hosted per-app server serves the MCP transport at the BARE per-app endpoint
|
|
56
56
|
* `<base>/apps/<appId>` (the `connectUrl` the backend advertises) — NOT a
|
|
57
57
|
* `/mcp` sub-path. The `/mcp` suffix is the LOCAL `ggui serve` convention;
|
|
58
|
-
* appending it here produced a URL the per-app
|
|
58
|
+
* appending it here produced a URL the per-app server 404s, so the agent (which
|
|
59
59
|
* reads GGUI_MCP_URL verbatim) could never connect to a deployed app.
|
|
60
60
|
*
|
|
61
61
|
* - `connectUrl` present (a create-app ran this session) → use it VERBATIM —
|
|
@@ -330,7 +330,7 @@ export async function runDeployCommand(_args) {
|
|
|
330
330
|
break;
|
|
331
331
|
}
|
|
332
332
|
// No prior value → resolve the deployment-correct BARE per-app URL
|
|
333
|
-
// (see resolveDeployMcpUrl: the per-app
|
|
333
|
+
// (see resolveDeployMcpUrl: the per-app server serves MCP at the bare
|
|
334
334
|
// endpoint, never `/mcp`). The fallback to the production default only
|
|
335
335
|
// fires when create-app didn't run this session — a first deploy always
|
|
336
336
|
// has connectUrl, so it never reaches the fallback in practice.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded drain for the CLI's success path.
|
|
3
|
+
*
|
|
4
|
+
* `main()` resolves with an exit code and the process is expected to end on
|
|
5
|
+
* its own: every command closes its handles, and a hard `process.exit()`
|
|
6
|
+
* while the local embedding model is loaded aborts under ONNX Runtime's
|
|
7
|
+
* parked worker threads (#855). The drain is the contract — this is what
|
|
8
|
+
* happens if a future change leaks a handle: instead of a process that
|
|
9
|
+
* never ends (strictly worse for an operator than the abort it replaced),
|
|
10
|
+
* the deadline names the live resources on stderr and hard-exits with the
|
|
11
|
+
* code. The timer is unref'd so the deadline itself never keeps the loop
|
|
12
|
+
* alive; a drained loop exits before it fires and nothing is written.
|
|
13
|
+
*/
|
|
14
|
+
export declare const DRAIN_DEADLINE_MS = 5000;
|
|
15
|
+
export interface DrainDeadlineDeps {
|
|
16
|
+
readonly exitCode: number;
|
|
17
|
+
readonly deadlineMs: number;
|
|
18
|
+
readonly exit: (code: number) => void;
|
|
19
|
+
readonly stderr: (line: string) => void;
|
|
20
|
+
readonly setTimer: (fn: () => void, ms: number) => {
|
|
21
|
+
unref: () => void;
|
|
22
|
+
};
|
|
23
|
+
/** `process.getActiveResourcesInfo()` — what still keeps the loop alive. */
|
|
24
|
+
readonly liveResources: () => readonly string[];
|
|
25
|
+
}
|
|
26
|
+
export declare function armDrainDeadline(deps: DrainDeadlineDeps): void;
|
|
27
|
+
//# sourceMappingURL=drain-deadline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drain-deadline.d.ts","sourceRoot":"","sources":["../src/drain-deadline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,iBAAiB,OAAQ,CAAC;AAEvC,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,QAAQ,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,KAAK;QAAE,KAAK,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC;IACzE,4EAA4E;IAC5E,QAAQ,CAAC,aAAa,EAAE,MAAM,SAAS,MAAM,EAAE,CAAC;CACjD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAS9D"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded drain for the CLI's success path.
|
|
3
|
+
*
|
|
4
|
+
* `main()` resolves with an exit code and the process is expected to end on
|
|
5
|
+
* its own: every command closes its handles, and a hard `process.exit()`
|
|
6
|
+
* while the local embedding model is loaded aborts under ONNX Runtime's
|
|
7
|
+
* parked worker threads (#855). The drain is the contract — this is what
|
|
8
|
+
* happens if a future change leaks a handle: instead of a process that
|
|
9
|
+
* never ends (strictly worse for an operator than the abort it replaced),
|
|
10
|
+
* the deadline names the live resources on stderr and hard-exits with the
|
|
11
|
+
* code. The timer is unref'd so the deadline itself never keeps the loop
|
|
12
|
+
* alive; a drained loop exits before it fires and nothing is written.
|
|
13
|
+
*/
|
|
14
|
+
export const DRAIN_DEADLINE_MS = 5_000;
|
|
15
|
+
export function armDrainDeadline(deps) {
|
|
16
|
+
const timer = deps.setTimer(() => {
|
|
17
|
+
const live = deps.liveResources();
|
|
18
|
+
deps.stderr(`ggui: shutdown did not drain within ${deps.deadlineMs}ms — live resources: ${live.length > 0 ? live.join(', ') : '(none reported)'}; exiting ${deps.exitCode}\n`);
|
|
19
|
+
deps.exit(deps.exitCode);
|
|
20
|
+
}, deps.deadlineMs);
|
|
21
|
+
timer.unref();
|
|
22
|
+
}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* re-runs the resolver for the chosen provider with
|
|
15
15
|
* `userScope: ctx.appId`, so per-end-user keys stored at the
|
|
16
16
|
* caller's identity scope flip in at request time without a
|
|
17
|
-
* server restart. Multi-
|
|
17
|
+
* server restart. Multi-user `ggui serve` lives off this
|
|
18
18
|
* seam: each authenticated user manages their OWN provider
|
|
19
19
|
* key via `/settings`, the resolver picks it up on the next
|
|
20
20
|
* `ggui_render`.
|
|
@@ -166,7 +166,7 @@ export interface GenerationBinding {
|
|
|
166
166
|
* `true` when the boot scan resolved a key at the operator's
|
|
167
167
|
* `'global'` scope (env or credentials-file). `false` means
|
|
168
168
|
* generation will fall back to either the per-end-user key
|
|
169
|
-
* (multi-
|
|
169
|
+
* (multi-user) or the {@link GenerationDeps.onNoCredentials}
|
|
170
170
|
* card on first call.
|
|
171
171
|
*/
|
|
172
172
|
readonly bootResolved: boolean;
|
package/dist/generation-probe.js
CHANGED
|
@@ -119,7 +119,7 @@ export async function probeGenerationBinding(opts) {
|
|
|
119
119
|
const resolveLlm = async (ctx) => {
|
|
120
120
|
// Per-call BYOK with `userScope: ctx.appId` — env + global
|
|
121
121
|
// (operator) checked first, then the caller's identity scope
|
|
122
|
-
// (end-user). Multi-
|
|
122
|
+
// (end-user). Multi-user + Anthropic-OAuth flows store
|
|
123
123
|
// user-supplied bundles under `userId` here.
|
|
124
124
|
const resolution = await opts.resolver.resolve(defaultProvider, {
|
|
125
125
|
userScope: ctx.appId,
|
package/dist/mcp-backend.d.ts
CHANGED
|
@@ -110,7 +110,7 @@ export interface BuildMcpServerBackendOptions {
|
|
|
110
110
|
* {@link probeGenerationBinding} — env (`ANTHROPIC_API_KEY` etc.)
|
|
111
111
|
* first, then `~/.ggui/credentials.json`. Programmatic hosts
|
|
112
112
|
* embedding `buildMcpServerBackend` directly supply their own
|
|
113
|
-
* `GenerationDeps` bundle (real BYOK in a hosted multi-
|
|
113
|
+
* `GenerationDeps` bundle (real BYOK in a hosted multi-user
|
|
114
114
|
* setting, a test double, etc.).
|
|
115
115
|
*/
|
|
116
116
|
readonly generation?: GenerationDeps;
|
|
@@ -188,20 +188,20 @@ export interface BuildMcpServerBackendOptions {
|
|
|
188
188
|
*/
|
|
189
189
|
readonly publicDemo?: boolean;
|
|
190
190
|
/**
|
|
191
|
-
* Multi-
|
|
191
|
+
* Multi-user posture. Switches the `/ggui/console/llm-keys` gate
|
|
192
192
|
* from admin-token to auth-adapter — each authenticated end-user
|
|
193
193
|
* manages their OWN provider keys (scope = `userId` for `kind:'user'`
|
|
194
194
|
* identities, `appId` for `kind:'app'`). `kind:'builder'` identities
|
|
195
|
-
* are rejected at the gate; multi-
|
|
195
|
+
* are rejected at the gate; multi-user is meaningless without a
|
|
196
196
|
* real per-caller id.
|
|
197
197
|
*
|
|
198
198
|
* Strict-auth shape — every bearer must clear the `AuthAdapter`
|
|
199
199
|
* (pairing-minted, OIDC, Cognito, or whatever the embedding host
|
|
200
200
|
* binds). Mutually exclusive with `devAllowAll` and `publicDemo`;
|
|
201
201
|
* the CLI rejects combinations at parse time. Surface =
|
|
202
|
-
* `--multi-
|
|
202
|
+
* `--multi-user` CLI flag.
|
|
203
203
|
*/
|
|
204
|
-
readonly
|
|
204
|
+
readonly multiUser?: boolean;
|
|
205
205
|
/**
|
|
206
206
|
* Public base URL that replaces `http://<host>:<port>` when
|
|
207
207
|
* composing `mcpApps.wsUrl` and `runtime.url`. Set this when the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-backend.d.ts","sourceRoot":"","sources":["../src/mcp-backend.ts"],"names":[],"mappings":"AA0CA,OAAO,EAQL,KAAK,iBAAiB,EACtB,KAAK,0BAA0B,EAE/B,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACnB,KAAK,WAAW,EACjB,MAAM,qBAAqB,CAAC;AAO7B,OAAO,EAIL,KAAK,aAAa,EAKnB,MAAM,sCAAsC,CAAC;AAE9C,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACvE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAMvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,MAAM,WAAW,4BAA4B;IAC3C;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,qBAAqB,CAAC;IACzC;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;;;;OAOG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;;;;OAOG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IAC/C;;;;;;;;;OASG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;IACjC;;;;;;;;OAQG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,SAAS,0BAA0B,EAAE,CAAC;IACnE;;;;;;;OAOG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,WAAW,CAAC;IAC7B;;;;;;;OAOG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC;IACnC;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MACrB;QACE,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;KAClC,GACD,SAAS,CAAC;IACd;;;;;;OAMG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAC;IAClE;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,cAAc,CAAC;IAErC;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;IAE9C;;;;OAIG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAEhD;;;;;;;;;;;;;;;;OAgBG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE;QAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAC7B,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;YAC9B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;YACpB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;YAC9B,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC;SAC/B,CAAC,CAAC;KACJ,CAAC;IAEF;;;;;;;;;OASG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,aAAa,CAAC,cAAc,CAAC,CAAC;IAEnD;;;;;;;;;OASG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAE/B;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAE9B;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"mcp-backend.d.ts","sourceRoot":"","sources":["../src/mcp-backend.ts"],"names":[],"mappings":"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"}
|
package/dist/mcp-backend.js
CHANGED
|
@@ -166,7 +166,14 @@ export function buildMcpServerBackend(opts) {
|
|
|
166
166
|
// fallback warning rather than a silent first-lookup degradation.
|
|
167
167
|
// eslint-disable-next-line no-console -- one-shot boot signal, mirrors banner output
|
|
168
168
|
console.warn(`[ggui:embedding] local ${embedding.id} (cache: ${embeddingCacheDir})`);
|
|
169
|
-
|
|
169
|
+
const warmupStartedAt = Date.now();
|
|
170
|
+
embedding.embed("warmup").then(() => {
|
|
171
|
+
// One-shot boot signal: the model is loaded and semantic search is
|
|
172
|
+
// live from here. Harnesses wait on this line before exercising
|
|
173
|
+
// (or tearing down) the loaded-model path (#855).
|
|
174
|
+
// eslint-disable-next-line no-console -- one-shot boot signal, mirrors banner output
|
|
175
|
+
console.warn(`[ggui:embedding] warm — local model loaded in ${Date.now() - warmupStartedAt}ms`);
|
|
176
|
+
}, (err) => {
|
|
170
177
|
const reason = err instanceof Error ? err.message : String(err);
|
|
171
178
|
// No provider swap happens here — the local provider stays bound and
|
|
172
179
|
// every embed() keeps failing, which search handlers absorb per-call
|
|
@@ -247,7 +254,7 @@ export function buildMcpServerBackend(opts) {
|
|
|
247
254
|
}
|
|
248
255
|
}
|
|
249
256
|
// Per-app metadata store seeded from `ggui.json#theme.preset` (when
|
|
250
|
-
// the manifest declares a preset variant). Single-
|
|
257
|
+
// the manifest declares a preset variant). Single-app: any
|
|
251
258
|
// appId the handlers see picks up this default theme via
|
|
252
259
|
// `InMemoryAppMetadataStore.get`'s defaults fall-through. File-mode
|
|
253
260
|
// themes don't have a registry id to surface here — agents pick from
|
|
@@ -405,12 +412,12 @@ export function buildMcpServerBackend(opts) {
|
|
|
405
412
|
: {}),
|
|
406
413
|
...(resolvedMcpInstructions !== undefined ? { mcpInstructions: resolvedMcpInstructions } : {}),
|
|
407
414
|
...(resolvedWithhold ? { withholdResultMeta: true } : {}),
|
|
408
|
-
// `--multi-
|
|
415
|
+
// `--multi-user` flips the `/ggui/console/llm-keys` gate from
|
|
409
416
|
// admin-token to auth-adapter. Default scope derivation in the
|
|
410
417
|
// server picks up `userId` / `appId` from the resolved identity;
|
|
411
418
|
// operators with composite scopes pass their own `providerKeyScope`
|
|
412
419
|
// by composing `createGguiServer` directly.
|
|
413
|
-
...(opts.
|
|
420
|
+
...(opts.multiUser ? { providerKeysGate: "auth-adapter" } : {}),
|
|
414
421
|
// Gate OAuth login routes on publicBaseUrl. Without it the
|
|
415
422
|
// redirect_uri can't be composed; the admin transport still mounts
|
|
416
423
|
// so operators can paste credentials in advance.
|
|
@@ -538,6 +545,14 @@ export function buildMcpServerBackend(opts) {
|
|
|
538
545
|
// `ggui.json#theme`; absent = `createGguiServer` falls back to its
|
|
539
546
|
// `lightTheme`-backed default internally.
|
|
540
547
|
...(opts.theme ? { theme: opts.theme } : {}),
|
|
548
|
+
// The theme document's declared font faces (ggui#987 §5): the
|
|
549
|
+
// server unions their origins into every served shell's CSP and
|
|
550
|
+
// inlines the rules, so the faces load without host cooperation.
|
|
551
|
+
...(opts.theme !== undefined &&
|
|
552
|
+
opts.theme.document.typography?.faces !== undefined &&
|
|
553
|
+
opts.theme.document.typography.faces.length > 0
|
|
554
|
+
? { fontFaces: opts.theme.document.typography.faces }
|
|
555
|
+
: {}),
|
|
541
556
|
// Console theme picker writer — paired with the admin-gated
|
|
542
557
|
// `/ggui/console/theme` POST. Absent = picker UI surfaces a
|
|
543
558
|
// read-only banner + POST returns 501. CLI sets this when
|
package/dist/push-command.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ export interface PushRecord {
|
|
|
20
20
|
/** Tool-identity catalog hash at export — feeds the import gate's re-key check. */
|
|
21
21
|
readonly toolIdentityCatalogHash?: string;
|
|
22
22
|
};
|
|
23
|
-
/** Compiled ESM JS, ready for the
|
|
23
|
+
/** Compiled ESM JS, ready for the hosted server to evaluate directly (no server-side esbuild). */
|
|
24
24
|
readonly compiledBytes: string;
|
|
25
25
|
}
|
|
26
26
|
export interface ParsedPushFlags {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"push-command.d.ts","sourceRoot":"","sources":["../src/push-command.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAWtD,kFAAkF;AAClF,MAAM,WAAW,UAAU;IACzB,2FAA2F;IAC3F,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,4DAA4D;IAC5D,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE;QACjB,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;QAChC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAC9B;;;;;WAKG;QACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QACzB,8EAA8E;QAC9E,QAAQ,CAAC,wBAAwB,CAAC,EAAE,MAAM,CAAC;QAC3C,mFAAmF;QACnF,QAAQ,CAAC,uBAAuB,CAAC,EAAE,MAAM,CAAC;KAC3C,CAAC;IACF,
|
|
1
|
+
{"version":3,"file":"push-command.d.ts","sourceRoot":"","sources":["../src/push-command.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAWtD,kFAAkF;AAClF,MAAM,WAAW,UAAU;IACzB,2FAA2F;IAC3F,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,4DAA4D;IAC5D,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE;QACjB,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;QAChC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAC9B;;;;;WAKG;QACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QACzB,8EAA8E;QAC9E,QAAQ,CAAC,wBAAwB,CAAC,EAAE,MAAM,CAAC;QAC3C,mFAAmF;QACnF,QAAQ,CAAC,uBAAuB,CAAC,EAAE,MAAM,CAAC;KAC3C,CAAC;IACF,kGAAkG;IAClG,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAMD,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,eAAe,CA+BvE;AAMD;;;;;;;;;;GAUG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA0B9D;AAMD;;;;;;GAMG;AACH,wBAAsB,yBAAyB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAyC1F;AAMD,eAAO,MAAM,SAAS,onBAerB,CAAC;AAEF,wBAAsB,cAAc,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA4E7E"}
|
package/dist/serve-command.d.ts
CHANGED
|
@@ -120,7 +120,7 @@ export interface ParsedServeFlags {
|
|
|
120
120
|
*/
|
|
121
121
|
publicDemo: boolean;
|
|
122
122
|
/**
|
|
123
|
-
* Multi-
|
|
123
|
+
* Multi-user posture. Switches the `/ggui/console/llm-keys` gate
|
|
124
124
|
* from admin-token to auth-adapter — each authenticated end-user
|
|
125
125
|
* manages their OWN provider keys (scope = `userId` for `kind:'user'`
|
|
126
126
|
* identities, `appId` for `kind:'app'`). `kind:'builder'` identities
|
|
@@ -129,14 +129,14 @@ export interface ParsedServeFlags {
|
|
|
129
129
|
* Strict-auth shape — every bearer must clear the `AuthAdapter`.
|
|
130
130
|
* Mutually exclusive with {@link devAllowAll} and {@link publicDemo};
|
|
131
131
|
* those modes collapse every identity to `kind:'builder'` which the
|
|
132
|
-
* multi-
|
|
133
|
-
* server that's wired multi-
|
|
132
|
+
* multi-user gate rejects, so the combination would produce a
|
|
133
|
+
* server that's wired multi-user but can't authenticate anyone.
|
|
134
134
|
*
|
|
135
135
|
* Use case: a single `ggui serve` instance fronting many users (a
|
|
136
136
|
* shared dev box, a small team server) where each user pastes their
|
|
137
137
|
* own LLM key via /settings using their paired bearer.
|
|
138
138
|
*/
|
|
139
|
-
|
|
139
|
+
multiUser: boolean;
|
|
140
140
|
/**
|
|
141
141
|
* Server-level MCP instructions preset (the string injected into
|
|
142
142
|
* the LLM's system prompt above the tool catalog). Operator-tunable
|
|
@@ -312,13 +312,13 @@ export interface ServeBannerInputs {
|
|
|
312
312
|
*/
|
|
313
313
|
readonly publicDemo?: boolean;
|
|
314
314
|
/**
|
|
315
|
-
* When true, the auth section adds a "MULTI-
|
|
315
|
+
* When true, the auth section adds a "MULTI-USER" line below the
|
|
316
316
|
* strict-auth blurb explaining that each user manages their own LLM
|
|
317
317
|
* keys via /settings under their paired bearer. Set by
|
|
318
|
-
* `--multi-
|
|
318
|
+
* `--multi-user`. Mutually exclusive with `devAllowAll` and
|
|
319
319
|
* `publicDemo` at parse time.
|
|
320
320
|
*/
|
|
321
|
-
readonly
|
|
321
|
+
readonly multiUser?: boolean;
|
|
322
322
|
/**
|
|
323
323
|
* Public base URL displayed under the local URLs when set via
|
|
324
324
|
* `--public-base-url`. Reminds the operator which URL their tunnel
|
|
@@ -525,5 +525,5 @@ export interface RunServeOptions {
|
|
|
525
525
|
* {@link describeServeBanner} / {@link describeAgentStatus}.
|
|
526
526
|
*/
|
|
527
527
|
export declare function runServe(opts: RunServeOptions): Promise<number>;
|
|
528
|
-
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";
|
|
528
|
+
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-user Multi-user 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-user: every request scopes to one `builder` app id.\n";
|
|
529
529
|
//# sourceMappingURL=serve-command.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serve-command.d.ts","sourceRoot":"","sources":["../src/serve-command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,KAAK,EACV,mBAAmB,EACnB,iBAAiB,EAEjB,sBAAsB,EACvB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAG1D;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,OAAO,CAAC;AAEvC,6DAA6D;AAC7D,eAAO,MAAM,kBAAkB,cAAc,CAAC;AAE9C,MAAM,WAAW,gBAAgB;IAC/B,+EAA+E;IAC/E,IAAI,EAAE,MAAM,CAAC;IACb,4DAA4D;IAC5D,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,OAAO,EAAE,OAAO,CAAC;IACjB;;;;;;;;;;OAUG;IACH,WAAW,EAAE,OAAO,CAAC;IACrB;;;;;;;;;;;OAWG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,KAAK,EAAE,OAAO,CAAC;IACf;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,UAAU,EAAE,OAAO,CAAC;IACpB;;;;;;;;;;;;;;;;OAgBG;IACH,
|
|
1
|
+
{"version":3,"file":"serve-command.d.ts","sourceRoot":"","sources":["../src/serve-command.ts"],"names":[],"mappings":"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"}
|
package/dist/serve-command.js
CHANGED
|
@@ -25,7 +25,7 @@ export function parseServeFlags(args) {
|
|
|
25
25
|
devAllowAll: false,
|
|
26
26
|
withholdResultMeta: false,
|
|
27
27
|
publicDemo: false,
|
|
28
|
-
|
|
28
|
+
multiUser: false,
|
|
29
29
|
oauth: false,
|
|
30
30
|
seedPools: [],
|
|
31
31
|
browserOrigins: [],
|
|
@@ -71,8 +71,8 @@ export function parseServeFlags(args) {
|
|
|
71
71
|
out.publicDemo = true;
|
|
72
72
|
continue;
|
|
73
73
|
}
|
|
74
|
-
if (arg === '--multi-
|
|
75
|
-
out.
|
|
74
|
+
if (arg === '--multi-user') {
|
|
75
|
+
out.multiUser = true;
|
|
76
76
|
continue;
|
|
77
77
|
}
|
|
78
78
|
if (arg === '--oauth') {
|
|
@@ -179,13 +179,13 @@ export function parseServeFlags(args) {
|
|
|
179
179
|
'public demo (rate-limited, "PUBLIC DEMO" copy). Pick one.',
|
|
180
180
|
};
|
|
181
181
|
}
|
|
182
|
-
if (out.
|
|
182
|
+
if (out.multiUser && (out.devAllowAll || out.publicDemo)) {
|
|
183
183
|
return {
|
|
184
184
|
...out,
|
|
185
|
-
error: '--multi-
|
|
186
|
-
'Multi-
|
|
185
|
+
error: '--multi-user is incompatible with --dev-allow-all and --public-demo. ' +
|
|
186
|
+
'Multi-user requires real per-user identities (kind:"user" / kind:"app"); ' +
|
|
187
187
|
'the any-bearer modes collapse every caller to kind:"builder" which the ' +
|
|
188
|
-
'multi-
|
|
188
|
+
'multi-user gate rejects. Drop the other flag and pair with real bearers.',
|
|
189
189
|
};
|
|
190
190
|
}
|
|
191
191
|
return out;
|
|
@@ -256,8 +256,8 @@ export function describeServeBanner(input) {
|
|
|
256
256
|
}
|
|
257
257
|
else {
|
|
258
258
|
lines.push(` auth: strict — only pair-minted bearer tokens authenticate /mcp.`, ` Pair via the code above (landing page or \`POST /pair\`).`, ` Override the adapter via GguiServer({ auth }) in code for`, ` custom deployments (OIDC, Cognito, etc.).`);
|
|
259
|
-
if (input.
|
|
260
|
-
lines.push(``, ` multi-
|
|
259
|
+
if (input.multiUser) {
|
|
260
|
+
lines.push(``, ` multi-user: each authenticated user manages their OWN LLM`, ` keys at /settings — the gate uses the request's bearer`, ` (Authorization: Bearer their-paired-token), NOT the`, ` admin token. Per-user scope is auto-derived from the`, ` identity (userId / appId).`, ` Note: ggui_render generation still resolves BYOK at the`, ` operator scope (env + credentials-file 'global'). Per-`, ` user generation-time BYOK is a follow-up — for now,`, ` multi-user lets each user MANAGE their key plane`, ` without granting them the operator's admin token.`);
|
|
261
261
|
}
|
|
262
262
|
if (input.oauth) {
|
|
263
263
|
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.`);
|
|
@@ -381,7 +381,7 @@ export async function runServe(opts) {
|
|
|
381
381
|
agent: opts.agentStatus,
|
|
382
382
|
devAllowAll: opts.flags.devAllowAll,
|
|
383
383
|
publicDemo: opts.flags.publicDemo,
|
|
384
|
-
|
|
384
|
+
multiUser: opts.flags.multiUser,
|
|
385
385
|
oauth: opts.flags.oauth,
|
|
386
386
|
...(opts.flags.publicBaseUrl !== undefined
|
|
387
387
|
? { publicBaseUrl: opts.flags.publicBaseUrl }
|
|
@@ -490,7 +490,7 @@ Options:
|
|
|
490
490
|
ggui_render (30 generations / 10 min) and a
|
|
491
491
|
"PUBLIC DEMO — operator pays" banner. Mutually
|
|
492
492
|
exclusive with --dev-allow-all.
|
|
493
|
-
--multi-
|
|
493
|
+
--multi-user Multi-user posture: switches the /settings LLM-
|
|
494
494
|
keys gate from admin-token to auth-adapter so
|
|
495
495
|
each authenticated end-user manages their OWN
|
|
496
496
|
key plane (scope = userId/appId). kind:'builder'
|
|
@@ -633,5 +633,5 @@ Current limits:
|
|
|
633
633
|
bearer you can use with MCP. Embed @ggui-ai/mcp-server in your
|
|
634
634
|
own entrypoint to inject a different AuthAdapter (OIDC, Cognito,
|
|
635
635
|
etc.) for production.
|
|
636
|
-
- Single-
|
|
636
|
+
- Single-user: every request scopes to one \`builder\` app id.
|
|
637
637
|
`;
|
package/dist/theme-command.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const THEME_HELP = "ggui theme \u2014 validate + inspect operator-authored DTCG themes\n\nUsage:\n ggui theme <subcommand> [options]\n\nSubcommands:\n validate <path> Validate a JSON theme file against the
|
|
1
|
+
export declare const THEME_HELP = "ggui theme \u2014 validate + inspect operator-authored DTCG themes\n\nUsage:\n ggui theme <subcommand> [options]\n\nSubcommands:\n validate <path> Validate a JSON theme file against the ThemeDocumentV2 schema.\n\nRun `ggui theme <subcommand> --help` for subcommand-specific options.\n";
|
|
2
2
|
export declare const THEME_VALIDATE_HELP = "ggui theme validate \u2014 validate a DTCG theme file\n\nUsage:\n ggui theme validate <path>\n\nArguments:\n <path> Path to a JSON theme document (e.g. `./theme.json`).\n\nExit codes:\n 0 theme is valid\n 1 theme file is unreadable, not JSON, or fails schema validation\n 2 bad CLI usage (missing path argument)\n";
|
|
3
3
|
export declare function runThemeCommand(args: readonly string[]): Promise<number>;
|
|
4
4
|
//# sourceMappingURL=theme-command.d.ts.map
|
package/dist/theme-command.js
CHANGED
|
@@ -27,7 +27,7 @@ Usage:
|
|
|
27
27
|
ggui theme <subcommand> [options]
|
|
28
28
|
|
|
29
29
|
Subcommands:
|
|
30
|
-
validate <path> Validate a JSON theme file against the
|
|
30
|
+
validate <path> Validate a JSON theme file against the ThemeDocumentV2 schema.
|
|
31
31
|
|
|
32
32
|
Run \`ggui theme <subcommand> --help\` for subcommand-specific options.
|
|
33
33
|
`;
|
|
@@ -127,7 +127,7 @@ async function runValidate(args) {
|
|
|
127
127
|
*/
|
|
128
128
|
function describeValidTheme(absPath, theme) {
|
|
129
129
|
const lines = [];
|
|
130
|
-
const mark = process.stdout.isTTY ? '
|
|
130
|
+
const mark = process.stdout.isTTY ? '\x1b[32m✓\x1b[0m' : '✓';
|
|
131
131
|
const nameSuffix = theme.$name ? ` (${theme.$name})` : '';
|
|
132
132
|
lines.push(`${mark} Theme valid${nameSuffix}`);
|
|
133
133
|
lines.push(` file: ${absPath}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ggui-ai/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.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.28.2",
|
|
39
39
|
"zod": "^4.3.6",
|
|
40
|
-
"@ggui-ai/
|
|
41
|
-
"@ggui-ai/
|
|
42
|
-
"@ggui-ai/
|
|
43
|
-
"@ggui-ai/
|
|
44
|
-
"@ggui-ai/
|
|
45
|
-
"@ggui-ai/embedding-local": "0.
|
|
46
|
-
"@ggui-ai/mcp-server": "0.
|
|
47
|
-
"@ggui-ai/mcp-server-
|
|
48
|
-
"@ggui-ai/
|
|
49
|
-
"@ggui-ai/
|
|
50
|
-
"@ggui-ai/
|
|
51
|
-
"@ggui-ai/
|
|
52
|
-
"@ggui-ai/
|
|
53
|
-
"@ggui-ai/
|
|
54
|
-
"@ggui-ai/ui-gen": "0.
|
|
55
|
-
"@ggui-ai/ui-registry": "0.
|
|
40
|
+
"@ggui-ai/gadget-signing": "0.17.0",
|
|
41
|
+
"@ggui-ai/dev-stack": "0.17.0",
|
|
42
|
+
"@ggui-ai/design": "0.17.0",
|
|
43
|
+
"@ggui-ai/artifact-manifest": "0.17.0",
|
|
44
|
+
"@ggui-ai/agent-runtime": "0.17.0",
|
|
45
|
+
"@ggui-ai/embedding-local": "0.17.0",
|
|
46
|
+
"@ggui-ai/mcp-server": "0.17.0",
|
|
47
|
+
"@ggui-ai/mcp-server-handlers": "0.17.0",
|
|
48
|
+
"@ggui-ai/protocol": "0.17.0",
|
|
49
|
+
"@ggui-ai/preview-a2ui": "0.17.0",
|
|
50
|
+
"@ggui-ai/registry-core": "0.17.0",
|
|
51
|
+
"@ggui-ai/project-config": "0.17.0",
|
|
52
|
+
"@ggui-ai/iframe-runtime": "0.17.0",
|
|
53
|
+
"@ggui-ai/mcp-server-core": "0.17.0",
|
|
54
|
+
"@ggui-ai/ui-gen": "0.17.0",
|
|
55
|
+
"@ggui-ai/ui-registry": "0.17.0"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"@types/node": "^24.0.0",
|