narratty 0.1.0__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.
- narratty-0.1.0/.codespellignore +5 -0
- narratty-0.1.0/.dockerignore +13 -0
- narratty-0.1.0/.github/workflows/docker.yml +96 -0
- narratty-0.1.0/.github/workflows/main.yml +79 -0
- narratty-0.1.0/.github/workflows/pr.yml +156 -0
- narratty-0.1.0/.github/workflows/release.yml +134 -0
- narratty-0.1.0/.gitignore +37 -0
- narratty-0.1.0/.pre-commit-config.yaml +54 -0
- narratty-0.1.0/AGENTS.md +29 -0
- narratty-0.1.0/CHANGELOG.md +22 -0
- narratty-0.1.0/Dockerfile +74 -0
- narratty-0.1.0/LICENSE +21 -0
- narratty-0.1.0/PKG-INFO +111 -0
- narratty-0.1.0/README.md +44 -0
- narratty-0.1.0/docs/changelog.md +1 -0
- narratty-0.1.0/docs/contributor-guide/design.md +825 -0
- narratty-0.1.0/docs/contributor-guide/dev-setup.md +27 -0
- narratty-0.1.0/docs/contributor-guide/release-process.md +29 -0
- narratty-0.1.0/docs/index.md +39 -0
- narratty-0.1.0/docs/user-guide/building.md +60 -0
- narratty-0.1.0/docs/user-guide/commands.md +39 -0
- narratty-0.1.0/docs/user-guide/configuration.md +42 -0
- narratty-0.1.0/docs/user-guide/container.md +110 -0
- narratty-0.1.0/docs/user-guide/installation.md +29 -0
- narratty-0.1.0/docs/user-guide/shell-completion.md +12 -0
- narratty-0.1.0/docs/user-guide/spec.md +158 -0
- narratty-0.1.0/docs/user-guide/voices.md +63 -0
- narratty-0.1.0/mkdocs.yml +91 -0
- narratty-0.1.0/mypy.ini +16 -0
- narratty-0.1.0/noxfile.py +173 -0
- narratty-0.1.0/pyproject.toml +113 -0
- narratty-0.1.0/ruff.toml +17 -0
- narratty-0.1.0/schema/v1.json +649 -0
- narratty-0.1.0/src/narratty/__init__.py +15 -0
- narratty-0.1.0/src/narratty/__main__.py +35 -0
- narratty-0.1.0/src/narratty/_version.py +24 -0
- narratty-0.1.0/src/narratty/build.py +208 -0
- narratty-0.1.0/src/narratty/cache.py +85 -0
- narratty-0.1.0/src/narratty/cli/__init__.py +1 -0
- narratty-0.1.0/src/narratty/cli/app.py +74 -0
- narratty-0.1.0/src/narratty/cli/arguments.py +14 -0
- narratty-0.1.0/src/narratty/cli/commands/__init__.py +1 -0
- narratty-0.1.0/src/narratty/cli/commands/build.py +97 -0
- narratty-0.1.0/src/narratty/cli/commands/cache.py +57 -0
- narratty-0.1.0/src/narratty/cli/commands/doctor.py +51 -0
- narratty-0.1.0/src/narratty/cli/commands/init.py +25 -0
- narratty-0.1.0/src/narratty/cli/commands/plan.py +56 -0
- narratty-0.1.0/src/narratty/cli/commands/render.py +79 -0
- narratty-0.1.0/src/narratty/cli/commands/schema.py +12 -0
- narratty-0.1.0/src/narratty/cli/commands/tape.py +37 -0
- narratty-0.1.0/src/narratty/cli/commands/tts.py +48 -0
- narratty-0.1.0/src/narratty/cli/commands/validate.py +34 -0
- narratty-0.1.0/src/narratty/cli/commands/voices.py +72 -0
- narratty-0.1.0/src/narratty/cli/completion.py +51 -0
- narratty-0.1.0/src/narratty/cli/options.py +82 -0
- narratty-0.1.0/src/narratty/config.py +40 -0
- narratty-0.1.0/src/narratty/container.py +303 -0
- narratty-0.1.0/src/narratty/data/voices.toml +106 -0
- narratty-0.1.0/src/narratty/doctor.py +84 -0
- narratty-0.1.0/src/narratty/end_card.py +149 -0
- narratty-0.1.0/src/narratty/errors.py +72 -0
- narratty-0.1.0/src/narratty/forward.py +83 -0
- narratty-0.1.0/src/narratty/paths.py +33 -0
- narratty-0.1.0/src/narratty/py.typed +0 -0
- narratty-0.1.0/src/narratty/render/__init__.py +1 -0
- narratty-0.1.0/src/narratty/render/media.py +103 -0
- narratty-0.1.0/src/narratty/render/narration.py +58 -0
- narratty-0.1.0/src/narratty/render/tape.py +142 -0
- narratty-0.1.0/src/narratty/runtime.py +63 -0
- narratty-0.1.0/src/narratty/sandbox.py +294 -0
- narratty-0.1.0/src/narratty/spec/__init__.py +6 -0
- narratty-0.1.0/src/narratty/spec/loader.py +179 -0
- narratty-0.1.0/src/narratty/spec/model.py +315 -0
- narratty-0.1.0/src/narratty/spec/schema.py +41 -0
- narratty-0.1.0/src/narratty/spec/template.py +46 -0
- narratty-0.1.0/src/narratty/timeline.py +101 -0
- narratty-0.1.0/src/narratty/tts/__init__.py +1 -0
- narratty-0.1.0/src/narratty/tts/audio.py +29 -0
- narratty-0.1.0/src/narratty/tts/base.py +73 -0
- narratty-0.1.0/src/narratty/tts/catalog.py +97 -0
- narratty-0.1.0/src/narratty/tts/download.py +78 -0
- narratty-0.1.0/src/narratty/tts/kokoro.py +102 -0
- narratty-0.1.0/src/narratty/tts/normalize.py +15 -0
- narratty-0.1.0/src/narratty/tts/piper.py +129 -0
- narratty-0.1.0/src/narratty/tts/registry.py +49 -0
- narratty-0.1.0/src/narratty/tts/synth.py +72 -0
- narratty-0.1.0/src/narratty/ui/__init__.py +1 -0
- narratty-0.1.0/src/narratty/ui/console.py +21 -0
- narratty-0.1.0/src/narratty/workspace.py +172 -0
- narratty-0.1.0/tests/__init__.py +0 -0
- narratty-0.1.0/tests/helpers.py +28 -0
- narratty-0.1.0/tests/integration/__init__.py +0 -0
- narratty-0.1.0/tests/integration/conftest.py +20 -0
- narratty-0.1.0/tests/integration/test_build.py +101 -0
- narratty-0.1.0/tests/integration/test_container.py +46 -0
- narratty-0.1.0/tests/integration/test_sandbox_network.py +101 -0
- narratty-0.1.0/tests/integration/test_tts_engines.py +67 -0
- narratty-0.1.0/tests/performance/__init__.py +0 -0
- narratty-0.1.0/tests/performance/test_cold_start_budget.py +44 -0
- narratty-0.1.0/tests/unit/__init__.py +0 -0
- narratty-0.1.0/tests/unit/cli/__init__.py +0 -0
- narratty-0.1.0/tests/unit/cli/test_app.py +46 -0
- narratty-0.1.0/tests/unit/cli/test_completion.py +57 -0
- narratty-0.1.0/tests/unit/cli/test_render_commands.py +111 -0
- narratty-0.1.0/tests/unit/cli/test_spec_commands.py +46 -0
- narratty-0.1.0/tests/unit/cli/test_tts_commands.py +118 -0
- narratty-0.1.0/tests/unit/conftest.py +17 -0
- narratty-0.1.0/tests/unit/render/__init__.py +0 -0
- narratty-0.1.0/tests/unit/render/test_media.py +81 -0
- narratty-0.1.0/tests/unit/render/test_narration.py +70 -0
- narratty-0.1.0/tests/unit/render/test_tape.py +122 -0
- narratty-0.1.0/tests/unit/spec/__init__.py +0 -0
- narratty-0.1.0/tests/unit/spec/test_loader.py +83 -0
- narratty-0.1.0/tests/unit/spec/test_model.py +109 -0
- narratty-0.1.0/tests/unit/spec/test_schema.py +39 -0
- narratty-0.1.0/tests/unit/test_build.py +70 -0
- narratty-0.1.0/tests/unit/test_cache.py +62 -0
- narratty-0.1.0/tests/unit/test_container.py +181 -0
- narratty-0.1.0/tests/unit/test_doctor.py +20 -0
- narratty-0.1.0/tests/unit/test_end_card.py +158 -0
- narratty-0.1.0/tests/unit/test_forward.py +48 -0
- narratty-0.1.0/tests/unit/test_main.py +18 -0
- narratty-0.1.0/tests/unit/test_runtime.py +40 -0
- narratty-0.1.0/tests/unit/test_sandbox.py +167 -0
- narratty-0.1.0/tests/unit/test_timeline.py +90 -0
- narratty-0.1.0/tests/unit/test_workspace.py +135 -0
- narratty-0.1.0/tests/unit/tts/__init__.py +0 -0
- narratty-0.1.0/tests/unit/tts/test_catalog.py +47 -0
- narratty-0.1.0/tests/unit/tts/test_download.py +40 -0
- narratty-0.1.0/tests/unit/tts/test_normalize_audio.py +28 -0
- narratty-0.1.0/tests/unit/tts/test_providers.py +178 -0
- narratty-0.1.0/tests/unit/tts/test_synth.py +119 -0
- narratty-0.1.0/uv.lock +2094 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
name: Docker image
|
|
2
|
+
# PRs: build and test the image (amd64, not pushed).
|
|
3
|
+
# main: push :edge / :edge-kokoro. Release tags v*: push :<version>, :latest (and -kokoro).
|
|
4
|
+
on:
|
|
5
|
+
pull_request:
|
|
6
|
+
push:
|
|
7
|
+
branches: [main]
|
|
8
|
+
tags: ["v[0-9]+.[0-9]+.[0-9]*"]
|
|
9
|
+
concurrency:
|
|
10
|
+
group: docker-${{ github.ref }}
|
|
11
|
+
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
env:
|
|
15
|
+
IMAGE: ghcr.io/${{ github.repository_owner }}/narratty
|
|
16
|
+
jobs:
|
|
17
|
+
image:
|
|
18
|
+
name: Image (${{ matrix.variant }})
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
permissions:
|
|
21
|
+
contents: read
|
|
22
|
+
packages: write
|
|
23
|
+
strategy:
|
|
24
|
+
fail-fast: false
|
|
25
|
+
matrix:
|
|
26
|
+
include:
|
|
27
|
+
- variant: base
|
|
28
|
+
target: base
|
|
29
|
+
suffix: ""
|
|
30
|
+
- variant: kokoro
|
|
31
|
+
target: kokoro
|
|
32
|
+
suffix: "-kokoro"
|
|
33
|
+
steps:
|
|
34
|
+
- uses: actions/checkout@v7
|
|
35
|
+
with:
|
|
36
|
+
fetch-depth: 0 # the version comes from git tags
|
|
37
|
+
- uses: astral-sh/setup-uv@v7
|
|
38
|
+
- name: Version
|
|
39
|
+
id: version
|
|
40
|
+
run: echo "version=$(uvx --from setuptools-scm python -m setuptools_scm)" >> "$GITHUB_OUTPUT"
|
|
41
|
+
- uses: docker/setup-qemu-action@v4
|
|
42
|
+
if: github.event_name != 'pull_request'
|
|
43
|
+
- uses: docker/setup-buildx-action@v4
|
|
44
|
+
- uses: docker/metadata-action@v6
|
|
45
|
+
id: meta
|
|
46
|
+
with:
|
|
47
|
+
images: ${{ env.IMAGE }}
|
|
48
|
+
flavor: |
|
|
49
|
+
latest=false
|
|
50
|
+
suffix=${{ matrix.suffix }},onlatest=true
|
|
51
|
+
tags: |
|
|
52
|
+
type=edge,branch=main
|
|
53
|
+
type=semver,pattern={{version}}
|
|
54
|
+
type=semver,pattern={{major}}.{{minor}}
|
|
55
|
+
type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/v') }}
|
|
56
|
+
type=ref,event=pr
|
|
57
|
+
- name: Log in to GHCR
|
|
58
|
+
if: github.event_name != 'pull_request'
|
|
59
|
+
uses: docker/login-action@v4
|
|
60
|
+
with:
|
|
61
|
+
registry: ghcr.io
|
|
62
|
+
username: ${{ github.actor }}
|
|
63
|
+
password: ${{ secrets.GITHUB_TOKEN }}
|
|
64
|
+
- name: Build (and push outside PRs)
|
|
65
|
+
uses: docker/build-push-action@v7
|
|
66
|
+
with:
|
|
67
|
+
context: .
|
|
68
|
+
target: ${{ matrix.target }}
|
|
69
|
+
build-args: NARRATTY_VERSION=${{ steps.version.outputs.version }}
|
|
70
|
+
platforms: ${{ github.event_name == 'pull_request' && 'linux/amd64' || 'linux/amd64,linux/arm64' }}
|
|
71
|
+
push: ${{ github.event_name != 'pull_request' }}
|
|
72
|
+
load: ${{ github.event_name == 'pull_request' }}
|
|
73
|
+
tags: ${{ github.event_name == 'pull_request' && format('narratty:test{0}', matrix.suffix) || steps.meta.outputs.tags }}
|
|
74
|
+
labels: ${{ steps.meta.outputs.labels }}
|
|
75
|
+
cache-from: type=gha,scope=${{ matrix.variant }}
|
|
76
|
+
cache-to: type=gha,mode=max,scope=${{ matrix.variant }}
|
|
77
|
+
- name: Smoke test
|
|
78
|
+
if: github.event_name == 'pull_request'
|
|
79
|
+
run: |
|
|
80
|
+
docker run --rm narratty:test${{ matrix.suffix }} --version
|
|
81
|
+
docker run --rm narratty:test${{ matrix.suffix }} doctor --runtime native
|
|
82
|
+
docker run --rm narratty:test${{ matrix.suffix }} voices --installed
|
|
83
|
+
- uses: actions/setup-python@v6
|
|
84
|
+
if: github.event_name == 'pull_request' && matrix.variant == 'base'
|
|
85
|
+
with:
|
|
86
|
+
python-version: "3.12"
|
|
87
|
+
- name: Install ffprobe (the test checks the video on the host)
|
|
88
|
+
if: github.event_name == 'pull_request' && matrix.variant == 'base'
|
|
89
|
+
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends ffmpeg
|
|
90
|
+
- name: Build a video through the container runtime and test the sandbox network
|
|
91
|
+
if: github.event_name == 'pull_request' && matrix.variant == 'base'
|
|
92
|
+
env:
|
|
93
|
+
NARRATTY_IMAGE: narratty:test
|
|
94
|
+
run: |
|
|
95
|
+
uv tool install nox
|
|
96
|
+
nox -s integration -- -k "container or sandbox_network"
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
name: Main
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches: [main]
|
|
5
|
+
concurrency:
|
|
6
|
+
group: main-${{ github.ref }}
|
|
7
|
+
cancel-in-progress: true
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
jobs:
|
|
11
|
+
# ── 1. Full quality gates ───────────────────────────────────────────────────
|
|
12
|
+
quality:
|
|
13
|
+
name: Quality gates (3.12)
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v7
|
|
17
|
+
with:
|
|
18
|
+
fetch-depth: 0
|
|
19
|
+
- uses: actions/setup-python@v6
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.12"
|
|
22
|
+
- uses: astral-sh/setup-uv@v7
|
|
23
|
+
- name: Install nox
|
|
24
|
+
run: uv tool install nox
|
|
25
|
+
- name: Run all quality gates
|
|
26
|
+
run: nox --no-error-on-missing-interpreters
|
|
27
|
+
# ── 2. Tests: multi-Python matrix, macOS best effort ────────────────────────
|
|
28
|
+
tests:
|
|
29
|
+
name: Tests (${{ matrix.os }}, Python ${{ matrix.python-version }})
|
|
30
|
+
runs-on: ${{ matrix.os }}
|
|
31
|
+
continue-on-error: ${{ matrix.os == 'macos-latest' }}
|
|
32
|
+
strategy:
|
|
33
|
+
fail-fast: false
|
|
34
|
+
matrix:
|
|
35
|
+
os: [ubuntu-latest]
|
|
36
|
+
python-version: ["3.12", "3.13", "3.14"]
|
|
37
|
+
include:
|
|
38
|
+
- os: macos-latest
|
|
39
|
+
python-version: "3.12"
|
|
40
|
+
steps:
|
|
41
|
+
- uses: actions/checkout@v7
|
|
42
|
+
with:
|
|
43
|
+
fetch-depth: 0
|
|
44
|
+
- uses: actions/setup-python@v6
|
|
45
|
+
with:
|
|
46
|
+
python-version: ${{ matrix.python-version }}
|
|
47
|
+
allow-prereleases: true
|
|
48
|
+
- uses: astral-sh/setup-uv@v7
|
|
49
|
+
- name: Install nox
|
|
50
|
+
run: uv tool install nox
|
|
51
|
+
- name: Unit tests
|
|
52
|
+
run: nox -s tests-${{ matrix.python-version }}
|
|
53
|
+
# ── 3. Deploy docs `latest` to GitHub Pages ─────────────────────────────────
|
|
54
|
+
docs-deploy:
|
|
55
|
+
name: Deploy docs (latest)
|
|
56
|
+
runs-on: ubuntu-latest
|
|
57
|
+
needs: [quality, tests]
|
|
58
|
+
permissions:
|
|
59
|
+
contents: write
|
|
60
|
+
steps:
|
|
61
|
+
- uses: actions/checkout@v7
|
|
62
|
+
with:
|
|
63
|
+
fetch-depth: 0
|
|
64
|
+
- uses: actions/setup-python@v6
|
|
65
|
+
with:
|
|
66
|
+
python-version: "3.12"
|
|
67
|
+
- uses: astral-sh/setup-uv@v7
|
|
68
|
+
- name: Install docs deps
|
|
69
|
+
run: uv pip install -e ".[docs]" --system
|
|
70
|
+
- name: Configure git for mike
|
|
71
|
+
run: |
|
|
72
|
+
git config user.name "github-actions[bot]"
|
|
73
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
74
|
+
- name: Deploy latest docs
|
|
75
|
+
env:
|
|
76
|
+
NO_MKDOCS_2_WARNING: "1"
|
|
77
|
+
run: |
|
|
78
|
+
mike deploy --push --update-aliases latest
|
|
79
|
+
mike set-default --push latest
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
name: PR
|
|
2
|
+
on:
|
|
3
|
+
pull_request:
|
|
4
|
+
types: [opened, synchronize, reopened, edited]
|
|
5
|
+
concurrency:
|
|
6
|
+
group: pr-${{ github.event.pull_request.number }}
|
|
7
|
+
cancel-in-progress: true
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
pull-requests: read
|
|
11
|
+
jobs:
|
|
12
|
+
# ── 1. Conventional Commits PR-title lint (primary gate for squash merges) ──
|
|
13
|
+
lint-title:
|
|
14
|
+
name: Lint PR title
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- uses: amannn/action-semantic-pull-request@v6
|
|
18
|
+
env:
|
|
19
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
20
|
+
with:
|
|
21
|
+
types: |
|
|
22
|
+
feat
|
|
23
|
+
fix
|
|
24
|
+
docs
|
|
25
|
+
refactor
|
|
26
|
+
perf
|
|
27
|
+
test
|
|
28
|
+
build
|
|
29
|
+
ci
|
|
30
|
+
chore
|
|
31
|
+
revert
|
|
32
|
+
requireScope: false
|
|
33
|
+
subjectPattern: ^[a-z].+[^.]$
|
|
34
|
+
subjectPatternError: |
|
|
35
|
+
Subject must start lowercase and not end with a period.
|
|
36
|
+
# ── 2. Code quality ─────────────────────────────────────────────────────────
|
|
37
|
+
quality:
|
|
38
|
+
name: Quality gates (3.12)
|
|
39
|
+
runs-on: ubuntu-latest
|
|
40
|
+
steps:
|
|
41
|
+
- uses: actions/checkout@v7
|
|
42
|
+
with:
|
|
43
|
+
fetch-depth: 0 # hatch-vcs needs tags for the version
|
|
44
|
+
- uses: actions/setup-python@v6
|
|
45
|
+
with:
|
|
46
|
+
python-version: "3.12"
|
|
47
|
+
- uses: astral-sh/setup-uv@v7
|
|
48
|
+
- name: Install nox
|
|
49
|
+
run: uv tool install nox
|
|
50
|
+
- name: Syntax check
|
|
51
|
+
run: nox -s check_syntax
|
|
52
|
+
- name: Lint
|
|
53
|
+
run: nox -s lint
|
|
54
|
+
- name: Type check
|
|
55
|
+
run: nox -s check_types
|
|
56
|
+
- name: Import analysis
|
|
57
|
+
run: nox -s necessary_imports
|
|
58
|
+
- name: Dead code
|
|
59
|
+
run: nox -s dead_code
|
|
60
|
+
- name: Duplicate code
|
|
61
|
+
run: nox -s duplicates
|
|
62
|
+
- name: Cyclic imports
|
|
63
|
+
run: nox -s cyclic_imports
|
|
64
|
+
# ── 3. Tests: multi-Python matrix, macOS best effort ────────────────────────
|
|
65
|
+
tests:
|
|
66
|
+
name: Tests (${{ matrix.os }}, Python ${{ matrix.python-version }})
|
|
67
|
+
runs-on: ${{ matrix.os }}
|
|
68
|
+
continue-on-error: ${{ matrix.os == 'macos-latest' }}
|
|
69
|
+
strategy:
|
|
70
|
+
fail-fast: false
|
|
71
|
+
matrix:
|
|
72
|
+
os: [ubuntu-latest]
|
|
73
|
+
python-version: ["3.12", "3.13", "3.14"]
|
|
74
|
+
include:
|
|
75
|
+
# macOS is optional: smoke-test the primary Python, never block.
|
|
76
|
+
- os: macos-latest
|
|
77
|
+
python-version: "3.12"
|
|
78
|
+
steps:
|
|
79
|
+
- uses: actions/checkout@v7
|
|
80
|
+
with:
|
|
81
|
+
fetch-depth: 0
|
|
82
|
+
- uses: actions/setup-python@v6
|
|
83
|
+
with:
|
|
84
|
+
python-version: ${{ matrix.python-version }}
|
|
85
|
+
allow-prereleases: true
|
|
86
|
+
- uses: astral-sh/setup-uv@v7
|
|
87
|
+
- name: Install nox
|
|
88
|
+
run: uv tool install nox
|
|
89
|
+
- name: Unit tests
|
|
90
|
+
run: nox -s tests-${{ matrix.python-version }}
|
|
91
|
+
# ── 4. Integration: real voices, VHS and ffmpeg ─────────────────────────────
|
|
92
|
+
integration:
|
|
93
|
+
name: Integration (3.12)
|
|
94
|
+
runs-on: ubuntu-latest
|
|
95
|
+
env:
|
|
96
|
+
NARRATTY_DATA_DIR: ${{ github.workspace }}/.narratty-data
|
|
97
|
+
VHS_VERSION: "0.12.1"
|
|
98
|
+
# Chromium's sandbox is blocked by Ubuntu's user-namespace restrictions on runners.
|
|
99
|
+
VHS_NO_SANDBOX: "true"
|
|
100
|
+
steps:
|
|
101
|
+
- uses: actions/checkout@v7
|
|
102
|
+
with:
|
|
103
|
+
fetch-depth: 0
|
|
104
|
+
- uses: actions/setup-python@v6
|
|
105
|
+
with:
|
|
106
|
+
python-version: "3.12"
|
|
107
|
+
- uses: astral-sh/setup-uv@v7
|
|
108
|
+
- name: Cache voices and models
|
|
109
|
+
uses: actions/cache@v5
|
|
110
|
+
with:
|
|
111
|
+
path: .narratty-data
|
|
112
|
+
key: narratty-voices-${{ hashFiles('src/narratty/data/voices.toml') }}
|
|
113
|
+
- name: Install ffmpeg, ttyd and VHS
|
|
114
|
+
run: |
|
|
115
|
+
sudo apt-get update
|
|
116
|
+
sudo apt-get install -y --no-install-recommends ffmpeg ttyd
|
|
117
|
+
curl -fsSL -o "$RUNNER_TEMP/vhs.deb" \
|
|
118
|
+
"https://github.com/charmbracelet/vhs/releases/download/v${VHS_VERSION}/vhs_${VHS_VERSION}_amd64.deb"
|
|
119
|
+
sudo apt-get install -y "$RUNNER_TEMP/vhs.deb"
|
|
120
|
+
vhs --version
|
|
121
|
+
- name: Install nox
|
|
122
|
+
run: uv tool install nox
|
|
123
|
+
- name: Integration tests
|
|
124
|
+
run: nox -s integration
|
|
125
|
+
# ── 5. CLI cold-start performance budgets ───────────────────────────────────
|
|
126
|
+
performance:
|
|
127
|
+
name: Performance budgets (3.12)
|
|
128
|
+
runs-on: ubuntu-latest
|
|
129
|
+
steps:
|
|
130
|
+
- uses: actions/checkout@v7
|
|
131
|
+
with:
|
|
132
|
+
fetch-depth: 0
|
|
133
|
+
- uses: actions/setup-python@v6
|
|
134
|
+
with:
|
|
135
|
+
python-version: "3.12"
|
|
136
|
+
- uses: astral-sh/setup-uv@v7
|
|
137
|
+
- name: Install nox
|
|
138
|
+
run: uv tool install nox
|
|
139
|
+
- name: Performance budgets
|
|
140
|
+
run: nox -s performance
|
|
141
|
+
# ── 6. Docs build (strict) ──────────────────────────────────────────────────
|
|
142
|
+
docs-build:
|
|
143
|
+
name: Docs build (strict)
|
|
144
|
+
runs-on: ubuntu-latest
|
|
145
|
+
steps:
|
|
146
|
+
- uses: actions/checkout@v7
|
|
147
|
+
with:
|
|
148
|
+
fetch-depth: 0
|
|
149
|
+
- uses: actions/setup-python@v6
|
|
150
|
+
with:
|
|
151
|
+
python-version: "3.12"
|
|
152
|
+
- uses: astral-sh/setup-uv@v7
|
|
153
|
+
- name: Install nox
|
|
154
|
+
run: uv tool install nox
|
|
155
|
+
- name: Build docs
|
|
156
|
+
run: nox -s docs
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
tags:
|
|
5
|
+
- "v[0-9]+.[0-9]+.[0-9]*"
|
|
6
|
+
permissions:
|
|
7
|
+
contents: write # create GitHub Release
|
|
8
|
+
id-token: write # OIDC Trusted Publishing (PyPI + TestPyPI)
|
|
9
|
+
jobs:
|
|
10
|
+
# ── 1. Build sdist + wheel ───────────────────────────────────────────────────
|
|
11
|
+
build:
|
|
12
|
+
name: Build distribution
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
outputs:
|
|
15
|
+
version: ${{ steps.version.outputs.version }}
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v7
|
|
18
|
+
with:
|
|
19
|
+
fetch-depth: 0 # hatch-vcs needs full history
|
|
20
|
+
- uses: actions/setup-python@v6
|
|
21
|
+
with:
|
|
22
|
+
python-version: "3.12"
|
|
23
|
+
- uses: astral-sh/setup-uv@v7
|
|
24
|
+
- name: Install hatch
|
|
25
|
+
run: uv tool install hatch
|
|
26
|
+
- name: Build
|
|
27
|
+
run: hatch build
|
|
28
|
+
- name: Extract version
|
|
29
|
+
id: version
|
|
30
|
+
run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
|
|
31
|
+
- uses: actions/upload-artifact@v7
|
|
32
|
+
with:
|
|
33
|
+
name: dist
|
|
34
|
+
path: dist/
|
|
35
|
+
# ── 2. Publish to TestPyPI (dry-run gate) ───────────────────────────────────
|
|
36
|
+
publish-test:
|
|
37
|
+
name: Publish to TestPyPI
|
|
38
|
+
runs-on: ubuntu-latest
|
|
39
|
+
needs: build
|
|
40
|
+
environment:
|
|
41
|
+
name: testpypi
|
|
42
|
+
url: https://test.pypi.org/p/narratty
|
|
43
|
+
steps:
|
|
44
|
+
- uses: actions/download-artifact@v8
|
|
45
|
+
with:
|
|
46
|
+
name: dist
|
|
47
|
+
path: dist/
|
|
48
|
+
- name: Publish to TestPyPI
|
|
49
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
50
|
+
with:
|
|
51
|
+
repository-url: https://test.pypi.org/legacy/
|
|
52
|
+
print-hash: true
|
|
53
|
+
verbose: true
|
|
54
|
+
- name: Verify install from TestPyPI
|
|
55
|
+
run: |
|
|
56
|
+
uv tool install \
|
|
57
|
+
--index-url https://test.pypi.org/simple/ \
|
|
58
|
+
--extra-index-url https://pypi.org/simple/ \
|
|
59
|
+
"narratty==${{ needs.build.outputs.version }}"
|
|
60
|
+
narratty --version
|
|
61
|
+
# ── 3. Publish to PyPI (production) ─────────────────────────────────────────
|
|
62
|
+
publish-pypi:
|
|
63
|
+
name: Publish to PyPI
|
|
64
|
+
runs-on: ubuntu-latest
|
|
65
|
+
needs: [build, publish-test]
|
|
66
|
+
environment:
|
|
67
|
+
name: pypi
|
|
68
|
+
url: https://pypi.org/p/narratty
|
|
69
|
+
steps:
|
|
70
|
+
- uses: actions/download-artifact@v8
|
|
71
|
+
with:
|
|
72
|
+
name: dist
|
|
73
|
+
path: dist/
|
|
74
|
+
- name: Publish to PyPI
|
|
75
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
76
|
+
with:
|
|
77
|
+
print-hash: true
|
|
78
|
+
# ── 4. Create GitHub Release ─────────────────────────────────────────────────
|
|
79
|
+
github-release:
|
|
80
|
+
name: Create GitHub Release
|
|
81
|
+
runs-on: ubuntu-latest
|
|
82
|
+
needs: [build, publish-pypi]
|
|
83
|
+
permissions:
|
|
84
|
+
contents: write
|
|
85
|
+
steps:
|
|
86
|
+
- uses: actions/checkout@v7
|
|
87
|
+
with:
|
|
88
|
+
fetch-depth: 0
|
|
89
|
+
- uses: actions/setup-python@v6
|
|
90
|
+
with:
|
|
91
|
+
python-version: "3.12"
|
|
92
|
+
- uses: astral-sh/setup-uv@v7
|
|
93
|
+
- name: Install commitizen
|
|
94
|
+
run: uv tool install commitizen
|
|
95
|
+
- name: Extract changelog for this version
|
|
96
|
+
run: |
|
|
97
|
+
cz changelog --dry-run "${{ needs.build.outputs.version }}" > /tmp/release-notes.md || \
|
|
98
|
+
echo "Release ${{ needs.build.outputs.version }}" > /tmp/release-notes.md
|
|
99
|
+
- uses: actions/download-artifact@v8
|
|
100
|
+
with:
|
|
101
|
+
name: dist
|
|
102
|
+
path: dist/
|
|
103
|
+
- name: Create GitHub Release
|
|
104
|
+
uses: softprops/action-gh-release@v3
|
|
105
|
+
with:
|
|
106
|
+
body_path: /tmp/release-notes.md
|
|
107
|
+
files: dist/*
|
|
108
|
+
fail_on_unmatched_files: true
|
|
109
|
+
# ── 5. Deploy versioned docs ─────────────────────────────────────────────────
|
|
110
|
+
docs-deploy:
|
|
111
|
+
name: Deploy versioned docs
|
|
112
|
+
runs-on: ubuntu-latest
|
|
113
|
+
needs: [build, github-release]
|
|
114
|
+
permissions:
|
|
115
|
+
contents: write
|
|
116
|
+
steps:
|
|
117
|
+
- uses: actions/checkout@v7
|
|
118
|
+
with:
|
|
119
|
+
fetch-depth: 0
|
|
120
|
+
- uses: actions/setup-python@v6
|
|
121
|
+
with:
|
|
122
|
+
python-version: "3.12"
|
|
123
|
+
- uses: astral-sh/setup-uv@v7
|
|
124
|
+
- name: Install docs deps
|
|
125
|
+
run: uv pip install -e ".[docs]" --system
|
|
126
|
+
- name: Configure git for mike
|
|
127
|
+
run: |
|
|
128
|
+
git config user.name "github-actions[bot]"
|
|
129
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
130
|
+
- name: Deploy versioned docs
|
|
131
|
+
run: |
|
|
132
|
+
VERSION="${{ needs.build.outputs.version }}"
|
|
133
|
+
mike deploy --push --update-aliases "$VERSION" stable
|
|
134
|
+
mike set-default --push stable
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# generated files
|
|
2
|
+
src/narratty/_version.py
|
|
3
|
+
|
|
4
|
+
# Byte-compiled / caches
|
|
5
|
+
__pycache__/
|
|
6
|
+
*.py[cod]
|
|
7
|
+
*.egg-info/
|
|
8
|
+
.eggs/
|
|
9
|
+
build/
|
|
10
|
+
dist/
|
|
11
|
+
|
|
12
|
+
# Environments
|
|
13
|
+
.venv/
|
|
14
|
+
venv/
|
|
15
|
+
.env
|
|
16
|
+
|
|
17
|
+
# Tooling caches
|
|
18
|
+
.nox/
|
|
19
|
+
.mypy_cache/
|
|
20
|
+
.ruff_cache/
|
|
21
|
+
.pytest_cache/
|
|
22
|
+
.coverage
|
|
23
|
+
coverage.xml
|
|
24
|
+
htmlcov/
|
|
25
|
+
|
|
26
|
+
# Editor
|
|
27
|
+
.idea/
|
|
28
|
+
*.swp
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# MkDocs build output
|
|
34
|
+
site/
|
|
35
|
+
|
|
36
|
+
# narratty render output
|
|
37
|
+
out/
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
default_install_hook_types: [pre-commit, commit-msg]
|
|
2
|
+
default_stages: [pre-commit, manual]
|
|
3
|
+
|
|
4
|
+
repos:
|
|
5
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks.git
|
|
6
|
+
rev: v6.0.0
|
|
7
|
+
hooks:
|
|
8
|
+
- id: check-added-large-files
|
|
9
|
+
args: [--maxkb=500]
|
|
10
|
+
- id: check-case-conflict
|
|
11
|
+
- id: check-merge-conflict
|
|
12
|
+
- id: check-symlinks
|
|
13
|
+
- id: check-toml
|
|
14
|
+
- id: check-yaml
|
|
15
|
+
args: [--unsafe] # mkdocs.yml uses custom tags
|
|
16
|
+
- id: end-of-file-fixer
|
|
17
|
+
- id: mixed-line-ending
|
|
18
|
+
args: [--fix=lf]
|
|
19
|
+
- id: trailing-whitespace
|
|
20
|
+
args: [--markdown-linebreak-ext=md]
|
|
21
|
+
- id: detect-private-key
|
|
22
|
+
|
|
23
|
+
- repo: https://github.com/codespell-project/codespell
|
|
24
|
+
rev: v2.4.2
|
|
25
|
+
hooks:
|
|
26
|
+
- id: codespell
|
|
27
|
+
args: [--ignore-words=.codespellignore, --quiet-level=2]
|
|
28
|
+
|
|
29
|
+
# Quality gates mirror the nox sessions and run in isolated uv envs, so
|
|
30
|
+
# versions come from the pyproject extras rather than host tools.
|
|
31
|
+
- repo: local
|
|
32
|
+
hooks:
|
|
33
|
+
- id: ruff-check
|
|
34
|
+
name: ruff check
|
|
35
|
+
entry: uv run --isolated --extra lint ruff check --fix
|
|
36
|
+
language: system
|
|
37
|
+
types: [python]
|
|
38
|
+
- id: ruff-format
|
|
39
|
+
name: ruff format
|
|
40
|
+
entry: uv run --isolated --extra lint ruff format
|
|
41
|
+
language: system
|
|
42
|
+
types: [python]
|
|
43
|
+
- id: mypy
|
|
44
|
+
name: mypy
|
|
45
|
+
entry: uv run --isolated --extra type-check mypy
|
|
46
|
+
language: system
|
|
47
|
+
pass_filenames: false
|
|
48
|
+
args: [--package, narratty]
|
|
49
|
+
|
|
50
|
+
- repo: https://github.com/commitizen-tools/commitizen
|
|
51
|
+
rev: v4.16.4
|
|
52
|
+
hooks:
|
|
53
|
+
- id: commitizen
|
|
54
|
+
stages: [commit-msg]
|
narratty-0.1.0/AGENTS.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
`narratty` is a Python CLI (command and import package `narratty`) that turns a
|
|
4
|
+
`.narratty.yaml` spec into a narrated terminal video. The design and milestones live in
|
|
5
|
+
`docs/contributor-guide/design.md`; read it before adding features.
|
|
6
|
+
|
|
7
|
+
## Tooling
|
|
8
|
+
|
|
9
|
+
- **uv** manages the environment (`uv sync --extra dev` creates `.venv`), **nox** runs the
|
|
10
|
+
quality gates. `noxfile.py` is the authoritative command list.
|
|
11
|
+
- Lint and format: ruff only (`nox -s lint`, `nox -s format`). Types: mypy (`nox -s check_types`).
|
|
12
|
+
- Unit tests: `nox -s tests` or `.venv/bin/pytest`. Performance budgets are marked
|
|
13
|
+
`performance` and deselected by default; run them with `nox -s performance`.
|
|
14
|
+
- Docs: `nox -s docs` (mkdocs `--strict`, zero warnings).
|
|
15
|
+
|
|
16
|
+
## Conventions
|
|
17
|
+
|
|
18
|
+
- One module per subcommand under `src/narratty/cli/commands/`. Import heavy dependencies
|
|
19
|
+
inside the command function so `--help` and shell completion stay under their budgets.
|
|
20
|
+
- Errors are `NarrattyError` subclasses carrying an `ExitCode` and an optional `hint`;
|
|
21
|
+
never renumber `ExitCode`.
|
|
22
|
+
- Data goes to stdout, logs and errors to stderr (`narratty.ui.console`).
|
|
23
|
+
- Commits and PR titles follow Conventional Commits.
|
|
24
|
+
|
|
25
|
+
## Gotchas
|
|
26
|
+
|
|
27
|
+
- The version comes from git tags via hatch-vcs; shallow clones without tags report
|
|
28
|
+
`0.1.devN`. CI checks out with `fetch-depth: 0`.
|
|
29
|
+
- `nox` without `NOX_CI=1` runs `format` first, which edits files.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format follows
|
|
4
|
+
[Conventional Commits](https://www.conventionalcommits.org/) and is maintained by
|
|
5
|
+
commitizen.
|
|
6
|
+
|
|
7
|
+
## v0.1.0 (2026-09-30)
|
|
8
|
+
|
|
9
|
+
### Feat
|
|
10
|
+
|
|
11
|
+
- **end-card**: close videos with a "Created with narratty" card and QR code
|
|
12
|
+
- **sandbox**: add workspace modes, network allowlist and sandbox consent
|
|
13
|
+
- **container**: add the narratty image, GHCR publishing and a container runtime
|
|
14
|
+
- **build**: render narrated videos with VHS and ffmpeg
|
|
15
|
+
- **tts**: add Piper and Kokoro providers with voice catalog and audio cache
|
|
16
|
+
- **init**: point the schema header at the installed version's schema
|
|
17
|
+
- **spec**: add spec format v1 with init, validate and schema commands
|
|
18
|
+
- project scaffold with doctor command and shell completion
|
|
19
|
+
|
|
20
|
+
### Fix
|
|
21
|
+
|
|
22
|
+
- **container**: install ttyd from its release binary
|