@leg3ndy/otto-bridge 1.0.2 → 1.0.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/README.md +18 -8
- package/dist/cli_terminal.js +394 -65
- package/dist/main.js +13 -10
- package/dist/types.js +1 -1
- package/package.json +1 -1
- package/scripts/postinstall.mjs +1 -1
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ Para o estado atual da arquitetura, capacidades entregues, limitacoes e roadmap
|
|
|
15
15
|
|
|
16
16
|
Para o corte de arquitetura do `0.9.0`, veja [`leg3ndy-ai-backend/docs/OTTO_BRIDGE_0_9_0_RELEASE.md`](../leg3ndy-ai-backend/docs/OTTO_BRIDGE_0_9_0_RELEASE.md).
|
|
17
17
|
|
|
18
|
-
Para a release atual `1.0.
|
|
18
|
+
Para a release atual `1.0.4`, com estabilizacao do TTY, pensamento visivel no modo `Thinking` e replay web mais compacto, veja [`leg3ndy-ai-backend/docs/OTTO_BRIDGE_1_0_4_PATCH.md`](../leg3ndy-ai-backend/docs/OTTO_BRIDGE_1_0_4_PATCH.md).
|
|
19
19
|
|
|
20
20
|
## Distribuicao
|
|
21
21
|
|
|
@@ -38,14 +38,14 @@ Enquanto o pacote nao estiver publicado, voce pode gerar um tarball local:
|
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
40
|
npm pack
|
|
41
|
-
npm install -g ./leg3ndy-otto-bridge-1.0.
|
|
41
|
+
npm install -g ./leg3ndy-otto-bridge-1.0.4.tgz
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
Na linha `1.0.
|
|
44
|
+
Na linha `1.0.4`, `playwright` segue como dependencia obrigatoria no `otto-bridge`. O primeiro `npm install -g @leg3ndy/otto-bridge` pode demorar mais porque instala o browser persistente usado pelo WhatsApp Web e pelos fluxos web em background do bridge.
|
|
45
45
|
|
|
46
|
-
No macOS, a linha `1.0.
|
|
46
|
+
No macOS, a linha `1.0.4` usa o provider `macos-helper`, um helper `WKWebView` sem Dock para o WhatsApp Web. O helper sobe com user-agent de Chrome moderno para evitar o bloqueio do WhatsApp ao detectar Safari/WebKit. O runtime antigo com Chromium/Playwright fica disponivel apenas como override explicito via `OTTO_BRIDGE_WHATSAPP_RUNTIME_PROVIDER=embedded-playwright`.
|
|
47
47
|
|
|
48
|
-
No nivel arquitetural, o `0.9.0` marcou a mudanca de papel do bridge: ele publica tools e resultados estruturados para o Otto, em vez de injetar resposta pronta como caminho principal do chat. O `1.0.0` oficializou isso como runtime agentico; o `1.0.
|
|
48
|
+
No nivel arquitetural, o `0.9.0` marcou a mudanca de papel do bridge: ele publica tools e resultados estruturados para o Otto, em vez de injetar resposta pronta como caminho principal do chat. O `1.0.0` oficializou isso como runtime agentico; o `1.0.4` consolida o hub terminal como fluxo principal, estabiliza o TTY do console, deixa o modo `Thinking` visualmente claro e reduz o ruido do replay no modal web.
|
|
49
49
|
|
|
50
50
|
## Publicacao
|
|
51
51
|
|
|
@@ -137,9 +137,19 @@ otto-bridge console
|
|
|
137
137
|
|
|
138
138
|
O console usa a mesma sessão local já ligada pelo `otto-bridge`, envia prompts naturais ao backend usando `device_token`, respeita quota/plano do usuário e só vira handoff local quando o pedido realmente tiver cara de ação no computador. Quando houver `device_job`, ele acompanha polling e resolve `confirm_required` no terminal.
|
|
139
139
|
|
|
140
|
+
Dentro do console, use:
|
|
141
|
+
|
|
142
|
+
- `/model fast` para `OttoAI Fast`
|
|
143
|
+
- `/model thinking` para `OttoAI Thinking`
|
|
144
|
+
- `/status` para ver detalhes técnicos do bridge e do runtime
|
|
145
|
+
|
|
146
|
+
No modo `OttoAI Thinking`, o terminal agora marca explicitamente o trecho de raciocínio com `Pensando (OttoAI Thinking)` e separa esse bloco da resposta final do Otto.
|
|
147
|
+
|
|
148
|
+
Quando o handoff local devolver resultado estruturado, o CLI agora mostra inline a listagem de arquivos e o conteúdo de `read_file`, em vez de só resumir que executou a tarefa.
|
|
149
|
+
|
|
140
150
|
### WhatsApp Web em background
|
|
141
151
|
|
|
142
|
-
Fluxo recomendado na linha `1.0.
|
|
152
|
+
Fluxo recomendado na linha `1.0.4`:
|
|
143
153
|
|
|
144
154
|
```bash
|
|
145
155
|
otto-bridge extensions --install whatsappweb
|
|
@@ -149,13 +159,13 @@ otto-bridge extensions --status whatsappweb
|
|
|
149
159
|
|
|
150
160
|
O setup agora abre o login do WhatsApp Web no helper/background browser do proprio bridge. Depois do QR code, o Otto usa a sessao local em background, sem depender de aba visivel no Safari.
|
|
151
161
|
|
|
152
|
-
Contrato da linha `1.0.
|
|
162
|
+
Contrato da linha `1.0.4`:
|
|
153
163
|
|
|
154
164
|
- `otto-bridge extensions --setup whatsappweb`: autentica a sessao uma vez
|
|
155
165
|
- `otto-bridge`: mantem o browser persistente do WhatsApp vivo em background enquanto o runtime do hub estiver ativo, sem depender de uma aba aberta no Safari
|
|
156
166
|
- ao fechar o `otto-bridge`: o browser em background e desligado, mas a sessao local fica lembrada para o proximo boot
|
|
157
167
|
|
|
158
|
-
## Handoff rapido da linha 1.0.
|
|
168
|
+
## Handoff rapido da linha 1.0.4
|
|
159
169
|
|
|
160
170
|
Ja fechado no codigo:
|
|
161
171
|
|
package/dist/cli_terminal.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { createInterface } from "node:readline/promises";
|
|
3
|
+
import { cursorTo, moveCursor, } from "node:readline";
|
|
3
4
|
import process, { stdin as input, stdout as output } from "node:process";
|
|
4
5
|
import { defaultDeviceName, getBridgeConfigPath, loadBridgeConfig, resolveApiBaseUrl, resolveExecutorConfig, } from "./config.js";
|
|
5
6
|
import { streamDeviceCliChat, } from "./chat_cli_client.js";
|
|
@@ -12,9 +13,12 @@ const ANSI = {
|
|
|
12
13
|
reset: "\u001b[0m",
|
|
13
14
|
dim: "\u001b[2m",
|
|
14
15
|
bold: "\u001b[1m",
|
|
15
|
-
|
|
16
|
+
italic: "\u001b[3m",
|
|
17
|
+
brandBlue: "\u001b[38;2;0;119;208m",
|
|
16
18
|
blue: "\u001b[38;5;111m",
|
|
17
19
|
teal: "\u001b[38;5;80m",
|
|
20
|
+
slate: "\u001b[38;5;245m",
|
|
21
|
+
slateItalic: "\u001b[38;5;245m\u001b[3m",
|
|
18
22
|
amber: "\u001b[38;5;221m",
|
|
19
23
|
red: "\u001b[38;5;203m",
|
|
20
24
|
green: "\u001b[38;5;114m",
|
|
@@ -29,6 +33,22 @@ const OTTOAI_BANNER = [
|
|
|
29
33
|
" ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝",
|
|
30
34
|
];
|
|
31
35
|
const CLI_EXIT_SENTINEL = "__OTTO_BRIDGE_CLI_EXIT__";
|
|
36
|
+
const CLI_MODEL_REGISTRY = {
|
|
37
|
+
fast: {
|
|
38
|
+
label: "OttoAI Fast",
|
|
39
|
+
requestModel: "deepseek-chat",
|
|
40
|
+
aliases: ["fast", "chat", "default", "ottoai fast", "otto fast"],
|
|
41
|
+
},
|
|
42
|
+
thinking: {
|
|
43
|
+
label: "OttoAI Thinking",
|
|
44
|
+
requestModel: "deepseek-reasoner",
|
|
45
|
+
aliases: ["thinking", "reasoner", "think", "ottoai thinking", "otto thinking"],
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
const MAX_RENDERED_LIST_ENTRIES = 28;
|
|
49
|
+
const MAX_RENDERED_LIST_ENTRIES_COMPACT = 10;
|
|
50
|
+
const MAX_RENDERED_FILE_CHARS = 6_000;
|
|
51
|
+
const MAX_RENDERED_FILE_CHARS_COMPACT = 1_400;
|
|
32
52
|
class CliRuntimeSession {
|
|
33
53
|
config;
|
|
34
54
|
runtime = null;
|
|
@@ -100,6 +120,18 @@ class CliRuntimeSession {
|
|
|
100
120
|
});
|
|
101
121
|
await delay(350);
|
|
102
122
|
}
|
|
123
|
+
async waitForReady(timeoutMs = 4500) {
|
|
124
|
+
const startedAt = Date.now();
|
|
125
|
+
for (;;) {
|
|
126
|
+
if (this.status !== "starting") {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
if (Date.now() - startedAt >= timeoutMs) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
await delay(120);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
103
135
|
async replaceConfig(nextConfig) {
|
|
104
136
|
await this.stop();
|
|
105
137
|
this.config = nextConfig;
|
|
@@ -155,16 +187,23 @@ function style(text, color, enabled = true) {
|
|
|
155
187
|
function supportsAnsi() {
|
|
156
188
|
return Boolean(output.isTTY);
|
|
157
189
|
}
|
|
190
|
+
function clearScreen() {
|
|
191
|
+
if (supportsAnsi()) {
|
|
192
|
+
output.write("\u001b[2J\u001b[3J\u001b[H");
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
console.clear();
|
|
196
|
+
}
|
|
158
197
|
function renderBanner() {
|
|
159
198
|
const enabled = supportsAnsi();
|
|
160
|
-
const lines = OTTOAI_BANNER.map((line) => style(line, ANSI.
|
|
199
|
+
const lines = OTTOAI_BANNER.map((line) => style(line, ANSI.brandBlue, enabled));
|
|
161
200
|
const title = `${BRIDGE_PACKAGE_NAME} v${BRIDGE_VERSION}`;
|
|
162
201
|
const subtitle = "Paired local runtime and terminal console";
|
|
163
202
|
return [
|
|
164
203
|
lines.join("\n"),
|
|
165
204
|
"",
|
|
166
|
-
`${style("OTTO BRIDGE", ANSI.
|
|
167
|
-
`${style(subtitle, ANSI.
|
|
205
|
+
`${style("OTTO BRIDGE", ANSI.brandBlue, enabled)} ${style(title, ANSI.white, enabled)}`,
|
|
206
|
+
`${style(subtitle, ANSI.slate, enabled)}`,
|
|
168
207
|
].join("\n");
|
|
169
208
|
}
|
|
170
209
|
function createCliExitError() {
|
|
@@ -182,11 +221,14 @@ function isReadlineClosedError(error) {
|
|
|
182
221
|
}
|
|
183
222
|
function printSection(title) {
|
|
184
223
|
const enabled = supportsAnsi();
|
|
185
|
-
console.log(`\n${style(title, ANSI.
|
|
224
|
+
console.log(`\n${style(title, ANSI.brandBlue, enabled)}`);
|
|
186
225
|
}
|
|
187
226
|
function printMuted(message) {
|
|
188
227
|
console.log(style(message, ANSI.dim, supportsAnsi()));
|
|
189
228
|
}
|
|
229
|
+
function printSoft(message) {
|
|
230
|
+
console.log(style(message, ANSI.slateItalic, supportsAnsi()));
|
|
231
|
+
}
|
|
190
232
|
function printSuccess(message) {
|
|
191
233
|
console.log(style(message, ANSI.green, supportsAnsi()));
|
|
192
234
|
}
|
|
@@ -206,6 +248,40 @@ function truncate(text, max = 180) {
|
|
|
206
248
|
}
|
|
207
249
|
return `${value.slice(0, Math.max(0, max - 1)).trimEnd()}…`;
|
|
208
250
|
}
|
|
251
|
+
function humanFileSize(value) {
|
|
252
|
+
const size = typeof value === "number" ? value : Number(value);
|
|
253
|
+
if (!Number.isFinite(size) || size < 0) {
|
|
254
|
+
return "";
|
|
255
|
+
}
|
|
256
|
+
if (size < 1024) {
|
|
257
|
+
return `${size} B`;
|
|
258
|
+
}
|
|
259
|
+
if (size < 1024 * 1024) {
|
|
260
|
+
return `${(size / 1024).toFixed(1)} KB`;
|
|
261
|
+
}
|
|
262
|
+
if (size < 1024 * 1024 * 1024) {
|
|
263
|
+
return `${(size / (1024 * 1024)).toFixed(1)} MB`;
|
|
264
|
+
}
|
|
265
|
+
return `${(size / (1024 * 1024 * 1024)).toFixed(1)} GB`;
|
|
266
|
+
}
|
|
267
|
+
function getCliModelLabel(mode) {
|
|
268
|
+
return CLI_MODEL_REGISTRY[mode].label;
|
|
269
|
+
}
|
|
270
|
+
function getCliModelRequestModel(mode) {
|
|
271
|
+
return CLI_MODEL_REGISTRY[mode].requestModel;
|
|
272
|
+
}
|
|
273
|
+
export function resolveCliModelMode(value) {
|
|
274
|
+
const normalized = normalizeText(value).toLowerCase();
|
|
275
|
+
if (!normalized) {
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
for (const [mode, definition] of Object.entries(CLI_MODEL_REGISTRY)) {
|
|
279
|
+
if (definition.aliases.includes(normalized)) {
|
|
280
|
+
return mode;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
209
285
|
function delay(ms) {
|
|
210
286
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
211
287
|
}
|
|
@@ -234,7 +310,7 @@ async function question(rl, prompt) {
|
|
|
234
310
|
async function ask(rl, label, options) {
|
|
235
311
|
const defaultValue = normalizeText(options?.defaultValue);
|
|
236
312
|
const suffix = defaultValue ? ` ${style(`[${defaultValue}]`, ANSI.dim, supportsAnsi())}` : "";
|
|
237
|
-
const answer = normalizeText(await question(rl, `${style("›", ANSI.
|
|
313
|
+
const answer = normalizeText(await question(rl, `${style("›", ANSI.brandBlue, supportsAnsi())} ${label}${suffix}: `));
|
|
238
314
|
if (answer) {
|
|
239
315
|
return answer;
|
|
240
316
|
}
|
|
@@ -247,7 +323,7 @@ async function ask(rl, label, options) {
|
|
|
247
323
|
return await ask(rl, label, options);
|
|
248
324
|
}
|
|
249
325
|
async function askYesNo(rl, promptText, defaultValue = true) {
|
|
250
|
-
const answer = normalizeText(await question(rl, `${style("?", ANSI.
|
|
326
|
+
const answer = normalizeText(await question(rl, `${style("?", ANSI.brandBlue, supportsAnsi())} ${promptText} ${style(defaultValue ? "[Y/n]" : "[y/N]", ANSI.dim, supportsAnsi())}: `)).toLowerCase();
|
|
251
327
|
if (!answer) {
|
|
252
328
|
return defaultValue;
|
|
253
329
|
}
|
|
@@ -259,8 +335,8 @@ async function pauseForEnter(rl, message = "Pressione Enter para continuar") {
|
|
|
259
335
|
async function chooseExecutor(rl, current) {
|
|
260
336
|
const defaultType = current?.type || resolveExecutorConfig().type;
|
|
261
337
|
console.log([
|
|
262
|
-
`${style("1.", ANSI.
|
|
263
|
-
`${style("2.", ANSI.
|
|
338
|
+
`${style("1.", ANSI.brandBlue, supportsAnsi())} native-macos ${style("(Mac real, runtime local)", ANSI.dim, supportsAnsi())}`,
|
|
339
|
+
`${style("2.", ANSI.brandBlue, supportsAnsi())} mock ${style("(ambiente de teste)", ANSI.dim, supportsAnsi())}`,
|
|
264
340
|
].join("\n"));
|
|
265
341
|
const selection = await ask(rl, "Executor", {
|
|
266
342
|
defaultValue: defaultType === "mock" ? "2" : "1",
|
|
@@ -322,16 +398,16 @@ function extractConfirmationPrompt(job) {
|
|
|
322
398
|
}
|
|
323
399
|
function renderStatusOverview(config, runtimeSession) {
|
|
324
400
|
return [
|
|
325
|
-
`${style("Device", ANSI.
|
|
326
|
-
`${style("Device ID", ANSI.
|
|
327
|
-
`${style("API", ANSI.
|
|
328
|
-
`${style("Executor", ANSI.
|
|
329
|
-
`${style("Approval", ANSI.
|
|
330
|
-
`${style("Runtime", ANSI.
|
|
401
|
+
`${style("Device", ANSI.brandBlue, supportsAnsi())}: ${config.deviceName}`,
|
|
402
|
+
`${style("Device ID", ANSI.brandBlue, supportsAnsi())}: ${config.deviceId}`,
|
|
403
|
+
`${style("API", ANSI.brandBlue, supportsAnsi())}: ${config.apiBaseUrl}`,
|
|
404
|
+
`${style("Executor", ANSI.brandBlue, supportsAnsi())}: ${config.executor.type}`,
|
|
405
|
+
`${style("Approval", ANSI.brandBlue, supportsAnsi())}: ${config.approvalMode}`,
|
|
406
|
+
`${style("Runtime", ANSI.brandBlue, supportsAnsi())}: ${runtimeSession?.getStatusLabel() || "offline"}`,
|
|
331
407
|
...(runtimeSession?.getStatusDetail()
|
|
332
|
-
? [`${style("Runtime note", ANSI.
|
|
408
|
+
? [`${style("Runtime note", ANSI.brandBlue, supportsAnsi())}: ${runtimeSession.getStatusDetail()}`]
|
|
333
409
|
: []),
|
|
334
|
-
`${style("Config", ANSI.
|
|
410
|
+
`${style("Config", ANSI.brandBlue, supportsAnsi())}: ${getBridgeConfigPath()}`,
|
|
335
411
|
];
|
|
336
412
|
}
|
|
337
413
|
function renderRuntimeHeadline(runtimeSession) {
|
|
@@ -356,49 +432,228 @@ function renderRuntimeHeadline(runtimeSession) {
|
|
|
356
432
|
function padRight(text, width) {
|
|
357
433
|
return text.length >= width ? text : `${text}${" ".repeat(width - text.length)}`;
|
|
358
434
|
}
|
|
435
|
+
function styleCardLine(line, tone, enabled) {
|
|
436
|
+
if (!enabled) {
|
|
437
|
+
return line;
|
|
438
|
+
}
|
|
439
|
+
if (tone === "title") {
|
|
440
|
+
return `${ANSI.bold}${ANSI.brandBlue}${line}${ANSI.reset}`;
|
|
441
|
+
}
|
|
442
|
+
if (tone === "muted") {
|
|
443
|
+
return `${ANSI.slateItalic}${line}${ANSI.reset}`;
|
|
444
|
+
}
|
|
445
|
+
return `${ANSI.white}${line}${ANSI.reset}`;
|
|
446
|
+
}
|
|
359
447
|
function renderInfoCard(lines) {
|
|
360
|
-
const
|
|
361
|
-
const
|
|
448
|
+
const enabled = supportsAnsi();
|
|
449
|
+
const normalized = lines.map((line) => ({
|
|
450
|
+
text: truncate(line.text, 82),
|
|
451
|
+
tone: line.tone,
|
|
452
|
+
}));
|
|
453
|
+
const width = Math.max(44, ...normalized.map((line) => line.text.length));
|
|
454
|
+
const top = style(`┌${"─".repeat(width + 2)}┐`, ANSI.brandBlue, enabled);
|
|
455
|
+
const bottom = style(`└${"─".repeat(width + 2)}┘`, ANSI.brandBlue, enabled);
|
|
362
456
|
return [
|
|
363
|
-
|
|
364
|
-
...normalized.map((line) =>
|
|
365
|
-
|
|
457
|
+
top,
|
|
458
|
+
...normalized.map((line) => {
|
|
459
|
+
const border = style("│", ANSI.brandBlue, enabled);
|
|
460
|
+
const content = styleCardLine(padRight(line.text, width), line.tone, enabled);
|
|
461
|
+
return `${border} ${content} ${border}`;
|
|
462
|
+
}),
|
|
463
|
+
bottom,
|
|
366
464
|
].join("\n");
|
|
367
465
|
}
|
|
368
|
-
function
|
|
369
|
-
|
|
466
|
+
function buildWelcomeCard(runtimeSession, modelMode) {
|
|
467
|
+
return [
|
|
468
|
+
{ text: "Welcome to OttoAI", tone: "title" },
|
|
469
|
+
{ text: "", tone: "muted" },
|
|
470
|
+
{ text: "/help inside the console, /status for bridge details", tone: "muted" },
|
|
471
|
+
{ text: "", tone: "muted" },
|
|
472
|
+
{ text: `model: ${getCliModelLabel(modelMode)}`, tone: "muted" },
|
|
473
|
+
{ text: `cwd: ${process.cwd()}`, tone: "muted" },
|
|
474
|
+
{ text: renderRuntimeHeadline(runtimeSession), tone: "muted" },
|
|
475
|
+
];
|
|
476
|
+
}
|
|
477
|
+
function printHubScreen(runtimeSession, modelMode) {
|
|
478
|
+
clearScreen();
|
|
370
479
|
console.log(renderBanner());
|
|
371
480
|
console.log("");
|
|
372
|
-
console.log(renderInfoCard(
|
|
373
|
-
"Welcome to OttoAI",
|
|
374
|
-
"/status for bridge details, /help inside the console",
|
|
375
|
-
"model: OttoAI local console",
|
|
376
|
-
`cwd: ${process.cwd()}`,
|
|
377
|
-
renderRuntimeHeadline(runtimeSession),
|
|
378
|
-
]));
|
|
481
|
+
console.log(renderInfoCard(buildWelcomeCard(runtimeSession, modelMode)));
|
|
379
482
|
}
|
|
380
|
-
function printConsoleScreen(runtimeSession) {
|
|
381
|
-
|
|
483
|
+
function printConsoleScreen(runtimeSession, modelMode) {
|
|
484
|
+
clearScreen();
|
|
382
485
|
console.log(renderBanner());
|
|
383
486
|
console.log("");
|
|
384
|
-
console.log(renderInfoCard(
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
`cwd: ${process.cwd()}`,
|
|
389
|
-
renderRuntimeHeadline(runtimeSession),
|
|
390
|
-
]));
|
|
487
|
+
console.log(renderInfoCard(buildWelcomeCard(runtimeSession, modelMode)));
|
|
488
|
+
console.log("");
|
|
489
|
+
console.log(style("Peça algo ao Otto", `${ANSI.bold}${ANSI.white}`, supportsAnsi()));
|
|
490
|
+
printSoft("Comandos: /help, /model [fast|thinking], /status, /clear, /exit");
|
|
391
491
|
console.log("");
|
|
392
492
|
}
|
|
493
|
+
function renderPromptFrameLine(width, edgeLeft, edgeRight) {
|
|
494
|
+
return style(`${edgeLeft}${"─".repeat(width)}${edgeRight}`, ANSI.brandBlue, supportsAnsi());
|
|
495
|
+
}
|
|
393
496
|
async function askConsoleInput(rl) {
|
|
394
|
-
|
|
497
|
+
if (!supportsAnsi()) {
|
|
498
|
+
return normalizeText(await question(rl, "> "));
|
|
499
|
+
}
|
|
500
|
+
const availableWidth = Number(output.columns || 96);
|
|
501
|
+
const inputWidth = Math.max(28, Math.min(availableWidth - 12, 92));
|
|
502
|
+
const top = renderPromptFrameLine(inputWidth + 4, "┌", "┐");
|
|
503
|
+
const bottom = renderPromptFrameLine(inputWidth + 4, "└", "┘");
|
|
504
|
+
const middle = [
|
|
505
|
+
style("│", ANSI.brandBlue, true),
|
|
506
|
+
" ",
|
|
507
|
+
style(">", `${ANSI.bold}${ANSI.white}`, true),
|
|
508
|
+
" ",
|
|
509
|
+
" ".repeat(inputWidth),
|
|
510
|
+
" ",
|
|
511
|
+
style("│", ANSI.brandBlue, true),
|
|
512
|
+
].join("");
|
|
513
|
+
output.write(`${top}\n${middle}\n${bottom}`);
|
|
514
|
+
cursorTo(output, 0);
|
|
515
|
+
moveCursor(output, 0, -1);
|
|
516
|
+
cursorTo(output, 4);
|
|
517
|
+
const answer = normalizeText(await question(rl, ""));
|
|
518
|
+
output.write("\n");
|
|
519
|
+
return answer;
|
|
395
520
|
}
|
|
396
521
|
function printAssistantMessage(message) {
|
|
397
522
|
const text = normalizeText(message);
|
|
398
523
|
if (!text) {
|
|
399
524
|
return;
|
|
400
525
|
}
|
|
401
|
-
console.log(`${style("•", ANSI.
|
|
526
|
+
console.log(`${style("•", ANSI.brandBlue, supportsAnsi())} ${text}`);
|
|
527
|
+
}
|
|
528
|
+
function extractJobOutcome(job) {
|
|
529
|
+
const result = job.result && typeof job.result === "object"
|
|
530
|
+
? job.result
|
|
531
|
+
: {};
|
|
532
|
+
const outcome = result.outcome && typeof result.outcome === "object"
|
|
533
|
+
? result.outcome
|
|
534
|
+
: {};
|
|
535
|
+
if (Object.keys(outcome).length > 0) {
|
|
536
|
+
return outcome;
|
|
537
|
+
}
|
|
538
|
+
const payload = job.payload && typeof job.payload === "object"
|
|
539
|
+
? job.payload
|
|
540
|
+
: {};
|
|
541
|
+
const actions = Array.isArray(payload.actions) ? payload.actions : [];
|
|
542
|
+
const firstAction = actions.find((item) => item && typeof item === "object");
|
|
543
|
+
const actionType = normalizeText(firstAction?.type).toLowerCase();
|
|
544
|
+
if (actionType === "list_files" && result.file_listing && typeof result.file_listing === "object") {
|
|
545
|
+
const listing = result.file_listing;
|
|
546
|
+
return {
|
|
547
|
+
action_type: "list_files",
|
|
548
|
+
path: normalizeText(firstAction?.path),
|
|
549
|
+
resolved_path: normalizeText(listing.resolved_path),
|
|
550
|
+
listed_item_count: listing.item_count,
|
|
551
|
+
total_item_count: listing.total_item_count,
|
|
552
|
+
limit_applied: listing.limit_applied,
|
|
553
|
+
entries: Array.isArray(listing.entries) ? listing.entries : [],
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
if (actionType === "read_file" && result.read_file && typeof result.read_file === "object") {
|
|
557
|
+
const readFile = result.read_file;
|
|
558
|
+
return {
|
|
559
|
+
action_type: "read_file",
|
|
560
|
+
path: normalizeText(firstAction?.path),
|
|
561
|
+
resolved_path: normalizeText(readFile.resolved_path),
|
|
562
|
+
content: typeof readFile.content === "string" ? readFile.content : undefined,
|
|
563
|
+
content_chunks: Array.isArray(readFile.chunks) ? readFile.chunks : [],
|
|
564
|
+
binary_notice: normalizeText(readFile.binary_notice),
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
return {};
|
|
568
|
+
}
|
|
569
|
+
function outcomePathLabel(outcome) {
|
|
570
|
+
return normalizeText(outcome.resolved_path || outcome.path);
|
|
571
|
+
}
|
|
572
|
+
function collectOutcomeFileContent(outcome) {
|
|
573
|
+
const directContent = outcome.content;
|
|
574
|
+
if (typeof directContent === "string" && directContent.trim()) {
|
|
575
|
+
return directContent;
|
|
576
|
+
}
|
|
577
|
+
const chunks = Array.isArray(outcome.content_chunks) ? outcome.content_chunks : [];
|
|
578
|
+
return chunks
|
|
579
|
+
.filter((item) => item && typeof item === "object")
|
|
580
|
+
.map((item) => String(item.text || ""))
|
|
581
|
+
.filter((item) => item.length > 0)
|
|
582
|
+
.join("");
|
|
583
|
+
}
|
|
584
|
+
function formatDirectoryEntry(entry) {
|
|
585
|
+
const name = normalizeText(entry.name) || "(sem nome)";
|
|
586
|
+
const kind = normalizeText(entry.kind).toLowerCase();
|
|
587
|
+
const prefix = kind === "directory" ? "[dir]" : "[file]";
|
|
588
|
+
const size = kind === "file" ? humanFileSize(entry.size_bytes) : "";
|
|
589
|
+
return `${prefix} ${name}${size ? ` (${size})` : ""}`;
|
|
590
|
+
}
|
|
591
|
+
export function renderStructuredOutcome(job, options) {
|
|
592
|
+
const compact = Boolean(options?.compact);
|
|
593
|
+
const outcome = extractJobOutcome(job);
|
|
594
|
+
const actionType = normalizeText(outcome.action_type).toLowerCase();
|
|
595
|
+
const lines = [];
|
|
596
|
+
if (actionType === "list_files") {
|
|
597
|
+
const entries = Array.isArray(outcome.entries)
|
|
598
|
+
? outcome.entries.filter((item) => item && typeof item === "object")
|
|
599
|
+
: [];
|
|
600
|
+
const target = outcomePathLabel(outcome);
|
|
601
|
+
const itemCount = outcome.listed_item_count ?? entries.length;
|
|
602
|
+
if (target) {
|
|
603
|
+
lines.push(target);
|
|
604
|
+
}
|
|
605
|
+
if (itemCount) {
|
|
606
|
+
lines.push(`${itemCount} item(ns) encontrados`);
|
|
607
|
+
}
|
|
608
|
+
if (lines.length) {
|
|
609
|
+
lines.push("");
|
|
610
|
+
}
|
|
611
|
+
const maxEntries = compact ? MAX_RENDERED_LIST_ENTRIES_COMPACT : MAX_RENDERED_LIST_ENTRIES;
|
|
612
|
+
entries.slice(0, maxEntries).forEach((entry) => {
|
|
613
|
+
lines.push(formatDirectoryEntry(entry));
|
|
614
|
+
});
|
|
615
|
+
if (entries.length > maxEntries) {
|
|
616
|
+
lines.push(`... +${entries.length - maxEntries} item(ns)`);
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
if (actionType === "read_file") {
|
|
620
|
+
const target = outcomePathLabel(outcome);
|
|
621
|
+
const binaryNotice = normalizeText(outcome.binary_notice);
|
|
622
|
+
const content = collectOutcomeFileContent(outcome);
|
|
623
|
+
const maxChars = compact ? MAX_RENDERED_FILE_CHARS_COMPACT : MAX_RENDERED_FILE_CHARS;
|
|
624
|
+
if (target) {
|
|
625
|
+
lines.push(target);
|
|
626
|
+
lines.push("");
|
|
627
|
+
}
|
|
628
|
+
if (binaryNotice) {
|
|
629
|
+
lines.push(binaryNotice);
|
|
630
|
+
}
|
|
631
|
+
else if (content) {
|
|
632
|
+
const truncatedContent = content.length > maxChars
|
|
633
|
+
? `${content.slice(0, maxChars).trimEnd()}\n\n[... conteúdo truncado ...]`
|
|
634
|
+
: content;
|
|
635
|
+
lines.push(truncatedContent);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
return lines.join("\n").trim();
|
|
639
|
+
}
|
|
640
|
+
function printStructuredOutcome(job) {
|
|
641
|
+
const rendered = renderStructuredOutcome(job);
|
|
642
|
+
if (!rendered) {
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
console.log("");
|
|
646
|
+
console.log(rendered);
|
|
647
|
+
}
|
|
648
|
+
function buildConversationSummary(summary, job) {
|
|
649
|
+
const rendered = renderStructuredOutcome(job, { compact: true });
|
|
650
|
+
if (!rendered) {
|
|
651
|
+
return summary;
|
|
652
|
+
}
|
|
653
|
+
if (!summary) {
|
|
654
|
+
return rendered;
|
|
655
|
+
}
|
|
656
|
+
return `${summary}\n${rendered}`.slice(0, 4_000).trim();
|
|
402
657
|
}
|
|
403
658
|
async function printExtensionsOverview(config) {
|
|
404
659
|
printSection("Extensions");
|
|
@@ -497,18 +752,19 @@ async function followConsoleJob(rl, config, jobId) {
|
|
|
497
752
|
? "Execução local falhou."
|
|
498
753
|
: "Execução local cancelada.");
|
|
499
754
|
printAssistantMessage(summary);
|
|
500
|
-
|
|
755
|
+
printStructuredOutcome(job);
|
|
756
|
+
return buildConversationSummary(summary, job);
|
|
501
757
|
}
|
|
502
758
|
await delay(1400);
|
|
503
759
|
}
|
|
504
760
|
}
|
|
505
761
|
async function runOttoConsole(rl, config, runtimeSession, options) {
|
|
506
|
-
|
|
507
|
-
|
|
762
|
+
let activeModel = "fast";
|
|
763
|
+
printConsoleScreen(runtimeSession, activeModel);
|
|
508
764
|
const sessionId = randomUUID();
|
|
509
765
|
const conversation = [];
|
|
510
766
|
const printConsoleHelp = () => {
|
|
511
|
-
|
|
767
|
+
printSoft("Comandos: /help, /model [fast|thinking], /status, /clear, /exit");
|
|
512
768
|
};
|
|
513
769
|
const handlePrompt = async (promptText) => {
|
|
514
770
|
const normalizedPrompt = normalizeText(promptText);
|
|
@@ -521,11 +777,32 @@ async function runOttoConsole(rl, config, runtimeSession, options) {
|
|
|
521
777
|
}
|
|
522
778
|
if (normalizedPrompt === "/clear") {
|
|
523
779
|
conversation.splice(0, conversation.length);
|
|
524
|
-
printConsoleScreen(runtimeSession);
|
|
780
|
+
printConsoleScreen(runtimeSession, activeModel);
|
|
525
781
|
printMuted("Contexto local do console limpo.");
|
|
526
782
|
return;
|
|
527
783
|
}
|
|
784
|
+
if (normalizedPrompt === "/model") {
|
|
785
|
+
printMuted(`Modelo ativo: ${getCliModelLabel(activeModel)}.`);
|
|
786
|
+
printSoft("Use /model fast ou /model thinking para trocar.");
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
if (normalizedPrompt.startsWith("/model ")) {
|
|
790
|
+
const nextMode = resolveCliModelMode(normalizedPrompt.slice("/model ".length));
|
|
791
|
+
if (!nextMode) {
|
|
792
|
+
printWarning("Modelo inválido. Use /model fast ou /model thinking.");
|
|
793
|
+
return;
|
|
794
|
+
}
|
|
795
|
+
if (nextMode === activeModel) {
|
|
796
|
+
printMuted(`Modelo já está em ${getCliModelLabel(activeModel)}.`);
|
|
797
|
+
return;
|
|
798
|
+
}
|
|
799
|
+
activeModel = nextMode;
|
|
800
|
+
printConsoleScreen(runtimeSession, activeModel);
|
|
801
|
+
printSuccess(`Modelo ativo: ${getCliModelLabel(activeModel)}.`);
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
528
804
|
if (normalizedPrompt === "/status") {
|
|
805
|
+
console.log(`${style("Model", ANSI.brandBlue, supportsAnsi())}: ${getCliModelLabel(activeModel)}`);
|
|
529
806
|
renderStatusOverview(config, runtimeSession).forEach((line) => console.log(line));
|
|
530
807
|
const runtimeFailure = runtimeSession.getLastError();
|
|
531
808
|
if (runtimeFailure) {
|
|
@@ -542,9 +819,12 @@ async function runOttoConsole(rl, config, runtimeSession, options) {
|
|
|
542
819
|
}
|
|
543
820
|
let streamedAssistant = "";
|
|
544
821
|
let assistantPrefixPrinted = false;
|
|
822
|
+
let reasoningPrefixPrinted = false;
|
|
823
|
+
let contentSeparatedFromReasoning = false;
|
|
545
824
|
let handoffPayload = null;
|
|
546
825
|
await streamDeviceCliChat(config, {
|
|
547
826
|
messages: conversation,
|
|
827
|
+
model: getCliModelRequestModel(activeModel),
|
|
548
828
|
session_id: sessionId,
|
|
549
829
|
}, async (event) => {
|
|
550
830
|
const chunkType = normalizeText(event.chunk_type).toLowerCase();
|
|
@@ -564,12 +844,27 @@ async function runOttoConsole(rl, config, runtimeSession, options) {
|
|
|
564
844
|
if (errorMessage) {
|
|
565
845
|
throw new Error(errorMessage);
|
|
566
846
|
}
|
|
847
|
+
const reasoningChunk = typeof event.content === "string" && eventType === "reasoning"
|
|
848
|
+
? event.content
|
|
849
|
+
: "";
|
|
850
|
+
if (reasoningChunk) {
|
|
851
|
+
if (!reasoningPrefixPrinted) {
|
|
852
|
+
output.write(`${style("Pensando (OttoAI Thinking)\n", ANSI.brandBlue, supportsAnsi())}`);
|
|
853
|
+
reasoningPrefixPrinted = true;
|
|
854
|
+
}
|
|
855
|
+
output.write(style(reasoningChunk, ANSI.slateItalic, supportsAnsi()));
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
567
858
|
const contentChunk = typeof event.content === "string" ? event.content : "";
|
|
568
859
|
if (!contentChunk) {
|
|
569
860
|
return;
|
|
570
861
|
}
|
|
862
|
+
if (reasoningPrefixPrinted && !contentSeparatedFromReasoning) {
|
|
863
|
+
output.write("\n\n");
|
|
864
|
+
contentSeparatedFromReasoning = true;
|
|
865
|
+
}
|
|
571
866
|
if (!assistantPrefixPrinted) {
|
|
572
|
-
output.write(`${style("•", ANSI.
|
|
867
|
+
output.write(`${style("•", ANSI.brandBlue, supportsAnsi())} `);
|
|
573
868
|
assistantPrefixPrinted = true;
|
|
574
869
|
}
|
|
575
870
|
output.write(contentChunk);
|
|
@@ -582,13 +877,13 @@ async function runOttoConsole(rl, config, runtimeSession, options) {
|
|
|
582
877
|
if (handoffPayload) {
|
|
583
878
|
const handoffData = handoffPayload;
|
|
584
879
|
const bridgeSummary = extractBridgeHandoffSummary(handoffData);
|
|
585
|
-
if (bridgeSummary) {
|
|
586
|
-
printAssistantMessage(bridgeSummary);
|
|
587
|
-
}
|
|
588
880
|
const job = handoffData.job && typeof handoffData.job === "object"
|
|
589
881
|
? handoffData.job
|
|
590
882
|
: null;
|
|
591
883
|
const jobId = normalizeText(job?.id);
|
|
884
|
+
if (bridgeSummary && !jobId) {
|
|
885
|
+
printAssistantMessage(bridgeSummary);
|
|
886
|
+
}
|
|
592
887
|
if (jobId) {
|
|
593
888
|
finalAssistantSummary = await followConsoleJob(rl, config, jobId);
|
|
594
889
|
}
|
|
@@ -603,7 +898,6 @@ async function runOttoConsole(rl, config, runtimeSession, options) {
|
|
|
603
898
|
}
|
|
604
899
|
}
|
|
605
900
|
};
|
|
606
|
-
printConsoleHelp();
|
|
607
901
|
if (options?.initialPrompt) {
|
|
608
902
|
await handlePrompt(options.initialPrompt);
|
|
609
903
|
}
|
|
@@ -623,27 +917,50 @@ async function runOttoConsole(rl, config, runtimeSession, options) {
|
|
|
623
917
|
async function printStatusView(rl, config, runtimeSession) {
|
|
624
918
|
printSection("Bridge Status");
|
|
625
919
|
renderStatusOverview(config, runtimeSession).forEach((line) => console.log(line));
|
|
626
|
-
await
|
|
920
|
+
await pauseForEnter(rl);
|
|
921
|
+
}
|
|
922
|
+
async function printHelpView(rl) {
|
|
923
|
+
printSection("Ajuda");
|
|
924
|
+
console.log(renderInfoCard([
|
|
925
|
+
{ text: "Otto Bridge CLI", tone: "title" },
|
|
926
|
+
{ text: "", tone: "muted" },
|
|
927
|
+
{ text: "otto-bridge", tone: "primary" },
|
|
928
|
+
{ text: "Abre o hub principal e sobe o runtime local automaticamente.", tone: "muted" },
|
|
929
|
+
{ text: "", tone: "muted" },
|
|
930
|
+
{ text: "otto-bridge setup", tone: "primary" },
|
|
931
|
+
{ text: "Repareia o dispositivo e atualiza config/executor.", tone: "muted" },
|
|
932
|
+
{ text: "", tone: "muted" },
|
|
933
|
+
{ text: "otto-bridge console", tone: "primary" },
|
|
934
|
+
{ text: "Abre direto o console do Otto no terminal.", tone: "muted" },
|
|
935
|
+
{ text: "", tone: "muted" },
|
|
936
|
+
{ text: "Dentro do console: /help, /model fast|thinking, /status, /clear, /exit", tone: "muted" },
|
|
937
|
+
]));
|
|
627
938
|
await pauseForEnter(rl);
|
|
628
939
|
}
|
|
629
940
|
async function pickHomeChoice(rl, paired) {
|
|
630
941
|
printSection("Home");
|
|
631
942
|
const options = paired
|
|
632
943
|
? [
|
|
633
|
-
`${style("1.", ANSI.
|
|
634
|
-
`${style("2.", ANSI.
|
|
635
|
-
`${style("3.", ANSI.
|
|
636
|
-
`${style("4.", ANSI.
|
|
637
|
-
`${style("5.", ANSI.
|
|
944
|
+
`${style("1.", ANSI.brandBlue, supportsAnsi())} Otto Console`,
|
|
945
|
+
`${style("2.", ANSI.brandBlue, supportsAnsi())} Setup / parear novamente`,
|
|
946
|
+
`${style("3.", ANSI.brandBlue, supportsAnsi())} Status detalhado`,
|
|
947
|
+
`${style("4.", ANSI.brandBlue, supportsAnsi())} Extensões instaladas`,
|
|
948
|
+
`${style("5.", ANSI.brandBlue, supportsAnsi())} Sair`,
|
|
949
|
+
`${style("6.", ANSI.brandBlue, supportsAnsi())} Ajuda`,
|
|
638
950
|
]
|
|
639
951
|
: [
|
|
640
|
-
`${style("1.", ANSI.
|
|
641
|
-
`${style("2.", ANSI.
|
|
952
|
+
`${style("1.", ANSI.brandBlue, supportsAnsi())} Pairing setup`,
|
|
953
|
+
`${style("2.", ANSI.brandBlue, supportsAnsi())} Sair`,
|
|
954
|
+
`${style("3.", ANSI.brandBlue, supportsAnsi())} Ajuda`,
|
|
642
955
|
];
|
|
643
956
|
console.log(options.join("\n"));
|
|
644
957
|
const answer = await ask(rl, "Escolha");
|
|
645
958
|
if (!paired) {
|
|
646
|
-
|
|
959
|
+
if (answer === "1")
|
|
960
|
+
return "setup";
|
|
961
|
+
if (answer === "3")
|
|
962
|
+
return "help";
|
|
963
|
+
return "exit";
|
|
647
964
|
}
|
|
648
965
|
if (answer === "1")
|
|
649
966
|
return "console";
|
|
@@ -653,6 +970,8 @@ async function pickHomeChoice(rl, paired) {
|
|
|
653
970
|
return "status";
|
|
654
971
|
if (answer === "4")
|
|
655
972
|
return "extensions";
|
|
973
|
+
if (answer === "6")
|
|
974
|
+
return "help";
|
|
656
975
|
return "exit";
|
|
657
976
|
}
|
|
658
977
|
export async function launchInteractiveCli(options) {
|
|
@@ -661,12 +980,13 @@ export async function launchInteractiveCli(options) {
|
|
|
661
980
|
try {
|
|
662
981
|
let config = await loadBridgeConfig();
|
|
663
982
|
if (!config) {
|
|
664
|
-
printHubScreen(null);
|
|
983
|
+
printHubScreen(null, "fast");
|
|
665
984
|
const setup = await runSetupWizard(rl, options);
|
|
666
985
|
config = setup.config;
|
|
667
986
|
if (config && setup.openConsole) {
|
|
668
987
|
runtimeSession = new CliRuntimeSession(config);
|
|
669
988
|
await runtimeSession.ensureStarted();
|
|
989
|
+
await runtimeSession.waitForReady();
|
|
670
990
|
await runOttoConsole(rl, config, runtimeSession);
|
|
671
991
|
}
|
|
672
992
|
if (!config) {
|
|
@@ -675,22 +995,29 @@ export async function launchInteractiveCli(options) {
|
|
|
675
995
|
}
|
|
676
996
|
runtimeSession = runtimeSession || new CliRuntimeSession(config);
|
|
677
997
|
await runtimeSession.ensureStarted();
|
|
998
|
+
await runtimeSession.waitForReady();
|
|
678
999
|
for (;;) {
|
|
679
|
-
printHubScreen(runtimeSession);
|
|
1000
|
+
printHubScreen(runtimeSession, "fast");
|
|
680
1001
|
const choice = await pickHomeChoice(rl, true);
|
|
681
1002
|
if (choice === "exit") {
|
|
682
1003
|
break;
|
|
683
1004
|
}
|
|
1005
|
+
if (choice === "help") {
|
|
1006
|
+
await printHelpView(rl);
|
|
1007
|
+
continue;
|
|
1008
|
+
}
|
|
684
1009
|
if (choice === "setup") {
|
|
685
1010
|
const setup = await runSetupWizard(rl);
|
|
686
1011
|
if (setup.config) {
|
|
687
1012
|
config = setup.config;
|
|
688
1013
|
if (runtimeSession) {
|
|
689
1014
|
await runtimeSession.replaceConfig(setup.config);
|
|
1015
|
+
await runtimeSession.waitForReady();
|
|
690
1016
|
}
|
|
691
1017
|
else {
|
|
692
1018
|
runtimeSession = new CliRuntimeSession(setup.config);
|
|
693
1019
|
await runtimeSession.ensureStarted();
|
|
1020
|
+
await runtimeSession.waitForReady();
|
|
694
1021
|
}
|
|
695
1022
|
}
|
|
696
1023
|
if (setup.config && setup.openConsole && runtimeSession) {
|
|
@@ -726,11 +1053,12 @@ export async function runSetupCommand(options) {
|
|
|
726
1053
|
const rl = await createPromptInterface();
|
|
727
1054
|
let runtimeSession = null;
|
|
728
1055
|
try {
|
|
729
|
-
printHubScreen(null);
|
|
1056
|
+
printHubScreen(null, "fast");
|
|
730
1057
|
const setup = await runSetupWizard(rl, options);
|
|
731
1058
|
if (setup.config && setup.openConsole) {
|
|
732
1059
|
runtimeSession = new CliRuntimeSession(setup.config);
|
|
733
1060
|
await runtimeSession.ensureStarted();
|
|
1061
|
+
await runtimeSession.waitForReady();
|
|
734
1062
|
await runOttoConsole(rl, setup.config, runtimeSession);
|
|
735
1063
|
}
|
|
736
1064
|
}
|
|
@@ -748,7 +1076,7 @@ export async function runConsoleCommand(initialPrompt) {
|
|
|
748
1076
|
const rl = await createPromptInterface();
|
|
749
1077
|
let runtimeSession = null;
|
|
750
1078
|
try {
|
|
751
|
-
printHubScreen(null);
|
|
1079
|
+
printHubScreen(null, "fast");
|
|
752
1080
|
let config = await loadBridgeConfig();
|
|
753
1081
|
if (!config) {
|
|
754
1082
|
const setup = await runSetupWizard(rl);
|
|
@@ -759,6 +1087,7 @@ export async function runConsoleCommand(initialPrompt) {
|
|
|
759
1087
|
}
|
|
760
1088
|
runtimeSession = new CliRuntimeSession(config);
|
|
761
1089
|
await runtimeSession.ensureStarted();
|
|
1090
|
+
await runtimeSession.waitForReady();
|
|
762
1091
|
await runOttoConsole(rl, config, runtimeSession, { initialPrompt });
|
|
763
1092
|
}
|
|
764
1093
|
catch (error) {
|
package/dist/main.js
CHANGED
|
@@ -104,28 +104,31 @@ function resolveExecutorOverrides(args, current) {
|
|
|
104
104
|
}
|
|
105
105
|
function printUsage() {
|
|
106
106
|
console.log(`Usage:
|
|
107
|
-
otto-bridge
|
|
108
|
-
otto-bridge setup
|
|
109
|
-
otto-bridge console
|
|
110
|
-
otto-bridge status
|
|
107
|
+
otto-bridge abre o hub principal e sobe o runtime local
|
|
108
|
+
otto-bridge setup refaz o pairing no terminal
|
|
109
|
+
otto-bridge console abre direto o console do Otto
|
|
110
|
+
otto-bridge status mostra o pairing atual em JSON
|
|
111
111
|
otto-bridge extensions --list
|
|
112
112
|
otto-bridge extensions --install <name>
|
|
113
113
|
otto-bridge extensions --setup <name>
|
|
114
114
|
otto-bridge extensions --status <name>
|
|
115
115
|
otto-bridge extensions --uninstall <name>
|
|
116
|
-
otto-bridge version
|
|
117
116
|
otto-bridge update [--tag latest|next] [--dry-run]
|
|
118
117
|
otto-bridge unpair
|
|
118
|
+
otto-bridge version
|
|
119
|
+
|
|
120
|
+
Console:
|
|
121
|
+
/help
|
|
122
|
+
/model fast
|
|
123
|
+
/model thinking
|
|
124
|
+
/status
|
|
125
|
+
/clear
|
|
126
|
+
/exit
|
|
119
127
|
|
|
120
128
|
Examples:
|
|
121
129
|
otto-bridge
|
|
122
|
-
otto-bridge setup
|
|
123
|
-
otto-bridge console
|
|
124
130
|
otto-bridge extensions --install <name>
|
|
125
131
|
otto-bridge extensions --setup <name>
|
|
126
|
-
otto-bridge extensions --status <name>
|
|
127
|
-
otto-bridge extensions --list
|
|
128
|
-
otto-bridge version
|
|
129
132
|
otto-bridge update --dry-run
|
|
130
133
|
otto-bridge --version`);
|
|
131
134
|
}
|
package/dist/types.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export const BRIDGE_CONFIG_VERSION = 1;
|
|
2
|
-
export const BRIDGE_VERSION = "1.0.
|
|
2
|
+
export const BRIDGE_VERSION = "1.0.4";
|
|
3
3
|
export const BRIDGE_PACKAGE_NAME = "@leg3ndy/otto-bridge";
|
|
4
4
|
export const DEFAULT_API_BASE_URL = "http://localhost:8000";
|
|
5
5
|
export const DEFAULT_POLL_INTERVAL_MS = 3000;
|
package/package.json
CHANGED
package/scripts/postinstall.mjs
CHANGED
|
@@ -24,7 +24,7 @@ if (!existsSync(mainPath)) {
|
|
|
24
24
|
process.exit(0);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
console.log("\n[otto-bridge] Welcome to OTTOAI 1.0.
|
|
27
|
+
console.log("\n[otto-bridge] Welcome to OTTOAI 1.0.4");
|
|
28
28
|
console.log("[otto-bridge] Vamos iniciar o setup interativo do bridge.\n");
|
|
29
29
|
|
|
30
30
|
const result = spawnSync(process.execPath, [mainPath, "setup", "--postinstall"], {
|