@leg3ndy/otto-bridge 1.1.3 → 1.1.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 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.3`, veja [`leg3ndy-ai-backend/docs/otto-bridge/releases/OTTO_BRIDGE_1_1_3_PATCH.md`](../leg3ndy-ai-backend/docs/otto-bridge/releases/OTTO_BRIDGE_1_1_3_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).
18
+ Para o patch atual `1.1.4`, veja [`leg3ndy-ai-backend/docs/otto-bridge/releases/OTTO_BRIDGE_1_1_4_PATCH.md`](../leg3ndy-ai-backend/docs/otto-bridge/releases/OTTO_BRIDGE_1_1_4_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.3.tgz
41
+ npm install -g ./leg3ndy-otto-bridge-1.1.4.tgz
42
42
  ```
43
43
 
44
- Na linha `1.1.3`, `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.
44
+ Na linha `1.1.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.1.3` 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`.
46
+ No macOS, a linha `1.1.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.1.3` 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 troca o `Otto Console` para scrollback real, menu com setas e palette de comandos ao digitar `/`.
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.4` 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 a regressao do `Otto Console` e volta ao renderer fixo com header no topo, transcript acima do composer, menu com setas e palette de comandos ao digitar `/`.
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.3`:
173
+ Fluxo recomendado na linha `1.1.4`:
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.3`:
183
+ Contrato da linha `1.1.4`:
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.3
189
+ ## Handoff rapido da linha 1.1.4
190
190
 
191
191
  Ja fechado no codigo:
192
192
 
@@ -509,6 +509,21 @@ function buildConsoleFooterApprovalLine(mode, enabled, statusSuffix) {
509
509
  const hint = statusSuffix || "Shift+Tab para alternar";
510
510
  return style(`${state.label} (${hint})`, state.tone === "warning" ? ANSI.red : state.tone === "primary" ? ANSI.amber : ANSI.slate, enabled);
511
511
  }
512
+ function buildConsoleSlashSuggestionLines(suggestions, selectedSuggestionIndex, width, enabled) {
513
+ if (!suggestions.length) {
514
+ return [];
515
+ }
516
+ const suggestionWidth = Math.max(24, width - 4);
517
+ return suggestions.map((item, index) => {
518
+ const selected = index === selectedSuggestionIndex;
519
+ const prefix = selected
520
+ ? style("›", `${ANSI.bold}${ANSI.brandBlue}`, enabled)
521
+ : style(" ", ANSI.slate, enabled);
522
+ const command = style(item.command, selected ? `${ANSI.bold}${ANSI.white}` : ANSI.brandBlue, enabled);
523
+ const description = style(truncate(item.description, Math.max(12, suggestionWidth - item.command.length - 4)), selected ? ANSI.white : ANSI.slate, enabled);
524
+ return `${prefix} ${command} ${description}`;
525
+ });
526
+ }
512
527
  function styleTranscriptPrefix(text, tone, enabled) {
513
528
  if (!enabled || !text) {
514
529
  return text;
@@ -534,6 +549,8 @@ class ConsoleScreenRenderer {
534
549
  draftValue = "";
535
550
  conversationMessages = [];
536
551
  approvalStatusSuffix = null;
552
+ slashSuggestions = [];
553
+ selectedSuggestionIndex = 0;
537
554
  usingAlternateBuffer = false;
538
555
  constructor(modelMode, approvalMode, headerFactory = () => []) {
539
556
  this.modelMode = modelMode;
@@ -593,6 +610,23 @@ class ConsoleScreenRenderer {
593
610
  this.draftValue = value;
594
611
  this.render();
595
612
  }
613
+ setSlashSuggestions(suggestions, selectedSuggestionIndex = 0) {
614
+ this.slashSuggestions = [...suggestions];
615
+ this.selectedSuggestionIndex = Math.max(0, Math.min(selectedSuggestionIndex, Math.max(0, suggestions.length - 1)));
616
+ this.render();
617
+ }
618
+ setComposerState(value, suggestions, selectedSuggestionIndex = 0) {
619
+ this.draftValue = value;
620
+ this.slashSuggestions = [...suggestions];
621
+ this.selectedSuggestionIndex = Math.max(0, Math.min(selectedSuggestionIndex, Math.max(0, suggestions.length - 1)));
622
+ this.render();
623
+ }
624
+ resetComposer() {
625
+ this.draftValue = "";
626
+ this.slashSuggestions = [];
627
+ this.selectedSuggestionIndex = 0;
628
+ this.render();
629
+ }
596
630
  setConversationMessages(messages) {
597
631
  this.conversationMessages = [...messages];
598
632
  this.render();
@@ -641,10 +675,12 @@ class ConsoleScreenRenderer {
641
675
  const headerLines = this.headerFactory();
642
676
  const separator = style("─".repeat(width), ANSI.brandBlue, enabled);
643
677
  const composer = renderConsoleComposerLines(this.draftValue, width, enabled);
678
+ const suggestionLines = buildConsoleSlashSuggestionLines(this.slashSuggestions, this.selectedSuggestionIndex, width, enabled);
644
679
  const usageTokens = Math.min(estimateConsoleContextTokens(this.conversationMessages, this.draftValue), getCliModelContextWindowTokens(this.modelMode));
645
680
  const footerLines = [
646
681
  separator,
647
682
  ...composer.renderedLines,
683
+ ...suggestionLines,
648
684
  separator,
649
685
  buildConsoleFooterStatusLine(width, this.modelMode, usageTokens, enabled),
650
686
  buildConsoleFooterApprovalLine(this.approvalMode, enabled, this.approvalStatusSuffix),
@@ -664,8 +700,19 @@ class ConsoleScreenRenderer {
664
700
  output.write("\u001b[?25h");
665
701
  }
666
702
  }
667
- function createConsoleScreenRenderer(_modelMode, _approvalMode, _runtimeSession) {
668
- return null;
703
+ export function createConsoleScreenRenderer(modelMode, approvalMode, runtimeSession, options) {
704
+ const canRender = (options?.ansiEnabled ?? supportsAnsi())
705
+ && (options?.inputIsTTY ?? Boolean(input.isTTY))
706
+ && (options?.outputIsTTY ?? Boolean(output.isTTY))
707
+ && (options?.hasRawMode ?? typeof input.setRawMode === "function");
708
+ if (!canRender) {
709
+ return null;
710
+ }
711
+ const renderer = new ConsoleScreenRenderer(modelMode, approvalMode, () => buildConsoleHeaderLines(runtimeSession));
712
+ if (options?.autoActivate ?? true) {
713
+ renderer.activate();
714
+ }
715
+ return renderer;
669
716
  }
670
717
  export function resolveCliModelMode(value) {
671
718
  const normalized = normalizeText(value).toLowerCase();
@@ -1401,27 +1448,11 @@ async function askConsoleInput(rl, options) {
1401
1448
  input.setRawMode(false);
1402
1449
  input.pause();
1403
1450
  rl.resume();
1404
- ui?.setDraftValue("");
1405
- };
1406
- const renderSuggestionLines = (width) => {
1407
- const suggestions = getVisibleSuggestions();
1408
- if (!suggestions.length) {
1409
- return [];
1410
- }
1411
- const suggestionWidth = Math.max(24, width - 4);
1412
- return suggestions.map((item, index) => {
1413
- const selected = index === selectedSuggestionIndex;
1414
- const prefix = selected
1415
- ? style("›", `${ANSI.bold}${ANSI.brandBlue}`, enabled)
1416
- : style(" ", ANSI.slate, enabled);
1417
- const command = style(item.command, selected ? `${ANSI.bold}${ANSI.white}` : ANSI.brandBlue, enabled);
1418
- const description = style(truncate(item.description, Math.max(12, suggestionWidth - item.command.length - 4)), selected ? ANSI.white : ANSI.slate, enabled);
1419
- return `${prefix} ${command} ${description}`;
1420
- });
1451
+ ui?.resetComposer();
1421
1452
  };
1422
1453
  const renderPromptBlock = () => {
1423
1454
  if (ui) {
1424
- ui.setDraftValue(value);
1455
+ ui.setComposerState(value, getVisibleSuggestions(), selectedSuggestionIndex);
1425
1456
  return;
1426
1457
  }
1427
1458
  const width = getPromptWidth();
@@ -1429,7 +1460,7 @@ async function askConsoleInput(rl, options) {
1429
1460
  const modelMode = getModelMode();
1430
1461
  const approvalMode = getApprovalMode();
1431
1462
  const usageTokens = Math.min(estimateConsoleContextTokens(getConversationMessages(), value), getCliModelContextWindowTokens(modelMode));
1432
- const suggestionLines = renderSuggestionLines(width);
1463
+ const suggestionLines = buildConsoleSlashSuggestionLines(getVisibleSuggestions(), selectedSuggestionIndex, width, enabled);
1433
1464
  const blockLines = [
1434
1465
  style("─".repeat(width), ANSI.brandBlue, enabled),
1435
1466
  ...composer.renderedLines,
@@ -1530,7 +1561,9 @@ async function askConsoleInput(rl, options) {
1530
1561
  continue;
1531
1562
  }
1532
1563
  cleanup();
1533
- output.write("\n");
1564
+ if (!ui) {
1565
+ output.write("\n");
1566
+ }
1534
1567
  resolve(normalizeText(value));
1535
1568
  return;
1536
1569
  }
@@ -1548,7 +1581,9 @@ async function askConsoleInput(rl, options) {
1548
1581
  renderPromptBlock();
1549
1582
  }
1550
1583
  };
1551
- output.on("resize", renderPromptBlock);
1584
+ if (!ui) {
1585
+ output.on("resize", renderPromptBlock);
1586
+ }
1552
1587
  renderPromptBlock();
1553
1588
  input.on("data", onData);
1554
1589
  });
package/dist/types.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export const BRIDGE_CONFIG_VERSION = 1;
2
- export const BRIDGE_VERSION = "1.1.3";
2
+ export const BRIDGE_VERSION = "1.1.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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leg3ndy/otto-bridge",
3
- "version": "1.1.3",
3
+ "version": "1.1.4",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Local companion for Otto Bridge device pairing and WebSocket runtime.",
@@ -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.3");
27
+ console.log("\n[otto-bridge] Welcome to OTTOAI 1.1.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"], {