tool-compass 2.3.0__tar.gz → 2.4.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.
Files changed (83) hide show
  1. {tool_compass-2.3.0 → tool_compass-2.4.0}/.env.example +4 -2
  2. {tool_compass-2.3.0 → tool_compass-2.4.0}/.github/workflows/ci.yml +8 -8
  3. {tool_compass-2.3.0 → tool_compass-2.4.0}/.github/workflows/publish.yml +64 -6
  4. tool_compass-2.4.0/.github/workflows/release-binaries.yml +175 -0
  5. tool_compass-2.4.0/.github/workflows/release.yml +165 -0
  6. {tool_compass-2.3.0 → tool_compass-2.4.0}/CHANGELOG.md +46 -0
  7. {tool_compass-2.3.0 → tool_compass-2.4.0}/PKG-INFO +13 -21
  8. {tool_compass-2.3.0 → tool_compass-2.4.0}/README.md +12 -20
  9. {tool_compass-2.3.0 → tool_compass-2.4.0}/SCORECARD.md +8 -8
  10. {tool_compass-2.3.0 → tool_compass-2.4.0}/SHIP_GATE.md +2 -2
  11. {tool_compass-2.3.0 → tool_compass-2.4.0}/analytics.py +103 -37
  12. {tool_compass-2.3.0 → tool_compass-2.4.0}/backend_client_mcp.py +34 -4
  13. {tool_compass-2.3.0 → tool_compass-2.4.0}/backend_client_simple.py +14 -3
  14. tool_compass-2.4.0/bootstrap.py +128 -0
  15. {tool_compass-2.3.0 → tool_compass-2.4.0}/chain_indexer.py +64 -2
  16. {tool_compass-2.3.0 → tool_compass-2.4.0}/cli.py +310 -50
  17. {tool_compass-2.3.0 → tool_compass-2.4.0}/compass_config.example.json +16 -1
  18. {tool_compass-2.3.0 → tool_compass-2.4.0}/config.py +291 -6
  19. {tool_compass-2.3.0 → tool_compass-2.4.0}/embedder.py +368 -25
  20. {tool_compass-2.3.0 → tool_compass-2.4.0}/gateway.py +297 -72
  21. {tool_compass-2.3.0 → tool_compass-2.4.0}/indexer.py +53 -9
  22. {tool_compass-2.3.0 → tool_compass-2.4.0}/pyproject.toml +17 -1
  23. {tool_compass-2.3.0 → tool_compass-2.4.0}/scripts/regenerate-scorecard.sh +7 -1
  24. {tool_compass-2.3.0 → tool_compass-2.4.0}/sync_manager.py +281 -26
  25. {tool_compass-2.3.0 → tool_compass-2.4.0}/tool_manifest.py +16 -2
  26. {tool_compass-2.3.0 → tool_compass-2.4.0}/ui.py +133 -29
  27. tool_compass-2.3.0/.github/workflows/release-binaries.yml +0 -268
  28. tool_compass-2.3.0/README.es.md +0 -346
  29. tool_compass-2.3.0/README.fr.md +0 -350
  30. tool_compass-2.3.0/README.hi.md +0 -342
  31. tool_compass-2.3.0/README.it.md +0 -350
  32. tool_compass-2.3.0/README.ja.md +0 -347
  33. tool_compass-2.3.0/README.pt-BR.md +0 -348
  34. tool_compass-2.3.0/README.zh.md +0 -346
  35. tool_compass-2.3.0/assets/logo.png +0 -0
  36. tool_compass-2.3.0/bootstrap.py +0 -80
  37. tool_compass-2.3.0/docs/assets/social-preview.png +0 -0
  38. tool_compass-2.3.0/docs/assets/social-preview.svg +0 -41
  39. tool_compass-2.3.0/docs/assets/tool-compass-logo-dark-bg.jpg +0 -0
  40. tool_compass-2.3.0/logo.png +0 -0
  41. tool_compass-2.3.0/npm/CHANGELOG.md +0 -338
  42. tool_compass-2.3.0/npm/LICENSE +0 -21
  43. tool_compass-2.3.0/npm/README.md +0 -171
  44. tool_compass-2.3.0/npm/bin/tool-compass.js +0 -14
  45. tool_compass-2.3.0/npm/package.json +0 -45
  46. tool_compass-2.3.0/npm/test/smoke.test.js +0 -54
  47. tool_compass-2.3.0/site/astro.config.mjs +0 -60
  48. tool_compass-2.3.0/site/package-lock.json +0 -7031
  49. tool_compass-2.3.0/site/package.json +0 -18
  50. tool_compass-2.3.0/site/src/content/docs/handbook/architecture.md +0 -143
  51. tool_compass-2.3.0/site/src/content/docs/handbook/beginners.md +0 -179
  52. tool_compass-2.3.0/site/src/content/docs/handbook/configuration.md +0 -137
  53. tool_compass-2.3.0/site/src/content/docs/handbook/getting-started.md +0 -177
  54. tool_compass-2.3.0/site/src/content/docs/handbook/index.md +0 -48
  55. tool_compass-2.3.0/site/src/content/docs/handbook/operations.md +0 -173
  56. tool_compass-2.3.0/site/src/content/docs/handbook/tools.md +0 -110
  57. tool_compass-2.3.0/site/src/content.config.ts +0 -7
  58. tool_compass-2.3.0/site/src/pages/index.astro +0 -33
  59. tool_compass-2.3.0/site/src/site-config.ts +0 -158
  60. tool_compass-2.3.0/site/src/styles/global.css +0 -3
  61. tool_compass-2.3.0/site/src/styles/starlight-custom.css +0 -17
  62. tool_compass-2.3.0/site/tsconfig.json +0 -5
  63. {tool_compass-2.3.0 → tool_compass-2.4.0}/.dockerignore +0 -0
  64. {tool_compass-2.3.0 → tool_compass-2.4.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  65. {tool_compass-2.3.0 → tool_compass-2.4.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  66. {tool_compass-2.3.0 → tool_compass-2.4.0}/.github/dependabot.yml +0 -0
  67. {tool_compass-2.3.0 → tool_compass-2.4.0}/.gitignore +0 -0
  68. {tool_compass-2.3.0 → tool_compass-2.4.0}/.pre-commit-config.yaml +0 -0
  69. {tool_compass-2.3.0 → tool_compass-2.4.0}/CODE_OF_CONDUCT.md +0 -0
  70. {tool_compass-2.3.0 → tool_compass-2.4.0}/CONTRIBUTING.md +0 -0
  71. {tool_compass-2.3.0 → tool_compass-2.4.0}/Dockerfile +0 -0
  72. {tool_compass-2.3.0 → tool_compass-2.4.0}/LICENSE +0 -0
  73. {tool_compass-2.3.0 → tool_compass-2.4.0}/Makefile +0 -0
  74. {tool_compass-2.3.0 → tool_compass-2.4.0}/SECURITY.md +0 -0
  75. {tool_compass-2.3.0 → tool_compass-2.4.0}/_version.py +0 -0
  76. {tool_compass-2.3.0 → tool_compass-2.4.0}/docker-compose.yml +0 -0
  77. {tool_compass-2.3.0 → tool_compass-2.4.0}/docs/index.md +0 -0
  78. {tool_compass-2.3.0 → tool_compass-2.4.0}/fly.toml +0 -0
  79. {tool_compass-2.3.0 → tool_compass-2.4.0}/llms.txt +0 -0
  80. {tool_compass-2.3.0 → tool_compass-2.4.0}/requirements-dev.txt +0 -0
  81. {tool_compass-2.3.0 → tool_compass-2.4.0}/requirements.txt +0 -0
  82. {tool_compass-2.3.0 → tool_compass-2.4.0}/scripts/check-org-urls.sh +0 -0
  83. {tool_compass-2.3.0 → tool_compass-2.4.0}/scripts/verify-metrics.sh +0 -0
@@ -55,8 +55,10 @@ GRADIO_SERVER_PORT=7860
55
55
  # Analytics (optional)
56
56
  # =============================================================================
57
57
 
58
- # Disable analytics tracking
58
+ # Disable analytics tracking (truthy: 1/true/yes/on). Overrides the
59
+ # analytics_enabled config-file key when set.
59
60
  # TOOL_COMPASS_ANALYTICS_DISABLED=true
60
61
 
61
- # Hot cache size (number of frequently used tools to pre-load)
62
+ # Hot cache size (number of frequently used tools to pre-load). Overrides the
63
+ # hot_cache_size config-file key; clamped to a safe minimum like any config value.
62
64
  # TOOL_COMPASS_HOT_CACHE_SIZE=10
@@ -86,12 +86,11 @@ jobs:
86
86
  continue-on-error: true
87
87
  uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1
88
88
 
89
- # CDS-FT-001: SCORECARD drift guard. Soft-fail for now shipcheck
90
- # markdown output is still settling. Flip continue-on-error to false
91
- # once the format stabilizes.
92
- # TODO(swarm): enforce once shipcheck JSON format stabilizes
89
+ # CDS-FT-001: SCORECARD drift guard now BLOCKING. The dogfood-swarm v3
90
+ # pass fixed CIDOCS-01 (regenerate-scorecard.sh forces NO_COLOR + strips
91
+ # ANSI), so `--check` diff-cleans deterministically in non-TTY CI. The
92
+ # committed SCORECARD was verified in sync at flip time.
93
93
  - name: Verify SCORECARD is in sync
94
- continue-on-error: true
95
94
  run: |
96
95
  if [ -f Makefile ] && grep -q "^verify-scorecard:" Makefile; then
97
96
  make verify-scorecard
@@ -202,12 +201,13 @@ jobs:
202
201
  # retention and is plenty of window for incident response.
203
202
  retention-days: 14
204
203
 
204
+ # Now BLOCKING. The dogfood-swarm v3 pass reviewed the CVE baseline:
205
+ # `pip-audit -r requirements.txt` reports no known vulnerabilities. The
206
+ # report-only artifact step above still runs for the full JSON snapshot.
205
207
  - name: Audit dependencies for vulnerabilities
206
208
  if: matrix.python-version == '3.11' && matrix.os == 'ubuntu-latest'
207
209
  run: |
208
210
  pip-audit -r requirements.txt
209
- # TODO(swarm): enforce after CVE baseline reviewed — issue #TBD
210
- continue-on-error: true # Warn-only until clean baseline established
211
211
 
212
212
  # TST-FT-002: nightly Hypothesis fuzzing. Runs on schedule (Mon/Wed/Fri 09:00
213
213
  # UTC) or manually via workflow_dispatch. Never runs on push/PR — nightly-only.
@@ -249,7 +249,7 @@ jobs:
249
249
  # SHA-pinned per SLSA L3 supply-chain hygiene (CT-B-001). nightly-fuzz
250
250
  # carries issues:write, so a compromised v7 mutable tag would inherit
251
251
  # issue-creation capability. Bump via dependabot's github-actions sweep.
252
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
252
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
253
253
  with:
254
254
  script: |
255
255
  const title = `[nightly-fuzz] Hypothesis failures on ${context.sha}`;
@@ -3,14 +3,32 @@
3
3
 
4
4
  name: Publish
5
5
 
6
+ # Triggers — the load-bearing one for the auto-chain is `workflow_run`:
7
+ # * `release: published` does NOT fire when the Release was created by
8
+ # release.yml using secrets.GITHUB_TOKEN (GitHub's recursion guard). Without
9
+ # the workflow_run trigger below, a tag-push release would publish to npm
10
+ # (via release.yml) but silently SKIP PyPI + GHCR here. The `workflow_run`
11
+ # trigger gated on Release.conclusion == 'success' closes the chain.
12
+ # * `release: published` retained for manual hand-cut Releases (gh release
13
+ # create from a maintainer's terminal — attributed to a user, fires normally).
14
+ # * `workflow_dispatch` retained for re-run-from-UI on transient failure.
6
15
  on:
7
16
  release:
8
17
  types: [published]
18
+ workflow_run:
19
+ workflows: [Release]
20
+ types: [completed]
9
21
  workflow_dispatch:
10
22
 
23
+ # Publish workflows must serialize, not cancel. Cancelling a mid-flight twine
24
+ # upload leaves PyPI in a state where the next retry fails with E409 ('File
25
+ # already exists') and needs manual --skip-existing recovery. Group per release
26
+ # tag — resolved across all trigger types (under workflow_run github.ref is the
27
+ # default branch, not the tag) — so distinct tags run independently while
28
+ # same-tag re-fires queue safely.
11
29
  concurrency:
12
- group: ${{ github.workflow }}-${{ github.ref }}
13
- cancel-in-progress: true
30
+ group: ${{ github.workflow }}-${{ github.event.workflow_run.head_branch || github.event.release.tag_name || github.ref }}
31
+ cancel-in-progress: false
14
32
 
15
33
  env:
16
34
  REGISTRY: ghcr.io
@@ -20,6 +38,11 @@ jobs:
20
38
  build:
21
39
  name: Build package
22
40
  runs-on: ubuntu-latest
41
+ # When triggered by workflow_run, only proceed if the upstream Release
42
+ # workflow succeeded. release: published / workflow_dispatch invocations set
43
+ # workflow_run to null, which evaluates this expression to truthy (we only
44
+ # want to short-circuit FAILED workflow_run events).
45
+ if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }}
23
46
  # CT-B-011: fail-fast budgets per SRE 'fail fast' (Google SRE Book ch.21).
