onde-cli 0.3.0__tar.gz → 0.3.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.
Files changed (62) hide show
  1. onde_cli-0.3.1/.agents/skills/distribution/SKILL.md +226 -0
  2. {onde_cli-0.3.0 → onde_cli-0.3.1}/.github/workflows/ci.yml +42 -5
  3. {onde_cli-0.3.0 → onde_cli-0.3.1}/.github/workflows/release-github.yml +1 -1
  4. {onde_cli-0.3.0 → onde_cli-0.3.1}/.github/workflows/release-homebrew.yml +1 -1
  5. {onde_cli-0.3.0 → onde_cli-0.3.1}/.github/workflows/release-npm.yml +2 -6
  6. onde_cli-0.3.1/.github/workflows/release-nuget.yml +305 -0
  7. onde_cli-0.3.1/.github/workflows/release-pub.yml +241 -0
  8. {onde_cli-0.3.0 → onde_cli-0.3.1}/.github/workflows/release-pypi.yml +5 -5
  9. onde_cli-0.3.1/.gitignore +17 -0
  10. onde_cli-0.3.1/.nuget/NuGet/NuGet.Config +6 -0
  11. {onde_cli-0.3.0 → onde_cli-0.3.1}/Cargo.lock +1 -1
  12. {onde_cli-0.3.0 → onde_cli-0.3.1}/Cargo.toml +1 -1
  13. {onde_cli-0.3.0 → onde_cli-0.3.1}/PKG-INFO +10 -4
  14. {onde_cli-0.3.0 → onde_cli-0.3.1}/README.md +20 -4
  15. {onde_cli-0.3.0 → onde_cli-0.3.1}/build.rs +5 -6
  16. {onde_cli-0.3.0 → onde_cli-0.3.1}/npm/onde-cli/README.md +8 -2
  17. {onde_cli-0.3.0 → onde_cli-0.3.1}/npm/onde-cli/package-lock.json +8 -8
  18. {onde_cli-0.3.0 → onde_cli-0.3.1}/npm/onde-cli/src/index.ts +4 -4
  19. {onde_cli-0.3.0 → onde_cli-0.3.1}/npm/scripts/render-main-package.cjs +2 -2
  20. {onde_cli-0.3.0 → onde_cli-0.3.1}/npm/scripts/render-platform-package.cjs +4 -4
  21. onde_cli-0.3.1/nuget/.gitignore +5 -0
  22. onde_cli-0.3.1/nuget/onde-cli/Onde.Cli.csproj +26 -0
  23. onde_cli-0.3.1/nuget/onde-cli/Program.cs +109 -0
  24. onde_cli-0.3.1/nuget/onde-cli/README.md +55 -0
  25. onde_cli-0.3.1/pub/onde_cli/.gitignore +2 -0
  26. onde_cli-0.3.1/pub/onde_cli/.pubignore +2 -0
  27. onde_cli-0.3.1/pub/onde_cli/CHANGELOG.md +7 -0
  28. onde_cli-0.3.1/pub/onde_cli/LICENSE +201 -0
  29. onde_cli-0.3.1/pub/onde_cli/README.md +48 -0
  30. onde_cli-0.3.1/pub/onde_cli/bin/onde.dart +13 -0
  31. onde_cli-0.3.1/pub/onde_cli/lib/onde_cli.dart +99 -0
  32. onde_cli-0.3.1/pub/onde_cli/pubspec.yaml +21 -0
  33. {onde_cli-0.3.0 → onde_cli-0.3.1}/pypi/README.md +9 -3
  34. {onde_cli-0.3.0 → onde_cli-0.3.1}/src/app.rs +12 -12
  35. onde_cli-0.3.0/.gitignore +0 -3
  36. {onde_cli-0.3.0 → onde_cli-0.3.1}/.agents/skills/git/SKILL.md +0 -0
  37. {onde_cli-0.3.0 → onde_cli-0.3.1}/.github/workflows/release-crates.yml +0 -0
  38. {onde_cli-0.3.0 → onde_cli-0.3.1}/.nvmrc +0 -0
  39. {onde_cli-0.3.0 → onde_cli-0.3.1}/LICENSE +0 -0
  40. {onde_cli-0.3.0 → onde_cli-0.3.1}/assets/ondeinference-apps.png +0 -0
  41. {onde_cli-0.3.0 → onde_cli-0.3.1}/npm/README.md.tmpl +0 -0
  42. {onde_cli-0.3.0 → onde_cli-0.3.1}/npm/onde-cli/.gitignore +0 -0
  43. {onde_cli-0.3.0 → onde_cli-0.3.1}/npm/onde-cli/package.json +0 -0
  44. {onde_cli-0.3.0 → onde_cli-0.3.1}/npm/onde-cli/tsconfig.json +0 -0
  45. {onde_cli-0.3.0 → onde_cli-0.3.1}/npm/package-main.json.tmpl +0 -0
  46. {onde_cli-0.3.0 → onde_cli-0.3.1}/npm/package.json.tmpl +0 -0
  47. {onde_cli-0.3.0 → onde_cli-0.3.1}/pypi/pyproject.toml +0 -0
  48. {onde_cli-0.3.0 → onde_cli-0.3.1}/pyproject.toml +0 -0
  49. {onde_cli-0.3.0 → onde_cli-0.3.1}/rust-toolchain.toml +0 -0
  50. {onde_cli-0.3.0 → onde_cli-0.3.1}/src/chat.rs +0 -0
  51. {onde_cli-0.3.0 → onde_cli-0.3.1}/src/finetune.rs +0 -0
  52. {onde_cli-0.3.0 → onde_cli-0.3.1}/src/gguf.rs +0 -0
  53. {onde_cli-0.3.0 → onde_cli-0.3.1}/src/gresiq.rs +0 -0
  54. {onde_cli-0.3.0 → onde_cli-0.3.1}/src/hf.rs +0 -0
  55. {onde_cli-0.3.0 → onde_cli-0.3.1}/src/hf_clone.rs +0 -0
  56. {onde_cli-0.3.0 → onde_cli-0.3.1}/src/hf_search.rs +0 -0
  57. {onde_cli-0.3.0 → onde_cli-0.3.1}/src/hf_upload.rs +0 -0
  58. {onde_cli-0.3.0 → onde_cli-0.3.1}/src/main.rs +0 -0
  59. {onde_cli-0.3.0 → onde_cli-0.3.1}/src/merge.rs +0 -0
  60. {onde_cli-0.3.0 → onde_cli-0.3.1}/src/project.rs +0 -0
  61. {onde_cli-0.3.0 → onde_cli-0.3.1}/src/token.rs +0 -0
  62. {onde_cli-0.3.0 → onde_cli-0.3.1}/src/ui.rs +0 -0
