svcloud 0.1.0-alpha.3 → 0.1.0-alpha.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svcloud",
3
- "version": "0.1.0-alpha.3",
3
+ "version": "0.1.0-alpha.4",
4
4
  "description": "The SV Cloud CLI. Alpha: login, logout, status, open, projects list, mcp, init, and runs are built; see PLANNING.md for what's still missing.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
@@ -21,11 +21,218 @@ export interface LoopbackListener {
21
21
  }
22
22
 
23
23
  const CALLBACK_PAGE = (ok: boolean) => `<!doctype html>
24
- <html><head><title>SV Cloud</title></head>
25
- <body style="font-family:system-ui;padding:2rem;color:#111">
26
- <h1>${ok ? "You're signed in." : "Sign-in didn't finish."}</h1>
27
- <p>You can close this tab and go back to your terminal.</p>
28
- </body></html>`;
24
+ <html lang="en">
25
+ <head>
26
+ <meta charset="utf-8" />
27
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
28
+ <title>SV Cloud</title>
29
+ <style>
30
+ :root {
31
+ --bg-canvas: #0b0c0e;
32
+ --bg-surface: #131519;
33
+ --bg-raised: #1b1e24;
34
+ --border-quiet: #23272e;
35
+ --border-loud: #343a44;
36
+ --text-1: #e9ebef;
37
+ --text-2: #a7aeba;
38
+ --text-3: #6e7684;
39
+ --accent: #8e6bff;
40
+ --state-live: #34c77b;
41
+ --state-failed: #e8a33d;
42
+ --font-sans: 'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
43
+ --font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
44
+ --shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
45
+ }
46
+ @media (prefers-color-scheme: light) {
47
+ :root {
48
+ --bg-canvas: #fafbfc;
49
+ --bg-surface: #ffffff;
50
+ --bg-raised: #f2f4f7;
51
+ --border-quiet: #e1e4ea;
52
+ --border-loud: #cdd2dc;
53
+ --text-1: #111318;
54
+ --text-2: #4a5160;
55
+ --text-3: #7d8594;
56
+ --accent: #7c5cfc;
57
+ --state-live: #1da462;
58
+ --state-failed: #d97706;
59
+ --shadow: 0 8px 32px rgba(0, 0, 0, 0.08);
60
+ }
61
+ }
62
+ * {
63
+ box-sizing: border-box;
64
+ margin: 0;
65
+ padding: 0;
66
+ }
67
+ body {
68
+ min-height: 100vh;
69
+ display: flex;
70
+ flex-direction: column;
71
+ align-items: center;
72
+ justify-content: center;
73
+ background-color: var(--bg-canvas);
74
+ background-image: radial-gradient(circle at 50% 15%, color-mix(in srgb, var(--accent) 12%, transparent), transparent 60%);
75
+ color: var(--text-1);
76
+ font-family: var(--font-sans);
77
+ padding: 24px;
78
+ -webkit-font-smoothing: antialiased;
79
+ }
80
+ .auth-container {
81
+ width: min(420px, 100%);
82
+ display: flex;
83
+ flex-direction: column;
84
+ align-items: center;
85
+ gap: 24px;
86
+ animation: fadeIn 0.3s ease-out;
87
+ }
88
+ @keyframes fadeIn {
89
+ from { opacity: 0; transform: translateY(6px); }
90
+ to { opacity: 1; transform: translateY(0); }
91
+ }
92
+ .lockup {
93
+ display: inline-flex;
94
+ align-items: center;
95
+ gap: 10px;
96
+ font-size: 15px;
97
+ font-weight: 500;
98
+ letter-spacing: -0.01em;
99
+ color: var(--text-1);
100
+ text-decoration: none;
101
+ }
102
+ .mark {
103
+ width: 24px;
104
+ height: 24px;
105
+ display: grid;
106
+ place-items: center;
107
+ border-radius: 5px;
108
+ border: 1px solid var(--border-loud);
109
+ background: var(--bg-raised);
110
+ color: var(--text-2);
111
+ font-family: var(--font-mono);
112
+ font-size: 10px;
113
+ font-weight: 600;
114
+ letter-spacing: 0.05em;
115
+ }
116
+ .card {
117
+ width: 100%;
118
+ background: var(--bg-surface);
119
+ border: 1px solid var(--border-quiet);
120
+ border-radius: 12px;
121
+ padding: 28px 24px;
122
+ display: flex;
123
+ flex-direction: column;
124
+ align-items: center;
125
+ text-align: center;
126
+ gap: 16px;
127
+ box-shadow: var(--shadow);
128
+ }
129
+ .status-icon {
130
+ width: 44px;
131
+ height: 44px;
132
+ border-radius: 50%;
133
+ display: grid;
134
+ place-items: center;
135
+ flex-shrink: 0;
136
+ }
137
+ .status-icon--ok {
138
+ background: color-mix(in srgb, var(--state-live) 15%, transparent);
139
+ color: var(--state-live);
140
+ border: 1px solid color-mix(in srgb, var(--state-live) 30%, transparent);
141
+ }
142
+ .status-icon--error {
143
+ background: color-mix(in srgb, var(--state-failed) 15%, transparent);
144
+ color: var(--state-failed);
145
+ border: 1px solid color-mix(in srgb, var(--state-failed) 30%, transparent);
146
+ }
147
+ h1 {
148
+ font-size: 20px;
149
+ font-weight: 600;
150
+ letter-spacing: -0.02em;
151
+ color: var(--text-1);
152
+ line-height: 1.3;
153
+ }
154
+ p.desc {
155
+ font-size: 14px;
156
+ color: var(--text-2);
157
+ line-height: 1.5;
158
+ }
159
+ .terminal-box {
160
+ width: 100%;
161
+ margin-top: 6px;
162
+ background: var(--bg-raised);
163
+ border: 1px solid var(--border-quiet);
164
+ border-radius: 8px;
165
+ padding: 12px 14px;
166
+ font-family: var(--font-mono);
167
+ font-size: 12px;
168
+ color: var(--text-2);
169
+ text-align: left;
170
+ display: flex;
171
+ align-items: center;
172
+ justify-content: space-between;
173
+ gap: 8px;
174
+ }
175
+ .terminal-box .cmd {
176
+ color: var(--text-1);
177
+ display: flex;
178
+ align-items: center;
179
+ gap: 6px;
180
+ }
181
+ .terminal-box .prompt {
182
+ color: var(--accent);
183
+ user-select: none;
184
+ }
185
+ .terminal-box .status-pill {
186
+ font-size: 11px;
187
+ padding: 2px 8px;
188
+ border-radius: 9999px;
189
+ font-family: var(--font-sans);
190
+ font-weight: 500;
191
+ }
192
+ .status-pill--ok {
193
+ background: color-mix(in srgb, var(--state-live) 15%, transparent);
194
+ color: var(--state-live);
195
+ }
196
+ .status-pill--error {
197
+ background: color-mix(in srgb, var(--state-failed) 15%, transparent);
198
+ color: var(--state-failed);
199
+ }
200
+ .foot {
201
+ font-size: 12px;
202
+ color: var(--text-3);
203
+ }
204
+ </style>
205
+ </head>
206
+ <body>
207
+ <div class="auth-container">
208
+ <div class="lockup">
209
+ <span class="mark">SV</span>
210
+ <span>SV Cloud</span>
211
+ </div>
212
+ <div class="card">
213
+ <div class="status-icon \${ok ? 'status-icon--ok' : 'status-icon--error'}">
214
+ \${ok
215
+ ? '<svg width="20" height="20" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 8.5 6.5 12 13 4.5"/></svg>'
216
+ : '<svg width="20" height="20" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M8 2.2 15 14H1Z"/><path d="M8 6.6v3.2"/><circle cx="8" cy="11.9" r="0.9" fill="currentColor"/></svg>'}
217
+ </div>
218
+ <div>
219
+ <h1>\${ok ? "You're signed in" : "Sign-in didn't finish"}</h1>
220
+ <p class="desc">\${ok ? "You can close this tab and return to your terminal." : "The sign-in request was not completed. Nothing changed on your account."}</p>
221
+ </div>
222
+ <div class="terminal-box">
223
+ <div class="cmd">
224
+ <span class="prompt">$</span>
225
+ <span>\${ok ? "svcloud" : "svcloud login"}</span>
226
+ </div>
227
+ <span class="status-pill \${ok ? 'status-pill--ok' : 'status-pill--error'}">
228
+ \${ok ? "Ready" : "Retry"}
229
+ </span>
230
+ </div>
231
+ </div>
232
+ <p class="foot">SV Cloud CLI</p>
233
+ </div>
234
+ </body>
235
+ </html>`;
29
236
 
30
237
  export function startLoopbackListener(): Promise<LoopbackListener> {
31
238
  return new Promise((resolve, reject) => {