24
47
  # Default GitHub timeout is 360 min; a wedged dependency install or twine
25
48
  # check is well outside the legitimate envelope at 10 min.
@@ -28,6 +51,11 @@ jobs:
28
51
  steps:
29
52
  - name: Checkout repository
30
53
  uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
54
+ with:
55
+ # Under workflow_run, github.ref is the default branch (main), NOT the
56
+ # tag — build the tagged commit, not main's HEAD. Resolve the tag from
57
+ # the single canonical expression used throughout this workflow.
58
+ ref: ${{ github.event.workflow_run.head_branch || github.event.release.tag_name || github.ref_name }}
31
59
 
32
60
  - name: Set up Python
33
61
  uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
@@ -107,6 +135,11 @@ jobs:
107
135
  steps:
108
136
  - name: Checkout repository
109
137
  uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
138
+ with:
139
+ # Under workflow_run, github.ref is main, NOT the tag — build the
140
+ # tagged commit, not main's HEAD. Same resolved-tag expression used
141
+ # throughout this workflow.
142
+ ref: ${{ github.event.workflow_run.head_branch || github.event.release.tag_name || github.ref_name }}
110
143
 
111
144
  - name: Log in to GHCR
112
145
  uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
@@ -115,14 +148,36 @@ jobs:
115
148
  username: ${{ github.actor }}