@@ -0,0 +1,226 @@
1
+ ---
2
+ name: distribution
3
+ description: Use when adding, fixing, or documenting package distribution for Onde CLI. Covers wrapper-package design across npm, PyPI, NuGet, pub.dev, GitHub Releases, and Homebrew, plus version alignment, artifact staging, README surfaces, and smoke-test strategy.
4
+ ---
5
+
6
+ # Onde CLI distribution
7
+
8
+ This skill captures how `onde-cli` is distributed today and what to watch when adding new channels.
9
+
10
+ ## Distribution model
11
+
12
+ `onde-cli` is a native Rust CLI first.
13
+
14
+ Everything else is packaging.
15
+
16
+ That means:
17
+
18
+ - build the Rust binary once per target
19
+ - publish thin wrappers that install or launch that binary
20
+ - keep channel-specific logic small and predictable
21
+
22
+ This design keeps behavior consistent across ecosystems and avoids re-implementing CLI logic in each language.
23
+
24
+ ## Channel map
25
+
26
+ ### Native source of truth
27
+
28
+ - Rust crate: `onde-cli`
29
+ - binary name: `onde`
30
+ - root manifest: `Cargo.toml`
31
+
32
+ ### Wrapper channels
33
+
34
+ - npm: JavaScript launcher + optional platform packages
35
+ - PyPI: `maturin` binary wheels
36
+ - NuGet: .NET global tool launcher
37
+ - pub.dev: Dart launcher package
38
+
39
+ ### Native artifact channels
40
+
41
+ - crates.io
42
+ - GitHub Releases
43
+ - Homebrew
44
+
45
+ ## Wrapper design patterns
46
+
47
+ ### npm
48
+
49
+ Use a very small Node launcher that:
50
+
51
+ - detects OS and architecture
52
+ - resolves the installed platform package
53
+ - spawns the binary with inherited stdio
54
+
55
+ Good fit for users who already live in npm tooling.
56
+
57
+ Important release detail:
58
+
59
+ - the committed `npm/onde-cli/package.json` is a working file, not the publish-time source of truth
60
+ - the release workflow rewrites the base package manifest with `npm/scripts/render-main-package.cjs`
61
+ - platform package manifests are generated on the fly with `npm/scripts/render-platform-package.cjs`
62
+ - the actual npm version comes from the release tag via `RELEASE_VERSION`, not from manually editing the committed npm manifest before publish
63
+
64
+ ### PyPI
65
+
66
+ Use `maturin` with `bindings = "bin"` so the native executable is what gets installed.
67
+
68
+ Good fit for Python users who want the CLI but not a Python reimplementation.
69
+
70
+ ### NuGet
71
+
72
+ Use a `.NET global tool` wrapper.
73
+
74
+ Important details:
75
+
76
+ - keep the package as a launcher, not a managed rewrite
77
+ - place native binaries under the tool payload
78
+ - resolve the runtime identifier at startup
79
+ - set Unix execute bits before launch
80
+
81
+ Good fit for .NET developers and CI environments that already use `dotnet tool install`.
82
+
83
+ ### pub.dev
84
+
85
+ Use a Dart package with a command entrypoint and a library that launches the bundled native binary.
86
+
87
+ Important details:
88
+
89
+ - executable command should stay `onde`
90
+ - use `Isolate.resolvePackageUri` to find the installed package path
91
+ - keep the runtime-id mapping explicit
92
+ - do not overcomplicate the wrapper with platform-specific Dart APIs unless necessary
93
+
94
+ Good fit for Dart and Flutter developers who want the same CLI through familiar tooling.
95
+
96
+ ## Runtime identifier mapping
97
+
98
+ Keep these names aligned anywhere wrappers or workflows refer to native assets:
99
+
100
+ - `darwin-x64`
101
+ - `darwin-arm64`
102
+ - `linux-x64`
103
+ - `linux-arm64`
104
+ - `windows-x64`
105
+ - `windows-arm64`
106
+
107
+ If a wrapper uses one naming scheme and a workflow uploads another, the installed package will pass packaging but fail at runtime.
108
+
109
+ ## Release workflow principles
110
+
111
+ ### Build first, package second
112
+
113
+ Always build native binaries in a target matrix first.
114
+
115
+ Then let the wrapper channel jobs package those artifacts.
116
+
117
+ This avoids rebuilding the product multiple times and makes failures easier to reason about.
118
+
119
+ ### Idempotency
120
+
121
+ Every publish workflow should check whether the target version already exists before publishing.
122
+
123
+ Examples:
124
+
125
+ - npm: `npm view`
126
+ - PyPI: package JSON endpoint
127
+ - NuGet: flat container index
128
+ - pub.dev: package API endpoint
129
+
130
+ ### Smoke tests should match the product shape
131
+
132
+ Because `onde` is TUI-first, avoid smoke tests that assume a traditional CLI help flow unless you know that code path is stable and non-interactive.
133
+
134
+ Safer checks:
135
+
136
+ - install succeeds
137
+ - bundled native binary exists where expected
138
+ - package manager validation passes
139
+
140
+ ## pub.dev-specific notes
141
+
142
+ pub.dev behaves differently from npm and NuGet in one important way:
143
+
144
+ - files ignored by git are generally excluded from publish input
145
+
146
+ That means staged native binaries for `pub/onde_cli/native/` must be available to the package at publish time.
147
+
148
+ Two practical consequences:
149
+
150
+ - do not ignore `pub/onde_cli/native/` in the root `.gitignore` if CI stages binaries there
151
+ - a `.pubignore` can hide local tool noise, but do not hide the native payload you intend to publish
152
+
153
+ Run these during verification:
154
+
155
+ - `dart pub get --directory pub/onde_cli`
156
+ - `dart analyze pub/onde_cli`
157
+ - `dart pub publish --dry-run --directory pub/onde_cli`
158
+
159
+ ## NuGet-specific notes
160
+
161
+ NuGet packaging is sensitive to path layout.
162
+
163
+ The safest pattern is:
164
+
165
+ - copy native files into the publish output
166
+ - let the .NET tool pack process carry them into the final package
167
+
168
+ Avoid custom `PackagePath` patterns that can duplicate path segments or create nested native folders by accident.
169
+
170
+ If the tool installs but cannot find the native binary, inspect the `.nupkg` contents before debugging the launcher.
171
+
172
+ ## README surfaces
173
+
174
+ Every user-facing channel should document the same product with channel-specific installation instructions.
175
+
176
+ Main files:
177
+
178
+ - `README.md`
179
+ - `npm/onde-cli/README.md`
180
+ - `pypi/README.md`
181
+ - `nuget/onde-cli/README.md`
182
+ - `pub/onde_cli/README.md`
183
+
184
+ Keep these aligned on:
185
+
186
+ - product description
187
+ - supported platforms
188
+ - install method
189
+ - license and copyright
190
+ - relevant supporting links like the forward-pass explainer
191
+
192
+ Do not let one channel sound like a different product.
193
+
194
+ ## Version alignment
195
+
196
+ When cutting a release, update every user-facing distribution version that should move with the CLI.
197
+
198
+ At minimum, check:
199
+
200
+ - Rust crate version
201
+ - npm release templates and workflow assumptions
202
+ - npm lockfile version if committed
203
+ - PyPI release version source
204
+ - NuGet package version at pack time
205
+ - pub.dev package version in `pubspec.yaml`
206
+ - workflow example tags and docs that mention concrete versions
207
+
208
+ ## Common failure modes
209
+
210
+ - wrapper version does not match the Rust release version
211
+ - manually bumping the committed npm manifest and assuming that is what npm publishes
212
+ - staged native binaries land in the wrong directory before packaging
213
+ - package builds successfully but installs without the native binary
214
+ - pub.dev package omits staged assets because gitignore excludes them
215
+ - smoke test invokes a TUI-first binary in a way that does not make sense for CI
216
+ - README badges and install commands drift out of sync with real package names
217
+
218
+ ## Rule of thumb
219
+
220
+ If the native binary works and the wrappers are boring, distribution stays manageable.
221
+
222
+ If a wrapper starts acting like its own product, complexity grows fast.
223
+
224
+ Keep it thin.
225
+ Keep it aligned.
226
+ Keep the Rust binary as the source of truth.
@@ -108,6 +108,39 @@ jobs:
108
108
  GRESIQ_API_SECRET: ${{ secrets.GRESIQ_API_SECRET }}
