onde-cli 0.4.0__tar.gz → 0.4.2__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 (77) hide show
  1. {onde_cli-0.4.0 → onde_cli-0.4.2}/.agents/AGENTS.md +1 -0
  2. {onde_cli-0.4.0 → onde_cli-0.4.2}/.agents/skills/distribution/SKILL.md +28 -0
  3. onde_cli-0.4.2/.github/workflows/release-crates.yml +217 -0
  4. {onde_cli-0.4.0 → onde_cli-0.4.2}/.github/workflows/release-github.yml +55 -6
  5. {onde_cli-0.4.0 → onde_cli-0.4.2}/.github/workflows/release-homebrew.yml +1 -1
  6. onde_cli-0.4.2/.github/workflows/release-mcp-registry.yml +130 -0
  7. {onde_cli-0.4.0 → onde_cli-0.4.2}/.github/workflows/release-npm.yml +2 -4
  8. {onde_cli-0.4.0 → onde_cli-0.4.2}/.github/workflows/release-nuget.yml +25 -4
  9. {onde_cli-0.4.0 → onde_cli-0.4.2}/.github/workflows/release-pub.yml +1 -1
  10. {onde_cli-0.4.0 → onde_cli-0.4.2}/.github/workflows/release-pypi.yml +2 -4
  11. onde_cli-0.4.2/.github/workflows/release-scoop.yml +148 -0
  12. onde_cli-0.4.2/.github/workflows/release-winget.yml +178 -0
  13. {onde_cli-0.4.0 → onde_cli-0.4.2}/.gitignore +3 -0
  14. onde_cli-0.4.2/.sigit/code-cloud-agent/config.toml +2 -0
  15. onde_cli-0.4.2/.sigit/code-review/config.toml +3 -0
  16. onde_cli-0.4.2/.sigit/factory/config.toml +9 -0
  17. {onde_cli-0.4.0 → onde_cli-0.4.2}/AGENTS.md +1 -0
  18. {onde_cli-0.4.0 → onde_cli-0.4.2}/CLAUDE.md +1 -0
  19. {onde_cli-0.4.0 → onde_cli-0.4.2}/Cargo.lock +837 -303
  20. {onde_cli-0.4.0 → onde_cli-0.4.2}/Cargo.toml +2 -2
  21. {onde_cli-0.4.0 → onde_cli-0.4.2}/PKG-INFO +1 -1
  22. onde_cli-0.4.2/docs/mcp-registry.md +109 -0
  23. {onde_cli-0.4.0 → onde_cli-0.4.2}/npm/package-main.json.tmpl +1 -0
  24. onde_cli-0.4.2/packaging/winget/OndeInference.onde-cli.installer.yaml.in +18 -0
  25. onde_cli-0.4.2/packaging/winget/OndeInference.onde-cli.locale.en-US.yaml.in +34 -0
  26. onde_cli-0.4.2/packaging/winget/OndeInference.onde-cli.yaml.in +6 -0
  27. {onde_cli-0.4.0 → onde_cli-0.4.2}/pub/onde_cli/CHANGELOG.md +4 -0
  28. {onde_cli-0.4.0 → onde_cli-0.4.2}/pub/onde_cli/pubspec.yaml +1 -1
  29. onde_cli-0.4.2/server.json +81 -0
  30. {onde_cli-0.4.0 → onde_cli-0.4.2}/src/chat.rs +7 -0
  31. {onde_cli-0.4.0 → onde_cli-0.4.2}/src/main.rs +37 -1
  32. onde_cli-0.4.0/.github/workflows/release-crates.yml +0 -104
  33. {onde_cli-0.4.0 → onde_cli-0.4.2}/.agents/skills/git/SKILL.md +0 -0
  34. {onde_cli-0.4.0 → onde_cli-0.4.2}/.github/workflows/ci.yml +0 -0
  35. {onde_cli-0.4.0 → onde_cli-0.4.2}/.nuget/NuGet/NuGet.Config +0 -0
  36. {onde_cli-0.4.0 → onde_cli-0.4.2}/.nvmrc +0 -0
  37. {onde_cli-0.4.0 → onde_cli-0.4.2}/LICENSE +0 -0
  38. {onde_cli-0.4.0 → onde_cli-0.4.2}/README.md +0 -0
  39. {onde_cli-0.4.0 → onde_cli-0.4.2}/assets/ondeinference-apps.png +0 -0
  40. {onde_cli-0.4.0 → onde_cli-0.4.2}/build.rs +0 -0
  41. {onde_cli-0.4.0 → onde_cli-0.4.2}/npm/README.md.tmpl +0 -0
  42. {onde_cli-0.4.0 → onde_cli-0.4.2}/npm/onde-cli/.gitignore +0 -0
  43. {onde_cli-0.4.0 → onde_cli-0.4.2}/npm/onde-cli/README.md +0 -0
  44. {onde_cli-0.4.0 → onde_cli-0.4.2}/npm/onde-cli/package-lock.json +0 -0
  45. {onde_cli-0.4.0 → onde_cli-0.4.2}/npm/onde-cli/package.json +0 -0
  46. {onde_cli-0.4.0 → onde_cli-0.4.2}/npm/onde-cli/src/index.ts +0 -0
  47. {onde_cli-0.4.0 → onde_cli-0.4.2}/npm/onde-cli/tsconfig.json +0 -0
  48. {onde_cli-0.4.0 → onde_cli-0.4.2}/npm/package.json.tmpl +0 -0
  49. {onde_cli-0.4.0 → onde_cli-0.4.2}/npm/scripts/render-main-package.cjs +0 -0
  50. {onde_cli-0.4.0 → onde_cli-0.4.2}/npm/scripts/render-platform-package.cjs +0 -0
  51. {onde_cli-0.4.0 → onde_cli-0.4.2}/nuget/.gitignore +0 -0
  52. {onde_cli-0.4.0 → onde_cli-0.4.2}/nuget/onde-cli/Onde.Cli.csproj +0 -0
  53. {onde_cli-0.4.0 → onde_cli-0.4.2}/nuget/onde-cli/Program.cs +0 -0
  54. {onde_cli-0.4.0 → onde_cli-0.4.2}/nuget/onde-cli/README.md +0 -0
  55. {onde_cli-0.4.0 → onde_cli-0.4.2}/pub/onde_cli/.gitignore +0 -0
  56. {onde_cli-0.4.0 → onde_cli-0.4.2}/pub/onde_cli/.pubignore +0 -0
  57. {onde_cli-0.4.0 → onde_cli-0.4.2}/pub/onde_cli/LICENSE +0 -0
  58. {onde_cli-0.4.0 → onde_cli-0.4.2}/pub/onde_cli/README.md +0 -0
  59. {onde_cli-0.4.0 → onde_cli-0.4.2}/pub/onde_cli/bin/onde.dart +0 -0
  60. {onde_cli-0.4.0 → onde_cli-0.4.2}/pub/onde_cli/lib/onde_cli.dart +0 -0
  61. {onde_cli-0.4.0 → onde_cli-0.4.2}/pypi/README.md +0 -0
  62. {onde_cli-0.4.0 → onde_cli-0.4.2}/pypi/pyproject.toml +0 -0
  63. {onde_cli-0.4.0 → onde_cli-0.4.2}/pyproject.toml +0 -0
  64. {onde_cli-0.4.0 → onde_cli-0.4.2}/rust-toolchain.toml +0 -0
  65. {onde_cli-0.4.0 → onde_cli-0.4.2}/src/app.rs +0 -0
  66. {onde_cli-0.4.0 → onde_cli-0.4.2}/src/finetune.rs +0 -0
  67. {onde_cli-0.4.0 → onde_cli-0.4.2}/src/gguf.rs +0 -0
  68. {onde_cli-0.4.0 → onde_cli-0.4.2}/src/gresiq.rs +0 -0
  69. {onde_cli-0.4.0 → onde_cli-0.4.2}/src/hf.rs +0 -0
  70. {onde_cli-0.4.0 → onde_cli-0.4.2}/src/hf_clone.rs +0 -0
  71. {onde_cli-0.4.0 → onde_cli-0.4.2}/src/hf_search.rs +0 -0
  72. {onde_cli-0.4.0 → onde_cli-0.4.2}/src/hf_upload.rs +0 -0
  73. {onde_cli-0.4.0 → onde_cli-0.4.2}/src/mcp.rs +0 -0
  74. {onde_cli-0.4.0 → onde_cli-0.4.2}/src/merge.rs +0 -0
  75. {onde_cli-0.4.0 → onde_cli-0.4.2}/src/project.rs +0 -0
  76. {onde_cli-0.4.0 → onde_cli-0.4.2}/src/token.rs +0 -0
  77. {onde_cli-0.4.0 → onde_cli-0.4.2}/src/ui.rs +0 -0
