relmio 0.2.0 → 0.2.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/CHANGELOG.md +42 -9
- package/LICENSE +201 -21
- package/NOTICE +11 -0
- package/README.md +65 -17
- package/docs/npm-publish.md +1 -1
- package/package.json +8 -7
- package/src/ui/app.js +21 -3
- package/src/ui/styles.css +368 -74
package/CHANGELOG.md
CHANGED
|
@@ -7,7 +7,40 @@ checks the registry separately after publication.
|
|
|
7
7
|
|
|
8
8
|
## Unreleased
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
## [0.2.1] - 2026-07-30
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Add the hosted ChatGPT site link to the package metadata and public guides.
|
|
15
|
+
- Document the upstream Codex relay model, known limitations, and legal
|
|
16
|
+
responsibilities in both the GitHub and npm README variants.
|
|
17
|
+
- Add a command-first install page for the current n8n and Hostinger VPS
|
|
18
|
+
wizard, plus a GitHub control with live package and repository metadata.
|
|
19
|
+
- Credit Evan Zhou Dev's `openai-oauth` method on the hosted Relmio page.
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- Refresh the local setup wizard and hosted chat presentation with the Relmio
|
|
24
|
+
redesign, including clearer progress, copy feedback, responsive layouts, and
|
|
25
|
+
request-state affordances.
|
|
26
|
+
- Move the hosted chat and package homepage to
|
|
27
|
+
[relmio.vercel.app](https://relmio.vercel.app/) with Node.js 22 and
|
|
28
|
+
repository-driven preview and production deployments.
|
|
29
|
+
- Return ChatGPT OAuth callbacks to the deployment that started sign-in so
|
|
30
|
+
Vercel preview URLs and the production domain both work.
|
|
31
|
+
- Run hosted web linting, type checks, builds, tests, and dependency auditing
|
|
32
|
+
in GitHub Actions alongside repository-driven deployments.
|
|
33
|
+
- Point package and documentation metadata at the canonical `relmio`
|
|
34
|
+
repository.
|
|
35
|
+
- License Relmio under Apache 2.0 and preserve the upstream `openai-oauth`
|
|
36
|
+
attribution in the distributed notice.
|
|
37
|
+
|
|
38
|
+
### Fixed
|
|
39
|
+
|
|
40
|
+
- Stream hosted chat responses incrementally through deployment proxies and
|
|
41
|
+
surface safe request errors instead of leaving an empty assistant message.
|
|
42
|
+
- Distinguish a ChatGPT hosting-network challenge from an expired OAuth
|
|
43
|
+
session without exposing upstream response bodies or credentials.
|
|
11
44
|
|
|
12
45
|
## [0.2.0] - 2026-07-29
|
|
13
46
|
|
|
@@ -180,11 +213,11 @@ No unreleased changes.
|
|
|
180
213
|
- The sidecar uses an internal-only Docker network endpoint and no published
|
|
181
214
|
VPS port.
|
|
182
215
|
|
|
183
|
-
[0.1.7]: https://github.com/Demonbane18/
|
|
184
|
-
[0.1.6]: https://github.com/Demonbane18/
|
|
185
|
-
[0.1.5]: https://github.com/Demonbane18/
|
|
186
|
-
[0.1.4]: https://github.com/Demonbane18/
|
|
187
|
-
[0.1.3]: https://github.com/Demonbane18/
|
|
188
|
-
[0.1.2]: https://github.com/Demonbane18/
|
|
189
|
-
[0.1.1]: https://github.com/Demonbane18/
|
|
190
|
-
[0.1.0]: https://github.com/Demonbane18/
|
|
216
|
+
[0.1.7]: https://github.com/Demonbane18/relmio/compare/v0.1.6...v0.1.7
|
|
217
|
+
[0.1.6]: https://github.com/Demonbane18/relmio/compare/v0.1.5...v0.1.6
|
|
218
|
+
[0.1.5]: https://github.com/Demonbane18/relmio/compare/v0.1.4...v0.1.5
|
|
219
|
+
[0.1.4]: https://github.com/Demonbane18/relmio/compare/v0.1.3...v0.1.4
|
|
220
|
+
[0.1.3]: https://github.com/Demonbane18/relmio/compare/v0.1.2...v0.1.3
|
|
221
|
+
[0.1.2]: https://github.com/Demonbane18/relmio/compare/v0.1.1...v0.1.2
|
|
222
|
+
[0.1.1]: https://github.com/Demonbane18/relmio/compare/v0.1.0...v0.1.1
|
|
223
|
+
[0.1.0]: https://github.com/Demonbane18/relmio/releases/tag/v0.1.0
|
package/LICENSE
CHANGED
|
@@ -1,21 +1,201 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
179
|
+
|
|
180
|
+
To apply the Apache License to your work, attach the following
|
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
182
|
+
replaced with your own identifying information. (Don't include
|
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
+
comment syntax for the file format. We also recommend that a
|
|
185
|
+
file or class name and description of purpose be included on the
|
|
186
|
+
same "printed page" as the copyright notice for easier
|
|
187
|
+
identification within third-party archives.
|
|
188
|
+
|
|
189
|
+
Copyright 2026 Relmio contributors
|
|
190
|
+
|
|
191
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
+
you may not use this file except in compliance with the License.
|
|
193
|
+
You may obtain a copy of the License at
|
|
194
|
+
|
|
195
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
196
|
+
|
|
197
|
+
Unless required by applicable law or agreed to in writing, software
|
|
198
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
200
|
+
See the License for the specific language governing permissions and
|
|
201
|
+
limitations under the License.
|
package/NOTICE
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Relmio
|
|
2
|
+
Copyright 2026 Relmio contributors
|
|
3
|
+
|
|
4
|
+
Relmio uses software and methods developed by Evan Zhou and the OpenAI OAuth
|
|
5
|
+
contributors:
|
|
6
|
+
|
|
7
|
+
OpenAI OAuth
|
|
8
|
+
Copyright 2026 Evan Zhou and OpenAI OAuth contributors
|
|
9
|
+
https://github.com/EvanZhouDev/openai-oauth
|
|
10
|
+
|
|
11
|
+
OpenAI OAuth is licensed under the Apache License, Version 2.0.
|
package/README.md
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
<div align="center">
|
|
2
|
-
<img src="https://
|
|
2
|
+
<img src="https://cdn.jsdelivr.net/npm/relmio@latest/docs/images/brand/relmio-mark.svg" alt="Relmio logo" width="88">
|
|
3
3
|
<h1>Relmio</h1>
|
|
4
4
|
<p>Relay a supported ChatGPT/Codex sign-in to OpenAI-compatible clients, starting with self-hosted n8n.</p>
|
|
5
5
|
<p>
|
|
6
|
-
<a href="https://github.com/Demonbane18/
|
|
6
|
+
<a href="https://github.com/Demonbane18/relmio">Full guide</a>
|
|
7
7
|
·
|
|
8
|
-
<a href="https://
|
|
8
|
+
<a href="https://relmio.vercel.app/">Hosted ChatGPT site</a>
|
|
9
9
|
·
|
|
10
|
-
<a href="https://github.com/Demonbane18/
|
|
10
|
+
<a href="https://github.com/Demonbane18/relmio/issues/new">Report an issue</a>
|
|
11
|
+
·
|
|
12
|
+
<a href="https://github.com/Demonbane18/relmio/blob/main/docs/roadmap.md">Roadmap</a>
|
|
11
13
|
</p>
|
|
12
14
|
</div>
|
|
13
15
|
|
|
@@ -19,6 +21,15 @@ exact change plan, and the final n8n credential settings.
|
|
|
19
21
|
|
|
20
22
|
The existing n8n image, Compose file, container, and workflows stay untouched.
|
|
21
23
|
|
|
24
|
+
Try the hosted browser demo at
|
|
25
|
+
[relmio.vercel.app](https://relmio.vercel.app/). It is a separate
|
|
26
|
+
request-bound ChatGPT experience; the npm package remains the local wizard for
|
|
27
|
+
installing the private n8n sidecar.
|
|
28
|
+
|
|
29
|
+
Use the site's [Install wizard](https://relmio.vercel.app/install) page for a
|
|
30
|
+
copyable command tailored to the current self-hosted n8n and Hostinger VPS
|
|
31
|
+
setup path.
|
|
32
|
+
|
|
22
33
|
## Quick start
|
|
23
34
|
|
|
24
35
|
Run this on your own macOS, Windows, or Linux computer—not on the VPS:
|
|
@@ -55,7 +66,7 @@ Relmio currently provides tested setup instructions for:
|
|
|
55
66
|
The broader direction is to support local chatbots, custom applications,
|
|
56
67
|
OpenAI-compatible clients, and provider adapters without tying the public
|
|
57
68
|
product name to n8n. SuperGrok/xAI OAuth is a gated feasibility item on the
|
|
58
|
-
[provider roadmap](https://github.com/Demonbane18/
|
|
69
|
+
[provider roadmap](https://github.com/Demonbane18/relmio/blob/main/docs/roadmap.md);
|
|
59
70
|
it is not currently advertised as supported.
|
|
60
71
|
|
|
61
72
|
## Visual walkthrough
|
|
@@ -65,23 +76,23 @@ data, and no real credential or session information.
|
|
|
65
76
|
|
|
66
77
|
### 1. Confirm the local ChatGPT/Codex sign-in
|
|
67
78
|
|
|
68
|
-
<img src="https://
|
|
79
|
+
<img src="https://cdn.jsdelivr.net/npm/relmio@latest/docs/images/setup/01-local-sign-in-ready.png" alt="Sanitized local sign-in ready screen" width="720">
|
|
69
80
|
|
|
70
81
|
### 2. Verify the VPS identity
|
|
71
82
|
|
|
72
|
-
<img src="https://
|
|
83
|
+
<img src="https://cdn.jsdelivr.net/npm/relmio@latest/docs/images/setup/02-vps-identity-confirmed.png" alt="Sanitized VPS fingerprint confirmation screen" width="720">
|
|
73
84
|
|
|
74
85
|
### 3. Choose the detected n8n container and network
|
|
75
86
|
|
|
76
|
-
<img src="https://
|
|
87
|
+
<img src="https://cdn.jsdelivr.net/npm/relmio@latest/docs/images/setup/03-n8n-detected.png" alt="Sanitized n8n discovery screen" width="720">
|
|
77
88
|
|
|
78
89
|
### 4. Review the exact sidecar-only plan
|
|
79
90
|
|
|
80
|
-
<img src="https://
|
|
91
|
+
<img src="https://cdn.jsdelivr.net/npm/relmio@latest/docs/images/setup/04-install-plan.png" alt="Sanitized installation plan screen" width="720">
|
|
81
92
|
|
|
82
93
|
### 5. Copy the verified n8n settings
|
|
83
94
|
|
|
84
|
-
<img src="https://
|
|
95
|
+
<img src="https://cdn.jsdelivr.net/npm/relmio@latest/docs/images/setup/05-bridge-ready.png" alt="Sanitized verified bridge screen" width="720">
|
|
85
96
|
|
|
86
97
|
Use these values in an n8n OpenAI credential:
|
|
87
98
|
|
|
@@ -108,15 +119,52 @@ Platform API key.
|
|
|
108
119
|
- Use it only where your account, subscription, provider terms, and applicable
|
|
109
120
|
policies allow.
|
|
110
121
|
|
|
122
|
+
## How it works
|
|
123
|
+
|
|
124
|
+
OpenAI's Codex CLI uses authenticated endpoints at
|
|
125
|
+
`chatgpt.com/backend-api/codex` to run models with a ChatGPT account. Relmio
|
|
126
|
+
uses the same OAuth credential shape through the upstream
|
|
127
|
+
[`openai-oauth`](https://github.com/EvanZhouDev/openai-oauth) helper to expose
|
|
128
|
+
an OpenAI-compatible path without creating an OpenAI Platform API key or
|
|
129
|
+
requiring separate API credits. The upstream service and its access rules may
|
|
130
|
+
change.
|
|
131
|
+
|
|
132
|
+
## Known limitations
|
|
133
|
+
|
|
134
|
+
- Only models supported by Codex are available. The list changes over time and
|
|
135
|
+
depends on your ChatGPT plan.
|
|
136
|
+
- The CLI `/v1/responses` endpoint is stateless. Callers must send the full
|
|
137
|
+
conversation history; stateful replay is not provided.
|
|
138
|
+
- Hosted browser sign-in currently supports Chrome and Firefox. Safari is not
|
|
139
|
+
yet supported by the upstream Sign in with ChatGPT flow.
|
|
140
|
+
|
|
141
|
+
## Legal
|
|
142
|
+
|
|
143
|
+
Relmio and `openai-oauth` are unofficial, community-maintained projects and
|
|
144
|
+
are not affiliated with, endorsed by, or sponsored by OpenAI.
|
|
145
|
+
|
|
146
|
+
ChatGPT OAuth credentials should be treated like passwords. Use your own
|
|
147
|
+
account, keep credentials private, and never pool, share, or redistribute
|
|
148
|
+
access tokens. Do not bypass rate limits, restrictions, or safeguards.
|
|
149
|
+
|
|
150
|
+
You are responsible for complying with OpenAI's [Terms of
|
|
151
|
+
Use](https://openai.com/policies/terms-of-use/), [Usage
|
|
152
|
+
Policies](https://openai.com/policies/usage-policies/), and any agreement that
|
|
153
|
+
applies to your account. This project is provided as-is without warranties;
|
|
154
|
+
OpenAI may change or disable the underlying services at any time.
|
|
155
|
+
|
|
111
156
|
## Documentation
|
|
112
157
|
|
|
113
|
-
- [Complete GitHub README and manual fallback](https://github.com/Demonbane18/
|
|
114
|
-
- [Configure n8n AI and HTTP nodes](https://github.com/Demonbane18/
|
|
115
|
-
- [Troubleshooting](https://github.com/Demonbane18/
|
|
116
|
-
- [Security and limitations](https://github.com/Demonbane18/
|
|
117
|
-
- [Refresh, upgrade, rollback, and uninstall](https://github.com/Demonbane18/
|
|
118
|
-
- [Changelog](https://github.com/Demonbane18/
|
|
158
|
+
- [Complete GitHub README and manual fallback](https://github.com/Demonbane18/relmio#readme)
|
|
159
|
+
- [Configure n8n AI and HTTP nodes](https://github.com/Demonbane18/relmio/blob/main/docs/n8n-configuration.md)
|
|
160
|
+
- [Troubleshooting](https://github.com/Demonbane18/relmio/blob/main/docs/troubleshooting.md)
|
|
161
|
+
- [Security and limitations](https://github.com/Demonbane18/relmio/blob/main/docs/security.md)
|
|
162
|
+
- [Refresh, upgrade, rollback, and uninstall](https://github.com/Demonbane18/relmio/blob/main/docs/maintenance.md)
|
|
163
|
+
- [Changelog](https://github.com/Demonbane18/relmio/blob/main/CHANGELOG.md)
|
|
119
164
|
|
|
120
165
|
## License
|
|
121
166
|
|
|
122
|
-
[
|
|
167
|
+
[Apache License 2.0](https://github.com/Demonbane18/relmio/blob/main/LICENSE).
|
|
168
|
+
See the package
|
|
169
|
+
[NOTICE](https://github.com/Demonbane18/relmio/blob/main/NOTICE) for the
|
|
170
|
+
upstream `openai-oauth` attribution.
|
package/docs/npm-publish.md
CHANGED
|
@@ -203,7 +203,7 @@ On the npm package's **Trusted Publisher** form, use:
|
|
|
203
203
|
|---|---|
|
|
204
204
|
| Publisher | GitHub Actions |
|
|
205
205
|
| Organization or user | `Demonbane18` |
|
|
206
|
-
| Repository | `
|
|
206
|
+
| Repository | `relmio` |
|
|
207
207
|
| Workflow filename | `publish.yml` |
|
|
208
208
|
| Environment name | `npm` |
|
|
209
209
|
| Allowed action | Allow npm publish |
|
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "relmio",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Turn a supported ChatGPT/Codex OAuth sign-in into a private OpenAI-compatible endpoint, starting with self-hosted n8n.",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"license": "
|
|
6
|
+
"license": "Apache-2.0",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
|
-
"url": "git+https://github.com/Demonbane18/
|
|
9
|
+
"url": "git+https://github.com/Demonbane18/relmio.git"
|
|
10
10
|
},
|
|
11
11
|
"bugs": {
|
|
12
|
-
"url": "https://github.com/Demonbane18/
|
|
12
|
+
"url": "https://github.com/Demonbane18/relmio/issues"
|
|
13
13
|
},
|
|
14
|
-
"homepage": "https://
|
|
14
|
+
"homepage": "https://relmio.vercel.app/",
|
|
15
15
|
"engines": {
|
|
16
16
|
"node": ">=22"
|
|
17
17
|
},
|
|
@@ -28,13 +28,14 @@
|
|
|
28
28
|
"README.md",
|
|
29
29
|
"SPEC.md",
|
|
30
30
|
"CHANGELOG.md",
|
|
31
|
-
"LICENSE"
|
|
31
|
+
"LICENSE",
|
|
32
|
+
"NOTICE"
|
|
32
33
|
],
|
|
33
34
|
"scripts": {
|
|
34
35
|
"start": "node src/cli.js",
|
|
35
36
|
"preview": "node scripts/preview.js",
|
|
36
37
|
"package:build": "node scripts/build-npm-package.js",
|
|
37
|
-
"test": "node --test",
|
|
38
|
+
"test": "node --test test/*.test.js",
|
|
38
39
|
"lint": "node scripts/check-syntax.js",
|
|
39
40
|
"release:check": "node scripts/check-release-metadata.js",
|
|
40
41
|
"check": "npm run lint && npm run release:check && npm test"
|
package/src/ui/app.js
CHANGED
|
@@ -48,6 +48,24 @@ function setBusy(button, busy, busyText) {
|
|
|
48
48
|
button.textContent = busy ? busyText : button.dataset.label;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
const revertTimers = new WeakMap();
|
|
52
|
+
|
|
53
|
+
function flashCopied(button) {
|
|
54
|
+
if (!button.dataset.label) {
|
|
55
|
+
button.dataset.label = button.textContent;
|
|
56
|
+
}
|
|
57
|
+
button.textContent = "Copied";
|
|
58
|
+
button.classList.add("copied");
|
|
59
|
+
window.clearTimeout(revertTimers.get(button));
|
|
60
|
+
revertTimers.set(
|
|
61
|
+
button,
|
|
62
|
+
window.setTimeout(() => {
|
|
63
|
+
button.textContent = button.dataset.label;
|
|
64
|
+
button.classList.remove("copied");
|
|
65
|
+
}, 1800),
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
51
69
|
async function copyText(value) {
|
|
52
70
|
try {
|
|
53
71
|
await navigator.clipboard.writeText(value);
|
|
@@ -405,7 +423,7 @@ element("container-select").addEventListener("change", async () => {
|
|
|
405
423
|
await loadNetworks();
|
|
406
424
|
} catch (error) {
|
|
407
425
|
element("install-confirm").checked = false;
|
|
408
|
-
button.disabled = true;
|
|
426
|
+
element("install-button").disabled = true;
|
|
409
427
|
showStep(2);
|
|
410
428
|
setMessage(
|
|
411
429
|
"The install stopped and the VPS connection was closed. Reconnect to inspect the sidecar before retrying.",
|
|
@@ -488,7 +506,7 @@ element("copy-settings").addEventListener("click", async (event) => {
|
|
|
488
506
|
clearError();
|
|
489
507
|
try {
|
|
490
508
|
await copyText(settings);
|
|
491
|
-
event.currentTarget
|
|
509
|
+
flashCopied(event.currentTarget);
|
|
492
510
|
setMessage("OpenAI credential settings copied.");
|
|
493
511
|
} catch {
|
|
494
512
|
showError(new Error("Copy failed. Select the values manually."));
|
|
@@ -503,7 +521,7 @@ for (const button of document.querySelectorAll("[data-copy-target]")) {
|
|
|
503
521
|
clearError();
|
|
504
522
|
try {
|
|
505
523
|
await copyText(value);
|
|
506
|
-
event.currentTarget
|
|
524
|
+
flashCopied(event.currentTarget);
|
|
507
525
|
setMessage(`${label} copied.`);
|
|
508
526
|
} catch {
|
|
509
527
|
showError(new Error(`Copy failed. Select the ${label} manually.`));
|
package/src/ui/styles.css
CHANGED
|
@@ -1,22 +1,30 @@
|
|
|
1
1
|
:root {
|
|
2
2
|
color-scheme: light;
|
|
3
|
-
--background: #
|
|
3
|
+
--background: #f4f2ec;
|
|
4
4
|
--surface: #ffffff;
|
|
5
|
-
--surface-muted: #
|
|
6
|
-
--text: #
|
|
7
|
-
--text-muted: #
|
|
8
|
-
--border: #
|
|
9
|
-
--border-strong: #
|
|
5
|
+
--surface-muted: #f7f6f1;
|
|
6
|
+
--text: #0d1b18;
|
|
7
|
+
--text-muted: #53655f;
|
|
8
|
+
--border: #dde3df;
|
|
9
|
+
--border-strong: #b9c4bf;
|
|
10
10
|
--accent: #137c74;
|
|
11
|
-
--accent-
|
|
12
|
-
--accent-
|
|
11
|
+
--accent-deep: #0c5f59;
|
|
12
|
+
--accent-bright: #1ba397;
|
|
13
|
+
--accent-soft: #e9f4ef;
|
|
13
14
|
--warning: #8a4b0f;
|
|
14
|
-
--warning-soft: #
|
|
15
|
+
--warning-soft: #fff4e2;
|
|
16
|
+
--warning-border: #e3c491;
|
|
15
17
|
--danger: #a22b2b;
|
|
16
18
|
--danger-soft: #fff0f0;
|
|
17
19
|
--success: #17653f;
|
|
18
|
-
--
|
|
19
|
-
--
|
|
20
|
+
--ease: cubic-bezier(0.22, 1, 0.36, 1);
|
|
21
|
+
--shadow-sm: 0 1px 2px rgb(13 27 24 / 5%);
|
|
22
|
+
--shadow-md:
|
|
23
|
+
0 1px 2px rgb(13 27 24 / 4%),
|
|
24
|
+
0 12px 36px -14px rgb(13 27 24 / 18%);
|
|
25
|
+
--radius-sm: 0.5rem;
|
|
26
|
+
--radius: 0.875rem;
|
|
27
|
+
--radius-lg: 1.25rem;
|
|
20
28
|
}
|
|
21
29
|
|
|
22
30
|
* {
|
|
@@ -29,12 +37,18 @@ html {
|
|
|
29
37
|
sans-serif;
|
|
30
38
|
color: var(--text);
|
|
31
39
|
background: var(--background);
|
|
40
|
+
scroll-behavior: smooth;
|
|
32
41
|
}
|
|
33
42
|
|
|
34
43
|
body {
|
|
35
44
|
min-width: 20rem;
|
|
36
45
|
margin: 0;
|
|
37
46
|
line-height: 1.5;
|
|
47
|
+
-webkit-font-smoothing: antialiased;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
::selection {
|
|
51
|
+
background: rgb(19 124 116 / 22%);
|
|
38
52
|
}
|
|
39
53
|
|
|
40
54
|
button,
|
|
@@ -66,29 +80,39 @@ a:focus-visible {
|
|
|
66
80
|
left: 0.5rem;
|
|
67
81
|
z-index: 10;
|
|
68
82
|
padding: 0.75rem 1rem;
|
|
83
|
+
border-radius: 999px;
|
|
69
84
|
color: #fff;
|
|
70
85
|
background: var(--text);
|
|
71
86
|
transform: translateY(-150%);
|
|
87
|
+
transition: transform 200ms var(--ease);
|
|
72
88
|
}
|
|
73
89
|
|
|
74
90
|
.skip-link:focus {
|
|
75
91
|
transform: translateY(0);
|
|
76
92
|
}
|
|
77
93
|
|
|
94
|
+
/* ---------- Header ---------- */
|
|
95
|
+
|
|
78
96
|
.site-header {
|
|
97
|
+
position: sticky;
|
|
98
|
+
top: 0;
|
|
99
|
+
z-index: 20;
|
|
79
100
|
display: flex;
|
|
80
101
|
align-items: center;
|
|
81
102
|
justify-content: space-between;
|
|
82
|
-
min-height:
|
|
103
|
+
min-height: 4.25rem;
|
|
83
104
|
padding: 0.75rem clamp(1rem, 4vw, 3rem);
|
|
84
|
-
border-bottom: 1px solid
|
|
85
|
-
background: rgb(
|
|
105
|
+
border-bottom: 1px solid rgb(221 227 223 / 75%);
|
|
106
|
+
background: rgb(244 242 236 / 82%);
|
|
107
|
+
backdrop-filter: blur(14px) saturate(1.4);
|
|
108
|
+
-webkit-backdrop-filter: blur(14px) saturate(1.4);
|
|
86
109
|
}
|
|
87
110
|
|
|
88
111
|
.brand {
|
|
89
112
|
display: flex;
|
|
90
113
|
align-items: center;
|
|
91
114
|
gap: 0.625rem;
|
|
115
|
+
font-size: 1.0625rem;
|
|
92
116
|
font-weight: 750;
|
|
93
117
|
letter-spacing: -0.01em;
|
|
94
118
|
}
|
|
@@ -101,19 +125,33 @@ a:focus-visible {
|
|
|
101
125
|
}
|
|
102
126
|
|
|
103
127
|
.local-badge {
|
|
104
|
-
|
|
128
|
+
display: inline-flex;
|
|
129
|
+
align-items: center;
|
|
130
|
+
gap: 0.4375rem;
|
|
131
|
+
padding: 0.4375rem 0.75rem;
|
|
105
132
|
border: 1px solid var(--border);
|
|
106
133
|
border-radius: 999px;
|
|
107
134
|
color: var(--text-muted);
|
|
108
135
|
background: var(--surface);
|
|
136
|
+
box-shadow: var(--shadow-sm);
|
|
109
137
|
font-size: 0.75rem;
|
|
110
138
|
font-weight: 650;
|
|
111
139
|
}
|
|
112
140
|
|
|
141
|
+
.local-badge::before {
|
|
142
|
+
width: 0.4375rem;
|
|
143
|
+
height: 0.4375rem;
|
|
144
|
+
border-radius: 50%;
|
|
145
|
+
background: var(--accent-bright);
|
|
146
|
+
content: "";
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/* ---------- Shell & intro ---------- */
|
|
150
|
+
|
|
113
151
|
.shell {
|
|
114
152
|
width: min(100% - 2rem, 54rem);
|
|
115
153
|
margin: 0 auto;
|
|
116
|
-
padding:
|
|
154
|
+
padding: 3.5rem 0 5rem;
|
|
117
155
|
}
|
|
118
156
|
|
|
119
157
|
.intro {
|
|
@@ -140,14 +178,14 @@ p {
|
|
|
140
178
|
h1 {
|
|
141
179
|
max-width: 42rem;
|
|
142
180
|
margin-bottom: 1rem;
|
|
143
|
-
font-size: clamp(
|
|
144
|
-
line-height: 1.
|
|
181
|
+
font-size: clamp(2.1rem, 6.5vw, 3.4rem);
|
|
182
|
+
line-height: 1.04;
|
|
145
183
|
letter-spacing: -0.045em;
|
|
146
184
|
}
|
|
147
185
|
|
|
148
186
|
h2 {
|
|
149
187
|
margin-bottom: 0.5rem;
|
|
150
|
-
font-size: clamp(1.
|
|
188
|
+
font-size: clamp(1.45rem, 4vw, 1.9rem);
|
|
151
189
|
line-height: 1.2;
|
|
152
190
|
letter-spacing: -0.025em;
|
|
153
191
|
}
|
|
@@ -167,16 +205,38 @@ h3 {
|
|
|
167
205
|
font-size: 1.0625rem;
|
|
168
206
|
}
|
|
169
207
|
|
|
208
|
+
/* ---------- Safety notes ---------- */
|
|
209
|
+
|
|
170
210
|
.safety-note {
|
|
211
|
+
position: relative;
|
|
171
212
|
display: grid;
|
|
172
|
-
grid-template-columns:
|
|
173
|
-
gap: 0.
|
|
174
|
-
|
|
175
|
-
|
|
213
|
+
grid-template-columns: 2.25rem 1fr;
|
|
214
|
+
gap: 0.25rem 0.875rem;
|
|
215
|
+
align-items: start;
|
|
216
|
+
margin: 1.25rem 0 0;
|
|
217
|
+
padding: 1rem 1.125rem;
|
|
176
218
|
border: 1px solid #b9d9d2;
|
|
177
|
-
border-
|
|
178
|
-
border-radius: 0.5rem;
|
|
219
|
+
border-radius: var(--radius);
|
|
179
220
|
background: var(--accent-soft);
|
|
221
|
+
box-shadow: var(--shadow-sm);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.safety-note::before {
|
|
225
|
+
display: grid;
|
|
226
|
+
width: 2.25rem;
|
|
227
|
+
height: 2.25rem;
|
|
228
|
+
grid-row: span 2;
|
|
229
|
+
place-items: center;
|
|
230
|
+
border-radius: 0.625rem;
|
|
231
|
+
color: var(--accent-deep);
|
|
232
|
+
background: #d3eae0;
|
|
233
|
+
font-size: 1rem;
|
|
234
|
+
font-weight: 800;
|
|
235
|
+
content: "✓";
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.safety-note strong {
|
|
239
|
+
align-self: center;
|
|
180
240
|
}
|
|
181
241
|
|
|
182
242
|
.safety-note span {
|
|
@@ -184,16 +244,24 @@ h3 {
|
|
|
184
244
|
}
|
|
185
245
|
|
|
186
246
|
.backup-note {
|
|
187
|
-
border-color:
|
|
247
|
+
border-color: var(--warning-border);
|
|
188
248
|
background: var(--warning-soft);
|
|
189
249
|
}
|
|
190
250
|
|
|
251
|
+
.backup-note::before {
|
|
252
|
+
color: var(--warning);
|
|
253
|
+
background: #f6e3c3;
|
|
254
|
+
content: "!";
|
|
255
|
+
}
|
|
256
|
+
|
|
191
257
|
.backup-note span {
|
|
192
258
|
color: var(--warning);
|
|
193
259
|
}
|
|
194
260
|
|
|
261
|
+
/* ---------- Stepper ---------- */
|
|
262
|
+
|
|
195
263
|
.steps {
|
|
196
|
-
margin:
|
|
264
|
+
margin: 2.5rem 0 1.25rem;
|
|
197
265
|
}
|
|
198
266
|
|
|
199
267
|
.steps ol {
|
|
@@ -208,7 +276,7 @@ h3 {
|
|
|
208
276
|
position: relative;
|
|
209
277
|
display: grid;
|
|
210
278
|
justify-items: center;
|
|
211
|
-
gap: 0.
|
|
279
|
+
gap: 0.4375rem;
|
|
212
280
|
color: var(--text-muted);
|
|
213
281
|
font-size: 0.75rem;
|
|
214
282
|
text-align: center;
|
|
@@ -216,13 +284,14 @@ h3 {
|
|
|
216
284
|
|
|
217
285
|
.steps li::before {
|
|
218
286
|
position: absolute;
|
|
219
|
-
top: 0.
|
|
287
|
+
top: 0.9375rem;
|
|
220
288
|
right: 50%;
|
|
221
|
-
z-index:
|
|
289
|
+
z-index: 0;
|
|
222
290
|
width: 100%;
|
|
223
291
|
height: 2px;
|
|
224
292
|
background: var(--border);
|
|
225
293
|
content: "";
|
|
294
|
+
transition: background 400ms var(--ease);
|
|
226
295
|
}
|
|
227
296
|
|
|
228
297
|
.steps li:first-child::before {
|
|
@@ -230,29 +299,52 @@ h3 {
|
|
|
230
299
|
}
|
|
231
300
|
|
|
232
301
|
.steps li span {
|
|
302
|
+
position: relative;
|
|
303
|
+
z-index: 1;
|
|
233
304
|
display: grid;
|
|
234
|
-
width:
|
|
235
|
-
height:
|
|
305
|
+
width: 2rem;
|
|
306
|
+
height: 2rem;
|
|
236
307
|
place-items: center;
|
|
237
308
|
border: 2px solid var(--border-strong);
|
|
238
309
|
border-radius: 50%;
|
|
239
|
-
background: var(--
|
|
310
|
+
background: var(--surface);
|
|
311
|
+
box-shadow: var(--shadow-sm);
|
|
312
|
+
font-size: 0.8125rem;
|
|
240
313
|
font-weight: 800;
|
|
314
|
+
transition:
|
|
315
|
+
border-color 300ms var(--ease),
|
|
316
|
+
background 300ms var(--ease),
|
|
317
|
+
color 300ms var(--ease),
|
|
318
|
+
box-shadow 300ms var(--ease);
|
|
241
319
|
}
|
|
242
320
|
|
|
243
321
|
.steps li em {
|
|
244
322
|
font-style: normal;
|
|
323
|
+
font-weight: 600;
|
|
245
324
|
}
|
|
246
325
|
|
|
247
326
|
.steps li[aria-current="step"] {
|
|
248
327
|
color: var(--text);
|
|
249
328
|
}
|
|
250
329
|
|
|
251
|
-
.steps li[aria-current="step"] span
|
|
252
|
-
.steps li.complete span {
|
|
330
|
+
.steps li[aria-current="step"] span {
|
|
253
331
|
border-color: var(--accent);
|
|
254
332
|
color: #fff;
|
|
255
333
|
background: var(--accent);
|
|
334
|
+
box-shadow: 0 0 0 5px rgb(19 124 116 / 15%);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
.steps li.complete span {
|
|
338
|
+
border-color: var(--accent);
|
|
339
|
+
color: transparent;
|
|
340
|
+
background: var(--accent);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
.steps li.complete span::after {
|
|
344
|
+
position: absolute;
|
|
345
|
+
color: #fff;
|
|
346
|
+
font-size: 0.8125rem;
|
|
347
|
+
content: "✓";
|
|
256
348
|
}
|
|
257
349
|
|
|
258
350
|
.steps li.complete::before,
|
|
@@ -260,17 +352,34 @@ h3 {
|
|
|
260
352
|
background: var(--accent);
|
|
261
353
|
}
|
|
262
354
|
|
|
355
|
+
/* ---------- Global messages ---------- */
|
|
356
|
+
|
|
263
357
|
.message,
|
|
264
358
|
.error {
|
|
265
|
-
|
|
359
|
+
display: flex;
|
|
360
|
+
align-items: center;
|
|
361
|
+
gap: 0.625rem;
|
|
362
|
+
min-height: 2.875rem;
|
|
266
363
|
margin: 1rem 0;
|
|
267
364
|
padding: 0.75rem 1rem;
|
|
268
|
-
border-radius:
|
|
365
|
+
border-radius: var(--radius-sm);
|
|
366
|
+
font-size: 0.9375rem;
|
|
269
367
|
}
|
|
270
368
|
|
|
271
369
|
.message {
|
|
370
|
+
border: 1px solid var(--border);
|
|
272
371
|
color: var(--text-muted);
|
|
273
|
-
background: var(--surface
|
|
372
|
+
background: var(--surface);
|
|
373
|
+
box-shadow: var(--shadow-sm);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
.message::before {
|
|
377
|
+
flex: 0 0 auto;
|
|
378
|
+
width: 0.4375rem;
|
|
379
|
+
height: 0.4375rem;
|
|
380
|
+
border-radius: 50%;
|
|
381
|
+
background: var(--accent-bright);
|
|
382
|
+
content: "";
|
|
274
383
|
}
|
|
275
384
|
|
|
276
385
|
.error {
|
|
@@ -278,14 +387,18 @@ h3 {
|
|
|
278
387
|
color: var(--danger);
|
|
279
388
|
background: var(--danger-soft);
|
|
280
389
|
font-weight: 650;
|
|
390
|
+
animation: shake 320ms var(--ease);
|
|
281
391
|
}
|
|
282
392
|
|
|
393
|
+
/* ---------- Panels ---------- */
|
|
394
|
+
|
|
283
395
|
.panel {
|
|
284
|
-
padding: clamp(1.
|
|
396
|
+
padding: clamp(1.5rem, 4vw, 2.25rem);
|
|
285
397
|
border: 1px solid var(--border);
|
|
286
|
-
border-radius: var(--radius);
|
|
398
|
+
border-radius: var(--radius-lg);
|
|
287
399
|
background: var(--surface);
|
|
288
|
-
box-shadow: var(--shadow);
|
|
400
|
+
box-shadow: var(--shadow-md);
|
|
401
|
+
animation: panel-in 380ms var(--ease);
|
|
289
402
|
}
|
|
290
403
|
|
|
291
404
|
.panel-heading {
|
|
@@ -301,9 +414,9 @@ h3 {
|
|
|
301
414
|
display: flex;
|
|
302
415
|
align-items: flex-start;
|
|
303
416
|
gap: 0.875rem;
|
|
304
|
-
padding: 1rem;
|
|
417
|
+
padding: 1rem 1.125rem;
|
|
305
418
|
border: 1px solid var(--border);
|
|
306
|
-
border-radius:
|
|
419
|
+
border-radius: var(--radius);
|
|
307
420
|
background: var(--surface-muted);
|
|
308
421
|
}
|
|
309
422
|
|
|
@@ -325,13 +438,20 @@ h3 {
|
|
|
325
438
|
margin-top: 0.375rem;
|
|
326
439
|
border: 2px solid var(--border-strong);
|
|
327
440
|
border-radius: 50%;
|
|
441
|
+
transition:
|
|
442
|
+
border-color 300ms var(--ease),
|
|
443
|
+
background 300ms var(--ease),
|
|
444
|
+
box-shadow 300ms var(--ease);
|
|
328
445
|
}
|
|
329
446
|
|
|
330
447
|
.status-dot.ready {
|
|
331
448
|
border-color: var(--success);
|
|
332
449
|
background: var(--success);
|
|
450
|
+
box-shadow: 0 0 0 4px rgb(23 101 63 / 14%);
|
|
333
451
|
}
|
|
334
452
|
|
|
453
|
+
/* ---------- Fields ---------- */
|
|
454
|
+
|
|
335
455
|
.field-grid {
|
|
336
456
|
display: grid;
|
|
337
457
|
grid-template-columns: minmax(0, 2fr) minmax(7rem, 1fr);
|
|
@@ -346,24 +466,56 @@ h3 {
|
|
|
346
466
|
.field {
|
|
347
467
|
display: grid;
|
|
348
468
|
align-content: start;
|
|
349
|
-
gap: 0.
|
|
469
|
+
gap: 0.4375rem;
|
|
350
470
|
font-weight: 700;
|
|
351
471
|
}
|
|
352
472
|
|
|
353
473
|
.field input,
|
|
354
474
|
.field select {
|
|
355
475
|
width: 100%;
|
|
356
|
-
min-height: 2.
|
|
357
|
-
padding: 0.625rem 0.
|
|
476
|
+
min-height: 2.875rem;
|
|
477
|
+
padding: 0.625rem 0.875rem;
|
|
358
478
|
border: 1px solid var(--border-strong);
|
|
359
|
-
border-radius:
|
|
479
|
+
border-radius: var(--radius-sm);
|
|
360
480
|
color: var(--text);
|
|
361
481
|
background: #fff;
|
|
482
|
+
transition:
|
|
483
|
+
border-color 200ms var(--ease),
|
|
484
|
+
box-shadow 200ms var(--ease),
|
|
485
|
+
background 200ms var(--ease);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
.field select {
|
|
489
|
+
appearance: none;
|
|
490
|
+
padding-right: 2.25rem;
|
|
491
|
+
background-image:
|
|
492
|
+
linear-gradient(45deg, transparent 50%, var(--text-muted) 50%),
|
|
493
|
+
linear-gradient(135deg, var(--text-muted) 50%, transparent 50%);
|
|
494
|
+
background-position:
|
|
495
|
+
calc(100% - 1.125rem) 50%,
|
|
496
|
+
calc(100% - 0.8125rem) 50%;
|
|
497
|
+
background-size:
|
|
498
|
+
0.3125rem 0.3125rem,
|
|
499
|
+
0.3125rem 0.3125rem;
|
|
500
|
+
background-repeat: no-repeat;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
.field input:hover,
|
|
504
|
+
.field select:hover {
|
|
505
|
+
border-color: var(--accent);
|
|
362
506
|
}
|
|
363
507
|
|
|
364
508
|
.field input:focus,
|
|
365
509
|
.field select:focus {
|
|
366
510
|
border-color: var(--accent);
|
|
511
|
+
outline: 0;
|
|
512
|
+
box-shadow: 0 0 0 4px rgb(19 124 116 / 13%);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
.field input:disabled {
|
|
516
|
+
color: var(--text-muted);
|
|
517
|
+
background: var(--surface-muted);
|
|
518
|
+
cursor: not-allowed;
|
|
367
519
|
}
|
|
368
520
|
|
|
369
521
|
.field small {
|
|
@@ -381,21 +533,46 @@ code {
|
|
|
381
533
|
overflow-wrap: anywhere;
|
|
382
534
|
}
|
|
383
535
|
|
|
536
|
+
/* ---------- Buttons ---------- */
|
|
537
|
+
|
|
384
538
|
.actions {
|
|
385
539
|
display: flex;
|
|
386
540
|
flex-wrap: wrap;
|
|
387
541
|
justify-content: flex-end;
|
|
388
542
|
gap: 0.75rem;
|
|
389
|
-
margin-top: 1.
|
|
543
|
+
margin-top: 1.75rem;
|
|
390
544
|
}
|
|
391
545
|
|
|
392
546
|
.button {
|
|
393
|
-
|
|
394
|
-
|
|
547
|
+
position: relative;
|
|
548
|
+
display: inline-flex;
|
|
549
|
+
align-items: center;
|
|
550
|
+
justify-content: center;
|
|
551
|
+
gap: 0.5rem;
|
|
552
|
+
min-height: 2.875rem;
|
|
553
|
+
padding: 0.625rem 1.125rem;
|
|
395
554
|
border: 1px solid transparent;
|
|
396
|
-
border-radius: 0.
|
|
555
|
+
border-radius: 0.625rem;
|
|
397
556
|
font-weight: 750;
|
|
557
|
+
box-shadow: var(--shadow-sm);
|
|
398
558
|
cursor: pointer;
|
|
559
|
+
transition:
|
|
560
|
+
transform 200ms var(--ease),
|
|
561
|
+
box-shadow 200ms var(--ease),
|
|
562
|
+
background 200ms var(--ease),
|
|
563
|
+
color 200ms var(--ease),
|
|
564
|
+
border-color 200ms var(--ease),
|
|
565
|
+
opacity 200ms var(--ease);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
.button:not(:disabled):hover {
|
|
569
|
+
transform: translateY(-1px);
|
|
570
|
+
box-shadow: var(--shadow-md);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
.button:not(:disabled):active {
|
|
574
|
+
transform: translateY(0) scale(0.98);
|
|
575
|
+
box-shadow: var(--shadow-sm);
|
|
399
576
|
}
|
|
400
577
|
|
|
401
578
|
.button:disabled {
|
|
@@ -403,13 +580,28 @@ code {
|
|
|
403
580
|
opacity: 0.48;
|
|
404
581
|
}
|
|
405
582
|
|
|
583
|
+
.button[aria-busy="true"] {
|
|
584
|
+
cursor: progress;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
.button[aria-busy="true"]::after {
|
|
588
|
+
width: 0.9375rem;
|
|
589
|
+
height: 0.9375rem;
|
|
590
|
+
flex: 0 0 auto;
|
|
591
|
+
border: 2px solid currentcolor;
|
|
592
|
+
border-top-color: transparent;
|
|
593
|
+
border-radius: 50%;
|
|
594
|
+
content: "";
|
|
595
|
+
animation: spin 700ms linear infinite;
|
|
596
|
+
}
|
|
597
|
+
|
|
406
598
|
.button.primary {
|
|
407
599
|
color: #fff;
|
|
408
600
|
background: var(--accent);
|
|
409
601
|
}
|
|
410
602
|
|
|
411
603
|
.button.primary:not(:disabled):hover {
|
|
412
|
-
background: var(--accent-
|
|
604
|
+
background: var(--accent-deep);
|
|
413
605
|
}
|
|
414
606
|
|
|
415
607
|
.button.secondary {
|
|
@@ -420,21 +612,32 @@ code {
|
|
|
420
612
|
|
|
421
613
|
.button.secondary:not(:disabled):hover,
|
|
422
614
|
.button.ghost:not(:disabled):hover {
|
|
423
|
-
|
|
615
|
+
border-color: var(--accent);
|
|
616
|
+
background: var(--accent-soft);
|
|
424
617
|
}
|
|
425
618
|
|
|
426
619
|
.button.ghost {
|
|
427
620
|
margin-right: auto;
|
|
428
621
|
color: var(--text-muted);
|
|
429
622
|
background: transparent;
|
|
623
|
+
box-shadow: none;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
.button.copied {
|
|
627
|
+
border-color: var(--success);
|
|
628
|
+
color: var(--success);
|
|
629
|
+
background: #e9f5ee;
|
|
430
630
|
}
|
|
431
631
|
|
|
632
|
+
/* ---------- Fingerprint & approvals ---------- */
|
|
633
|
+
|
|
432
634
|
.fingerprint {
|
|
433
635
|
margin-top: 1rem;
|
|
434
|
-
padding:
|
|
435
|
-
border: 1px solid
|
|
436
|
-
border-radius:
|
|
636
|
+
padding: 1.125rem;
|
|
637
|
+
border: 1px solid var(--warning-border);
|
|
638
|
+
border-radius: var(--radius);
|
|
437
639
|
background: var(--warning-soft);
|
|
640
|
+
animation: panel-in 320ms var(--ease);
|
|
438
641
|
}
|
|
439
642
|
|
|
440
643
|
.fingerprint > span {
|
|
@@ -449,6 +652,9 @@ code {
|
|
|
449
652
|
.fingerprint > code {
|
|
450
653
|
display: block;
|
|
451
654
|
margin-bottom: 1rem;
|
|
655
|
+
padding: 0.625rem 0.75rem;
|
|
656
|
+
border: 1px solid var(--warning-border);
|
|
657
|
+
border-radius: var(--radius-sm);
|
|
452
658
|
background: #fff;
|
|
453
659
|
}
|
|
454
660
|
|
|
@@ -465,23 +671,30 @@ code {
|
|
|
465
671
|
width: 1.125rem;
|
|
466
672
|
height: 1.125rem;
|
|
467
673
|
margin: 0.2rem 0 0;
|
|
674
|
+
accent-color: var(--accent);
|
|
675
|
+
cursor: pointer;
|
|
468
676
|
}
|
|
469
677
|
|
|
470
678
|
.version-strip {
|
|
471
679
|
display: flex;
|
|
472
680
|
flex-wrap: wrap;
|
|
473
|
-
gap: 0.
|
|
474
|
-
margin-bottom:
|
|
681
|
+
gap: 0.625rem;
|
|
682
|
+
margin-bottom: 1.25rem;
|
|
475
683
|
}
|
|
476
684
|
|
|
477
685
|
.version-strip span {
|
|
478
|
-
|
|
686
|
+
display: inline-flex;
|
|
687
|
+
align-items: center;
|
|
688
|
+
gap: 0.375rem;
|
|
689
|
+
padding: 0.4375rem 0.75rem;
|
|
479
690
|
border: 1px solid var(--border);
|
|
480
691
|
border-radius: 999px;
|
|
481
692
|
background: var(--surface-muted);
|
|
482
|
-
font-size: 0.
|
|
693
|
+
font-size: 0.8125rem;
|
|
483
694
|
}
|
|
484
695
|
|
|
696
|
+
/* ---------- Review ---------- */
|
|
697
|
+
|
|
485
698
|
.review-grid {
|
|
486
699
|
display: grid;
|
|
487
700
|
grid-template-columns: 1fr 1fr;
|
|
@@ -489,9 +702,20 @@ code {
|
|
|
489
702
|
}
|
|
490
703
|
|
|
491
704
|
.review-grid section {
|
|
492
|
-
padding:
|
|
705
|
+
padding: 1.125rem;
|
|
493
706
|
border: 1px solid var(--border);
|
|
494
|
-
border-radius:
|
|
707
|
+
border-radius: var(--radius);
|
|
708
|
+
background: var(--surface-muted);
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
.review-grid section:first-child {
|
|
712
|
+
border-color: #b9d9d2;
|
|
713
|
+
background: var(--accent-soft);
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
.review-grid section:last-child {
|
|
717
|
+
border-color: #e4abab;
|
|
718
|
+
background: var(--danger-soft);
|
|
495
719
|
}
|
|
496
720
|
|
|
497
721
|
.check-list,
|
|
@@ -512,27 +736,31 @@ code {
|
|
|
512
736
|
|
|
513
737
|
.approval {
|
|
514
738
|
margin-top: 1rem;
|
|
515
|
-
padding: 1rem;
|
|
516
|
-
border: 1px solid
|
|
517
|
-
border-radius:
|
|
739
|
+
padding: 1rem 1.125rem;
|
|
740
|
+
border: 1px solid var(--warning-border);
|
|
741
|
+
border-radius: var(--radius);
|
|
518
742
|
background: var(--warning-soft);
|
|
519
743
|
}
|
|
520
744
|
|
|
745
|
+
/* ---------- Success ---------- */
|
|
746
|
+
|
|
521
747
|
.success-panel {
|
|
522
748
|
position: relative;
|
|
523
749
|
}
|
|
524
750
|
|
|
525
751
|
.success-mark {
|
|
526
752
|
display: grid;
|
|
527
|
-
width:
|
|
528
|
-
height:
|
|
529
|
-
margin-bottom:
|
|
753
|
+
width: 3.25rem;
|
|
754
|
+
height: 3.25rem;
|
|
755
|
+
margin-bottom: 1.25rem;
|
|
530
756
|
place-items: center;
|
|
531
757
|
border-radius: 50%;
|
|
532
758
|
color: #fff;
|
|
533
|
-
background: var(--success);
|
|
759
|
+
background: linear-gradient(140deg, #1d8a5f, var(--success));
|
|
760
|
+
box-shadow: 0 0 0 6px rgb(23 101 63 / 14%);
|
|
534
761
|
font-size: 1.5rem;
|
|
535
762
|
font-weight: 900;
|
|
763
|
+
animation: pop-in 480ms var(--ease);
|
|
536
764
|
}
|
|
537
765
|
|
|
538
766
|
.result-list {
|
|
@@ -543,6 +771,7 @@ code {
|
|
|
543
771
|
display: grid;
|
|
544
772
|
grid-template-columns: 9rem 1fr;
|
|
545
773
|
gap: 1rem;
|
|
774
|
+
align-items: center;
|
|
546
775
|
padding: 0.875rem 0;
|
|
547
776
|
border-bottom: 1px solid var(--border);
|
|
548
777
|
}
|
|
@@ -560,20 +789,23 @@ code {
|
|
|
560
789
|
display: flex;
|
|
561
790
|
flex-wrap: wrap;
|
|
562
791
|
align-items: center;
|
|
792
|
+
justify-content: space-between;
|
|
563
793
|
gap: 0.75rem;
|
|
564
794
|
}
|
|
565
795
|
|
|
566
796
|
.copy-value {
|
|
567
|
-
min-height:
|
|
568
|
-
padding: 0.
|
|
797
|
+
min-height: 2.125rem;
|
|
798
|
+
padding: 0.3125rem 0.75rem;
|
|
799
|
+
border-radius: 0.5rem;
|
|
569
800
|
font-size: 0.8125rem;
|
|
570
801
|
}
|
|
571
802
|
|
|
572
803
|
.model-box,
|
|
573
804
|
.final-note {
|
|
574
805
|
margin-top: 1.5rem;
|
|
575
|
-
padding:
|
|
576
|
-
border
|
|
806
|
+
padding: 1.125rem;
|
|
807
|
+
border: 1px solid var(--border);
|
|
808
|
+
border-radius: var(--radius);
|
|
577
809
|
background: var(--surface-muted);
|
|
578
810
|
}
|
|
579
811
|
|
|
@@ -582,6 +814,10 @@ code {
|
|
|
582
814
|
margin-bottom: 0;
|
|
583
815
|
}
|
|
584
816
|
|
|
817
|
+
.model-box p {
|
|
818
|
+
color: var(--text-muted);
|
|
819
|
+
}
|
|
820
|
+
|
|
585
821
|
footer {
|
|
586
822
|
padding: 1.5rem 1rem;
|
|
587
823
|
border-top: 1px solid var(--border);
|
|
@@ -595,6 +831,54 @@ footer p {
|
|
|
595
831
|
margin: 0;
|
|
596
832
|
}
|
|
597
833
|
|
|
834
|
+
/* ---------- Animations ---------- */
|
|
835
|
+
|
|
836
|
+
@keyframes panel-in {
|
|
837
|
+
from {
|
|
838
|
+
opacity: 0;
|
|
839
|
+
transform: translateY(14px);
|
|
840
|
+
}
|
|
841
|
+
to {
|
|
842
|
+
opacity: 1;
|
|
843
|
+
transform: translateY(0);
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
@keyframes pop-in {
|
|
848
|
+
0% {
|
|
849
|
+
opacity: 0;
|
|
850
|
+
transform: scale(0.5);
|
|
851
|
+
}
|
|
852
|
+
70% {
|
|
853
|
+
transform: scale(1.08);
|
|
854
|
+
}
|
|
855
|
+
100% {
|
|
856
|
+
opacity: 1;
|
|
857
|
+
transform: scale(1);
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
@keyframes shake {
|
|
862
|
+
0%,
|
|
863
|
+
100% {
|
|
864
|
+
transform: translateX(0);
|
|
865
|
+
}
|
|
866
|
+
25% {
|
|
867
|
+
transform: translateX(-4px);
|
|
868
|
+
}
|
|
869
|
+
75% {
|
|
870
|
+
transform: translateX(4px);
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
@keyframes spin {
|
|
875
|
+
to {
|
|
876
|
+
transform: rotate(360deg);
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
/* ---------- Responsive ---------- */
|
|
881
|
+
|
|
598
882
|
@media (max-width: 42rem) {
|
|
599
883
|
.local-badge {
|
|
600
884
|
display: none;
|
|
@@ -611,12 +895,16 @@ footer p {
|
|
|
611
895
|
grid-template-columns: 1fr;
|
|
612
896
|
}
|
|
613
897
|
|
|
898
|
+
.safety-note::before {
|
|
899
|
+
grid-row: auto;
|
|
900
|
+
}
|
|
901
|
+
|
|
614
902
|
.steps li em {
|
|
615
903
|
font-size: 0.6875rem;
|
|
616
904
|
}
|
|
617
905
|
|
|
618
906
|
.panel {
|
|
619
|
-
border-radius:
|
|
907
|
+
border-radius: var(--radius);
|
|
620
908
|
}
|
|
621
909
|
|
|
622
910
|
.actions {
|
|
@@ -636,9 +924,15 @@ footer p {
|
|
|
636
924
|
}
|
|
637
925
|
|
|
638
926
|
@media (prefers-reduced-motion: reduce) {
|
|
927
|
+
html {
|
|
928
|
+
scroll-behavior: auto;
|
|
929
|
+
}
|
|
930
|
+
|
|
639
931
|
*,
|
|
640
932
|
*::before,
|
|
641
933
|
*::after {
|
|
934
|
+
animation-duration: 0.01ms !important;
|
|
935
|
+
animation-iteration-count: 1 !important;
|
|
642
936
|
scroll-behavior: auto !important;
|
|
643
937
|
transition-duration: 0.01ms !important;
|
|
644
938
|
}
|