116
149
  password: ${{ secrets.GITHUB_TOKEN }}
117
150
 
151
+ # Resolve the release version explicitly. Under workflow_run github.ref
152
+ # points at the default branch (main), NOT the tag — so
153
+ # docker/metadata-action's type=semver rules (which only fire on a
154
+ # refs/tags/... ref) emit NOTHING and the image never gets a :X.Y.Z / :X.Y
155
+ # tag (only :latest + :sha-...). The tag that started the upstream Release
156
+ # run is carried on github.event.workflow_run.head_branch (= the tag ref).
157
+ # Feed the resolved version into metadata-action via type=raw below.
158
+ - name: Resolve release version
159
+ id: ver
160
+ shell: bash
161
+ run: |
162
+ set -euo pipefail
163
+ REF="${{ github.event.workflow_run.head_branch || github.event.release.tag_name || github.ref_name }}"
164
+ V="${REF#v}"
165
+ echo "version=${V}" >> "$GITHUB_OUTPUT"
166
+ echo "major_minor=$(echo "$V" | cut -d. -f1-2)" >> "$GITHUB_OUTPUT"
167
+ echo "resolved=${V} (event=${{ github.event_name }} ref=${REF})"
168
+
118
169
  - name: Extract metadata
119
170
  id: meta
120
171
  uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