@@ -64,6 +64,7 @@ The `onde` crate provides the inference engine (`onde::mistralrs`, a vendored mi
64
64
  - **Commits:** include `Co-Authored-By: siGit Code <297239231+sigitc@users.noreply.github.com>` trailer when committing with the agent.
65
65
  - **`[patch.crates-io]` and `path =` deps:** commented out in `Cargo.toml` for local dev against `onde`/`smbcloud-*`/`candle`. Never commit with these uncommented.
66
66
  - **Distribution:** before touching any wrapper package (npm, PyPI, NuGet, pub.dev, Homebrew), read `.agents/skills/distribution/SKILL.md`. Keep all channel versions aligned with the Rust crate version in `Cargo.toml`.
67
+ - **MCP Registry:** the listing's ownership markers ship inside the published npm and NuGet artifacts, so a version published without them can never be listed. See `docs/mcp-registry.md` before touching `server.json` or either marker.
67
68
  - **Wrapper packages** are in `npm/`, `pypi/`, `nuget/`, `pub/`. The npm base manifest is rewritten at release time by `npm/scripts/render-main-package.cjs`; do not hand-edit committed package.json versions as the source of truth for releases.
68
69
  - **Clippy** runs with `-D warnings` in CI; all lints must pass.
69
70
  - **Rust edition:** 2024; toolchain: stable.
@@ -110,6 +110,34 @@ If a wrapper uses one naming scheme and a workflow uploads another, the installe
110
110
 
111
111
  ## Release workflow principles
112
112
 
113
+ ### One tag trigger, then fan out
114
+
115
+ `release-crates.yml` is the only workflow that reacts to a tag push. It verifies the
116
+ tag against `Cargo.toml` and `pubspec.yaml`, publishes the crate, then dispatches
117
+ `release-github`, `release-npm`, `release-nuget`, and `release-pypi` with the same tag.
118
+ `release-github` in turn dispatches `release-homebrew` and `release-pub` after the
119
+ release assets exist.
120
+
121
+ ```
122
+ tag push
123
+ └─ release-crates (verify -> publish -> dispatch)
124
+ ├─ release-github ─┬─ release-homebrew
125
+ │ └─ release-pub
126
+ ├─ release-npm
127
+ ├─ release-nuget
128
+ └─ release-pypi
129
+ ```
130
+
131
+ This mirrors `smbcloud-cli`. Two properties matter:
132
+
133
+ - crates.io is the gate. If verify or publish fails, no wrapper publishes a version
134
+ that has no crate behind it.
135
+ - every dispatch passes `ref: <tag>`, not `ref: main`, so downstream workflows run the
136
+ workflow definition from the release state instead of whatever `main` happens to be.
137
+
138
+ Do not add `push: tags:` to a wrapper workflow. Several workflows racing on the same tag
139
+ is what lets the pub.dev launcher publish before its GitHub Release assets exist.
140
+
113
141
  ### Build first, package second
114
142
 
115
143
  Always build native binaries in a target matrix first.
@@ -0,0 +1,217 @@
1
+ name: Release crates.io
2
+
3
+ # This is the only workflow that reacts to a tag push. It verifies the tag,
4
+ # publishes the crate, and then dispatches every distribution workflow with the
5
+ # same tag. Wrappers never publish for a crate release that failed.
6
+
7
+ on:
8
+ push:
9
+ tags:
10
+ - "v*.*.*"
11
+ workflow_dispatch:
12
+ inputs:
13
+ tag:
14
+ description: "Release tag (e.g. v0.4.0)"
15
+ required: true
16
+
17
+ permissions:
18
+ contents: read
19
+ actions: write
20
+
21
+ concurrency:
22
+ group: release-crates-${{ github.ref }}
23
+ cancel-in-progress: false
24
+
25
+ env:
26
+ CARGO_TERM_COLOR: always
27
+ ONDE_APP_ID: ${{ secrets.ONDE_APP_ID }}
28
+ ONDE_APP_SECRET: ${{ secrets.ONDE_APP_SECRET }}
29
+ GRESIQ_API_KEY: ${{ secrets.GRESIQ_API_KEY }}
30
+ GRESIQ_API_SECRET: ${{ secrets.GRESIQ_API_SECRET }}
31
+ HF_TOKEN: ${{ secrets.HF_TOKEN }}
32
+
33
+ jobs:
34
+ verify:
35
+ name: Verify release
36
+ runs-on: ubuntu-latest
37
+ outputs:
38
+ version: ${{ steps.release.outputs.version }}
39
+ tag: ${{ steps.release.outputs.tag }}
40
+ steps:
41
+ - name: Checkout
42
+ uses: actions/checkout@v6
43
+ with:
44
+ ref: ${{ github.event.inputs.tag || github.ref }}
45
+
46
+ - name: Read Rust toolchain
47
+ shell: bash
48
+ run: |
49
+ rust_toolchain="$(sed -n 's/^channel = "\(.*\)"/\1/p' rust-toolchain.toml | head -n 1)"
50
+ if [ -z "$rust_toolchain" ]; then
51
+ echo "Failed to read Rust toolchain from rust-toolchain.toml" >&2
52
+ exit 1
53
+ fi
54
+ echo "RUST_TOOLCHAIN=${rust_toolchain}" >> "$GITHUB_ENV"
55
+
56
+ - name: Install Rust toolchain
57
+ uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9
58
+ with:
59
+ toolchain: ${{ env.RUST_TOOLCHAIN }}
60
+ components: clippy, rustfmt
61
+
62
+ - name: Cache cargo registry and build artifacts
63
+ uses: Swatinem/rust-cache@v2
64
+
65
+ - name: Set the release version
66
+ id: release
67
+ shell: bash
68
+ run: |
69
+ if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
70
+ release_tag="${GITHUB_REF_NAME}"
71
+ else
72
+ release_tag="${{ github.event.inputs.tag }}"
73
+ release_tag="${release_tag#refs/tags/}"
74
+ fi
75
+ release_version="${release_tag#v}"
76
+
77
+ echo "tag=${release_tag}" >> "$GITHUB_OUTPUT"
78
+ echo "version=${release_version}" >> "$GITHUB_OUTPUT"
79
+
80
+ - name: Ensure tag matches Cargo.toml version
81
+ shell: bash
82
+ run: |
83
+ version="$(sed -n 's/^version = "\(.*\)"/\1/p' Cargo.toml | head -n 1)"
84
+ if [ -z "$version" ]; then
85
+ echo "::error::Failed to read package version from Cargo.toml"
86
+ exit 1
87
+ fi
88
+ if [ "$version" != "${{ steps.release.outputs.version }}" ]; then
89
+ echo "::error::Cargo.toml is ${version} but the tag is ${{ steps.release.outputs.version }}"
90
+ exit 1
91
+ fi
92
+
93
+ - name: Ensure the pub.dev wrapper matches the tag
94
+ shell: bash
95
+ run: |
96
+ pub_version="$(sed -n 's/^version: \(.*\)/\1/p' pub/onde_cli/pubspec.yaml | head -n 1)"
97
+ if [ "$pub_version" != "${{ steps.release.outputs.version }}" ]; then
98
+ echo "::error::pubspec.yaml is ${pub_version} but the tag is ${{ steps.release.outputs.version }}"
99
+ exit 1
100
+ fi
101
+
102
+ - name: Check formatting
103
+ run: cargo fmt --all -- --check
104
+
105
+ - name: Run clippy
106
+ run: cargo clippy --all-targets --all-features -- -D warnings
107
+
108
+ - name: Run tests
109
+ run: cargo test --all-features --locked --verbose
110
+
111
+ - name: Run cargo check
112
+ run: cargo check --locked
113
+
114
+ - name: Verify package contents
115
+ run: cargo package --locked --allow-dirty
116
+
117
+ publish:
118
+ name: Publish to crates.io
119
+ runs-on: ubuntu-latest
120
+ needs: verify
121
+ environment:
122
+ name: crates-io
123
+ permissions:
124
+ contents: read
125
+ steps:
126
+ - name: Checkout
127
+ uses: actions/checkout@v6
128
+ with:
129
+ ref: ${{ github.event.inputs.tag || github.ref }}
130
+
131
+ - name: Read Rust toolchain
132
+ shell: bash
133
+ run: |
134
+ rust_toolchain="$(sed -n 's/^channel = "\(.*\)"/\1/p' rust-toolchain.toml | head -n 1)"
135
+ echo "RUST_TOOLCHAIN=${rust_toolchain}" >> "$GITHUB_ENV"
136
+
137
+ - name: Install Rust toolchain
138
+ uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9
139
+ with:
140
+ toolchain: ${{ env.RUST_TOOLCHAIN }}
141
+
142
+ - name: Cache cargo registry and build artifacts
143
+ uses: Swatinem/rust-cache@v2
144
+
145
+ - name: Publish crate
146
+ env:
147
+ CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
148
+ shell: bash
149
+ run: |
150
+ version="${{ needs.verify.outputs.version }}"
151
+ if curl -sSf "https://crates.io/api/v1/crates/onde-cli/${version}" >/dev/null 2>&1; then
152
+ echo "onde-cli ${version} is already on crates.io, skipping publish"
153
+ exit 0
154
+ fi
155
+ cargo publish --locked
156
+
157
+ dispatch-distributions:
158
+ name: Trigger distribution workflows
159
+ needs: [verify, publish]
160
+ runs-on: ubuntu-latest
161
+
162
+ steps:
163
+ - name: Trigger GitHub release
164
+ uses: actions/github-script@v7
165
+ with:
166
+ script: |
167
+ await github.rest.actions.createWorkflowDispatch({
168
+ owner: context.repo.owner,
169
+ repo: context.repo.repo,
170
+ workflow_id: 'release-github.yml',
171
+ ref: '${{ needs.verify.outputs.tag }}',
172
+ inputs: {
173
+ tag: '${{ needs.verify.outputs.tag }}'
174
+ }
175
+ })
176
+
177
+ - name: Trigger npm release
178
+ uses: actions/github-script@v7
179
+ with:
180
+ script: |
181
+ await github.rest.actions.createWorkflowDispatch({
182
+ owner: context.repo.owner,
183
+ repo: context.repo.repo,
184
+ workflow_id: 'release-npm.yml',
185
+ ref: '${{ needs.verify.outputs.tag }}',
186
+ inputs: {
187
+ tag: '${{ needs.verify.outputs.tag }}'
188
+ }
189
+ })
190
+
191
+ - name: Trigger NuGet release
192
+ uses: actions/github-script@v7
193
+ with:
194
+ script: |
195
+ await github.rest.actions.createWorkflowDispatch({
196
+ owner: context.repo.owner,
197
+ repo: context.repo.repo,
198
+ workflow_id: 'release-nuget.yml',
199
+ ref: '${{ needs.verify.outputs.tag }}',
200
+ inputs: {
201
+ tag: '${{ needs.verify.outputs.tag }}'
202
+ }
203
+ })
204
+
205
+ - name: Trigger PyPI release
206
+ uses: actions/github-script@v7
207
+ with:
208
+ script: |
209
+ await github.rest.actions.createWorkflowDispatch({
210
+ owner: context.repo.owner,
211
+ repo: context.repo.repo,
212
+ workflow_id: 'release-pypi.yml',
213
+ ref: '${{ needs.verify.outputs.tag }}',
214
+ inputs: {
215
+ tag: '${{ needs.verify.outputs.tag }}'
216
+ }
217
+ })
@@ -1,13 +1,11 @@
1
1
  name: GitHub Release
2
2
 
3
+ # Dispatched by release-crates.yml once the crate publish succeeds.
3
4
  on:
4
- push:
5
- tags:
6
- - "v*.*.*"
7
5
  workflow_dispatch:
8
6
  inputs:
9
7
  tag:
10
- description: "Release tag (e.g. v0.3.1)"
8
+ description: "Release tag (e.g. v0.4.0)"
11
9
  required: true
12
10
 
13
11
  permissions:
@@ -124,6 +122,25 @@ jobs:
124
122
  echo "Archive: ${ARCHIVE_NAME}"
125
123
  echo "SHA256: $(cat "${ARCHIVE_NAME}.sha256")"
126
124
 
125
+ # Scoop and winget consume the raw Windows binaries rather than a
126
+ # tarball, and both need a SHA256 sidecar. Windows runners use bash from
127
+ # Git for Windows, which has sha256sum; macOS only has shasum.
128
+ - name: Checksum release assets
129
+ shell: bash
130
+ run: |
131
+ cd release
132
+ for asset in *; do
133
+ case "${asset}" in *.sha256) continue ;; esac
134
+
135
+ if command -v sha256sum >/dev/null 2>&1; then
136
+ sha256sum "${asset}" | awk '{print $1}' > "${asset}.sha256"
137
+ else
138
+ shasum -a 256 "${asset}" | awk '{print $1}' > "${asset}.sha256"
139
+ fi
140
+
141
+ echo "${asset}: $(cat "${asset}.sha256")"
142
+ done
143
+
127
144
  - name: Upload binary artifact