109
109
  HF_TOKEN: ${{ secrets.HF_TOKEN }}
110
110
 
111
+ dotnet-tool:
112
+ name: .NET tool launcher build
113
+ runs-on: ubuntu-latest
114
+ steps:
115
+ - name: Checkout
116
+ uses: actions/checkout@v6
117
+
118
+ - name: Setup .NET SDK
119
+ uses: actions/setup-dotnet@v4
120
+ with:
121
+ dotnet-version: 8.0.x
122
+
123
+ - name: Build .NET tool launcher
124
+ run: dotnet build nuget/onde-cli/Onde.Cli.csproj --configuration Release
125
+
126
+ dart-package:
127
+ name: Dart pub package check
128
+ runs-on: ubuntu-latest
129
+ steps:
130
+ - name: Checkout
131
+ uses: actions/checkout@v6
132
+
133
+ - name: Setup Dart SDK
134
+ uses: dart-lang/setup-dart@v1
135
+
136
+ - name: Get package dependencies
137
+ working-directory: pub/onde_cli
138
+ run: dart pub get
139
+
140
+ - name: Analyze Dart package
141
+ working-directory: pub/onde_cli
142
+ run: dart analyze
143
+
111
144
  build:
112
145
  name: Build (aarch64-apple-darwin)
113
146
  runs-on: macos-26
