@volter/twin-xai 0.1.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.
Files changed (56) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +246 -0
  3. package/client/xai-device-auth.css +246 -0
  4. package/client/xai-device-auth.tsx +138 -0
  5. package/dist/client/xai-device-auth.bundle.js +18 -0
  6. package/dist/client/xai-device-auth.css +246 -0
  7. package/dist/client/xai-device-auth.d.ts +19 -0
  8. package/dist/client/xai-device-auth.js +50 -0
  9. package/dist/client/xai-device-auth.tsx +138 -0
  10. package/dist/src/cli.d.ts +2 -0
  11. package/dist/src/cli.js +28 -0
  12. package/dist/src/index.d.ts +17 -0
  13. package/dist/src/index.js +70 -0
  14. package/dist/src/xai-budget.d.ts +60 -0
  15. package/dist/src/xai-budget.js +139 -0
  16. package/dist/src/xai-capabilities.d.ts +4 -0
  17. package/dist/src/xai-capabilities.js +1072 -0
  18. package/dist/src/xai-conformance.d.ts +13 -0
  19. package/dist/src/xai-conformance.js +148 -0
  20. package/dist/src/xai-connector.d.ts +82 -0
  21. package/dist/src/xai-connector.js +174 -0
  22. package/dist/src/xai-device-auth-css.gen.d.ts +1 -0
  23. package/dist/src/xai-device-auth-css.gen.js +6 -0
  24. package/dist/src/xai-device-auth-ui.d.ts +13 -0
  25. package/dist/src/xai-device-auth-ui.js +72 -0
  26. package/dist/src/xai-models.d.ts +57 -0
  27. package/dist/src/xai-models.js +102 -0
  28. package/dist/src/xai-oauth.d.ts +30 -0
  29. package/dist/src/xai-oauth.js +279 -0
  30. package/dist/src/xai-scenario.d.ts +33 -0
  31. package/dist/src/xai-scenario.js +139 -0
  32. package/dist/src/xai-server.d.ts +36 -0
  33. package/dist/src/xai-server.js +232 -0
  34. package/dist/src/xai-stub.d.ts +69 -0
  35. package/dist/src/xai-stub.js +210 -0
  36. package/dist/src/xai-twin.d.ts +89 -0
  37. package/dist/src/xai-twin.js +883 -0
  38. package/dist/src/xai-types.d.ts +118 -0
  39. package/dist/src/xai-types.js +6 -0
  40. package/package.json +76 -0
  41. package/src/cli.ts +27 -0
  42. package/src/index.ts +120 -0
  43. package/src/xai-budget.ts +165 -0
  44. package/src/xai-capabilities.ts +1046 -0
  45. package/src/xai-conformance.ts +136 -0
  46. package/src/xai-connector.ts +212 -0
  47. package/src/xai-device-auth-css.gen.ts +6 -0
  48. package/src/xai-device-auth-ui.ts +90 -0
  49. package/src/xai-journey.uitest.ts +155 -0
  50. package/src/xai-models.ts +154 -0
  51. package/src/xai-oauth.ts +301 -0
  52. package/src/xai-scenario.ts +148 -0
  53. package/src/xai-server.ts +258 -0
  54. package/src/xai-stub.ts +213 -0
  55. package/src/xai-twin.ts +960 -0
  56. package/src/xai-types.ts +111 -0
