@stevezhou/sisu 0.1.9 → 0.1.11
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/commands.js +61 -2
- package/dist/main.js +11 -0
- package/dist/pager/app.js +99 -9
- package/dist/pager/model.js +6 -0
- package/dist/pager/render.js +18 -23
- package/dist/pager/text.js +40 -0
- package/dist/store.js +1 -0
- package/dist/transport.js +2 -0
- package/dist/tui.js +8 -0
- package/package.json +1 -1
package/dist/commands.js
CHANGED
|
@@ -18,6 +18,10 @@ exports.execCommand = execCommand;
|
|
|
18
18
|
exports.listConversationsCommand = listConversationsCommand;
|
|
19
19
|
exports.openConversationCommand = openConversationCommand;
|
|
20
20
|
exports.setTrainingCommand = setTrainingCommand;
|
|
21
|
+
exports.fetchModelCatalog = fetchModelCatalog;
|
|
22
|
+
exports.resolveCatalogModel = resolveCatalogModel;
|
|
23
|
+
exports.listModelsCommand = listModelsCommand;
|
|
24
|
+
exports.setModelCommand = setModelCommand;
|
|
21
25
|
const child_process_1 = require("child_process");
|
|
22
26
|
const fs_1 = __importDefault(require("fs"));
|
|
23
27
|
const path_1 = __importDefault(require("path"));
|
|
@@ -274,7 +278,7 @@ async function execCommand(prompt, options = {}, http = http_1.defaultHttp) {
|
|
|
274
278
|
headers: (0, http_1.authHeaders)(auth.token),
|
|
275
279
|
body: JSON.stringify({
|
|
276
280
|
title: text.slice(0, 50),
|
|
277
|
-
model: options.model || undefined,
|
|
281
|
+
model: options.model || (0, store_1.readSession)().last_model || undefined,
|
|
278
282
|
project_id: options.projectId || (0, store_1.readSession)().last_project_id || undefined,
|
|
279
283
|
client: stamp.client,
|
|
280
284
|
client_version: stamp.client_version,
|
|
@@ -293,7 +297,7 @@ async function execCommand(prompt, options = {}, http = http_1.defaultHttp) {
|
|
|
293
297
|
body: JSON.stringify({
|
|
294
298
|
conversation_id: conversationId,
|
|
295
299
|
message: text,
|
|
296
|
-
model: options.model || undefined,
|
|
300
|
+
model: options.model || (0, store_1.readSession)().last_model || undefined,
|
|
297
301
|
task_category: 'coding',
|
|
298
302
|
client: stamp.client,
|
|
299
303
|
client_version: stamp.client_version,
|
|
@@ -348,3 +352,58 @@ async function setTrainingCommand(optIn, http = http_1.defaultHttp) {
|
|
|
348
352
|
throw new Error((0, http_1.errorDetail)(body, `training update failed (${response.status})`));
|
|
349
353
|
return optIn ? 'training opt-in on (new turns may be used if eligible)' : 'training opt-in off';
|
|
350
354
|
}
|
|
355
|
+
function normalizeModelKey(value) {
|
|
356
|
+
return value.toLowerCase().replace(/[-_.\s]/g, '');
|
|
357
|
+
}
|
|
358
|
+
async function fetchModelCatalog(http = http_1.defaultHttp) {
|
|
359
|
+
const auth = (0, store_1.requireAuth)();
|
|
360
|
+
const response = await http(`${auth.api_base}/api/chat/models`, { headers: (0, http_1.authHeaders)(auth.token) });
|
|
361
|
+
const body = await response.json().catch(() => ({}));
|
|
362
|
+
if (!response.ok)
|
|
363
|
+
throw new Error((0, http_1.errorDetail)(body, `models failed (${response.status})`));
|
|
364
|
+
const rows = Array.isArray(body?.models) ? body.models : [];
|
|
365
|
+
const models = rows
|
|
366
|
+
.map((row) => {
|
|
367
|
+
const name = String(row?.name || '').trim();
|
|
368
|
+
if (!name)
|
|
369
|
+
return null;
|
|
370
|
+
return { name, label: String(row.display_name || row.label || name) };
|
|
371
|
+
})
|
|
372
|
+
.filter((row) => Boolean(row));
|
|
373
|
+
return { models, defaultModel: String(body?.default_model || '') };
|
|
374
|
+
}
|
|
375
|
+
function resolveCatalogModel(query, models) {
|
|
376
|
+
const needle = normalizeModelKey(query);
|
|
377
|
+
if (!needle)
|
|
378
|
+
return undefined;
|
|
379
|
+
return (models.find((row) => normalizeModelKey(row.name) === needle) ||
|
|
380
|
+
models.find((row) => normalizeModelKey(row.label) === needle) ||
|
|
381
|
+
models.find((row) => normalizeModelKey(row.name).includes(needle) || normalizeModelKey(row.label).includes(needle)));
|
|
382
|
+
}
|
|
383
|
+
async function listModelsCommand(http = http_1.defaultHttp) {
|
|
384
|
+
const { models, defaultModel } = await fetchModelCatalog(http);
|
|
385
|
+
const current = (0, store_1.readSession)().last_model || defaultModel;
|
|
386
|
+
if (!current && !models.length)
|
|
387
|
+
return 'no models available';
|
|
388
|
+
const lines = models.map((row) => {
|
|
389
|
+
const mark = row.name === current ? '* ' : ' ';
|
|
390
|
+
const extra = row.label !== row.name ? ` ${row.label}` : '';
|
|
391
|
+
return `${mark}${row.name}${extra}`;
|
|
392
|
+
});
|
|
393
|
+
if (current && !models.some((row) => row.name === current)) {
|
|
394
|
+
lines.unshift(`* ${current}`);
|
|
395
|
+
}
|
|
396
|
+
return lines.join('\n') || `* ${current}`;
|
|
397
|
+
}
|
|
398
|
+
async function setModelCommand(query, http = http_1.defaultHttp) {
|
|
399
|
+
const wanted = query.trim();
|
|
400
|
+
if (!wanted)
|
|
401
|
+
return listModelsCommand(http);
|
|
402
|
+
const { models, defaultModel } = await fetchModelCatalog(http);
|
|
403
|
+
const match = resolveCatalogModel(wanted, models);
|
|
404
|
+
const name = match?.name || (normalizeModelKey(wanted) === normalizeModelKey(defaultModel) ? defaultModel : '');
|
|
405
|
+
if (!name)
|
|
406
|
+
throw new Error(`unknown model ${wanted}`);
|
|
407
|
+
(0, store_1.writeSession)({ ...(0, store_1.readSession)(), last_model: name });
|
|
408
|
+
return `model ${name}`;
|
|
409
|
+
}
|
package/dist/main.js
CHANGED
|
@@ -25,6 +25,8 @@ Usage:
|
|
|
25
25
|
sisu open <dir> --project <project-id>
|
|
26
26
|
sisu ls [--project <project-id>]
|
|
27
27
|
sisu exec "<prompt>" [--project <id>] [--model <name>] [--new]
|
|
28
|
+
sisu models
|
|
29
|
+
sisu model <name>
|
|
28
30
|
sisu history
|
|
29
31
|
sisu thread <conversation-id>
|
|
30
32
|
sisu training --on|--off
|
|
@@ -146,6 +148,15 @@ async function runCli(argv, deps = {}) {
|
|
|
146
148
|
process.stdout.write(`${(0, commands_1.openConversationCommand)(id)}\n`);
|
|
147
149
|
return 0;
|
|
148
150
|
}
|
|
151
|
+
if (command === 'models') {
|
|
152
|
+
process.stdout.write(`${await (0, commands_1.listModelsCommand)(http)}\n`);
|
|
153
|
+
return 0;
|
|
154
|
+
}
|
|
155
|
+
if (command === 'model') {
|
|
156
|
+
const name = args.find((item) => !item.startsWith('--')) || '';
|
|
157
|
+
process.stdout.write(`${await (0, commands_1.setModelCommand)(name, http)}\n`);
|
|
158
|
+
return 0;
|
|
159
|
+
}
|
|
149
160
|
if (command === 'training') {
|
|
150
161
|
if (args.includes('--on')) {
|
|
151
162
|
process.stdout.write(`${await (0, commands_1.setTrainingCommand)(true)}\n`);
|
package/dist/pager/app.js
CHANGED
|
@@ -1,28 +1,42 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.formatChromeStatus = formatChromeStatus;
|
|
4
7
|
exports.chromeShortQuota = chromeShortQuota;
|
|
5
8
|
exports.runPager = runPager;
|
|
9
|
+
const fs_1 = __importDefault(require("fs"));
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
6
11
|
const store_1 = require("../store");
|
|
7
12
|
const input_1 = require("./input");
|
|
8
13
|
const model_1 = require("./model");
|
|
9
14
|
const history_1 = require("./history");
|
|
10
15
|
const logo_1 = require("../logo");
|
|
16
|
+
const text_1 = require("./text");
|
|
11
17
|
const render_1 = require("./render");
|
|
12
18
|
const ALT_ENTER = '\x1b[?1049h\x1b[?25l';
|
|
13
19
|
const ALT_LEAVE = '\x1b[?1049l\x1b[?25h';
|
|
14
|
-
function
|
|
20
|
+
function shortConversationId(id) {
|
|
21
|
+
const conv = (id || '').trim();
|
|
22
|
+
if (!conv || conv === 'new')
|
|
23
|
+
return '';
|
|
24
|
+
return conv.length > 12 ? conv.slice(0, 8) : conv;
|
|
25
|
+
}
|
|
26
|
+
function formatChromeStatus(email, quota, conversationId = '', model = '') {
|
|
15
27
|
const who = (email || '').trim();
|
|
28
|
+
const conv = shortConversationId(conversationId);
|
|
29
|
+
const modelName = (model || '').trim();
|
|
16
30
|
if (!who) {
|
|
17
|
-
|
|
18
|
-
return conv && conv !== 'new' ? `sisu · not signed in · ${conv}` : 'sisu · not signed in';
|
|
31
|
+
return conv ? `sisu · not signed in · ${conv}` : 'sisu · not signed in';
|
|
19
32
|
}
|
|
20
33
|
const parts = [who];
|
|
34
|
+
if (modelName)
|
|
35
|
+
parts.push(modelName);
|
|
21
36
|
const quotaText = (quota || '').trim();
|
|
22
37
|
if (quotaText && quotaText !== 'quota unavailable')
|
|
23
38
|
parts.push(quotaText);
|
|
24
|
-
|
|
25
|
-
if (conv && conv !== 'new')
|
|
39
|
+
if (conv)
|
|
26
40
|
parts.push(conv);
|
|
27
41
|
return parts.join(' · ');
|
|
28
42
|
}
|
|
@@ -69,6 +83,8 @@ function commandHead(text) {
|
|
|
69
83
|
return '/new';
|
|
70
84
|
if (token === '/history')
|
|
71
85
|
return '/resume';
|
|
86
|
+
if (token === '/m')
|
|
87
|
+
return '/model';
|
|
72
88
|
return token;
|
|
73
89
|
}
|
|
74
90
|
async function resolveText(value) {
|
|
@@ -80,9 +96,10 @@ async function runPager(io, transport, options = {}) {
|
|
|
80
96
|
let theme = options.theme ?? 'dark';
|
|
81
97
|
let quotaLine = 'quota unavailable';
|
|
82
98
|
let chromeEmail = (options.email || '').trim();
|
|
99
|
+
let chromeModel = ((0, store_1.readSession)().last_model || '').trim();
|
|
83
100
|
const withChrome = (next) => ({
|
|
84
101
|
...next,
|
|
85
|
-
statusLine: formatChromeStatus(chromeEmail, quotaLine, next.conversationId),
|
|
102
|
+
statusLine: formatChromeStatus(chromeEmail, quotaLine, next.conversationId, chromeModel),
|
|
86
103
|
});
|
|
87
104
|
const refreshQuota = async () => {
|
|
88
105
|
if (!options.quota)
|
|
@@ -211,24 +228,24 @@ async function runPager(io, transport, options = {}) {
|
|
|
211
228
|
paint();
|
|
212
229
|
return;
|
|
213
230
|
}
|
|
214
|
-
state =
|
|
231
|
+
state = { ...state, statusLine: 'Opening browser to sign in…' };
|
|
215
232
|
paint();
|
|
216
233
|
try {
|
|
217
234
|
const email = await options.login((line) => {
|
|
218
235
|
if (!running)
|
|
219
236
|
return;
|
|
220
|
-
state =
|
|
237
|
+
state = { ...state, statusLine: line };
|
|
221
238
|
paint();
|
|
222
239
|
});
|
|
223
240
|
if (!running)
|
|
224
241
|
return;
|
|
225
242
|
chromeEmail = email;
|
|
226
243
|
state = withChrome(state);
|
|
227
|
-
state = pushEntry(state, 'status', `logged in as ${email}`);
|
|
228
244
|
}
|
|
229
245
|
catch (err) {
|
|
230
246
|
if (!running)
|
|
231
247
|
return;
|
|
248
|
+
state = withChrome(state);
|
|
232
249
|
state = pushEntry(state, 'status', err instanceof Error ? err.message : String(err));
|
|
233
250
|
}
|
|
234
251
|
paint();
|
|
@@ -290,6 +307,79 @@ async function runPager(io, transport, options = {}) {
|
|
|
290
307
|
paint();
|
|
291
308
|
return;
|
|
292
309
|
}
|
|
310
|
+
if (head === '/logout') {
|
|
311
|
+
options.logout?.();
|
|
312
|
+
chromeEmail = '';
|
|
313
|
+
chromeModel = '';
|
|
314
|
+
state = withChrome(state);
|
|
315
|
+
state = pushEntry(state, 'status', 'signed out');
|
|
316
|
+
paint();
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
if (head === '/models' || (head === '/model' && !text.replace(/^\S+\s*/, '').trim())) {
|
|
320
|
+
const body = options.models ? await resolveText(options.models()) : 'not wired';
|
|
321
|
+
if (!running)
|
|
322
|
+
return;
|
|
323
|
+
state = pushEntry(state, 'status', body);
|
|
324
|
+
paint();
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
if (head === '/model') {
|
|
328
|
+
const wanted = text.replace(/^\S+\s*/, '').trim();
|
|
329
|
+
if (!options.setModel) {
|
|
330
|
+
state = pushEntry(state, 'status', 'not wired');
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
try {
|
|
334
|
+
const body = await resolveText(options.setModel(wanted));
|
|
335
|
+
if (!running)
|
|
336
|
+
return;
|
|
337
|
+
chromeModel = ((0, store_1.readSession)().last_model || wanted).trim();
|
|
338
|
+
state = withChrome(state);
|
|
339
|
+
state = pushEntry(state, 'status', body);
|
|
340
|
+
}
|
|
341
|
+
catch (err) {
|
|
342
|
+
if (!running)
|
|
343
|
+
return;
|
|
344
|
+
state = pushEntry(state, 'status', err instanceof Error ? err.message : String(err));
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
paint();
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
if (head === '/copy') {
|
|
351
|
+
const last = [...state.entries].reverse().find((entry) => entry.kind === 'assistant');
|
|
352
|
+
const body = last ? (0, text_1.visibleAssistantText)(last.text).trim() : '';
|
|
353
|
+
if (!body) {
|
|
354
|
+
state = pushEntry(state, 'status', 'nothing to copy');
|
|
355
|
+
}
|
|
356
|
+
else {
|
|
357
|
+
const dest = path_1.default.join((0, store_1.getSisuHome)(), 'last-copy.txt');
|
|
358
|
+
fs_1.default.mkdirSync((0, store_1.getSisuHome)(), { recursive: true });
|
|
359
|
+
fs_1.default.writeFileSync(dest, `${body}\n`, 'utf8');
|
|
360
|
+
state = pushEntry(state, 'status', `copied to ${dest}`);
|
|
361
|
+
}
|
|
362
|
+
paint();
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
if (head === '/export') {
|
|
366
|
+
const dest = text.replace(/^\S+\s*/, '').trim() || path_1.default.join((0, store_1.getSisuHome)(), 'export.md');
|
|
367
|
+
const body = state.entries
|
|
368
|
+
.map((entry) => {
|
|
369
|
+
if (entry.kind === 'user')
|
|
370
|
+
return `## You\n\n${entry.text}`;
|
|
371
|
+
if (entry.kind === 'assistant')
|
|
372
|
+
return `## SiSu\n\n${(0, text_1.visibleAssistantText)(entry.text)}`;
|
|
373
|
+
return '';
|
|
374
|
+
})
|
|
375
|
+
.filter(Boolean)
|
|
376
|
+
.join('\n\n');
|
|
377
|
+
fs_1.default.mkdirSync(path_1.default.dirname(path_1.default.resolve(dest)), { recursive: true });
|
|
378
|
+
fs_1.default.writeFileSync(path_1.default.resolve(dest), `${body}\n`, 'utf8');
|
|
379
|
+
state = pushEntry(state, 'status', `exported ${path_1.default.resolve(dest)}`);
|
|
380
|
+
paint();
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
293
383
|
if (head === '/status') {
|
|
294
384
|
const body = options.status ? await resolveText(options.status()) : 'not wired';
|
|
295
385
|
if (!running)
|
package/dist/pager/model.js
CHANGED
|
@@ -9,8 +9,13 @@ exports.appendText = appendText;
|
|
|
9
9
|
exports.applyKey = applyKey;
|
|
10
10
|
exports.SLASH_COMMANDS = [
|
|
11
11
|
{ name: '/login', hint: 'Sign in with the browser' },
|
|
12
|
+
{ name: '/logout', hint: 'Sign out of this terminal' },
|
|
12
13
|
{ name: '/new', hint: 'Start a new conversation (alias: /clear)' },
|
|
13
14
|
{ name: '/resume', hint: 'Resume a conversation (alias: /history)' },
|
|
15
|
+
{ name: '/model', hint: 'Switch model (alias: /m)' },
|
|
16
|
+
{ name: '/models', hint: 'List models available to your account' },
|
|
17
|
+
{ name: '/copy', hint: 'Copy the last assistant reply' },
|
|
18
|
+
{ name: '/export', hint: 'Write this conversation to a markdown file' },
|
|
14
19
|
{ name: '/status', hint: 'Show session status' },
|
|
15
20
|
{ name: '/ls', hint: 'List local workspace files' },
|
|
16
21
|
{ name: '/training', hint: 'Training mode' },
|
|
@@ -23,6 +28,7 @@ const SLASH_ALIASES = {
|
|
|
23
28
|
'/clear': '/new',
|
|
24
29
|
'/history': '/resume',
|
|
25
30
|
'/exit': '/quit',
|
|
31
|
+
'/m': '/model',
|
|
26
32
|
};
|
|
27
33
|
let nextEntryId = 1;
|
|
28
34
|
function entryId() {
|
package/dist/pager/render.js
CHANGED
|
@@ -7,25 +7,13 @@ const mobius_1 = require("../mobius");
|
|
|
7
7
|
const model_1 = require("./model");
|
|
8
8
|
const theme_1 = require("./theme");
|
|
9
9
|
Object.defineProperty(exports, "stripAnsi", { enumerable: true, get: function () { return theme_1.stripAnsi; } });
|
|
10
|
+
const text_1 = require("./text");
|
|
10
11
|
const PROMPT_PREFIX = '› ';
|
|
11
12
|
const PROMPT_BOX_ROWS = 2;
|
|
12
13
|
const STATUS_ROWS = 1;
|
|
13
14
|
const MARK_WIDTH = 2;
|
|
14
15
|
function wrapPlain(text, width) {
|
|
15
|
-
|
|
16
|
-
if (!text)
|
|
17
|
-
return [''];
|
|
18
|
-
const out = [];
|
|
19
|
-
for (const paragraph of text.split('\n')) {
|
|
20
|
-
if (!paragraph) {
|
|
21
|
-
out.push('');
|
|
22
|
-
continue;
|
|
23
|
-
}
|
|
24
|
-
for (let i = 0; i < paragraph.length; i += max) {
|
|
25
|
-
out.push(paragraph.slice(i, i + max));
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
return out;
|
|
16
|
+
return (0, text_1.wrapCells)(text, width);
|
|
29
17
|
}
|
|
30
18
|
function lineCount(text) {
|
|
31
19
|
if (!text)
|
|
@@ -43,22 +31,25 @@ function paintKind(kind, body, theme) {
|
|
|
43
31
|
return theme.dim(body);
|
|
44
32
|
return theme.text(body);
|
|
45
33
|
}
|
|
46
|
-
function
|
|
47
|
-
if (kind === '
|
|
48
|
-
return
|
|
49
|
-
|
|
50
|
-
return 'tool ';
|
|
51
|
-
return '';
|
|
34
|
+
function shownText(entry) {
|
|
35
|
+
if (entry.kind === 'assistant')
|
|
36
|
+
return (0, text_1.visibleAssistantText)(entry.text);
|
|
37
|
+
return entry.text;
|
|
52
38
|
}
|
|
53
39
|
function entryBodyLines(entry, wrapWidth) {
|
|
40
|
+
const text = shownText(entry);
|
|
54
41
|
if (entry.folded) {
|
|
55
|
-
const n = lineCount(
|
|
42
|
+
const n = lineCount(text);
|
|
56
43
|
const unit = n === 1 ? 'line' : 'lines';
|
|
57
44
|
return wrapPlain(`${entry.kind} · ${n} ${unit}`, wrapWidth);
|
|
58
45
|
}
|
|
59
|
-
if (
|
|
46
|
+
if (entry.kind === 'user')
|
|
47
|
+
return ['You', ...wrapPlain(text || ' ', wrapWidth)];
|
|
48
|
+
if (entry.kind === 'tool')
|
|
49
|
+
return wrapPlain(text ? `tool ${text}` : 'tool', wrapWidth);
|
|
50
|
+
if (!text)
|
|
60
51
|
return [''];
|
|
61
|
-
return wrapPlain(
|
|
52
|
+
return wrapPlain(text, wrapWidth);
|
|
62
53
|
}
|
|
63
54
|
function layoutScrollback(state, cols, theme) {
|
|
64
55
|
const wrapWidth = Math.max(1, cols - MARK_WIDTH);
|
|
@@ -68,6 +59,10 @@ function layoutScrollback(state, cols, theme) {
|
|
|
68
59
|
const entry = state.entries[i];
|
|
69
60
|
const body = entryBodyLines(entry, wrapWidth);
|
|
70
61
|
const selected = i === state.selected && state.entries.length > 0;
|
|
62
|
+
if (i > 0) {
|
|
63
|
+
lines.push('');
|
|
64
|
+
entryOf.push(i);
|
|
65
|
+
}
|
|
71
66
|
for (let j = 0; j < body.length; j += 1) {
|
|
72
67
|
const mark = selected && j === 0 ? theme.accent('▸ ') : ' ';
|
|
73
68
|
lines.push(`${mark}${paintKind(entry.kind, body[j], theme)}`);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/** Display-side text: hide model scratch and wrap by terminal cells. */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.visibleAssistantText = visibleAssistantText;
|
|
5
|
+
exports.wrapCells = wrapCells;
|
|
6
|
+
const theme_1 = require("./theme");
|
|
7
|
+
const THINK_BLOCK = /<think\b[^>]*>[\s\S]*?<\/think>/gi;
|
|
8
|
+
const THINK_OPEN = /<think\b[^>]*>[\s\S]*$/i;
|
|
9
|
+
function visibleAssistantText(raw) {
|
|
10
|
+
let text = String(raw || '');
|
|
11
|
+
text = text.replace(THINK_BLOCK, '');
|
|
12
|
+
text = text.replace(THINK_OPEN, '');
|
|
13
|
+
return text.replace(/^\n+/, '').replace(/\n+$/, '');
|
|
14
|
+
}
|
|
15
|
+
function wrapCells(text, width) {
|
|
16
|
+
const max = Math.max(1, width);
|
|
17
|
+
if (!text)
|
|
18
|
+
return [''];
|
|
19
|
+
const out = [];
|
|
20
|
+
for (const paragraph of text.split('\n')) {
|
|
21
|
+
if (!paragraph) {
|
|
22
|
+
out.push('');
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
let line = '';
|
|
26
|
+
for (const ch of paragraph) {
|
|
27
|
+
if ((0, theme_1.visibleWidth)(line + ch) > max) {
|
|
28
|
+
if (line)
|
|
29
|
+
out.push(line);
|
|
30
|
+
line = ch;
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
line += ch;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (line)
|
|
37
|
+
out.push(line);
|
|
38
|
+
}
|
|
39
|
+
return out.length ? out : [''];
|
|
40
|
+
}
|
package/dist/store.js
CHANGED
package/dist/transport.js
CHANGED
|
@@ -64,6 +64,7 @@ function createFastApiTransport(http) {
|
|
|
64
64
|
headers: (0, http_1.authHeaders)(auth.token),
|
|
65
65
|
body: JSON.stringify({
|
|
66
66
|
title: text.slice(0, 50),
|
|
67
|
+
model: session.last_model || undefined,
|
|
67
68
|
project_id: session.last_project_id || undefined,
|
|
68
69
|
client: stamp.client,
|
|
69
70
|
client_version: stamp.client_version,
|
|
@@ -87,6 +88,7 @@ function createFastApiTransport(http) {
|
|
|
87
88
|
body: JSON.stringify({
|
|
88
89
|
conversation_id: conversationId,
|
|
89
90
|
message: text,
|
|
91
|
+
model: session.last_model || undefined,
|
|
90
92
|
task_category: 'coding',
|
|
91
93
|
client: stamp.client,
|
|
92
94
|
client_version: stamp.client_version,
|
package/dist/tui.js
CHANGED
|
@@ -171,6 +171,11 @@ async function promptLogin(io, login) {
|
|
|
171
171
|
function tuiHelp() {
|
|
172
172
|
return [
|
|
173
173
|
'/login sign in with the browser',
|
|
174
|
+
'/logout sign out',
|
|
175
|
+
'/model switch model (alias /m)',
|
|
176
|
+
'/models list available models',
|
|
177
|
+
'/copy copy last reply to ~/.sisu/last-copy.txt',
|
|
178
|
+
'/export write the thread to a markdown file',
|
|
174
179
|
'/status account and quota',
|
|
175
180
|
'/ls local workspace files',
|
|
176
181
|
'/history saved cloud conversations',
|
|
@@ -224,6 +229,9 @@ async function runTui(io, deps = {}) {
|
|
|
224
229
|
columns,
|
|
225
230
|
email: account?.email,
|
|
226
231
|
login: startWebLogin,
|
|
232
|
+
logout: commands_1.logoutCommand,
|
|
233
|
+
models: () => (0, commands_1.listModelsCommand)(http),
|
|
234
|
+
setModel: (name) => (0, commands_1.setModelCommand)(name, http),
|
|
227
235
|
intro: animate,
|
|
228
236
|
sleep: deps.sleep,
|
|
229
237
|
quota: async () => (0, commands_1.formatQuota)(await (0, commands_1.fetchBalance)(http)),
|