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