@@ -0,0 +1,246 @@
1
+ :root {
2
+ color-scheme: light;
3
+ --xai-bg: #ffffff;
4
+ --xai-text: #0a0a0a;
5
+ --xai-muted: #777777;
6
+ --xai-faint: #fafafa;
7
+ --xai-border: #dedede;
8
+ --xai-error: #b42318;
9
+ }
10
+
11
+ * { box-sizing: border-box; }
12
+
13
+ html, body, #root { min-height: 100%; }
14
+
15
+ body {
16
+ margin: 0;
17
+ background: var(--xai-bg);
18
+ color: var(--xai-text);
19
+ font-family: Inter, ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
20
+ -webkit-font-smoothing: antialiased;
21
+ }
22
+
23
+ button, input { font: inherit; }
24
+
25
+ .account-page { min-height: 100vh; }
26
+
27
+ .account-header {
28
+ position: fixed;
29
+ inset: 0 0 auto;
30
+ z-index: 2;
31
+ display: flex;
32
+ align-items: center;
33
+ justify-content: space-between;
34
+ height: 88px;
35
+ padding: 20px 24px;
36
+ pointer-events: none;
37
+ }
38
+
39
+ .account-header > * { pointer-events: auto; }
40
+
41
+ .account-home {
42
+ display: inline-flex;
43
+ color: var(--xai-text);
44
+ text-decoration: none;
45
+ padding: 8px 0;
46
+ }
47
+
48
+ .xai-mark {
49
+ display: block;
50
+ width: 52px;
51
+ height: auto;
52
+ }
53
+
54
+ .sign-out {
55
+ display: inline-flex;
56
+ align-items: center;
57
+ text-decoration: none;
58
+ min-height: 40px;
59
+ padding: 0 18px;
60
+ border: 1px solid var(--xai-border);
61
+ border-radius: 999px;
62
+ background: var(--xai-bg);
63
+ color: var(--xai-text);
64
+ cursor: pointer;
65
+ font-size: 14px;
66
+ transition: background .15s ease, border-color .15s ease;
67
+ }
68
+
69
+ .sign-out:hover { background: #f6f6f6; border-color: #c8c8c8; }
70
+
71
+ .auth-shell {
72
+ width: min(512px, calc(100% - 40px));
73
+ margin: 0 auto;
74
+ padding: clamp(106px, 11vh, 112px) 0 72px;
75
+ }
76
+
77
+ .auth-shell-compact {
78
+ width: min(448px, calc(100% - 40px));
79
+ padding-top: clamp(240px, 35.7vh, 351px);
80
+ }
81
+
82
+ h1 {
83
+ margin: 0 0 32px;
84
+ font-size: 16px;
85
+ line-height: 1.3;
86
+ font-weight: 650;
87
+ letter-spacing: -0.015em;
88
+ }
89
+
90
+ .auth-shell-compact h1 {
91
+ margin-bottom: 16px;
92
+ font-size: 26px;
93
+ font-weight: 450;
94
+ letter-spacing: -0.035em;
95
+ }
96
+
97
+ .lead {
98
+ margin: 0 0 28px;
99
+ color: var(--xai-muted);
100
+ font-size: 17px;
101
+ line-height: 1.5;
102
+ }
103
+
104
+ .entry-form input {
105
+ width: 100%;
106
+ height: 42px;
107
+ border: 1px solid #252525;
108
+ border-radius: 0;
109
+ background: var(--xai-bg);
110
+ color: var(--xai-text);
111
+ padding: 0 16px;
112
+ text-align: center;
113
+ text-transform: uppercase;
114
+ letter-spacing: .08em;
115
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
116
+ font-size: 18px;
117
+ outline: none;
118
+ }
119
+
120
+ .entry-form input:focus { box-shadow: 0 0 0 2px #bbbbbb; }
121
+ .device-help, .form-error {
122
+ margin: 14px 0 20px;
123
+ color: var(--xai-muted);
124
+ font-size: 14px;
125
+ line-height: 1.45;
126
+ }
127
+
128
+ .form-error { margin-bottom: -7px; color: var(--xai-error); }
129
+
130
+ .primary-action, .secondary-action {
131
+ min-height: 40px;
132
+ border-radius: 999px;
133
+ padding: 0 24px;
134
+ cursor: pointer;
135
+ font-size: 16px;
136
+ transition: transform .12s ease, background .15s ease;
137
+ }
138
+
139
+ .primary-action {
140
+ border: 1px solid #050505;
141
+ background: #050505;
142
+ color: #ffffff;
143
+ }
144
+
145
+ .primary-action:hover { background: #252525; }
146
+ .primary-action:disabled,
147
+ .primary-action:disabled:hover {
148
+ background: #4b4b4b;
149
+ border-color: #4b4b4b;
150
+ cursor: default;
151
+ }
152
+ .primary-action:active, .secondary-action:active { transform: scale(.99); }
153
+ .entry-form .primary-action { width: 100%; min-height: 50px; }
154
+
155
+ .permission-list {
156
+ display: grid;
157
+ gap: 4px;
158
+ margin: 0;
159
+ padding: 0;
160
+ list-style: none;
161
+ }
162
+
163
+ .permission-list li {
164
+ display: flex;
165
+ align-items: center;
166
+ min-height: 44px;
167
+ padding: 0 16px;
168
+ border-radius: 13px;
169
+ background: var(--xai-faint);
170
+ font-size: 15px;
171
+ font-weight: 500;
172
+ }
173
+
174
+ .permission-icon {
175
+ flex: 0 0 auto;
176
+ width: 17px;
177
+ height: 17px;
178
+ margin-right: 16px;
179
+ color: #888888;
180
+ }
181
+
182
+ .decision-form {
183
+ display: grid;
184
+ grid-template-columns: 1fr 1fr;
185
+ gap: 12px;
186
+ margin-top: 32px;
187
+ }
188
+
189
+ .secondary-action {
190
+ border: 1px solid var(--xai-border);
191
+ background: var(--xai-bg);
192
+ color: var(--xai-text);
193
+ }
194
+
195
+ .secondary-action:hover { background: #f7f7f7; }
196
+
197
+ .result-icon {
198
+ display: grid;
199
+ place-items: center;
200
+ width: 48px;
201
+ height: 48px;
202
+ margin-bottom: 24px;
203
+ border-radius: 50%;
204
+ background: #f1f1f1;
205
+ font-size: 28px;
206
+ font-weight: 350;
207
+ }
208
+
209
+ .result-icon-approved { background: #050505; color: #ffffff; }
210
+ .result-copy { margin-bottom: 6px; }
211
+
212
+ .sr-only {
213
+ position: absolute;
214
+ width: 1px;
215
+ height: 1px;
216
+ padding: 0;
217
+ margin: -1px;
218
+ overflow: hidden;
219
+ clip: rect(0, 0, 0, 0);
220
+ white-space: nowrap;
221
+ border: 0;
222
+ }
223
+
224
+ button:focus-visible, a:focus-visible, input:focus-visible {
225
+ outline: 2px solid #666666;
226
+ outline-offset: 3px;
227
+ }
228
+
229
+ @media (max-width: 640px) {
230
+ .account-header { height: 76px; padding: 16px 20px; }
231
+ .sign-out { min-height: 42px; padding: 0 17px; font-size: 15px; }
232
+ .auth-shell, .auth-shell-compact {
233
+ width: min(100% - 32px, 532px);
234
+ padding-top: 126px;
235
+ }
236
+ .auth-shell h1, .auth-shell-compact h1 { font-size: 27px; margin-bottom: 18px; }
237
+ .lead { font-size: 16px; }
238
+ .permission-list li { min-height: 54px; padding: 0 14px; font-size: 15px; }
239
+ .permission-icon { margin-right: 14px; }
240
+ .decision-form { grid-template-columns: 1fr; margin-top: 28px; }
241
+ .decision-form .primary-action { grid-row: 1; }
242
+ }
243
+
244
+ @media (prefers-reduced-motion: reduce) {
245
+ * { transition: none !important; }
246
+ }
@@ -0,0 +1,19 @@
1
+ export declare const XAI_DEVICE_PERMISSIONS: readonly ["Verify your identity", "Read your profile (name, avatar)", "Read your email address", "Maintain access when you're not present", "Use the xAI API", "Read and write access Grok.com"];
2
+ export type XaiDeviceAuthView = {
3
+ userCode: string;
4
+ status: 'pending' | 'approved' | 'denied' | 'connected' | 'expired' | 'unknown';
5
+ permissions: readonly string[];
6
+ error?: string;
7
+ };
8
+ export declare function DeviceEntryPage({ view, base }: {
9
+ view: XaiDeviceAuthView;
10
+ base?: string;
11
+ }): import("react").JSX.Element;
12
+ export declare function DeviceConsentPage({ view, base }: {
13
+ view: XaiDeviceAuthView;
14
+ base?: string;
15
+ }): import("react").JSX.Element;
16
+ export declare function DeviceDonePage({ approved, base }: {
17
+ approved: boolean;
18
+ base?: string;
19
+ }): import("react").JSX.Element;
@@ -0,0 +1,50 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ export const XAI_DEVICE_PERMISSIONS = [
3
+ 'Verify your identity',
4
+ 'Read your profile (name, avatar)',
5
+ 'Read your email address',
6
+ "Maintain access when you're not present",
7
+ 'Use the xAI API',
8
+ 'Read and write access Grok.com',
9
+ ];
10
+ function XaiMark() {
11
+ return (_jsxs("svg", { className: "xai-mark", viewBox: "0 0 834 318", fill: "none", "aria-hidden": "true", children: [_jsx("path", { d: "M832.565 0.590983C736.633 8.41256 359.563 55.1598 98.1057 317.999H1.08203L11.9228 307.195C66.6371 254.336 308.741 30.3127 832.565 0.299805V0.590983Z", fill: "black" }), _jsx("path", { d: "M504.192 317.999H428.146L278.315 208.933C292.122 200.25 306.018 191.98 319.957 184.104L504.192 317.999Z", fill: "black" }), _jsx("path", { d: "M382.659 318H306.648L283.589 301.228H154.852C163.915 293.18 173.091 285.368 182.362 277.784H251.322L215.636 251.826C228.392 242.335 241.288 233.244 254.287 224.535L382.659 318Z", fill: "black" }), _jsx("path", { d: "M105.997 116.89L164.612 159.488C150.024 168.078 136.37 176.58 123.626 184.897L30.0522 116.854L105.997 116.89Z", fill: "black" })] }));
12
+ }
13
+ // `base` is where the twin is reached (`twinPublicBase`: origin plus any served-World mount path);
14
+ // every link and form action the pages emit is built from it, so they stay inside the World's
15
+ // mount. Empty for an in-process render, where the paths are the vendor's own root-relative ones.
16
+ function AccountHeader({ base, signOutReturnTo, userCode }) {
17
+ const signOutHref = signOutReturnTo
18
+ ? `${base}/sign-out?redirect=oauth2-provider&return_to=${encodeURIComponent(signOutReturnTo)}`
19
+ : `${base}/sign-out`;
20
+ return (_jsxs("header", { className: "account-header", children: [_jsx("a", { className: "account-home", href: `${base}/`, "aria-label": "SpaceXAI account home link", children: _jsx(XaiMark, {}) }), userCode ? (_jsx("a", { className: "sign-out", href: signOutHref, children: "Sign out" })) : null] }));
21
+ }
22
+ function AccountShell({ base, children, userCode, compact = false, result = false, signOutReturnTo }) {
23
+ return (_jsxs("div", { className: "account-page", children: [_jsx(AccountHeader, { base: base, userCode: userCode, signOutReturnTo: signOutReturnTo }), _jsx("main", { className: `auth-shell${compact ? ' auth-shell-compact' : ''}${result ? ' auth-shell-result' : ''}`, children: children })] }));
24
+ }
25
+ export function DeviceEntryPage({ view, base = '' }) {
26
+ const canContinue = !view.error && /^[A-Z0-9]{4}-[A-Z0-9]{4}$/u.test(view.userCode);
27
+ return (_jsxs(AccountShell, { base: base, compact: true, userCode: view.userCode || undefined, children: [_jsx("h1", { children: "Sign in to Grok Build" }), _jsx("p", { className: "lead", children: "Enter the code shown in your terminal." }), _jsxs("form", { className: "entry-form", method: "POST", action: `${base}/oauth2/device/continue`, children: [_jsx("label", { className: "sr-only", htmlFor: "device-code", children: "Enter device code" }), _jsx("input", { id: "device-code", name: "user_code", inputMode: "text", autoComplete: "one-time-code", autoCapitalize: "characters", spellCheck: false, defaultValue: view.userCode, placeholder: "Enter device code", "aria-describedby": view.error ? 'device-code-error device-code-help' : 'device-code-help' }), view.error ? _jsx("p", { id: "device-code-error", className: "form-error", role: "alert", children: view.error }) : null, _jsx("p", { id: "device-code-help", className: "device-help", children: "Only enter this code if you just initiated a sign-in from your device." }), _jsx("button", { className: "primary-action", type: "submit", disabled: !canContinue, children: "Continue" })] })] }));
28
+ }
29
+ function PermissionIcon({ index }) {
30
+ const paths = [
31
+ _jsxs(_Fragment, { children: [_jsx("circle", { cx: "12", cy: "8", r: "3" }), _jsx("path", { d: "M6.8 19c.6-3.3 2.4-5 5.2-5s4.6 1.7 5.2 5" }), _jsx("circle", { cx: "12", cy: "12", r: "9" })] }),
32
+ _jsxs(_Fragment, { children: [_jsx("circle", { cx: "12", cy: "8", r: "3" }), _jsx("path", { d: "M6.5 20v-1.2c0-3.2 2.2-5.3 5.5-5.3s5.5 2.1 5.5 5.3V20" })] }),
33
+ _jsxs(_Fragment, { children: [_jsx("rect", { x: "3.5", y: "5.5", width: "17", height: "13", rx: "1.5" }), _jsx("path", { d: "m4.5 7 7.5 6 7.5-6" })] }),
34
+ _jsxs(_Fragment, { children: [_jsx("circle", { cx: "12", cy: "12", r: "9" }), _jsx("path", { d: "M3 12h18M12 3c2.2 2.5 3.3 5.5 3.3 9S14.2 18.5 12 21c-2.2-2.5-3.3-5.5-3.3-9S9.8 5.5 12 3" })] }),
35
+ _jsx("path", { d: "m13.3 2-8 11h6l-.6 9 8-12h-6l.6-8Z" }),
36
+ _jsx("path", { d: "M4 5.5h16v11H9l-5 4v-15Z" }),
37
+ ];
38
+ return _jsx("svg", { className: "permission-icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.7", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: paths[index] });
39
+ }
40
+ export function DeviceConsentPage({ view, base = '' }) {
41
+ return (_jsxs(AccountShell, { base: base, userCode: view.userCode, signOutReturnTo: `${base}/oauth2/device/consent?user_code=${view.userCode}`, children: [_jsx("h1", { children: "Authorize Grok Build" }), _jsx("ul", { className: "permission-list", "aria-label": "Requested permissions", children: view.permissions.map((permission) => {
42
+ const index = XAI_DEVICE_PERMISSIONS.indexOf(permission);
43
+ return (_jsxs("li", { children: [_jsx(PermissionIcon, { index: index < 0 ? 0 : index }), _jsx("span", { children: permission })] }, permission));
44
+ }) }), _jsxs("form", { className: "decision-form", method: "POST", action: `${base}/oauth2/device/decision`, children: [_jsx("input", { type: "hidden", name: "user_code", value: view.userCode }), _jsx("button", { className: "secondary-action", name: "decision", value: "deny", type: "submit", children: "Deny" }), _jsx("button", { className: "primary-action", name: "decision", value: "approve", type: "submit", children: "Allow" })] })] }));
45
+ }
46
+ export function DeviceDonePage({ approved, base = '' }) {
47
+ const title = approved ? 'Device Authorized' : 'Authorization Denied';
48
+ const detail = approved ? 'Return to your terminal to continue.' : 'The Grok Build request was denied.';
49
+ return (_jsxs(AccountShell, { base: base, compact: true, result: true, children: [_jsx("div", { className: approved ? 'result-icon result-icon-approved' : 'result-icon', "aria-hidden": "true", children: approved ? '✓' : '×' }), _jsx("h1", { children: title }), _jsx("p", { className: "lead result-copy", children: detail }), _jsx("p", { className: "device-help", children: "You can close this tab." })] }));
50
+ }
@@ -0,0 +1,138 @@
1
+ // xAI's Grok Build device-authorization surface, rendered by the Twin on the vendor paths.
2
+ //
3
+ // This is the ONE renderer for the device entry, consent, and terminal screens. The server
4
+ // renders these exported components, the capability census renders these same components over
5
+ // projected OAuth state, and the browser journey drives the forms they emit. The forms are
6
+ // deliberately server-native: the authorization round trip works with JavaScript disabled.
7
+ import type { ReactNode } from 'react';
8
+
9
+ export const XAI_DEVICE_PERMISSIONS = [
10
+ 'Verify your identity',
11
+ 'Read your profile (name, avatar)',
12
+ 'Read your email address',
13
+ "Maintain access when you're not present",
14
+ 'Use the xAI API',
15
+ 'Read and write access Grok.com',
16
+ ] as const;
17
+
18
+ export type XaiDeviceAuthView = {
19
+ userCode: string;
20
+ status: 'pending' | 'approved' | 'denied' | 'connected' | 'expired' | 'unknown';
21
+ permissions: readonly string[];
22
+ error?: string;
23
+ };
24
+
25
+ function XaiMark() {
26
+ return (
27
+ <svg className="xai-mark" viewBox="0 0 834 318" fill="none" aria-hidden="true">
28
+ <path d="M832.565 0.590983C736.633 8.41256 359.563 55.1598 98.1057 317.999H1.08203L11.9228 307.195C66.6371 254.336 308.741 30.3127 832.565 0.299805V0.590983Z" fill="black" />
29
+ <path d="M504.192 317.999H428.146L278.315 208.933C292.122 200.25 306.018 191.98 319.957 184.104L504.192 317.999Z" fill="black" />
30
+ <path d="M382.659 318H306.648L283.589 301.228H154.852C163.915 293.18 173.091 285.368 182.362 277.784H251.322L215.636 251.826C228.392 242.335 241.288 233.244 254.287 224.535L382.659 318Z" fill="black" />
31
+ <path d="M105.997 116.89L164.612 159.488C150.024 168.078 136.37 176.58 123.626 184.897L30.0522 116.854L105.997 116.89Z" fill="black" />
32
+ </svg>
33
+ );
34
+ }
35
+
36
+ // `base` is where the twin is reached (`twinPublicBase`: origin plus any served-World mount path);
37
+ // every link and form action the pages emit is built from it, so they stay inside the World's
38
+ // mount. Empty for an in-process render, where the paths are the vendor's own root-relative ones.
39
+ function AccountHeader({ base, signOutReturnTo, userCode }: { base: string; signOutReturnTo?: string; userCode?: string }) {
40
+ const signOutHref = signOutReturnTo
41
+ ? `${base}/sign-out?redirect=oauth2-provider&return_to=${encodeURIComponent(signOutReturnTo)}`
42
+ : `${base}/sign-out`;
43
+ return (
44
+ <header className="account-header">
45
+ <a className="account-home" href={`${base}/`} aria-label="SpaceXAI account home link">
46
+ <XaiMark />
47
+ </a>
48
+ {userCode ? (
49
+ <a className="sign-out" href={signOutHref}>Sign out</a>
50
+ ) : null}
51
+ </header>
52
+ );
53
+ }
54
+
55
+ function AccountShell({ base, children, userCode, compact = false, result = false, signOutReturnTo }: { base: string; children: ReactNode; userCode?: string; compact?: boolean; result?: boolean; signOutReturnTo?: string }) {
56
+ return (
57
+ <div className="account-page">
58
+ <AccountHeader base={base} userCode={userCode} signOutReturnTo={signOutReturnTo} />
59
+ <main className={`auth-shell${compact ? ' auth-shell-compact' : ''}${result ? ' auth-shell-result' : ''}`}>{children}</main>
60
+ </div>
61
+ );
62
+ }
63
+
64
+ export function DeviceEntryPage({ view, base = '' }: { view: XaiDeviceAuthView; base?: string }) {
65
+ const canContinue = !view.error && /^[A-Z0-9]{4}-[A-Z0-9]{4}$/u.test(view.userCode);
66
+ return (
67
+ <AccountShell base={base} compact userCode={view.userCode || undefined}>
68
+ <h1>Sign in to Grok Build</h1>
69
+ <p className="lead">Enter the code shown in your terminal.</p>
70
+ <form className="entry-form" method="POST" action={`${base}/oauth2/device/continue`}>
71
+ <label className="sr-only" htmlFor="device-code">Enter device code</label>
72
+ <input
73
+ id="device-code"
74
+ name="user_code"
75
+ inputMode="text"
76
+ autoComplete="one-time-code"
77
+ autoCapitalize="characters"
78
+ spellCheck={false}
79
+ defaultValue={view.userCode}
80
+ placeholder="Enter device code"
81
+ aria-describedby={view.error ? 'device-code-error device-code-help' : 'device-code-help'}
82
+ />
83
+ {view.error ? <p id="device-code-error" className="form-error" role="alert">{view.error}</p> : null}
84
+ <p id="device-code-help" className="device-help">Only enter this code if you just initiated a sign-in from your device.</p>
85
+ <button className="primary-action" type="submit" disabled={!canContinue}>Continue</button>
86
+ </form>
87
+ </AccountShell>
88
+ );
89
+ }
90
+
91
+ function PermissionIcon({ index }: { index: number }) {
92
+ const paths = [
93
+ <><circle cx="12" cy="8" r="3"/><path d="M6.8 19c.6-3.3 2.4-5 5.2-5s4.6 1.7 5.2 5"/><circle cx="12" cy="12" r="9"/></>,
94
+ <><circle cx="12" cy="8" r="3"/><path d="M6.5 20v-1.2c0-3.2 2.2-5.3 5.5-5.3s5.5 2.1 5.5 5.3V20"/></>,
95
+ <><rect x="3.5" y="5.5" width="17" height="13" rx="1.5"/><path d="m4.5 7 7.5 6 7.5-6"/></>,
96
+ <><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3c2.2 2.5 3.3 5.5 3.3 9S14.2 18.5 12 21c-2.2-2.5-3.3-5.5-3.3-9S9.8 5.5 12 3"/></>,
97
+ <path d="m13.3 2-8 11h6l-.6 9 8-12h-6l.6-8Z" />,
98
+ <path d="M4 5.5h16v11H9l-5 4v-15Z" />,
99
+ ];
100
+ return <svg className="permission-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">{paths[index]}</svg>;
101
+ }
102
+
103
+ export function DeviceConsentPage({ view, base = '' }: { view: XaiDeviceAuthView; base?: string }) {
104
+ return (
105
+ <AccountShell base={base} userCode={view.userCode} signOutReturnTo={`${base}/oauth2/device/consent?user_code=${view.userCode}`}>
106
+ <h1>Authorize Grok Build</h1>
107
+ <ul className="permission-list" aria-label="Requested permissions">
108
+ {view.permissions.map((permission) => {
109
+ const index = XAI_DEVICE_PERMISSIONS.indexOf(permission as typeof XAI_DEVICE_PERMISSIONS[number]);
110
+ return (
111
+ <li key={permission}>
112
+ <PermissionIcon index={index < 0 ? 0 : index} />
113
+ <span>{permission}</span>
114
+ </li>
115
+ );
116
+ })}
117
+ </ul>
118
+ <form className="decision-form" method="POST" action={`${base}/oauth2/device/decision`}>
119
+ <input type="hidden" name="user_code" value={view.userCode} />
120
+ <button className="secondary-action" name="decision" value="deny" type="submit">Deny</button>
121
+ <button className="primary-action" name="decision" value="approve" type="submit">Allow</button>
122
+ </form>
123
+ </AccountShell>
124
+ );
125
+ }
126
+
127
+ export function DeviceDonePage({ approved, base = '' }: { approved: boolean; base?: string }) {
128
+ const title = approved ? 'Device Authorized' : 'Authorization Denied';
129
+ const detail = approved ? 'Return to your terminal to continue.' : 'The Grok Build request was denied.';
130
+ return (
131
+ <AccountShell base={base} compact result>
132
+ <div className={approved ? 'result-icon result-icon-approved' : 'result-icon'} aria-hidden="true">{approved ? '✓' : '×'}</div>
133
+ <h1>{title}</h1>
134
+ <p className="lead result-copy">{detail}</p>
135
+ <p className="device-help">You can close this tab.</p>
136
+ </AccountShell>
137
+ );
138
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env node
2
+ import { keepProcessAlive } from '@volter/world-core/lifecycle';
3
+ // world-xai CLI: serve the xAI/Grok API, OAuth protocol UI, or run conformance. `mirror` is an
4
+ // alias for the SAME server because entry and consent are the vendor-owned browser leg of OAuth;
5
+ // denial and completion are explicitly Twin-local terminal states, not a second dashboard.
6
+ import { hasFlag, optionValue } from '@volter/world-core/args';
7
+ import { createXaiTwinServer } from "./xai-server.js";
8
+ const [cmd, ...rest] = process.argv.slice(2);
9
+ const port = Number(optionValue(rest, '--port', '0')) || undefined;
10
+ const root = optionValue(rest, '--root') || undefined;
11
+ const readOnly = hasFlag(rest, '--read-only'); // a twin accepts writes unless started read-only
12
+ const scenario = optionValue(rest, '--scenario') || undefined; // scripted completions (JSON scenario file)
13
+ if (cmd === 'serve' || cmd === 'mirror') {
14
+ const s = await createXaiTwinServer({ readOnly, ...(root ? { root } : {}), ...(port ? { port } : {}), ...(scenario ? { scenarioPath: scenario } : {}) });
15
+ process.stdout.write(`xai twin (chat/completions/messages output is a deterministic stub)${readOnly ? ' [read-only]' : ''}${scenario ? ` [scenario: ${scenario}]` : ''} at http://127.0.0.1:${s.port}\n`);
16
+ await keepProcessAlive();
17
+ }
18
+ else if (cmd === 'conformance') {
19
+ // dev-only; lazy so the bin runs without @volter/world-tooling
20
+ const { checkXaiConformance } = await import("./xai-conformance.js");
21
+ const report = await checkXaiConformance({ ...(root ? { root } : {}) });
22
+ process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
23
+ if (!report.ok)
24
+ process.exitCode = 1;
25
+ }
26
+ else {
27
+ process.stdout.write('Usage: world-xai serve|mirror|conformance [--port N] [--root DIR] [--read-only] [--scenario FILE]\n');
28
+ }
@@ -0,0 +1,17 @@
1
+ export { handleXaiTwinRequest, streamChat, buildChatCompletion } from './xai-twin.js';
2
+ export type { XaiRequest, XaiResponseEnvelope } from './xai-twin.js';
3
+ export { createXaiTwinFetch, createXaiTwinServer, type XaiTwinFetchOptions } from './xai-server.js';
4
+ export { deviceConsentPageHtml, deviceDonePageHtml, deviceEntryPageHtml, xaiDeviceAuthView, XAI_DEVICE_STYLE_PATH, } from './xai-device-auth-ui.js';
5
+ export { XAI_MODELS, XAI_LANGUAGE_MODELS, XAI_IMAGE_GENERATION_MODELS, findModel, findLanguageModel, findImageGenerationModel, modelBehavior, canonicalModelId, } from './xai-models.js';
6
+ export type { XaiModel, XaiLanguageModel, XaiImageGenerationModel, XaiModelBehavior } from './xai-models.js';
7
+ export { contentToText, countPromptTokens, countPromptTokenDetails, estimateTokens, lastUserText, pseudoTokenize, stubAssistantText, stubCitations, stubJsonObject, stubReasoningText, stubToolArguments, stubToolCall, uuidFromSeed, } from './xai-stub.js';
8
+ export type { XaiToken } from './xai-stub.js';
9
+ export type { ChatMessageParam, ChatToolCall, ChatCompletion, ChatChoice, ChatUsage, TextCompletion, MessagesResponse, MessagesContentBlock, XaiError, SseEvent, SseSink, } from './xai-types.js';
10
+ export { createXaiScenarioEngine, loadXaiScenarioDocument, realizeXaiRespond, xaiScenarioAdapter } from './xai-scenario.js';
11
+ export type { ScenarioToolCall, ScriptedResult, XaiScenarioEngine, XaiScenarioRequest, XaiScenarioRespond } from './xai-scenario.js';
12
+ export { XAI_BUDGET_CEILING, XAI_BUDGET_MAX_RETRY_AFTER_S, XAI_BUDGET_WINDOW_MS, XAI_CALL_WEIGHTS, XAI_RATE_BUDGET, XaiBudget, XaiBudgetError, xaiBudgetPath, xaiCallWeight, splitXaiPath, } from './xai-budget.js';
13
+ export type { XaiBudgetErrorKind, XaiBudgetOptions, XaiBudgetReservation, XaiBudgetSnapshot, } from './xai-budget.js';
14
+ export { XAI_API_BASE, liveXaiExecute, mapModel, mapLanguageModel, pullXaiModels, syncXaiFromReal, pushXaiAction, } from './xai-connector.js';
15
+ export type { XaiExecute, LiveXaiOptions } from './xai-connector.js';
16
+ import { type TwinPack } from '@volter/world-core';
17
+ export declare const pack: TwinPack;
@@ -0,0 +1,70 @@
1
+ // @volter/twin-xai — the xAI (Grok) twin (one vendor, one package), built on the shared
2
+ // @volter/world-core kernel. The xAI API: an OpenAI-chat-compatible protocol envelope with xAI's
3
+ // deltas modeled explicitly — the grok-4-family model catalogs (/v1/models,
4
+ // /v1/language-models, /v1/image-generation-models), the flat {code, error} error envelope,
5
+ // deferred completions (stateful, kernel-backed), Live Search parameters + citations,
6
+ // reasoning_content/reasoning-token accounting, the Anthropic-compatible /v1/messages
7
+ // endpoint, legacy /v1/completions, api-key introspection, tokenize-text, the vendor-owned Grok
8
+ // Build device-entry/consent UI, and explicitly Twin-local terminal result states. The xAI console
9
+ // itself remains outside this API-first pack.
10
+ //
11
+ // THE DETERMINISTIC STUBS ARE THE ANSWER: every inference endpoint returns a clearly-labeled
12
+ // STUB completion, and Live Search returns deterministic labeled citations. Everything around
13
+ // them — the wire protocol — is faithful. (Conformance + capability tooling live in @volter/world-tooling, a dev
14
+ // dependency — NOT re-exported here, per E2.)
15
+ export { handleXaiTwinRequest, streamChat, buildChatCompletion } from "./xai-twin.js";
16
+ export { createXaiTwinFetch, createXaiTwinServer } from "./xai-server.js";
17
+ export { deviceConsentPageHtml, deviceDonePageHtml, deviceEntryPageHtml, xaiDeviceAuthView, XAI_DEVICE_STYLE_PATH, } from "./xai-device-auth-ui.js";
18
+ export { XAI_MODELS, XAI_LANGUAGE_MODELS, XAI_IMAGE_GENERATION_MODELS, findModel, findLanguageModel, findImageGenerationModel, modelBehavior, canonicalModelId, } from "./xai-models.js";
19
+ export { contentToText, countPromptTokens, countPromptTokenDetails, estimateTokens, lastUserText, pseudoTokenize, stubAssistantText, stubCitations, stubJsonObject, stubReasoningText, stubToolArguments, stubToolCall, uuidFromSeed, } from "./xai-stub.js";
20
+ export { createXaiScenarioEngine, loadXaiScenarioDocument, realizeXaiRespond, xaiScenarioAdapter } from "./xai-scenario.js";
21
+ export { XAI_BUDGET_CEILING, XAI_BUDGET_MAX_RETRY_AFTER_S, XAI_BUDGET_WINDOW_MS, XAI_CALL_WEIGHTS, XAI_RATE_BUDGET, XaiBudget, XaiBudgetError, xaiBudgetPath, xaiCallWeight, splitXaiPath, } from "./xai-budget.js";
22
+ export { XAI_API_BASE, liveXaiExecute, mapModel, mapLanguageModel, pullXaiModels, syncXaiFromReal, pushXaiAction, } from "./xai-connector.js";
23
+ // Registry descriptor: the pack self-describes so tooling can discover it.
24
+ import { registerPack } from '@volter/world-core';
25
+ import { XAI_RATE_BUDGET as RATE_BUDGET } from "./xai-budget.js";
26
+ import { performXaiAction, syncXaiFromRemote } from "./xai-connector.js";
27
+ export const pack = {
28
+ // PROTOCOL 2 (docs/contributing/architecture.md#protocol-2-the-pack-is-a-plugin): the pack is a plugin — its wire, its tree, and its half of the real
29
+ // state system. Moved 2026-09-08. The xAI API has NO client-writable resource, so `perform` settles every
30
+ // entry with that reason and only `refresh` reads; the pack's executor is GET-only by type to say so.
31
+ protocol: '2',
32
+ refresh: { every: '30m', onDemand: { atMost: '60s' } }, // a model catalogue moves slowly
33
+ stateSystem: { perform: performXaiAction, refresh: syncXaiFromRemote },
34
+ // the round trip: a DEFERRED completion — a plain completion is answered and forgotten, but xAI's
35
+ // deferred mode persists the request so a caller can poll it, which is the row this twin keeps
36
+ roundTrip: { method: 'POST', path: '/v1/chat/completions', body: { model: 'grok-4-latest', deferred: true, messages: [{ role: 'user', content: 'round trip' }] }, headers: { authorization: 'Bearer round-trip' } },
37
+ parityOrigin: 'http://twin',
38
+ vendor: 'xai',
39
+ // The client-side rate budget, armed by `registerPack` as well as by importing the budget module.
40
+ rateBudget: RATE_BUDGET,
41
+ transport: 'rest',
42
+ archetype: 'generative',
43
+ bin: 'world-xai',
44
+ // R2 adopted-as-debt, legibly: declared types no replay can create, each with its reason.
45
+ resourcesUnreachable: {
46
+ 'language_model': 'the vendor catalog',
47
+ 'model': 'the vendor catalog',
48
+ },
49
+ resources: ['deferred_completion', 'language_model', 'model', 'oauth_account', 'oauth_device_authorization', 'oauth_usage'],
50
+ specSource: 'xAI (Grok) REST API + Grok Build OAuth/device and chat-proxy protocols (envelope-faithful; model output is a deterministic stub, Live Search citations are deterministic labeled stubs)',
51
+ description: 'xAI (Grok) twin — coherent virtual account/device OAuth/refresh/usage plus the Grok CLI proxy and OpenAI-chat-compatible API envelope; generative output is a labeled stub.',
52
+ // Adoption + interception, moved off the central maps unchanged (descriptor-first back-migration, adding-a-twin.md §3,
53
+ // 2026-08-31). Both credential-env spellings the vendor and its users write —
54
+ // XAI_* and GROK_*.
55
+ adoption: {
56
+ // xAI's official Python SDK (xai-org/xai-sdk-python). An `openai` client pointed at api.x.ai is NOT
57
+ // claimed here: that distribution is the openai pack's and XAI_API_BASE is what routes it.
58
+ pypi: ['xai-sdk'],
59
+ sdks: ['@ai-sdk/xai'], envStems: ['XAI', 'GROK'],
60
+ },
61
+ // Inference lives on https://api.x.ai — the pack's connector pins XAI_API_BASE =
62
+ // 'https://api.x.ai' (xai-connector.ts). management-api.x.ai is a separate console/
63
+ // administration product the pack deliberately does NOT twin (README §Management API) — left
64
+ // unclaimed so strict egress fails closed rather than letting a half-modeled flow through.
65
+ hosts: [{ host: 'api.x.ai' }],
66
+ // The SDK calls the same-origin '/v1/…' and loads from api.x.ai — the dev proxy forwards
67
+ // '/v1/' to the twin and strips the absolute host so calls come back same-origin.
68
+ browserRouting: { apiPathPrefix: '/v1/', loaderHost: 'https://api.x.ai' },
69
+ };
70
+ registerPack(pack);
@@ -0,0 +1,60 @@
1
+ import { RateBudget, type RateBudgetDeclaration, type RateBudgetOptions, type RateBudgetReservation, type RateBudgetSnapshot } from '@volter/world-core';
2
+ /** Rolling window, in ms. The fallback's, because xAI publishes no per-minute figure to match. */
3
+ export declare const XAI_BUDGET_WINDOW_MS = 60000;
4
+ /**
5
+ * Weighted units allowed inside one window. 60/60s at the default weight of 2 = 30 calls a minute —
6
+ * the kernel's austere fallback exactly, adopted deliberately because xAI publishes no scalar limit.
7
+ */
8
+ export declare const XAI_BUDGET_CEILING = 60;
9
+ /** Seconds. A `Retry-After` above this means the key is throttled hard — fail loudly, don't sleep. */
10
+ export declare const XAI_BUDGET_MAX_RETRY_AFTER_S = 300;
11
+ /**
12
+ * Per-call cost. FLAT by design — see the header: the execute is GET-only over read-only catalogs,
13
+ * so no reachable endpoint is credibly dearer than another, and inventing a ratio would be a
14
+ * fabricated vendor fact. `other` is the only weight, and it is never zero.
15
+ */
16
+ export declare const XAI_CALL_WEIGHTS: {
17
+ /** Every call. xAI publishes no per-endpoint cost, and this execute reaches only catalog reads. */
18
+ readonly other: 2;
19
+ };
20
+ /**
21
+ * THE PACK'S DECLARATION — pure data, the only xAI-specific thing in the whole budget.
22
+ *
23
+ * `rules` is EMPTY on purpose (see the header). Also exported as `pack.rateBudget` (see index.ts),
24
+ * so `registerPack` arms it too.
25
+ */
26
+ export declare const XAI_RATE_BUDGET: RateBudgetDeclaration;
27
+ /** Split a connector path (which may carry its own query string) into pathname + parsed query. */
28
+ export declare function splitXaiPath(path: string): {
29
+ pathname: string;
30
+ query: Record<string, string>;
31
+ };
32
+ /**
33
+ * Price one call. Keyed off the request the connector is ABOUT to make. With no rules declared every
34
+ * call takes `defaultWeight` — which is the point: an unclassified endpoint must never be free.
35
+ */
36
+ export declare function xaiCallWeight(method: string, path: string): number;
37
+ /** Where xAI's ledger lives. API-key-keyed and cwd-independent by default (the limit, whatever it
38
+ * is, is per key, so a cwd-scoped ledger would hand the same key a fresh allowance in every
39
+ * checkout, worktree and CI matrix leg); pass `root` to opt into world-scoped accounting instead. */
40
+ export declare function xaiBudgetPath(opts?: {
41
+ root?: string;
42
+ token?: string;
43
+ } | string): string;
44
+ /** Construction options for xAI's budget. The vendor is fixed; everything else may only TIGHTEN. */
45
+ export type XaiBudgetOptions = Omit<RateBudgetOptions, 'vendor'>;
46
+ /**
47
+ * xAI's budget — the shared kernel guard bound to this vendor's declaration. A real subclass, not an
48
+ * alias, so the guard check in `liveXaiExecute` still means "a budget that accounts against XAI's
49
+ * ledger under XAI's ceiling": another vendor's `RateBudget` (with its own, possibly larger,
50
+ * ceiling) is NOT assignable there.
51
+ */
52
+ export declare class XaiBudget extends RateBudget {
53
+ constructor(opts?: XaiBudgetOptions);
54
+ }
55
+ /** The typed refusal. One error class shared with every other vendor's budget; `err.vendor` says
56
+ * which one refused, and `err.kind` says why. */
57
+ export { RateBudgetError as XaiBudgetError } from '@volter/world-core';
58
+ export type { RateBudgetErrorKind as XaiBudgetErrorKind } from '@volter/world-core';
59
+ export type XaiBudgetReservation = RateBudgetReservation;
60
+ export type XaiBudgetSnapshot = RateBudgetSnapshot;