@stevezhou/sisu 0.1.0 → 0.1.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/dist/logo.js CHANGED
@@ -14,10 +14,7 @@ function sisuMobiusArt(columns = 80, phase = 0, color = false) {
14
14
  });
15
15
  }
16
16
  function sisuWordmark() {
17
- return [
18
- ' 思 溯',
19
- ' S I S U',
20
- ].join('\n');
17
+ return ['思溯', 'SISU'].join('\n');
21
18
  }
22
19
  function sisuBanner(columns = 80, phase = 0, color = false) {
23
20
  return [
package/dist/mobius.js CHANGED
@@ -232,9 +232,9 @@ function renderMobiusFrame(options = {}) {
232
232
  return ch;
233
233
  let [r, g, b] = mobiusRgb(cell.t);
234
234
  const lift = 0.18 + cell.shade * 0.95 + cell.spec * 0.7;
235
- r = clamp(Math.round(r * lift), 0, 255);
236
- g = clamp(Math.round(g * lift), 0, 255);
237
- b = clamp(Math.round(b * lift), 0, 255);
235
+ r = clamp(Number.isFinite(r * lift) ? Math.round(r * lift) : 180, 0, 255);
236
+ g = clamp(Number.isFinite(g * lift) ? Math.round(g * lift) : 180, 0, 255);
237
+ b = clamp(Number.isFinite(b * lift) ? Math.round(b * lift) : 180, 0, 255);
238
238
  return `${ansiRgb(r, g, b)}${ch}${RESET}`;
239
239
  }).join('')).join('\n');
240
240
  }
package/dist/pager/app.js CHANGED
@@ -13,7 +13,7 @@ const ALT_LEAVE = '\x1b[?1049l\x1b[?25h';
13
13
  const CLEAR_HOME = '\x1b[2J\x1b[H';
