gammonview-helper 0.1.1__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.
- gammonview_helper-0.1.1/.github/workflows/ci.yml +99 -0
- gammonview_helper-0.1.1/.github/workflows/publish.yml +182 -0
- gammonview_helper-0.1.1/.gitignore +21 -0
- gammonview_helper-0.1.1/.python-version +1 -0
- gammonview_helper-0.1.1/LICENSE +21 -0
- gammonview_helper-0.1.1/PKG-INFO +197 -0
- gammonview_helper-0.1.1/README.md +168 -0
- gammonview_helper-0.1.1/deploy/com.gammonview.helper.plist +88 -0
- gammonview_helper-0.1.1/deploy/install-login-item.sh +95 -0
- gammonview_helper-0.1.1/docs/Relay.md +103 -0
- gammonview_helper-0.1.1/gvhelper/__init__.py +42 -0
- gammonview_helper-0.1.1/gvhelper/__main__.py +14 -0
- gammonview_helper-0.1.1/gvhelper/cli.py +291 -0
- gammonview_helper-0.1.1/gvhelper/client.py +319 -0
- gammonview_helper-0.1.1/gvhelper/config.py +261 -0
- gammonview_helper-0.1.1/gvhelper/daemon.py +250 -0
- gammonview_helper-0.1.1/gvhelper/runner.py +207 -0
- gammonview_helper-0.1.1/gvhelper/store.py +164 -0
- gammonview_helper-0.1.1/pyproject.toml +93 -0
- gammonview_helper-0.1.1/tests/conftest.py +46 -0
- gammonview_helper-0.1.1/tests/golden/B4_SrGcsKAQmoTyHlgJCbM.fast.gvab +0 -0
- gammonview_helper-0.1.1/tests/test_cli.py +194 -0
- gammonview_helper-0.1.1/tests/test_client.py +262 -0
- gammonview_helper-0.1.1/tests/test_config.py +137 -0
- gammonview_helper-0.1.1/tests/test_contract.py +119 -0
- gammonview_helper-0.1.1/tests/test_daemon.py +242 -0
- gammonview_helper-0.1.1/tests/test_runner.py +113 -0
- gammonview_helper-0.1.1/tests/test_store.py +156 -0
- gammonview_helper-0.1.1/uv.lock +843 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# The helper's suite, on every push and pull request.
|
|
2
|
+
#
|
|
3
|
+
# This package runs on other people's computers, which is what the matrix is
|
|
4
|
+
# shaped around: the platforms, not the Python versions. What breaks here is a
|
|
5
|
+
# credential store that is not a Keychain and an `os.nice` that does not exist
|
|
6
|
+
# on Windows -- neither of which a second interpreter on Linux would ever find.
|
|
7
|
+
name: CI
|
|
8
|
+
|
|
9
|
+
on:
|
|
10
|
+
push:
|
|
11
|
+
branches: [main]
|
|
12
|
+
pull_request:
|
|
13
|
+
workflow_dispatch:
|
|
14
|
+
|
|
15
|
+
permissions:
|
|
16
|
+
contents: read
|
|
17
|
+
|
|
18
|
+
# A newer push to the same ref makes the older run's verdict worthless.
|
|
19
|
+
concurrency:
|
|
20
|
+
group: ci-${{ github.ref }}
|
|
21
|
+
cancel-in-progress: true
|
|
22
|
+
|
|
23
|
+
jobs:
|
|
24
|
+
tests:
|
|
25
|
+
name: ${{ matrix.os }} / py${{ matrix.python }}
|
|
26
|
+
runs-on: ${{ matrix.os }}
|
|
27
|
+
strategy:
|
|
28
|
+
# One red row must not hide the others: the usual reason to read this
|
|
29
|
+
# matrix is to find out *which* platform broke.
|
|
30
|
+
fail-fast: false
|
|
31
|
+
matrix:
|
|
32
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
33
|
+
python: ["3.13"]
|
|
34
|
+
include:
|
|
35
|
+
# The floor and the ceiling of the supported range, on the cheap
|
|
36
|
+
# runner. `keyring` and `httpx` are where a version difference would
|
|
37
|
+
# actually show up; the middle versions are not worth three minutes.
|
|
38
|
+
- os: ubuntu-latest
|
|
39
|
+
python: "3.10"
|
|
40
|
+
- os: ubuntu-latest
|
|
41
|
+
python: "3.14"
|
|
42
|
+
steps:
|
|
43
|
+
- uses: actions/checkout@v4
|
|
44
|
+
|
|
45
|
+
- uses: astral-sh/setup-uv@v6
|
|
46
|
+
with:
|
|
47
|
+
enable-cache: true
|
|
48
|
+
|
|
49
|
+
# Two markers deselected, for different reasons.
|
|
50
|
+
#
|
|
51
|
+
# `slow` runs a real analysis: it needs a minute of CPU and proves the
|
|
52
|
+
# engine works, which is bgsage's suite's job rather than this one's.
|
|
53
|
+
#
|
|
54
|
+
# `contract` talks to a live relay. The server half of that protocol is
|
|
55
|
+
# in a private repository, so there is nothing a public workflow could
|
|
56
|
+
# stand up, and pointing this at beta would make every push a request to
|
|
57
|
+
# a running service. `docs/Relay.md` says when to run it by hand.
|
|
58
|
+
- name: helper suite
|
|
59
|
+
run: uv run --python ${{ matrix.python }} pytest -q -m "not slow and not contract"
|
|
60
|
+
|
|
61
|
+
build:
|
|
62
|
+
name: build (sdist + wheel)
|
|
63
|
+
runs-on: ubuntu-latest
|
|
64
|
+
steps:
|
|
65
|
+
- uses: actions/checkout@v4
|
|
66
|
+
with:
|
|
67
|
+
# hatch-vcs derives the version from git tags, and a shallow clone has
|
|
68
|
+
# none. It does not fail -- it quietly stamps 0.1.dev1+g<sha> on the
|
|
69
|
+
# artifacts, which is the kind of thing you discover on PyPI.
|
|
70
|
+
fetch-depth: 0
|
|
71
|
+
|
|
72
|
+
- uses: astral-sh/setup-uv@v6
|
|
73
|
+
with:
|
|
74
|
+
enable-cache: true
|
|
75
|
+
|
|
76
|
+
- run: uv build
|
|
77
|
+
|
|
78
|
+
- name: report the derived version
|
|
79
|
+
run: ls -l dist/
|
|
80
|
+
|
|
81
|
+
# The wheel's real test is that the console script it installs actually
|
|
82
|
+
# runs. It is the first thing a user types after `uv tool install`, and an
|
|
83
|
+
# entry point naming a module that moved fails right there -- with a
|
|
84
|
+
# traceback, on their machine, before they have any reason to trust this.
|
|
85
|
+
#
|
|
86
|
+
# `--version` rather than `status`: it exits 0 with no credentials (status
|
|
87
|
+
# exits 1, correctly, because an unlinked helper is not a working one) and
|
|
88
|
+
# it reads the version back out of the *installed metadata*, so it fails
|
|
89
|
+
# if hatch-vcs stamped nothing. Resolving the dependencies at all is the
|
|
90
|
+
# other half of the check -- this is the only place `gammonview[engine]`
|
|
91
|
+
# is installed from PyPI the way a user gets it.
|
|
92
|
+
#
|
|
93
|
+
# From outside the checkout on purpose: with the repo as cwd, `gvhelper`
|
|
94
|
+
# is importable from the source tree and the wheel is never involved.
|
|
95
|
+
- name: the wheel's entry point runs
|
|
96
|
+
working-directory: ${{ runner.temp }}
|
|
97
|
+
run: |
|
|
98
|
+
uv run --isolated --no-project --with "$GITHUB_WORKSPACE"/dist/*.whl \
|
|
99
|
+
gammonview-helper --version
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# Publish to PyPI via trusted publishing (OIDC). No API token exists anywhere:
|
|
2
|
+
# PyPI is configured to trust *this workflow in this repository*, and mints a
|
|
3
|
+
# short-lived credential for the job at run time. Nothing to store, leak, or
|
|
4
|
+
# rotate, and a stolen repo secret cannot publish because there is no secret.
|
|
5
|
+
#
|
|
6
|
+
# This is the reason the helper is a public repository on GitHub at all. It is
|
|
7
|
+
# installed by strangers with `uv tool install gammonview-helper`, so PyPI is
|
|
8
|
+
# not optional -- and the alternative to OIDC is a long-lived upload token with
|
|
9
|
+
# write access to the namespace, sitting on a laptop.
|
|
10
|
+
#
|
|
11
|
+
# One-time setup on PyPI (https://pypi.org/manage/account/publishing/), which
|
|
12
|
+
# must be done before the first run, because the project does not exist yet:
|
|
13
|
+
#
|
|
14
|
+
# PyPI project name : gammonview-helper
|
|
15
|
+
# Owner : ngvlamis
|
|
16
|
+
# Repository name : gammonview-helper
|
|
17
|
+
# Workflow name : publish.yml
|
|
18
|
+
# Environment name : pypi
|
|
19
|
+
#
|
|
20
|
+
# That registers a "pending publisher"; the project is created by the first
|
|
21
|
+
# successful upload.
|
|
22
|
+
name: publish
|
|
23
|
+
|
|
24
|
+
on:
|
|
25
|
+
# A tag is the release signal, matching how the version is derived: hatch-vcs
|
|
26
|
+
# reads it from git, so the tag *is* the version. Pushing v0.2.0 publishes
|
|
27
|
+
# 0.2.0 -- there is no number to bump anywhere else, and no way for the tag
|
|
28
|
+
# and the artifact to disagree.
|
|
29
|
+
#
|
|
30
|
+
# These tags are this repository's own. The helper used to share the analysis
|
|
31
|
+
# monorepo's tags, which meant a codec release renumbered a helper nobody had
|
|
32
|
+
# touched; `pyproject.toml` records why that was the wrong coupling.
|
|
33
|
+
push:
|
|
34
|
+
tags: ["v*"]
|
|
35
|
+
# Manual trigger, to retry a failed upload against a tag that already exists.
|
|
36
|
+
workflow_dispatch:
|
|
37
|
+
|
|
38
|
+
permissions:
|
|
39
|
+
contents: read
|
|
40
|
+
|
|
41
|
+
jobs:
|
|
42
|
+
# The suite is a gate on the release, not merely a thing that also runs.
|
|
43
|
+
# Publishing is irreversible -- a version number on PyPI cannot be reused
|
|
44
|
+
# even after a yank -- and this package's failures land on other people's
|
|
45
|
+
# computers, where nobody can roll them back for them.
|
|
46
|
+
test:
|
|
47
|
+
name: ${{ matrix.os }}
|
|
48
|
+
runs-on: ${{ matrix.os }}
|
|
49
|
+
strategy:
|
|
50
|
+
fail-fast: false
|
|
51
|
+
matrix:
|
|
52
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
53
|
+
steps:
|
|
54
|
+
- uses: actions/checkout@v4
|
|
55
|
+
|
|
56
|
+
- uses: astral-sh/setup-uv@v6
|
|
57
|
+
with:
|
|
58
|
+
enable-cache: true
|
|
59
|
+
|
|
60
|
+
- run: uv run pytest -q -m "not slow and not contract"
|
|
61
|
+
|
|
62
|
+
build:
|
|
63
|
+
name: build sdist + wheel
|
|
64
|
+
needs: test
|
|
65
|
+
runs-on: ubuntu-latest
|
|
66
|
+
steps:
|
|
67
|
+
- uses: actions/checkout@v4
|
|
68
|
+
with:
|
|
69
|
+
# hatch-vcs derives the version from git tags, and a shallow clone has
|
|
70
|
+
# none. It does not fail -- it quietly stamps 0.1.dev1+g<sha> on the
|
|
71
|
+
# artifacts, which is the sort of thing you discover on PyPI.
|
|
72
|
+
fetch-depth: 0
|
|
73
|
+
|
|
74
|
+
- uses: astral-sh/setup-uv@v6
|
|
75
|
+
with:
|
|
76
|
+
enable-cache: true
|
|
77
|
+
|
|
78
|
+
- run: uv build
|
|
79
|
+
|
|
80
|
+
# Refuse to publish a version that git did not name. Without this, a run
|
|
81
|
+
# from an untagged commit uploads a dev version to PyPI, where it cannot
|
|
82
|
+
# be taken back.
|
|
83
|
+
- name: the artifacts carry a real release version
|
|
84
|
+
run: |
|
|
85
|
+
ls -l dist/
|
|
86
|
+
version=$(ls dist/*.whl | sed -E 's|.*/gammonview_helper-([^-]+)-py3.*|\1|')
|
|
87
|
+
echo "derived version: $version"
|
|
88
|
+
case "$version" in
|
|
89
|
+
*dev*|*+*)
|
|
90
|
+
echo "::error::refusing to publish $version -- hatch-vcs found no tag on this commit"
|
|
91
|
+
exit 1 ;;
|
|
92
|
+
esac
|
|
93
|
+
|
|
94
|
+
- name: metadata renders on PyPI
|
|
95
|
+
run: uv run --isolated --no-project --with twine python -m twine check dist/*
|
|
96
|
+
|
|
97
|
+
- uses: actions/upload-artifact@v4
|
|
98
|
+
with:
|
|
99
|
+
name: dist
|
|
100
|
+
path: dist/
|
|
101
|
+
|
|
102
|
+
pypi:
|
|
103
|
+
name: upload to PyPI
|
|
104
|
+
needs: build
|
|
105
|
+
runs-on: ubuntu-latest
|
|
106
|
+
# The environment is the approval gate: GitHub can require a manual review
|
|
107
|
+
# before the job runs, and PyPI's trusted publisher is bound to this name,
|
|
108
|
+
# so a workflow that does not declare it cannot publish.
|
|
109
|
+
environment:
|
|
110
|
+
name: pypi
|
|
111
|
+
url: https://pypi.org/p/gammonview-helper
|
|
112
|
+
permissions:
|
|
113
|
+
# The OIDC token this mints is what PyPI trades for an upload credential.
|
|
114
|
+
# Without it the action fails with a confusing 403.
|
|
115
|
+
id-token: write
|
|
116
|
+
steps:
|
|
117
|
+
- uses: actions/download-artifact@v4
|
|
118
|
+
with:
|
|
119
|
+
name: dist
|
|
120
|
+
path: dist/
|
|
121
|
+
|
|
122
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
123
|
+
|
|
124
|
+
# ---------------------------------------------------------------------------
|
|
125
|
+
# The same wheel, attached to the GitHub Release.
|
|
126
|
+
# ---------------------------------------------------------------------------
|
|
127
|
+
# `uv tool install <url-to-wheel>` is a complete install path that needs no
|
|
128
|
+
# index at all, which is what makes shipping ahead of PyPI possible. It is
|
|
129
|
+
# deliberately the *wheel* and not `git+https://…`: a git install makes every
|
|
130
|
+
# user's machine clone the repo and run the build backend, so it needs `git`
|
|
131
|
+
# present (a fresh Mac prompts for the Xcode tools) and it needs hatch-vcs to
|
|
132
|
+
# find a tag in whatever clone uv made -- the exact failure `fetch-depth: 0`
|
|
133
|
+
# above exists to prevent, reproduced on a stranger's laptop where nothing
|
|
134
|
+
# checks it. The artifact is pure Python, so one file covers every platform;
|
|
135
|
+
# `bgsage`'s per-platform wheels still come from PyPI either way.
|
|
136
|
+
#
|
|
137
|
+
# It is also the artifact the launcher installs (docs/DesktopHelper.md, step
|
|
138
|
+
# 7), which "asks the server which version to install rather than taking
|
|
139
|
+
# whatever is newest" -- a version string and a predictable asset name is all
|
|
140
|
+
# that takes.
|
|
141
|
+
#
|
|
142
|
+
# `needs: build`, NOT `needs: pypi`, and that ordering is the point: a PyPI
|
|
143
|
+
# upload that fails for reasons of its own must not withhold an install path
|
|
144
|
+
# that does not depend on it, and deleting the `pypi` job later must leave
|
|
145
|
+
# this one working unchanged.
|
|
146
|
+
release:
|
|
147
|
+
name: attach to the GitHub Release
|
|
148
|
+
needs: build
|
|
149
|
+
runs-on: ubuntu-latest
|
|
150
|
+
# A dispatch run has no tag to attach to. The tag is the release signal
|
|
151
|
+
# everywhere else in this file; here it is also the destination.
|
|
152
|
+
if: startsWith(github.ref, 'refs/tags/')
|
|
153
|
+
permissions:
|
|
154
|
+
# Overrides the read-only default at the top of the file. Scoped to this
|
|
155
|
+
# job so the test and build jobs stay unable to write to the repository.
|
|
156
|
+
contents: write
|
|
157
|
+
steps:
|
|
158
|
+
- uses: actions/download-artifact@v4
|
|
159
|
+
with:
|
|
160
|
+
name: dist
|
|
161
|
+
path: dist/
|
|
162
|
+
|
|
163
|
+
# `gh` is preinstalled on the runner. Used in preference to a third-party
|
|
164
|
+
# release action because this is a supply-chain path: the fewer things
|
|
165
|
+
# that get to touch the artifact between `uv build` and the user, the
|
|
166
|
+
# better, and that argument is the same one that put trusted publishing
|
|
167
|
+
# above an upload token.
|
|
168
|
+
#
|
|
169
|
+
# Written to be re-runnable. `workflow_dispatch` exists to retry a tag
|
|
170
|
+
# that already exists, and by then the Release usually does too.
|
|
171
|
+
- name: upload
|
|
172
|
+
env:
|
|
173
|
+
GH_TOKEN: ${{ github.token }}
|
|
174
|
+
TAG: ${{ github.ref_name }}
|
|
175
|
+
run: |
|
|
176
|
+
if gh release view "$TAG" >/dev/null 2>&1; then
|
|
177
|
+
gh release upload "$TAG" dist/* --clobber
|
|
178
|
+
else
|
|
179
|
+
gh release create "$TAG" dist/* \
|
|
180
|
+
--title "$TAG" \
|
|
181
|
+
--generate-notes
|
|
182
|
+
fi
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Python-generated files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[oc]
|
|
4
|
+
build/
|
|
5
|
+
dist/
|
|
6
|
+
wheels/
|
|
7
|
+
*.egg-info
|
|
8
|
+
|
|
9
|
+
.pytest_cache/
|
|
10
|
+
|
|
11
|
+
# Virtual environments
|
|
12
|
+
.venv
|
|
13
|
+
|
|
14
|
+
# Agent instruction data -- covered by a global gitignore on the author's
|
|
15
|
+
# machine, which a public clone obviously cannot rely on.
|
|
16
|
+
.claude/
|
|
17
|
+
|
|
18
|
+
# The helper's own state, if anyone points GAMMONVIEW_CONFIG_DIR in here while
|
|
19
|
+
# poking at it. It holds a worker token.
|
|
20
|
+
config.json
|
|
21
|
+
token
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.13
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nicholas Vlamis
|
|
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.
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: gammonview-helper
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Analyze GammonView matches on your own computer.
|
|
5
|
+
Project-URL: Homepage, https://gammonview.com
|
|
6
|
+
Project-URL: Repository, https://github.com/ngvlamis/gammonview-helper
|
|
7
|
+
Project-URL: Issues, https://github.com/ngvlamis/gammonview-helper/issues
|
|
8
|
+
Author: Nicholas Vlamis
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: analysis,backgammon,bgsage,gammonview
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
15
|
+
Classifier: Operating System :: MacOS
|
|
16
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
17
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
23
|
+
Classifier: Topic :: Games/Entertainment :: Board Games
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Requires-Dist: gammonview[engine]>=1.0.0
|
|
26
|
+
Requires-Dist: httpx>=0.27
|
|
27
|
+
Requires-Dist: keyring>=25.0
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
# gammonview-helper
|
|
31
|
+
|
|
32
|
+
Analyze your backgammon matches on your own computer, and see the results on
|
|
33
|
+
[gammonview.com](https://gammonview.com).
|
|
34
|
+
|
|
35
|
+
GammonView analyses matches on a shared server. That server is shared, so the
|
|
36
|
+
deepest settings are not on its menu — a *World Class* run that takes a minute
|
|
37
|
+
on your laptop would take an hour of a queue everybody else is waiting in. The
|
|
38
|
+
helper moves that work to your machine: you keep using the website exactly as
|
|
39
|
+
before, and the analysis happens at home.
|
|
40
|
+
|
|
41
|
+
Nothing listens on a port. The helper dials out to gammonview.com, waits for
|
|
42
|
+
work **you** queued from your own browser, runs it, and sends the result back.
|
|
43
|
+
There is no inbound connection, no router setting, no firewall rule.
|
|
44
|
+
|
|
45
|
+
## Install
|
|
46
|
+
|
|
47
|
+
Needs [uv](https://docs.astral.sh/uv/) (or pipx, or a plain `pip install` into
|
|
48
|
+
a virtualenv).
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
uv tool install https://github.com/ngvlamis/gammonview-helper/releases/download/v0.1.1/gammonview_helper-0.1.1-py3-none-any.whl
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
That pulls in the analysis engine and its neural networks — about 80 MB, and it
|
|
55
|
+
takes a minute or two the first time.
|
|
56
|
+
|
|
57
|
+
The URL names a version on purpose. Point it at a different release to install
|
|
58
|
+
that one, and re-run the same line with a newer version to upgrade — there is
|
|
59
|
+
no `uv tool upgrade` for a package installed from a URL, because there is no
|
|
60
|
+
index for it to ask.
|
|
61
|
+
|
|
62
|
+
Two other forms, for whoever prefers them:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# once this is on PyPI, the short name and `uv tool upgrade` both work
|
|
66
|
+
uv tool install gammonview-helper
|
|
67
|
+
|
|
68
|
+
# straight from a tag — needs `git`, and builds from source rather than
|
|
69
|
+
# installing the wheel that was tested
|
|
70
|
+
uv tool install git+https://github.com/ngvlamis/gammonview-helper@v0.1.1
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Link this computer
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
gammonview-helper link
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
It prints a word and opens your browser. Sign in if you are asked, and pick the
|
|
80
|
+
word it printed out of the three you are shown. You will get an email saying
|
|
81
|
+
the computer was linked.
|
|
82
|
+
|
|
83
|
+
If the three words do not include the one on your screen, **something is
|
|
84
|
+
wrong** — close the page and start again. That is the check working.
|
|
85
|
+
|
|
86
|
+
## Run it
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
gammonview-helper run
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Leave it running. Analyses you start on gammonview.com will now go to this
|
|
93
|
+
computer, and the deeper presets appear in the menu. If the helper is not
|
|
94
|
+
running, the website falls back to the shared server on its own — you never get
|
|
95
|
+
an error for having closed it.
|
|
96
|
+
|
|
97
|
+
You can start it before linking. An unlinked helper waits for a credential
|
|
98
|
+
rather than giving up, so the usual order — install, let it start, then link in
|
|
99
|
+
the browser — needs no third step telling it to look again; it picks the link
|
|
100
|
+
up within a few seconds. The same is true if you unlink and re-link later.
|
|
101
|
+
|
|
102
|
+
### Keeping it running (macOS)
|
|
103
|
+
|
|
104
|
+
`run` stops when you close the terminal. To have it start at login and stay up:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
deploy/install-login-item.sh
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
That registers a launchd agent pointing at the installed `gammonview-helper`,
|
|
111
|
+
logging to `~/Library/Logs/GammonView/helper.log`. Re-run it after an upgrade —
|
|
112
|
+
it boots the old job out first, so you never end up with two pollers sharing one
|
|
113
|
+
worker id, and it keeps whatever site the installed agent already pointed at.
|
|
114
|
+
To move a machine between sites, say so explicitly:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
GAMMONVIEW_SITE=https://gammonview.com deploy/install-login-item.sh
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
It says when it moves one, because a credential is per site: the machine has to
|
|
121
|
+
be linked to the new one separately.
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
deploy/install-login-item.sh stop # stop it, and leave it stopped
|
|
125
|
+
tail -f ~/Library/Logs/GammonView/helper.log
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Installing always leaves the helper running, so a `stop` does not survive the
|
|
129
|
+
next install. After stopping, the website keeps saying **Connected** for up to
|
|
130
|
+
two minutes — a helper stops by going quiet, and the relay waits that long
|
|
131
|
+
before believing a silence.
|
|
132
|
+
|
|
133
|
+
The eventual installer does this for you; the script exists because the machine
|
|
134
|
+
this is developed on needed it first, and `deploy/com.gammonview.helper.plist`
|
|
135
|
+
records the four choices in it that are not boilerplate.
|
|
136
|
+
|
|
137
|
+
## The other two commands
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
gammonview-helper status # what is configured, and is the link still alive
|
|
141
|
+
gammonview-helper unlink # forget this computer's credentials
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
`unlink` is local. To remove the computer from your account, use **Unlink** in
|
|
145
|
+
your account settings on the website — the helper's credentials deliberately
|
|
146
|
+
cannot reach your account, so they cannot revoke themselves.
|
|
147
|
+
|
|
148
|
+
## Settings
|
|
149
|
+
|
|
150
|
+
Everything lives in one directory, which is the whole of the uninstall:
|
|
151
|
+
|
|
152
|
+
| | |
|
|
153
|
+
|---|---|
|
|
154
|
+
| macOS | `~/Library/Application Support/GammonView/` |
|
|
155
|
+
| Windows | `%LOCALAPPDATA%\GammonView\` |
|
|
156
|
+
| Linux | `~/.config/gammonview/` |
|
|
157
|
+
|
|
158
|
+
The credential is kept in your platform's credential store (Keychain, Credential
|
|
159
|
+
Manager, Secret Service), not in that directory. `status` says which store it
|
|
160
|
+
actually got — on a machine with no credential store it falls back to a
|
|
161
|
+
`0600` file, and tells you so.
|
|
162
|
+
|
|
163
|
+
`config.json` takes a few optional keys:
|
|
164
|
+
|
|
165
|
+
| key | default | what it does |
|
|
166
|
+
|---|---|---|
|
|
167
|
+
| `jobs` | `0` — the engine decides | how many of a match's decisions run in parallel |
|
|
168
|
+
| `threads` | `0` — the engine decides | engine threads inside each of those |
|
|
169
|
+
| `nice` | 10 | how hard the helper tries to stay out of your way |
|
|
170
|
+
|
|
171
|
+
The parallelism is sized by the engine, from measurements it keeps for the
|
|
172
|
+
purpose; set either to a number if you want a hard cap, and it will be kept.
|
|
173
|
+
`nice` is what makes the helper something you forget is running — it yields to
|
|
174
|
+
whatever you are actually doing, and every engine worker inherits it.
|
|
175
|
+
|
|
176
|
+
## Licence
|
|
177
|
+
|
|
178
|
+
MIT. The engine ([bgsage](https://pypi.org/project/bgsage/)) is MPL-2.0 and is
|
|
179
|
+
installed as an ordinary dependency.
|
|
180
|
+
|
|
181
|
+
## Development
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
uv run pytest -q -m "not slow and not contract"
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Two markers are deselected there. `slow` runs a real analysis and needs a
|
|
188
|
+
minute of CPU. `contract` talks to a **live** relay and is opt-in:
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
GAMMONVIEW_CONTRACT_BASE=https://beta.gammonview.com uv run pytest -m contract
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
The other end of that protocol — the relay itself — is part of the
|
|
195
|
+
gammonview.com service and is not open source. `docs/Relay.md` documents the
|
|
196
|
+
seam from this side, says which revision this client implements, and explains
|
|
197
|
+
why the contract carries a number of its own.
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# gammonview-helper
|
|
2
|
+
|
|
3
|
+
Analyze your backgammon matches on your own computer, and see the results on
|
|
4
|
+
[gammonview.com](https://gammonview.com).
|
|
5
|
+
|
|
6
|
+
GammonView analyses matches on a shared server. That server is shared, so the
|
|
7
|
+
deepest settings are not on its menu — a *World Class* run that takes a minute
|
|
8
|
+
on your laptop would take an hour of a queue everybody else is waiting in. The
|
|
9
|
+
helper moves that work to your machine: you keep using the website exactly as
|
|
10
|
+
before, and the analysis happens at home.
|
|
11
|
+
|
|
12
|
+
Nothing listens on a port. The helper dials out to gammonview.com, waits for
|
|
13
|
+
work **you** queued from your own browser, runs it, and sends the result back.
|
|
14
|
+
There is no inbound connection, no router setting, no firewall rule.
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
Needs [uv](https://docs.astral.sh/uv/) (or pipx, or a plain `pip install` into
|
|
19
|
+
a virtualenv).
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
uv tool install https://github.com/ngvlamis/gammonview-helper/releases/download/v0.1.1/gammonview_helper-0.1.1-py3-none-any.whl
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
That pulls in the analysis engine and its neural networks — about 80 MB, and it
|
|
26
|
+
takes a minute or two the first time.
|
|
27
|
+
|
|
28
|
+
The URL names a version on purpose. Point it at a different release to install
|
|
29
|
+
that one, and re-run the same line with a newer version to upgrade — there is
|
|
30
|
+
no `uv tool upgrade` for a package installed from a URL, because there is no
|
|
31
|
+
index for it to ask.
|
|
32
|
+
|
|
33
|
+
Two other forms, for whoever prefers them:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# once this is on PyPI, the short name and `uv tool upgrade` both work
|
|
37
|
+
uv tool install gammonview-helper
|
|
38
|
+
|
|
39
|
+
# straight from a tag — needs `git`, and builds from source rather than
|
|
40
|
+
# installing the wheel that was tested
|
|
41
|
+
uv tool install git+https://github.com/ngvlamis/gammonview-helper@v0.1.1
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Link this computer
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
gammonview-helper link
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
It prints a word and opens your browser. Sign in if you are asked, and pick the
|
|
51
|
+
word it printed out of the three you are shown. You will get an email saying
|
|
52
|
+
the computer was linked.
|
|
53
|
+
|
|
54
|
+
If the three words do not include the one on your screen, **something is
|
|
55
|
+
wrong** — close the page and start again. That is the check working.
|
|
56
|
+
|
|
57
|
+
## Run it
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
gammonview-helper run
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Leave it running. Analyses you start on gammonview.com will now go to this
|
|
64
|
+
computer, and the deeper presets appear in the menu. If the helper is not
|
|
65
|
+
running, the website falls back to the shared server on its own — you never get
|
|
66
|
+
an error for having closed it.
|
|
67
|
+
|
|
68
|
+
You can start it before linking. An unlinked helper waits for a credential
|
|
69
|
+
rather than giving up, so the usual order — install, let it start, then link in
|
|
70
|
+
the browser — needs no third step telling it to look again; it picks the link
|
|
71
|
+
up within a few seconds. The same is true if you unlink and re-link later.
|
|
72
|
+
|
|
73
|
+
### Keeping it running (macOS)
|
|
74
|
+
|
|
75
|
+
`run` stops when you close the terminal. To have it start at login and stay up:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
deploy/install-login-item.sh
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
That registers a launchd agent pointing at the installed `gammonview-helper`,
|
|
82
|
+
logging to `~/Library/Logs/GammonView/helper.log`. Re-run it after an upgrade —
|
|
83
|
+
it boots the old job out first, so you never end up with two pollers sharing one
|
|
84
|
+
worker id, and it keeps whatever site the installed agent already pointed at.
|
|
85
|
+
To move a machine between sites, say so explicitly:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
GAMMONVIEW_SITE=https://gammonview.com deploy/install-login-item.sh
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
It says when it moves one, because a credential is per site: the machine has to
|
|
92
|
+
be linked to the new one separately.
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
deploy/install-login-item.sh stop # stop it, and leave it stopped
|
|
96
|
+
tail -f ~/Library/Logs/GammonView/helper.log
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Installing always leaves the helper running, so a `stop` does not survive the
|
|
100
|
+
next install. After stopping, the website keeps saying **Connected** for up to
|
|
101
|
+
two minutes — a helper stops by going quiet, and the relay waits that long
|
|
102
|
+
before believing a silence.
|
|
103
|
+
|
|
104
|
+
The eventual installer does this for you; the script exists because the machine
|
|
105
|
+
this is developed on needed it first, and `deploy/com.gammonview.helper.plist`
|
|
106
|
+
records the four choices in it that are not boilerplate.
|
|
107
|
+
|
|
108
|
+
## The other two commands
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
gammonview-helper status # what is configured, and is the link still alive
|
|
112
|
+
gammonview-helper unlink # forget this computer's credentials
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
`unlink` is local. To remove the computer from your account, use **Unlink** in
|
|
116
|
+
your account settings on the website — the helper's credentials deliberately
|
|
117
|
+
cannot reach your account, so they cannot revoke themselves.
|
|
118
|
+
|
|
119
|
+
## Settings
|
|
120
|
+
|
|
121
|
+
Everything lives in one directory, which is the whole of the uninstall:
|
|
122
|
+
|
|
123
|
+
| | |
|
|
124
|
+
|---|---|
|
|
125
|
+
| macOS | `~/Library/Application Support/GammonView/` |
|
|
126
|
+
| Windows | `%LOCALAPPDATA%\GammonView\` |
|
|
127
|
+
| Linux | `~/.config/gammonview/` |
|
|
128
|
+
|
|
129
|
+
The credential is kept in your platform's credential store (Keychain, Credential
|
|
130
|
+
Manager, Secret Service), not in that directory. `status` says which store it
|
|
131
|
+
actually got — on a machine with no credential store it falls back to a
|
|
132
|
+
`0600` file, and tells you so.
|
|
133
|
+
|
|
134
|
+
`config.json` takes a few optional keys:
|
|
135
|
+
|
|
136
|
+
| key | default | what it does |
|
|
137
|
+
|---|---|---|
|
|
138
|
+
| `jobs` | `0` — the engine decides | how many of a match's decisions run in parallel |
|
|
139
|
+
| `threads` | `0` — the engine decides | engine threads inside each of those |
|
|
140
|
+
| `nice` | 10 | how hard the helper tries to stay out of your way |
|
|
141
|
+
|
|
142
|
+
The parallelism is sized by the engine, from measurements it keeps for the
|
|
143
|
+
purpose; set either to a number if you want a hard cap, and it will be kept.
|
|
144
|
+
`nice` is what makes the helper something you forget is running — it yields to
|
|
145
|
+
whatever you are actually doing, and every engine worker inherits it.
|
|
146
|
+
|
|
147
|
+
## Licence
|
|
148
|
+
|
|
149
|
+
MIT. The engine ([bgsage](https://pypi.org/project/bgsage/)) is MPL-2.0 and is
|
|
150
|
+
installed as an ordinary dependency.
|
|
151
|
+
|
|
152
|
+
## Development
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
uv run pytest -q -m "not slow and not contract"
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Two markers are deselected there. `slow` runs a real analysis and needs a
|
|
159
|
+
minute of CPU. `contract` talks to a **live** relay and is opt-in:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
GAMMONVIEW_CONTRACT_BASE=https://beta.gammonview.com uv run pytest -m contract
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
The other end of that protocol — the relay itself — is part of the
|
|
166
|
+
gammonview.com service and is not open source. `docs/Relay.md` documents the
|
|
167
|
+
seam from this side, says which revision this client implements, and explains
|
|
168
|
+
why the contract carries a number of its own.
|