archicad-mcp-server 0.5.4__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.
- archicad_mcp_server-0.5.4/.gitattributes +15 -0
- archicad_mcp_server-0.5.4/.github/workflows/publish.yml +233 -0
- archicad_mcp_server-0.5.4/.github/workflows/test.yml +43 -0
- archicad_mcp_server-0.5.4/.gitignore +23 -0
- archicad_mcp_server-0.5.4/LICENSE +21 -0
- archicad_mcp_server-0.5.4/PKG-INFO +595 -0
- archicad_mcp_server-0.5.4/PRIVACY.md +105 -0
- archicad_mcp_server-0.5.4/README.md +579 -0
- archicad_mcp_server-0.5.4/docs/api-dashboard.html +519 -0
- archicad_mcp_server-0.5.4/docs/gdl-pipeline.md +124 -0
- archicad_mcp_server-0.5.4/docs/index.md +39 -0
- archicad_mcp_server-0.5.4/docs/known-issues.md +282 -0
- archicad_mcp_server-0.5.4/docs/query.md +242 -0
- archicad_mcp_server-0.5.4/docs/rules.md +248 -0
- archicad_mcp_server-0.5.4/docs/scheme-criteria-codes.md +83 -0
- archicad_mcp_server-0.5.4/docs/superpowers/plans/2026-07-28-schedule-scheme-editing.md +2305 -0
- archicad_mcp_server-0.5.4/docs/superpowers/plans/2026-09-01-railing-creation.md +912 -0
- archicad_mcp_server-0.5.4/docs/superpowers/plans/2026-09-02-gdl-mcp-tools.md +1798 -0
- archicad_mcp_server-0.5.4/docs/superpowers/specs/2026-07-16-archicad-mcp-design.md +265 -0
- archicad_mcp_server-0.5.4/docs/superpowers/specs/2026-07-28-schedule-scheme-editing-design.md +267 -0
- archicad_mcp_server-0.5.4/docs/superpowers/specs/2026-09-01-railing-creation-design.md +264 -0
- archicad_mcp_server-0.5.4/docs/superpowers/specs/2026-09-02-gdl-mcp-tools-design.md +270 -0
- archicad_mcp_server-0.5.4/docs/superpowers/specs/2026-09-03-criteria-query-design.md +86 -0
- archicad_mcp_server-0.5.4/icon.png +0 -0
- archicad_mcp_server-0.5.4/icon.svg +17 -0
- archicad_mcp_server-0.5.4/manifest.json +258 -0
- archicad_mcp_server-0.5.4/pyproject.toml +36 -0
- archicad_mcp_server-0.5.4/scripts/__init__.py +0 -0
- archicad_mcp_server-0.5.4/scripts/build_bundle.py +286 -0
- archicad_mcp_server-0.5.4/scripts/build_dashboard.py +796 -0
- archicad_mcp_server-0.5.4/scripts/check_release_version.py +204 -0
- archicad_mcp_server-0.5.4/scripts/diff_scheme_criteria.py +120 -0
- archicad_mcp_server-0.5.4/scripts/make_icon.py +83 -0
- archicad_mcp_server-0.5.4/scripts/sync_tapir_defs.py +63 -0
- archicad_mcp_server-0.5.4/server.json +31 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/__init__.py +0 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/actions.py +34 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/connection.py +214 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/core/__init__.py +0 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/core/attributes.py +31 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/core/create.py +30 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/core/definitions.py +283 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/core/element_data.py +98 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/core/issues.py +53 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/core/mutate.py +25 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/core/project.py +50 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/core/publish.py +8 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/core/query.py +250 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/core/query_schema.py +88 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/core/schemes.py +341 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/core/selection.py +36 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/core/teamwork.py +131 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/criteria.py +467 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/extract.py +372 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/gateway/__init__.py +0 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/gateway/definitions/command_definitions.js +10875 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/gateway/definitions/common_schema_definitions.js +8087 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/gateway/definitions/local_commands.json +42 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/gateway/definitions/tapir_version.json +5 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/gateway/execute.py +149 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/gateway/registry.py +131 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/gdl/__init__.py +7 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/gdl/cli.py +160 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/gdl/config.py +160 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/gdl/deploy.py +89 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/gdl/generate.py +472 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/gdl/mesh.py +265 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/gdl/toolchain.py +229 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/gdl/tools.py +366 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/gdl/workspace.py +57 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/rules/__init__.py +0 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/rules/builtin/__init__.py +0 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/rules/builtin/base.py +95 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/rules/builtin/classification_required.py +48 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/rules/builtin/ifc_readiness.py +57 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/rules/builtin/layer_compliance.py +64 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/rules/builtin/property_required.py +48 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/rules/builtin/zone_checks.py +39 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/rules/engine.py +73 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/rules/examples/example-rules.yaml +20 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/rules/loader.py +92 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/rules/types.py +67 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/schemes/__init__.py +0 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/schemes/columns.py +208 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/schemes/model.py +226 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/schemes/spec.py +364 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/schemes/validate.py +87 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/schemes/xml_io.py +118 -0
- archicad_mcp_server-0.5.4/src/archicad_mcp/server.py +768 -0
- archicad_mcp_server-0.5.4/tests/__init__.py +0 -0
- archicad_mcp_server-0.5.4/tests/conftest.py +25 -0
- archicad_mcp_server-0.5.4/tests/fixtures/__init__.py +0 -0
- archicad_mcp_server-0.5.4/tests/fixtures/api_replays.py +234 -0
- archicad_mcp_server-0.5.4/tests/fixtures/schemes/sample_scheme.xml +114 -0
- archicad_mcp_server-0.5.4/tests/rules/__init__.py +0 -0
- archicad_mcp_server-0.5.4/tests/rules/test_applies_to_where.py +59 -0
- archicad_mcp_server-0.5.4/tests/rules/test_builtin_layers_zones_ifc.py +64 -0
- archicad_mcp_server-0.5.4/tests/rules/test_builtin_property_classification.py +64 -0
- archicad_mcp_server-0.5.4/tests/rules/test_engine.py +127 -0
- archicad_mcp_server-0.5.4/tests/rules/test_loader.py +84 -0
- archicad_mcp_server-0.5.4/tests/rules/test_types.py +37 -0
- archicad_mcp_server-0.5.4/tests/schemes/__init__.py +0 -0
- archicad_mcp_server-0.5.4/tests/schemes/conftest.py +102 -0
- archicad_mcp_server-0.5.4/tests/schemes/test_columns.py +394 -0
- archicad_mcp_server-0.5.4/tests/schemes/test_core_edit.py +665 -0
- archicad_mcp_server-0.5.4/tests/schemes/test_core_read.py +134 -0
- archicad_mcp_server-0.5.4/tests/schemes/test_criteria_diff.py +71 -0
- archicad_mcp_server-0.5.4/tests/schemes/test_model.py +234 -0
- archicad_mcp_server-0.5.4/tests/schemes/test_spec.py +636 -0
- archicad_mcp_server-0.5.4/tests/schemes/test_validate.py +173 -0
- archicad_mcp_server-0.5.4/tests/schemes/test_xml_io.py +232 -0
- archicad_mcp_server-0.5.4/tests/test_cli_transport.py +75 -0
- archicad_mcp_server-0.5.4/tests/test_connection.py +204 -0
- archicad_mcp_server-0.5.4/tests/test_criteria.py +276 -0
- archicad_mcp_server-0.5.4/tests/test_definitions.py +148 -0
- archicad_mcp_server-0.5.4/tests/test_element_coverage.py +134 -0
- archicad_mcp_server-0.5.4/tests/test_extract.py +187 -0
- archicad_mcp_server-0.5.4/tests/test_gateway.py +230 -0
- archicad_mcp_server-0.5.4/tests/test_gdl_config.py +61 -0
- archicad_mcp_server-0.5.4/tests/test_gdl_deploy.py +44 -0
- archicad_mcp_server-0.5.4/tests/test_gdl_generate.py +182 -0
- archicad_mcp_server-0.5.4/tests/test_gdl_mesh.py +100 -0
- archicad_mcp_server-0.5.4/tests/test_gdl_toolchain.py +75 -0
- archicad_mcp_server-0.5.4/tests/test_gdl_tools.py +720 -0
- archicad_mcp_server-0.5.4/tests/test_gdl_workspace.py +70 -0
- archicad_mcp_server-0.5.4/tests/test_live.py +282 -0
- archicad_mcp_server-0.5.4/tests/test_manifest.py +25 -0
- archicad_mcp_server-0.5.4/tests/test_query.py +207 -0
- archicad_mcp_server-0.5.4/tests/test_query_schema.py +89 -0
- archicad_mcp_server-0.5.4/tests/test_release_version.py +200 -0
- archicad_mcp_server-0.5.4/tests/test_server_gdl_wiring.py +39 -0
- archicad_mcp_server-0.5.4/tests/test_server_smoke.py +29 -0
- archicad_mcp_server-0.5.4/tests/test_startup_banner.py +245 -0
- archicad_mcp_server-0.5.4/tests/test_teamwork.py +165 -0
- archicad_mcp_server-0.5.4/tests/test_tier1_tools.py +224 -0
- archicad_mcp_server-0.5.4/tests/test_tier2_mutations.py +128 -0
- archicad_mcp_server-0.5.4/tests/test_tier2_project_issues.py +132 -0
- archicad_mcp_server-0.5.4/tests/test_tier2_query_data.py +142 -0
- archicad_mcp_server-0.5.4/tests/test_tool_annotations.py +143 -0
- archicad_mcp_server-0.5.4/uv.lock +1538 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Scheme XML is compared byte for byte. tests/schemes/test_xml_io.py asserts
|
|
2
|
+
# that a load/save cycle reproduces tests/fixtures/schemes/sample_scheme.xml
|
|
3
|
+
# exactly, and round_trips_exactly() treats a newline difference as a rewrite
|
|
4
|
+
# it must refuse. If a checkout converted these files to CRLF (Git for Windows
|
|
5
|
+
# installs with core.autocrlf=true by default, and actions/checkout does not
|
|
6
|
+
# override it), the fixture on disk would no longer be the bytes those tests
|
|
7
|
+
# were written against. Pin it so every platform sees the same file.
|
|
8
|
+
*.xml text eol=lf
|
|
9
|
+
|
|
10
|
+
# Same reasoning for the YAML specs and rule files the suite reads, and for
|
|
11
|
+
# Python sources, so nothing in the tree depends on the checkout's newline
|
|
12
|
+
# policy.
|
|
13
|
+
*.yaml text eol=lf
|
|
14
|
+
*.yml text eol=lf
|
|
15
|
+
*.py text eol=lf
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
name: release
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
# Version tags only. A tag is the one signal that says "this exact commit
|
|
5
|
+
# is 0.1.0", and nothing else in the repository should be able to publish.
|
|
6
|
+
tags: ["v*"]
|
|
7
|
+
|
|
8
|
+
# Two privileged things happen here, and this is the whole grant for both.
|
|
9
|
+
# contents creates the release. id-token mints a short-lived OIDC token that
|
|
10
|
+
# PyPI and the MCP registry each accept as proof this run is from this
|
|
11
|
+
# repository, which is why publishing to either needs no stored credential:
|
|
12
|
+
# there is nothing to rotate, nothing to leak, and a token that is worthless
|
|
13
|
+
# minutes later. PyPI matches the token against this file's name, so renaming
|
|
14
|
+
# publish.yml silently ends PyPI publishing until the trusted publisher on
|
|
15
|
+
# pypi.org is re-registered to match. Every other step reads the checkout and
|
|
16
|
+
# writes to the runner.
|
|
17
|
+
permissions:
|
|
18
|
+
contents: write
|
|
19
|
+
id-token: write
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
release:
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
env:
|
|
25
|
+
# One Python, not test.yml's matrix. The wheel is py3-none-any and the
|
|
26
|
+
# bundle ships pyproject.toml and uv.lock rather than vendored wheels,
|
|
27
|
+
# so nothing that gets uploaded depends on the interpreter that built
|
|
28
|
+
# it. 3.13 is the newer of the two the suite covers, so the release is
|
|
29
|
+
# still built on a version that is actually tested.
|
|
30
|
+
UV_PYTHON: "3.13"
|
|
31
|
+
steps:
|
|
32
|
+
# The same two pins as test.yml, for the reasons written out there:
|
|
33
|
+
# checkout follows its major, setup-uv is an exact version because
|
|
34
|
+
# astral-sh stopped publishing major tags after v7. Move the two
|
|
35
|
+
# workflows together, so a release is built by the toolchain that
|
|
36
|
+
# tested the commit rather than a later one nothing has run yet.
|
|
37
|
+
# persist-credentials defaults to true, which writes this run's
|
|
38
|
+
# GITHUB_TOKEN into .git/config as an auth header. This job holds
|
|
39
|
+
# contents: write and then runs code that is not ours (npx fetches the
|
|
40
|
+
# mcpb packer, uv sync resolves the whole PyPI tree), so that would leave
|
|
41
|
+
# a write-capable token on disk alongside it. Nothing here pushes over
|
|
42
|
+
# git: gh release create authenticates through GH_TOKEN instead.
|
|
43
|
+
- uses: actions/checkout@v7
|
|
44
|
+
with:
|
|
45
|
+
persist-credentials: false
|
|
46
|
+
- uses: astral-sh/setup-uv@v9.0.0
|
|
47
|
+
with:
|
|
48
|
+
# Same reason test.yml gives every matrix entry its own key. The
|
|
49
|
+
# default one is derived from the runner image's default Python, not
|
|
50
|
+
# from UV_PYTHON, so without a suffix this job would race a test run
|
|
51
|
+
# for the one key that image hands both of them.
|
|
52
|
+
cache-suffix: release
|
|
53
|
+
|
|
54
|
+
# The gate, before anything is synced, built, or packed. It is the one
|
|
55
|
+
# failure here whose cost is not a re-run: a tag has already been pushed
|
|
56
|
+
# by the time this workflow exists, so a mismatch means deleting the tag
|
|
57
|
+
# and pushing it again, and every second spent before saying so is spent
|
|
58
|
+
# on work that is going to be thrown away. --no-project because the
|
|
59
|
+
# check imports nothing outside the standard library.
|
|
60
|
+
#
|
|
61
|
+
# $GITHUB_REF_NAME rather than ${{ github.ref_name }}: a tag name is text
|
|
62
|
+
# somebody chose, and ${{ }} substitution pastes it into the script
|
|
63
|
+
# before the shell parses it. Through the environment it stays one
|
|
64
|
+
# argument no matter what it contains.
|
|
65
|
+
- run: uv run --no-project python scripts/check_release_version.py "$GITHUB_REF_NAME"
|
|
66
|
+
|
|
67
|
+
# The version lives in a fourth place that check cannot see: uv.lock
|
|
68
|
+
# records the project's own version, and the bundle SHIPS uv.lock. Bump
|
|
69
|
+
# pyproject.toml, manifest.json and the README without re-running
|
|
70
|
+
# uv lock, and the check above happily says "agree" while the extension
|
|
71
|
+
# goes out with a lock file that disagrees with its own pyproject, which
|
|
72
|
+
# makes uv re-resolve on the user's machine at first launch. uv lock
|
|
73
|
+
# --check is the purpose-built test for exactly that, and is a sub-second
|
|
74
|
+
# no-op when they agree. It has to run before uv sync, because sync
|
|
75
|
+
# quietly updates the lock and would erase the evidence.
|
|
76
|
+
- run: uv lock --check
|
|
77
|
+
|
|
78
|
+
# test.yml has already run the full matrix if this commit reached main
|
|
79
|
+
# the usual way, but a tag can be pushed at any commit, including one
|
|
80
|
+
# that never did. This is the tripwire for that case, and is deliberately
|
|
81
|
+
# a single run rather than a second copy of the matrix, which would only
|
|
82
|
+
# re-prove what main already proved.
|
|
83
|
+
- run: uv sync
|
|
84
|
+
- run: uv run pytest -v
|
|
85
|
+
|
|
86
|
+
# Wheel and sdist first, because uv build is also what creates dist/ for
|
|
87
|
+
# the bundle to be written into. dist/ is not in the repository.
|
|
88
|
+
- run: uv build
|
|
89
|
+
|
|
90
|
+
# One bundle per platform, all three cross-built on this one runner. The
|
|
91
|
+
# bundles are platform-specific because the dependency tree contains
|
|
92
|
+
# compiled wheels; the build is not, because uv resolves wheels for a
|
|
93
|
+
# named target platform and the standalone interpreters are plain
|
|
94
|
+
# downloads. That is what keeps this a single job rather than a runner
|
|
95
|
+
# matrix, at the cost of the one check a matrix would give for free:
|
|
96
|
+
# nothing here can execute a Windows bundle, so a release is not proven
|
|
97
|
+
# until one is installed on Windows. The script validates each generated
|
|
98
|
+
# manifest before packing it, and pins the mcpb packer for the reason
|
|
99
|
+
# pins exist here generally: the packer decides the bundle format, so it
|
|
100
|
+
# is the thing worth holding still between releases.
|
|
101
|
+
#
|
|
102
|
+
# Node is whatever the runner image ships, an LTS it keeps current. It
|
|
103
|
+
# runs the packer; it does not decide anything the packer produces.
|
|
104
|
+
- run: uv run python scripts/build_bundle.py --target all
|
|
105
|
+
|
|
106
|
+
# server.json tells the registry where each bundle is and what it must
|
|
107
|
+
# hash to, and clients check that hash before they install. Every other
|
|
108
|
+
# field in it is committed and gated by check_release_version.py, the
|
|
109
|
+
# same as manifest.json. These cannot be: they are hashes of bundles
|
|
110
|
+
# built from the very commit that would have to contain them. So they are
|
|
111
|
+
# stamped at the first moment they are knowable, and the placeholder that
|
|
112
|
+
# is committed is never what gets published.
|
|
113
|
+
#
|
|
114
|
+
# Matched on the filename rather than by position, so that reordering
|
|
115
|
+
# server.json's packages cannot quietly pair a bundle with another
|
|
116
|
+
# platform's hash. The check afterwards is what makes that safe to rely
|
|
117
|
+
# on: a package left holding the placeholder is refused by every client
|
|
118
|
+
# that checks the hash, and an unstamped entry is the only way that
|
|
119
|
+
# happens by accident.
|
|
120
|
+
- run: |
|
|
121
|
+
version="${GITHUB_REF_NAME#v}"
|
|
122
|
+
for target in win32 darwin-arm64; do
|
|
123
|
+
name="archicad-mcp-${version}-${target}.mcpb"
|
|
124
|
+
sha="$(sha256sum "dist/$name" | cut -d' ' -f1)"
|
|
125
|
+
jq --arg name "$name" --arg sha "$sha" \
|
|
126
|
+
'(.packages[] | select(.identifier | endswith($name))).fileSha256 = $sha' \
|
|
127
|
+
server.json > server.stamped
|
|
128
|
+
mv server.stamped server.json
|
|
129
|
+
done
|
|
130
|
+
if jq -e '[.packages[] | select(.fileSha256 | test("^0{64}$"))] | length > 0' \
|
|
131
|
+
server.json > /dev/null; then
|
|
132
|
+
echo "::error::a package in server.json kept its placeholder hash" >&2
|
|
133
|
+
exit 1
|
|
134
|
+
fi
|
|
135
|
+
|
|
136
|
+
# Anything that is not exactly major.minor.patch is a prerelease,
|
|
137
|
+
# whichever way it is spelled (v0.2.0rc1, v0.2.0-beta.1). Decided once,
|
|
138
|
+
# here, because the two steps below need the same answer and a second
|
|
139
|
+
# copy of this regex would be a second thing to keep in step.
|
|
140
|
+
- run: |
|
|
141
|
+
if [[ "${GITHUB_REF_NAME#v}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
142
|
+
echo "PRERELEASE=false" >> "$GITHUB_ENV"
|
|
143
|
+
else
|
|
144
|
+
echo "PRERELEASE=true" >> "$GITHUB_ENV"
|
|
145
|
+
fi
|
|
146
|
+
|
|
147
|
+
# gh is preinstalled on the runner and is the same command this would be
|
|
148
|
+
# by hand, so there is no third-party release action to pin and keep
|
|
149
|
+
# current. The wheel and sdist go up alongside the bundle as well as to
|
|
150
|
+
# PyPI, so that a pinned install can name a release asset by URL without
|
|
151
|
+
# depending on a second service. A prerelease is labelled as one rather
|
|
152
|
+
# than offered from the releases page as the current version to download.
|
|
153
|
+
#
|
|
154
|
+
# Create, or re-upload if the release already exists. The registry publish
|
|
155
|
+
# below is the last step and the one most likely to fail on its own terms,
|
|
156
|
+
# since it talks to a service still in preview. When it did, the run could
|
|
157
|
+
# not simply be re-run: this step had already created the release, and
|
|
158
|
+
# creating it again is an error, so the recovery the comment below
|
|
159
|
+
# promises was not actually available. Now it is.
|
|
160
|
+
- run: |
|
|
161
|
+
flags=(--generate-notes --title "$GITHUB_REF_NAME")
|
|
162
|
+
if [[ "$PRERELEASE" == "true" ]]; then
|
|
163
|
+
flags+=(--prerelease)
|
|
164
|
+
fi
|
|
165
|
+
if gh release view "$GITHUB_REF_NAME" > /dev/null 2>&1; then
|
|
166
|
+
echo "release exists, replacing its assets"
|
|
167
|
+
gh release upload "$GITHUB_REF_NAME" --clobber \
|
|
168
|
+
dist/*.mcpb dist/*.whl dist/*.tar.gz
|
|
169
|
+
else
|
|
170
|
+
gh release create "$GITHUB_REF_NAME" "${flags[@]}" \
|
|
171
|
+
dist/*.mcpb dist/*.whl dist/*.tar.gz
|
|
172
|
+
fi
|
|
173
|
+
env:
|
|
174
|
+
GH_TOKEN: ${{ github.token }}
|
|
175
|
+
|
|
176
|
+
# The wheel and sdist, and only those: dist/ also holds the bundles by
|
|
177
|
+
# now, and uv publish would try to upload whatever it is handed. Named
|
|
178
|
+
# archicad-mcp-server on PyPI because archicad-mcp was already taken
|
|
179
|
+
# there by an unrelated project; the import package, the extension and
|
|
180
|
+
# the registry entry all keep the shorter name, so the distribution name
|
|
181
|
+
# in pyproject.toml is the only place the two differ.
|
|
182
|
+
#
|
|
183
|
+
# uv publish does trusted publishing natively over the id-token grant
|
|
184
|
+
# above, which is what keeps this a plain command rather than a
|
|
185
|
+
# third-party action to pin, the same reason gh is used for the release.
|
|
186
|
+
# "always" rather than the default "automatic" so that a run that cannot
|
|
187
|
+
# get a token fails here with that reason, instead of falling through to
|
|
188
|
+
# a password prompt that has nothing to read from.
|
|
189
|
+
#
|
|
190
|
+
# --check-url is what makes a re-run survivable. PyPI refuses a file it
|
|
191
|
+
# already holds, and the registry step below is the one most likely to
|
|
192
|
+
# fail, so without it every registry failure would also be a PyPI
|
|
193
|
+
# failure on the retry. With it, files already on the index are skipped
|
|
194
|
+
# and the run proceeds to the step that actually needs re-running.
|
|
195
|
+
#
|
|
196
|
+
# Prereleases go up too. PyPI understands them, and pip and uv leave
|
|
197
|
+
# them alone unless asked, so publishing one hands nobody a release
|
|
198
|
+
# candidate by default, which is the reason the registry step skips them.
|
|
199
|
+
- name: Publish to PyPI
|
|
200
|
+
run: |
|
|
201
|
+
uv publish --trusted-publishing always \
|
|
202
|
+
--check-url https://pypi.org/simple/ \
|
|
203
|
+
dist/*.whl dist/*.tar.gz
|
|
204
|
+
|
|
205
|
+
# After the release exists, never before. The registry stores the
|
|
206
|
+
# bundle's download URL and hands it to clients verbatim, so publishing
|
|
207
|
+
# while the asset was still uploading would advertise a URL that 404s,
|
|
208
|
+
# and nothing would tell the registry to look again later.
|
|
209
|
+
#
|
|
210
|
+
# Skipped for prereleases. The registry offers one current version per
|
|
211
|
+
# server, so registering v0.2.0rc1 would hand a release candidate to
|
|
212
|
+
# everyone who installs from a client's server list.
|
|
213
|
+
#
|
|
214
|
+
# Unpinned, unlike the mcpb packer above, and for the opposite reason.
|
|
215
|
+
# The packer decides the format of a file this repository produces, so
|
|
216
|
+
# holding it still is what keeps bundles comparable between releases.
|
|
217
|
+
# mcp-publisher speaks a protocol the registry defines and is still
|
|
218
|
+
# changing while it is in preview, so the version that works is the one
|
|
219
|
+
# matching the registry as it is today, not as it was at the last release.
|
|
220
|
+
#
|
|
221
|
+
# Last, so that nothing else in the release depends on it. A failure here
|
|
222
|
+
# leaves the GitHub release intact and correct, which is what every
|
|
223
|
+
# install path other than the registry uses, and re-running the job
|
|
224
|
+
# recovers it. What re-running cannot do is correct a publish that
|
|
225
|
+
# succeeded: the registry refuses a version it already holds ("cannot
|
|
226
|
+
# publish duplicate version"), so a wrong entry is fixed by releasing the
|
|
227
|
+
# next patch version, never by pushing this tag again.
|
|
228
|
+
- name: Publish to the MCP registry
|
|
229
|
+
if: env.PRERELEASE == 'false'
|
|
230
|
+
run: |
|
|
231
|
+
curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher
|
|
232
|
+
./mcp-publisher login github-oidc
|
|
233
|
+
./mcp-publisher publish
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
name: test
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches: [main]
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
test:
|
|
9
|
+
strategy:
|
|
10
|
+
fail-fast: false
|
|
11
|
+
matrix:
|
|
12
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
13
|
+
python-version: ["3.12", "3.13"]
|
|
14
|
+
runs-on: ${{ matrix.os }}
|
|
15
|
+
env:
|
|
16
|
+
UV_PYTHON: ${{ matrix.python-version }}
|
|
17
|
+
steps:
|
|
18
|
+
# Both pinned to versions that run on Node 24. checkout moved to Node 24
|
|
19
|
+
# in v5 and setup-uv in v7; the older v4/v5 pair here ran on Node 20,
|
|
20
|
+
# which the runners now force onto Node 24 anyway while emitting a
|
|
21
|
+
# deprecation warning on every job.
|
|
22
|
+
- uses: actions/checkout@v7
|
|
23
|
+
# Exact version, not a floating major like the line above, because
|
|
24
|
+
# astral-sh stopped publishing major tags after v7: there is no v8 or v9
|
|
25
|
+
# to track, so the alternatives are pinning a full version or sitting two
|
|
26
|
+
# majors behind on v7. Bump this by hand (or let Dependabot do it).
|
|
27
|
+
- uses: astral-sh/setup-uv@v9.0.0
|
|
28
|
+
with:
|
|
29
|
+
# The default cache key carries the runner image's own default Python
|
|
30
|
+
# (3.14.6 on the macOS image, for instance), not UV_PYTHON, so both
|
|
31
|
+
# matrix entries for a given OS land on one key and race to reserve
|
|
32
|
+
# it: one saves and the other warns that another job may be creating
|
|
33
|
+
# the cache. The suffix gives every entry its own key.
|
|
34
|
+
cache-suffix: ${{ matrix.python-version }}
|
|
35
|
+
# Before uv sync, which quietly updates the lock and would erase the
|
|
36
|
+
# evidence. uv.lock records the project's own version and ships inside
|
|
37
|
+
# the .mcpb bundle, so a bump that forgot to re-lock is caught here, on
|
|
38
|
+
# the commit that caused it, rather than at tag time when the fix is to
|
|
39
|
+
# delete a pushed tag.
|
|
40
|
+
- run: uv lock --check
|
|
41
|
+
- run: uv sync
|
|
42
|
+
- run: uv run pytest -v
|
|
43
|
+
- run: uv build
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
.claude/settings.local.json
|
|
2
|
+
__pycache__/
|
|
3
|
+
.venv/
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.pytest_cache/
|
|
6
|
+
.DS_Store
|
|
7
|
+
|
|
8
|
+
# Real project files used to exercise the server against a live model: survey
|
|
9
|
+
# points, CAD exports, a .pln. They are someone's drawings rather than
|
|
10
|
+
# fixtures, and this repository is public, so they stay on the machine that
|
|
11
|
+
# needs them. Test data that belongs here goes in tests/fixtures/.
|
|
12
|
+
teren/
|
|
13
|
+
|
|
14
|
+
# Staging tree and cached standalone interpreters for scripts/build_bundle.py.
|
|
15
|
+
# Both are rebuildable from pinned inputs, and the interpreter cache alone is
|
|
16
|
+
# tens of megabytes per target.
|
|
17
|
+
build/
|
|
18
|
+
|
|
19
|
+
# Isolated worktrees for parallel work, and the subagent-driven-development
|
|
20
|
+
# scratch area (ledgers, task briefs, review packages). Both are working state
|
|
21
|
+
# rebuilt on demand; the git history is the durable record.
|
|
22
|
+
.worktrees/
|
|
23
|
+
.superpowers/
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Aleš Dolenec
|
|
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.
|