relmio 0.3.1 → 0.4.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/CHANGELOG.md +32 -0
- package/README.md +67 -10
- package/docs/architecture.md +57 -0
- package/docs/local-endpoints-spec.md +370 -0
- package/docs/local-endpoints.md +374 -0
- package/docs/npm-publish.md +121 -201
- package/docs/security.md +92 -3
- package/package.json +2 -2
- package/src/domain/local-endpoints.js +460 -0
- package/src/gateway/openai.js +834 -0
- package/src/infrastructure/local-process.js +375 -0
- package/src/services/codex-login.js +711 -0
- package/src/services/local-installer.js +1120 -0
- package/src/ui/app.js +4 -0
- package/src/ui/index.html +13 -0
- package/src/ui/local.css +262 -0
- package/src/ui/local.html +442 -0
- package/src/ui/local.js +550 -0
- package/src/web/server.js +247 -12
package/src/ui/app.js
CHANGED
|
@@ -13,6 +13,10 @@ const state = {
|
|
|
13
13
|
};
|
|
14
14
|
|
|
15
15
|
const element = (id) => document.getElementById(id);
|
|
16
|
+
const localEndpointLink = element("local-endpoint-link");
|
|
17
|
+
if (token) {
|
|
18
|
+
localEndpointLink.href = `/local?session=${encodeURIComponent(token)}`;
|
|
19
|
+
}
|
|
16
20
|
const messageToast = element("global-message");
|
|
17
21
|
const message = element("global-message-text");
|
|
18
22
|
const errorBox = element("global-error");
|
package/src/ui/index.html
CHANGED
|
@@ -177,6 +177,19 @@
|
|
|
177
177
|
</div>
|
|
178
178
|
</div>
|
|
179
179
|
|
|
180
|
+
<aside class="final-note" aria-labelledby="local-endpoint-title">
|
|
181
|
+
<h3 id="local-endpoint-title">Need an endpoint on this computer?</h3>
|
|
182
|
+
<p>
|
|
183
|
+
Install a loopback-only OpenAI API endpoint with a Platform key, or
|
|
184
|
+
the experimental official Codex App Server with ChatGPT sign-in.
|
|
185
|
+
</p>
|
|
186
|
+
<div class="actions">
|
|
187
|
+
<a id="local-endpoint-link" class="button secondary">
|
|
188
|
+
Set up a local endpoint
|
|
189
|
+
</a>
|
|
190
|
+
</div>
|
|
191
|
+
</aside>
|
|
192
|
+
|
|
180
193
|
<div class="actions">
|
|
181
194
|
<button id="login-button" class="button secondary" type="button">
|
|
182
195
|
Sign in with ChatGPT
|
package/src/ui/local.css
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
.local-wizard .shell {
|
|
2
|
+
width: min(100% - 2.5rem, 78rem);
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.local-wizard .panel {
|
|
6
|
+
scroll-behavior: smooth;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.local-wizard .status-row {
|
|
10
|
+
margin-bottom: 1rem;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.local-wizard .safety-note {
|
|
14
|
+
grid-template-columns: 1.75rem minmax(0, 1fr);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.local-wizard .safety-note > span {
|
|
18
|
+
grid-column: 2;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.target-picker {
|
|
22
|
+
display: grid;
|
|
23
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
24
|
+
gap: 0.75rem;
|
|
25
|
+
min-width: 0;
|
|
26
|
+
margin: 0 0 1rem;
|
|
27
|
+
padding: 0;
|
|
28
|
+
border: 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.target-picker legend {
|
|
32
|
+
width: 100%;
|
|
33
|
+
margin-bottom: 0.5rem;
|
|
34
|
+
font-weight: 800;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.target-card {
|
|
38
|
+
position: relative;
|
|
39
|
+
display: grid;
|
|
40
|
+
grid-template-columns: 1.25rem minmax(0, 1fr);
|
|
41
|
+
gap: 0.75rem;
|
|
42
|
+
min-width: 0;
|
|
43
|
+
padding: 1rem;
|
|
44
|
+
border: 1px solid var(--border-strong);
|
|
45
|
+
border-radius: var(--radius);
|
|
46
|
+
background: var(--surface-muted);
|
|
47
|
+
cursor: pointer;
|
|
48
|
+
transition:
|
|
49
|
+
border-color 180ms var(--ease),
|
|
50
|
+
background 180ms var(--ease),
|
|
51
|
+
box-shadow 180ms var(--ease),
|
|
52
|
+
transform 180ms var(--ease);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.target-card:hover {
|
|
56
|
+
border-color: var(--accent);
|
|
57
|
+
transform: translateY(-1px);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.target-card:has(input:checked) {
|
|
61
|
+
border-color: var(--accent);
|
|
62
|
+
background: var(--accent-soft);
|
|
63
|
+
box-shadow: 0 0 0 3px rgb(19 124 116 / 12%);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.target-card:has(input:focus-visible) {
|
|
67
|
+
outline: 3px solid #f2a94a;
|
|
68
|
+
outline-offset: 2px;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.target-card input {
|
|
72
|
+
width: 1.125rem;
|
|
73
|
+
height: 1.125rem;
|
|
74
|
+
margin: 0.2rem 0 0;
|
|
75
|
+
accent-color: var(--accent);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.target-card-copy {
|
|
79
|
+
display: grid;
|
|
80
|
+
gap: 0.35rem;
|
|
81
|
+
color: var(--text-muted);
|
|
82
|
+
font-size: 0.875rem;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.target-card-copy strong {
|
|
86
|
+
color: var(--text);
|
|
87
|
+
font-size: 1rem;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.target-card-copy .target-meta {
|
|
91
|
+
color: var(--accent-deep);
|
|
92
|
+
font-size: 0.75rem;
|
|
93
|
+
font-weight: 800;
|
|
94
|
+
letter-spacing: 0.02em;
|
|
95
|
+
text-transform: uppercase;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.warning-card:has(input:checked) {
|
|
99
|
+
border-color: var(--warning-border);
|
|
100
|
+
background: var(--warning-soft);
|
|
101
|
+
box-shadow: 0 0 0 3px color-mix(in srgb, var(--warning) 13%, transparent);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.warning-card .target-meta {
|
|
105
|
+
color: var(--warning);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.local-fields {
|
|
109
|
+
grid-template-columns: minmax(8rem, 0.55fr) minmax(0, 1.45fr);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.field textarea {
|
|
113
|
+
width: 100%;
|
|
114
|
+
min-height: 5.75rem;
|
|
115
|
+
padding: 0.625rem 0.875rem;
|
|
116
|
+
resize: vertical;
|
|
117
|
+
border: 1px solid var(--border-strong);
|
|
118
|
+
border-radius: var(--radius-sm);
|
|
119
|
+
color: var(--text);
|
|
120
|
+
background: var(--surface);
|
|
121
|
+
font: 0.875rem/1.5 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
122
|
+
transition:
|
|
123
|
+
border-color 200ms var(--ease),
|
|
124
|
+
box-shadow 200ms var(--ease);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.field textarea:hover {
|
|
128
|
+
border-color: var(--accent);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.field textarea:focus {
|
|
132
|
+
border-color: var(--accent);
|
|
133
|
+
outline: 0;
|
|
134
|
+
box-shadow: 0 0 0 4px rgb(19 124 116 / 13%);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.policy-note,
|
|
138
|
+
.high-trust-warning,
|
|
139
|
+
.one-time-note,
|
|
140
|
+
.codex-login {
|
|
141
|
+
margin-top: 1rem;
|
|
142
|
+
padding: 0.875rem 1rem;
|
|
143
|
+
border: 1px solid var(--accent-border);
|
|
144
|
+
border-radius: var(--radius);
|
|
145
|
+
background: var(--accent-soft);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.policy-note p,
|
|
149
|
+
.high-trust-warning p,
|
|
150
|
+
.one-time-note p,
|
|
151
|
+
.codex-login p {
|
|
152
|
+
margin: 0.35rem 0 0;
|
|
153
|
+
color: var(--text-muted);
|
|
154
|
+
font-size: 0.875rem;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.high-trust-warning {
|
|
158
|
+
border-color: var(--warning-border);
|
|
159
|
+
background: var(--warning-soft);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.high-trust-warning strong,
|
|
163
|
+
.high-trust-warning p {
|
|
164
|
+
color: var(--warning);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.one-time-note {
|
|
168
|
+
margin: 0 0 1rem;
|
|
169
|
+
border-color: var(--warning-border);
|
|
170
|
+
background: var(--warning-soft);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.one-time-note strong,
|
|
174
|
+
.one-time-note p {
|
|
175
|
+
color: var(--warning);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.local-review-grid {
|
|
179
|
+
margin-top: 1rem;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.review-details dd {
|
|
183
|
+
overflow-wrap: anywhere;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.review-details div {
|
|
187
|
+
grid-template-columns: 9.5rem minmax(0, 1fr);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.codex-login {
|
|
191
|
+
border-color: var(--warning-border);
|
|
192
|
+
background: var(--warning-soft);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.codex-login h3 {
|
|
196
|
+
margin-bottom: 0;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.codex-login > .button {
|
|
200
|
+
margin-top: 0.875rem;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.device-code-result {
|
|
204
|
+
margin-top: 1rem;
|
|
205
|
+
padding-top: 1rem;
|
|
206
|
+
border-top: 1px solid var(--warning-border);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.device-code-row {
|
|
210
|
+
display: flex;
|
|
211
|
+
flex-wrap: wrap;
|
|
212
|
+
align-items: center;
|
|
213
|
+
gap: 0.625rem;
|
|
214
|
+
margin: 0.75rem 0;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.device-code-row code {
|
|
218
|
+
padding: 0.65rem 0.875rem;
|
|
219
|
+
border: 1px solid var(--warning-border);
|
|
220
|
+
background: var(--surface);
|
|
221
|
+
font-size: 1.125rem;
|
|
222
|
+
font-weight: 800;
|
|
223
|
+
letter-spacing: 0.08em;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.device-code-status {
|
|
227
|
+
font-weight: 700;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.local-wizard a.button {
|
|
231
|
+
text-decoration: none;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
@media (max-width: 60rem),
|
|
235
|
+
(min-width: 961px) and (max-height: 768px) {
|
|
236
|
+
.local-wizard .steps ol {
|
|
237
|
+
grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
@media (max-width: 48rem) {
|
|
242
|
+
.target-picker,
|
|
243
|
+
.local-fields,
|
|
244
|
+
.local-review-grid {
|
|
245
|
+
grid-template-columns: minmax(0, 1fr);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.review-details div {
|
|
249
|
+
grid-template-columns: minmax(0, 1fr);
|
|
250
|
+
gap: 0.2rem;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
@media (prefers-reduced-motion: reduce) {
|
|
255
|
+
.local-wizard *,
|
|
256
|
+
.local-wizard *::before,
|
|
257
|
+
.local-wizard *::after {
|
|
258
|
+
scroll-behavior: auto !important;
|
|
259
|
+
transition-duration: 0.01ms !important;
|
|
260
|
+
animation-duration: 0.01ms !important;
|
|
261
|
+
}
|
|
262
|
+
}
|