@hybridlabor-api/aos 4.4.2-beta.8 → 4.5.0

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.de.md CHANGED
@@ -20,10 +20,10 @@
20
20
  [![NPM Version](https://img.shields.io/npm/v/@hybridlabor-api/aos.svg)](https://www.npmjs.com/package/@hybridlabor-api/aos)
21
21
  [![runtime](https://img.shields.io/badge/node-20+-blue.svg)](https://github.com/hybridlabor-api/aos)
22
22
  [![license](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
23
- [![skills](https://img.shields.io/badge/skills-183%20kuratiert-brightgreen.svg)](https://github.com/hybridlabor-api/aos)
23
+ [![skills](https://img.shields.io/badge/skills-184%20kuratiert-brightgreen.svg)](https://github.com/hybridlabor-api/aos)
24
24
  [![SkillSpector](https://img.shields.io/badge/NVIDIA%20SkillSpector-CLEAN-76B900?logo=nvidia&logoColor=white)](https://github.com/NVIDIA/SkillSpector)
25
25
 
26
- > **Supercharging von KI-Coding-Agenten mit 183 hochkuratierten Skills, 19 lokalen MCP Wrappern und tiefgreifenden Integrationen für die Creative-Technology-Branche.**
26
+ > **Supercharging von KI-Coding-Agenten mit 184 hochkuratierten Skills, 19 lokalen MCP Wrappern und tiefgreifenden Integrationen für die Creative-Technology-Branche.**
27
27
 
28
28
  Willkommen im **BDB DEV Skills & MCP Configuration** Repository. Dieses Projekt dient als Rückgrat unseres Entwicklungs-Ecosystems für Creative & Full-Stack Development. Es erweitert KI-Agenten um hochspezialisierte Fähigkeiten, die speziell auf die Event- und Medientechnologie-Branche sowie auf allgemeine Software-Entwicklung zugeschnitten sind.
29
29
 
@@ -80,11 +80,11 @@ Keines dieser Plugins ist in diesem Paket enthalten — es handelt sich um unabh
80
80
 
81
81
  ## Übersicht
82
82
 
83
- Dieses Repo liefert drei Dinge: eine kuratierte Skill-Bibliothek für Coding-Agenten, einen Installer, der diese (plus 21 lokale MCP Wrapper) in das von Ihnen genutzte Harness einbindet, und einen Dispatcher-Graphen, der sie als Multi-Agenten Build-Pipeline orchestriert. Siehe [AOS: Der Dispatcher-Graph](#-aos-der-dispatcher-graph) weiter unten für Details zur Funktionsweise der Pipeline selbst.
83
+ Dieses Repo liefert drei Dinge: eine kuratierte Skill-Bibliothek für Coding-Agenten, einen Installer, der diese (plus 19 lokale MCP Wrapper) in das von Ihnen genutzte Harness einbindet, und einen Dispatcher-Graphen, der sie als Multi-Agenten Build-Pipeline orchestriert. Siehe [AOS: Der Dispatcher-Graph](#-aos-der-dispatcher-graph) weiter unten für Details zur Funktionsweise der Pipeline selbst.
84
84
 
85
- ## 🌟 183 Optimierte Skills
85
+ ## 🌟 184 Optimierte Skills
86
86
 
87
- Wir haben mit einem gewaltigen Pool von über 1.400 rohen KI-Skills begonnen. Nach intensiven Tests, Filterungen und Verfeinerungen haben wir sie zu einem hochkuratierten Set von **183 Optimierten Skills** destilliert (mit nativer OpenWiki-Dokumentationsengine, dem **lokalen semantischen Gedächtnis memB** und jetzt der **Universal Agent Harness Synchronisation in v4.0.0**).
87
+ Wir haben mit einem gewaltigen Pool von über 1.400 rohen KI-Skills begonnen. Nach intensiven Tests, Filterungen und Verfeinerungen haben wir sie zu einem hochkuratierten Set von **184 Optimierten Skills** destilliert (mit nativer OpenWiki-Dokumentationsengine, dem **lokalen semantischen Gedächtnis memB** und jetzt der **Universal Agent Harness Synchronisation in v4.0.0**).
88
88
 
89
89
  Diese Skills sind präzise optimiert, damit Agenten keine Zeit mit redundanten Aufgaben verschwenden, sondern mit maximaler Autonomie, strengen Architekturvorgaben und robustem Kontextbewusstsein agieren.
90
90
 
@@ -93,8 +93,8 @@ Anstatt Agenten durch generische Anweisungen irren zu lassen, setzt die oberste
93
93
  - **`godmode-engineering`**: Erzwingt Domain-Driven Design, strenge TypeScript-Prüfungen, Clean Architecture und systematisches Debugging.
94
94
  - **`godmode-ui-ux`**: Der Frontend-Goldstandard. Erzwingt BDB "Anti-Slop"-Prinzipien, Barrierefreiheit (Accessibility) und fluide Bewegungsdynamiken.
95
95
  - **`godmode-shipping`**: Der finale Wächter für Production Releases. Erzwingt Spec-Driven Development, Pre-Launch-Prüfungen und sichere Rollbacks.
96
- - **`godmode-eventtech`**: Das oberste Regelwerk für die BDB Creator Engine, das 3D, Medien und 21 Creative-Tech MCP Wrappern steuert.
97
- - **`godmode-eventtech`**: Das oberste Regelwerk für die BDB Creator Engine, das 3D, Medien und 21 Creative-Tech MCP Wrappern steuert.
96
+ - **`godmode-eventtech`**: Das oberste Regelwerk für die BDB Creator Engine, das 3D, Medien und 19 Creative-Tech MCP Wrappern steuert.
97
+ - **`godmode-eventtech`**: Das oberste Regelwerk für die BDB Creator Engine, das 3D, Medien und 19 Creative-Tech MCP Wrappern steuert.
98
98
  - **`godmode-3d-creation`**: Steuert die Agentic-3D-Pipeline (TripoSR, TRELLIS) für generative Modelle und CAD-Strukturen.
99
99
  - **`godmode-media-creation`**: Orchestriert automatisierte Videoproduktion, Storytelling und ComfyUI-Generierungsschleifen.
100
100
 
@@ -118,7 +118,7 @@ Nachfolgend finden Sie die vollständige Übersicht aller in diesem Paket enthal
118
118
  |------------|-------------|
119
119
  | `godmode-3d-creation` | Orchestrierungs-Master-Skill für alle 3D-Generierungs-, Modellierungs- und Rekonstruktionsaufgaben. Agiert als 3D-Gehirn für die BDB Creator Extension. |
120
120
  | `godmode-engineering` | BDB Engineering Godmode. Erzwingt strenges Domain-Driven Design, TypeScript-Striktheit, Clean Architecture und systematisches 5-Stufen-Debugging. |
121
- | `godmode-eventtech` | BDB EventTech Godmode. Das oberste Regelwerk für die BDB Creator Engine, das Godmode-3D, Godmode-Media und die 21 Creative-Tech MCP Wrappern steuert. |
121
+ | `godmode-eventtech` | BDB EventTech Godmode. Das oberste Regelwerk für die BDB Creator Engine, das Godmode-3D, Godmode-Media und die 19 Creative-Tech MCP Wrappern steuert. |
122
122
  | `godmode-media-creation` | Orchestrierungs-Master-Skill für alle Medienerstellungsaufgaben (Video, Audio, Bild, Motion Design). Agiert als Gehirn für die BDB Creator Extension. |
123
123
  | `godmode-shipping` | BDB Shipping Godmode. Der finale Wächter für Production Releases. Erzwingt Spec-Driven Development, strenge Pre-Launch-Prüfungen, Feature Flags und Rollback-Strategien. |
124
124
  | `godmode-ui-ux` | BDB UI/UX Godmode. Der absolute Goldstandard für Frontend-Design. Erzwingt Anti-Slop-Prinzipien, Enterprise-Barrierefreiheit, fluide Bewegungsdynamiken und datengestützte Design-Generierung über alle Agent-Harnesses hinweg. |
@@ -433,11 +433,11 @@ BDBrainstorm kombiniert Multi-Agenten-Brainstorming, den Slash-Befehl `/grill-me
433
433
 
434
434
  ---
435
435
 
436
- ## 🔌 21 Lokale MCP Wrapper
436
+ ## 🔌 19 Lokale MCP Wrapper
437
437
 
438
438
  ![BDB Architecture Sketch](assets/bdb_architecture_sketch.jpg)
439
439
 
440
- Anstatt sich auf rudimentäre Python-Mocks oder fehlerhafte Remote-APIs zu verlassen, bündelt dieses Repository **21 eigene, lokale MCP-Wrapper** (im Ordner `mcps/`). Diese werden automatisch erstellt/aufgewärmt und ermöglichen Ihrem KI-Assistenten das Lesen, Schreiben und Ausführen von Befehlen in der führenden Kreativsoftware der Branche.
440
+ Anstatt sich auf rudimentäre Python-Mocks oder fehlerhafte Remote-APIs zu verlassen, bündelt dieses Repository **19 eigene, lokale MCP-Wrapper** (im Ordner `mcps/`). Diese werden automatisch erstellt/aufgewärmt und ermöglichen Ihrem KI-Assistenten das Lesen, Schreiben und Ausführen von Befehlen in der führenden Kreativsoftware der Branche.
441
441
 
442
442
  <details>
443
443
  <summary><strong>🎨 Adobe Creative Cloud (Illustrator, Photoshop, After Effects, Premiere Pro)</strong></summary>
package/README.md CHANGED
@@ -10,17 +10,17 @@
10
10
  [![GitHub stars](https://img.shields.io/github/stars/hybridlabor-api/aos?style=flat&color=gold)](https://github.com/hybridlabor-api/aos/stargazers)
11
11
  [![last commit](https://img.shields.io/github/last-commit/hybridlabor-api/aos.svg)](https://github.com/hybridlabor-api/aos/commits/main)
12
12
 
13
- [![skills](https://img.shields.io/badge/skills-183%20curated-brightgreen.svg)](docs/skills_table.md)
13
+ [![skills](https://img.shields.io/badge/skills-184%20curated-brightgreen.svg)](docs/skills_table.md)
14
14
  [![MCPs](https://img.shields.io/badge/local%20MCPs-19-brightgreen.svg)](mcps/)
15
15
  [![harnesses](https://img.shields.io/badge/harnesses-9%20supported-blueviolet.svg)](#-installation)
16
16
  [![runtime](https://img.shields.io/badge/node-20+-blue.svg)](https://github.com/hybridlabor-api/aos)
17
17
  [![SkillSpector](https://img.shields.io/badge/NVIDIA%20SkillSpector-CLEAN-76B900?logo=nvidia&logoColor=white)](https://github.com/NVIDIA/SkillSpector)
18
18
 
19
- > **Supercharging AI coding agents with 183 hyper-curated skills, 21 local MCP wrappers, and a runnable multi-agent dispatcher graph.**
19
+ > **Supercharging AI coding agents with 184 hyper-curated skills, 19 local MCP wrappers, and a runnable multi-agent dispatcher graph.**
20
20
 
21
- Welcome to **BDB Agent OS — AOS**: 183 curated skills, 19 local MCP wrappers, an optional Hardware & PCB design module, and a dispatcher graph that turns all of it into a real multi-agent build pipeline, not just a prompt library. Point it at a goal and it plans, builds, reviews, and ships through seven coordinated agent nodes — with a mechanically enforced gate before anything actually goes live.
21
+ Welcome to **BDB Agent OS — AOS**: 184 curated skills, 19 local MCP wrappers, an optional Hardware & PCB design module, and a dispatcher graph that turns all of it into a real multi-agent build pipeline, not just a prompt library. Point it at a goal and it plans, builds, reviews, and ships through seven coordinated agent nodes — with a mechanically enforced gate before anything actually goes live.
22
22
 
23
- **Current release:** `v4.4.2` (beta channel) — see the NPM badge above for the exact published version.
23
+ **Current release:** `v4.5.0` — see the NPM badge above for the exact published version.
24
24
 
25
25
  It is harness-neutral by design, not "optimized for one tool with others as an afterthought": the dispatcher graph runs on Claude Code's Dynamic Workflows, the same skills and MCP configuration install natively into **Google Antigravity, ChatGPT Codex / Codex CLI, Claude Desktop, Cursor, Aider, Roo Code, Cline, and Windsurf**, and the lightweight `/startcycle-graph-user` variant falls back to Claude Code's own subagents on any machine that has none of the above installed.
26
26
 
@@ -98,16 +98,16 @@ separately if you want the same routing available outside a `/startcycle` run.
98
98
  ## Overview
99
99
 
100
100
  This repo ships three things: a curated skill library for coding agents, an
101
- installer that wires them (plus 21 local MCP wrappers) into whichever harness
101
+ installer that wires them (plus 19 local MCP wrappers) into whichever harness
102
102
  you use, and a dispatcher graph that orchestrates them as a multi-agent
103
103
  build pipeline. See [AOS: The Dispatcher Graph](#-aos-the-dispatcher-graph)
104
104
  below for how the pipeline itself works.
105
105
 
106
106
  ---
107
107
 
108
- ## 🌟 183 Optimized Skills
108
+ ## 🌟 184 Optimized Skills
109
109
 
110
- We started with a massive pool of over 1,400 raw AI skills. After rigorous testing, filtering, and refinement, we've distilled them down to a hyper-curated set of **183 Optimized Skills** (featuring a native OpenWiki documentation engine, the **memB local semantic memory brain**, and **Universal Agent Harness synchronization**).
110
+ We started with a massive pool of over 1,400 raw AI skills. After rigorous testing, filtering, and refinement, we've distilled them down to a hyper-curated set of **184 Optimized Skills** (featuring a native OpenWiki documentation engine, the **memB local semantic memory brain**, and **Universal Agent Harness synchronization**).
111
111
 
112
112
  These skills are precision-engineered to ensure agents waste no time on redundant tasks and instead operate with maximum agency, strict architectural constraints, and robust context awareness.
113
113
 
@@ -138,7 +138,7 @@ While heavily optimized for the creative tech industry, these skills are deeply
138
138
 
139
139
  ## 🗂️ The Complete Skill Library
140
140
 
141
- 147 skills across 15 domains, collapsed by default so this section does not require endless scrolling to get past. Click any category to expand it.
141
+ 184 skills across 15 domains, collapsed by default so this section does not require endless scrolling to get past. Click any category to expand it.
142
142
 
143
143
  <details>
144
144
  <summary><strong>🎨 Frontend & UI/UX Design</strong> — 20 skills</summary>
@@ -482,11 +482,11 @@ BDBrainstorm combines multi-agent brainstorming, the `/grill-me` slash command,
482
482
 
483
483
  ---
484
484
 
485
- ## 🔌 21 Local MCP Wrappers
485
+ ## 🔌 19 Local MCP Wrappers
486
486
 
487
487
  ![BDB Architecture Sketch](assets/bdb_architecture_sketch.jpg)
488
488
 
489
- Rather than relying on skeletal python mocks or broken remote APIs, this repository bundles **21 local MCP wrappers** (in the `mcps/` directory). These are built/warmed automatically and allow your AI assistant to read, write, and execute commands within the industry's leading creative software.
489
+ Rather than relying on skeletal python mocks or broken remote APIs, this repository bundles **19 local MCP wrappers** (in the `mcps/` directory). These are built/warmed automatically and allow your AI assistant to read, write, and execute commands within the industry's leading creative software.
490
490
 
491
491
  <details>
492
492
  <summary><strong>🎨 Adobe Creative Cloud (Illustrator, Photoshop, After Effects, Premiere Pro)</strong></summary>
package/README.pt.md CHANGED
@@ -20,12 +20,12 @@
20
20
  [![NPM Version](https://img.shields.io/npm/v/@hybridlabor-api/aos.svg)](https://www.npmjs.com/package/@hybridlabor-api/aos)
21
21
  [![runtime](https://img.shields.io/badge/node-20+-blue.svg)](https://github.com/hybridlabor-api/aos)
22
22
  [![license](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
23
- [![skills](https://img.shields.io/badge/skills-183%20curadas-brightgreen.svg)](https://github.com/hybridlabor-api/aos)
23
+ [![skills](https://img.shields.io/badge/skills-184%20curadas-brightgreen.svg)](https://github.com/hybridlabor-api/aos)
24
24
  [![SkillSpector](https://img.shields.io/badge/NVIDIA%20SkillSpector-CLEAN-76B900?logo=nvidia&logoColor=white)](https://github.com/NVIDIA/SkillSpector)
25
25
 
26
- > **Potencializando agentes de código de IA com 183 skills hipercuradas, 19 wrappers MCP locais e um grafo dispatcher de multi-agentes executável.**
26
+ > **Potencializando agentes de código de IA com 184 skills hipercuradas, 19 wrappers MCP locais e um grafo dispatcher de multi-agentes executável.**
27
27
 
28
- Bem-vindo ao **BDB Agent OS — AOS**: 183 skills curadas, 19 wrappers MCP locais e um grafo dispatcher que os transforma em um verdadeiro pipeline de build multi-agente, não apenas uma biblioteca de prompts. Aponte para um objetivo e ele planeja, constrói, revisa e implementa através de sete nós de agentes coordenados — com um portão imposto mecanicamente antes que qualquer coisa vá ao ar.
28
+ Bem-vindo ao **BDB Agent OS — AOS**: 184 skills curadas, 19 wrappers MCP locais e um grafo dispatcher que os transforma em um verdadeiro pipeline de build multi-agente, não apenas uma biblioteca de prompts. Aponte para um objetivo e ele planeja, constrói, revisa e implementa através de sete nós de agentes coordenados — com um portão imposto mecanicamente antes que qualquer coisa vá ao ar.
29
29
 
30
30
  É neutro em relação ao harness por design, não "otimizado para uma ferramenta com outras como reflexão tardia": o grafo dispatcher é executado no Dynamic Workflows do Claude Code, as mesmas skills e configuração MCP são instaladas nativamente no **Google Antigravity, ChatGPT Codex / Codex CLI, Claude Desktop, Cursor, Aider, Roo Code, Cline e Windsurf**, e a variante leve `/startcycle-graph-user` recorre aos próprios subagentes do Claude Code em qualquer máquina que não tenha nenhum dos acima instalados.
31
31
 
@@ -81,14 +81,14 @@ Nenhum destes vem dentro deste pacote — são plugins do Claude Code independen
81
81
  ## Visão Geral
82
82
 
83
83
  Este repositório entrega três coisas: uma biblioteca curada de skills para agentes de código, um
84
- instalador que conecta eles (mais 21 wrappers MCP locais) em qualquer harness
84
+ instalador que conecta eles (mais 19 wrappers MCP locais) em qualquer harness
85
85
  que você use, e um grafo dispatcher que os orquestra como um pipeline de
86
86
  build multi-agente. Veja [AOS: O Grafo Dispatcher](#-aos-o-grafo-dispatcher)
87
87
  abaixo para entender como o próprio pipeline funciona.
88
88
 
89
- ## 🌟 183 Skills Otimizadas
89
+ ## 🌟 184 Skills Otimizadas
90
90
 
91
- Começamos com um conjunto massivo de mais de 1.400 skills de IA brutas. Após rigorosos testes, filtragem e refinamento, destilamo-las em um conjunto hipercurado de **183 Skills Otimizadas** (apresentando um motor nativo de documentação OpenWiki, o **cérebro de memória semântica local memB** e agora a **sincronização Universal Agent Harness na v4.0.0**).
91
+ Começamos com um conjunto massivo de mais de 1.400 skills de IA brutas. Após rigorosos testes, filtragem e refinamento, destilamo-las em um conjunto hipercurado de **184 Skills Otimizadas** (apresentando um motor nativo de documentação OpenWiki, o **cérebro de memória semântica local memB** e agora a **sincronização Universal Agent Harness na v4.0.0**).
92
92
 
93
93
  Essas skills são projetadas com precisão para garantir que os agentes não percam tempo com tarefas redundantes e, em vez disso, operem com máxima autonomia, restrições arquitetônicas rígidas e robusta consciência de contexto.
94
94
 
@@ -97,7 +97,7 @@ Em vez de deixar os agentes vagando por instruções genéricas, o nível superi
97
97
  - **`godmode-engineering`**: Impõe Domain-Driven Design, verificações rígidas de TypeScript, Clean Architecture e depuração sistemática.
98
98
  - **`godmode-ui-ux`**: O padrão de ouro do frontend. Impõe princípios "Anti-Slop" da BDB, acessibilidade e dinâmicas de movimento fluidas.
99
99
  - **`godmode-shipping`**: O guardião final para lançamentos em produção. Impõe Spec-Driven Development, verificações pré-lançamento e rollbacks seguros.
100
- - **`godmode-eventtech`**: O livro de regras supremo para o BDB Creator Engine, governando 3D, Mídia e 21 wrappers MCP de tecnologia criativa.
100
+ - **`godmode-eventtech`**: O livro de regras supremo para o BDB Creator Engine, governando 3D, Mídia e 19 wrappers MCP de tecnologia criativa.
101
101
  - **`godmode-3d-creation`**: Controla o pipeline 3D agêntico (TripoSR, TRELLIS) para modelos generativos e estruturas CAD.
102
102
  - **`godmode-media-creation`**: Orquestra a produção automatizada de vídeo, narrativa e loops de geração do ComfyUI.
103
103
 
@@ -121,7 +121,7 @@ Abaixo está a visão geral completa de todas as skills curadas de agentes inclu
121
121
  |------------|-------------|
122
122
  | `godmode-3d-creation` | Skill mestre de orquestração para todas as tarefas de geração, modelagem e reconstrução 3D. Atua como o cérebro 3D para a BDB Creator Extension. |
123
123
  | `godmode-engineering` | BDB Engineering Godmode. Impõe Domain-Driven Design rigoroso, estrito TypeScript, Clean Architecture e triagem sistemática de depuração em 5 etapas. |
124
- | `godmode-eventtech` | BDB EventTech Godmode. O livro de regras supremo para o BDB Creator Engine, governando Godmode-3D, Godmode-Media e os 21 wrappers MCP de tecnologia criativa. |
124
+ | `godmode-eventtech` | BDB EventTech Godmode. O livro de regras supremo para o BDB Creator Engine, governando Godmode-3D, Godmode-Media e os 19 wrappers MCP de tecnologia criativa. |
125
125
  | `godmode-media-creation` | Skill mestre de orquestração para todas as tarefas de criação de mídia (Vídeo, Áudio, Imagem, Motion Design). Atua como o cérebro para a BDB Creator Extension. |
126
126
  | `godmode-shipping` | BDB Shipping Godmode. O guardião final para lançamentos em produção. Impõe Spec-Driven Development, rigorosas verificações pré-lançamento, feature flags e estratégias de rollback. |
127
127
  | `godmode-ui-ux` | BDB UI/UX Godmode. O padrão de ouro absoluto para design frontend. Impõe princípios Anti-Slop, acessibilidade corporativa, dinâmicas de movimento fluidas e geração de design orientada a dados em todos os harnesses de agentes. |
@@ -425,11 +425,11 @@ O BDBrainstorm combina brainstorming multi-agente, o comando slash `/grill-me`,
425
425
 
426
426
  ---
427
427
 
428
- ## 🔌 21 Integrações Locais de MCPP
428
+ ## 🔌 19 Integrações Locais de MCPs
429
429
 
430
430
  ![BDB Architecture Sketch](assets/bdb_architecture_sketch.jpg)
431
431
 
432
- Em vez de depender de mocks rudimentares em python ou APIs remotas com falhas, este repositório empacota **21 wrappers MCP locais** (no diretório `mcps/`). Eles são construídos/preparados automaticamente e permitem que seu assistente de IA leia, escreva e execute comandos nos principais softwares criativos do mercado.
432
+ Em vez de depender de mocks rudimentares em python ou APIs remotas com falhas, este repositório empacota **19 wrappers MCP locais** (no diretório `mcps/`). Eles são construídos/preparados automaticamente e permitem que seu assistente de IA leia, escreva e execute comandos nos principais softwares criativos do mercado.
433
433
 
434
434
  <details>
435
435
  <summary><strong>🎨 Adobe Creative Cloud (Illustrator, Photoshop, After Effects, Premiere Pro)</strong></summary>
package/installer.js CHANGED
@@ -1996,6 +1996,91 @@ async function installSynapse() {
1996
1996
  }
1997
1997
  }
1998
1998
 
1999
+ async function installOpenWikiVisualizer() {
2000
+ if (DRY_RUN) {
2001
+ log.step('[dry-run] would register the OpenWiki Visualizer background daemon (Port 4321)');
2002
+ return;
2003
+ }
2004
+ if (!hasExecutable('openwiki')) {
2005
+ log.warn('Skipping OpenWiki Visualizer setup: the openwiki CLI was not found on PATH. Install it with: npm install -g openwiki@latest');
2006
+ return;
2007
+ }
2008
+ // launchd starts agents with a minimal PATH that never includes npm's global
2009
+ // bin dir, so resolve the absolute binary path now instead of relying on PATH at boot.
2010
+ let openwikiBin = 'openwiki';
2011
+ try {
2012
+ const lookup = process.platform === 'win32' ? 'where openwiki' : 'command -v openwiki';
2013
+ openwikiBin = execSync(lookup, { encoding: 'utf8' }).split(/\r?\n/)[0].trim() || 'openwiki';
2014
+ } catch (e) { logDebug(e, 'openwiki path lookup'); }
2015
+
2016
+ if (process.platform === 'darwin') {
2017
+ const plistPath = path.join(homeDir, 'Library', 'LaunchAgents', 'com.bdb.openwiki-visualize.plist');
2018
+ const plistContent = `<?xml version="1.0" encoding="UTF-8"?>
2019
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
2020
+ <plist version="1.0">
2021
+ <dict>
2022
+ <key>Label</key>
2023
+ <string>com.bdb.openwiki-visualize</string>
2024
+ <key>ProgramArguments</key>
2025
+ <array>
2026
+ <string>${openwikiBin}</string>
2027
+ <string>visualize</string>
2028
+ <string>--port</string>
2029
+ <string>4321</string>
2030
+ <string>--no-open</string>
2031
+ </array>
2032
+ <key>WorkingDirectory</key>
2033
+ <string>${homeDir}</string>
2034
+ <key>RunAtLoad</key>
2035
+ <true/>
2036
+ <key>KeepAlive</key>
2037
+ <true/>
2038
+ <key>StandardOutPath</key>
2039
+ <string>${path.join(homeDir, '.openwiki', 'visualize.stdout.log')}</string>
2040
+ <key>StandardErrorPath</key>
2041
+ <string>${path.join(homeDir, '.openwiki', 'visualize.stderr.log')}</string>
2042
+ </dict>
2043
+ </plist>`;
2044
+ try {
2045
+ fs.mkdirSync(path.join(homeDir, '.openwiki'), { recursive: true });
2046
+ fs.writeFileSync(plistPath, plistContent);
2047
+ execSync(`launchctl unload "${plistPath}" 2>/dev/null || true`, { stdio: 'ignore' });
2048
+ execSync(`launchctl load -w "${plistPath}" 2>/dev/null || true`, { stdio: 'ignore' });
2049
+ const isListening = await verifyDaemonListening(4321, 'OpenWiki Visualizer');
2050
+ if (isListening) {
2051
+ log.success('OpenWiki Visualizer LaunchAgent active (Port 4321)');
2052
+ } else {
2053
+ log.warn('OpenWiki Visualizer daemon did not respond on Port 4321 within timeout. You may need to start it manually or check for port conflicts.');
2054
+ }
2055
+ } catch (e) { logDebug(e, 'openwiki visualizer plist setup'); }
2056
+ } else if (process.platform === 'win32') {
2057
+ const startupDir = path.join(process.env.APPDATA || path.join(homeDir, 'AppData', 'Roaming'), 'Microsoft', 'Windows', 'Start Menu', 'Programs', 'Startup');
2058
+ fs.mkdirSync(startupDir, { recursive: true });
2059
+ const visualizerLogDir = path.join(homeDir, '.openwiki');
2060
+ fs.mkdirSync(visualizerLogDir, { recursive: true });
2061
+ const stdoutLog = path.join(visualizerLogDir, 'visualize.stdout.log');
2062
+ const stderrLog = path.join(visualizerLogDir, 'visualize.stderr.log');
2063
+ const batPath = path.join(visualizerLogDir, 'run-openwiki-visualize.bat');
2064
+ const runCmd = `"${openwikiBin}" visualize --port 4321 --no-open`;
2065
+ const batContent = `@echo off\r\ncd /d "${homeDir}"\r\n${runCmd} >> "${stdoutLog}" 2>> "${stderrLog}"\r\n`;
2066
+ const vbsPath = path.join(startupDir, 'com.bdb.openwiki-visualize.vbs');
2067
+ const vbsContent = `Set WshShell = CreateObject("WScript.Shell")\r\nWshShell.CurrentDirectory = "${homeDir}"\r\nWshShell.Run """${batPath}""", 0, False\r\n`;
2068
+ try {
2069
+ fs.writeFileSync(batPath, batContent, 'utf-8');
2070
+ fs.writeFileSync(vbsPath, vbsContent, 'utf-8');
2071
+ spawn('wscript.exe', [vbsPath], { detached: true, stdio: 'ignore' }).unref();
2072
+ // Same reasoning as the Synapse Windows path: wscript -> WshShell.Run is
2073
+ // multiple layers of indirection, so allow the generous 12s budget here too.
2074
+ const isListening = await verifyDaemonListening(4321, 'OpenWiki Visualizer', 12000);
2075
+ if (isListening) {
2076
+ log.success('OpenWiki Visualizer Windows Background Service registered & started (Port 4321)');
2077
+ } else {
2078
+ log.warn(`OpenWiki Visualizer Windows daemon did not respond on Port 4321 within timeout. Check ${stderrLog} for the actual error before assuming it's just slow to start.`);
2079
+ }
2080
+ } catch (e) { logDebug(e, 'windows openwiki visualizer daemon setup'); }
2081
+ }
2082
+ }
2083
+
1999
2084
  async function installCreatorExtension() {
2000
2085
  const creatorDir = path.join(moduleBasePath(), 'bdb-dev-creator-extension');
2001
2086
  if (!downloadOrUpdateModule('@hybridlabor-api/bdb-dev-creator-extension', creatorDir, 'BDB Creator Extension')) {
@@ -3348,6 +3433,10 @@ function generateAndOpenLaunchpad() {
3348
3433
  <meta charset="UTF-8">
3349
3434
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
3350
3435
  <title>BDB Agent OS – Launchpad</title>
3436
+ <link rel="icon" type="image/svg+xml" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MTIgNTEyIj48ZGVmcz48bGluZWFyR3JhZGllbnQgaWQ9ImEiIHgxPSIwJSIgeTE9IjAlIiB4Mj0iMTAwJSIgeTI9IjEwMCUiPjxzdG9wIG9mZnNldD0iMCUiIHN0b3AtY29sb3I9IiNGRkZGRkYiLz48c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNFN0U3RUEiLz48L2xpbmVhckdyYWRpZW50PjwvZGVmcz48Y2lyY2xlIGN4PSIyNTYiIGN5PSIyNTYiIHI9IjI0NiIgZmlsbD0iIzBhMGEwYSIgc3Ryb2tlPSIjOWIzMGM0IiBzdHJva2Utd2lkdGg9IjEyIi8+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNzAsNjgpIj48cGF0aCBmaWxsPSJ1cmwoI2EpIiBkPSJNMTgxLjYzLjA1YzEwMS4zOS0yLjQ3LDE4NC41Niw4MC4wOSwxOTAuMTQsMTc5LjkzLDUuNTMsOTkuMDMtNjYuMTYsMTg1LjQyLTE2NS4xMSwxOTUuNDYtODcuMzksOC44Ni0xNzEuMS00NS41Ni0xOTcuNjctMTI4Ljk2Qy0yOC43NCwxMjguMDMsNTYuNzgsMy4xLDE4MS42My4wNWgwWk0xNzcuNSwyMS4zQzY5LjA5LDI1LjMxLTcuMTYsMTI5LjYyLDIxLjc2LDIzNC41MmMxOC43Miw2Ny44OCw4MS41NiwxMTYuNywxNTEuNTMsMTIxLjMyLDEwNi4yMSw3LjAzLDE5NS42LTgxLjYzLDE3OS42OC0xODkuMDYtMTIuNTQtODQuNjUtODkuODEtMTQ4LjY2LTE3NS40Ny0xNDUuNDloMFoiLz48ZyBmaWxsPSIjRkZGRkZGIj48cGF0aCBkPSJNMTQ3LjY5LDEyMC4wNWMxMi4wNC4zNiwyNC42NC0uNzIsMzYuNjItLjA3LDI0LjI5LDEuMzIsNDEuMzcsMjAuMTMsNDIuOTEsNDMuOTktLjY5LDE2LjM1LjU3LDMzLjQyLS4yOCw0OS42OS0xLjMxLDI1LjQyLTE4LjU1LDQzLjc1LTQ0LjAyLDQ1LjY0LTkuNTkuNzItMjAuMTQuNjktMjkuNzguODQtNC45Ny4wOC05LjkuNjgtMTAuMzctNS42NnMuNDMtOS40MS4zNC0xNC4wM2MxMi42NS0xMS44NCwxNC43NS0zMS4xNyw0Ljc1LTQ1LjQxLS42My0uOS0yLjI2LTIuMzQtMi42Mi0zLjE3cy0uNDYtMTIuNTgtLjI2LTE0LjM3LDEuMS0zLjUyLDEuNDYtNS4xNmMxLjIxLTUuNDIsMS4wNi0xMS4yNi0uMzktMTYuNjItLjQxLTEuNTQtMS40OC0zLjU2LTEuNjMtNC45OS0uNDctNC4yOC0uMTQtOS42Ny0uMjYtMTQuMDgtLjExLTMuNTYtLjg0LTguNDMtLjU3LTExLjg2czEuMzItNC4zNSw0LjA4LTQuNzVoMFoiLz48cGF0aCBkPSJNMjMyLjY2LDEzMi40NmM5LjUzLjM2LDE5Ljc0LS43MiwyOS4xOS0uMDgsMjIuNjQsMS41MiwzMy45MiwyOC41OCwyMS45Myw0Ny4wNS0xLjQ5LDIuMy00LjMyLDQuNDctMy44NSw3LjQyLjQ3LDIuOTUsNS42NCw2LjIxLDcuNDIsOC4zLDExLjg4LDEzLjk2LDguNDEsMzUuNjktNi45MSw0NS40OS03Ljg1LDUuMDItMTQuNjksNC40My0yMy41Niw0Ljg2LTcuNjcuMzctMTYuMjQsMS4wNS0yMy45MS42NloiLz48cGF0aCBkPSJNOTAuNTksMTMzLjAzYzguODQtLjQ0LDI1LjI0LTEuMDgsMzMuMjMsMS45MiwxOC4wNyw2Ljc3LDIzLjk5LDI5Ljk2LDEzLjU2LDQ1LjctMS42LDIuNDEtNC41Miw0LjQ0LTMuMjgsNy43NS42OSwxLjg1LDUuNDEsNS40Miw3LjAzLDcuMzEsMTEuODYsMTMuODIsOC43NywzNS4yMy02LjI1LDQ1LjMzLTE1LjAyLDEwLjEtMjMuMzEsNS4yNy0zNC40NCw1LjU2WiIvPjwvZz48L2c+PC9zdmc+">
3437
+ <link rel="preconnect" href="https://fonts.googleapis.com">
3438
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
3439
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&family=IBM+Plex+Mono:wght@400;500&display=swap" rel="stylesheet">
3351
3440
  <style>
3352
3441
  :root {
3353
3442
  --bg: #090a0f;
@@ -3355,10 +3444,10 @@ function generateAndOpenLaunchpad() {
3355
3444
  --card-border: rgba(255, 255, 255, 0.08);
3356
3445
  --text: #f0f6fc;
3357
3446
  --text-muted: #8b949e;
3358
- --accent: #58a6ff;
3447
+ --accent: #9b30c4;
3359
3448
  --green: #3fb950;
3360
- --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
3361
- --mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
3449
+ --font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
3450
+ --mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
3362
3451
  }
3363
3452
  * { box-sizing: border-box; margin: 0; padding: 0; }
3364
3453
  body {
@@ -3384,12 +3473,9 @@ function generateAndOpenLaunchpad() {
3384
3473
  letter-spacing: -0.5px;
3385
3474
  margin-bottom: 6px;
3386
3475
  }
3387
- .logo-badge {
3388
- background: linear-gradient(135deg, #58a6ff 0%, #bc8cff 100%);
3389
- -webkit-background-clip: text;
3390
- -webkit-text-fill-color: transparent;
3391
- }
3392
- .tagline { color: var(--text-muted); font-size: 14px; }
3476
+ .logo-mark { width: 36px; height: 36px; flex-shrink: 0; }
3477
+ .logo-badge { color: #ffffff; }
3478
+ .tagline { color: var(--text-muted); font-size: 14px; font-weight: 400; }
3393
3479
  .grid { display: flex; flex-direction: column; gap: 12px; }
3394
3480
  .card {
3395
3481
  background: var(--card-bg);
@@ -3405,15 +3491,15 @@ function generateAndOpenLaunchpad() {
3405
3491
  transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
3406
3492
  }
3407
3493
  .card:hover {
3408
- border-color: rgba(88, 166, 255, 0.4);
3494
+ border-color: rgba(155, 48, 196, 0.45);
3409
3495
  transform: translateY(-2px);
3410
3496
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
3411
3497
  }
3412
3498
  .card-content { display: flex; align-items: center; gap: 14px; }
3413
3499
  .card-icon {
3414
- font-size: 22px;
3415
3500
  width: 40px;
3416
3501
  height: 40px;
3502
+ padding: 6px;
3417
3503
  border-radius: 10px;
3418
3504
  background: rgba(255, 255, 255, 0.04);
3419
3505
  border: 1px solid rgba(255, 255, 255, 0.06);
@@ -3421,6 +3507,7 @@ function generateAndOpenLaunchpad() {
3421
3507
  align-items: center;
3422
3508
  justify-content: center;
3423
3509
  }
3510
+ .card-icon svg { width: 100%; height: 100%; }
3424
3511
  .card-info h2 { font-size: 15px; font-weight: 600; margin-bottom: 2px; }
3425
3512
  .card-info p { font-size: 13px; color: var(--text-muted); }
3426
3513
  .card-meta {
@@ -3434,7 +3521,7 @@ function generateAndOpenLaunchpad() {
3434
3521
  background: rgba(255, 255, 255, 0.06);
3435
3522
  padding: 4px 10px;
3436
3523
  border-radius: 20px;
3437
- color: #79c0ff;
3524
+ color: #c77dea;
3438
3525
  }
3439
3526
  .status-dot {
3440
3527
  width: 8px;
@@ -3460,13 +3547,43 @@ function generateAndOpenLaunchpad() {
3460
3547
  <body>
3461
3548
  <div class="container">
3462
3549
  <div class="header">
3463
- <div class="logo">🚀 <span class="logo-badge">BDB Agent OS</span></div>
3550
+ <div class="logo">
3551
+ <svg class="logo-mark" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">
3552
+ <defs>
3553
+ <linearGradient id="bdbPlateLight" x1="0%" y1="0%" x2="100%" y2="100%">
3554
+ <stop offset="0%" stop-color="#FFFFFF"/><stop offset="60%" stop-color="#FFFFFF"/><stop offset="100%" stop-color="#E7E7EA"/>
3555
+ </linearGradient>
3556
+ <linearGradient id="bdbPlateDark" x1="0%" y1="0%" x2="0%" y2="100%">
3557
+ <stop offset="0%" stop-color="#1C1C1F"/><stop offset="100%" stop-color="#050505"/>
3558
+ </linearGradient>
3559
+ </defs>
3560
+ <circle cx="256" cy="256" r="195" fill="url(#bdbPlateDark)" stroke="#FFFFFF" stroke-width="2" stroke-opacity="0.6"/>
3561
+ <circle cx="256" cy="256" r="175" fill="#0a0a0a"/>
3562
+ <g transform="translate(70, 68) scale(1.0)">
3563
+ <path fill="url(#bdbPlateLight)" d="M181.63.05c101.39-2.47,184.56,80.09,190.14,179.93,5.53,99.03-66.16,185.42-165.11,195.46-87.39,8.86-171.1-45.56-197.67-128.96C-28.74,128.03,56.78,3.1,181.63.05h0ZM177.5,21.3C69.09,25.31-7.16,129.62,21.76,234.52c18.72,67.88,81.56,116.7,151.53,121.32,106.21,7.03,195.6-81.63,179.68-189.06-12.54-84.65-89.81-148.66-175.47-145.49h0Z"/>
3564
+ <g fill="#FFFFFF">
3565
+ <path d="M147.69,120.05c12.04.36,24.64-.72,36.62-.07,24.29,1.32,41.37,20.13,42.91,43.99-.69,16.35.57,33.42-.28,49.69-1.31,25.42-18.55,43.75-44.02,45.64-9.59.72-20.14.69-29.78.84-4.97.08-9.9.68-10.37-5.66s.43-9.41.34-14.03c12.65-11.84,14.75-31.17,4.75-45.41-.63-.9-2.26-2.34-2.62-3.17s-.46-12.58-.26-14.37,1.1-3.52,1.46-5.16c1.21-5.42,1.06-11.26-.39-16.62-.41-1.54-1.48-3.56-1.63-4.99-.47-4.28-.14-9.67-.26-14.08-.11-3.56-.84-8.43-.57-11.86s1.32-4.35,4.08-4.75h0ZM162.03,135.5c-4.32.73-3.34,6.65-3.26,10.01.17,6.21.91,12.51,1.13,18.73.83,23.13-1.03,45.49-1.41,68.42-.07,3.93-1.27,10.87,4.01,11.46,10.36-.51,21.39,1.89,31.38-1.45,13.74-4.59,20.43-17.79,19.81-31.81-1.77-14.46-1.19-29.09-1.94-43.58-.52-10.12-3.97-20.33-12.44-26.46-10.8-7.82-24.82-4.88-37.29-5.34h0Z"/>
3566
+ <path d="M232.66,132.46c9.53.36,19.74-.72,29.19-.08,22.64,1.52,33.92,28.58,21.93,47.05-1.49,2.3-4.32,4.47-3.85,7.42.47,2.95,5.64,6.21,7.42,8.3,11.88,13.96,8.41,35.69-6.91,45.49-7.85,5.02-14.69,4.43-23.56,4.86-7.67.37-16.24,1.05-23.91.66-1.66-.08-2.98-.73-3.68-2.32s-.52-7.28-.43-9.26c.36-6.63,3.52-13.04,3.89-20.39.58-11.38-.1-23.12-.3-34.49-.1-5.68.32-11.44-.3-17.08-.41-3.82-1.64-7.52-1.89-11.35-.25-3.85-.18-7.99-.26-11.88-.07-2.84-1.26-6.03,2.68-6.95h-.01ZM243.68,144.59c-3.41.77-2.55,6.7-2.66,9.2-.28,6.08-.58,12.36-.29,18.47.1,2.06.36,6.36.9,8.21.54,1.85.84,1.79,1.66,2.19,1.66.83,8-.68,10.26-.88,4.22-.39,8.12.03,12.28-1.24,16.76-5.12,16.53-26.53,1.01-33.02-15.52-6.5-13.5-2.7-18.82-2.98-5.31-.28-3.37-.17-4.36.06h.03ZM243.68,194.52c-3.49.79-2.58,8.66-2.68,11.39-.26,7.05-1.06,17.41.07,24.21,1.13,6.8,2.63,3.38,5.32,3.26,3.96-.19,8.36-1.32,12.4-1.67,5.85-.5,10.68.22,16.24-2.25,13.6-6.04,12.62-25.27-.46-31.46-5.63-2.66-9.89-1.97-15.78-2.43-3.57-.28-7.2-.92-10.76-1.1-1.12-.06-3.35-.17-4.36.06h0Z"/>
3567
+ <path d="M90.59,133.03c8.84-.44,25.24-1.08,33.23,1.92,18.07,6.77,23.99,29.96,13.56,45.7-1.6,2.41-4.52,4.44-3.28,7.75.69,1.85,5.41,5.42,7.03,7.31,11.86,13.82,8.77,35.23-6.25,45.33-15.02,10.1-23.31,5.27-34.44,5.56-4.12.11-10.36.88-14.32.28-2.22-.34-3.45-2.79-3.48-4.83-.11-7.84.77-15.89,1.1-23.71.99-23.09,1.31-45.33.57-68.43-.14-4.15-1.05-9.79-.57-13.79.43-3.52,4.1-2.95,6.84-3.09h0ZM98.3,145.15c-1.71.29-2.98,1.7-3.21,3.41-.15,1.19-.23,3.13-.3,4.39-.39,8.01-.9,19.53.58,27.27.23,1.24.57,2.55,1.82,3.15,1.81.84,7.03-.55,9.32-.76,3.3-.3,6.62-.1,9.89-.59,21.2-3.21,21.02-29.7,1.28-34.86-4.36-1.14-13.16-1.92-17.79-2.07-.55-.01-1.03-.03-1.59.07h0ZM98.03,195.09c-4.25.88-2.46,6.76-3.24,9.72-.06,7.92-.55,15.86,0,23.75.22,3.21.77,5.75,4.57,5.67,3.82-.08,8.46-1.32,12.41-1.67,5.55-.48,11.21.12,16.48-2,14.62-5.88,13.53-26.13-.52-32.17-5.13-2.21-8.25-1.59-13.48-1.97-4.69-.34-9.7-1.23-14.35-1.38-.62-.01-1.26-.07-1.86.06h-.01Z"/>
3568
+ </g>
3569
+ </g>
3570
+ </svg>
3571
+ <span class="logo-badge">BDB Agent OS</span>
3572
+ </div>
3464
3573
  <p class="tagline">Local Multi-Agent Ecosystem Hub</p>
3465
3574
  </div>
3466
3575
  <div class="grid">
3467
3576
  <a class="card" href="http://127.0.0.1:8088" target="_blank">
3468
3577
  <div class="card-content">
3469
- <div class="card-icon">🧠</div>
3578
+ <div class="card-icon"><svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
3579
+ <defs><linearGradient id="grad-memb" x1="50%" y1="0%" x2="50%" y2="100%"><stop offset="0%" stop-color="#FFFFFF"/><stop offset="100%" stop-color="#51116F"/></linearGradient></defs>
3580
+ <polygon points="50,10 85,45 50,90 15,45" fill="url(#grad-memb)" opacity="0.9"/>
3581
+ <polyline points="50,10 50,90" stroke="#FFFFFF" stroke-width="2" opacity="0.6"/>
3582
+ <polyline points="15,45 85,45" stroke="#FFFFFF" stroke-width="2" opacity="0.6"/>
3583
+ <line x1="50" y1="45" x2="70" y2="25" stroke="#FFFFFF" stroke-width="1.5" opacity="0.5"/>
3584
+ <line x1="50" y1="45" x2="30" y2="70" stroke="#FFFFFF" stroke-width="1.5" opacity="0.5"/>
3585
+ <circle cx="50" cy="45" r="4" fill="#FFFFFF"/><circle cx="70" cy="25" r="2" fill="#FFFFFF"/><circle cx="30" cy="70" r="2" fill="#FFFFFF"/>
3586
+ </svg></div>
3470
3587
  <div class="card-info">
3471
3588
  <h2>memB Vector Memory</h2>
3472
3589
  <p>Autonomous Vector & Long-Term Memory</p>
@@ -3479,7 +3596,15 @@ function generateAndOpenLaunchpad() {
3479
3596
  </a>
3480
3597
  <a class="card" href="http://127.0.0.1:7781" target="_blank">
3481
3598
  <div class="card-content">
3482
- <div class="card-icon">🏙️</div>
3599
+ <div class="card-icon"><svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
3600
+ <defs><linearGradient id="grad-synapse" x1="50%" y1="0%" x2="50%" y2="100%"><stop offset="0%" stop-color="#FFFFFF"/><stop offset="100%" stop-color="#51116F"/></linearGradient></defs>
3601
+ <rect x="20" y="55" width="14" height="30" rx="2" fill="url(#grad-synapse)" opacity="0.85"/>
3602
+ <rect x="43" y="35" width="14" height="50" rx="2" fill="url(#grad-synapse)" opacity="0.9"/>
3603
+ <rect x="66" y="45" width="14" height="40" rx="2" fill="url(#grad-synapse)" opacity="0.8"/>
3604
+ <line x1="27" y1="55" x2="50" y2="35" stroke="#FFFFFF" stroke-width="1.5" opacity="0.5"/>
3605
+ <line x1="50" y1="35" x2="73" y2="45" stroke="#FFFFFF" stroke-width="1.5" opacity="0.5"/>
3606
+ <circle cx="27" cy="55" r="3" fill="#FFFFFF"/><circle cx="50" cy="35" r="3" fill="#FFFFFF"/><circle cx="73" cy="45" r="3" fill="#FFFFFF"/>
3607
+ </svg></div>
3483
3608
  <div class="card-info">
3484
3609
  <h2>Synapse 3D</h2>
3485
3610
  <p>Interactive Codebase Topology & Sessions</p>
@@ -3492,7 +3617,40 @@ function generateAndOpenLaunchpad() {
3492
3617
  </a>
3493
3618
  <a class="card" href="http://127.0.0.1:3101" target="_blank">
3494
3619
  <div class="card-content">
3495
- <div class="card-icon">⚡</div>
3620
+ <div class="card-icon"><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">
3621
+ <defs>
3622
+ <linearGradient id="plateLight" x1="0%" y1="0%" x2="0%" y2="100%"><stop offset="0%" stop-color="#FFFFFF"/><stop offset="60%" stop-color="#FFFFFF"/><stop offset="100%" stop-color="#E7E7EA"/></linearGradient>
3623
+ <linearGradient id="plateMid" x1="0%" y1="0%" x2="0%" y2="100%"><stop offset="0%" stop-color="#9b30c4"/><stop offset="100%" stop-color="#51116F"/></linearGradient>
3624
+ <linearGradient id="plateDark" x1="0%" y1="0%" x2="0%" y2="100%"><stop offset="0%" stop-color="#1C1C1F"/><stop offset="100%" stop-color="#050505"/></linearGradient>
3625
+ </defs>
3626
+ <g id="antennae" stroke="#000000" stroke-width="2.5" stroke-linejoin="round">
3627
+ <rect x="180" y="45" width="20" height="30" rx="2" fill="url(#plateLight)"/><polygon points="180,45 190,25 200,45" fill="#FFFFFF"/><circle cx="190" cy="25" r="4" fill="#FFFFFF"/>
3628
+ <rect x="186" y="80" width="22" height="34" rx="2" fill="url(#plateMid)"/><rect x="194" y="118" width="24" height="38" rx="2" fill="url(#plateDark)"/><rect x="202" y="160" width="26" height="38" rx="2" fill="url(#plateDark)"/>
3629
+ <rect x="312" y="45" width="20" height="30" rx="2" fill="url(#plateLight)"/><polygon points="312,45 322,25 332,45" fill="#FFFFFF"/><circle cx="322" cy="25" r="4" fill="#FFFFFF"/>
3630
+ <rect x="304" y="80" width="22" height="34" rx="2" fill="url(#plateMid)"/><rect x="294" y="118" width="24" height="38" rx="2" fill="url(#plateDark)"/><rect x="284" y="160" width="26" height="38" rx="2" fill="url(#plateDark)"/>
3631
+ </g>
3632
+ <g id="head" stroke="#000000" stroke-width="2.5" stroke-linejoin="round">
3633
+ <rect x="238" y="170" width="36" height="32" rx="3" fill="url(#plateLight)"/>
3634
+ <rect x="156" y="206" width="200" height="88" rx="6" fill="url(#plateDark)"/>
3635
+ <rect x="136" y="230" width="20" height="40" rx="3" fill="url(#plateMid)"/><rect x="356" y="230" width="20" height="40" rx="3" fill="url(#plateMid)"/>
3636
+ </g>
3637
+ <g id="eyes">
3638
+ <rect x="174" y="222" width="56" height="52" rx="5" fill="#000000" stroke="#FFFFFF" stroke-width="2"/><rect x="180" y="228" width="44" height="40" rx="3" fill="url(#plateDark)"/>
3639
+ <circle cx="202" cy="248" r="14" fill="#FFFFFF" opacity="0.3"/><circle cx="202" cy="248" r="7" fill="#FFFFFF"/><circle cx="205" cy="245" r="2.5" fill="#FFFFFF"/>
3640
+ <rect x="282" y="222" width="56" height="52" rx="5" fill="#000000" stroke="#FFFFFF" stroke-width="2"/><rect x="288" y="228" width="44" height="40" rx="3" fill="url(#plateDark)"/>
3641
+ <circle cx="310" cy="248" r="14" fill="#FFFFFF" opacity="0.3"/><circle cx="310" cy="248" r="7" fill="#FFFFFF"/><circle cx="313" cy="245" r="2.5" fill="#FFFFFF"/>
3642
+ </g>
3643
+ <g id="mandibles" stroke="#000000" stroke-width="2.5">
3644
+ <rect x="226" y="298" width="60" height="18" rx="3" fill="url(#plateLight)"/>
3645
+ <rect x="236" y="303" width="10" height="8" rx="1.5" fill="#51116F"/><rect x="251" y="303" width="10" height="8" rx="1.5" fill="#51116F"/><rect x="266" y="303" width="10" height="8" rx="1.5" fill="#51116F"/>
3646
+ <polygon points="196,300 220,300 206,340" fill="url(#plateLight)"/><polygon points="316,300 292,300 306,340" fill="url(#plateLight)"/>
3647
+ </g>
3648
+ <g id="thorax" stroke="#000000" stroke-width="2.5" stroke-linejoin="round">
3649
+ <rect x="180" y="336" width="152" height="74" rx="6" fill="url(#plateMid)"/>
3650
+ <rect x="216" y="352" width="80" height="42" rx="4" fill="#0c0414" stroke="#FFFFFF" stroke-width="1.5"/>
3651
+ <text x="256" y="378" fill="#FFFFFF" font-family="monospace" font-size="14" font-weight="900" text-anchor="middle" letter-spacing="3">BDB</text>
3652
+ </g>
3653
+ </svg></div>
3496
3654
  <div class="card-info">
3497
3655
  <h2>AO — Agent Orchestrator</h2>
3498
3656
  <p>Multi-Agent Cockpit & Git-Worktree Orchestration</p>
@@ -3505,7 +3663,15 @@ function generateAndOpenLaunchpad() {
3505
3663
  </a>
3506
3664
  <a class="card" href="http://127.0.0.1:9080" target="_blank">
3507
3665
  <div class="card-content">
3508
- <div class="card-icon">🌐</div>
3666
+ <div class="card-icon"><svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
3667
+ <defs><linearGradient id="grad-remote" x1="50%" y1="0%" x2="50%" y2="100%"><stop offset="0%" stop-color="#FFFFFF"/><stop offset="100%" stop-color="#51116F"/></linearGradient></defs>
3668
+ <circle cx="50" cy="50" r="32" fill="none" stroke="url(#grad-remote)" stroke-width="3" opacity="0.6"/>
3669
+ <circle cx="50" cy="50" r="8" fill="url(#grad-remote)"/>
3670
+ <circle cx="50" cy="14" r="4" fill="#FFFFFF"/><circle cx="82" cy="65" r="4" fill="#FFFFFF"/><circle cx="18" cy="65" r="4" fill="#FFFFFF"/>
3671
+ <line x1="50" y1="50" x2="50" y2="18" stroke="#FFFFFF" stroke-width="1.5" opacity="0.6"/>
3672
+ <line x1="50" y1="50" x2="79" y2="63" stroke="#FFFFFF" stroke-width="1.5" opacity="0.6"/>
3673
+ <line x1="50" y1="50" x2="21" y2="63" stroke="#FFFFFF" stroke-width="1.5" opacity="0.6"/>
3674
+ </svg></div>
3509
3675
  <div class="card-info">
3510
3676
  <h2>RemoteOS Gateway</h2>
3511
3677
  <p>Multi-Cloud Execution & 4-Eyes Approval Gateway</p>
@@ -3516,6 +3682,30 @@ function generateAndOpenLaunchpad() {
3516
3682
  <span class="status-dot" id="dot-remote" title="Checking..."></span>
3517
3683
  </div>
3518
3684
  </a>
3685
+ <a class="card" href="http://127.0.0.1:4321" target="_blank">
3686
+ <div class="card-content">
3687
+ <div class="card-icon"><svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
3688
+ <defs><linearGradient id="grad-openwiki" x1="50%" y1="0%" x2="50%" y2="100%"><stop offset="0%" stop-color="#FFFFFF"/><stop offset="100%" stop-color="#51116F"/></linearGradient></defs>
3689
+ <rect x="26" y="16" width="48" height="68" rx="4" fill="url(#grad-openwiki)" opacity="0.9"/>
3690
+ <line x1="36" y1="32" x2="64" y2="32" stroke="#0a0a0a" stroke-width="2.5" opacity="0.5"/>
3691
+ <line x1="36" y1="42" x2="64" y2="42" stroke="#0a0a0a" stroke-width="2.5" opacity="0.5"/>
3692
+ <line x1="36" y1="52" x2="52" y2="52" stroke="#0a0a0a" stroke-width="2.5" opacity="0.5"/>
3693
+ <circle cx="70" cy="68" r="14" fill="#0a0a0a" stroke="#FFFFFF" stroke-width="2"/>
3694
+ <circle cx="65" cy="64" r="2.5" fill="#FFFFFF"/><circle cx="74" cy="63" r="2.5" fill="#FFFFFF"/><circle cx="70" cy="72" r="2.5" fill="#FFFFFF"/>
3695
+ <line x1="65" y1="64" x2="74" y2="63" stroke="#FFFFFF" stroke-width="1.2" opacity="0.7"/>
3696
+ <line x1="65" y1="64" x2="70" y2="72" stroke="#FFFFFF" stroke-width="1.2" opacity="0.7"/>
3697
+ <line x1="74" y1="63" x2="70" y2="72" stroke="#FFFFFF" stroke-width="1.2" opacity="0.7"/>
3698
+ </svg></div>
3699
+ <div class="card-info">
3700
+ <h2>OpenWiki</h2>
3701
+ <p>Grounded Documentation & Evidence Graph</p>
3702
+ </div>
3703
+ </div>
3704
+ <div class="card-meta">
3705
+ <span class="port-pill">:4321</span>
3706
+ <span class="status-dot" id="dot-openwiki" title="Checking..."></span>
3707
+ </div>
3708
+ </a>
3519
3709
  </div>
3520
3710
  <div class="footer">
3521
3711
  <span>Autostart Daemons • 127.0.0.1</span>
@@ -3534,6 +3724,7 @@ function generateAndOpenLaunchpad() {
3534
3724
  checkHealth('http://127.0.0.1:7781', 'dot-synapse');
3535
3725
  checkHealth('http://127.0.0.1:3101', 'dot-ao');
3536
3726
  checkHealth('http://127.0.0.1:9080', 'dot-remote');
3727
+ checkHealth('http://127.0.0.1:4321', 'dot-openwiki');
3537
3728
  }
3538
3729
  checkAllHealth();
3539
3730
  setInterval(checkAllHealth, 5000);
@@ -3761,6 +3952,7 @@ async function runQuickUpdate(installState) {
3761
3952
  const creds = await promptCredentials(paths.targetMcpDir);
3762
3953
  if (creds !== BACK) {
3763
3954
  await installOpenWikiDaemon(creds.gemini, paths.targetSkillDir, { provider: creds.openwikiProvider, model: creds.openwikiModel, baseUrl: creds.openwikiBaseUrl });
3955
+ await installOpenWikiVisualizer();
3764
3956
  }
3765
3957
  }
3766
3958
 
@@ -4173,6 +4365,7 @@ async function main() {
4173
4365
  }
4174
4366
 
4175
4367
  await installOpenWikiDaemon(creds.gemini, primaryTarget.targetSkillDir, { provider: creds.openwikiProvider, model: creds.openwikiModel, baseUrl: creds.openwikiBaseUrl });
4368
+ await installOpenWikiVisualizer();
4176
4369
  await installTokenSaver(primaryTarget.platformValue);
4177
4370
 
4178
4371
  const installedModulesForPrompt = (installState && installState.installedModules) || [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hybridlabor-api/aos",
3
- "version": "4.4.2-beta.8",
3
+ "version": "4.5.0",
4
4
  "description": "AOS — A Curated AI AGENT OS. Optimized agent skills and add-ons like memB, OpenWiki, Heimdall Token Saver, and Godmode architectures.",
5
5
  "main": "installer.js",
6
6
  "engines": {
@@ -26,35 +26,84 @@ try {
26
26
  Write-Host "Warning: pip install failed. Install google-genai manually." -ForegroundColor Yellow
27
27
  }
28
28
 
29
- # 3. Resolve API key
30
- $GeminiKey = $env:GEMINI_API_KEY
31
- if ([string]::IsNullOrWhiteSpace($GeminiKey)) {
32
- Write-Host ""
33
- $GeminiKey = Read-Host "Enter your Gemini API key (or press Enter to skip)"
34
- }
35
-
36
- if (-not [string]::IsNullOrWhiteSpace($GeminiKey)) {
37
- Write-Host "Verifying API key..." -ForegroundColor Yellow
38
- # verify_api_key.py reads GEMINI_API_KEY from its own process environment.
39
- # A key typed at the Read-Host prompt above exists only in $GeminiKey, so it
40
- # has to be published to this process before python is started - otherwise
41
- # the child sees nothing and every interactively entered key fails the check
42
- # and is discarded below.
43
- $env:GEMINI_API_KEY = $GeminiKey
44
- $VerifyScript = Join-Path $PSScriptRoot "verify_api_key.py"
45
- $VerifyOutput = & python $VerifyScript 2>&1
46
- $VerifyCode = $LASTEXITCODE
47
- if ($VerifyCode -eq 0 -and ($VerifyOutput -match "VERIFIED_OK")) {
48
- Write-Host " -> API key verified." -ForegroundColor Green
49
- [System.Environment]::SetEnvironmentVariable("GEMINI_API_KEY", $GeminiKey, "User")
29
+ # 3. Resolve provider and API key
30
+ $OpenwikiProvider = $env:OPENWIKI_PROVIDER
31
+ if ([string]::IsNullOrWhiteSpace($OpenwikiProvider)) {
32
+ $OpenwikiProvider = "google"
33
+ }
34
+
35
+ # Map provider to its API key environment variable name
36
+ $ApiKeyVar = switch ($OpenwikiProvider) {
37
+ "google" { "GEMINI_API_KEY" }
38
+ "groq" { "GROQ_API_KEY" }
39
+ "grok" { "XAI_API_KEY" }
40
+ "xai" { "XAI_API_KEY" }
41
+ "nvidia" { "NVIDIA_API_KEY" }
42
+ "openrouter" { "OPENROUTER_API_KEY" }
43
+ "openai" { "OPENAI_API_KEY" }
44
+ "custom" { "OPENWIKI_API_KEY" }
45
+ "ollama" { $null }
46
+ default { "GEMINI_API_KEY"; $OpenwikiProvider = "google" }
47
+ }
48
+
49
+ # For Google provider, use the existing interactive flow with verification
50
+ if ($OpenwikiProvider -eq "google") {
51
+ $ApiKey = $env:GEMINI_API_KEY
52
+ if ([string]::IsNullOrWhiteSpace($ApiKey)) {
53
+ Write-Host ""
54
+ $ApiKey = Read-Host "Enter your Gemini API key (or press Enter to skip)"
55
+ }
56
+
57
+ if (-not [string]::IsNullOrWhiteSpace($ApiKey)) {
58
+ Write-Host "Verifying API key..." -ForegroundColor Yellow
59
+ # verify_api_key.py reads GEMINI_API_KEY from its own process environment.
60
+ # A key typed at the Read-Host prompt above exists only in $ApiKey, so it
61
+ # has to be published to this process before python is started - otherwise
62
+ # the child sees nothing and every interactively entered key fails the check
63
+ # and is discarded below.
64
+ $env:GEMINI_API_KEY = $ApiKey
65
+ $VerifyScript = Join-Path $PSScriptRoot "verify_api_key.py"
66
+ $VerifyOutput = & python $VerifyScript 2>&1
67
+ $VerifyCode = $LASTEXITCODE
68
+ if ($VerifyCode -eq 0 -and ($VerifyOutput -match "VERIFIED_OK")) {
69
+ Write-Host " -> API key verified." -ForegroundColor Green
70
+ [System.Environment]::SetEnvironmentVariable("GEMINI_API_KEY", $ApiKey, "User")
71
+ } else {
72
+ Write-Host " -> WARNING: API key verification failed (with retry + TLS fallback)." -ForegroundColor Yellow
73
+ $VerifyOutput | ForEach-Object { Write-Host " $_" -ForegroundColor DarkGray }
74
+ Write-Host " The daemon will run in collect-only mode until a valid key is set." -ForegroundColor Yellow
75
+ $ApiKey = ""
76
+ }
50
77
  } else {
51
- Write-Host " -> WARNING: API key verification failed (with retry + TLS fallback)." -ForegroundColor Yellow
52
- $VerifyOutput | ForEach-Object { Write-Host " $_" -ForegroundColor DarkGray }
53
- Write-Host " The daemon will run in collect-only mode until a valid key is set." -ForegroundColor Yellow
54
- $GeminiKey = ""
78
+ Write-Host "No API key provided. Daemon will run in collect-only mode." -ForegroundColor Yellow
55
79
  }
56
80
  } else {
57
- Write-Host "No API key provided. Daemon will run in collect-only mode." -ForegroundColor Yellow
81
+ # For non-Google providers, skip verification and use the configured key
82
+ if ([string]::IsNullOrWhiteSpace($ApiKeyVar)) {
83
+ $ApiKey = ""
84
+ } else {
85
+ $ApiKey = (Get-Item -Path "env:$ApiKeyVar" -ErrorAction SilentlyContinue).Value
86
+ if ([string]::IsNullOrWhiteSpace($ApiKey)) {
87
+ $ApiKey = ""
88
+ }
89
+ }
90
+ if ([string]::IsNullOrWhiteSpace($ApiKey)) {
91
+ Write-Host "No API key provided for provider '$OpenwikiProvider'. Daemon will run in collect-only mode." -ForegroundColor Yellow
92
+ }
93
+ }
94
+
95
+ # Persist provider and model configuration
96
+ [System.Environment]::SetEnvironmentVariable("OPENWIKI_PROVIDER", $OpenwikiProvider, "User")
97
+ if (-not [string]::IsNullOrWhiteSpace($env:OPENWIKI_MODEL)) {
98
+ [System.Environment]::SetEnvironmentVariable("OPENWIKI_MODEL", $env:OPENWIKI_MODEL, "User")
99
+ }
100
+ if (-not [string]::IsNullOrWhiteSpace($env:OPENWIKI_BASE_URL)) {
101
+ [System.Environment]::SetEnvironmentVariable("OPENWIKI_BASE_URL", $env:OPENWIKI_BASE_URL, "User")
102
+ }
103
+
104
+ # Persist the appropriate API key
105
+ if (-not [string]::IsNullOrWhiteSpace($ApiKey) -and -not [string]::IsNullOrWhiteSpace($ApiKeyVar)) {
106
+ [System.Environment]::SetEnvironmentVariable($ApiKeyVar, $ApiKey, "User")
58
107
  }
59
108
 
60
109
  # 4. Ensure log directory
@@ -171,8 +220,12 @@ if ($Registered) {
171
220
  Write-Host " -> Projects config: $DaemonLogDir\projects.json" -ForegroundColor Yellow
172
221
  }
173
222
 
174
- if (-not [string]::IsNullOrWhiteSpace($GeminiKey)) {
175
- Write-Host " -> API key stored as the GEMINI_API_KEY user environment variable" -ForegroundColor Green
223
+ if (-not [string]::IsNullOrWhiteSpace($ApiKey)) {
224
+ if (-not [string]::IsNullOrWhiteSpace($ApiKeyVar)) {
225
+ Write-Host " -> API key stored as the $ApiKeyVar user environment variable" -ForegroundColor Green
226
+ } else {
227
+ Write-Host " -> Provider configured: $OpenwikiProvider" -ForegroundColor Green
228
+ }
176
229
  Write-Host " (not embedded in the task or the startup file)." -ForegroundColor Green
177
230
  }
178
231
 
@@ -92,29 +92,65 @@ else
92
92
  echo " -> google-genai installed; daemon will run under $DAEMON_PYTHON"
93
93
  fi
94
94
 
95
- # 3. Resolve API key
96
- GEMINI_KEY="${GEMINI_API_KEY:-}"
97
- if [ -z "$GEMINI_KEY" ]; then
98
- echo ""
99
- echo "GEMINI_API_KEY is not set in your environment."
100
- read -rp "Enter your Gemini API key (or press Enter to skip): " GEMINI_KEY
101
- fi
95
+ # 3. Resolve provider and API key
96
+ OPENWIKI_PROVIDER="${OPENWIKI_PROVIDER:-google}"
97
+ # set -u is active; a provider that needs no model override/base URL (the
98
+ # common case) never gets these exported, and the bare $OPENWIKI_MODEL /
99
+ # $OPENWIKI_BASE_URL reads inside write_launcher()'s subshell used to abort
100
+ # that subshell on "unbound variable" -- silently truncating the launcher
101
+ # before it reached the API key export or the final exec line.
102
+ OPENWIKI_MODEL="${OPENWIKI_MODEL:-}"
103
+ OPENWIKI_BASE_URL="${OPENWIKI_BASE_URL:-}"
104
+
105
+ # Map provider to its API key environment variable name
106
+ case "$OPENWIKI_PROVIDER" in
107
+ google) API_KEY_VAR="GEMINI_API_KEY" ;;
108
+ groq) API_KEY_VAR="GROQ_API_KEY" ;;
109
+ grok|xai) API_KEY_VAR="XAI_API_KEY" ;;
110
+ nvidia) API_KEY_VAR="NVIDIA_API_KEY" ;;
111
+ openrouter) API_KEY_VAR="OPENROUTER_API_KEY" ;;
112
+ openai) API_KEY_VAR="OPENAI_API_KEY" ;;
113
+ custom) API_KEY_VAR="OPENWIKI_API_KEY" ;;
114
+ ollama) API_KEY_VAR="" ;;
115
+ *) OPENWIKI_PROVIDER="google"; API_KEY_VAR="GEMINI_API_KEY" ;;
116
+ esac
117
+
118
+ # For Google provider, use the existing interactive flow with verification
119
+ if [ "$OPENWIKI_PROVIDER" = "google" ]; then
120
+ GEMINI_KEY="${GEMINI_API_KEY:-}"
121
+ if [ -z "$GEMINI_KEY" ]; then
122
+ echo ""
123
+ echo "GEMINI_API_KEY is not set in your environment."
124
+ read -rp "Enter your Gemini API key (or press Enter to skip): " GEMINI_KEY
125
+ fi
102
126
 
103
- if [ -n "$GEMINI_KEY" ]; then
104
- export GEMINI_API_KEY="$GEMINI_KEY"
105
- echo "Verifying API key..."
106
- VERIFY_OUTPUT=$("$DAEMON_PYTHON" "$SCRIPTS_DIR/verify_api_key.py" 2>&1)
107
- VERIFY_CODE=$?
108
- if [ $VERIFY_CODE -eq 0 ] && echo "$VERIFY_OUTPUT" | grep -q "VERIFIED_OK"; then
109
- echo " -> API key verified successfully."
127
+ if [ -n "$GEMINI_KEY" ]; then
128
+ export GEMINI_API_KEY="$GEMINI_KEY"
129
+ echo "Verifying API key..."
130
+ VERIFY_OUTPUT=$("$DAEMON_PYTHON" "$SCRIPTS_DIR/verify_api_key.py" 2>&1)
131
+ VERIFY_CODE=$?
132
+ if [ $VERIFY_CODE -eq 0 ] && echo "$VERIFY_OUTPUT" | grep -q "VERIFIED_OK"; then
133
+ echo " -> API key verified successfully."
134
+ else
135
+ echo " -> WARNING: API key verification failed (with retry + TLS fallback)."
136
+ echo "$VERIFY_OUTPUT" | sed 's/^/ /'
137
+ echo " The daemon will run in collect-only mode until a valid key is set."
138
+ GEMINI_KEY=""
139
+ fi
110
140
  else
111
- echo " -> WARNING: API key verification failed (with retry + TLS fallback)."
112
- echo "$VERIFY_OUTPUT" | sed 's/^/ /'
113
- echo " The daemon will run in collect-only mode until a valid key is set."
114
- GEMINI_KEY=""
141
+ echo "No API key provided. Daemon will run in collect-only mode."
115
142
  fi
143
+ API_KEY="$GEMINI_KEY"
116
144
  else
117
- echo "No API key provided. Daemon will run in collect-only mode."
145
+ # For non-Google providers, skip verification and use the configured key
146
+ if [ -n "$API_KEY_VAR" ]; then
147
+ API_KEY="${!API_KEY_VAR:-}"
148
+ else
149
+ API_KEY=""
150
+ fi
151
+ if [ -z "$API_KEY" ]; then
152
+ echo "No API key provided for provider '$OPENWIKI_PROVIDER'. Daemon will run in collect-only mode."
153
+ fi
118
154
  fi
119
155
 
120
156
  # --- Helpers -------------------------------------------------------------
@@ -179,12 +215,29 @@ write_launcher() {
179
215
  {
180
216
  printf '#!/bin/sh\n'
181
217
  printf '# Generated by install_daemon.sh - do not edit, re-run the installer.\n'
182
- printf '# Holds the OpenWiki API key so it stays out of the LaunchAgent plist\n'
183
- printf '# and the systemd unit. Mode 700 on purpose.\n'
218
+ printf '# Holds the OpenWiki provider config and API keys so they stay out of\n'
219
+ printf '# the LaunchAgent plist and the systemd unit. Mode 700 on purpose.\n'
184
220
  printf 'HOME=%s; export HOME\n' "$(sq "$HOME")"
185
221
  printf 'PATH=%s; export PATH\n' "$(sq "$path_value")"
186
- if [ -n "$GEMINI_KEY" ]; then
187
- printf 'GEMINI_API_KEY=%s; export GEMINI_API_KEY\n' "$(sq "$GEMINI_KEY")"
222
+ if [ -n "$OPENWIKI_PROVIDER" ]; then
223
+ printf 'OPENWIKI_PROVIDER=%s; export OPENWIKI_PROVIDER\n' "$(sq "$OPENWIKI_PROVIDER")"
224
+ fi
225
+ if [ -n "$OPENWIKI_MODEL" ]; then
226
+ printf 'OPENWIKI_MODEL=%s; export OPENWIKI_MODEL\n' "$(sq "$OPENWIKI_MODEL")"
227
+ fi
228
+ if [ -n "$OPENWIKI_BASE_URL" ]; then
229
+ printf 'OPENWIKI_BASE_URL=%s; export OPENWIKI_BASE_URL\n' "$(sq "$OPENWIKI_BASE_URL")"
230
+ fi
231
+ if [ -n "$API_KEY" ]; then
232
+ case "$OPENWIKI_PROVIDER" in
233
+ google) printf 'GEMINI_API_KEY=%s; export GEMINI_API_KEY\n' "$(sq "$API_KEY")" ;;
234
+ groq) printf 'GROQ_API_KEY=%s; export GROQ_API_KEY\n' "$(sq "$API_KEY")" ;;
235
+ grok|xai) printf 'XAI_API_KEY=%s; export XAI_API_KEY\n' "$(sq "$API_KEY")" ;;
236
+ nvidia) printf 'NVIDIA_API_KEY=%s; export NVIDIA_API_KEY\n' "$(sq "$API_KEY")" ;;
237
+ openrouter) printf 'OPENROUTER_API_KEY=%s; export OPENROUTER_API_KEY\n' "$(sq "$API_KEY")" ;;
238
+ openai) printf 'OPENAI_API_KEY=%s; export OPENAI_API_KEY\n' "$(sq "$API_KEY")" ;;
239
+ custom) printf 'OPENWIKI_API_KEY=%s; export OPENWIKI_API_KEY\n' "$(sq "$API_KEY")" ;;
240
+ esac
188
241
  fi
189
242
  printf 'exec %s %s --one-shot\n' "$(sq "$python_bin")" "$(sq "$SCRIPT_PATH")"
190
243
  } > "$LAUNCHER_PATH"
@@ -214,7 +267,7 @@ if [ "$OS" = "macos" ]; then
214
267
 
215
268
  MACOS_PATH="/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
216
269
  write_launcher "$DAEMON_PYTHON" "$MACOS_PATH"
217
- echo " -> Launcher written to $LAUNCHER_PATH (mode 700; holds the API key, if any)."
270
+ echo " -> Launcher written to $LAUNCHER_PATH (mode 700; holds the provider config and API key)."
218
271
 
219
272
  cat <<EOF > "$PLIST_PATH"
220
273
  <?xml version="1.0" encoding="UTF-8"?>
@@ -272,7 +325,7 @@ elif [ "$OS" = "linux" ]; then
272
325
 
273
326
  LINUX_PATH="/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
274
327
  write_launcher "$DAEMON_PYTHON" "$LINUX_PATH"
275
- echo " -> Launcher written to $LAUNCHER_PATH (mode 700; holds the API key, if any)."
328
+ echo " -> Launcher written to $LAUNCHER_PATH (mode 700; holds the provider config and API key)."
276
329
 
277
330
  cat > "$SYSTEMD_SERVICE" <<EOF
278
331
  [Unit]
@@ -1,276 +0,0 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
- const os = require('os');
4
- const https = require('https');
5
- const crypto = require('crypto');
6
- const { execSync, spawn } = require('child_process');
7
-
8
- const ISSUER = 'https://auth.awsbdb.rcentry.pro';
9
- const TARBALL_URL = 'https://internal.awsbdb.rcentry.pro/aos-internal/aos-internal.tgz';
10
- const CLIENT_ID = 'aos-installer';
11
- const CONFIG_DIR = path.join(os.homedir(), '.agents');
12
- const TOKEN_FILE = path.join(CONFIG_DIR, 'aos-internal.oauth.json');
13
-
14
- function httpsGet(url) {
15
- return new Promise((resolve, reject) => {
16
- https.get(url, { timeout: 10000 }, (res) => {
17
- let data = '';
18
- res.on('data', chunk => data += chunk);
19
- res.on('end', () => {
20
- try {
21
- resolve(JSON.parse(data));
22
- } catch (e) {
23
- reject(new Error(`Failed to parse response: ${e.message}`));
24
- }
25
- });
26
- }).on('error', reject).on('timeout', function() {
27
- this.destroy();
28
- reject(new Error('Request timeout'));
29
- });
30
- });
31
- }
32
-
33
- function httpsPost(url, body) {
34
- return new Promise((resolve, reject) => {
35
- const bodyStr = JSON.stringify(body);
36
- const req = https.request(url, {
37
- method: 'POST',
38
- headers: {
39
- 'Content-Type': 'application/x-www-form-urlencoded',
40
- 'Content-Length': Buffer.byteLength(bodyStr)
41
- },
42
- timeout: 10000
43
- }, (res) => {
44
- let data = '';
45
- res.on('data', chunk => data += chunk);
46
- res.on('end', () => {
47
- try {
48
- resolve({ status: res.statusCode, body: JSON.parse(data) });
49
- } catch (e) {
50
- reject(new Error(`Failed to parse response: ${e.message}`));
51
- }
52
- });
53
- });
54
- req.on('error', reject);
55
- req.on('timeout', function() {
56
- this.destroy();
57
- reject(new Error('Request timeout'));
58
- });
59
-
60
- const params = new URLSearchParams(body);
61
- req.write(params.toString());
62
- req.end();
63
- });
64
- }
65
-
66
- function httpsGetBinary(url, headers) {
67
- return new Promise((resolve, reject) => {
68
- const req = https.get(url, { headers, timeout: 30000 }, (res) => {
69
- if (res.statusCode !== 200) {
70
- reject(new Error(`HTTP ${res.statusCode}`));
71
- return;
72
- }
73
- const chunks = [];
74
- res.on('data', chunk => chunks.push(chunk));
75
- res.on('end', () => resolve(Buffer.concat(chunks)));
76
- });
77
- req.on('error', reject);
78
- req.on('timeout', function() {
79
- this.destroy();
80
- reject(new Error('Request timeout'));
81
- });
82
- });
83
- }
84
-
85
- function generatePKCE() {
86
- const codeVerifier = crypto.randomBytes(32).toString('base64url');
87
- const codeChallenge = crypto.createHash('sha256')
88
- .update(codeVerifier)
89
- .digest('base64url');
90
- return { codeVerifier, codeChallenge };
91
- }
92
-
93
- function tryOpenBrowser(verificationUri) {
94
- const cmd = process.platform === 'darwin' ? 'open' :
95
- process.platform === 'win32' ? 'start' : 'xdg-open';
96
- try {
97
- if (process.platform === 'win32') {
98
- execSync(`start ${verificationUri}`, { stdio: 'ignore', shell: true });
99
- } else {
100
- execSync(`${cmd} "${verificationUri}"`, { stdio: 'ignore' });
101
- }
102
- } catch (e) {
103
- // Browser open failed, but that's OK -- user can type the code manually
104
- }
105
- }
106
-
107
- function loadStoredToken() {
108
- try {
109
- if (!fs.existsSync(TOKEN_FILE)) return null;
110
- const data = JSON.parse(fs.readFileSync(TOKEN_FILE, 'utf8'));
111
- return data.refresh_token || null;
112
- } catch (e) {
113
- return null;
114
- }
115
- }
116
-
117
- function saveToken(refreshToken) {
118
- try {
119
- fs.mkdirSync(CONFIG_DIR, { recursive: true });
120
- fs.writeFileSync(TOKEN_FILE, JSON.stringify({ refresh_token: refreshToken }, null, 2), 'utf8');
121
- fs.chmodSync(TOKEN_FILE, 0o600);
122
- } catch (e) {
123
- // If we can't save the token, continue anyway - the user will just re-auth next time
124
- }
125
- }
126
-
127
- async function refreshAccessToken(refreshToken, discoveryResp) {
128
- try {
129
- const { codeVerifier } = generatePKCE();
130
- const resp = await httpsPost(discoveryResp.token_endpoint, {
131
- grant_type: 'refresh_token',
132
- refresh_token: refreshToken,
133
- client_id: CLIENT_ID,
134
- code_verifier: codeVerifier
135
- });
136
- if (resp.body.access_token) {
137
- if (resp.body.refresh_token) {
138
- saveToken(resp.body.refresh_token);
139
- }
140
- return resp.body.access_token;
141
- }
142
- return null;
143
- } catch (e) {
144
- return null;
145
- }
146
- }
147
-
148
- async function pollForToken(discoveryResp, deviceCode, codeVerifier, interval, expiresIn) {
149
- const deadline = Date.now() + (expiresIn * 1000);
150
- let currentInterval = interval;
151
-
152
- while (Date.now() < deadline) {
153
- await new Promise(r => setTimeout(r, currentInterval * 1000));
154
-
155
- try {
156
- const resp = await httpsPost(discoveryResp.token_endpoint, {
157
- grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
158
- device_code: deviceCode,
159
- client_id: CLIENT_ID,
160
- code_verifier: codeVerifier
161
- });
162
-
163
- const err = resp.body.error;
164
- if (err === 'authorization_pending') {
165
- continue;
166
- } else if (err === 'slow_down') {
167
- currentInterval += 5;
168
- continue;
169
- } else if (err === 'expired_token' || err === 'access_denied') {
170
- return null;
171
- } else if (resp.body.access_token) {
172
- if (resp.body.refresh_token) {
173
- saveToken(resp.body.refresh_token);
174
- }
175
- return resp.body.access_token;
176
- }
177
- } catch (e) {
178
- // Network error, keep polling
179
- continue;
180
- }
181
- }
182
- return null;
183
- }
184
-
185
- async function tryFetchInternalAddon(log) {
186
- try {
187
- const discovery = await httpsGet(`${ISSUER}/.well-known/openid-configuration`);
188
-
189
- if (!discovery.device_authorization_endpoint) {
190
- log.warn('Internal add-on package not available — device_authorization_endpoint missing.');
191
- return true;
192
- }
193
-
194
- const scopes = discovery.scopes_supported || [];
195
- if (!scopes.includes('authelia.bearer.authz')) {
196
- log.warn('Internal add-on package not available — authelia.bearer.authz scope not supported.');
197
- return true;
198
- }
199
-
200
- let accessToken = null;
201
-
202
- const storedRefresh = loadStoredToken();
203
- if (storedRefresh) {
204
- accessToken = await refreshAccessToken(storedRefresh, discovery);
205
- }
206
-
207
- if (!accessToken) {
208
- const { codeVerifier, codeChallenge } = generatePKCE();
209
-
210
- const deviceResp = await httpsPost(discovery.device_authorization_endpoint, {
211
- client_id: CLIENT_ID,
212
- scope: 'openid groups offline_access authelia.bearer.authz',
213
- code_challenge: codeChallenge,
214
- code_challenge_method: 'S256'
215
- });
216
-
217
- const deviceCode = deviceResp.body.device_code;
218
- const userCode = deviceResp.body.user_code;
219
- const verificationUri = deviceResp.body.verification_uri ||
220
- deviceResp.body.verification_uri_complete;
221
- const pollInterval = deviceResp.body.interval || 5;
222
- const expiresIn = deviceResp.body.expires_in || 1800;
223
-
224
- if (!deviceCode || !userCode || !verificationUri) {
225
- log.warn('Internal add-on package not available — device flow not available.');
226
- return true;
227
- }
228
-
229
- log.message('');
230
- log.message(' To authorize the internal add-on package:');
231
- log.message(` Code: ${userCode}`);
232
- log.message(` URL: ${verificationUri}`);
233
- log.message('');
234
-
235
- tryOpenBrowser(verificationUri);
236
-
237
- accessToken = await pollForToken(discovery, deviceCode, codeVerifier, pollInterval, expiresIn);
238
- if (!accessToken) {
239
- log.warn('Internal add-on package not available — authorization timeout.');
240
- return true;
241
- }
242
- }
243
-
244
- const tarballData = await httpsGetBinary(TARBALL_URL, {
245
- 'Authorization': `Bearer ${accessToken}`
246
- });
247
-
248
- const tempDir = path.join(CONFIG_DIR, '.tmp');
249
- fs.mkdirSync(tempDir, { recursive: true });
250
- const tempTarball = path.join(tempDir, 'aos-internal.tgz');
251
- fs.writeFileSync(tempTarball, tarballData);
252
-
253
- try {
254
- const installDir = path.join(CONFIG_DIR, 'aos-internal');
255
- fs.mkdirSync(installDir, { recursive: true });
256
- execSync(`npm install "${tempTarball}"`, {
257
- cwd: installDir,
258
- stdio: 'pipe',
259
- maxBuffer: 16 * 1024 * 1024
260
- });
261
- log.step('Internal add-on package installed');
262
- return true;
263
- } catch (e) {
264
- log.warn('Internal add-on package not available — npm install failed.');
265
- return true;
266
- } finally {
267
- try { fs.unlinkSync(tempTarball); } catch (e) {}
268
- try { fs.rmdirSync(tempDir); } catch (e) {}
269
- }
270
- } catch (e) {
271
- log.warn('Internal add-on package not available — continuing without it.');
272
- return true;
273
- }
274
- }
275
-
276
- module.exports = { tryFetchInternalAddon };