128
145
  uses: actions/upload-artifact@v4
129
146
  with:
@@ -184,7 +201,7 @@ jobs:
184
201
  owner: context.repo.owner,
185
202
  repo: context.repo.repo,
186
203
  workflow_id: 'release-homebrew.yml',
187
- ref: 'main',
204
+ ref: '${{ steps.tag.outputs.tag }}',
188
205
  inputs: {
189
206
  tag: '${{ steps.tag.outputs.tag }}'
190
207
  }
@@ -199,9 +216,41 @@ jobs:
199
216
  owner: context.repo.owner,
200
217
  repo: context.repo.repo,
201
218
  workflow_id: 'release-pub.yml',
202
- ref: 'main',
219
+ ref: '${{ steps.tag.outputs.tag }}',
203
220
  inputs: {
204
221
  tag: '${{ steps.tag.outputs.tag }}'
205
222
  }
206
223
  })
207
224
  console.log('Dispatched release-pub.yml for tag ${{ steps.tag.outputs.tag }}')
225
+
226
+ # These channels publish outside this repo (a Scoop bucket,
227
+ # microsoft/winget-pkgs) and read checksums off the release created
228
+ # above, so they hang off this job rather than firing on the tag
229
+ # directly.
230
+ - name: Trigger OS package manager releases
231
+ uses: actions/github-script@v7
232
+ with:
233
+ script: |
234
+ const tag = '${{ steps.tag.outputs.tag }}'
235
+ const workflows = [
236
+ 'release-scoop.yml',
237
+ 'release-winget.yml',
238
+ ]
239
+
240
+ for (const workflow_id of workflows) {
241
+ try {
242
+ await github.rest.actions.createWorkflowDispatch({
243
+ owner: context.repo.owner,
244
+ repo: context.repo.repo,
245
+ workflow_id,
246
+ ref: tag,
247
+ inputs: { tag },
248
+ })
249
+ console.log(`Dispatched ${workflow_id} for tag ${tag}`)
250
+ } catch (error) {
251
+ // One packaging channel being unconfigured (a missing secret,
252
+ // a bucket repo that does not exist yet) should not take the
253
+ // rest of the fan-out down with it.
254
+ core.warning(`Failed to dispatch ${workflow_id}: ${error.message}`)
255
+ }
256
+ }
@@ -4,7 +4,7 @@ on:
4
4
  workflow_dispatch:
