@leg3ndy/otto-bridge 1.1.4 → 1.1.5
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 +8 -8
- package/dist/cli_terminal.js +289 -33
- 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/releases/OTTO_BRIDGE_0_9_0_RELEASE.md`](../leg3ndy-ai-backend/docs/otto-bridge/releases/OTTO_BRIDGE_0_9_0_RELEASE.md).
|
|
17
17
|
|
|
18
|
-
Para o patch atual `1.1.
|
|
18
|
+
Para o patch atual `1.1.5`, veja [`leg3ndy-ai-backend/docs/otto-bridge/releases/OTTO_BRIDGE_1_1_5_PATCH.md`](../leg3ndy-ai-backend/docs/otto-bridge/releases/OTTO_BRIDGE_1_1_5_PATCH.md). Para o corte funcional da linha `1.1.0`, veja [`leg3ndy-ai-backend/docs/otto-bridge/releases/OTTO_BRIDGE_1_1_0_RELEASE.md`](../leg3ndy-ai-backend/docs/otto-bridge/releases/OTTO_BRIDGE_1_1_0_RELEASE.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.1.
|
|
41
|
+
npm install -g ./leg3ndy-otto-bridge-1.1.5.tgz
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
Na linha `1.1.
|
|
44
|
+
Na linha `1.1.5`, `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.1.
|
|
46
|
+
No macOS, a linha `1.1.5` 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.1.
|
|
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.1.5` mantem a camada workspace-first com rail de coding, trust/policy por workspace, source control first-class, working set persistido e grounding remoto por repositório, enquanto corrige o `Otto Console` para voltar ao scrollback real, aceitar digitação enquanto o Otto streama e reaproveitar a tela do hub sem duplicar o banner.
|
|
49
49
|
|
|
50
50
|
## Publicacao
|
|
51
51
|
|
|
@@ -170,7 +170,7 @@ Esse comando abre um shell local interativo para instalar extensoes, rodar coman
|
|
|
170
170
|
|
|
171
171
|
### WhatsApp Web em background
|
|
172
172
|
|
|
173
|
-
Fluxo recomendado na linha `1.1.
|
|
173
|
+
Fluxo recomendado na linha `1.1.5`:
|
|
174
174
|
|
|
175
175
|
```bash
|
|
176
176
|
otto-bridge extensions --install whatsappweb
|
|
@@ -180,13 +180,13 @@ otto-bridge extensions --status whatsappweb
|
|
|
180
180
|
|
|
181
181
|
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.
|
|
182
182
|
|
|
183
|
-
Contrato da linha `1.1.
|
|
183
|
+
Contrato da linha `1.1.5`:
|
|
184
184
|
|
|
185
185
|
- `otto-bridge extensions --setup whatsappweb`: autentica a sessao uma vez
|
|
186
186
|
- `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
|
|
187
187
|
- ao fechar o `otto-bridge`: o browser em background e desligado, mas a sessao local fica lembrada para o proximo boot
|
|
188
188
|
|
|
189
|
-
## Handoff rapido da linha 1.1.
|
|
189
|
+
## Handoff rapido da linha 1.1.5
|
|
190
190
|
|
|
191
191
|
Ja fechado no codigo:
|
|
192
192
|
|
package/dist/cli_terminal.js
CHANGED
|
@@ -540,7 +540,7 @@ class ConsoleScreenRenderer {
|
|
|
540
540
|
modelMode;
|
|
541
541
|
approvalMode;
|
|
542
542
|
headerFactory;
|
|
543
|
-
|
|
543
|
+
liveEntries = [];
|
|
544
544
|
onResize = () => {
|
|
545
545
|
this.render();
|
|
546
546
|
};
|
|
@@ -551,7 +551,8 @@ class ConsoleScreenRenderer {
|
|
|
551
551
|
approvalStatusSuffix = null;
|
|
552
552
|
slashSuggestions = [];
|
|
553
553
|
selectedSuggestionIndex = 0;
|
|
554
|
-
|
|
554
|
+
renderedOnce = false;
|
|
555
|
+
renderedCursorLineIndex = 0;
|
|
555
556
|
constructor(modelMode, approvalMode, headerFactory = () => []) {
|
|
556
557
|
this.modelMode = modelMode;
|
|
557
558
|
this.approvalMode = approvalMode;
|
|
@@ -562,8 +563,6 @@ class ConsoleScreenRenderer {
|
|
|
562
563
|
return;
|
|
563
564
|
}
|
|
564
565
|
this.active = true;
|
|
565
|
-
output.write("\u001b[?1049h");
|
|
566
|
-
this.usingAlternateBuffer = true;
|
|
567
566
|
output.on("resize", this.onResize);
|
|
568
567
|
this.render();
|
|
569
568
|
}
|
|
@@ -572,34 +571,40 @@ class ConsoleScreenRenderer {
|
|
|
572
571
|
return;
|
|
573
572
|
}
|
|
574
573
|
output.off("resize", this.onResize);
|
|
574
|
+
this.clearRenderBlock();
|
|
575
575
|
this.active = false;
|
|
576
576
|
output.write("\u001b[?25h");
|
|
577
|
-
if (this.usingAlternateBuffer) {
|
|
578
|
-
output.write("\u001b[?1049l");
|
|
579
|
-
this.usingAlternateBuffer = false;
|
|
580
|
-
}
|
|
581
577
|
}
|
|
582
578
|
isActive() {
|
|
583
579
|
return this.active;
|
|
584
580
|
}
|
|
585
581
|
clearTranscript() {
|
|
586
|
-
this.
|
|
582
|
+
this.liveEntries.splice(0, this.liveEntries.length);
|
|
583
|
+
this.renderedOnce = false;
|
|
584
|
+
clearScreen();
|
|
585
|
+
output.write(this.headerFactory().join("\n"));
|
|
586
|
+
output.write("\n\n");
|
|
587
587
|
this.render();
|
|
588
588
|
}
|
|
589
589
|
pushEntry(entry) {
|
|
590
590
|
const id = this.nextEntryId++;
|
|
591
|
-
|
|
591
|
+
const nextEntry = {
|
|
592
592
|
id,
|
|
593
593
|
...entry,
|
|
594
|
-
}
|
|
595
|
-
|
|
594
|
+
};
|
|
595
|
+
if (nextEntry.text.length === 0 && (Boolean(nextEntry.prefix) || nextEntry.tone === "reasoning")) {
|
|
596
|
+
this.liveEntries.push(nextEntry);
|
|
597
|
+
this.render();
|
|
598
|
+
return id;
|
|
599
|
+
}
|
|
600
|
+
this.printCommittedEntry(nextEntry);
|
|
596
601
|
return id;
|
|
597
602
|
}
|
|
598
603
|
appendToEntry(id, text) {
|
|
599
604
|
if (!id || !text) {
|
|
600
605
|
return;
|
|
601
606
|
}
|
|
602
|
-
const entry = this.
|
|
607
|
+
const entry = this.liveEntries.find((item) => item.id === id);
|
|
603
608
|
if (!entry) {
|
|
604
609
|
return;
|
|
605
610
|
}
|
|
@@ -627,6 +632,15 @@ class ConsoleScreenRenderer {
|
|
|
627
632
|
this.selectedSuggestionIndex = 0;
|
|
628
633
|
this.render();
|
|
629
634
|
}
|
|
635
|
+
commitLiveEntries() {
|
|
636
|
+
if (this.liveEntries.length === 0) {
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
const width = this.getRenderWidth();
|
|
640
|
+
const lines = this.liveEntries.flatMap((entry) => this.buildEntryLines(entry, width));
|
|
641
|
+
this.liveEntries.splice(0, this.liveEntries.length);
|
|
642
|
+
this.printLinesAbove(lines);
|
|
643
|
+
}
|
|
630
644
|
setConversationMessages(messages) {
|
|
631
645
|
this.conversationMessages = [...messages];
|
|
632
646
|
this.render();
|
|
@@ -665,19 +679,50 @@ class ConsoleScreenRenderer {
|
|
|
665
679
|
}
|
|
666
680
|
return rendered;
|
|
667
681
|
}
|
|
682
|
+
getRenderWidth() {
|
|
683
|
+
return Math.max(48, Number(output.columns || 96));
|
|
684
|
+
}
|
|
685
|
+
clearRenderBlock() {
|
|
686
|
+
if (!this.renderedOnce) {
|
|
687
|
+
return;
|
|
688
|
+
}
|
|
689
|
+
output.write("\u001b[?25l");
|
|
690
|
+
cursorTo(output, 0);
|
|
691
|
+
if (this.renderedCursorLineIndex > 0) {
|
|
692
|
+
moveCursor(output, 0, -this.renderedCursorLineIndex);
|
|
693
|
+
}
|
|
694
|
+
clearScreenDown(output);
|
|
695
|
+
output.write("\u001b[?25h");
|
|
696
|
+
this.renderedOnce = false;
|
|
697
|
+
this.renderedCursorLineIndex = 0;
|
|
698
|
+
}
|
|
699
|
+
printLinesAbove(lines) {
|
|
700
|
+
if (!this.active) {
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
703
|
+
this.clearRenderBlock();
|
|
704
|
+
if (lines.length > 0) {
|
|
705
|
+
output.write(lines.join("\n"));
|
|
706
|
+
output.write("\n");
|
|
707
|
+
}
|
|
708
|
+
this.render();
|
|
709
|
+
}
|
|
710
|
+
printCommittedEntry(entry) {
|
|
711
|
+
this.printLinesAbove(this.buildEntryLines(entry, this.getRenderWidth()));
|
|
712
|
+
}
|
|
668
713
|
render() {
|
|
669
714
|
if (!this.active) {
|
|
670
715
|
return;
|
|
671
716
|
}
|
|
672
717
|
const enabled = supportsAnsi();
|
|
673
|
-
const width =
|
|
674
|
-
const height = Math.max(12, Number(output.rows || 24));
|
|
675
|
-
const headerLines = this.headerFactory();
|
|
718
|
+
const width = this.getRenderWidth();
|
|
676
719
|
const separator = style("─".repeat(width), ANSI.brandBlue, enabled);
|
|
677
720
|
const composer = renderConsoleComposerLines(this.draftValue, width, enabled);
|
|
678
721
|
const suggestionLines = buildConsoleSlashSuggestionLines(this.slashSuggestions, this.selectedSuggestionIndex, width, enabled);
|
|
679
722
|
const usageTokens = Math.min(estimateConsoleContextTokens(this.conversationMessages, this.draftValue), getCliModelContextWindowTokens(this.modelMode));
|
|
680
|
-
const
|
|
723
|
+
const liveLines = this.liveEntries.flatMap((entry) => this.buildEntryLines(entry, width));
|
|
724
|
+
const blockLines = [
|
|
725
|
+
...liveLines,
|
|
681
726
|
separator,
|
|
682
727
|
...composer.renderedLines,
|
|
683
728
|
...suggestionLines,
|
|
@@ -685,18 +730,17 @@ class ConsoleScreenRenderer {
|
|
|
685
730
|
buildConsoleFooterStatusLine(width, this.modelMode, usageTokens, enabled),
|
|
686
731
|
buildConsoleFooterApprovalLine(this.approvalMode, enabled, this.approvalStatusSuffix),
|
|
687
732
|
];
|
|
688
|
-
|
|
689
|
-
const transcriptHeight = Math.max(0, height - visibleHeader.length - footerLines.length);
|
|
690
|
-
const transcriptLines = this.transcript.flatMap((entry) => this.buildEntryLines(entry, width));
|
|
691
|
-
const visibleTranscript = transcriptLines.slice(-transcriptHeight);
|
|
692
|
-
const paddedTranscript = [
|
|
693
|
-
...Array.from({ length: Math.max(0, transcriptHeight - visibleTranscript.length) }, () => ""),
|
|
694
|
-
...visibleTranscript,
|
|
695
|
-
];
|
|
733
|
+
this.clearRenderBlock();
|
|
696
734
|
output.write("\u001b[?25l");
|
|
697
|
-
output.write("\
|
|
698
|
-
|
|
699
|
-
|
|
735
|
+
output.write(blockLines.join("\n"));
|
|
736
|
+
this.renderedOnce = true;
|
|
737
|
+
this.renderedCursorLineIndex = liveLines.length + 1 + composer.cursorLineIndex;
|
|
738
|
+
const linesBelowCursor = blockLines.length - 1 - this.renderedCursorLineIndex;
|
|
739
|
+
cursorTo(output, Math.min(width - 1, CONSOLE_COMPOSER_CURSOR_COLUMN + composer.cursorColumn));
|
|
740
|
+
if (linesBelowCursor > 0) {
|
|
741
|
+
moveCursor(output, 0, -linesBelowCursor);
|
|
742
|
+
}
|
|
743
|
+
cursorTo(output, Math.min(width - 1, CONSOLE_COMPOSER_CURSOR_COLUMN + composer.cursorColumn));
|
|
700
744
|
output.write("\u001b[?25h");
|
|
701
745
|
}
|
|
702
746
|
}
|
|
@@ -709,7 +753,7 @@ export function createConsoleScreenRenderer(modelMode, approvalMode, runtimeSess
|
|
|
709
753
|
return null;
|
|
710
754
|
}
|
|
711
755
|
const renderer = new ConsoleScreenRenderer(modelMode, approvalMode, () => buildConsoleHeaderLines(runtimeSession));
|
|
712
|
-
if (options?.autoActivate ??
|
|
756
|
+
if (options?.autoActivate ?? false) {
|
|
713
757
|
renderer.activate();
|
|
714
758
|
}
|
|
715
759
|
return renderer;
|
|
@@ -1411,6 +1455,183 @@ export function tryConsumeControlSequence(buffer) {
|
|
|
1411
1455
|
}
|
|
1412
1456
|
return null;
|
|
1413
1457
|
}
|
|
1458
|
+
class ConsoleInputController {
|
|
1459
|
+
rl;
|
|
1460
|
+
ui;
|
|
1461
|
+
options;
|
|
1462
|
+
active = false;
|
|
1463
|
+
value = "";
|
|
1464
|
+
controlBuffer = "";
|
|
1465
|
+
selectedSuggestionIndex = 0;
|
|
1466
|
+
queuedValues = [];
|
|
1467
|
+
pendingResolvers = [];
|
|
1468
|
+
terminalError = null;
|
|
1469
|
+
constructor(rl, ui, options) {
|
|
1470
|
+
this.rl = rl;
|
|
1471
|
+
this.ui = ui;
|
|
1472
|
+
this.options = options;
|
|
1473
|
+
}
|
|
1474
|
+
activate() {
|
|
1475
|
+
if (this.active || typeof input.setRawMode !== "function" || !input.isTTY) {
|
|
1476
|
+
return;
|
|
1477
|
+
}
|
|
1478
|
+
this.active = true;
|
|
1479
|
+
this.rl.pause();
|
|
1480
|
+
input.setRawMode(true);
|
|
1481
|
+
input.resume();
|
|
1482
|
+
input.on("data", this.onData);
|
|
1483
|
+
this.render();
|
|
1484
|
+
}
|
|
1485
|
+
dispose() {
|
|
1486
|
+
if (!this.active) {
|
|
1487
|
+
return;
|
|
1488
|
+
}
|
|
1489
|
+
input.removeListener("data", this.onData);
|
|
1490
|
+
input.setRawMode(false);
|
|
1491
|
+
input.pause();
|
|
1492
|
+
this.rl.resume();
|
|
1493
|
+
this.active = false;
|
|
1494
|
+
this.ui.resetComposer();
|
|
1495
|
+
}
|
|
1496
|
+
nextValue() {
|
|
1497
|
+
if (this.queuedValues.length > 0) {
|
|
1498
|
+
return Promise.resolve(this.queuedValues.shift() || "");
|
|
1499
|
+
}
|
|
1500
|
+
if (this.terminalError) {
|
|
1501
|
+
return Promise.reject(this.terminalError);
|
|
1502
|
+
}
|
|
1503
|
+
return new Promise((resolve, reject) => {
|
|
1504
|
+
this.pendingResolvers.push({ resolve, reject });
|
|
1505
|
+
});
|
|
1506
|
+
}
|
|
1507
|
+
getVisibleSuggestions() {
|
|
1508
|
+
const suggestions = resolveConsoleSlashSuggestions(this.value).slice(0, 6);
|
|
1509
|
+
if (this.selectedSuggestionIndex >= suggestions.length) {
|
|
1510
|
+
this.selectedSuggestionIndex = Math.max(0, suggestions.length - 1);
|
|
1511
|
+
}
|
|
1512
|
+
return suggestions;
|
|
1513
|
+
}
|
|
1514
|
+
render() {
|
|
1515
|
+
this.ui.setComposerState(this.value, this.getVisibleSuggestions(), this.selectedSuggestionIndex);
|
|
1516
|
+
}
|
|
1517
|
+
enqueueValue(value) {
|
|
1518
|
+
const next = this.pendingResolvers.shift();
|
|
1519
|
+
if (next) {
|
|
1520
|
+
next.resolve(value);
|
|
1521
|
+
return;
|
|
1522
|
+
}
|
|
1523
|
+
this.queuedValues.push(value);
|
|
1524
|
+
}
|
|
1525
|
+
rejectPending(error) {
|
|
1526
|
+
while (this.pendingResolvers.length > 0) {
|
|
1527
|
+
const next = this.pendingResolvers.shift();
|
|
1528
|
+
next?.reject(error);
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
closeWithError(error) {
|
|
1532
|
+
this.terminalError = error;
|
|
1533
|
+
this.rejectPending(error);
|
|
1534
|
+
this.dispose();
|
|
1535
|
+
}
|
|
1536
|
+
applySelectedSuggestion() {
|
|
1537
|
+
const suggestions = this.getVisibleSuggestions();
|
|
1538
|
+
const selected = suggestions[this.selectedSuggestionIndex];
|
|
1539
|
+
if (!selected) {
|
|
1540
|
+
return false;
|
|
1541
|
+
}
|
|
1542
|
+
if (normalizeText(this.value) === selected.insertText) {
|
|
1543
|
+
return false;
|
|
1544
|
+
}
|
|
1545
|
+
this.value = selected.insertText;
|
|
1546
|
+
this.selectedSuggestionIndex = 0;
|
|
1547
|
+
this.render();
|
|
1548
|
+
return true;
|
|
1549
|
+
}
|
|
1550
|
+
consumeControlBuffer() {
|
|
1551
|
+
while (this.controlBuffer.length > 0) {
|
|
1552
|
+
const parsed = tryConsumeControlSequence(this.controlBuffer);
|
|
1553
|
+
if (!parsed) {
|
|
1554
|
+
this.controlBuffer = "";
|
|
1555
|
+
return;
|
|
1556
|
+
}
|
|
1557
|
+
if (parsed.action === "incomplete") {
|
|
1558
|
+
return;
|
|
1559
|
+
}
|
|
1560
|
+
this.controlBuffer = this.controlBuffer.slice(parsed.consumed);
|
|
1561
|
+
if (parsed.action === "ignore") {
|
|
1562
|
+
continue;
|
|
1563
|
+
}
|
|
1564
|
+
if (parsed.action === "cycle_approval") {
|
|
1565
|
+
void Promise.resolve(this.options?.onCycleApprovalMode?.()).finally(() => {
|
|
1566
|
+
this.render();
|
|
1567
|
+
});
|
|
1568
|
+
continue;
|
|
1569
|
+
}
|
|
1570
|
+
if (parsed.action === "move_up") {
|
|
1571
|
+
const suggestions = this.getVisibleSuggestions();
|
|
1572
|
+
if (suggestions.length > 0) {
|
|
1573
|
+
this.selectedSuggestionIndex = this.selectedSuggestionIndex > 0
|
|
1574
|
+
? this.selectedSuggestionIndex - 1
|
|
1575
|
+
: suggestions.length - 1;
|
|
1576
|
+
this.render();
|
|
1577
|
+
}
|
|
1578
|
+
continue;
|
|
1579
|
+
}
|
|
1580
|
+
if (parsed.action === "move_down") {
|
|
1581
|
+
const suggestions = this.getVisibleSuggestions();
|
|
1582
|
+
if (suggestions.length > 0) {
|
|
1583
|
+
this.selectedSuggestionIndex = this.selectedSuggestionIndex < suggestions.length - 1
|
|
1584
|
+
? this.selectedSuggestionIndex + 1
|
|
1585
|
+
: 0;
|
|
1586
|
+
this.render();
|
|
1587
|
+
}
|
|
1588
|
+
continue;
|
|
1589
|
+
}
|
|
1590
|
+
if (parsed.action === "newline") {
|
|
1591
|
+
this.value += "\n";
|
|
1592
|
+
this.selectedSuggestionIndex = 0;
|
|
1593
|
+
this.render();
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
onData = (chunk) => {
|
|
1598
|
+
const text = Buffer.isBuffer(chunk) ? chunk.toString("utf8") : String(chunk);
|
|
1599
|
+
for (const char of Array.from(text)) {
|
|
1600
|
+
if (this.controlBuffer || char === "\u001b") {
|
|
1601
|
+
this.controlBuffer += char;
|
|
1602
|
+
this.consumeControlBuffer();
|
|
1603
|
+
continue;
|
|
1604
|
+
}
|
|
1605
|
+
if (char === "\u0003") {
|
|
1606
|
+
this.closeWithError(createCliExitError());
|
|
1607
|
+
return;
|
|
1608
|
+
}
|
|
1609
|
+
if (char === "\r" || char === "\n") {
|
|
1610
|
+
if (this.applySelectedSuggestion()) {
|
|
1611
|
+
continue;
|
|
1612
|
+
}
|
|
1613
|
+
const submittedValue = normalizeText(this.value);
|
|
1614
|
+
this.value = "";
|
|
1615
|
+
this.selectedSuggestionIndex = 0;
|
|
1616
|
+
this.render();
|
|
1617
|
+
this.enqueueValue(submittedValue);
|
|
1618
|
+
continue;
|
|
1619
|
+
}
|
|
1620
|
+
if (char === "\u007f" || char === "\b") {
|
|
1621
|
+
this.value = this.value.slice(0, -1);
|
|
1622
|
+
this.selectedSuggestionIndex = 0;
|
|
1623
|
+
this.render();
|
|
1624
|
+
continue;
|
|
1625
|
+
}
|
|
1626
|
+
if (char === "\t") {
|
|
1627
|
+
this.applySelectedSuggestion();
|
|
1628
|
+
continue;
|
|
1629
|
+
}
|
|
1630
|
+
this.value += char;
|
|
1631
|
+
this.render();
|
|
1632
|
+
}
|
|
1633
|
+
};
|
|
1634
|
+
}
|
|
1414
1635
|
async function askConsoleInput(rl, options) {
|
|
1415
1636
|
if (!supportsAnsi() || typeof input.setRawMode !== "function" || !input.isTTY) {
|
|
1416
1637
|
return normalizeText(await question(rl, "> "));
|
|
@@ -1888,10 +2109,20 @@ async function runOttoConsole(rl, config, runtimeSession, options) {
|
|
|
1888
2109
|
let activeModel = "fast";
|
|
1889
2110
|
let sessionId = randomUUID();
|
|
1890
2111
|
const conversation = [];
|
|
1891
|
-
const ui = createConsoleScreenRenderer(activeModel, config.approvalMode, runtimeSession
|
|
2112
|
+
const ui = createConsoleScreenRenderer(activeModel, config.approvalMode, runtimeSession, {
|
|
2113
|
+
autoActivate: false,
|
|
2114
|
+
});
|
|
1892
2115
|
if (!ui) {
|
|
1893
2116
|
printConsoleScreen(runtimeSession);
|
|
1894
2117
|
}
|
|
2118
|
+
else if (options?.reuseHubHeader) {
|
|
2119
|
+
output.write(`${style(`Comandos: ${CONSOLE_COMMAND_HINT}`, ANSI.slateItalic, supportsAnsi())}\n\n`);
|
|
2120
|
+
ui.activate();
|
|
2121
|
+
}
|
|
2122
|
+
else {
|
|
2123
|
+
printConsoleScreen(runtimeSession);
|
|
2124
|
+
ui.activate();
|
|
2125
|
+
}
|
|
1895
2126
|
const renderConversationState = () => {
|
|
1896
2127
|
ui?.setConversationMessages(conversation);
|
|
1897
2128
|
ui?.setModelMode(activeModel);
|
|
@@ -1962,7 +2193,16 @@ async function runOttoConsole(rl, config, runtimeSession, options) {
|
|
|
1962
2193
|
const cycleApprovalMode = () => {
|
|
1963
2194
|
void setApprovalMode(getNextApprovalMode(config.approvalMode));
|
|
1964
2195
|
};
|
|
2196
|
+
const inputController = ui
|
|
2197
|
+
? new ConsoleInputController(rl, ui, {
|
|
2198
|
+
onCycleApprovalMode: cycleApprovalMode,
|
|
2199
|
+
})
|
|
2200
|
+
: null;
|
|
2201
|
+
inputController?.activate();
|
|
1965
2202
|
const readConsoleInput = async () => {
|
|
2203
|
+
if (inputController) {
|
|
2204
|
+
return await inputController.nextValue();
|
|
2205
|
+
}
|
|
1966
2206
|
return await askConsoleInput(rl, {
|
|
1967
2207
|
ui,
|
|
1968
2208
|
onCycleApprovalMode: cycleApprovalMode,
|
|
@@ -2322,6 +2562,7 @@ async function runOttoConsole(rl, config, runtimeSession, options) {
|
|
|
2322
2562
|
}
|
|
2323
2563
|
streamedAssistant += contentChunk;
|
|
2324
2564
|
});
|
|
2565
|
+
ui?.commitLiveEntries();
|
|
2325
2566
|
if (assistantPrefixPrinted && !ui) {
|
|
2326
2567
|
output.write("\n");
|
|
2327
2568
|
}
|
|
@@ -2366,6 +2607,7 @@ async function runOttoConsole(rl, config, runtimeSession, options) {
|
|
|
2366
2607
|
}
|
|
2367
2608
|
}
|
|
2368
2609
|
finally {
|
|
2610
|
+
inputController?.dispose();
|
|
2369
2611
|
ui?.dispose();
|
|
2370
2612
|
}
|
|
2371
2613
|
}
|
|
@@ -2410,6 +2652,14 @@ function renderHomeOptionLine(label, selected) {
|
|
|
2410
2652
|
}
|
|
2411
2653
|
return `${style("▸", ANSI.brandBlue, supportsAnsi())} ${style(label, `${ANSI.bold}${ANSI.white}`, supportsAnsi())}`;
|
|
2412
2654
|
}
|
|
2655
|
+
function clearHomeMenuBlock(optionCount) {
|
|
2656
|
+
if (!supportsAnsi() || !output.isTTY) {
|
|
2657
|
+
return;
|
|
2658
|
+
}
|
|
2659
|
+
cursorTo(output, 0);
|
|
2660
|
+
moveCursor(output, 0, -(optionCount + 4));
|
|
2661
|
+
clearScreenDown(output);
|
|
2662
|
+
}
|
|
2413
2663
|
async function pickHomeChoice(rl, paired, renderBaseScreen) {
|
|
2414
2664
|
const options = paired
|
|
2415
2665
|
? [
|
|
@@ -2496,9 +2746,15 @@ async function pickHomeChoice(rl, paired, renderBaseScreen) {
|
|
|
2496
2746
|
return;
|
|
2497
2747
|
}
|
|
2498
2748
|
if (char === "\r" || char === "\n") {
|
|
2749
|
+
const selectedOption = options[selectedIndex];
|
|
2499
2750
|
cleanup();
|
|
2500
|
-
|
|
2501
|
-
|
|
2751
|
+
if (selectedOption?.value === "console") {
|
|
2752
|
+
clearHomeMenuBlock(options.length);
|
|
2753
|
+
}
|
|
2754
|
+
else {
|
|
2755
|
+
output.write("\n");
|
|
2756
|
+
}
|
|
2757
|
+
resolve(selectedOption?.value || "exit");
|
|
2502
2758
|
return;
|
|
2503
2759
|
}
|
|
2504
2760
|
}
|
|
@@ -2601,7 +2857,7 @@ export async function launchInteractiveCli(options) {
|
|
|
2601
2857
|
continue;
|
|
2602
2858
|
}
|
|
2603
2859
|
if (choice === "console" && runtimeSession) {
|
|
2604
|
-
await runOttoConsole(rl, config, runtimeSession);
|
|
2860
|
+
await runOttoConsole(rl, config, runtimeSession, { reuseHubHeader: true });
|
|
2605
2861
|
continue;
|
|
2606
2862
|
}
|
|
2607
2863
|
if (choice === "status" && runtimeSession) {
|
package/dist/types.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export const BRIDGE_CONFIG_VERSION = 1;
|
|
2
|
-
export const BRIDGE_VERSION = "1.1.
|
|
2
|
+
export const BRIDGE_VERSION = "1.1.5";
|
|
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.1.
|
|
27
|
+
console.log("\n[otto-bridge] Welcome to OTTOAI 1.1.5");
|
|
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"], {
|