@ggui-ai/protocol-reference-server 0.1.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +45 -0
- package/dist/action-router.d.ts +40 -0
- package/dist/action-router.d.ts.map +1 -0
- package/dist/action-router.js +283 -0
- package/dist/cli.d.ts +10 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +110 -0
- package/dist/conformance-host.d.ts +44 -0
- package/dist/conformance-host.d.ts.map +1 -0
- package/dist/conformance-host.js +185 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/server.d.ts +59 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +224 -0
- package/dist/session.d.ts +142 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +134 -0
- package/dist/tool-registry.d.ts +63 -0
- package/dist/tool-registry.d.ts.map +1 -0
- package/dist/tool-registry.js +99 -0
- package/package.json +64 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* `ggui-protocol-reference-server` — CLI entry.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
*
|
|
7
|
+
* npx @ggui-ai/protocol-reference-server --port 3100
|
|
8
|
+
*
|
|
9
|
+
* Prints `READY ws://host:port/ws` to stdout when bound. Runs
|
|
10
|
+
* indefinitely; Ctrl-C to stop.
|
|
11
|
+
*
|
|
12
|
+
* This is the manual smoke-check entry. For programmatic use (the
|
|
13
|
+
* conformance CI test, third-party integration tests), import
|
|
14
|
+
* `ReferenceServer` + `createReferenceConformanceHost` directly.
|
|
15
|
+
*/
|
|
16
|
+
import { ReferenceServer } from './server.js';
|
|
17
|
+
function parseArgs(argv) {
|
|
18
|
+
let port = 3100;
|
|
19
|
+
let host = '127.0.0.1';
|
|
20
|
+
let help = false;
|
|
21
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
22
|
+
const flag = argv[i];
|
|
23
|
+
const next = () => {
|
|
24
|
+
const value = argv[i + 1];
|
|
25
|
+
if (value === undefined || value.startsWith('--')) {
|
|
26
|
+
throw new Error(`missing value for '${flag}'`);
|
|
27
|
+
}
|
|
28
|
+
i += 1;
|
|
29
|
+
return value;
|
|
30
|
+
};
|
|
31
|
+
switch (flag) {
|
|
32
|
+
case '--port':
|
|
33
|
+
port = Number.parseInt(next(), 10);
|
|
34
|
+
if (Number.isNaN(port))
|
|
35
|
+
throw new Error('--port must be an integer');
|
|
36
|
+
break;
|
|
37
|
+
case '--host':
|
|
38
|
+
host = next();
|
|
39
|
+
break;
|
|
40
|
+
case '--help':
|
|
41
|
+
case '-h':
|
|
42
|
+
help = true;
|
|
43
|
+
break;
|
|
44
|
+
default:
|
|
45
|
+
throw new Error(`unknown flag '${flag}' — run with --help for usage`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return { port, host, help };
|
|
49
|
+
}
|
|
50
|
+
const USAGE = `
|
|
51
|
+
ggui-protocol-reference-server — minimal ggui protocol reference implementation
|
|
52
|
+
|
|
53
|
+
Usage:
|
|
54
|
+
ggui-protocol-reference-server [--port <N>] [--host <H>]
|
|
55
|
+
|
|
56
|
+
Options:
|
|
57
|
+
--port <N> Port to bind. Default 3100.
|
|
58
|
+
--host <H> Host interface. Default 127.0.0.1.
|
|
59
|
+
--help, -h Show this help.
|
|
60
|
+
|
|
61
|
+
Scope: narrow WS server implementing the ggui live-channel wire.
|
|
62
|
+
Used by @ggui-ai/protocol-conformance to prove the protocol is vendor-neutral.
|
|
63
|
+
NOT a production server — no auth, no persistence.
|
|
64
|
+
`.trimStart();
|
|
65
|
+
async function main(argv) {
|
|
66
|
+
let parsed;
|
|
67
|
+
try {
|
|
68
|
+
parsed = parseArgs(argv);
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
process.stderr.write(`error: ${String(err.message ?? err)}\n\n${USAGE}`);
|
|
72
|
+
return 2;
|
|
73
|
+
}
|
|
74
|
+
if (parsed.help) {
|
|
75
|
+
process.stdout.write(USAGE);
|
|
76
|
+
return 0;
|
|
77
|
+
}
|
|
78
|
+
const server = new ReferenceServer({ port: parsed.port, host: parsed.host });
|
|
79
|
+
await server.start();
|
|
80
|
+
process.stdout.write(`READY ws://${parsed.host}:${server.port}/ws\n`);
|
|
81
|
+
// Keep the process alive until SIGINT/SIGTERM.
|
|
82
|
+
await new Promise((done) => {
|
|
83
|
+
const shutdown = () => {
|
|
84
|
+
void server.stop().then(done);
|
|
85
|
+
};
|
|
86
|
+
process.once('SIGINT', shutdown);
|
|
87
|
+
process.once('SIGTERM', shutdown);
|
|
88
|
+
});
|
|
89
|
+
return 0;
|
|
90
|
+
}
|
|
91
|
+
function isEntryPoint() {
|
|
92
|
+
if (typeof import.meta.url !== 'string')
|
|
93
|
+
return false;
|
|
94
|
+
const scriptPath = process.argv[1];
|
|
95
|
+
if (typeof scriptPath !== 'string' || scriptPath.length === 0)
|
|
96
|
+
return false;
|
|
97
|
+
try {
|
|
98
|
+
return import.meta.url === new URL(`file://${scriptPath}`).href;
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (isEntryPoint()) {
|
|
105
|
+
main(process.argv.slice(2)).then((code) => process.exit(code), (err) => {
|
|
106
|
+
process.stderr.write(`fatal: ${String(err.message ?? err)}\n`);
|
|
107
|
+
process.exit(2);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
export { main, parseArgs };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ConformanceHost` adapter — wires the `@ggui-ai/protocol-conformance`
|
|
3
|
+
* setup/teardown directive dispatcher onto this package's
|
|
4
|
+
* `ReferenceServer` instance.
|
|
5
|
+
*
|
|
6
|
+
* Directives split into "implement" and "throw":
|
|
7
|
+
*
|
|
8
|
+
* Implement:
|
|
9
|
+
* - create-session → `sessions.create()`
|
|
10
|
+
* - register-tool → `tools.register(name, handler)`
|
|
11
|
+
* - register-actionspec → `sessions.registerActionSpec()`
|
|
12
|
+
* - register-streamspec → `sessions.registerStreamSpec()`
|
|
13
|
+
* - server-version-override → `sessions.setVersionOverride()`
|
|
14
|
+
* - emit-envelope → `sessions.injectFrame()`
|
|
15
|
+
* - close-session → `sessions.close()`
|
|
16
|
+
* - unregister-tool → `tools.unregister()`
|
|
17
|
+
*
|
|
18
|
+
* Throw (kit records SKIP, not FAIL):
|
|
19
|
+
* - seed-channel — unimplemented
|
|
20
|
+
* - renderer-url-override — unimplemented (browser-level)
|
|
21
|
+
* - ui-initialize-response-override — unimplemented
|
|
22
|
+
*
|
|
23
|
+
* The "throw" set matches the conformance kit's `unmatchable-on-ws`
|
|
24
|
+
* skip expectations — browser-level fault injection that requires a
|
|
25
|
+
* richer host harness. Throwing surfaces "directive not implemented"
|
|
26
|
+
* with the error message as the skip reason.
|
|
27
|
+
*/
|
|
28
|
+
import type { ConformanceHost } from '@ggui-ai/protocol-conformance';
|
|
29
|
+
import type { ReferenceServer } from './server.js';
|
|
30
|
+
export interface CreateReferenceConformanceHostInput {
|
|
31
|
+
readonly serverInstance: ReferenceServer;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Build a `ConformanceHost` bound to the given `ReferenceServer`
|
|
35
|
+
* instance. Pass the return value to `runConformance({host})` to
|
|
36
|
+
* drive the kit against the server.
|
|
37
|
+
*
|
|
38
|
+
* The server MUST be `start()`-ed before the first dispatch — the
|
|
39
|
+
* kit calls `create-session` via `dispatchSetup` before any subscribe,
|
|
40
|
+
* so the session store must be reachable. The caller owns the
|
|
41
|
+
* server lifecycle (`start()` + `stop()`).
|
|
42
|
+
*/
|
|
43
|
+
export declare function createReferenceConformanceHost({ serverInstance, }: CreateReferenceConformanceHostInput): ConformanceHost;
|
|
44
|
+
//# sourceMappingURL=conformance-host.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conformance-host.d.ts","sourceRoot":"","sources":["../src/conformance-host.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,KAAK,EAEV,eAAe,EAMhB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,MAAM,WAAW,mCAAmC;IAClD,QAAQ,CAAC,cAAc,EAAE,eAAe,CAAC;CAC1C;AAED;;;;;;;;;GASG;AACH,wBAAgB,8BAA8B,CAAC,EAC7C,cAAc,GACf,EAAE,mCAAmC,GAAG,eAAe,CAwNvD"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build a `ConformanceHost` bound to the given `ReferenceServer`
|
|
3
|
+
* instance. Pass the return value to `runConformance({host})` to
|
|
4
|
+
* drive the kit against the server.
|
|
5
|
+
*
|
|
6
|
+
* The server MUST be `start()`-ed before the first dispatch — the
|
|
7
|
+
* kit calls `create-session` via `dispatchSetup` before any subscribe,
|
|
8
|
+
* so the session store must be reachable. The caller owns the
|
|
9
|
+
* server lifecycle (`start()` + `stop()`).
|
|
10
|
+
*/
|
|
11
|
+
export function createReferenceConformanceHost({ serverInstance, }) {
|
|
12
|
+
return {
|
|
13
|
+
async dispatchSetup(step) {
|
|
14
|
+
// Discriminant-narrow via explicit casts — the extensibly-closed
|
|
15
|
+
// `HostUnknownSetupStep` arm (`kind: string & {}`) widens the
|
|
16
|
+
// discriminant and blocks literal-narrowing on the union.
|
|
17
|
+
if (step.kind === 'create-session') {
|
|
18
|
+
const s = step;
|
|
19
|
+
serverInstance.sessions.create(s.sessionId, s.appId ?? 'conformance');
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if (step.kind === 'register-tool') {
|
|
23
|
+
// Fixture JSON authors the field as `toolName`; the kit's
|
|
24
|
+
// runtime narrowing (`run-conformance.ts::narrowSetupStep`)
|
|
25
|
+
// only renames `type → kind` and passes other fields verbatim,
|
|
26
|
+
// so the runtime object carries `toolName` not `name`.
|
|
27
|
+
// Tolerate both for forward-compat with a kit fix.
|
|
28
|
+
const raw = step;
|
|
29
|
+
const toolName = raw.toolName ?? raw.name;
|
|
30
|
+
if (typeof toolName !== 'string' || toolName.length === 0) {
|
|
31
|
+
throw new Error(`register-tool directive missing toolName/name: ${JSON.stringify(step)}`);
|
|
32
|
+
}
|
|
33
|
+
serverInstance.tools.register(toolName, raw.handler);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (step.kind === 'register-actionspec') {
|
|
37
|
+
const s = step;
|
|
38
|
+
// register-actionspec doesn't carry a sessionId in the
|
|
39
|
+
// directive shape — it's scoped to the most-recently-created
|
|
40
|
+
// session, matching the fixture-authoring convention that
|
|
41
|
+
// create-session → register-tool → register-actionspec all
|
|
42
|
+
// land in order on the same session.
|
|
43
|
+
const lastSession = serverInstance.sessions.lastCreatedSessionId();
|
|
44
|
+
if (lastSession === undefined) {
|
|
45
|
+
throw new Error('reference-server: register-actionspec invoked before create-session — no session scope to bind to');
|
|
46
|
+
}
|
|
47
|
+
serverInstance.sessions.registerActionSpec(lastSession, {
|
|
48
|
+
name: s.name,
|
|
49
|
+
tool: s.tool,
|
|
50
|
+
});
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (step.kind === 'register-streamspec') {
|
|
54
|
+
// register-streamspec is the streamSpec analogue of register-
|
|
55
|
+
// actionspec — binds a stream channel to a refresh tool. The
|
|
56
|
+
// kit does not export a `RegisterStreamSpecSetup` type today
|
|
57
|
+
// (the directive is reference-server-specific scaffolding for
|
|
58
|
+
// Slice I refresh-stream support); the runtime shape is
|
|
59
|
+
// narrowed locally, matching the same convention as the
|
|
60
|
+
// pre-existing `register-tool` branch above. Same most-
|
|
61
|
+
// recently-created session scoping as register-actionspec.
|
|
62
|
+
const raw = step;
|
|
63
|
+
if (typeof raw.channel !== 'string' || raw.channel.length === 0) {
|
|
64
|
+
throw new Error(`register-streamspec directive missing channel: ${JSON.stringify(step)}`);
|
|
65
|
+
}
|
|
66
|
+
if (typeof raw.tool !== 'string' || raw.tool.length === 0) {
|
|
67
|
+
throw new Error(`register-streamspec directive missing tool: ${JSON.stringify(step)}`);
|
|
68
|
+
}
|
|
69
|
+
const lastSession = serverInstance.sessions.lastCreatedSessionId();
|
|
70
|
+
if (lastSession === undefined) {
|
|
71
|
+
throw new Error('reference-server: register-streamspec invoked before create-session — no session scope to bind to');
|
|
72
|
+
}
|
|
73
|
+
serverInstance.sessions.registerStreamSpec(lastSession, {
|
|
74
|
+
channel: raw.channel,
|
|
75
|
+
tool: raw.tool,
|
|
76
|
+
});
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (step.kind === 'emit-envelope') {
|
|
80
|
+
// The directive carries `channel` + `payload` but no
|
|
81
|
+
// sessionId — it's scoped to the most-recently-created
|
|
82
|
+
// session, matching the same fixture-authoring convention as
|
|
83
|
+
// register-actionspec / register-streamspec / server-version-
|
|
84
|
+
// override (the kit's `narrowSetupStep` is a flat `type → kind`
|
|
85
|
+
// rename pass-through, so any sessionId on the directive JSON
|
|
86
|
+
// would survive, but the canonical EmitEnvelopeSetup shape
|
|
87
|
+
// doesn't declare one).
|
|
88
|
+
//
|
|
89
|
+
// Wire-format wrapping: the directive's `payload: unknown` is
|
|
90
|
+
// the envelope body; the host wraps it in the SPEC §12.2
|
|
91
|
+
// `{type:'stream', payload:{channel, value}}` shape (matching
|
|
92
|
+
// the existing reference-server stream emissions in
|
|
93
|
+
// action-router.ts) before fan-out. Per the kit type docstring,
|
|
94
|
+
// "Host is responsible for wrapping in the wire format
|
|
95
|
+
// (sequence stamp, timestamp, etc.)" — the kit does NOT
|
|
96
|
+
// expect the directive to carry a fully-formed wire frame.
|
|
97
|
+
const s = step;
|
|
98
|
+
if (typeof s.channel !== 'string' || s.channel.length === 0) {
|
|
99
|
+
throw new Error(`emit-envelope directive missing channel: ${JSON.stringify(step)}`);
|
|
100
|
+
}
|
|
101
|
+
const lastSession = serverInstance.sessions.lastCreatedSessionId();
|
|
102
|
+
if (lastSession === undefined) {
|
|
103
|
+
throw new Error('reference-server: emit-envelope invoked before create-session — no session scope to bind to');
|
|
104
|
+
}
|
|
105
|
+
const fanned = serverInstance.sessions.injectFrame(lastSession, {
|
|
106
|
+
type: 'stream',
|
|
107
|
+
payload: {
|
|
108
|
+
channel: s.channel,
|
|
109
|
+
value: s.payload,
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
if (!fanned) {
|
|
113
|
+
// No subscribers attached — the directive's emission is
|
|
114
|
+
// unobservable. Surface for fixture-authoring debuggability
|
|
115
|
+
// (the canonical sequence is create-session → subscribe →
|
|
116
|
+
// emit-envelope; fixtures that swap order silently lose the
|
|
117
|
+
// injection). Not a throw — the directive itself succeeded;
|
|
118
|
+
// the unobservability is a fixture concern.
|
|
119
|
+
// eslint-disable-next-line no-console
|
|
120
|
+
console.warn(`[@ggui-ai/protocol-reference-server] emit-envelope on session '${lastSession}' channel '${s.channel}' had no subscribers — frame dropped`);
|
|
121
|
+
}
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (step.kind === 'renderer-url-override') {
|
|
125
|
+
throw new Error('reference server does not implement renderer-url-override — browser-level fault injection, out of scope');
|
|
126
|
+
}
|
|
127
|
+
if (step.kind === 'ui-initialize-response-override') {
|
|
128
|
+
throw new Error('reference server does not implement ui-initialize-response-override — MCP Apps host concern, out of scope');
|
|
129
|
+
}
|
|
130
|
+
if (step.kind === 'server-version-override') {
|
|
131
|
+
// Fixture JSON authors `advertiseVersion` (matches the
|
|
132
|
+
// semantic — "advertise this version on the wire"); the kit's
|
|
133
|
+
// exported `ServerVersionOverrideSetup` interface uses
|
|
134
|
+
// `version`. Tolerate both for forward-compat with the kit's
|
|
135
|
+
// own type, mirroring the same name-tolerance pattern in
|
|
136
|
+
// register-tool above. The runtime `narrowSetupStep` only
|
|
137
|
+
// renames `type → kind` and passes other fields verbatim, so
|
|
138
|
+
// whichever the fixture authors arrives unchanged.
|
|
139
|
+
const raw = step;
|
|
140
|
+
const advertise = raw.advertiseVersion ?? raw.version;
|
|
141
|
+
if (typeof advertise !== 'string' || advertise.length === 0) {
|
|
142
|
+
throw new Error(`server-version-override directive missing advertiseVersion/version: ${JSON.stringify(step)}`);
|
|
143
|
+
}
|
|
144
|
+
// Same most-recently-created session scope as register-
|
|
145
|
+
// actionspec / register-streamspec — the fixture authoring
|
|
146
|
+
// convention is `create-session` immediately precedes this
|
|
147
|
+
// directive, and the kit's narrowSetupStep doesn't surface a
|
|
148
|
+
// sessionId on the directive object even when the fixture
|
|
149
|
+
// JSON includes one (only `type → kind` is renamed; the rest
|
|
150
|
+
// is a flat passthrough, so a `sessionId` field WOULD survive
|
|
151
|
+
// — but the canonical ServerVersionOverrideSetup type doesn't
|
|
152
|
+
// declare one, so fixtures may omit it. Falling back to
|
|
153
|
+
// `lastCreatedSessionId()` keeps the host robust to either.
|
|
154
|
+
const lastSession = serverInstance.sessions.lastCreatedSessionId();
|
|
155
|
+
if (lastSession === undefined) {
|
|
156
|
+
throw new Error('reference-server: server-version-override invoked before create-session — no session scope to bind to');
|
|
157
|
+
}
|
|
158
|
+
serverInstance.sessions.setVersionOverride(lastSession, advertise);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
// Unknown kind — extensibly-closed. Throw so the kit records
|
|
162
|
+
// SKIP with an honest reason.
|
|
163
|
+
const unknownKind = step.kind ?? 'unknown';
|
|
164
|
+
throw new Error(`reference server does not implement setup kind '${String(unknownKind)}'`);
|
|
165
|
+
},
|
|
166
|
+
async dispatchTeardown(step) {
|
|
167
|
+
if (step.kind === 'close-session') {
|
|
168
|
+
const s = step;
|
|
169
|
+
serverInstance.sessions.close(s.sessionId);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
if (step.kind === 'unregister-tool') {
|
|
173
|
+
// Same toolName/name tolerance as register-tool.
|
|
174
|
+
const raw = step;
|
|
175
|
+
const toolName = raw.toolName ?? raw.name;
|
|
176
|
+
if (typeof toolName === 'string' && toolName.length > 0) {
|
|
177
|
+
serverInstance.tools.unregister(toolName);
|
|
178
|
+
}
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
const unknownKind = step.kind ?? 'unknown';
|
|
182
|
+
throw new Error(`reference server does not implement teardown kind '${String(unknownKind)}'`);
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@ggui-ai/protocol-reference-server` — minimal reference
|
|
3
|
+
* implementation of the ggui protocol.
|
|
4
|
+
*
|
|
5
|
+
* **Role**: empirical proof of the protocol's vendor-neutral
|
|
6
|
+
* separation. If an independent, from-scratch implementation passes
|
|
7
|
+
* `@ggui-ai/protocol-conformance`, the protocol's vendor-neutrality
|
|
8
|
+
* claim is grounded — not an aspiration.
|
|
9
|
+
*
|
|
10
|
+
* **Non-goals**:
|
|
11
|
+
* - Not a production server.
|
|
12
|
+
* - Not intended for agent use.
|
|
13
|
+
* - Deliberately does NOT depend on `@ggui-ai/mcp-server*` — the
|
|
14
|
+
* whole point of this package is to prove those aren't needed.
|
|
15
|
+
*/
|
|
16
|
+
export declare const REFERENCE_SERVER_VERSION = "0.1.0";
|
|
17
|
+
export { ReferenceServer } from './server.js';
|
|
18
|
+
export type { ReferenceServerOptions } from './server.js';
|
|
19
|
+
export { createReferenceConformanceHost, type CreateReferenceConformanceHostInput, } from './conformance-host.js';
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,wBAAwB,UAAU,CAAC;AAahD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,YAAY,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EACL,8BAA8B,EAC9B,KAAK,mCAAmC,GACzC,MAAM,uBAAuB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@ggui-ai/protocol-reference-server` — minimal reference
|
|
3
|
+
* implementation of the ggui protocol.
|
|
4
|
+
*
|
|
5
|
+
* **Role**: empirical proof of the protocol's vendor-neutral
|
|
6
|
+
* separation. If an independent, from-scratch implementation passes
|
|
7
|
+
* `@ggui-ai/protocol-conformance`, the protocol's vendor-neutrality
|
|
8
|
+
* claim is grounded — not an aspiration.
|
|
9
|
+
*
|
|
10
|
+
* **Non-goals**:
|
|
11
|
+
* - Not a production server.
|
|
12
|
+
* - Not intended for agent use.
|
|
13
|
+
* - Deliberately does NOT depend on `@ggui-ai/mcp-server*` — the
|
|
14
|
+
* whole point of this package is to prove those aren't needed.
|
|
15
|
+
*/
|
|
16
|
+
export const REFERENCE_SERVER_VERSION = '0.1.0';
|
|
17
|
+
// Public surface for embedding the reference server in an external
|
|
18
|
+
// runner — used to drive the `@ggui-ai/protocol-conformance` kit
|
|
19
|
+
// through the reference WS server from inside a browser-based test
|
|
20
|
+
// harness.
|
|
21
|
+
//
|
|
22
|
+
// Embedding contract:
|
|
23
|
+
// - Caller owns lifecycle: `new ReferenceServer({port: 0}); await
|
|
24
|
+
// server.start(); … await server.stop()`.
|
|
25
|
+
// - `createReferenceConformanceHost({serverInstance})` returns the
|
|
26
|
+
// `ConformanceHost` to pass into `runConformance({host})`.
|
|
27
|
+
// - Throws on unimplemented directives — kit maps them to SKIP.
|
|
28
|
+
export { ReferenceServer } from './server.js';
|
|
29
|
+
export { createReferenceConformanceHost, } from './conformance-host.js';
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { SessionStore } from './session.js';
|
|
2
|
+
import { ToolRegistry } from './tool-registry.js';
|
|
3
|
+
export interface ReferenceServerOptions {
|
|
4
|
+
/** Port to bind. `0` = ephemeral — use {@link ReferenceServer.port}
|
|
5
|
+
* to read the resolved port after start. */
|
|
6
|
+
readonly port: number;
|
|
7
|
+
/** Host interface. Default `127.0.0.1`. */
|
|
8
|
+
readonly host?: string;
|
|
9
|
+
/**
|
|
10
|
+
* If `true` (default), reject subscribes whose `supportedVersions`
|
|
11
|
+
* does not include `PROTOCOL_SCHEMA_VERSION` by emitting
|
|
12
|
+
* `UPGRADE_REQUIRED` AND closing the underlying WebSocket. This is
|
|
13
|
+
* the default first-party posture. Set to `false` for an 'advisory'
|
|
14
|
+
* posture — the error frame is emitted but the connection stays
|
|
15
|
+
* open (used by tests that need the mismatch emission observable
|
|
16
|
+
* without closing the socket).
|
|
17
|
+
*/
|
|
18
|
+
readonly strictVersionPolicy?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Override the server-advertised protocol schema version. Defaults to
|
|
21
|
+
* `PROTOCOL_SCHEMA_VERSION` (current canonical). Used by the
|
|
22
|
+
* `server-version-override` conformance directive — a Path-A test
|
|
23
|
+
* boots a sidecar `ReferenceServer` with a deliberately mismatched
|
|
24
|
+
* version so the kit's `version-mismatch` fixture can drive the
|
|
25
|
+
* UPGRADE_REQUIRED emission entirely over WS.
|
|
26
|
+
*
|
|
27
|
+
* Discipline: this field is for conformance-test fault injection ONLY.
|
|
28
|
+
* Production-use of the reference server (none planned — see
|
|
29
|
+
* package non-goals) MUST default to canonical.
|
|
30
|
+
*/
|
|
31
|
+
readonly versionOverride?: string;
|
|
32
|
+
}
|
|
33
|
+
export declare class ReferenceServer {
|
|
34
|
+
readonly sessions: SessionStore;
|
|
35
|
+
readonly tools: ToolRegistry;
|
|
36
|
+
private readonly options;
|
|
37
|
+
private http;
|
|
38
|
+
private wss;
|
|
39
|
+
private boundPort;
|
|
40
|
+
constructor(options: ReferenceServerOptions);
|
|
41
|
+
/**
|
|
42
|
+
* Protocol schema version the server advertises in subscribe ack
|
|
43
|
+
* frames + UPGRADE_REQUIRED error frames. Defaults to
|
|
44
|
+
* `PROTOCOL_SCHEMA_VERSION`; overridable via
|
|
45
|
+
* {@link ReferenceServerOptions.versionOverride} for conformance
|
|
46
|
+
* fault injection.
|
|
47
|
+
*/
|
|
48
|
+
get advertisedVersion(): string;
|
|
49
|
+
/** Resolved port (valid after `start()` resolves). */
|
|
50
|
+
get port(): number;
|
|
51
|
+
/** Base URL for the kit's `runConformance({serverUrl})`. */
|
|
52
|
+
get baseUrl(): string;
|
|
53
|
+
start(): Promise<void>;
|
|
54
|
+
stop(): Promise<void>;
|
|
55
|
+
private handleConnection;
|
|
56
|
+
private handleMessage;
|
|
57
|
+
private handleSubscribe;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,YAAY,EAAmB,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,WAAW,sBAAsB;IACrC;iDAC6C;IAC7C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,2CAA2C;IAC3C,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;;;;OAQG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IACvC;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;CACnC;AAED,qBAAa,eAAe;IAC1B,QAAQ,CAAC,QAAQ,eAAsB;IACvC,QAAQ,CAAC,KAAK,eAAsB;IAEpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmC;IAC3D,OAAO,CAAC,IAAI,CAA2B;IACvC,OAAO,CAAC,GAAG,CAAgC;IAC3C,OAAO,CAAC,SAAS,CAAuB;gBAE5B,OAAO,EAAE,sBAAsB;IAS3C;;;;;;OAMG;IACH,IAAI,iBAAiB,IAAI,MAAM,CAE9B;IAED,sDAAsD;IACtD,IAAI,IAAI,IAAI,MAAM,CAKjB;IAED,4DAA4D;IAC5D,IAAI,OAAO,IAAI,MAAM,CAEpB;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA+BtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB3B,OAAO,CAAC,gBAAgB;YAoCV,aAAa;IAuC3B,OAAO,CAAC,eAAe;CAmExB"}
|