121
172
  with:
122
173
  images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
174
+ # type=raw from the explicitly-resolved version (see Resolve step) —
175
+ # NOT type=semver, which silently emits nothing under workflow_run
176
+ # because github.ref is main, not the tag. Each enable=... gates its
177
+ # raw tag so an empty/missing version never pushes a bogus tag.
123
178
  tags: |
124
- type=semver,pattern={{version}}
125
- type=semver,pattern={{major}}.{{minor}}
179
+ type=raw,value=${{ steps.ver.outputs.version }},enable=${{ steps.ver.outputs.version != '' }}
180
+ type=raw,value=${{ steps.ver.outputs.major_minor }},enable=${{ steps.ver.outputs.major_minor != '' }}
126
181
  type=sha
127
182
  type=raw,value=latest,enable={{is_default_branch}}
128
183
 
@@ -131,7 +186,7 @@ jobs:
131
186
  # SHA-pinned per SLSA L3 supply-chain hygiene (CT-B-002). publish job
132
187
  # carries packages:write — a compromised mutable v3 tag would inherit
133
188
  # GHCR write capability during a release window. Bump via dependabot.
134
- uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3
189
+ uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4.1.0
135
190
 
136
191
  - name: Set up Docker Buildx
137
192
  uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
@@ -169,7 +224,10 @@ jobs:
169
224
  id: ver
170
225
  run: |
171
226
  set -euo pipefail
172
- TAG="${{ github.event.release.tag_name }}"
227
+ # Resolve the tag across all trigger types. Under workflow_run
228
+ # github.event.release.tag_name is null and github.ref is main —
229
+ # workflow_run.head_branch carries the tag ref (e.g. v2.4.0).
230
+ TAG="${{ github.event.workflow_run.head_branch || github.event.release.tag_name || github.ref_name }}"
173
231
  echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
174
232
  echo "version=${TAG#v}" >> "$GITHUB_OUTPUT"
175
233
 
