mirror of
https://github.com/MervinPraison/PraisonAIUI.git
synced 2026-11-07 05:56:17 -10:00
Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
afce1e542d | ||
|
|
1807595cd0 | ||
|
|
3058886312 | ||
|
|
70d8610733 | ||
|
|
0f60ec41f1 | ||
|
|
2797667e04 | ||
|
|
f23aacdec9 | ||
|
|
8dc8b9f49f |
No files matched your search
@@ -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
|
||||
@@ -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 || '' }}
|
||||
@@ -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 || '' }}
|
||||
@@ -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' }}
|
||||
@@ -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
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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"
|
||||
|
||||
@@ -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.
|
||||
@@ -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
@@ -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,3 +1,3 @@
|
||||
"""Version information."""
|
||||
|
||||
__version__ = "0.3.145"
|
||||
__version__ = "0.3.146"
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
Reference in new issue
Block a user