qwenloop 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.
- qwenloop-0.1.0/.githooks/commit-msg +49 -0
- qwenloop-0.1.0/.githooks/pre-push +69 -0
- qwenloop-0.1.0/.github/CODEOWNERS +1 -0
- qwenloop-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +23 -0
- qwenloop-0.1.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
- qwenloop-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +23 -0
- qwenloop-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +15 -0
- qwenloop-0.1.0/.github/dependabot.yml +21 -0
- qwenloop-0.1.0/.github/workflows/ci.yml +68 -0
- qwenloop-0.1.0/.github/workflows/merge-train.yml +78 -0
- qwenloop-0.1.0/.github/workflows/promote-to-main.yml +78 -0
- qwenloop-0.1.0/.github/workflows/provenance.yml +67 -0
- qwenloop-0.1.0/.github/workflows/release.yml +110 -0
- qwenloop-0.1.0/.gitignore +11 -0
- qwenloop-0.1.0/.vibey-gh.toml +22 -0
- qwenloop-0.1.0/AGENTS.md +7 -0
- qwenloop-0.1.0/CODE_OF_CONDUCT.md +8 -0
- qwenloop-0.1.0/CONTRIBUTING.md +27 -0
- qwenloop-0.1.0/LICENSE +22 -0
- qwenloop-0.1.0/PKG-INFO +111 -0
- qwenloop-0.1.0/README.md +76 -0
- qwenloop-0.1.0/SECURITY.md +17 -0
- qwenloop-0.1.0/deploy/docker/Dockerfile +12 -0
- qwenloop-0.1.0/docs/architecture/decisions/0001-local-inference.md +7 -0
- qwenloop-0.1.0/docs/architecture/decisions/0002-tool-security.md +7 -0
- qwenloop-0.1.0/docs/capability-matrix.md +9 -0
- qwenloop-0.1.0/pyproject.toml +75 -0
- qwenloop-0.1.0/scripts/evaluate_quantizations.py +172 -0
- qwenloop-0.1.0/src/qwenloop/__init__.py +4 -0
- qwenloop-0.1.0/src/qwenloop/application/__init__.py +2 -0
- qwenloop-0.1.0/src/qwenloop/application/backend_selection.py +28 -0
- qwenloop-0.1.0/src/qwenloop/application/interfaces.py +30 -0
- qwenloop-0.1.0/src/qwenloop/application/runner.py +115 -0
- qwenloop-0.1.0/src/qwenloop/cli/__init__.py +2 -0
- qwenloop-0.1.0/src/qwenloop/cli/app.py +343 -0
- qwenloop-0.1.0/src/qwenloop/domain/__init__.py +2 -0
- qwenloop-0.1.0/src/qwenloop/domain/config.py +37 -0
- qwenloop-0.1.0/src/qwenloop/domain/model.py +84 -0
- qwenloop-0.1.0/src/qwenloop/infrastructure/__init__.py +2 -0
- qwenloop-0.1.0/src/qwenloop/infrastructure/inference.py +315 -0
- qwenloop-0.1.0/src/qwenloop/infrastructure/model_cache.py +96 -0
- qwenloop-0.1.0/src/qwenloop/infrastructure/profiles.py +31 -0
- qwenloop-0.1.0/src/qwenloop/infrastructure/run_store.py +52 -0
- qwenloop-0.1.0/src/qwenloop/infrastructure/tools.py +61 -0
- qwenloop-0.1.0/src/qwenloop/py.typed +1 -0
- qwenloop-0.1.0/tests/test_cli.py +305 -0
- qwenloop-0.1.0/tests/test_domain.py +38 -0
- qwenloop-0.1.0/tests/test_inference.py +277 -0
- qwenloop-0.1.0/tests/test_model_cache.py +88 -0
- qwenloop-0.1.0/tests/test_runner.py +173 -0
- qwenloop-0.1.0/uv.lock +736 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Installed by `vibey-gh install` — do not edit; edit the template in vibey-gh.
|
|
3
|
+
#
|
|
4
|
+
# Appends the provenance trailer to any commit message that lacks it, so the rule holds
|
|
5
|
+
# locally without anyone having to remember it. CI enforces the same trailer, so a commit
|
|
6
|
+
# made without this hook fails the pull request rather than slipping through.
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# Resolve the CLI. `vibey-gh` on PATH is the normal case, but a project virtualenv that
|
|
10
|
+
# has not been activated is just as normal — and a gate that reports "not installed"
|
|
11
|
+
# when the tool IS installed is a gate people learn to bypass. Look where it actually
|
|
12
|
+
# lives before giving up. Hooks run from the top of the working tree.
|
|
13
|
+
vibey_gh() {
|
|
14
|
+
if command -v vibey-gh >/dev/null 2>&1; then
|
|
15
|
+
vibey-gh "$@"
|
|
16
|
+
elif [ -n "${VIRTUAL_ENV:-}" ] && [ -x "${VIRTUAL_ENV}/bin/vibey-gh" ]; then
|
|
17
|
+
"${VIRTUAL_ENV}/bin/vibey-gh" "$@"
|
|
18
|
+
elif [ -x ".venv/bin/vibey-gh" ]; then
|
|
19
|
+
./.venv/bin/vibey-gh "$@"
|
|
20
|
+
elif [ -x "venv/bin/vibey-gh" ]; then
|
|
21
|
+
./venv/bin/vibey-gh "$@"
|
|
22
|
+
elif python3 -c "import vibey_gh.cli" >/dev/null 2>&1; then
|
|
23
|
+
python3 -m vibey_gh.cli "$@"
|
|
24
|
+
elif python3 -c "import vibey_bootstrap.gh.cli" >/dev/null 2>&1; then
|
|
25
|
+
python3 -m vibey_bootstrap.gh.cli "$@" # pre-split layout
|
|
26
|
+
else
|
|
27
|
+
return 127
|
|
28
|
+
fi
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
msg_file="$1"
|
|
33
|
+
key=$(vibey_gh trailer-key 2>/dev/null || echo "Made-With")
|
|
34
|
+
trailer=$(vibey_gh trailer 2>/dev/null || echo "Made-With: Vibey, the auto-vibecoding machine by Adam Matthew Steinberger")
|
|
35
|
+
|
|
36
|
+
# A pre-existing project hook runs first and may do its own thing.
|
|
37
|
+
[ -x "$(dirname "$0")/commit-msg.local" ] && "$(dirname "$0")/commit-msg.local" "$@"
|
|
38
|
+
|
|
39
|
+
# Already present in any case — nothing to do.
|
|
40
|
+
if grep -qiE "^${key}:[[:space:]]*[^[:space:]]" "$msg_file"; then
|
|
41
|
+
exit 0
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
# A comment-only or empty message means an aborted commit; leave it alone.
|
|
45
|
+
if ! grep -qvE '^\s*(#.*)?$' "$msg_file"; then
|
|
46
|
+
exit 0
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
printf '\n%s\n' "$trailer" >> "$msg_file"
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Installed by `vibey-gh install` — do not edit; edit the template in vibey-gh.
|
|
3
|
+
#
|
|
4
|
+
# THE GATE. A repository that has adopted the vibey GitHub automation must keep it
|
|
5
|
+
# installed and working. If the tooling is missing, or the fingerprints it enforces are
|
|
6
|
+
# not intact, the push is refused — to any branch, local or remote.
|
|
7
|
+
#
|
|
8
|
+
# The point is not ceremony. Provenance that can be skipped whenever it is inconvenient
|
|
9
|
+
# is provenance nobody can rely on, so the check has to sit on the last action before
|
|
10
|
+
# code leaves the machine.
|
|
11
|
+
#
|
|
12
|
+
# Escape hatch: `git push --no-verify` still works, because a hook that cannot be
|
|
13
|
+
# bypassed in an emergency gets uninstalled instead. CI applies the same rule server-side,
|
|
14
|
+
# so skipping here only defers the failure rather than avoiding it.
|
|
15
|
+
|
|
16
|
+
set -e
|
|
17
|
+
|
|
18
|
+
red() { printf '\033[0;31m%s\033[0m\n' "$1"; }
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# Resolve the CLI. `vibey-gh` on PATH is the normal case, but a project virtualenv that
|
|
22
|
+
# has not been activated is just as normal — and a gate that reports "not installed"
|
|
23
|
+
# when the tool IS installed is a gate people learn to bypass. Look where it actually
|
|
24
|
+
# lives before giving up. Hooks run from the top of the working tree.
|
|
25
|
+
vibey_gh() {
|
|
26
|
+
if command -v vibey-gh >/dev/null 2>&1; then
|
|
27
|
+
vibey-gh "$@"
|
|
28
|
+
elif [ -n "${VIRTUAL_ENV:-}" ] && [ -x "${VIRTUAL_ENV}/bin/vibey-gh" ]; then
|
|
29
|
+
"${VIRTUAL_ENV}/bin/vibey-gh" "$@"
|
|
30
|
+
elif [ -x ".venv/bin/vibey-gh" ]; then
|
|
31
|
+
./.venv/bin/vibey-gh "$@"
|
|
32
|
+
elif [ -x "venv/bin/vibey-gh" ]; then
|
|
33
|
+
./venv/bin/vibey-gh "$@"
|
|
34
|
+
elif python3 -c "import vibey_gh.cli" >/dev/null 2>&1; then
|
|
35
|
+
python3 -m vibey_gh.cli "$@"
|
|
36
|
+
elif python3 -c "import vibey_bootstrap.gh.cli" >/dev/null 2>&1; then
|
|
37
|
+
python3 -m vibey_bootstrap.gh.cli "$@" # pre-split layout
|
|
38
|
+
else
|
|
39
|
+
return 127
|
|
40
|
+
fi
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if ! vibey_gh trailer-key >/dev/null 2>&1; then
|
|
44
|
+
red "✖ push refused: the vibey GitHub automation is not installed."
|
|
45
|
+
echo
|
|
46
|
+
echo " This repository requires it for provenance and release automation."
|
|
47
|
+
echo
|
|
48
|
+
echo " pip install vibey-gh"
|
|
49
|
+
echo " vibey-gh install"
|
|
50
|
+
echo
|
|
51
|
+
echo " Then push again. To bypass once: git push --no-verify"
|
|
52
|
+
exit 1
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
if ! vibey_gh check --quiet; then
|
|
56
|
+
red "✖ push refused: the provenance fingerprints are not intact."
|
|
57
|
+
echo
|
|
58
|
+
echo " vibey-gh check # see what is missing"
|
|
59
|
+
echo " vibey-gh check --apply # add the missing file headers"
|
|
60
|
+
echo
|
|
61
|
+
echo " Commit trailers are added automatically by the commit-msg hook."
|
|
62
|
+
echo " To bypass once: git push --no-verify"
|
|
63
|
+
exit 1
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
# Chain to a pre-existing project hook, so adopting this does not discard local checks.
|
|
67
|
+
if [ -x "$(dirname "$0")/pre-push.local" ]; then
|
|
68
|
+
"$(dirname "$0")/pre-push.local" "$@"
|
|
69
|
+
fi
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
* @adammatthewsteinberger
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Report reproducible qwenloop behavior.
|
|
3
|
+
title: "bug: "
|
|
4
|
+
labels: [bug]
|
|
5
|
+
body:
|
|
6
|
+
- type: textarea
|
|
7
|
+
attributes:
|
|
8
|
+
label: What happened?
|
|
9
|
+
description: Include the command, expected result, and actual result.
|
|
10
|
+
validations:
|
|
11
|
+
required: true
|
|
12
|
+
- type: textarea
|
|
13
|
+
attributes:
|
|
14
|
+
label: Environment
|
|
15
|
+
description: OS, hardware, Python, backend, runtime version, and model profile. Never include secrets.
|
|
16
|
+
validations:
|
|
17
|
+
required: true
|
|
18
|
+
- type: textarea
|
|
19
|
+
attributes:
|
|
20
|
+
label: Reproduction
|
|
21
|
+
description: Provide the smallest safe reproduction and relevant redacted events.
|
|
22
|
+
validations:
|
|
23
|
+
required: true
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Propose a qwenloop capability or integration.
|
|
3
|
+
title: "feat: "
|
|
4
|
+
labels: [enhancement]
|
|
5
|
+
body:
|
|
6
|
+
- type: textarea
|
|
7
|
+
attributes:
|
|
8
|
+
label: Problem
|
|
9
|
+
description: What operator or agent problem should this solve?
|
|
10
|
+
validations:
|
|
11
|
+
required: true
|
|
12
|
+
- type: textarea
|
|
13
|
+
attributes:
|
|
14
|
+
label: Proposed contract
|
|
15
|
+
description: Describe CLI, persisted-state, security-policy, and compatibility implications.
|
|
16
|
+
validations:
|
|
17
|
+
required: true
|
|
18
|
+
- type: textarea
|
|
19
|
+
attributes:
|
|
20
|
+
label: Acceptance criteria
|
|
21
|
+
description: List observable, testable outcomes.
|
|
22
|
+
validations:
|
|
23
|
+
required: true
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
## Summary
|
|
2
|
+
|
|
3
|
+
<!-- What changes, and why? -->
|
|
4
|
+
|
|
5
|
+
## Verification
|
|
6
|
+
|
|
7
|
+
- [ ] Ruff and formatting pass
|
|
8
|
+
- [ ] Strict mypy passes
|
|
9
|
+
- [ ] Onion-boundary checks pass
|
|
10
|
+
- [ ] Tests retain 100% line and branch coverage
|
|
11
|
+
- [ ] No model weights, caches, credentials, or generated artifacts are committed
|
|
12
|
+
|
|
13
|
+
## Runtime impact
|
|
14
|
+
|
|
15
|
+
<!-- Note model/backend, security-policy, run-contract, or Vibey boundary changes. -->
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: pip
|
|
4
|
+
directory: /
|
|
5
|
+
schedule:
|
|
6
|
+
interval: weekly
|
|
7
|
+
groups:
|
|
8
|
+
python-dependencies:
|
|
9
|
+
patterns: ["*"]
|
|
10
|
+
- package-ecosystem: github-actions
|
|
11
|
+
directory: /
|
|
12
|
+
schedule:
|
|
13
|
+
interval: weekly
|
|
14
|
+
# vibey-gh owns the versions used by its generated workflows. Upgrade these
|
|
15
|
+
# through vibey-gh so Dependabot cannot make the canonical templates drift.
|
|
16
|
+
ignore:
|
|
17
|
+
- dependency-name: actions/checkout
|
|
18
|
+
- dependency-name: actions/setup-python
|
|
19
|
+
groups:
|
|
20
|
+
github-actions:
|
|
21
|
+
patterns: ["*"]
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Made with love by Vibey, the auto-vibecoding machine by Adam Matthew Steinberger.
|
|
2
|
+
name: CI
|
|
3
|
+
|
|
4
|
+
on:
|
|
5
|
+
push:
|
|
6
|
+
branches: [main, develop]
|
|
7
|
+
pull_request:
|
|
8
|
+
branches: [main, develop]
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
|
|
13
|
+
concurrency:
|
|
14
|
+
group: ci-${{ github.workflow }}-${{ github.ref }}
|
|
15
|
+
cancel-in-progress: true
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
quality:
|
|
19
|
+
name: Quality and architecture
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v7
|
|
23
|
+
- uses: astral-sh/setup-uv@v7
|
|
24
|
+
with:
|
|
25
|
+
enable-cache: true
|
|
26
|
+
- run: uv sync --frozen --extra dev
|
|
27
|
+
- run: uv run ruff check .
|
|
28
|
+
- run: uv run ruff format --check .
|
|
29
|
+
- run: uv run mypy --strict src/qwenloop
|
|
30
|
+
- run: uv run lint-imports
|
|
31
|
+
- run: uv run bandit -q -r src/qwenloop
|
|
32
|
+
|
|
33
|
+
test:
|
|
34
|
+
name: Tests (Python ${{ matrix.python-version }})
|
|
35
|
+
runs-on: ubuntu-latest
|
|
36
|
+
strategy:
|
|
37
|
+
fail-fast: false
|
|
38
|
+
matrix:
|
|
39
|
+
python-version: ["3.12", "3.13", "3.14"]
|
|
40
|
+
steps:
|
|
41
|
+
- uses: actions/checkout@v7
|
|
42
|
+
- uses: astral-sh/setup-uv@v7
|
|
43
|
+
with:
|
|
44
|
+
python-version: ${{ matrix.python-version }}
|
|
45
|
+
enable-cache: true
|
|
46
|
+
- run: uv sync --frozen --extra dev
|
|
47
|
+
- run: uv run pytest -q
|
|
48
|
+
|
|
49
|
+
lock:
|
|
50
|
+
name: Lockfile is current
|
|
51
|
+
runs-on: ubuntu-latest
|
|
52
|
+
steps:
|
|
53
|
+
- uses: actions/checkout@v7
|
|
54
|
+
- uses: astral-sh/setup-uv@v7
|
|
55
|
+
- run: uv lock --check
|
|
56
|
+
|
|
57
|
+
build:
|
|
58
|
+
name: Build and install distributions
|
|
59
|
+
runs-on: ubuntu-latest
|
|
60
|
+
steps:
|
|
61
|
+
- uses: actions/checkout@v7
|
|
62
|
+
- uses: astral-sh/setup-uv@v7
|
|
63
|
+
- run: uv build
|
|
64
|
+
- run: uvx twine check --strict dist/*
|
|
65
|
+
- run: uv venv /tmp/qwenloop-wheel
|
|
66
|
+
- run: uv pip install --python /tmp/qwenloop-wheel/bin/python dist/*.whl
|
|
67
|
+
- run: /tmp/qwenloop-wheel/bin/qwenloop --version
|
|
68
|
+
- run: /tmp/qwenloop-wheel/bin/qwenloop --help
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Made with love by Vibey, the auto-vibecoding machine by Adam Matthew Steinberger.
|
|
2
|
+
name: Merge train
|
|
3
|
+
|
|
4
|
+
# Weekly: merge every pull request into the integration branch that is READY.
|
|
5
|
+
#
|
|
6
|
+
# Readiness is mechanical and is decided by `vibey-gh merge-train` — not a draft, no
|
|
7
|
+
# conflicts, checks green, no changes requested — plus the trust rule: work from the owner
|
|
8
|
+
# or their own bots merges on a green build, work from anyone else additionally needs an
|
|
9
|
+
# approving review. The logic lives in the library, where it is unit-tested, rather than
|
|
10
|
+
# in this file where it would not be.
|
|
11
|
+
#
|
|
12
|
+
# A pull request held ONLY on that approval is labelled `needs-human-review` and the owner
|
|
13
|
+
# is mentioned on it, once — because otherwise the contribution just sits there and nobody
|
|
14
|
+
# finds out. Repeating the mention weekly would train the owner to ignore it, so an
|
|
15
|
+
# existing notification is detected before another is posted. A draft or a red build gets
|
|
16
|
+
# neither: that is the contributor's to fix, and paging anyone about it is noise.
|
|
17
|
+
#
|
|
18
|
+
# The run also writes a markdown table to the job summary, so a week that merged nothing
|
|
19
|
+
# still says what it looked at.
|
|
20
|
+
#
|
|
21
|
+
# PERMISSIONS. A branch ruleset that requires an approving review cannot be satisfied by
|
|
22
|
+
# the default GITHUB_TOKEN, and GitHub Actions is usually not a bypass actor. Supply a
|
|
23
|
+
# repository secret `AUTOMERGE_TOKEN` belonging to someone with the admin role. Without
|
|
24
|
+
# one this job reports every pull request as blocked rather than merging anything.
|
|
25
|
+
#
|
|
26
|
+
# Use a real token rather than adding GitHub Actions to the bypass list: a push made with
|
|
27
|
+
# GITHUB_TOKEN does not trigger further workflows, so a release chain downstream of this
|
|
28
|
+
# would silently stop.
|
|
29
|
+
|
|
30
|
+
on:
|
|
31
|
+
schedule:
|
|
32
|
+
- cron: "17 7 * * 1"
|
|
33
|
+
workflow_dispatch:
|
|
34
|
+
inputs:
|
|
35
|
+
dry_run:
|
|
36
|
+
description: "Report what would be merged without merging it"
|
|
37
|
+
required: false
|
|
38
|
+
default: false
|
|
39
|
+
type: boolean
|
|
40
|
+
|
|
41
|
+
permissions:
|
|
42
|
+
contents: write
|
|
43
|
+
pull-requests: write
|
|
44
|
+
|
|
45
|
+
concurrency:
|
|
46
|
+
group: merge-train
|
|
47
|
+
cancel-in-progress: false
|
|
48
|
+
|
|
49
|
+
jobs:
|
|
50
|
+
merge:
|
|
51
|
+
name: Merge train
|
|
52
|
+
runs-on: ubuntu-latest
|
|
53
|
+
steps:
|
|
54
|
+
- uses: actions/checkout@v4
|
|
55
|
+
|
|
56
|
+
- name: Set up Python
|
|
57
|
+
uses: actions/setup-python@v5
|
|
58
|
+
with:
|
|
59
|
+
python-version: "3.12"
|
|
60
|
+
|
|
61
|
+
- name: Install the tooling
|
|
62
|
+
run: |
|
|
63
|
+
set -euo pipefail
|
|
64
|
+
if grep -qE '^name = "vibey-(gh|bootstrap)"' pyproject.toml 2>/dev/null; then
|
|
65
|
+
python -m pip install --quiet -e .
|
|
66
|
+
else
|
|
67
|
+
python -m pip install --quiet vibey-gh
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
- name: Merge what is ready
|
|
71
|
+
env:
|
|
72
|
+
GH_TOKEN: ${{ secrets.AUTOMERGE_TOKEN || github.token }}
|
|
73
|
+
run: |
|
|
74
|
+
set -euo pipefail
|
|
75
|
+
# No `tee` into the job summary: the command writes its own markdown table
|
|
76
|
+
# there. Piping stdout in as well would append the plain log lines too, which
|
|
77
|
+
# are not markdown and render as one run-on paragraph above the table.
|
|
78
|
+
vibey-gh merge-train ${{ inputs.dry_run && '--dry-run' || '' }}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Made with love by Vibey, the auto-vibecoding machine by Adam Matthew Steinberger.
|
|
2
|
+
name: Promote
|
|
3
|
+
|
|
4
|
+
# The other half of the flow. The merge train fills the integration branch; this moves it
|
|
5
|
+
# to the release branch, which is what publishes.
|
|
6
|
+
#
|
|
7
|
+
# It follows the merge train's SUCCESS rather than a clock, so a week's work is promoted
|
|
8
|
+
# as soon as it is all in. The cron is a backstop for the weeks the train has nothing to
|
|
9
|
+
# merge and so never completes, and for anything that arrives by another route.
|
|
10
|
+
#
|
|
11
|
+
# The decisions live in `vibey-gh promote`, where they are unit-tested: compare the
|
|
12
|
+
# branches by CONTENT rather than commit count, derive the version before opening
|
|
13
|
+
# anything, wait for the checks, then merge. A hand-written version of this workflow gets
|
|
14
|
+
# at least one of those wrong.
|
|
15
|
+
#
|
|
16
|
+
# PERMISSIONS. A ruleset requiring an approving review cannot be satisfied by the default
|
|
17
|
+
# GITHUB_TOKEN. Supply `AUTOMERGE_TOKEN` (a token belonging to someone with the admin
|
|
18
|
+
# role) or the job will open the pull request and report that it could not merge it —
|
|
19
|
+
# which is a safe place to stop.
|
|
20
|
+
|
|
21
|
+
on:
|
|
22
|
+
workflow_run:
|
|
23
|
+
workflows: ["Merge train"]
|
|
24
|
+
types: [completed]
|
|
25
|
+
schedule:
|
|
26
|
+
- cron: "17 8 * * 1"
|
|
27
|
+
workflow_dispatch:
|
|
28
|
+
inputs:
|
|
29
|
+
dry_run:
|
|
30
|
+
description: "Report what would be promoted without opening or merging anything"
|
|
31
|
+
required: false
|
|
32
|
+
default: false
|
|
33
|
+
type: boolean
|
|
34
|
+
|
|
35
|
+
permissions:
|
|
36
|
+
contents: write
|
|
37
|
+
pull-requests: write
|
|
38
|
+
|
|
39
|
+
concurrency:
|
|
40
|
+
group: promote
|
|
41
|
+
cancel-in-progress: false
|
|
42
|
+
|
|
43
|
+
jobs:
|
|
44
|
+
promote:
|
|
45
|
+
name: Promote
|
|
46
|
+
# A merge train that failed leaves the integration branch in an unknown state.
|
|
47
|
+
if: github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success'
|
|
48
|
+
runs-on: ubuntu-latest
|
|
49
|
+
steps:
|
|
50
|
+
- uses: actions/checkout@v4
|
|
51
|
+
with:
|
|
52
|
+
fetch-depth: 0
|
|
53
|
+
# checkout's extraheader beats a remote URL, so the push of the version bump
|
|
54
|
+
# needs the token HERE or it authenticates as the default bot and is refused.
|
|
55
|
+
token: ${{ secrets.AUTOMERGE_TOKEN || github.token }}
|
|
56
|
+
|
|
57
|
+
- name: Set up Python
|
|
58
|
+
uses: actions/setup-python@v5
|
|
59
|
+
with:
|
|
60
|
+
python-version: "3.12"
|
|
61
|
+
|
|
62
|
+
- name: Install the tooling
|
|
63
|
+
run: |
|
|
64
|
+
set -euo pipefail
|
|
65
|
+
if grep -qE '^name = "vibey-(gh|bootstrap)"' pyproject.toml 2>/dev/null; then
|
|
66
|
+
python -m pip install --quiet -e .
|
|
67
|
+
else
|
|
68
|
+
python -m pip install --quiet vibey-gh
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
- name: Promote
|
|
72
|
+
env:
|
|
73
|
+
GH_TOKEN: ${{ secrets.AUTOMERGE_TOKEN || github.token }}
|
|
74
|
+
run: |
|
|
75
|
+
set -euo pipefail
|
|
76
|
+
git config user.name "vibey[bot]"
|
|
77
|
+
git config user.email "adam@matthewsteinberger.com"
|
|
78
|
+
vibey-gh promote ${{ inputs.dry_run && '--dry-run' || '' }}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Made with love by Vibey, the auto-vibecoding machine by Adam Matthew Steinberger.
|
|
2
|
+
name: Provenance
|
|
3
|
+
|
|
4
|
+
# Server-side half of the provenance rule. The pre-push hook is the fast, local half, but
|
|
5
|
+
# a hook lives in a clone: it can be skipped with --no-verify, and a fresh clone that
|
|
6
|
+
# never ran `vibey-gh install` has no hook at all. This job is what makes the rule hold
|
|
7
|
+
# for everyone, so make it a REQUIRED status check on every protected branch.
|
|
8
|
+
#
|
|
9
|
+
# It runs on every branch, not just pull requests, so an unfingerprinted commit is caught
|
|
10
|
+
# where it is pushed rather than at merge time.
|
|
11
|
+
#
|
|
12
|
+
# The job name below — "Provenance" — is the context you add to the branch ruleset.
|
|
13
|
+
|
|
14
|
+
on:
|
|
15
|
+
push:
|
|
16
|
+
branches: ["**"]
|
|
17
|
+
pull_request:
|
|
18
|
+
|
|
19
|
+
permissions:
|
|
20
|
+
contents: read
|
|
21
|
+
|
|
22
|
+
concurrency:
|
|
23
|
+
group: provenance-${{ github.ref }}
|
|
24
|
+
cancel-in-progress: true
|
|
25
|
+
|
|
26
|
+
jobs:
|
|
27
|
+
provenance:
|
|
28
|
+
name: Provenance
|
|
29
|
+
runs-on: ubuntu-latest
|
|
30
|
+
steps:
|
|
31
|
+
- uses: actions/checkout@v4
|
|
32
|
+
with:
|
|
33
|
+
# Needed to walk the commits a pull request adds.
|
|
34
|
+
fetch-depth: 0
|
|
35
|
+
|
|
36
|
+
- name: Set up Python
|
|
37
|
+
uses: actions/setup-python@v5
|
|
38
|
+
with:
|
|
39
|
+
python-version: "3.12"
|
|
40
|
+
|
|
41
|
+
# A repository that IS the tooling installs itself; everyone else takes the
|
|
42
|
+
# published package. Self-describing, so the same template works in both places.
|
|
43
|
+
- name: Install the tooling
|
|
44
|
+
run: |
|
|
45
|
+
set -euo pipefail
|
|
46
|
+
if grep -qE '^name = "vibey-(gh|bootstrap)"' pyproject.toml 2>/dev/null; then
|
|
47
|
+
echo "this repository provides the tooling — installing from source"
|
|
48
|
+
python -m pip install --quiet -e .
|
|
49
|
+
else
|
|
50
|
+
python -m pip install --quiet vibey-gh
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
# --ci skips the core.hooksPath assertion, which is per-clone local git config that
|
|
54
|
+
# no runner can satisfy. The hook FILES are repository state and are still checked.
|
|
55
|
+
# The base SHA goes through env: rather than into the shell, so there is no
|
|
56
|
+
# injection surface even though it comes from github.event.
|
|
57
|
+
- name: Check provenance
|
|
58
|
+
env:
|
|
59
|
+
BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
|
60
|
+
run: |
|
|
61
|
+
set -euo pipefail
|
|
62
|
+
if [ -n "${BASE_SHA:-}" ]; then
|
|
63
|
+
git fetch --quiet --depth=50 origin "${BASE_SHA}" 2>/dev/null || true
|
|
64
|
+
vibey-gh check --ci --commits "${BASE_SHA}..HEAD"
|
|
65
|
+
else
|
|
66
|
+
vibey-gh check --ci
|
|
67
|
+
fi
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Made with love by Vibey, the auto-vibecoding machine by Adam Matthew Steinberger.
|
|
2
|
+
name: Release
|
|
3
|
+
|
|
4
|
+
on:
|
|
5
|
+
push:
|
|
6
|
+
branches: [main, develop]
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
build:
|
|
13
|
+
name: Build distributions
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
outputs:
|
|
16
|
+
version: ${{ steps.version.outputs.version }}
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v7
|
|
19
|
+
- uses: astral-sh/setup-uv@v7
|
|
20
|
+
- name: Stamp development version
|
|
21
|
+
if: github.ref == 'refs/heads/develop'
|
|
22
|
+
run: |
|
|
23
|
+
uvx vibey-gh version --dev "${GITHUB_RUN_NUMBER}" --apply
|
|
24
|
+
- id: version
|
|
25
|
+
run: |
|
|
26
|
+
python - <<'PY' >> "$GITHUB_OUTPUT"
|
|
27
|
+
import pathlib
|
|
28
|
+
import tomllib
|
|
29
|
+
data = tomllib.loads(pathlib.Path("pyproject.toml").read_text())
|
|
30
|
+
print("version=" + data["project"]["version"])
|
|
31
|
+
PY
|
|
32
|
+
- run: uv build
|
|
33
|
+
- uses: actions/upload-artifact@v7
|
|
34
|
+
with:
|
|
35
|
+
name: dist
|
|
36
|
+
path: dist/
|
|
37
|
+
|
|
38
|
+
testpypi:
|
|
39
|
+
name: Publish to TestPyPI
|
|
40
|
+
if: github.ref == 'refs/heads/develop'
|
|
41
|
+
needs: build
|
|
42
|
+
runs-on: ubuntu-latest
|
|
43
|
+
environment: testpypi
|
|
44
|
+
permissions:
|
|
45
|
+
id-token: write
|
|
46
|
+
steps:
|
|
47
|
+
- uses: actions/download-artifact@v8
|
|
48
|
+
with: {name: dist, path: dist}
|
|
49
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
50
|
+
with:
|
|
51
|
+
repository-url: https://test.pypi.org/legacy/
|
|
52
|
+
skip-existing: true
|
|
53
|
+
|
|
54
|
+
verify-testpypi:
|
|
55
|
+
name: Verify TestPyPI artifact
|
|
56
|
+
needs: [build, testpypi]
|
|
57
|
+
runs-on: ubuntu-latest
|
|
58
|
+
steps:
|
|
59
|
+
- uses: astral-sh/setup-uv@v7
|
|
60
|
+
- name: Install exact TestPyPI version
|
|
61
|
+
env:
|
|
62
|
+
VERSION: ${{ needs.build.outputs.version }}
|
|
63
|
+
run: |
|
|
64
|
+
for attempt in $(seq 1 20); do
|
|
65
|
+
if uv tool install --refresh \
|
|
66
|
+
--index https://test.pypi.org/simple/ \
|
|
67
|
+
--index https://pypi.org/simple/ \
|
|
68
|
+
"qwenloop==${VERSION}"; then
|
|
69
|
+
break
|
|
70
|
+
fi
|
|
71
|
+
sleep 30
|
|
72
|
+
done
|
|
73
|
+
qwenloop --version
|
|
74
|
+
qwenloop --help
|
|
75
|
+
|
|
76
|
+
pypi:
|
|
77
|
+
name: Publish to PyPI
|
|
78
|
+
if: github.ref == 'refs/heads/main'
|
|
79
|
+
needs: build
|
|
80
|
+
runs-on: ubuntu-latest
|
|
81
|
+
environment: pypi
|
|
82
|
+
permissions:
|
|
83
|
+
id-token: write
|
|
84
|
+
steps:
|
|
85
|
+
- uses: actions/download-artifact@v8
|
|
86
|
+
with: {name: dist, path: dist}
|
|
87
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
88
|
+
with:
|
|
89
|
+
skip-existing: true
|
|
90
|
+
|
|
91
|
+
verify-pypi:
|
|
92
|
+
name: Verify PyPI artifact
|
|
93
|
+
needs: [build, pypi]
|
|
94
|
+
runs-on: ubuntu-latest
|
|
95
|
+
steps:
|
|
96
|
+
- uses: astral-sh/setup-uv@v7
|
|
97
|
+
- name: Install exact PyPI version
|
|
98
|
+
env:
|
|
99
|
+
VERSION: ${{ needs.build.outputs.version }}
|
|
100
|
+
run: |
|
|
101
|
+
for attempt in $(seq 1 20); do
|
|
102
|
+
if uv tool install --refresh \
|
|
103
|
+
--index https://pypi.org/simple/ \
|
|
104
|
+
"qwenloop==${VERSION}"; then
|
|
105
|
+
break
|
|
106
|
+
fi
|
|
107
|
+
sleep 30
|
|
108
|
+
done
|
|
109
|
+
qwenloop --version
|
|
110
|
+
qwenloop --help
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# vibey-gh owns provenance and release automation for this repository.
|
|
2
|
+
|
|
3
|
+
[fingerprint]
|
|
4
|
+
sources = [
|
|
5
|
+
"src/**/*.py",
|
|
6
|
+
"tests/**/*.py",
|
|
7
|
+
"scripts/**/*.py",
|
|
8
|
+
".github/workflows/*.yml",
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
[version]
|
|
12
|
+
files = ["pyproject.toml", "src/qwenloop/__init__.py"]
|
|
13
|
+
content_paths = ["src/qwenloop/"]
|
|
14
|
+
code_paths = ["src/qwenloop/"]
|
|
15
|
+
|
|
16
|
+
[branches]
|
|
17
|
+
integration = "develop"
|
|
18
|
+
release = "main"
|
|
19
|
+
|
|
20
|
+
[merge_train]
|
|
21
|
+
owner = "adammatthewsteinberger"
|
|
22
|
+
trusted_authors = ["adammatthewsteinberger", "claude[bot]", "github-actions[bot]", "vibey[bot]"]
|
qwenloop-0.1.0/AGENTS.md
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Code of conduct
|
|
2
|
+
|
|
3
|
+
Be respectful, constructive, and specific. Harassment, discrimination,
|
|
4
|
+
threats, and disclosure of another person's private information are not
|
|
5
|
+
accepted in this project.
|
|
6
|
+
|
|
7
|
+
Report conduct concerns privately to the repository owner. Reports will be
|
|
8
|
+
reviewed promptly and handled as confidentially as practical.
|