14
14
  function formatChromeStatus(email, quota, conversationId) {
15
15
  const parts = [
16
- (email || '').trim(),
16
+ (email || '').trim() || 'not logged in',
17
17
  (quota || '').trim() || 'quota unavailable',
18
18
  conversationId || 'new',
19
19
  'client=tui',
@@ -73,9 +73,10 @@ async function runPager(io, transport, options = {}) {
73
73
  const rows = options.rows ?? io.rows;
74
74
  let theme = options.theme ?? 'dark';
75
75
  let quotaLine = 'quota unavailable';
76
+ let chromeEmail = (options.email || '').trim();
76
77
  const withChrome = (next) => ({
77
78
  ...next,
78
- statusLine: formatChromeStatus(options.email, quotaLine, next.conversationId),
79
+ statusLine: formatChromeStatus(chromeEmail, quotaLine, next.conversationId),
79
80
  });
80
81
  const refreshQuota = async () => {
81
82
  if (!options.quota)
@@ -88,6 +89,9 @@ async function runPager(io, transport, options = {}) {
88
89
  }
89
90
  };
90
91
  let state = withChrome((0, model_1.createPagerState)());
92
+ if (!chromeEmail && options.login) {
93
+ state = pushEntry(state, 'status', 'Not logged in. Type /login to sign in with your browser.');
94
+ }
91
95
  let rest = '';
92
96
  let newConversation = false;
93
97
  let pickMode = false;
@@ -185,6 +189,35 @@ async function runPager(io, transport, options = {}) {
185
189
  finish(0);
186
190
  return;
187
191
  }
192
+ if (head === '/login') {
193
+ if (!options.login) {
194
+ state = pushEntry(state, 'status', 'not wired');
195
+ paint();
196
+ return;
197
+ }
198
+ state = pushEntry(state, 'status', 'Opening browser to sign in…');
199
+ paint();
200
+ try {
201
+ const email = await options.login((line) => {
202
+ if (!running)
203
+ return;
204
+ state = pushEntry(state, 'status', line);
205
+ paint();
206
+ });
207
+ if (!running)
208
+ return;
209
+ chromeEmail = email;
210
+ state = withChrome(state);
211
+ state = pushEntry(state, 'status', `logged in as ${email}`);
212
+ }
213
+ catch (err) {
214
+ if (!running)
215
+ return;
216
+ state = pushEntry(state, 'status', err instanceof Error ? err.message : String(err));
217
+ }
218
+ paint();
219
+ return;
220
+ }
188
221
  if (head === '/new') {
189
222
  pickMode = false;
190
223
  pickableIds.clear();
@@ -289,6 +322,12 @@ async function runPager(io, transport, options = {}) {
289
322
  paint();
290
323
  };
291
324
  const sendTurn = async (prompt) => {
325
+ if (!chromeEmail && options.login) {
326
+ state = pushEntry(state, 'status', 'Not logged in. Type /login to sign in.');
327
+ state = clearDraft(state);
328
+ paint();
329
+ return;
330
+ }
292
331
  state = pushEntry(state, 'user', prompt);
293
332
  state = (0, model_1.startAssistant)(state);
294
333
  state = clearDraft(state);
@@ -8,6 +8,7 @@ exports.insertToolBeforeLiveAssistant = insertToolBeforeLiveAssistant;
8
8
  exports.appendText = appendText;
9
9
  exports.applyKey = applyKey;
10
10
  exports.SLASH_COMMANDS = [
11
+ { name: '/login', hint: 'Sign in with the browser' },
11
12
  { name: '/new', hint: 'Start a new conversation (alias: /clear)' },
12
13
  { name: '/resume', hint: 'Resume a conversation (alias: /history)' },
13
14
  { name: '/status', hint: 'Show session status' },
package/dist/tui.js CHANGED
@@ -149,6 +149,7 @@ async function promptLogin(io, login) {
149
149
  }
150
150
  function tuiHelp() {
151
151
  return [
152
+ '/login sign in with the browser',
152
153
  '/status account and quota',
153
154
  '/ls local workspace files',
154
155
  '/history saved cloud conversations',
@@ -169,34 +170,30 @@ async function runTui(io, deps = {}) {
169
170
  const openThread = deps.openThread ?? commands_1.openConversationCommand;
170
171
  const training = deps.training ?? commands_1.setTrainingCommand;
171
172
  const auth = deps.auth ?? store_1.readAuth;
173
+ const webLogin = deps.webLogin ?? commands_1.webLoginCommand;
172
174
  const columns = deps.columns ?? process.stdout.columns ?? 80;
173
175
  const animate = deps.animate ?? shouldAnimateSplash();
174
- const color = deps.color ?? Boolean(process.stdout.isTTY);
175
176
  try {
177
+ io.write(`\n${(0, logo_1.sisuWordmark)()}\n\n`);
176
178
  if (animate) {
177
- await playMobiusIntro(io, { columns, sleep: deps.sleep, color });
178
- }
179
- else {
180
- io.write(`${(0, logo_1.sisuBanner)(columns, 0.35, color)}\n`);
181
- }
182
- let account = auth();
183
- if (!account) {
184
- const login = deps.login ?? commands_1.loginCommand;
185
- const result = await promptLogin(io, login);
186
- if (result !== 'ok')
187
- return 2;
188
- account = auth();
189
- if (!account) {
190
- io.write('login did not persist auth\n');
191
- return 2;
192
- }
179
+ await (deps.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms))))(80);
193
180
  }
181
+ const account = auth();
182
+ const startWebLogin = async (notify) => {
183
+ return webLogin({
184
+ onStart: (info) => {
185
+ notify(`Open ${info.verification_uri_complete}`);
186
+ notify(`Confirm code ${info.user_code}`);
187
+ },
188
+ }, http);
189
+ };
194
190
  if (deps.pager || shouldUsePager(deps)) {
195
191
  io.close?.();
196
192
  const transport = (0, transport_1.createFastApiTransport)(http);
197
193
  return await (deps.pager ?? app_1.runPager)((0, stdio_1.stdioPagerIo)(), transport, {
198
194
  columns,
199
- email: account.email,
195
+ email: account?.email,
196
+ login: startWebLogin,
200
197
  quota: async () => (0, commands_1.formatQuota)(await (0, commands_1.fetchBalance)(http)),
201
198
  status: () => status(http),
202
199
  ls: () => {
@@ -211,12 +208,24 @@ async function runTui(io, deps = {}) {
211
208
  });
212
209
  }
213
210
  io.write(`${await status(http)}\n`);
211
+ if (!account)
212
+ io.write('Not logged in. Type /login to sign in with your browser.\n');
214
213
  io.write(`${tuiHelp()}\n\n`);
215
214
  let newConversation = false;
216
215
  while (true) {
217
216
  const raw = (await io.question('› ')).trim();
218
217
  if (!raw)
219
218
  continue;
219
+ if (raw === '/login') {
220
+ try {
221
+ const email = await startWebLogin((line) => io.write(`${line}\n`));
222
+ io.write(`logged in as ${email}\n`);
223
+ }
224
+ catch (error) {
225
+ io.write(`${error instanceof Error ? error.message : String(error)}\n`);
226
+ }
227
+ continue;
228
+ }
220
229
  if (raw === '/quit' || raw === '/exit') {
221
230
  io.write('bye\n');
222
231
  return 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stevezhou/sisu",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "SiSu CLI — one login, cloud quota, local workspace",
5
5
  "license": "UNLICENSED",
6
6
  "homepage": "https://www.sisu.chat",