5
5
  inputs:
6
6
  tag:
7
- description: "Release tag (e.g. v0.3.1)"
7
+ description: "Release tag (e.g. v0.4.0)"
8
8
  required: true
9
9
 
10
10
  permissions:
@@ -0,0 +1,130 @@
1
+ name: MCP Registry Release
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ tag:
7
+ description: "Release tag (e.g. v0.4.1)"
8
+ required: true
9
+
10
+ # OIDC is how we authenticate to the MCP Registry: the registry trusts a GitHub
11
+ # Actions token issued for this repository, so no long-lived secret is needed.
12
+ permissions:
13
+ id-token: write
14
+ contents: read
15
+
16
+ jobs:
17
+ publish:
18
+ name: Publish server.json to the MCP Registry
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ # Unlike the other release workflows, this one builds nothing from source:
22
+ # it uploads metadata. So it checks out the branch it was dispatched on
23
+ # rather than the tag — `server.json` may have landed after the tag was
24
+ # cut — and uses the tag input only to pick the version to publish.
25
+ - name: Checkout
26
+ uses: actions/checkout@v6
27
+
28
+ - name: Set the release version
29
+ shell: bash
30
+ run: |
31
+ release_version="${{ github.event.inputs.tag }}"
32
+ release_version="${release_version#v}"
33
+
34
+ echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV"
35
+
36
+ - name: Check the server name is consistent across packages
37
+ shell: bash
38
+ run: |
39
+ server_name="$(jq -r '.name' server.json)"
40
+ echo "Server name: ${server_name}"
41
+
42
+ # npm proves ownership through `mcpName` in the published package.json,
43
+ # rendered at release time from this template.
44
+ grep -q "\"mcpName\": \"${server_name}\"" npm/package-main.json.tmpl
45
+
46
+ # NuGet proves ownership through an `mcp-name:` marker in the package README.
47
+ grep -q "mcp-name: ${server_name}" nuget/onde-cli/README.md
48
+
49
+ - name: Set the version in server.json
50
+ shell: bash
51
+ run: |
52
+ jq --arg v "${RELEASE_VERSION}" \
53
+ '.version = $v | .packages |= map(.version = $v)' \
54
+ server.json > server.tmp
55
+ mv server.tmp server.json
56
+ cat server.json
57
+
58
+ - name: Verify the published packages carry the ownership marker
59
+ shell: bash
60
+ run: |
61
+ # The registry stores metadata only, and validates it by fetching each
62
+ # listed package and looking for a marker naming this server. Checking
63
+ # the sources isn't enough: a package published before the marker
64
+ # landed will still be missing it. Both comparisons are case-sensitive.
65
+ server_name="$(jq -r '.name' server.json)"
66
+
67
+ # npm is queryable within seconds of publishing, but the npm release
68
+ # workflow may still be building its platform packages when this runs.
69
+ for attempt in $(seq 1 20); do
70
+ if npm view "@ondeinference/cli@${RELEASE_VERSION}" version; then
71
+ break
72
+ fi
73
+ if [ "${attempt}" -eq 20 ]; then
74
+ echo "@ondeinference/cli@${RELEASE_VERSION} is still not on npm after 10 minutes." >&2
75
+ exit 1
76
+ fi
77
+ echo "Waiting for @ondeinference/cli@${RELEASE_VERSION} on npm (attempt ${attempt}/20)..."
78
+ sleep 30
79
+ done
80
+
81
+ npm_mcp_name="$(npm view "@ondeinference/cli@${RELEASE_VERSION}" mcpName)"
82
+ if [ "${npm_mcp_name}" != "${server_name}" ]; then
83
+ echo "@ondeinference/cli@${RELEASE_VERSION} declares mcpName '${npm_mcp_name}', expected '${server_name}'." >&2
84
+ echo "npm versions are immutable — cut a new release with the marker in place." >&2
85
+ exit 1
86
+ fi
87
+
88
+ # nuget.org validates a package before it reaches the flat container,
89
+ # so a version pushed minutes ago is not queryable yet. Poll instead
90
+ # of failing the release on that race.
91
+ for attempt in $(seq 1 20); do
92
+ nuget_versions="$(curl -fsSL "https://api.nuget.org/v3-flatcontainer/onde.cli/index.json")"
93
+ if echo "${nuget_versions}" | jq -e --arg v "${RELEASE_VERSION}" '.versions | index($v)' >/dev/null; then
94
+ echo "Onde.Cli ${RELEASE_VERSION} is indexed."
95
+ break
96
+ fi
97
+ if [ "${attempt}" -eq 20 ]; then
98
+ echo "Onde.Cli ${RELEASE_VERSION} is still not indexed on nuget.org after 10 minutes." >&2
99
+ exit 1
100
+ fi
101
+ echo "Waiting for nuget.org to index ${RELEASE_VERSION} (attempt ${attempt}/20)..."
102
+ sleep 30
103
+ done
104
+
105
+ curl -fsSL -o package.nupkg \
106
+ "https://api.nuget.org/v3-flatcontainer/onde.cli/${RELEASE_VERSION}/onde.cli.${RELEASE_VERSION}.nupkg"
107
+ if ! unzip -p package.nupkg README.md | grep -q "mcp-name: ${server_name}"; then
108
+ echo "Onde.Cli ${RELEASE_VERSION} README is missing the 'mcp-name: ${server_name}' marker." >&2
109
+ exit 1
110
+ fi
111
+ rm package.nupkg
112
+
113
+ - name: Install mcp-publisher
114
+ shell: bash
115
+ run: |
116
+ 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
117
+
118
+ - name: Authenticate to the MCP Registry
119
+ shell: bash
120
+ run: ./mcp-publisher login github-oidc
121
+
122
+ - name: Publish
123
+ shell: bash
124
+ run: ./mcp-publisher publish
125
+
126
+ - name: Verify the server is listed
127
+ shell: bash
128
+ run: |
129
+ server_name="$(jq -r '.name' server.json)"
130
+ curl -fsSL "https://registry.modelcontextprotocol.io/v0.1/servers?search=${server_name}" | jq .
@@ -1,13 +1,11 @@
1
1
  name: NPM Release