@@ -140,13 +173,17 @@ jobs:
140
173
  - clippy
141
174
  - test
142
175
  - check
176
+ - dotnet-tool
177
+ - dart-package
143
178
  - build
144
179
  if: always()
145
180
  steps:
146
181
  - name: Verify all required jobs succeeded
147
182
  run: |
148
- test "${{ needs.fmt.result }}" = "success"
149
- test "${{ needs.clippy.result }}" = "success"
150
- test "${{ needs.test.result }}" = "success"
151
- test "${{ needs.check.result }}" = "success"
152
- test "${{ needs.build.result }}" = "success"
183
+ test "${{ needs.fmt.result }}" = "success"
184
+ test "${{ needs.clippy.result }}" = "success"
185
+ test "${{ needs.test.result }}" = "success"
186
+ test "${{ needs.check.result }}" = "success"
187
+ test "${{ needs.dotnet-tool.result }}" = "success"
188
+ test "${{ needs.dart-package.result }}" = "success"
189
+ test "${{ needs.build.result }}" = "success"
@@ -7,7 +7,7 @@ on:
7
7
  workflow_dispatch:
8
8
  inputs:
9
9
  tag:
10
- description: "Release tag (e.g. v0.1.1)"
10
+ description: "Release tag (e.g. v0.3.1)"
11
11
  required: true