@@ -0,0 +1,175 @@
1
+ # Builds platform binaries on release, uploads to the GitHub Release with
2
+ # SHA256 checksums. Consumed by the @mcptoolshop/tool-compass npm wrapper
3
+ # (via @mcptoolshop/npm-launcher) for zero-prerequisite `npx` installs.
4
+ #
5
+ # Asset naming convention (must match npm-launcher expectations):
6
+ # binary: tool-compass-<version>-<os>-<arch>[.exe]
7
+ # checksums: checksums-<version>.txt
8
+ name: Release Binaries
9
+
10
+ # Triggers — the load-bearing one for the auto-chain is `workflow_run`:
11
+ # * `release: published` does NOT fire when the Release was created by
12
+ # release.yml using secrets.GITHUB_TOKEN (GitHub's recursion guard). Without
13
+ # the workflow_run trigger below, a tag-push release would publish npm + PyPI
14
+ # but silently SKIP the platform binaries here (and the npm wrapper that
15
+ # depends on them). The `workflow_run` trigger gated on
16
+ # Release.conclusion == 'success' closes the chain.
17
+ # * `release: published` retained for manual hand-cut Releases (gh release
18
+ # create from a maintainer's terminal — attributed to a user, fires normally).
19
+ # * `workflow_dispatch` retained for manually (re)building binaries for a tag.
20
+ on:
21
+ release:
22
+ types: [published]
23
+ workflow_run:
24
+ workflows: [Release]
25
+ types: [completed]
26
+ workflow_dispatch:
27
+ inputs:
28
+ tag:
29
+ description: "Tag to build binaries for (e.g. v2.3.0)"
30
+ required: true
31
+ type: string
32
+
33
+ # Serialize per-tag — resolved across all trigger types (under workflow_run
34
+ # github.ref is the default branch, not the tag). Never cancel a mid-flight
35
+ # binary build / asset upload.
36
+ concurrency:
37
+ group: ${{ github.workflow }}-${{ github.event.workflow_run.head_branch || github.event.release.tag_name || github.ref }}
38
+ cancel-in-progress: false
39
+
40
+ env:
41
+ TOOL_NAME: tool-compass
42
+ ENTRYPOINT: cli.py
43
+
44
+ jobs:
45
+ build:
46
+ name: Build ${{ matrix.target }}
47
+ # When triggered by workflow_run, only proceed if the upstream Release
48
+ # workflow succeeded. release: published / workflow_dispatch invocations set
49
+ # workflow_run to null, which evaluates this expression to truthy (we only
50
+ # short-circuit FAILED workflow_run events).
51
+ if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }}
52
+ strategy:
53
+ fail-fast: false
54
+ matrix:
55
+ include:
56
+ - os: ubuntu-latest
57
+ target: linux-x64
58
+ ext: ""
59
+ - os: macos-latest
60
+ target: darwin-arm64
61
+ ext: ""
62
+ - os: windows-latest
63
+ target: win-x64
64
+ ext: ".exe"
65
+ runs-on: ${{ matrix.os }}
66
+ timeout-minutes: 25
67
+ steps:
68
+ - name: Checkout repository
69
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
70
+ with:
71
+ # Under workflow_run, github.ref is main, NOT the tag — check out the
72
+ # tagged commit so binaries are built from the released source.
73
+ ref: ${{ github.event.workflow_run.head_branch || github.event.release.tag_name || inputs.tag }}
74
+
75
+ - name: Set up Python
76
+ uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
77
+ with:
78
+ python-version: "3.12"
79
+
80
+ - name: Install package + PyInstaller
81
+ shell: bash
82
+ run: |
83
+ python -m pip install --upgrade pip
84
+ pip install . "pyinstaller>=6.9.0"
85
+
86
+ - name: Resolve version
87
+ id: version
88
+ shell: bash
89
+ run: |
90
+ # Resolve the tag across all trigger types. Under workflow_run
91
+ # github.event.release.tag_name is null — workflow_run.head_branch
92
+ # carries the tag ref. Asset names derive from this, so a stale value
93
+ # would name binaries tool-compass-main-... instead of -2.4.0-...
94
+ TAG="${{ github.event.workflow_run.head_branch || github.event.release.tag_name || inputs.tag }}"
95
+ VERSION="${TAG#v}"
96
+ echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
97
+ echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
98
+
99
+ - name: Build single-file binary
100
+ shell: bash
101
+ run: |
102
+ VERSION="${{ steps.version.outputs.version }}"
103
+ # --collect-submodules covers dynamic imports MCP / Gradio / Rich pull in.
104
+ # --console keeps stdout/stderr behavior identical to `python cli.py`.
105
+ pyinstaller --onefile \
106
+ --name "${{ env.TOOL_NAME }}" \
107
+ --console \
108
+ --collect-submodules mcp.client \
109
+ --collect-submodules mcp.server \
110
+ --collect-submodules mcp.types \
111
+ --collect-submodules mcp.shared \
112
+ --exclude-module mcp.cli \
113
+ --exclude-module typer \
114
+ --collect-submodules hnswlib \
115
+ --collect-submodules numpy \
116
+ --collect-submodules httpx \
117
+ "${{ env.ENTRYPOINT }}"
118
+ OUTNAME="${{ env.TOOL_NAME }}-${VERSION}-${{ matrix.target }}${{ matrix.ext }}"
119
+ mv "dist/${{ env.TOOL_NAME }}${{ matrix.ext }}" "dist/${OUTNAME}"
120
+ echo "Built: dist/${OUTNAME}"
121
+ ls -la "dist/${OUTNAME}"
122
+
123
+ - name: Smoke test binary
124
+ shell: bash
125
+ run: |
126
+ VERSION="${{ steps.version.outputs.version }}"
127
+ BIN="dist/${{ env.TOOL_NAME }}-${VERSION}-${{ matrix.target }}${{ matrix.ext }}"
128
+ # --version is wired on the root parser as of v2.2.1 (a942a67).
129
+ "$BIN" --version
130
+ "$BIN" --help
131
+
132
+ - name: Upload binary artifact
133
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
134
+ with:
135
+ name: binary-${{ matrix.target }}
136
+ path: dist/${{ env.TOOL_NAME }}-*
137
+ retention-days: 7
138
+
139
+ attach:
140
+ name: Attach binaries + checksums to release
141
+ needs: build
142
+ runs-on: ubuntu-latest
143
+ timeout-minutes: 5
144
+ permissions:
145
+ contents: write
146
+ steps:
147
+ - name: Download all binaries
148
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
149
+ with:
150
+ path: artifacts
151
+ merge-multiple: true
152
+
153
+ - name: Generate checksums
154
+ shell: bash
155
+ run: |
156
+ # Resolve the tag across all trigger types (see Resolve version notes).
157
+ # The checksum filename embeds VERSION, so a stale value would emit
158
+ # checksums-main.txt — which npm-launcher could never find.
159
+ TAG="${{ github.event.workflow_run.head_branch || github.event.release.tag_name || inputs.tag }}"
160
+ VERSION="${TAG#v}"
161
+ cd artifacts
162
+ sha256sum * > "checksums-${VERSION}.txt"
163
+ echo "--- checksums-${VERSION}.txt ---"
164
+ cat "checksums-${VERSION}.txt"
165
+
166
+ - name: Upload to GitHub Release
167
+ uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
168
+ with:
169
+ # Resolve the tag across all trigger types — under workflow_run the
170
+ # release context is null; head_branch carries the tag. A stale value
171
+ # would try to attach assets to a release named "main".
172
+ tag_name: ${{ github.event.workflow_run.head_branch || github.event.release.tag_name || inputs.tag }}
173
+ files: artifacts/*
174
+ fail_on_unmatched_files: true
175
+
@@ -0,0 +1,165 @@
1
+ # Tool Compass — npm Trusted Publisher (OIDC) + GitHub Release.
2
+ #
3
+ # This is the canonical npm publish path. The npm Trusted Publisher binding
4
+ # configured on npmjs.com for @mcptoolshop/tool-compass points at THIS file
5
+ # (.github/workflows/release.yml, workflow name "Release") — the filename and
6
+ # the `name:` below are load-bearing and MUST NOT be renamed.
7
+ #
8
+ # The GitHub Release this workflow creates (step "Create GitHub Release") is
9
+ # what fires the downstream chain: publish.yml (PyPI + GHCR + smoke) and
10
+ # release-binaries.yml (platform binaries + npm wrapper). Because that Release
11
+ # is created with secrets.GITHUB_TOKEN, the `release: published` event does NOT
12
+ # fire (GitHub's recursion guard) — the downstream workflows therefore key off
13
+ # a `workflow_run` trigger gated on this workflow's success. See their headers.
14
+ #
15
+ # The npm wrapper lives in the npm/ subdir (npm/package.json,
16
+ # npm/bin/tool-compass.js), so every npm step runs with working-directory: npm.
17
+ # The pyproject.toml version check runs at the repo root.
18
+ name: Release
19
+
20
+ on:
21
+ push:
22
+ tags: ['v*']
23
+ workflow_dispatch:
24
+
25
+ # Serialize per-tag releases; never cancel an in-flight release just because
26
+ # someone re-pushed the same tag or fired workflow_dispatch. Cancelling a
27
+ # mid-flight `npm publish` after the Sigstore-provenance attestation is signed
28
+ # but before the packument-save commits leaves the registry returning E409
29
+ # ('packument-save race') for 5-30 minutes on retry.
30
+ concurrency:
31
+ group: release-${{ github.ref }}
32
+ cancel-in-progress: false
33
+
34
+ permissions:
35
+ contents: write # for GitHub Release creation
36
+ id-token: write # for npm provenance via Sigstore OIDC
37
+
38
+ jobs:
39
+ release:
40
+ name: Publish to npm + GitHub Release
41
+ runs-on: ubuntu-latest
42
+ timeout-minutes: 15
43
+
44
+ steps:
45
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
46
+ with:
47
+ fetch-depth: 0
48
+
49
+ - name: Setup Node
50
+ uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
51
+ with:
52
+ node-version: 22
53
+ registry-url: 'https://registry.npmjs.org'
54
+
55
+ - name: Install npm >=11.5 in sandbox for OIDC trusted-publishing auth
56
+ run: |
57
+ # Node 22 ships npm 10.9, which signs Sigstore provenance fine but
58
+ # cannot negotiate the OIDC auth path for trusted publishing — the
59
+ # PUT returns a misleading 404 "not in this registry".
60
+ #
61
+ # An in-place `npm install -g npm@latest` races on Node 22's bundled
62
+ # npm 10.9 arborist rebuild and breaks irrecoverably (MODULE_NOT_FOUND:
63
+ # promise-retry). Sandbox install + PATH shadow avoids the race.
64
+ SANDBOX="$HOME/.npm-cli-sandbox"
65
+ mkdir -p "$SANDBOX"
66
+ pushd "$SANDBOX" >/dev/null
67
+ echo '{"name":"npm-cli-sandbox","version":"0.0.0","private":true}' > package.json
68
+ npm install --no-save --no-audit --no-fund --silent npm@latest
69
+ popd >/dev/null
70
+ echo "$SANDBOX/node_modules/.bin" >> "$GITHUB_PATH"
71
+ "$SANDBOX/node_modules/.bin/npm" --version
72
+
73
+ - name: Verify tag matches npm/package.json version
74
+ run: |
75
+ PKG_VERSION=$(node -p "require('./npm/package.json').version")
76
+ TAG_VERSION="${GITHUB_REF_NAME#v}"
77
+ echo "Tag: ${GITHUB_REF_NAME} → ${TAG_VERSION}"
78
+ echo "npm/package.json: ${PKG_VERSION}"
79
+ if [ "${PKG_VERSION}" != "${TAG_VERSION}" ]; then
80
+ echo "::error::Tag ${TAG_VERSION} does not match npm/package.json version ${PKG_VERSION}"
81
+ exit 1
82
+ fi
83
+
84
+ # ubuntu-latest's default python3 is not pinned to a particular minor
85
+ # version. tomllib lives in Python 3.11+ stdlib — falling through to a
86
+ # 3.10 default would ImportError. Pin 3.11 explicitly (same setup-python
87
+ # SHA as ci.yml + publish.yml) so the version check is reproducible.
88
+ - name: Setup Python for pyproject version check
89
+ uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
90
+ with:
91
+ python-version: '3.11'
92
+
93
+ - name: Verify tag matches pyproject.toml version
94
+ run: |
95
+ PY_VERSION=$(python3 -c "import tomllib; print(tomllib.loads(open('pyproject.toml').read())['project']['version'])")
96
+ TAG_VERSION="${GITHUB_REF_NAME#v}"
97
+ echo "pyproject.toml: ${PY_VERSION}"
98
+ if [ "${PY_VERSION}" != "${TAG_VERSION}" ]; then
99
+ echo "::error::Tag ${TAG_VERSION} does not match pyproject.toml version ${PY_VERSION}"
100
+ exit 1
101
+ fi
102
+
103
+ # The npm wrapper's bin shim hard-codes the release tag (it points
104
+ # npm-launcher at the GitHub Release binaries for this exact tag). A stale
105
+ # tag here would make `npx tool-compass` fetch the wrong release's
106
+ # binaries. Verify the shim was synced before we publish.
107
+ - name: Verify npm/bin/tool-compass.js references the tag
108
+ run: |
109
+ if ! grep -Fq "${GITHUB_REF_NAME}" npm/bin/tool-compass.js; then
110
+ echo "::error::npm/bin/tool-compass.js does not reference ${GITHUB_REF_NAME} — run scripts/sync-version.mjs before tagging"
111
+ exit 1
112
+ fi
113
+ echo "npm/bin/tool-compass.js references ${GITHUB_REF_NAME} ✓"
114
+
115
+ # No package-lock.json is committed (sole runtime dep is
116
+ # @mcptoolshop/npm-launcher, digest-locked by the registry). `npm install`
117
+ # is the honest path here.
118
+ - name: Install npm wrapper dependencies
119
+ working-directory: npm
120
+ run: npm install --no-audit --no-fund
121
+
122
+ - name: npm pack dry-run (verify shape)
123
+ working-directory: npm
124
+ run: npm pack --dry-run
125
+
126
+ - name: Publish to npm with provenance (OIDC trusted publisher)
127
+ working-directory: npm
128
+ # OIDC trusted publisher — NO token, NO NODE_AUTH_TOKEN. The
129
+ # id-token: write permission + the npm@latest installed above negotiate
130
+ # the auth path. --access public is required for the scoped package.
131
+ run: npm publish --provenance --access public
132
+
133
+ - name: Create GitHub Release (idempotent)
134
+ env:
135
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
136
+ run: |
137
+ # Extract the [<version>] section from CHANGELOG.md as the release
138
+ # notes. Falls back to the tag name if the section is missing/empty.
139
+ VERSION="${GITHUB_REF_NAME#v}"
140
+ NOTES_FILE="$(mktemp)"
141
+ awk -v ver="${VERSION}" '
142
+ $0 ~ "^## \\[" ver "\\]" {capture=1; next}
143
+ capture && /^## \[/ {exit}
144
+ capture {print}
145
+ ' CHANGELOG.md > "${NOTES_FILE}"
146
+
147
+ if [ ! -s "${NOTES_FILE}" ]; then
148
+ echo "Tool Compass ${GITHUB_REF_NAME}" > "${NOTES_FILE}"
149
+ echo "" >> "${NOTES_FILE}"
150
+ echo "See CHANGELOG.md for details." >> "${NOTES_FILE}"
151
+ fi
152
+
153
+ # Create the release only if it doesn't already exist. This Release is
154
+ # what fires the downstream workflow_run chain (publish.yml +
155
+ # release-binaries.yml). Skipping when it exists makes the step
156
+ # idempotent on workflow_dispatch re-runs / second tag pushes (no
157
+ # HTTP 422 "tag_name already exists").
158
+ if gh release view "${GITHUB_REF_NAME}" >/dev/null 2>&1; then
159
+ echo "Release ${GITHUB_REF_NAME} already exists; skipping create."
160
+ else
161
+ gh release create "${GITHUB_REF_NAME}" \
162
+ --title "Tool Compass ${GITHUB_REF_NAME}" \
163
+ --notes-file "${NOTES_FILE}" \
164
+ --verify-tag
165
+ fi
@@ -7,6 +7,52 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.4.0] - 2026-06-20
11
+
12
+ Dogfood swarm v3 — full health pass (bug/security → proactive → humanization
13
+ → visual) + a user-scoped feature pass. Tests 991 → 1151; ruff errors 31 → 0.
14
+ No breaking changes; the default config path, the Ollama embedding default,
15
+ and all existing tool/CLI behavior are unchanged.
16
+
17
+ ### Added
18
+ - **`tool-compass init`** — scaffolds `compass_config.json` at the resolved
19
+ config path and prints a ready-to-paste Claude Desktop `mcpServers` snippet.
20
+ `--force` to overwrite, `--json` for machine output.
21
+ - **Pluggable embedding backend** — `embedding_provider` config selects the
22
+ embedder: `ollama` (default, unchanged) or `openai`/`openai-compatible`
23
+ (`/v1/embeddings`; covers OpenAI, LM Studio, and any compatible server),
24
+ with `embedding_base_url`, `embedding_api_key` (redacted;
25
+ `TOOL_COMPASS_EMBEDDING_API_KEY` env override), and prefix overrides.
26
+ - MCP-client registration recipes (Claude Desktop, Cursor, Cline) in the handbook.
27
+ - `LOG_LEVEL`, `TOOL_COMPASS_ANALYTICS_DISABLED`, and
28
+ `TOOL_COMPASS_HOT_CACHE_SIZE` env overrides are now honored (previously
29
+ advertised in `.env.example` but ignored).
30
+
31
+ ### Fixed
32
+ - **`tool-compass serve` / `serve --http`** crashed with "unrecognized
33
+ arguments: serve" — the CLI now neutralizes `sys.argv` before delegating to
34
+ the gateway.
35
+ - Oversize backend lines (>1 MiB) no longer wedge a connection — the read loop
36
+ caught the wrong exception type (`LimitOverrunError` vs the `ValueError`
37
+ `readline()` actually raises).
38
+ - `config doctor`/`show_config` no longer leak `${VAR}`-resolved secrets in
39
+ backend `headers`/`env`/`args` or credentialed `ollama_url`/backend URLs.
40
+ - Cold-start (`get_index()` RuntimeError) now returns the structured
41
+ service-unavailable envelope on every read tool instead of a raw stack.
42
+ - `tool-compass sync` reports the honest indexed count + warns on backends
43
+ that failed to connect (was a fabricated "+0 ~0 -0" line); per-backend sync
44
+ status is now durable (a failing backend stops reporting healthy).
45
+ - `gateway.py --sync` exits non-zero when it indexes nothing (CI-safe).
46
+ - Gradio UI: pinned the dark theme surface (the UI was invisible in light
47
+ mode); Status tab now probes the configured Ollama; empty index shows a
48
+ "run sync" card.
49
+ - Cross-event-loop `RuntimeError` in the embedder semaphore + gateway locks
50
+ (per-loop keying); several unguarded `json.loads`/error paths hardened.
51
+
52
+ ### Changed
53
+ - Lint gate cleaned (31 ruff errors → 0); 4 vacuous/skip-masking tests
54
+ hardened so `/ready` + `/metrics` now have executing coverage.
55
+
10
56
  ## [2.3.0] - 2026-05-15
11
57
 
12
58
  Dogfood swarm v2 release — comprehensive Stage A bug/security pass +
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tool-compass
3
- Version: 2.3.0
3
+ Version: 2.4.0
4
4
  Summary: Semantic MCP tool discovery gateway - find tools by intent, not memory
5
5
  Project-URL: Homepage, https://github.com/mcp-tool-shop-org/tool-compass
6
6
  Project-URL: Documentation, https://github.com/mcp-tool-shop-org/tool-compass#readme
@@ -86,14 +86,6 @@ Savings: 95%
86
86
 
87
87
  Tool Compass uses **semantic search** to find relevant tools from a natural language description. Instead of loading all tools, Claude calls `compass()` with an intent and gets back only the relevant tools.
88
88
 
89
- <!--
90
- ## Demo
91
-
92
- <p align="center">
93
- <img src="docs/assets/demo.gif" alt="Tool Compass Demo" width="600">
94
- </p>
95
- -->
96
-
97
89
  ## Quick Start
98
90
 
99
91
  📖 **Full documentation:** See the [Tool Compass Handbook](https://mcp-tool-shop-org.github.io/tool-compass/handbook/) for installation, configuration, and architecture deep-dives.
@@ -177,20 +169,20 @@ docker-compose --profile with-ollama up
177
169
 
178
170
  ```
179
171
  ┌─────────────────────────────────────────────────────────────┐
180
- TOOL COMPASS
172
+ TOOL COMPASS
181
173
  │ │
182
- │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
183
- │ │ Ollama │ │ hnswlib │ │ SQLite │
184
- │ │ Embedder │───▶│ HNSW │◀───│ Metadata │
185
- │ │ (nomic) │ │ Index │ │ Store │
186
- │ └──────────────┘ └──────────────┘ └──────────────┘
174
+ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
175
+ │ │ Ollama │ │ hnswlib │ │ SQLite │
176
+ │ │ Embedder │───▶│ HNSW │◀───│ Metadata │
177
+ │ │ (nomic) │ │ Index │ │ Store │
178
+ │ └──────────────┘ └──────────────┘ └──────────────┘
187
179
  │ │ │
188
180
  │ ▼ │
189
- ┌──────────────────┐
190
- │ │ Gateway (9 tools)│ │
191
- │ │ compass, describe│ │
192
- │ │ execute, etc. │ │
193
- └──────────────────┘
181
+ ┌───────────────────┐
182
+ │ │ Gateway (9 tools) │ │
183
+ │ │ compass, describe │ │
184
+ │ │ execute, etc. │ │
185
+ └───────────────────┘
194
186
  └─────────────────────────────────────────────────────────────┘
195
187
  ```
196
188
 
@@ -341,7 +333,7 @@ ollama pull nomic-embed-text
341
333
  ### Index Not Found
342
334
 
343
335
  ```bash
344
- python gateway.py --sync
336
+ tool-compass sync
345
337
  ```
346
338
 
347
339
  ## Related Projects