Compare commits

...
Author SHA1 Message Date
MervinPraisonandClaude Opus 4.8 afce1e542d docs: wire BeautifulUI playbook into aiui.template.yaml navigation
The shipped docs site is built by `aiui build` from aiui.template.yaml
(see ci.yml / deploy-pages.yml), not mkdocs.yml. Add a Frontend nav group
so the playbook is discoverable in the built site navigation.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-23 14:11:45 +00:00
MervinPraisonandClaude Opus 4.8 1807595cd0 docs: add BeautifulUI upgrade playbook and MIT attribution (fixes #298)
Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-23 13:52:35 +00:00
MervinPraisonandCursor 3058886312 chore: bump automation hub to v1.1.10 for merge gate fix
Co-authored-by: Cursor <[email protected]>
2026-09-22 15:30:07 +01:00
Mervin Praison 70d8610733 Merge pull request #291 from MervinPraison/claude/issue-290-20260916
docs: add SECURITY.md with private disclosure policy
2026-09-17 10:37:03 +01:00
MervinPraison 0f60ec41f1 Release v0.3.146 2026-09-17 03:02:10 +00:00
MervinPraisonandClaude Opus 4.8 2797667e04 docs: add SECURITY.md with private disclosure policy (fixes #290)
Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-16 16:28:01 +00:00
Mervin Praison f23aacdec9 Merge pull request #289 from MervinPraison/claude/issue-286-20260915
fix: auto-load ~/.praisonai/.env on aiui run so env: channel tokens resolve
2026-09-16 14:43:31 +01:00
MervinPraisonandClaude Opus 4.8 8dc8b9f49f fix: auto-load ~/.praisonai/.env on aiui run so env: tokens resolve (fixes #286)
Channels configured with env:VAR token references silently resolved to
empty strings when the dashboard was started without the shell exporting
the tokens, so bots showed 'Connected' but never replied. aiui run now
loads the standard PraisonAI .env files (~/.praisonai/.env, then ./.env)
into the process environment at startup, matching the PraisonAI CLI
convention. Existing process vars are never overridden and parsing is
dependency-free (no python-dotenv).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-15 13:16:37 +00:00
18 changed files with 333 additions and 19 deletions

No files matched your search

+2 -2
View File
@@ -27,7 +27,7 @@ jobs:
permissions:
issues: write
pull-requests: write
uses: MervinPraison/github-automation-template/.github/workflows/[email protected].8
uses: MervinPraison/github-automation-template/.github/workflows/[email protected].10
secrets: inherit
with:
hub_ref: v1.1.8
hub_ref: v1.1.10
+2 -2
View File
@@ -16,8 +16,8 @@ permissions:
jobs:
recover:
uses: MervinPraison/github-automation-template/.github/workflows/[email protected].8
uses: MervinPraison/github-automation-template/.github/workflows/[email protected].10
secrets: inherit
with:
hub_ref: v1.1.8
hub_ref: v1.1.10
pr_number: ${{ github.event.inputs.pr_number || '' }}
+2 -2
View File
@@ -25,8 +25,8 @@ permissions:
jobs:
detect-and-trigger:
uses: MervinPraison/github-automation-template/.github/workflows/[email protected].8
uses: MervinPraison/github-automation-template/.github/workflows/[email protected].10
secrets: inherit
with:
hub_ref: v1.1.8
hub_ref: v1.1.10
pr_number: ${{ github.event.inputs.pr_number || '' }}
+4 -4
View File
@@ -43,9 +43,9 @@ jobs:
id-token: write
steps:
- uses: actions/checkout@v4
- uses: MervinPraison/github-automation-template/.github/actions/[email protected].8
- uses: MervinPraison/github-automation-template/.github/actions/[email protected].10
with:
hub_ref: v1.1.8
hub_ref: v1.1.10
- name: Generate GitHub App token
id: app-token
uses: actions/create-github-app-token@v1
@@ -87,9 +87,9 @@ jobs:
issues: write
actions: read
id-token: write
uses: MervinPraison/github-automation-template/.github/workflows/[email protected].8
uses: MervinPraison/github-automation-template/.github/workflows/[email protected].10
secrets: inherit
with:
hub_ref: v1.1.8
hub_ref: v1.1.10
pr_number: ${{ github.event.inputs.pr_number || github.event.client_payload.pr_number || '' }}
merge_method: ${{ github.event.inputs.merge_method || 'merge' }}
+2 -2
View File
@@ -18,7 +18,7 @@ jobs:
issues: write
actions: read
id-token: write
uses: MervinPraison/github-automation-template/.github/workflows/[email protected].8
uses: MervinPraison/github-automation-template/.github/workflows/[email protected].10
secrets: inherit
with:
hub_ref: v1.1.8
hub_ref: v1.1.10
+2 -2
View File
@@ -25,9 +25,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: MervinPraison/github-automation-template/.github/actions/[email protected].8
- uses: MervinPraison/github-automation-template/.github/actions/[email protected].10
with:
hub_ref: v1.1.8
hub_ref: v1.1.10
- name: Detect conflicting PRs and trigger Claude
uses: actions/github-script@v7
with:
+2 -2
View File
@@ -13,7 +13,7 @@ permissions:
jobs:
sync:
uses: MervinPraison/github-automation-template/.github/workflows/[email protected].8
uses: MervinPraison/github-automation-template/.github/workflows/[email protected].10
secrets: inherit
with:
hub_ref: v1.1.8
hub_ref: v1.1.10
+4
View File
@@ -366,3 +366,7 @@ pytest tests -v
## License
MIT © [Praison Limited](https://praison.ai)
Third-party vendored source is documented in [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md).
See the [BeautifulUI upgrade playbook](docs/frontend/beautifului.md) for how BeautifulUI
primitives are vendored and pinned.
+37
View File
@@ -0,0 +1,37 @@
# Security Policy
We take the security of PraisonAIUI seriously and appreciate responsible
disclosure of vulnerabilities.
## Supported Versions
Security fixes are applied to the latest released version of PraisonAIUI.
Please make sure you are on the most recent release before reporting.
## Reporting a Vulnerability
**Please do not open a public issue for security vulnerabilities.**
Report privately through GitHub's **Private Vulnerability Reporting**:
1. Go to the [Security tab](https://github.com/MervinPraison/PraisonAIUI/security)
of this repository.
2. Click **"Report a vulnerability"** to open a private advisory.
3. Include as much detail as you can:
- Affected component(s) and version.
- Steps to reproduce.
- Impact assessment.
- Any suggested fix or mitigation.
If you are unable to use private reporting, you may open a public issue that
contains **no technical specifics** and requests a private channel, and a
maintainer will follow up.
## What to Expect
- We aim to acknowledge new reports within a few business days.
- We will keep you informed as we investigate and work on a fix.
- Once a fix is released, we are happy to credit you in the advisory (unless
you prefer to remain anonymous).
Thank you for helping keep PraisonAIUI and its users safe.
+43
View File
@@ -0,0 +1,43 @@
# Third-Party Notices
PraisonAIUI incorporates or vendors source from the third-party projects listed below.
Their licences and copyright notices are retained here as required.
---
## BeautifulUI
- Project: BeautifulUI — <https://www.beautifului.dev/>
- Source: <https://github.com/slev12397/beautiful-ui>
- Licence: MIT
BeautifulUI is distributed as a shadcn registry / copy-paste library (no npm package).
When its React primitives are vendored into `src/frontend`, the following MIT licence
applies to that copied source.
```
MIT License
Copyright (c) Shane Levine
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```
See the upgrade playbook at [`docs/frontend/beautifului.md`](docs/frontend/beautifului.md)
for how BeautifulUI is vendored and pinned.
+5
View File
@@ -59,6 +59,11 @@ navigation:
- typescript/runtime
- typescript/nextjs
- typescript/components
- group: "Frontend"
icon: "layout"
prefix: "frontend"
pages:
- frontend/beautifului
- group: "Examples"
icon: "folder-open"
prefix: "examples"
+107
View File
@@ -0,0 +1,107 @@
# BeautifulUI Upgrade Playbook
How PraisonAIUI vendors [BeautifulUI](https://www.beautifului.dev/) React primitives so
upgrades are **repeatable** and licence obligations are **explicit**.
!!! info "Related planning"
Epic [#292](https://github.com/MervinPraison/PraisonAIUI/issues/292) (integration
strategy) and the adapter/pin policy in
[#294](https://github.com/MervinPraison/PraisonAIUI/issues/294).
## 1. What BeautifulUI is
BeautifulUI (MIT, © Shane Levine / Turbo) is a library of React primitives aimed at
**AI-native interfaces** — thinking traces, streaming answers with inline sources,
human-in-the-loop approval cards, tool chips, task rows, context chunks, and a reference
chat harness.
**It is a shadcn registry + copy-paste library — not an npm package.** There is no
published `beautiful-ui` package. You install components by resolving a registry URL, and
the source is copied into your tree (like any other shadcn/ui primitive).
- Website & registry: <https://www.beautifului.dev/>
- Upstream source: <https://github.com/slev12397/beautiful-ui>
Upstream stack (Next.js 15 · React 19 · Tailwind CSS v4 · TypeScript) is closely aligned
with PraisonAIUI's `src/frontend` (Vite · React 19 · Tailwind v4 · shadcn/Radix), which is
why copy-paste vendoring works without a framework shim.
## 2. One-time foundation setup
PraisonAIUI already carries the shadcn/ui foundation that BeautifulUI primitives depend on:
- **shadcn config** — `src/frontend/components.json` (`style: new-york`,
`baseColor: neutral`, `iconLibrary: lucide`, `cssVariables: true`). Its `registries`
map is where pinned BeautifulUI registry URLs are added (see §3).
- **Theme tokens** — `src/praisonaiui/themes.py` generates the shadcn CSS variables
(`--background`, `--foreground`, `--primary`, `--radius`, …) at build time for all 22
official presets, offline. BeautifulUI's foundation CSS (upstream `app/globals.css`)
must only contribute **new** tokens/utilities; it must **not** redefine variables that
`themes.py` already owns, or theme switching and dark mode break.
**Rule:** when merging upstream `app/globals.css`, diff it against the variables emitted by
`themes.py` and keep only the additive slices (new keyframes, component-scoped utilities).
Record what was merged in the pin doc (§3).
## 3. Adding or updating a primitive
1. **Install with a pinned registry URL** from `src/frontend/`:
```bash
npx shadcn add https://www.beautifului.dev/r/<component>.json
```
The registry resolves dependencies and CSS slices. Commit the resulting
`package-lock.json` change in the same PR.
2. **Re-export through the adapter** — add the component to
`src/frontend/src/components/index.ts` (`@praisonaiui/react`). Consumers never import
the raw vendored path (see §4).
3. **Update the pin record** — create/update `docs/frontend/BEAUTIFULUI_UPSTREAM.md` with:
the upstream **git SHA**, the **date**, the **registry base URL**, and the **component
list** vendored so far. This file is the single source of truth for "what version are
we on". (It is created the first time a real primitive is vendored — do not add it
empty.)
4. **Rebuild & sync the bundle** — the committed frontend bundle must be regenerated:
```bash
cd src/frontend && npm run build
# then sync dist/{index.html,assets/,icon.svg} → src/praisonaiui/templates/frontend/
```
(See `AGENTS.md` → "Frontend Build".)
5. **Run frontend CI** — `.github/workflows/ci.yml` (ruff + pytest) must pass, plus the
frontend build step.
## 4. Adapter boundary
Consumers import from **`@praisonaiui/react` only** — never from raw vendored paths such as
`@/components/ui/...` or any upstream module.
```tsx
// ✅ stable PraisonAIUI contract
import { Button, ThemeToggle } from '@praisonaiui/react'
// ❌ leaks upstream/shadcn paths across the codebase
import { Button } from '@/components/ui/button'
```
This keeps the upstream surface behind one file (`components/index.ts`), so a BeautifulUI
bump changes vendored source but not consumer imports.
## 5. Rollback
- BeautifulUI-backed views mount behind a **feature flag**; the **vanilla dashboard views**
(`src/praisonaiui/templates/frontend/plugins/*`) remain the fallback and are kept working.
- To roll back a bad bump: revert the vendoring PR (source + `BEAUTIFULUI_UPSTREAM.md` +
rebuilt bundle move together in one commit), and disable the flag. No consumer import
changes are needed because everything routes through the adapter (§4).
## 6. Licence
BeautifulUI is **MIT, © Shane Levine**. The full licence text is retained in
[`THIRD_PARTY_NOTICES.md`](https://github.com/MervinPraison/PraisonAIUI/blob/main/THIRD_PARTY_NOTICES.md)
at the repository root. Any PR that vendors or bumps BeautifulUI source must keep that
notice present and current.
## 7. Commercial icons — do not vendor
Do **not** use `@central-icons-react` without a licence — it is commercial. PraisonAIUI
standardises on **`lucide-react`** (`iconLibrary: lucide` in `components.json`). If an
upstream BeautifulUI primitive imports commercial icons, swap them for lucide equivalents
during vendoring.
+2
View File
@@ -135,6 +135,8 @@ nav:
- How to Add a Feature: features/how-to-add-a-feature.md
- Message Elements: features/message-elements.md
- Steps: features/steps.md
- Frontend:
- BeautifulUI Playbook: frontend/beautifului.md
- API Reference:
- Python CLI: api/cli.md
- Python API: api/python.md
+1 -1
View File
@@ -1,6 +1,6 @@
[project]
name = "aiui"
version = "0.3.145"
version = "0.3.146"
description = "YAML-driven website generator - CLI and compiler"
readme = "README.md"
license = {text = "MIT"}
+1 -1
View File
@@ -1,3 +1,3 @@
"""Version information."""
__version__ = "0.3.145"
__version__ = "0.3.146"
+48
View File
@@ -44,6 +44,43 @@ def _icon(symbol: str, fallback: str) -> str:
return symbol if _supports_unicode() else fallback
def _load_env_files() -> int:
"""Load environment variables from the standard PraisonAI ``.env`` files.
Mirrors the PraisonAI CLI convention so ``env:VAR`` references (e.g. in
Channels config) resolve when the server was started without the shell
exporting the tokens. Reads ``~/.praisonai/.env`` first, then a ``.env`` in
the current working directory. Existing process env vars are never
overridden, and parsing is intentionally dependency-free (no python-dotenv).
Returns the number of variables newly set into ``os.environ``.
"""
import os
loaded = 0
for env_path in (Path.home() / ".praisonai" / ".env", Path.cwd() / ".env"):
try:
if not env_path.is_file():
continue
for line in env_path.read_text(encoding="utf-8").splitlines():
line = line.strip()
if not line or line.startswith("#") or "=" not in line:
continue
if line.startswith("export "):
line = line[len("export "):]
key, value = line.split("=", 1)
key = key.strip()
value = value.strip().strip('"').strip("'")
if key and key not in os.environ:
os.environ[key] = value
loaded += 1
except Exception:
# Never let env loading break startup — resolution falls back to
# the existing process environment.
continue
return loaded
app = typer.Typer(
name="aiui",
help="PraisonAIUI - YAML-driven website generator",
@@ -1380,6 +1417,17 @@ def run(
console.print(f"[red]Error:[/red] App file not found: {app_file}")
raise typer.Exit(code=1)
# Auto-load standard PraisonAI env files so `env:VAR` references (e.g. in
# Channels config) resolve even when the shell did not export the tokens.
# This matches the PraisonAI CLI convention and fixes the "Connected but
# bot never replies" class of issues caused by empty env-resolved tokens.
_loaded = _load_env_files()
if _loaded:
console.print(
f"[green]{_icon('✓', 'OK')}[/green] Loaded {_loaded} environment "
f"variable(s) from PraisonAI config"
)
is_yaml = app_file.suffix in (".yaml", ".yml")
if is_yaml:
+68
View File
@@ -0,0 +1,68 @@
"""Unit tests for `_load_env_files` — auto-loading PraisonAI `.env` files.
Regression coverage for issue #286: `env:VAR` channel token references
resolved to empty strings because `aiui run` never loaded the standard
`~/.praisonai/.env` file, so bots showed "Connected" but never replied.
"""
import os
from praisonaiui.cli import _load_env_files
def _write_env(path, body):
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(body, encoding="utf-8")
def test_loads_home_praisonai_env(tmp_path, monkeypatch):
"""Variables in ~/.praisonai/.env are loaded into the process env."""
monkeypatch.setattr("pathlib.Path.home", lambda: tmp_path)
monkeypatch.chdir(tmp_path)
monkeypatch.delenv("TELEGRAM_BOT_TOKEN", raising=False)
_write_env(tmp_path / ".praisonai" / ".env", 'TELEGRAM_BOT_TOKEN="123:AAtoken"\n')
loaded = _load_env_files()
assert loaded >= 1
assert os.environ["TELEGRAM_BOT_TOKEN"] == "123:AAtoken"
def test_does_not_override_existing_env(tmp_path, monkeypatch):
"""An already-set process variable is never clobbered by the file."""
monkeypatch.setattr("pathlib.Path.home", lambda: tmp_path)
monkeypatch.chdir(tmp_path)
monkeypatch.setenv("SLACK_BOT_TOKEN", "xoxb-from-shell")
_write_env(tmp_path / ".praisonai" / ".env", "SLACK_BOT_TOKEN=xoxb-from-file\n")
_load_env_files()
assert os.environ["SLACK_BOT_TOKEN"] == "xoxb-from-shell"
def test_ignores_comments_blanks_and_export_prefix(tmp_path, monkeypatch):
"""Comments/blank lines are skipped and `export ` prefixes are stripped."""
monkeypatch.setattr("pathlib.Path.home", lambda: tmp_path)
monkeypatch.chdir(tmp_path)
monkeypatch.delenv("FOO", raising=False)
monkeypatch.delenv("BAR", raising=False)
_write_env(
tmp_path / ".praisonai" / ".env",
"# a comment\n\nexport FOO=foo\nBAR='bar'\n",
)
_load_env_files()
assert os.environ["FOO"] == "foo"
assert os.environ["BAR"] == "bar"
def test_missing_files_are_harmless(tmp_path, monkeypatch):
"""No env files present → returns 0 and does not raise."""
monkeypatch.setattr("pathlib.Path.home", lambda: tmp_path)
monkeypatch.chdir(tmp_path)
assert _load_env_files() == 0
Generated
+1 -1
View File
@@ -207,7 +207,7 @@ wheels = [
[[package]]
name = "aiui"
version = "0.3.145"
version = "0.3.146"
source = { editable = "." }
dependencies = [
{ name = "pydantic" },