@leg3ndy/otto-bridge 1.1.4 → 1.1.6
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 +327 -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.6`, veja [`leg3ndy-ai-backend/docs/otto-bridge/releases/OTTO_BRIDGE_1_1_6_PATCH.md`](../leg3ndy-ai-backend/docs/otto-bridge/releases/OTTO_BRIDGE_1_1_6_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.6.tgz
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
Na linha `1.1.
|
|
44
|
+
Na linha `1.1.6`, `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.6` 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.6` 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 endurece o `Otto Console` para manter o scrollback real sem vazar separadores do rodape e deduplicar chunks de stream sobrepostos.
|
|
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.6`:
|
|
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.6`:
|
|
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.6
|
|
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,9 @@ class ConsoleScreenRenderer {
|
|
|
551
551
|
approvalStatusSuffix = null;
|
|
552
552
|
slashSuggestions = [];
|
|
553
553
|
selectedSuggestionIndex = 0;
|
|
554
|
-
|
|
554
|
+
renderedOnce = false;
|
|
555
|
+
renderedLineCount = 0;
|
|
556
|
+
renderedTopRow = 0;
|
|
555
557
|
constructor(modelMode, approvalMode, headerFactory = () => []) {
|
|
556
558
|
this.modelMode = modelMode;
|
|
557
559
|
this.approvalMode = approvalMode;
|
|
@@ -562,8 +564,6 @@ class ConsoleScreenRenderer {
|
|
|
562
564
|
return;
|
|
563
565
|
}
|
|
564
566
|
this.active = true;
|
|
565
|
-
output.write("\u001b[?1049h");
|
|
566
|
-
this.usingAlternateBuffer = true;
|
|
567
567
|
output.on("resize", this.onResize);
|
|
568
568
|
this.render();
|
|
569
569
|
}
|
|
@@ -572,34 +572,42 @@ class ConsoleScreenRenderer {
|
|
|
572
572
|
return;
|
|
573
573
|
}
|
|
574
574
|
output.off("resize", this.onResize);
|
|
575
|
+
this.clearRenderBlock();
|
|
575
576
|
this.active = false;
|
|
576
577
|
output.write("\u001b[?25h");
|
|
577
|
-
if (this.usingAlternateBuffer) {
|
|
578
|
-
output.write("\u001b[?1049l");
|
|
579
|
-
this.usingAlternateBuffer = false;
|
|
580
|
-
}
|
|
581
578
|
}
|
|
582
579
|
isActive() {
|
|
583
580
|
return this.active;
|
|
584
581
|
}
|
|
585
582
|
clearTranscript() {
|
|
586
|
-
this.
|
|
583
|
+
this.liveEntries.splice(0, this.liveEntries.length);
|
|
584
|
+
this.renderedOnce = false;
|
|
585
|
+
this.renderedLineCount = 0;
|
|
586
|
+
this.renderedTopRow = 0;
|
|
587
|
+
clearScreen();
|
|
588
|
+
output.write(this.headerFactory().join("\n"));
|
|
589
|
+
output.write("\n\n");
|
|
587
590
|
this.render();
|
|
588
591
|
}
|
|
589
592
|
pushEntry(entry) {
|
|
590
593
|
const id = this.nextEntryId++;
|
|
591
|
-
|
|
594
|
+
const nextEntry = {
|
|
592
595
|
id,
|
|
593
596
|
...entry,
|
|
594
|
-
}
|
|
595
|
-
|
|
597
|
+
};
|
|
598
|
+
if (nextEntry.text.length === 0 && (Boolean(nextEntry.prefix) || nextEntry.tone === "reasoning")) {
|
|
599
|
+
this.liveEntries.push(nextEntry);
|
|
600
|
+
this.render();
|
|
601
|
+
return id;
|
|
602
|
+
}
|
|
603
|
+
this.printCommittedEntry(nextEntry);
|
|
596
604
|
return id;
|
|
597
605
|
}
|
|
598
606
|
appendToEntry(id, text) {
|
|
599
607
|
if (!id || !text) {
|
|
600
608
|
return;
|
|
601
609
|
}
|
|
602
|
-
const entry = this.
|
|
610
|
+
const entry = this.liveEntries.find((item) => item.id === id);
|
|
603
611
|
if (!entry) {
|
|
604
612
|
return;
|
|
605
613
|
}
|
|
@@ -627,6 +635,15 @@ class ConsoleScreenRenderer {
|
|
|
627
635
|
this.selectedSuggestionIndex = 0;
|
|
628
636
|
this.render();
|
|
629
637
|
}
|
|
638
|
+
commitLiveEntries() {
|
|
639
|
+
if (this.liveEntries.length === 0) {
|
|
640
|
+
return;
|
|
641
|
+
}
|
|
642
|
+
const width = this.getRenderWidth();
|
|
643
|
+
const lines = this.liveEntries.flatMap((entry) => this.buildEntryLines(entry, width));
|
|
644
|
+
this.liveEntries.splice(0, this.liveEntries.length);
|
|
645
|
+
this.printLinesAbove(lines);
|
|
646
|
+
}
|
|
630
647
|
setConversationMessages(messages) {
|
|
631
648
|
this.conversationMessages = [...messages];
|
|
632
649
|
this.render();
|
|
@@ -665,18 +682,50 @@ class ConsoleScreenRenderer {
|
|
|
665
682
|
}
|
|
666
683
|
return rendered;
|
|
667
684
|
}
|
|
685
|
+
getRenderWidth() {
|
|
686
|
+
return Math.max(48, Number(output.columns || 96));
|
|
687
|
+
}
|
|
688
|
+
getRenderHeight() {
|
|
689
|
+
return Math.max(10, Number(output.rows || 24));
|
|
690
|
+
}
|
|
691
|
+
clearRenderBlock() {
|
|
692
|
+
if (!this.renderedOnce) {
|
|
693
|
+
return;
|
|
694
|
+
}
|
|
695
|
+
output.write("\u001b[?25l");
|
|
696
|
+
cursorTo(output, 0, this.renderedTopRow);
|
|
697
|
+
clearScreenDown(output);
|
|
698
|
+
output.write("\u001b[?25h");
|
|
699
|
+
this.renderedOnce = false;
|
|
700
|
+
this.renderedLineCount = 0;
|
|
701
|
+
this.renderedTopRow = 0;
|
|
702
|
+
}
|
|
703
|
+
printLinesAbove(lines) {
|
|
704
|
+
if (!this.active) {
|
|
705
|
+
return;
|
|
706
|
+
}
|
|
707
|
+
this.clearRenderBlock();
|
|
708
|
+
if (lines.length > 0) {
|
|
709
|
+
output.write(lines.join("\n"));
|
|
710
|
+
output.write("\n");
|
|
711
|
+
}
|
|
712
|
+
this.render();
|
|
713
|
+
}
|
|
714
|
+
printCommittedEntry(entry) {
|
|
715
|
+
this.printLinesAbove(this.buildEntryLines(entry, this.getRenderWidth()));
|
|
716
|
+
}
|
|
668
717
|
render() {
|
|
669
718
|
if (!this.active) {
|
|
670
719
|
return;
|
|
671
720
|
}
|
|
672
721
|
const enabled = supportsAnsi();
|
|
673
|
-
const width =
|
|
674
|
-
const height =
|
|
675
|
-
const headerLines = this.headerFactory();
|
|
722
|
+
const width = this.getRenderWidth();
|
|
723
|
+
const height = this.getRenderHeight();
|
|
676
724
|
const separator = style("─".repeat(width), ANSI.brandBlue, enabled);
|
|
677
725
|
const composer = renderConsoleComposerLines(this.draftValue, width, enabled);
|
|
678
726
|
const suggestionLines = buildConsoleSlashSuggestionLines(this.slashSuggestions, this.selectedSuggestionIndex, width, enabled);
|
|
679
727
|
const usageTokens = Math.min(estimateConsoleContextTokens(this.conversationMessages, this.draftValue), getCliModelContextWindowTokens(this.modelMode));
|
|
728
|
+
const liveLines = this.liveEntries.flatMap((entry) => this.buildEntryLines(entry, width));
|
|
680
729
|
const footerLines = [
|
|
681
730
|
separator,
|
|
682
731
|
...composer.renderedLines,
|
|
@@ -685,18 +734,24 @@ class ConsoleScreenRenderer {
|
|
|
685
734
|
buildConsoleFooterStatusLine(width, this.modelMode, usageTokens, enabled),
|
|
686
735
|
buildConsoleFooterApprovalLine(this.approvalMode, enabled, this.approvalStatusSuffix),
|
|
687
736
|
];
|
|
688
|
-
const
|
|
689
|
-
const
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
const
|
|
693
|
-
...
|
|
694
|
-
...
|
|
737
|
+
const maxVisibleLiveLines = Math.max(0, height - footerLines.length);
|
|
738
|
+
const visibleLiveLines = maxVisibleLiveLines > 0
|
|
739
|
+
? liveLines.slice(-maxVisibleLiveLines)
|
|
740
|
+
: [];
|
|
741
|
+
const blockLines = [
|
|
742
|
+
...visibleLiveLines,
|
|
743
|
+
...footerLines,
|
|
695
744
|
];
|
|
745
|
+
const topRow = Math.max(0, height - blockLines.length);
|
|
746
|
+
this.clearRenderBlock();
|
|
696
747
|
output.write("\u001b[?25l");
|
|
697
|
-
output
|
|
698
|
-
output.write(
|
|
699
|
-
|
|
748
|
+
cursorTo(output, 0, topRow);
|
|
749
|
+
output.write(blockLines.join("\n"));
|
|
750
|
+
this.renderedOnce = true;
|
|
751
|
+
this.renderedLineCount = blockLines.length;
|
|
752
|
+
this.renderedTopRow = topRow;
|
|
753
|
+
const composerRow = topRow + visibleLiveLines.length + 1 + composer.cursorLineIndex;
|
|
754
|
+
cursorTo(output, Math.min(width - 1, CONSOLE_COMPOSER_CURSOR_COLUMN + composer.cursorColumn), composerRow);
|
|
700
755
|
output.write("\u001b[?25h");
|
|
701
756
|
}
|
|
702
757
|
}
|
|
@@ -709,7 +764,7 @@ export function createConsoleScreenRenderer(modelMode, approvalMode, runtimeSess
|
|
|
709
764
|
return null;
|
|
710
765
|
}
|
|
711
766
|
const renderer = new ConsoleScreenRenderer(modelMode, approvalMode, () => buildConsoleHeaderLines(runtimeSession));
|
|
712
|
-
if (options?.autoActivate ??
|
|
767
|
+
if (options?.autoActivate ?? false) {
|
|
713
768
|
renderer.activate();
|
|
714
769
|
}
|
|
715
770
|
return renderer;
|
|
@@ -1411,6 +1466,206 @@ export function tryConsumeControlSequence(buffer) {
|
|
|
1411
1466
|
}
|
|
1412
1467
|
return null;
|
|
1413
1468
|
}
|
|
1469
|
+
export function resolveConsoleStreamDelta(previousText, incomingChunk) {
|
|
1470
|
+
const previous = previousText || "";
|
|
1471
|
+
const incoming = incomingChunk || "";
|
|
1472
|
+
if (!incoming) {
|
|
1473
|
+
return "";
|
|
1474
|
+
}
|
|
1475
|
+
if (!previous) {
|
|
1476
|
+
return incoming;
|
|
1477
|
+
}
|
|
1478
|
+
if (incoming === previous || previous.endsWith(incoming)) {
|
|
1479
|
+
return "";
|
|
1480
|
+
}
|
|
1481
|
+
if (incoming.startsWith(previous)) {
|
|
1482
|
+
return incoming.slice(previous.length);
|
|
1483
|
+
}
|
|
1484
|
+
const maxOverlap = Math.min(previous.length, incoming.length);
|
|
1485
|
+
for (let overlap = maxOverlap; overlap > 0; overlap -= 1) {
|
|
1486
|
+
if (previous.slice(-overlap) === incoming.slice(0, overlap)) {
|
|
1487
|
+
return incoming.slice(overlap);
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
return incoming;
|
|
1491
|
+
}
|
|
1492
|
+
class ConsoleInputController {
|
|
1493
|
+
rl;
|
|
1494
|
+
ui;
|
|
1495
|
+
options;
|
|
1496
|
+
active = false;
|
|
1497
|
+
value = "";
|
|
1498
|
+
controlBuffer = "";
|
|
1499
|
+
selectedSuggestionIndex = 0;
|
|
1500
|
+
queuedValues = [];
|
|
1501
|
+
pendingResolvers = [];
|
|
1502
|
+
terminalError = null;
|
|
1503
|
+
constructor(rl, ui, options) {
|
|
1504
|
+
this.rl = rl;
|
|
1505
|
+
this.ui = ui;
|
|
1506
|
+
this.options = options;
|
|
1507
|
+
}
|
|
1508
|
+
activate() {
|
|
1509
|
+
if (this.active || typeof input.setRawMode !== "function" || !input.isTTY) {
|
|
1510
|
+
return;
|
|
1511
|
+
}
|
|
1512
|
+
this.active = true;
|
|
1513
|
+
this.rl.pause();
|
|
1514
|
+
input.setRawMode(true);
|
|
1515
|
+
input.resume();
|
|
1516
|
+
input.on("data", this.onData);
|
|
1517
|
+
this.render();
|
|
1518
|
+
}
|
|
1519
|
+
dispose() {
|
|
1520
|
+
if (!this.active) {
|
|
1521
|
+
return;
|
|
1522
|
+
}
|
|
1523
|
+
input.removeListener("data", this.onData);
|
|
1524
|
+
input.setRawMode(false);
|
|
1525
|
+
input.pause();
|
|
1526
|
+
this.rl.resume();
|
|
1527
|
+
this.active = false;
|
|
1528
|
+
this.ui.resetComposer();
|
|
1529
|
+
}
|
|
1530
|
+
nextValue() {
|
|
1531
|
+
if (this.queuedValues.length > 0) {
|
|
1532
|
+
return Promise.resolve(this.queuedValues.shift() || "");
|
|
1533
|
+
}
|
|
1534
|
+
if (this.terminalError) {
|
|
1535
|
+
return Promise.reject(this.terminalError);
|
|
1536
|
+
}
|
|
1537
|
+
return new Promise((resolve, reject) => {
|
|
1538
|
+
this.pendingResolvers.push({ resolve, reject });
|
|
1539
|
+
});
|
|
1540
|
+
}
|
|
1541
|
+
getVisibleSuggestions() {
|
|
1542
|
+
const suggestions = resolveConsoleSlashSuggestions(this.value).slice(0, 6);
|
|
1543
|
+
if (this.selectedSuggestionIndex >= suggestions.length) {
|
|
1544
|
+
this.selectedSuggestionIndex = Math.max(0, suggestions.length - 1);
|
|
1545
|
+
}
|
|
1546
|
+
return suggestions;
|
|
1547
|
+
}
|
|
1548
|
+
render() {
|
|
1549
|
+
this.ui.setComposerState(this.value, this.getVisibleSuggestions(), this.selectedSuggestionIndex);
|
|
1550
|
+
}
|
|
1551
|
+
enqueueValue(value) {
|
|
1552
|
+
const next = this.pendingResolvers.shift();
|
|
1553
|
+
if (next) {
|
|
1554
|
+
next.resolve(value);
|
|
1555
|
+
return;
|
|
1556
|
+
}
|
|
1557
|
+
this.queuedValues.push(value);
|
|
1558
|
+
}
|
|
1559
|
+
rejectPending(error) {
|
|
1560
|
+
while (this.pendingResolvers.length > 0) {
|
|
1561
|
+
const next = this.pendingResolvers.shift();
|
|
1562
|
+
next?.reject(error);
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
closeWithError(error) {
|
|
1566
|
+
this.terminalError = error;
|
|
1567
|
+
this.rejectPending(error);
|
|
1568
|
+
this.dispose();
|
|
1569
|
+
}
|
|
1570
|
+
applySelectedSuggestion() {
|
|
1571
|
+
const suggestions = this.getVisibleSuggestions();
|
|
1572
|
+
const selected = suggestions[this.selectedSuggestionIndex];
|
|
1573
|
+
if (!selected) {
|
|
1574
|
+
return false;
|
|
1575
|
+
}
|
|
1576
|
+
if (normalizeText(this.value) === selected.insertText) {
|
|
1577
|
+
return false;
|
|
1578
|
+
}
|
|
1579
|
+
this.value = selected.insertText;
|
|
1580
|
+
this.selectedSuggestionIndex = 0;
|
|
1581
|
+
this.render();
|
|
1582
|
+
return true;
|
|
1583
|
+
}
|
|
1584
|
+
consumeControlBuffer() {
|
|
1585
|
+
while (this.controlBuffer.length > 0) {
|
|
1586
|
+
const parsed = tryConsumeControlSequence(this.controlBuffer);
|
|
1587
|
+
if (!parsed) {
|
|
1588
|
+
this.controlBuffer = "";
|
|
1589
|
+
return;
|
|
1590
|
+
}
|
|
1591
|
+
if (parsed.action === "incomplete") {
|
|
1592
|
+
return;
|
|
1593
|
+
}
|
|
1594
|
+
this.controlBuffer = this.controlBuffer.slice(parsed.consumed);
|
|
1595
|
+
if (parsed.action === "ignore") {
|
|
1596
|
+
continue;
|
|
1597
|
+
}
|
|
1598
|
+
if (parsed.action === "cycle_approval") {
|
|
1599
|
+
void Promise.resolve(this.options?.onCycleApprovalMode?.()).finally(() => {
|
|
1600
|
+
this.render();
|
|
1601
|
+
});
|
|
1602
|
+
continue;
|
|
1603
|
+
}
|
|
1604
|
+
if (parsed.action === "move_up") {
|
|
1605
|
+
const suggestions = this.getVisibleSuggestions();
|
|
1606
|
+
if (suggestions.length > 0) {
|
|
1607
|
+
this.selectedSuggestionIndex = this.selectedSuggestionIndex > 0
|
|
1608
|
+
? this.selectedSuggestionIndex - 1
|
|
1609
|
+
: suggestions.length - 1;
|
|
1610
|
+
this.render();
|
|
1611
|
+
}
|
|
1612
|
+
continue;
|
|
1613
|
+
}
|
|
1614
|
+
if (parsed.action === "move_down") {
|
|
1615
|
+
const suggestions = this.getVisibleSuggestions();
|
|
1616
|
+
if (suggestions.length > 0) {
|
|
1617
|
+
this.selectedSuggestionIndex = this.selectedSuggestionIndex < suggestions.length - 1
|
|
1618
|
+
? this.selectedSuggestionIndex + 1
|
|
1619
|
+
: 0;
|
|
1620
|
+
this.render();
|
|
1621
|
+
}
|
|
1622
|
+
continue;
|
|
1623
|
+
}
|
|
1624
|
+
if (parsed.action === "newline") {
|
|
1625
|
+
this.value += "\n";
|
|
1626
|
+
this.selectedSuggestionIndex = 0;
|
|
1627
|
+
this.render();
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
onData = (chunk) => {
|
|
1632
|
+
const text = Buffer.isBuffer(chunk) ? chunk.toString("utf8") : String(chunk);
|
|
1633
|
+
for (const char of Array.from(text)) {
|
|
1634
|
+
if (this.controlBuffer || char === "\u001b") {
|
|
1635
|
+
this.controlBuffer += char;
|
|
1636
|
+
this.consumeControlBuffer();
|
|
1637
|
+
continue;
|
|
1638
|
+
}
|
|
1639
|
+
if (char === "\u0003") {
|
|
1640
|
+
this.closeWithError(createCliExitError());
|
|
1641
|
+
return;
|
|
1642
|
+
}
|
|
1643
|
+
if (char === "\r" || char === "\n") {
|
|
1644
|
+
if (this.applySelectedSuggestion()) {
|
|
1645
|
+
continue;
|
|
1646
|
+
}
|
|
1647
|
+
const submittedValue = normalizeText(this.value);
|
|
1648
|
+
this.value = "";
|
|
1649
|
+
this.selectedSuggestionIndex = 0;
|
|
1650
|
+
this.render();
|
|
1651
|
+
this.enqueueValue(submittedValue);
|
|
1652
|
+
continue;
|
|
1653
|
+
}
|
|
1654
|
+
if (char === "\u007f" || char === "\b") {
|
|
1655
|
+
this.value = this.value.slice(0, -1);
|
|
1656
|
+
this.selectedSuggestionIndex = 0;
|
|
1657
|
+
this.render();
|
|
1658
|
+
continue;
|
|
1659
|
+
}
|
|
1660
|
+
if (char === "\t") {
|
|
1661
|
+
this.applySelectedSuggestion();
|
|
1662
|
+
continue;
|
|
1663
|
+
}
|
|
1664
|
+
this.value += char;
|
|
1665
|
+
this.render();
|
|
1666
|
+
}
|
|
1667
|
+
};
|
|
1668
|
+
}
|
|
1414
1669
|
async function askConsoleInput(rl, options) {
|
|
1415
1670
|
if (!supportsAnsi() || typeof input.setRawMode !== "function" || !input.isTTY) {
|
|
1416
1671
|
return normalizeText(await question(rl, "> "));
|
|
@@ -1888,10 +2143,20 @@ async function runOttoConsole(rl, config, runtimeSession, options) {
|
|
|
1888
2143
|
let activeModel = "fast";
|
|
1889
2144
|
let sessionId = randomUUID();
|
|
1890
2145
|
const conversation = [];
|
|
1891
|
-
const ui = createConsoleScreenRenderer(activeModel, config.approvalMode, runtimeSession
|
|
2146
|
+
const ui = createConsoleScreenRenderer(activeModel, config.approvalMode, runtimeSession, {
|
|
2147
|
+
autoActivate: false,
|
|
2148
|
+
});
|
|
1892
2149
|
if (!ui) {
|
|
1893
2150
|
printConsoleScreen(runtimeSession);
|
|
1894
2151
|
}
|
|
2152
|
+
else if (options?.reuseHubHeader) {
|
|
2153
|
+
output.write(`${style(`Comandos: ${CONSOLE_COMMAND_HINT}`, ANSI.slateItalic, supportsAnsi())}\n\n`);
|
|
2154
|
+
ui.activate();
|
|
2155
|
+
}
|
|
2156
|
+
else {
|
|
2157
|
+
printConsoleScreen(runtimeSession);
|
|
2158
|
+
ui.activate();
|
|
2159
|
+
}
|
|
1895
2160
|
const renderConversationState = () => {
|
|
1896
2161
|
ui?.setConversationMessages(conversation);
|
|
1897
2162
|
ui?.setModelMode(activeModel);
|
|
@@ -1962,7 +2227,16 @@ async function runOttoConsole(rl, config, runtimeSession, options) {
|
|
|
1962
2227
|
const cycleApprovalMode = () => {
|
|
1963
2228
|
void setApprovalMode(getNextApprovalMode(config.approvalMode));
|
|
1964
2229
|
};
|
|
2230
|
+
const inputController = ui
|
|
2231
|
+
? new ConsoleInputController(rl, ui, {
|
|
2232
|
+
onCycleApprovalMode: cycleApprovalMode,
|
|
2233
|
+
})
|
|
2234
|
+
: null;
|
|
2235
|
+
inputController?.activate();
|
|
1965
2236
|
const readConsoleInput = async () => {
|
|
2237
|
+
if (inputController) {
|
|
2238
|
+
return await inputController.nextValue();
|
|
2239
|
+
}
|
|
1966
2240
|
return await askConsoleInput(rl, {
|
|
1967
2241
|
ui,
|
|
1968
2242
|
onCycleApprovalMode: cycleApprovalMode,
|
|
@@ -2244,6 +2518,7 @@ async function runOttoConsole(rl, config, runtimeSession, options) {
|
|
|
2244
2518
|
conversation.push({ role: "user", content: normalizedPrompt });
|
|
2245
2519
|
renderConversationState();
|
|
2246
2520
|
let streamedAssistant = "";
|
|
2521
|
+
let streamedReasoning = "";
|
|
2247
2522
|
let assistantEntryId = null;
|
|
2248
2523
|
let assistantPrefixPrinted = false;
|
|
2249
2524
|
let reasoningPrefixPrinted = false;
|
|
@@ -2273,7 +2548,7 @@ async function runOttoConsole(rl, config, runtimeSession, options) {
|
|
|
2273
2548
|
throw new Error(errorMessage);
|
|
2274
2549
|
}
|
|
2275
2550
|
const reasoningChunk = typeof event.content === "string" && eventType === "reasoning"
|
|
2276
|
-
? event.content
|
|
2551
|
+
? resolveConsoleStreamDelta(streamedReasoning, event.content)
|
|
2277
2552
|
: "";
|
|
2278
2553
|
if (reasoningChunk) {
|
|
2279
2554
|
if (!reasoningPrefixPrinted) {
|
|
@@ -2289,9 +2564,12 @@ async function runOttoConsole(rl, config, runtimeSession, options) {
|
|
|
2289
2564
|
else {
|
|
2290
2565
|
output.write(style(reasoningChunk, ANSI.slateItalic, supportsAnsi()));
|
|
2291
2566
|
}
|
|
2567
|
+
streamedReasoning += reasoningChunk;
|
|
2292
2568
|
return;
|
|
2293
2569
|
}
|
|
2294
|
-
const contentChunk = typeof event.content === "string"
|
|
2570
|
+
const contentChunk = typeof event.content === "string"
|
|
2571
|
+
? resolveConsoleStreamDelta(streamedAssistant, event.content)
|
|
2572
|
+
: "";
|
|
2295
2573
|
if (!contentChunk) {
|
|
2296
2574
|
return;
|
|
2297
2575
|
}
|
|
@@ -2322,6 +2600,7 @@ async function runOttoConsole(rl, config, runtimeSession, options) {
|
|
|
2322
2600
|
}
|
|
2323
2601
|
streamedAssistant += contentChunk;
|
|
2324
2602
|
});
|
|
2603
|
+
ui?.commitLiveEntries();
|
|
2325
2604
|
if (assistantPrefixPrinted && !ui) {
|
|
2326
2605
|
output.write("\n");
|
|
2327
2606
|
}
|
|
@@ -2366,6 +2645,7 @@ async function runOttoConsole(rl, config, runtimeSession, options) {
|
|
|
2366
2645
|
}
|
|
2367
2646
|
}
|
|
2368
2647
|
finally {
|
|
2648
|
+
inputController?.dispose();
|
|
2369
2649
|
ui?.dispose();
|
|
2370
2650
|
}
|
|
2371
2651
|
}
|
|
@@ -2410,6 +2690,14 @@ function renderHomeOptionLine(label, selected) {
|
|
|
2410
2690
|
}
|
|
2411
2691
|
return `${style("▸", ANSI.brandBlue, supportsAnsi())} ${style(label, `${ANSI.bold}${ANSI.white}`, supportsAnsi())}`;
|
|
2412
2692
|
}
|
|
2693
|
+
function clearHomeMenuBlock(optionCount) {
|
|
2694
|
+
if (!supportsAnsi() || !output.isTTY) {
|
|
2695
|
+
return;
|
|
2696
|
+
}
|
|
2697
|
+
cursorTo(output, 0);
|
|
2698
|
+
moveCursor(output, 0, -(optionCount + 4));
|
|
2699
|
+
clearScreenDown(output);
|
|
2700
|
+
}
|
|
2413
2701
|
async function pickHomeChoice(rl, paired, renderBaseScreen) {
|
|
2414
2702
|
const options = paired
|
|
2415
2703
|
? [
|
|
@@ -2496,9 +2784,15 @@ async function pickHomeChoice(rl, paired, renderBaseScreen) {
|
|
|
2496
2784
|
return;
|
|
2497
2785
|
}
|
|
2498
2786
|
if (char === "\r" || char === "\n") {
|
|
2787
|
+
const selectedOption = options[selectedIndex];
|
|
2499
2788
|
cleanup();
|
|
2500
|
-
|
|
2501
|
-
|
|
2789
|
+
if (selectedOption?.value === "console") {
|
|
2790
|
+
clearHomeMenuBlock(options.length);
|
|
2791
|
+
}
|
|
2792
|
+
else {
|
|
2793
|
+
output.write("\n");
|
|
2794
|
+
}
|
|
2795
|
+
resolve(selectedOption?.value || "exit");
|
|
2502
2796
|
return;
|
|
2503
2797
|
}
|
|
2504
2798
|
}
|
|
@@ -2601,7 +2895,7 @@ export async function launchInteractiveCli(options) {
|
|
|
2601
2895
|
continue;
|
|
2602
2896
|
}
|
|
2603
2897
|
if (choice === "console" && runtimeSession) {
|
|
2604
|
-
await runOttoConsole(rl, config, runtimeSession);
|
|
2898
|
+
await runOttoConsole(rl, config, runtimeSession, { reuseHubHeader: true });
|
|
2605
2899
|
continue;
|
|
2606
2900
|
}
|
|
2607
2901
|
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.6";
|
|
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.6");
|
|
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"], {
|