2
2
 
3
+ # Dispatched by release-crates.yml once the crate publish succeeds.
3
4
  on:
4
- push:
5
- tags:
6
- - "v*.*.*"
7
5
  workflow_dispatch:
8
6
  inputs:
9
7
  tag:
10
- description: "Release tag (e.g. v0.3.1)"
8
+ description: "Release tag (e.g. v0.4.0)"
11
9
  required: true
12
10
 
13
11
  permissions:
@@ -1,13 +1,11 @@
1
1
  name: NuGet Release
2
2
 
3
+ # Dispatched by release-crates.yml once the crate publish succeeds.
3
4
  on:
4
- push:
5
- tags:
6
- - "v*.*.*"
7
5
  workflow_dispatch:
8
6
  inputs:
9
7
  tag:
10
- description: "Release tag (e.g. v0.3.1)"
8
+ description: "Release tag (e.g. v0.4.0)"
11
9
  required: true
12
10
 
13
11
  permissions:
@@ -303,3 +301,26 @@ jobs:
303
301
  --api-key "${NUGET_API_KEY}" \
304
302
  --source https://api.nuget.org/v3/index.json \
305
303
  --skip-duplicate
304
+
305
+ dispatch-mcp-registry:
306
+ name: Trigger MCP Registry release
307
+ needs: publish-nuget
308
+ runs-on: ubuntu-latest
309
+ permissions:
310
+ actions: write
311
+ steps:
312
+ # The MCP Registry listing needs both npm and NuGet live at this version,
313
+ # and NuGet is the slower of the two, so it hangs off this workflow rather
314
+ # than the fan-out in release-crates.yml.
315
+ - name: Trigger MCP Registry release workflow
316
+ uses: actions/github-script@v7
317
+ with:
318
+ script: |
319
+ const tag = '${{ github.event.inputs.tag }}' || context.ref.replace('refs/tags/', '')
320
+ await github.rest.actions.createWorkflowDispatch({
321
+ owner: context.repo.owner,
322
+ repo: context.repo.repo,
323
+ workflow_id: 'release-mcp-registry.yml',
324
+ ref: tag,
325
+ inputs: { tag }
326
+ })
@@ -4,7 +4,7 @@ on:
4
4
  workflow_dispatch:
5
5
  inputs:
6
6
  tag:
7
- description: "Release tag (e.g. v0.3.1)"
7
+ description: "Release tag (e.g. v0.4.0)"
8
8
  required: true
9
9
 
10
10
  permissions:
@@ -1,13 +1,11 @@
1
1
  name: PyPI Release
2
2
 
3
+ # Dispatched by release-crates.yml once the crate publish succeeds.
3
4
  on:
4
- push:
5
- tags:
6
- - "v*.*.*"
7
5
  workflow_dispatch:
8
6
  inputs:
9
7
  tag:
10
- description: "Release tag (e.g. v0.3.1)"
8
+ description: "Release tag (e.g. v0.4.0)"
11
9
  required: true
12
10
 
13
11
  permissions: