forgeui 0.1.0a2__tar.gz
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.
- forgeui-0.1.0a2/.dockerignore +15 -0
- forgeui-0.1.0a2/.env.example +28 -0
- forgeui-0.1.0a2/.github/workflows/ci.yml +81 -0
- forgeui-0.1.0a2/.github/workflows/publish.yml +82 -0
- forgeui-0.1.0a2/.gitignore +23 -0
- forgeui-0.1.0a2/.impeccable.md +56 -0
- forgeui-0.1.0a2/.python-version +1 -0
- forgeui-0.1.0a2/AGENTS.local.example.md +6 -0
- forgeui-0.1.0a2/AGENTS.md +14 -0
- forgeui-0.1.0a2/CHANGELOG.md +55 -0
- forgeui-0.1.0a2/CONTRIBUTING.md +27 -0
- forgeui-0.1.0a2/Dockerfile +45 -0
- forgeui-0.1.0a2/LICENSE +21 -0
- forgeui-0.1.0a2/PKG-INFO +277 -0
- forgeui-0.1.0a2/README.md +209 -0
- forgeui-0.1.0a2/SECURITY.md +27 -0
- forgeui-0.1.0a2/THIRD_PARTY_NOTICES.md +25 -0
- forgeui-0.1.0a2/compose.ollama.yaml +24 -0
- forgeui-0.1.0a2/compose.yaml +46 -0
- forgeui-0.1.0a2/docs/adr/0001-strict-manifest.md +13 -0
- forgeui-0.1.0a2/docs/adr/0002-server-owned-state.md +13 -0
- forgeui-0.1.0a2/docs/adr/0003-design-profiles.md +11 -0
- forgeui-0.1.0a2/docs/adr/0004-trusted-integrations.md +14 -0
- forgeui-0.1.0a2/docs/adr/0005-assets.md +12 -0
- forgeui-0.1.0a2/docs/adr/0006-bounded-repair.md +14 -0
- forgeui-0.1.0a2/docs/adr/0007-distribution-boundaries.md +19 -0
- forgeui-0.1.0a2/docs/adr/README.md +9 -0
- forgeui-0.1.0a2/docs/api.md +123 -0
- forgeui-0.1.0a2/docs/architecture.md +85 -0
- forgeui-0.1.0a2/docs/components.md +62 -0
- forgeui-0.1.0a2/docs/data-sources.md +119 -0
- forgeui-0.1.0a2/docs/deployment.md +105 -0
- forgeui-0.1.0a2/docs/distribution.md +162 -0
- forgeui-0.1.0a2/docs/embedding.md +131 -0
- forgeui-0.1.0a2/docs/footprint.md +63 -0
- forgeui-0.1.0a2/docs/implementation-plan.md +141 -0
- forgeui-0.1.0a2/docs/manifest.md +99 -0
- forgeui-0.1.0a2/docs/releases/0.1.0a1.md +37 -0
- forgeui-0.1.0a2/docs/releases/0.1.0a2.md +44 -0
- forgeui-0.1.0a2/docs/security.md +81 -0
- forgeui-0.1.0a2/docs/surfaces.md +106 -0
- forgeui-0.1.0a2/examples/ai_search_host.py +105 -0
- forgeui-0.1.0a2/examples/data/device-health-empty.json +18 -0
- forgeui-0.1.0a2/examples/data/device-health-stale.json +54 -0
- forgeui-0.1.0a2/examples/data/device-health.json +135 -0
- forgeui-0.1.0a2/examples/manifests/device-detail.json +232 -0
- forgeui-0.1.0a2/examples/manifests/fleet-overview.json +289 -0
- forgeui-0.1.0a2/examples/manifests/resource-pressure.json +175 -0
- forgeui-0.1.0a2/examples/prompts/device-detail.txt +3 -0
- forgeui-0.1.0a2/examples/prompts/fleet-overview.txt +3 -0
- forgeui-0.1.0a2/examples/prompts/resource-pressure.txt +3 -0
- forgeui-0.1.0a2/pyproject.toml +151 -0
- forgeui-0.1.0a2/src/forgeui/__init__.py +10 -0
- forgeui-0.1.0a2/src/forgeui/a2ui/README.md +68 -0
- forgeui-0.1.0a2/src/forgeui/a2ui/__init__.py +36 -0
- forgeui-0.1.0a2/src/forgeui/a2ui/adapter.py +486 -0
- forgeui-0.1.0a2/src/forgeui/a2ui/errors.py +54 -0
- forgeui-0.1.0a2/src/forgeui/a2ui/models.py +116 -0
- forgeui-0.1.0a2/src/forgeui/app.py +465 -0
- forgeui-0.1.0a2/src/forgeui/catalog/__init__.py +5 -0
- forgeui-0.1.0a2/src/forgeui/catalog/registry.py +552 -0
- forgeui-0.1.0a2/src/forgeui/cli.py +38 -0
- forgeui-0.1.0a2/src/forgeui/config.py +120 -0
- forgeui-0.1.0a2/src/forgeui/container.py +135 -0
- forgeui-0.1.0a2/src/forgeui/data/__init__.py +6 -0
- forgeui-0.1.0a2/src/forgeui/data/database.py +103 -0
- forgeui-0.1.0a2/src/forgeui/data/models.py +175 -0
- forgeui-0.1.0a2/src/forgeui/data/repositories.py +444 -0
- forgeui-0.1.0a2/src/forgeui/domain/__init__.py +23 -0
- forgeui-0.1.0a2/src/forgeui/domain/device_health.py +213 -0
- forgeui-0.1.0a2/src/forgeui/domain/models.py +217 -0
- forgeui-0.1.0a2/src/forgeui/expressions/__init__.py +14 -0
- forgeui-0.1.0a2/src/forgeui/expressions/ast.py +126 -0
- forgeui-0.1.0a2/src/forgeui/expressions/evaluator.py +231 -0
- forgeui-0.1.0a2/src/forgeui/icons.py +126 -0
- forgeui-0.1.0a2/src/forgeui/llm/__init__.py +51 -0
- forgeui-0.1.0a2/src/forgeui/llm/fake.py +31 -0
- forgeui-0.1.0a2/src/forgeui/llm/generation.py +218 -0
- forgeui-0.1.0a2/src/forgeui/llm/ollama.py +118 -0
- forgeui-0.1.0a2/src/forgeui/llm/prompting.py +113 -0
- forgeui-0.1.0a2/src/forgeui/llm/types.py +103 -0
- forgeui-0.1.0a2/src/forgeui/logging.py +42 -0
- forgeui-0.1.0a2/src/forgeui/observability.py +62 -0
- forgeui-0.1.0a2/src/forgeui/py.typed +1 -0
- forgeui-0.1.0a2/src/forgeui/renderer/__init__.py +12 -0
- forgeui-0.1.0a2/src/forgeui/renderer/renderer.py +839 -0
- forgeui-0.1.0a2/src/forgeui/runtime.py +114 -0
- forgeui-0.1.0a2/src/forgeui/security.py +57 -0
- forgeui-0.1.0a2/src/forgeui/services/__init__.py +40 -0
- forgeui-0.1.0a2/src/forgeui/services/actions.py +413 -0
- forgeui-0.1.0a2/src/forgeui/services/apps.py +207 -0
- forgeui-0.1.0a2/src/forgeui/services/audit.py +79 -0
- forgeui-0.1.0a2/src/forgeui/services/capabilities.py +159 -0
- forgeui-0.1.0a2/src/forgeui/services/devices.py +166 -0
- forgeui-0.1.0a2/src/forgeui/services/exceptions.py +27 -0
- forgeui-0.1.0a2/src/forgeui/services/jobs.py +170 -0
- forgeui-0.1.0a2/src/forgeui/services/state.py +131 -0
- forgeui-0.1.0a2/src/forgeui/sources/__init__.py +29 -0
- forgeui-0.1.0a2/src/forgeui/sources/http.py +122 -0
- forgeui-0.1.0a2/src/forgeui/sources/registry.py +358 -0
- forgeui-0.1.0a2/src/forgeui/surfaces.py +64 -0
- forgeui-0.1.0a2/src/forgeui/validation/__init__.py +30 -0
- forgeui-0.1.0a2/src/forgeui/validation/parser.py +82 -0
- forgeui-0.1.0a2/src/forgeui/validation/repair.py +68 -0
- forgeui-0.1.0a2/src/forgeui/validation/validator.py +653 -0
- forgeui-0.1.0a2/src/forgeui/web/__init__.py +5 -0
- forgeui-0.1.0a2/src/forgeui/web/router.py +1083 -0
- forgeui-0.1.0a2/src/forgeui/web/static/favicon.svg +4 -0
- forgeui-0.1.0a2/src/forgeui/web/static/forgeui-embed.js +38 -0
- forgeui-0.1.0a2/src/forgeui/web/static/forgeui.css +1780 -0
- forgeui-0.1.0a2/src/forgeui/web/static/forgeui.js +300 -0
- forgeui-0.1.0a2/src/forgeui/web/templates/base.html +53 -0
- forgeui-0.1.0a2/src/forgeui/web/templates/components/_component.html +88 -0
- forgeui-0.1.0a2/tests/contracts/a2ui/fixtures/device_health_dashboard_v0_9_1.jsonl +3 -0
- forgeui-0.1.0a2/tests/contracts/a2ui/test_adapter_v0_9_1.py +430 -0
- forgeui-0.1.0a2/tests/contracts/test_catalog_templates.py +142 -0
- forgeui-0.1.0a2/tests/contracts/test_distribution.py +46 -0
- forgeui-0.1.0a2/tests/contracts/test_examples.py +23 -0
- forgeui-0.1.0a2/tests/contracts/test_footprint.py +57 -0
- forgeui-0.1.0a2/tests/integration/test_custom_runtime.py +202 -0
- forgeui-0.1.0a2/tests/integration/test_web.py +703 -0
- forgeui-0.1.0a2/tests/llm_gauntlet/test_live_ollama.py +29 -0
- forgeui-0.1.0a2/tests/security/test_renderer_security.py +41 -0
- forgeui-0.1.0a2/tests/security/test_web_security.py +24 -0
- forgeui-0.1.0a2/tests/unit/catalog/__init__.py +1 -0
- forgeui-0.1.0a2/tests/unit/catalog/test_registry.py +82 -0
- forgeui-0.1.0a2/tests/unit/data/test_repository.py +70 -0
- forgeui-0.1.0a2/tests/unit/domain/test_device_health.py +60 -0
- forgeui-0.1.0a2/tests/unit/expressions/test_evaluator.py +112 -0
- forgeui-0.1.0a2/tests/unit/expressions/test_evaluator_matrix.py +168 -0
- forgeui-0.1.0a2/tests/unit/llm/test_generation.py +121 -0
- forgeui-0.1.0a2/tests/unit/llm/test_ollama.py +125 -0
- forgeui-0.1.0a2/tests/unit/llm/test_prompting.py +48 -0
- forgeui-0.1.0a2/tests/unit/renderer/test_renderer.py +471 -0
- forgeui-0.1.0a2/tests/unit/services/conftest.py +65 -0
- forgeui-0.1.0a2/tests/unit/services/test_apps_state_actions.py +103 -0
- forgeui-0.1.0a2/tests/unit/services/test_capabilities.py +89 -0
- forgeui-0.1.0a2/tests/unit/services/test_jobs_devices.py +127 -0
- forgeui-0.1.0a2/tests/unit/sources/__init__.py +1 -0
- forgeui-0.1.0a2/tests/unit/sources/test_http.py +74 -0
- forgeui-0.1.0a2/tests/unit/sources/test_registry.py +150 -0
- forgeui-0.1.0a2/tests/unit/test_cli.py +16 -0
- forgeui-0.1.0a2/tests/unit/test_config.py +57 -0
- forgeui-0.1.0a2/tests/unit/test_icons.py +40 -0
- forgeui-0.1.0a2/tests/unit/test_logging.py +27 -0
- forgeui-0.1.0a2/tests/unit/test_security.py +24 -0
- forgeui-0.1.0a2/tests/unit/validation/test_manifest_validation.py +264 -0
- forgeui-0.1.0a2/tests/unit/validation/test_parser.py +17 -0
- forgeui-0.1.0a2/tests/unit/validation/test_repair.py +135 -0
- forgeui-0.1.0a2/uv.lock +1782 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
FORGEUI_ENVIRONMENT=development
|
|
2
|
+
FORGEUI_HOST=0.0.0.0
|
|
3
|
+
FORGEUI_PORT=8000
|
|
4
|
+
FORGEUI_DATABASE_URL=sqlite:////data/forgeui.db
|
|
5
|
+
FORGEUI_DATA_DIR=/data
|
|
6
|
+
# Generate unique production values, for example: openssl rand -hex 32
|
|
7
|
+
FORGEUI_SECRET_KEY=replace-with-a-long-random-value
|
|
8
|
+
FORGEUI_ADMIN_TOKEN=replace-with-an-admin-token
|
|
9
|
+
FORGEUI_ALLOW_PUBLIC_READ=true
|
|
10
|
+
# Set true behind HTTPS. Compose defaults this to true.
|
|
11
|
+
FORGEUI_SECURE_COOKIES=false
|
|
12
|
+
# JSON list, not a comma-separated string.
|
|
13
|
+
FORGEUI_TRUSTED_HOSTS=["localhost","127.0.0.1"]
|
|
14
|
+
# Exact origins permitted to frame /embed and /artifact views. Keep self-only unless needed.
|
|
15
|
+
FORGEUI_FRAME_ANCESTORS=["'self'"]
|
|
16
|
+
|
|
17
|
+
# Ollama is expected to run separately. On Docker Desktop this reaches the host.
|
|
18
|
+
FORGEUI_OLLAMA_BASE_URL=http://host.docker.internal:11434
|
|
19
|
+
FORGEUI_OLLAMA_MODEL=qwen3.5:9b
|
|
20
|
+
FORGEUI_OLLAMA_CONNECT_TIMEOUT_SECONDS=5
|
|
21
|
+
FORGEUI_OLLAMA_RESPONSE_TIMEOUT_SECONDS=90
|
|
22
|
+
FORGEUI_OLLAMA_MAX_CONCURRENCY=1
|
|
23
|
+
FORGEUI_OLLAMA_TEMPERATURE=0.1
|
|
24
|
+
FORGEUI_OLLAMA_SEED=42
|
|
25
|
+
|
|
26
|
+
FORGEUI_ASSET_MODE=self-hosted
|
|
27
|
+
FORGEUI_LOG_LEVEL=INFO
|
|
28
|
+
FORGEUI_JSON_LOGS=false
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
quality:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
timeout-minutes: 15
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v7.0.1
|
|
16
|
+
- uses: astral-sh/setup-uv@v10.0.1
|
|
17
|
+
with:
|
|
18
|
+
python-version: "3.12"
|
|
19
|
+
enable-cache: true
|
|
20
|
+
- run: uv sync --frozen --all-extras
|
|
21
|
+
- run: uv run ruff format --check .
|
|
22
|
+
- run: uv run ruff check .
|
|
23
|
+
- run: uv run mypy src/forgeui
|
|
24
|
+
- run: uv run bandit -q -r src/forgeui
|
|
25
|
+
- run: >-
|
|
26
|
+
uv run pytest -q -m "not browser and not docker and not ollama"
|
|
27
|
+
--cov=forgeui --cov-report=term-missing:skip-covered
|
|
28
|
+
- run: uv build
|
|
29
|
+
- run: uv run twine check dist/*
|
|
30
|
+
- name: Smoke-test base, HTTP adapter, mounted-web, and complete wheels
|
|
31
|
+
run: |
|
|
32
|
+
WHEEL=$(find dist -name 'forgeui-*.whl' -print -quit)
|
|
33
|
+
WHEEL_BYTES=$(wc -c < "$WHEEL")
|
|
34
|
+
if [ "$WHEEL_BYTES" -gt $((128 * 1024)) ]; then
|
|
35
|
+
echo "Wheel size $WHEEL_BYTES bytes exceeds the 128 KiB budget"
|
|
36
|
+
exit 1
|
|
37
|
+
fi
|
|
38
|
+
PACKAGE_SMOKE_DIR=$(mktemp -d)
|
|
39
|
+
uv venv "$PACKAGE_SMOKE_DIR/base"
|
|
40
|
+
uv pip install --python "$PACKAGE_SMOKE_DIR/base/bin/python" "$WHEEL"
|
|
41
|
+
"$PACKAGE_SMOKE_DIR/base/bin/python" -c \
|
|
42
|
+
"import importlib.util; from forgeui.a2ui import adapt_a2ui_jsonl; from forgeui.renderer import Renderer; from forgeui.validation import validate_manifest; assert importlib.util.find_spec('fastapi') is None; assert importlib.util.find_spec('httpx') is None; assert importlib.util.find_spec('sqlalchemy') is None"
|
|
43
|
+
if BASE_CLI_OUTPUT=$("$PACKAGE_SMOKE_DIR/base/bin/forgeui" serve 2>&1); then
|
|
44
|
+
echo "Base CLI unexpectedly started without the app extra"
|
|
45
|
+
exit 1
|
|
46
|
+
fi
|
|
47
|
+
if ! grep -q "forgeui\[app\]" <<< "$BASE_CLI_OUTPUT"; then
|
|
48
|
+
echo "Base CLI did not explain the missing app extra"
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
uv venv "$PACKAGE_SMOKE_DIR/http"
|
|
52
|
+
uv pip install --python "$PACKAGE_SMOKE_DIR/http/bin/python" "${WHEEL}[http]"
|
|
53
|
+
"$PACKAGE_SMOKE_DIR/http/bin/python" -c \
|
|
54
|
+
"import importlib.util; from forgeui.sources.http import HttpDataSource; assert importlib.util.find_spec('sqlalchemy') is None"
|
|
55
|
+
uv venv "$PACKAGE_SMOKE_DIR/web"
|
|
56
|
+
uv pip install --python "$PACKAGE_SMOKE_DIR/web/bin/python" "${WHEEL}[web]"
|
|
57
|
+
"$PACKAGE_SMOKE_DIR/web/bin/python" -c \
|
|
58
|
+
"import importlib.util; from forgeui.app import mount_forgeui; from forgeui.data import Database; assert importlib.util.find_spec('httpx') is None"
|
|
59
|
+
uv venv "$PACKAGE_SMOKE_DIR/app"
|
|
60
|
+
uv pip install --python "$PACKAGE_SMOKE_DIR/app/bin/python" "${WHEEL}[app]"
|
|
61
|
+
"$PACKAGE_SMOKE_DIR/app/bin/python" -c \
|
|
62
|
+
"from forgeui.app import create_app; from forgeui.data import Database; from forgeui.llm import OllamaProvider"
|
|
63
|
+
|
|
64
|
+
compatibility:
|
|
65
|
+
name: Python ${{ matrix.python-version }} compatibility
|
|
66
|
+
runs-on: ubuntu-latest
|
|
67
|
+
timeout-minutes: 15
|
|
68
|
+
strategy:
|
|
69
|
+
fail-fast: false
|
|
70
|
+
matrix:
|
|
71
|
+
python-version: ["3.11", "3.13"]
|
|
72
|
+
steps:
|
|
73
|
+
- uses: actions/checkout@v7.0.1
|
|
74
|
+
with:
|
|
75
|
+
persist-credentials: false
|
|
76
|
+
- uses: astral-sh/setup-uv@v10.0.1
|
|
77
|
+
with:
|
|
78
|
+
python-version: ${{ matrix.python-version }}
|
|
79
|
+
enable-cache: true
|
|
80
|
+
- run: uv sync --frozen --all-extras
|
|
81
|
+
- run: uv run pytest -q -m "not browser and not docker and not ollama"
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
build:
|
|
12
|
+
name: Build and verify distribution
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
timeout-minutes: 15
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v7.0.1
|
|
17
|
+
with:
|
|
18
|
+
persist-credentials: false
|
|
19
|
+
- uses: astral-sh/setup-uv@v10.0.1
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.12"
|
|
22
|
+
enable-cache: true
|
|
23
|
+
- name: Check release tag matches package version
|
|
24
|
+
run: |
|
|
25
|
+
PACKAGE_VERSION=$(python -c 'import tomllib; print(tomllib.load(open("pyproject.toml", "rb"))["project"]["version"])')
|
|
26
|
+
RELEASE_VERSION=${GITHUB_REF_NAME#v}
|
|
27
|
+
if [ "$PACKAGE_VERSION" != "$RELEASE_VERSION" ]; then
|
|
28
|
+
echo "Release tag $GITHUB_REF_NAME does not match package version $PACKAGE_VERSION"
|
|
29
|
+
exit 1
|
|
30
|
+
fi
|
|
31
|
+
- run: uv sync --frozen --all-extras
|
|
32
|
+
- run: uv run ruff format --check .
|
|
33
|
+
- run: uv run ruff check .
|
|
34
|
+
- run: uv run mypy src/forgeui
|
|
35
|
+
- run: uv run bandit -q -r src/forgeui
|
|
36
|
+
- run: >-
|
|
37
|
+
uv run pytest -q -m "not browser and not docker and not ollama"
|
|
38
|
+
--cov=forgeui --cov-report=term-missing:skip-covered
|
|
39
|
+
- run: uv build
|
|
40
|
+
- run: uv run twine check dist/*
|
|
41
|
+
- name: Enforce wheel budget
|
|
42
|
+
run: |
|
|
43
|
+
WHEEL=$(find dist -name 'forgeui-*.whl' -print -quit)
|
|
44
|
+
WHEEL_BYTES=$(wc -c < "$WHEEL")
|
|
45
|
+
if [ "$WHEEL_BYTES" -gt $((128 * 1024)) ]; then
|
|
46
|
+
echo "Wheel size $WHEEL_BYTES bytes exceeds the 128 KiB budget"
|
|
47
|
+
exit 1
|
|
48
|
+
fi
|
|
49
|
+
- name: Smoke-test the exact release wheel
|
|
50
|
+
run: |
|
|
51
|
+
WHEEL=$(find dist -name 'forgeui-*.whl' -print -quit)
|
|
52
|
+
RELEASE_SMOKE_DIR=$(mktemp -d)
|
|
53
|
+
uv venv "$RELEASE_SMOKE_DIR/venv"
|
|
54
|
+
uv pip install --python "$RELEASE_SMOKE_DIR/venv/bin/python" "${WHEEL}[app]"
|
|
55
|
+
"$RELEASE_SMOKE_DIR/venv/bin/python" -c \
|
|
56
|
+
"from forgeui import __version__; from forgeui.app import create_app; assert __version__ == '${GITHUB_REF_NAME#v}'"
|
|
57
|
+
- name: Store distributions
|
|
58
|
+
uses: actions/upload-artifact@v7.0.1
|
|
59
|
+
with:
|
|
60
|
+
name: python-package-distributions
|
|
61
|
+
path: dist/
|
|
62
|
+
if-no-files-found: error
|
|
63
|
+
retention-days: 7
|
|
64
|
+
|
|
65
|
+
publish:
|
|
66
|
+
name: Publish verified distribution
|
|
67
|
+
needs: build
|
|
68
|
+
runs-on: ubuntu-latest
|
|
69
|
+
timeout-minutes: 10
|
|
70
|
+
environment:
|
|
71
|
+
name: pypi
|
|
72
|
+
url: https://pypi.org/p/forgeui
|
|
73
|
+
permissions:
|
|
74
|
+
id-token: write
|
|
75
|
+
steps:
|
|
76
|
+
- name: Retrieve distributions
|
|
77
|
+
uses: actions/download-artifact@v8.0.1
|
|
78
|
+
with:
|
|
79
|
+
name: python-package-distributions
|
|
80
|
+
path: dist/
|
|
81
|
+
- name: Publish with PyPI Trusted Publishing
|
|
82
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*.egg-info/
|
|
4
|
+
.coverage
|
|
5
|
+
.env
|
|
6
|
+
.hypothesis/
|
|
7
|
+
.mypy_cache/
|
|
8
|
+
.pytest_cache/
|
|
9
|
+
.ruff_cache/
|
|
10
|
+
.venv/
|
|
11
|
+
build/
|
|
12
|
+
dist/
|
|
13
|
+
htmlcov/
|
|
14
|
+
playwright-report/
|
|
15
|
+
test-results/
|
|
16
|
+
/data/
|
|
17
|
+
*.db
|
|
18
|
+
*.db-shm
|
|
19
|
+
*.db-wal
|
|
20
|
+
.DS_Store
|
|
21
|
+
|
|
22
|
+
# Machine-specific agent instructions may contain local paths or other private context.
|
|
23
|
+
AGENTS.local.md
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
## Design Context
|
|
2
|
+
|
|
3
|
+
### Users
|
|
4
|
+
|
|
5
|
+
ForgeUI serves two connected groups:
|
|
6
|
+
|
|
7
|
+
- Operations engineers, fleet administrators, and support staff who scan device health, identify
|
|
8
|
+
exceptions, and act under time pressure. They need dense information to remain legible and
|
|
9
|
+
trustworthy at a glance.
|
|
10
|
+
- Application developers who embed ForgeUI into a FastAPI service and use a small local model to
|
|
11
|
+
assemble dashboards from an approved catalog. They need the generated UI to feel intentional
|
|
12
|
+
without granting the model arbitrary styling or executable output.
|
|
13
|
+
|
|
14
|
+
The first job is to turn a normalized device-health report into a useful fleet overview, resource
|
|
15
|
+
pressure view, or device detail page. Existing dashboards must remain useful when Ollama is
|
|
16
|
+
offline.
|
|
17
|
+
|
|
18
|
+
### Brand Personality
|
|
19
|
+
|
|
20
|
+
Calm, dependable, precise. The interface should create confidence through restraint, clear status
|
|
21
|
+
hierarchy, exact labels, and visible system state. Urgency comes from actual warning and critical
|
|
22
|
+
data, not decorative intensity. Copy is concise, direct, and helpful.
|
|
23
|
+
|
|
24
|
+
### Aesthetic Direction
|
|
25
|
+
|
|
26
|
+
The default visual language is a compact system-font interface with deep teal actions,
|
|
27
|
+
cool-neutral page and card surfaces, 6-pixel control/card radii, restrained
|
|
28
|
+
elevation, strong table structure, and a charcoal application bar with a teal rule. It should feel
|
|
29
|
+
like a dependable operational tool, not an editorial showcase or a generic marketing dashboard.
|
|
30
|
+
|
|
31
|
+
Support light, dark, and system themes as first-class modes. Dark mode uses distinct lifted
|
|
32
|
+
surfaces instead of inverting the light palette. Use the system stack
|
|
33
|
+
(`system-ui`, `-apple-system`, `Segoe UI`, `Roboto`) for predictable embedding. Avoid
|
|
34
|
+
neon-on-dark styling, cyan/purple gradients, glassmorphism, excessive rounding and shadows,
|
|
35
|
+
nested cards, ornamental sparklines, gradient text, oversized display headings, and large icon
|
|
36
|
+
tiles.
|
|
37
|
+
|
|
38
|
+
The four safe model-selectable design profiles may vary density and composition, but all inherit
|
|
39
|
+
the same semantic tokens, accessible status language, typography discipline, and trusted shell:
|
|
40
|
+
|
|
41
|
+
- `ops-compact`: dense, ruled, exception-first monitoring.
|
|
42
|
+
- `signal-cards`: stronger visual metric and chart emphasis without decorative effects.
|
|
43
|
+
- `executive-summary`: spacious synthesis with fewer simultaneous details.
|
|
44
|
+
- `calm-neutral`: quiet reading and detail review.
|
|
45
|
+
|
|
46
|
+
### Design Principles
|
|
47
|
+
|
|
48
|
+
1. Signal before decoration. Color, weight, and motion explain state changes or urgency.
|
|
49
|
+
2. Dense does not mean cramped. Use varied rhythm, hairline separators, and tabular alignment to
|
|
50
|
+
make operational data scannable.
|
|
51
|
+
3. The shell is trusted. Theme controls, focus behavior, error states, and interaction patterns do
|
|
52
|
+
not depend on model output.
|
|
53
|
+
4. Profiles are complete systems, not bags of knobs. The model chooses a tested bundle and cannot
|
|
54
|
+
mix arbitrary colors, classes, fonts, radii, or layout values.
|
|
55
|
+
5. Accessibility is visible quality. Preserve semantic HTML, 44-pixel touch targets, keyboard
|
|
56
|
+
focus, non-color status cues, reduced motion, AA contrast, and mobile adaptations.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# ForgeUI local agent rules
|
|
2
|
+
|
|
3
|
+
Copy this file to `AGENTS.local.md` and add only machine-specific instructions that should not be
|
|
4
|
+
published, such as absolute paths to adjacent checkouts. `AGENTS.local.md` is ignored by Git.
|
|
5
|
+
|
|
6
|
+
- Treat `<absolute-path-to-adjacent-checkout>` as read-only; it may contain user changes.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# ForgeUI agent rules
|
|
2
|
+
|
|
3
|
+
- If `AGENTS.local.md` exists, read it before starting work. It contains machine-specific rules and
|
|
4
|
+
must remain untracked.
|
|
5
|
+
- ForgeUI is a standalone Python project.
|
|
6
|
+
- Keep the model boundary strict: manifests never contain HTML, JavaScript, CSS, Tailwind classes, URLs, SQL, file paths, or arbitrary executable expressions.
|
|
7
|
+
- Keep the component catalog, Pydantic models, JSON Schema, renderer dispatch, and prompt documentation in sync.
|
|
8
|
+
- Reject invalid manifests before persistence or rendering. Do not silently weaken security rules while repairing output.
|
|
9
|
+
- Prefer server-owned state, immutable manifest revisions, and trusted capability/data-source registries.
|
|
10
|
+
- Keep UI behavior accessible: semantic HTML, visible focus, labelled inputs, keyboard support, reduced motion, and tested light/dark themes.
|
|
11
|
+
- Treat adjacent checkouts as read-only; they may contain user changes.
|
|
12
|
+
- Agents working concurrently must have disjoint file ownership.
|
|
13
|
+
- Run focused tests for changed code and report exact commands and failures.
|
|
14
|
+
- Avoid vague production-readiness claims. State implemented controls, checks, and remaining risks precisely.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to ForgeUI are documented here. Versions follow
|
|
4
|
+
[PEP 440](https://peps.python.org/pep-0440/).
|
|
5
|
+
|
|
6
|
+
## 0.1.0a2 — 2026-09-01
|
|
7
|
+
|
|
8
|
+
First published public alpha.
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Raised light-theme timeline timestamp contrast above the WCAG AA text threshold.
|
|
13
|
+
- Made the shell wordmark a 44-pixel touch target at mobile widths.
|
|
14
|
+
- Added a small self-hosted favicon so standalone pages do not generate a missing-asset request.
|
|
15
|
+
- Replaced the segmented theme selector with one compact system-default light/dark toggle.
|
|
16
|
+
- Added trusted axis titles, tick labels, scales, and formatted summaries to operational charts.
|
|
17
|
+
- Added hover/focus chart inspection with bounded keyboard stops and an accessible data summary.
|
|
18
|
+
- Added explicit dashboard drill-down affordances and host-allowlisted navigation destination IDs.
|
|
19
|
+
|
|
20
|
+
## 0.1.0a1 — 2026-09-01
|
|
21
|
+
|
|
22
|
+
Initial release candidate.
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
- Strict `forgeui/1` manifests with a server-owned catalog, Pydantic models, JSON Schema,
|
|
27
|
+
semantic validation, graph limits, and a pure bounded expression AST.
|
|
28
|
+
- Safe server rendering through Jinja2 with 46 catalog components, four complete design profiles,
|
|
29
|
+
accessible light/dark/system themes, and trusted SVG charts.
|
|
30
|
+
- Stateful and stateless dashboard, standalone, desktop, mobile, embedded-card, and chat-artifact
|
|
31
|
+
surfaces using FastAPI and HTMX.
|
|
32
|
+
- Immutable SQLite manifest revisions, server-owned state, optimistic concurrency, audit events,
|
|
33
|
+
device snapshots, and bounded in-process generation jobs.
|
|
34
|
+
- Qwen/Ollama structured generation with strict parsing, dry rendering, duplicate detection, and
|
|
35
|
+
at most two repair attempts after the initial candidate.
|
|
36
|
+
- Frozen data-contract, data-source, and capability registries for explicit host integrations.
|
|
37
|
+
- A bounded Google A2UI v0.9.1 JSONL importer.
|
|
38
|
+
- Three device-health example manifests, an AI-search host example, Docker/Compose support, and
|
|
39
|
+
package extras for base, web, HTTP sources, Ollama, serving, and the complete app.
|
|
40
|
+
- Secretless PyPI Trusted Publishing workflow with release-version and wheel-size gates.
|
|
41
|
+
|
|
42
|
+
### Security boundaries
|
|
43
|
+
|
|
44
|
+
- Manifests cannot contain HTML, Jinja, JavaScript, CSS, Tailwind classes, URLs, SQL, file paths,
|
|
45
|
+
SVG paths, callbacks, or arbitrary executable expressions.
|
|
46
|
+
- Invalid generated candidates are rejected before persistence and rendering.
|
|
47
|
+
- Host code owns credentials, endpoints, authorization, data access, and side-effect handlers.
|
|
48
|
+
|
|
49
|
+
### Known alpha limitations
|
|
50
|
+
|
|
51
|
+
- SQLite persistence and the in-process job worker support one ForgeUI process/replica per database.
|
|
52
|
+
- The live Ollama gauntlet requires an explicitly configured Ollama service and is not part of the
|
|
53
|
+
ordinary offline test suite.
|
|
54
|
+
- Google A2UI support is an allowlisted v0.9.1 snapshot importer, not a general A2UI client.
|
|
55
|
+
- APIs and the `forgeui/1` contract may change incompatibly before the first stable release.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
ForgeUI keeps its manifest and rendering boundary deliberately narrow. Before proposing a change,
|
|
4
|
+
read [the architecture](docs/architecture.md), [manifest contract](docs/manifest.md), and
|
|
5
|
+
[security boundaries](docs/security.md).
|
|
6
|
+
|
|
7
|
+
## Development
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
uv sync --frozen --all-extras
|
|
11
|
+
uv run ruff format --check .
|
|
12
|
+
uv run ruff check .
|
|
13
|
+
uv run mypy src/forgeui
|
|
14
|
+
uv run pytest -q --cov=forgeui --cov-fail-under=85
|
|
15
|
+
uv build
|
|
16
|
+
uv run twine check dist/*
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Changes to a component must keep its catalog entry, strict Pydantic props, generated schema and
|
|
20
|
+
prompt documentation, renderer template, examples, and tests synchronized. New model-controlled
|
|
21
|
+
HTML, CSS, classes, URLs, paths, executable expressions, or generic transport capabilities are not
|
|
22
|
+
accepted.
|
|
23
|
+
|
|
24
|
+
Use focused tests while developing and run the full suite before opening a pull request. Live
|
|
25
|
+
Ollama, browser, and Docker checks have explicit markers because they require external runtimes.
|
|
26
|
+
|
|
27
|
+
Report security issues privately as described in [SECURITY.md](SECURITY.md).
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# syntax=docker/dockerfile:1
|
|
2
|
+
# Build a small, reproducible runtime image from the committed uv lockfile.
|
|
3
|
+
FROM ghcr.io/astral-sh/uv:0.12.8 AS uv
|
|
4
|
+
|
|
5
|
+
FROM python:3.12-slim AS builder
|
|
6
|
+
|
|
7
|
+
COPY --from=uv /uv /uvx /bin/
|
|
8
|
+
WORKDIR /build
|
|
9
|
+
ENV UV_COMPILE_BYTECODE=1 \
|
|
10
|
+
UV_LINK_MODE=copy \
|
|
11
|
+
UV_NO_CACHE=1
|
|
12
|
+
|
|
13
|
+
COPY pyproject.toml uv.lock README.md LICENSE THIRD_PARTY_NOTICES.md ./
|
|
14
|
+
RUN uv sync --frozen --no-dev --extra app --no-install-project
|
|
15
|
+
|
|
16
|
+
COPY src ./src
|
|
17
|
+
RUN uv sync --frozen --no-dev --extra app
|
|
18
|
+
|
|
19
|
+
FROM python:3.12-slim AS runtime
|
|
20
|
+
|
|
21
|
+
ENV PYTHONDONTWRITEBYTECODE=1 \
|
|
22
|
+
PYTHONUNBUFFERED=1 \
|
|
23
|
+
PYTHONPATH=/app/src \
|
|
24
|
+
VIRTUAL_ENV=/opt/venv \
|
|
25
|
+
PATH=/opt/venv/bin:$PATH \
|
|
26
|
+
FORGEUI_DATA_DIR=/data \
|
|
27
|
+
FORGEUI_DATABASE_URL=sqlite:////data/forgeui.db
|
|
28
|
+
|
|
29
|
+
RUN addgroup --system --gid 10001 forgeui \
|
|
30
|
+
&& adduser --system --uid 10001 --ingroup forgeui --home /nonexistent forgeui \
|
|
31
|
+
&& mkdir -p /app /data \
|
|
32
|
+
&& chown -R forgeui:forgeui /app /data
|
|
33
|
+
|
|
34
|
+
WORKDIR /app
|
|
35
|
+
COPY --from=builder --chown=forgeui:forgeui /build/.venv /opt/venv
|
|
36
|
+
COPY --from=builder --chown=forgeui:forgeui /build/src /app/src
|
|
37
|
+
|
|
38
|
+
USER forgeui
|
|
39
|
+
EXPOSE 8000
|
|
40
|
+
|
|
41
|
+
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
|
|
42
|
+
CMD python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/api/health/ready', timeout=3)"
|
|
43
|
+
|
|
44
|
+
# The SQLite-backed in-process job worker requires one Uvicorn worker.
|
|
45
|
+
CMD ["uvicorn", "forgeui.app:create_app", "--factory", "--host", "0.0.0.0", "--port", "8000", "--workers", "1"]
|
forgeui-0.1.0a2/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ForgeUI contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|