12
12
 
13
13
  permissions:
@@ -4,7 +4,7 @@ on:
4
4
  workflow_dispatch:
5
5
  inputs:
6
6
  tag:
7
- description: "Release tag (e.g. v0.1.1)"
7
+ description: "Release tag (e.g. v0.3.1)"
8
8
  required: true
9
9
 
10
10
  permissions:
@@ -7,7 +7,7 @@ on:
7
7
  workflow_dispatch:
8
8
  inputs:
9
9
  tag:
10
- description: "Release tag (e.g. v0.2.0)"
10
+ description: "Release tag (e.g. v0.3.1)"
11
11
  required: true
12
12
 
13
13
  permissions:
@@ -55,11 +55,7 @@ jobs:
55
55
  OS: macos-26-intel,
56
56
  TARGET: x86_64-apple-darwin,
57
57
  }
58
- - {
59
- NAME: darwin-arm64,
60
- OS: macos-26,
61
- TARGET: aarch64-apple-darwin,
62
- }
58
+ - { NAME: darwin-arm64, OS: macos-26, TARGET: aarch64-apple-darwin }
63
59
 
64
60
  steps:
65
61
  - name: Checkout
@@ -0,0 +1,305 @@
1
+ name: NuGet Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*.*.*"
7
+ workflow_dispatch:
8
+ inputs:
9
+ tag:
10
+ description: "Release tag (e.g. v0.3.1)"
11
+ required: true
12
+
13
+ permissions:
14
+ contents: read
15
+
16
+ env:
17
+ CARGO_TERM_COLOR: always
18
+ DOTNET_VERSION: 8.0.x
19
+ NUGET_PACKAGE_ID: Onde.Cli
20
+ ONDE_APP_ID: ${{ secrets.ONDE_APP_ID }}
21
+ ONDE_APP_SECRET: ${{ secrets.ONDE_APP_SECRET }}
22
+ GRESIQ_API_KEY: ${{ secrets.GRESIQ_API_KEY }}
23
+ GRESIQ_API_SECRET: ${{ secrets.GRESIQ_API_SECRET }}
24
+ HF_TOKEN: ${{ secrets.HF_TOKEN }}
25
+
26
+ jobs:
27
+ build-native-binaries:
28
+ name: Build native binary (${{ matrix.build.NAME }})
29
+ runs-on: ${{ matrix.build.OS }}
30
+ strategy:
31
+ fail-fast: false
32
+ matrix:
33
+ build:
34
+ - {
35
+ NAME: linux-x64,
36
+ OS: ubuntu-latest,
37
+ TARGET: x86_64-unknown-linux-gnu,
38
+ }
39
+ - {
40
+ NAME: linux-arm64,
41
+ OS: ubuntu-24.04-arm,
42
+ TARGET: aarch64-unknown-linux-gnu,
43
+ }
44
+ - {
45
+ NAME: windows-x64,
46
+ OS: windows-2022,
47
+ TARGET: x86_64-pc-windows-msvc,
48
+ }
49
+ - {
50
+ NAME: windows-arm64,
51
+ OS: windows-2022,
52
+ TARGET: aarch64-pc-windows-msvc,
53
+ }
54
+ - {
55
+ NAME: darwin-x64,
56
+ OS: macos-26-intel,
57
+ TARGET: x86_64-apple-darwin,
58
+ }
59
+ - { NAME: darwin-arm64, OS: macos-26, TARGET: aarch64-apple-darwin }
60
+ steps:
61
+ - name: Checkout
62
+ uses: actions/checkout@v6
63
+ with:
64
+ ref: ${{ github.event.inputs.tag || github.ref }}
65
+
66
+ - name: Set the release version
67
+ shell: bash
68
+ run: |
69
+ if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
70
+ release_version="${GITHUB_REF_NAME#v}"
71
+ else
72
+ release_version="${{ github.event.inputs.tag }}"
73
+ release_version="${release_version#v}"
74
+ fi
75
+
76
+ echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV"
77
+
78
+ - name: Read Rust toolchain
79
+ shell: bash
80
+ run: |
81
+ rust_toolchain="$(sed -n 's/^channel = "\(.*\)"/\1/p' rust-toolchain.toml | head -n 1)"
82
+ if [ -z "$rust_toolchain" ]; then
83
+ echo "Failed to read Rust toolchain from rust-toolchain.toml" >&2
84
+ exit 1
85
+ fi
86
+
87
+ echo "RUST_TOOLCHAIN=${rust_toolchain}" >> "$GITHUB_ENV"
88
+
89
+ - name: Install Rust toolchain
90
+ uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9
91
+ with:
92
+ toolchain: ${{ env.RUST_TOOLCHAIN }}
93
+ targets: ${{ matrix.build.TARGET }}
94
+
95
+ - name: Setup Rust cache
96
+ uses: Swatinem/rust-cache@v2
97
+ with:
98
+ key: nuget-${{ matrix.build.TARGET }}
99
+
100
+ - name: Build binary
101
+ shell: bash
102
+ run: cargo build --locked --release --target ${{ matrix.build.TARGET }}
103
+
104
+ - name: Prepare artifact
105
+ shell: bash
106
+ run: |
107
+ executable_name="onde"
108
+ if [[ "${{ matrix.build.OS }}" == "windows-2022" ]]; then
109
+ executable_name="onde.exe"
110
+ fi
111
+
112
+ mkdir -p "nuget-artifacts/native/${{ matrix.build.NAME }}"
113
+ cp "target/${{ matrix.build.TARGET }}/release/${executable_name}" "nuget-artifacts/native/${{ matrix.build.NAME }}/${executable_name}"
114
+
115
+ - name: Upload native artifact
116
+ uses: actions/upload-artifact@v4
117
+ with:
118
+ name: nuget-native-${{ matrix.build.NAME }}
119
+ path: nuget-artifacts/native
120
+
121
+ pack-nuget:
122
+ name: Pack NuGet .NET tool
123
+ runs-on: ubuntu-latest
124
+ needs: build-native-binaries
125
+ steps:
126
+ - name: Checkout
127
+ uses: actions/checkout@v6
128
+ with:
129
+ ref: ${{ github.event.inputs.tag || github.ref }}
130
+
131
+ - name: Set the release version
132
+ shell: bash
133
+ run: |
134
+ if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
135
+ release_version="${GITHUB_REF_NAME#v}"
136
+ else
137
+ release_version="${{ github.event.inputs.tag }}"
138
+ release_version="${release_version#v}"
139
+ fi
140
+
141
+ echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV"
142
+
143
+ - name: Download native artifacts
144
+ uses: actions/download-artifact@v4
145
+ with:
146
+ pattern: nuget-native-*
147
+ path: nuget/onde-cli/native
148
+ merge-multiple: true
149
+
150
+ - name: Setup .NET SDK
151
+ uses: actions/setup-dotnet@v4
152
+ with:
153
+ dotnet-version: ${{ env.DOTNET_VERSION }}
154
+
155
+ - name: Pack .NET tool
156
+ shell: bash
157
+ run: |
158
+ dotnet pack nuget/onde-cli/Onde.Cli.csproj \
159
+ --configuration Release \
160
+ --output nuget/dist \
161
+ -p:PackageVersion=${RELEASE_VERSION}
162
+
163
+ - name: Upload package artifact
164
+ uses: actions/upload-artifact@v4
165
+ with:
166
+ name: nuget-package
167
+ path: nuget/dist/*.nupkg
168
+
169
+ smoke-test:
170
+ name: Smoke test (${{ matrix.os }})
171
+ runs-on: ${{ matrix.os }}
172
+ needs: pack-nuget
173
+ strategy:
174
+ fail-fast: false
175
+ matrix:
176
+ os:
177
+ - ubuntu-latest
178
+ - windows-2022
179
+ - macos-26
180
+ steps:
181
+ - name: Checkout
182
+ uses: actions/checkout@v6
183
+ with:
184
+ ref: ${{ github.event.inputs.tag || github.ref }}
185
+
186
+ - name: Set the release version
187
+ shell: bash
188
+ run: |
189
+ if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
190
+ release_version="${GITHUB_REF_NAME#v}"
191
+ else
192
+ release_version="${{ github.event.inputs.tag }}"
193
+ release_version="${release_version#v}"
194
+ fi
195
+
196
+ echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV"
197
+
198
+ - name: Download package artifact
199
+ uses: actions/download-artifact@v4
200
+ with:
201
+ name: nuget-package
202
+ path: nuget/dist
203
+
204
+ - name: Setup .NET SDK
205
+ uses: actions/setup-dotnet@v4
206
+ with:
207
+ dotnet-version: ${{ env.DOTNET_VERSION }}
208
+
209
+ - name: Install tool from local package
210
+ shell: pwsh
211
+ run: |
212
+ $packageSource = (Resolve-Path "nuget/dist").Path
213
+ @"
214
+ <?xml version="1.0" encoding="utf-8"?>
215
+ <configuration>
216
+ <packageSources>
217
+ <clear />
218
+ <add key="local" value="$packageSource" />
219
+ </packageSources>
220
+ </configuration>
221
+ "@ | Set-Content -Path "nuget/NuGet.Config"
222
+
223
+ dotnet tool install `
224
+ --tool-path ".tool" `
225
+ --configfile "nuget/NuGet.Config" `
226
+ --version "$env:RELEASE_VERSION" `
227
+ "$env:NUGET_PACKAGE_ID"
228
+
229
+ - name: Verify bundled native binary
230
+ shell: pwsh
231
+ run: |
232
+ $runtimeIdentifier = if ($IsWindows) {
233
+ if ([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture -eq [System.Runtime.InteropServices.Architecture]::Arm64) { "windows-arm64" } else { "windows-x64" }
234
+ } elseif ($IsMacOS) {
235
+ if ([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture -eq [System.Runtime.InteropServices.Architecture]::Arm64) { "darwin-arm64" } else { "darwin-x64" }
236
+ } else {
237
+ if ([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture -eq [System.Runtime.InteropServices.Architecture]::Arm64) { "linux-arm64" } else { "linux-x64" }
238
+ }
239
+
240
+ $binaryName = if ($IsWindows) { "onde.exe" } else { "onde" }
241
+ $nativeBinary = Get-ChildItem ".tool/.store" -Recurse -File | Where-Object {
242
+ $_.FullName -like "*native*${runtimeIdentifier}*${binaryName}"
243
+ } | Select-Object -First 1
244
+
245
+ if (-not $nativeBinary) {
246
+ Write-Error "Onde native binary for ${runtimeIdentifier} was not bundled in the installed .NET tool package."
247
+ }
248
+
249
+ Write-Host "Found bundled native binary at $($nativeBinary.FullName)"
250
+
251
+ publish-nuget:
252
+ name: Publish to NuGet
253
+ runs-on: ubuntu-latest
254
+ needs: smoke-test
255
+ steps:
256
+ - name: Checkout
257
+ uses: actions/checkout@v6
258
+ with:
259
+ ref: ${{ github.event.inputs.tag || github.ref }}
260
+
261
+ - name: Set the release version
262
+ shell: bash
263
+ run: |
264
+ if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
265
+ release_version="${GITHUB_REF_NAME#v}"
266
+ else
267
+ release_version="${{ github.event.inputs.tag }}"
268
+ release_version="${release_version#v}"
269
+ fi
270
+
271
+ echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV"
272
+
273
+ - name: Download package artifact
274
+ uses: actions/download-artifact@v4
275
+ with:
276
+ name: nuget-package
277
+ path: nuget/dist
278
+
279
+ - name: Setup .NET SDK
280
+ uses: actions/setup-dotnet@v4
281
+ with:
282
+ dotnet-version: ${{ env.DOTNET_VERSION }}
283
+
284
+ - name: Check whether release already exists on NuGet
285
+ id: nuget-check
286
+ shell: bash
287
+ run: |
288
+ package_index_url="https://api.nuget.org/v3-flatcontainer/onde.cli/index.json"
289
+ if curl -fsS "${package_index_url}" | grep -F "\"${RELEASE_VERSION}\"" >/dev/null; then
290
+ echo "${NUGET_PACKAGE_ID} ${RELEASE_VERSION} already exists on NuGet, skipping publish"
291
+ echo "exists=true" >> "$GITHUB_OUTPUT"
292
+ else
293
+ echo "exists=false" >> "$GITHUB_OUTPUT"
294
+ fi
295
+
296
+ - name: Publish package
297
+ if: steps.nuget-check.outputs.exists != 'true'
298
+ env:
299
+ NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
300
+ shell: bash
301
+ run: |
302
+ dotnet nuget push nuget/dist/*.nupkg \
303
+ --api-key "${NUGET_API_KEY}" \
304
+ --source https://api.nuget.org/v3/index.json \
305
+ --skip-duplicate