diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index a567522f6..6e79e6aaf 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -147,6 +147,38 @@ jobs: if: github.ref == 'refs/heads/main' run: dotnet nuget push ./artifacts/*.nupkg --api-key ${{ steps.nuget-login.outputs.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate + publish-rust: + name: Publish Rust SDK + if: github.event.inputs.dist-tag != 'unstable' + needs: version + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./rust + steps: + - uses: actions/checkout@v6.0.2 + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + with: + toolchain: "1.94.0" + - uses: Swatinem/rust-cache@v2 + with: + workspaces: "rust" + - name: Set version + run: sed -i -E 's/^version = ".*"$/version = "${{ needs.version.outputs.version }}"/' Cargo.toml + - name: Package (dry run) + run: cargo publish --dry-run --allow-dirty + - name: Upload artifact + uses: actions/upload-artifact@v7.0.0 + with: + name: rust-package + path: rust/target/package/*.crate + - name: Publish to crates.io + if: github.ref == 'refs/heads/main' + run: cargo publish --allow-dirty + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} + publish-python: name: Publish Python SDK if: github.event.inputs.dist-tag != 'unstable' @@ -185,7 +217,7 @@ jobs: github-release: name: Create GitHub Release - needs: [version, publish-nodejs, publish-dotnet, publish-python] + needs: [version, publish-nodejs, publish-dotnet, publish-python, publish-rust] if: github.ref == 'refs/heads/main' && github.event.inputs.dist-tag != 'unstable' runs-on: ubuntu-latest steps: @@ -238,3 +270,45 @@ jobs: fi env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Tag Rust SDK and create Rust GitHub Release + # Rust gets its own version-scoped GitHub Release with notes + # derived from PR titles since the previous Rust tag. The + # cross-language `vX.Y.Z` release above still exists; this one + # is the canonical reference for Rust users. + if: github.event.inputs.dist-tag == 'latest' || github.event.inputs.dist-tag == 'prerelease' + run: | + set -e + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git fetch --tags + VERSION="${{ needs.version.outputs.version }}" + TAG_NAME="rust/v${VERSION}" + if git tag "$TAG_NAME" ${{ github.sha }} 2>/dev/null; then + git push https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git "$TAG_NAME" + echo "Created and pushed tag $TAG_NAME" + else + echo "Tag $TAG_NAME already exists, skipping tag push" + fi + # Find the previous Rust tag for note generation. Prefer rust/v*, + # fall back to the historical rust-v* tags from the release-plz era. + PREV_TAG=$(git tag --list 'rust/v*' --sort=-v:refname | grep -vFx "$TAG_NAME" | head -n1) + if [ -z "$PREV_TAG" ]; then + PREV_TAG=$(git tag --list 'rust-v*' --sort=-v:refname | head -n1) + fi + NOTES_FLAG="" + if [ -n "$PREV_TAG" ]; then + NOTES_FLAG="--notes-start-tag $PREV_TAG" + echo "Generating notes from $PREV_TAG..$TAG_NAME" + else + echo "No previous Rust tag found; generating notes from full history" + fi + PRERELEASE_FLAG="" + if [ "${{ github.event.inputs.dist-tag }}" = "prerelease" ]; then + PRERELEASE_FLAG="--prerelease" + fi + gh release create "$TAG_NAME" \ + --title "$TAG_NAME" \ + --generate-notes $NOTES_FLAG $PRERELEASE_FLAG \ + --target ${{ github.sha }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/rust-publish-release.yml b/.github/workflows/rust-publish-release.yml deleted file mode 100644 index daf768929..000000000 --- a/.github/workflows/rust-publish-release.yml +++ /dev/null @@ -1,55 +0,0 @@ -name: "Rust SDK: Publish Release" - -# Publishes the `copilot-sdk` crate to crates.io when a release-plz -# version-bump PR is merged to `main`. See rust/RELEASING.md for the -# full release process and one-time setup (CARGO_REGISTRY_TOKEN, etc). - -on: - push: - branches: - - main - paths: - - 'rust/Cargo.toml' - - 'rust/Cargo.lock' - - 'rust/release-plz.toml' - workflow_dispatch: - -permissions: - contents: write - -concurrency: - group: rust-release-plz-publish - cancel-in-progress: false - -jobs: - publish: - name: Publish to crates.io - if: github.event.repository.fork == false - runs-on: ubuntu-latest - defaults: - run: - working-directory: ./rust - steps: - - uses: actions/checkout@v6.0.2 - with: - fetch-depth: 0 - token: ${{ secrets.GITHUB_TOKEN }} - - - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable - with: - toolchain: "1.94.0" - - - uses: Swatinem/rust-cache@v2 - with: - workspaces: "rust" - - - name: Run release-plz release - uses: release-plz/action@v0.5 - with: - command: release - manifest_path: rust/Cargo.toml - config: rust/release-plz.toml - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} diff --git a/.github/workflows/rust-release-pr.yml b/.github/workflows/rust-release-pr.yml deleted file mode 100644 index 41420f3e4..000000000 --- a/.github/workflows/rust-release-pr.yml +++ /dev/null @@ -1,56 +0,0 @@ -name: "Rust SDK: Create Release PR" - -# release-plz opens a PR that bumps the `copilot-sdk` version in -# `rust/Cargo.toml` and updates `rust/CHANGELOG.md` based on -# conventional-commit history since the last `rust-vX.Y.Z` tag. -# -# Review and merge that PR on the maintainer's schedule. Publishing to -# crates.io happens separately in `rust-publish-release.yml` once the -# version bump lands on `main`. -# -# Runs manually only — we don't want a PR to race with every push. - -on: - workflow_dispatch: - -permissions: - contents: write - pull-requests: write - -concurrency: - group: rust-release-plz-pr - cancel-in-progress: false - -jobs: - release-pr: - name: Create Release PR - runs-on: ubuntu-latest - defaults: - run: - working-directory: ./rust - steps: - - uses: actions/checkout@v6.0.2 - with: - fetch-depth: 0 - token: ${{ secrets.GITHUB_TOKEN }} - - - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable - with: - toolchain: "1.94.0" - - - uses: Swatinem/rust-cache@v2 - with: - workspaces: "rust" - - - name: Run release-plz release-pr - uses: release-plz/action@v0.5 - with: - command: release-pr - manifest_path: rust/Cargo.toml - config: rust/release-plz.toml - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # CARGO_REGISTRY_TOKEN is not required for release-pr (no publish), - # but release-plz inspects the crate on crates.io to compute the - # next version. Public crate inspection doesn't need auth. diff --git a/.github/workflows/rust-sdk-tests.yml b/.github/workflows/rust-sdk-tests.yml index 5dc100e72..207ed6de9 100644 --- a/.github/workflows/rust-sdk-tests.yml +++ b/.github/workflows/rust-sdk-tests.yml @@ -99,18 +99,6 @@ jobs: COPILOT_CLI_PATH: ${{ steps.setup-copilot.outputs.cli-path }} run: cargo test --features test-support - # Detects accidental public-API breakage against the crate's last - # published version on crates.io. Non-blocking until the crate has - # a first published release — once a 0.1.0 ships, flip - # `continue-on-error` to `false` to enforce SemVer. - - name: cargo semver-checks - if: runner.os == 'Linux' - continue-on-error: true - uses: obi1kenobi/cargo-semver-checks-action@v2 - with: - package: github-copilot-sdk - manifest-path: rust/Cargo.toml - # Validates the `embedded-cli` build path on all three supported # platforms. This is the only place `build.rs` actually runs (the # default `cargo test` job above has `COPILOT_CLI_VERSION` unset, so diff --git a/rust/CHANGELOG.md b/rust/CHANGELOG.md deleted file mode 100644 index 37dff98ab..000000000 --- a/rust/CHANGELOG.md +++ /dev/null @@ -1,511 +0,0 @@ -# Changelog - -All notable changes to the `github-copilot-sdk` crate will be documented in this file. - -The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -After 0.1.0 ships, [release-plz](https://release-plz.dev/) will prepend new -entries from conventional-commit history. The Unreleased entry below is -hand-curated so that crates.io readers get a usable summary of the public -surface on first publish, not a flat list of merge commits — release-plz -will rename `[Unreleased]` to `[0.1.0] - ` and add a fresh empty -`[Unreleased]` above it when it cuts the first release PR. - -## [Unreleased] - -Initial public release. Programmatic Rust access to the GitHub Copilot CLI -over JSON-RPC 2.0 (stdio or TCP), with handler-based event dispatch, typed -tool/permission/elicitation helpers, and runtime session management. - -This is a **technical preview**. The crate is pre-1.0 and the public API may -change in breaking ways before 1.0. The rendered docs on -[docs.rs](https://docs.rs/github-copilot-sdk) are the canonical reference for the -public surface. - -### Added - -#### Client lifecycle -- `Client::start` — spawn and manage a GitHub Copilot CLI child process. -- `Client::from_streams` — connect to a CLI server over caller-supplied - `AsyncRead`/`AsyncWrite` (testing, custom transports). -- `Client::stop` / `Client::force_stop` — graceful and immediate shutdown. -- `Client::state` returning `ConnectionState` (`Connecting`, `Connected`, - `Disconnecting`, `Disconnected`). -- `Client::subscribe_lifecycle` returning a `LifecycleSubscription` for - runtime observation of created / destroyed / foreground / background - events. Implements `tokio_stream::Stream` and offers an inherent - `recv()`; drop the value to unsubscribe. -- `Client::ping(message)` returning typed `PingResponse` and - `Client::verify_protocol_version` for handshake validation. -- `Client::list_sessions`, `get_session_metadata`, `delete_session`, - `get_last_session_id`, `get_foreground_session_id`, - `set_foreground_session_id`. -- `Client::list_models`, `get_status` (typed `GetStatusResponse`), - `get_auth_status` (typed `GetAuthStatusResponse`). - -#### Sessions -- `Client::create_session` and `Client::resume_session` accepting - `SessionConfig` with handler, capabilities, system message, mode, model, - permission policy, working directory, and resume parameters. -- `Session::send` returning the assigned message ID for - correlation with later events. -- `Session::send_and_wait` for synchronous prompt → final-event flows. -- `Session::subscribe` returning an `EventSubscription` for observe-only - access to the session's event stream. Implements `tokio_stream::Stream` - and offers an inherent `recv()`; drop the value to unsubscribe. -- `Session::set_model(model, SetModelOptions)` with `reasoning_effort` - and `model_capabilities` overrides (matches Node/Python/.NET). -- UI primitives: `session.ui().elicitation()`, `confirm()`, `select()`, - `input()` — grouped under a `SessionUi` sub-API to mirror .NET / Python / - Go. -- `Session::log(message, LogOptions)` with optional severity and - ephemeral flag. -- `Session::abort` (matches all other SDKs). -- `Session::disconnect` (canonical) and `Session::destroy` (alias) - preserve on-disk session state for later resume. -- `Session::stop_event_loop` for shutting down the per-session loop. -- `Session::cancellation_token()` returns a [`tokio_util::sync::CancellationToken`] - child token that fires when the session shuts down (via - `stop_event_loop`, `destroy`, or `Drop`). Lets external tasks bind their - lifetime to a session via `tokio::select!` without taking a strong - reference to the session. Cancelling the returned child token does not - shut the session down — only `stop_event_loop` (or dropping the session) - does. - -#### Handlers + helpers -- `SessionHandler` trait with default fallback impls for each event - (permissions, external tools, elicitation, plan-mode prompts). -- `ApproveAllHandler` / `DenyAllHandler` reference handlers. -- Permission policy helpers: `permission::approve_all`, - `permission::deny_all`, `permission::approve_if`, plus chainable - builders on `SessionConfig` (`approve_all_permissions`, - `deny_all_permissions`, `approve_if`). -- `PermissionResult` is `#[non_exhaustive]` and supports `Approved`, - `Denied`, `Deferred` (handler will resolve via - `handlePendingPermissionRequest` itself — notification path only; - direct RPC falls back to `Approved`), and - `Custom(serde_json::Value)` for response shapes beyond - `{ "kind": "approve-once" | "reject" }` (e.g. allowlist payloads). -- All extension-point and protocol-evolving public enums are - `#[non_exhaustive]` so future variants are additive (non-breaking): - `Error`, `ProtocolError`, `SessionError`, `Transport`, `Attachment`, - `ToolResult`, `ElicitationMode`, `InputFormat`, `GitHubReferenceType`, - `SessionLifecycleEventType`, plus the handler/hook event/response enums. - Closed taxonomies (`LogLevel`, `ConnectionState`, `CliProgram`) remain - exhaustive so callers benefit from compile-time exhaustiveness checks. -- Tool helpers: `tool::DefineTool`, `tool::tool_schema_for`, - `tool::ToolHandlerRouter`, derive support via `derive` feature. - `ToolHandlerRouter` overrides each `SessionHandler` per-event method - directly, so callers can use the narrow-typed entry points (e.g. - `router.on_external_tool(invocation).await -> ToolResult`) instead of - unwrapping a `HandlerResponse` from `on_event`. The default `on_event` - still routes correctly through the per-event methods, so legacy - callers are unaffected. -- Hooks API for instrumenting send/receive flows (`github_copilot_sdk::hooks`). -- `SessionHandler::on_auto_mode_switch` — typed handler for the CLI's - rate-limit-recovery prompt (`autoModeSwitch.request` JSON-RPC - callback, added in copilot-agent-runtime PR #7024). Returns a typed - [`AutoModeSwitchResponse`] enum with `Yes`, `YesAlways`, `No` - variants (`#[serde(rename_all = "snake_case")]`, wire values byte- - identical to the runtime's `"yes" | "yes_always" | "no"` schema). - Default impl declines (`No`); override only if your application - surfaces a UX for the prompt. `SessionConfig::request_auto_mode_switch` - and `ResumeSessionConfig::request_auto_mode_switch` default to - `Some(true)` so the CLI advertises the callback to the SDK out of the - box. **Cross-SDK divergence:** typed handler is Rust-only as of 0.1.0. - Node, Python, Go, and .NET observe the request as a raw JSON-RPC - callback today; parity ports for those SDKs are post-release follow-up - work. -- New session-event fields surfaced by the `@github/copilot ^1.0.39` - schema bump: - - `SessionErrorData.eligible_for_auto_switch: Option` — set on - `errorType: "rate_limit"` to signal the runtime will follow with an - `auto_mode_switch.requested` event. UI clients can suppress - duplicate rendering of the rate-limit error when they show their - own auto-mode-switch prompt. - - `SessionErrorData.error_code: Option` — fine-grained - upstream provider error code (e.g. - `"user_weekly_rate_limited"`, `"integration_rate_limited"`). - - `SessionModelChangeData.cause: Option` — - `"rate_limit_auto_switch"` for changes triggered by the - auto-mode-switch recovery path. Lets UI render contextual copy. - - `AutoModeSwitchRequestedData.retry_after_seconds: Option` — - seconds until the rate limit resets, when known. Clients can - render a humanized reset time alongside the prompt. The request- - callback path's `retry_after_seconds` parameter on - [`SessionHandler::on_auto_mode_switch`](crate::handler::SessionHandler::on_auto_mode_switch) - uses the same `Option` representation. - -#### Types -- Newtype `SessionId`, plus generated RPC types under `github_copilot_sdk::generated`. -- `LogLevel`, `LogOptions`, `SetModelOptions`, `PingResponse`, - `SessionLifecycleEvent`, `SessionLifecycleEventType`, `ConnectionState`, - `SystemMessageConfig`, `MessageOptions`, `SectionOverride`, `Attachment`, - `InputFormat`, `InputOptions`. -- Strongly-typed `Error` and `ProtocolError` with `is_transport_failure` - classifier and `error_codes` constants. - -#### Typed RPC namespace -- `Client::rpc()` and `Session::rpc()` accessors exposing a generated, typed - view over the full GitHub Copilot CLI JSON-RPC API. Sub-namespaces mirror the - schema (e.g. `client.rpc().models().list()`, `session.rpc().workspaces() - .list_files()`, `session.rpc().agent().list()`, - `session.rpc().tasks().list()`). -- All hand-authored helpers (`list_workspace_files`, `read_plan`, `set_mode`, - `list_models`, `get_quota`, etc.) are now thin one-line delegations over - this namespace. Wire-method strings exist in exactly one place - (`generated/rpc.rs`), making typo bugs like the `session.workspace.*` - → `session.workspaces.*` regression structurally impossible. Public - helper signatures are unchanged. - -#### Configuration parity -- All remaining public configuration types are now `#[non_exhaustive]` - for forward-compatibility — adding fields post-1.0 is non-breaking on - consumers that construct via `Default::default()` plus field - assignment or the `with_*` builders. Affected: `SessionConfig`, - `ResumeSessionConfig`, `ClientOptions`, `ProviderConfig`, - `McpServerConfig`, `Tool`, `CustomAgentConfig`, - `InfiniteSessionConfig`, `SystemMessageConfig`, `ConnectionState`. - (`HookEvent`, `HookOutput`, `MessageOptions`, `TelemetryConfig`, - `SessionFsConfig`, `FsError`, `FileInfo`, `DirEntry`, `ToolInvocation`, - `Error`, `Transport`, `DeliveryMode` were already marked.) Callers - using exhaustive struct literals must switch to - `let mut x = Type::default(); x.field = ...;` or the available `with_*` - builders; `..Default::default()` no longer compiles for these types - outside the defining crate. -- `MessageOptions::mode` is now typed `Option` (was - `Option`). `DeliveryMode` is `#[non_exhaustive]` and serializes - to the wire strings `"enqueue"` (default) and `"immediate"`. The prior - rustdoc incorrectly described this field as a permission mode; the - field controls how the prompt is delivered relative to in-flight work. - `MessageOptions::with_mode` now takes `DeliveryMode` directly. Callers - that previously passed `"agent"` or `"autopilot"` were already silently - no-ops at the CLI level — switch to a `DeliveryMode` variant or omit - the field entirely. -- `SessionConfig::default()` and `ResumeSessionConfig::new()` now set the - four permission-flow flags (`request_user_input`, `request_permission`, - `request_exit_plan_mode`, `request_elicitation`) to `Some(true)` instead - of `None`. Mirrors Node's `client.ts` behavior of always advertising the - permission surface and deriving handler presence from the - `SessionHandler` impl. The default `DenyAllHandler` refuses all - permission requests so the wire surface is safe out-of-the-box; callers - that want the wire surface fully disabled set the flags explicitly to - `Some(false)`. -- `SessionListFilter` — typed filter for `Client::list_sessions` covering - `cwd`, `git_root`, `repository`, and `branch`. Replaces the prior - `Option` parameter. -- `McpServerConfig` tagged enum (`Stdio` / `Http` / `Sse`) with - `McpStdioServerConfig` and `McpHttpServerConfig` payload structs. - `SessionConfig::mcp_servers`, `ResumeSessionConfig::mcp_servers`, and - `CustomAgentConfig::mcp_servers` are now `Option>` instead of typeless `Value` maps. Stdio configurations - serialized by older callers (no explicit `type`, or `type: "local"`) are - accepted on the deserialize path. -- `PermissionRequestData` gains typed `kind: Option` - and `tool_call_id: Option` fields covering the eight CLI - permission categories (`shell`, `write`, `read`, `url`, `mcp`, - `custom-tool`, `memory`, `hook`); unknown values fall through to - `PermissionRequestKind::Unknown` for forward compatibility. The original - params object is still available via the existing `extra: Value` flatten. -- `PermissionResult` gains `UserNotAvailable` (sent as - `{ "kind": "user-not-available" }`) and `NoResult` (sent as - `{ "kind": "no-result" }`) variants for headless agents and explicit - fall-through-to-CLI-default responses. -- `Client::stop` cooperatively shuts down active sessions before killing - the CLI child: walks every session still registered with the client, - sends `session.destroy` for each, then kills the child. Errors from - per-session destroys and the terminal child-kill are collected into a - new `StopErrors` aggregate (`Result<(), StopErrors>`) instead of - short-circuiting on the first failure, mirroring the Node SDK's - `Error[]` return shape. `StopErrors` implements `std::error::Error` - and exposes `errors()` / `into_errors()` for inspection. Callers that - previously used `client.stop().await?` should switch to - `client.stop().await.ok();` (best-effort) or match on the aggregate. -- `ResumeSessionConfig::disable_resume: Option` — force-fail resume - if the session does not exist on disk, instead of silently starting a - new session. -- `SessionConfig` and `ResumeSessionConfig` gain six configuration knobs - matching the Node SDK shape (Bucket B.1): - - `session_id: Option` (SessionConfig only — required on - resume, where it remains `SessionId`) — supply a custom session ID - instead of letting the CLI generate one. - - `working_directory: Option` — per-session cwd override, - independent of [`ClientOptions::cwd`](crate::ClientOptions::cwd). - - `config_dir: Option` — override the default configuration - directory location for this session. - - `model_capabilities: Option` — per-property - overrides for model capabilities, deep-merged over runtime defaults. - The same type was previously available only on - `SetModelOptions::model_capabilities`. - - `github_token: Option` — per-session GitHub token. Distinct - from [`ClientOptions::github_token`], which authenticates the CLI - process; this token determines the GitHub identity used for content - exclusion, model routing, and quota checks for this session. The - field is redacted from the `Debug` output. - - `include_sub_agent_streaming_events: Option` — forward streaming - delta events from sub-agents to this connection (Node default: true). -- `ClientOptions` gains the simple subset of Node's - `CopilotClientOptions` knobs (Bucket B.2): - - `log_level: Option` — typed enum (`None`, `Error`, `Warning`, - `Info`, `Debug`, `All`) replacing the previously hard-coded - `--log-level info` argument. When unset, the SDK still passes - `--log-level info` for parity with prior behavior. - - `session_idle_timeout_seconds: Option` — server-wide idle - timeout for sessions in seconds. When `Some(n)` with `n > 0`, the - SDK passes `--session-idle-timeout `. `None` or `Some(0)` leaves - sessions running indefinitely (the CLI default). - - The Node knob `isChildProcess` (sub-CLI parent-stdio mode) and - `autoStart` (lazy-init pattern) are intentionally **not** ported — - `isChildProcess` requires a transport variant the Rust SDK does not - yet support; `autoStart` does not apply because [`Client::start`] is - a single explicit constructor rather than a deferred-init pattern. - - `on_list_models: Option>` — BYOK escape - hatch matching Node's `onListModels`. When set, [`Client::list_models`] - returns the handler's result without making a `models.list` RPC. - `ListModelsHandler` is a new public `async_trait` (mirrors the shape - of `SessionHandler` / `SessionHooks`) with a single - `async fn list_models(&self) -> Result, Error>` method. - `ClientOptions` switched from `#[derive(Debug)]` to a manual `Debug` - impl that prints the handler as `` / `None` (same precedent as - `SessionConfig::handler` and `github_token`). -- `MessageOptions` gains `request_headers: Option>` - with a corresponding [`MessageOptions::with_request_headers`] builder - method, matching Node's `MessageOptions.requestHeaders` and Go's - `MessageOptions.RequestHeaders`. Custom HTTP headers are forwarded to - the CLI via the `requestHeaders` field on `session.send`. The field is - omitted from the wire when `None` or empty (matches Node's - `omitempty` semantics). -- Slash command registration: new [`CommandHandler`] async trait, - [`CommandDefinition`] (with `new`/`with_description` builders), and - [`CommandContext`] (`session_id`, `command`, `command_name`, `args`) - hand-authored in `crate::types`. `SessionConfig::commands` and - `ResumeSessionConfig::commands` accept a `Vec` via - the new `with_commands` builder, matching Node's - `SessionConfig.commands`, Python's `SessionConfig.commands`, and Go's - `SessionConfig.Commands`. The SDK serializes only `{name, description?}` - on the wire (handlers stay client-side), and dispatches incoming - `command.execute` events to the registered handler — acking with no - error on success, `error: ` on `Err`, and - `error: "Unknown command: "` when the name is unregistered. - `CommandContext` and `CommandDefinition` are `#[non_exhaustive]` so - forward-compatible fields (e.g. aliases, completion providers) can land - without breaking callers. -- Custom session filesystem: new [`SessionFsProvider`] async trait, - [`SessionFsConfig`], [`FsError`], [`FileInfo`], [`DirEntry`], - [`DirEntryKind`], and [`SessionFsConventions`] in `crate::session_fs` - (also re-exported from `crate::types`). When [`ClientOptions::session_fs`] - is set, [`Client::start`] calls `sessionFs.setProvider` on the CLI to - delegate per-session filesystem operations to a provider supplied via - [`SessionConfig::with_session_fs_provider`] / - [`ResumeSessionConfig::with_session_fs_provider`]. Inbound `sessionFs.*` - requests dispatch to the provider; `FsError::NotFound` maps to the wire - `ENOENT` code and other `FsError` values map to `UNKNOWN`. - `From` is provided so handlers backed by `std::fs` / - `tokio::fs` can propagate errors with `?`. All trait methods have - default implementations returning `Err(FsError::Other("not supported"))`, - so providers only override the methods they need and forward-compatible - schema additions land without breaking existing implementations. - Diverges from Node/Python/Go's factory-closure pattern in favor of - direct `Arc` registration. -- W3C Trace Context propagation: new [`TraceContext`] struct and - [`TraceContextProvider`] async trait in `crate::trace_context` (also - re-exported from `crate::types`). Hybrid shape combines Node's - callback-based `onGetTraceContext` and Go's per-turn - `MessageOptions.Traceparent` / `Tracestate`: - [`ClientOptions::on_get_trace_context`] supplies an ambient provider that - injects `traceparent` / `tracestate` on `session.create`, - `session.resume`, and `session.send`, while - [`MessageOptions::with_traceparent`], [`MessageOptions::with_tracestate`], - and [`MessageOptions::with_trace_context`] override per-turn (override - wins; provider is not invoked when MessageOptions carries trace headers). - [`ToolInvocation`] is now `#[non_exhaustive]` and exposes inbound - `traceparent` / `tracestate` populated from `external_tool.requested` - events, plus a [`ToolInvocation::trace_context`] helper. Wire fields are - omitted when unset (matches Node/Go `omitempty` semantics). -- `ToolInvocation` and `SessionId` now derive `Default`. Production code - never constructs `ToolInvocation` literals (it's a CLI-emitted read-only - type), but downstream test scaffolding can now use - `ToolInvocation { tool_name: "...".into(), ..Default::default() }` and - absorb future `#[non_exhaustive]` field additions automatically. -- OpenTelemetry env-var passthrough: new [`TelemetryConfig`] struct and - [`OtelExporterType`] enum (both `#[non_exhaustive]`), wired on - [`ClientOptions::telemetry`]. When `Some(...)`, the SDK injects - `COPILOT_OTEL_ENABLED=true` plus `OTEL_EXPORTER_OTLP_ENDPOINT`, - `COPILOT_OTEL_FILE_EXPORTER_PATH`, `COPILOT_OTEL_EXPORTER_TYPE`, - `COPILOT_OTEL_SOURCE_NAME`, and - `OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT` into the spawned CLI - process — verbatim env-var names matching Node/Python/Go. Pure - passthrough: no `opentelemetry-rust` dependency; the CLI itself owns the - exporter. `exporter_type` is a typed enum (`OtlpHttp` / `File`) following - the [`LogLevel`](LogLevel) precedent for finite, enumerated CLI knobs; - serialized verbatim as `"otlp-http"` / `"file"`. User-supplied - `ClientOptions::env` continues to win over telemetry-injected values. -- `ClientOptions::copilot_home: Option` (and - `with_copilot_home`) — overrides the directory where the CLI persists - its state. Exported as `COPILOT_HOME` to the spawned CLI process. - Useful for sandboxing test runs or running multiple isolated SDK - instances side-by-side. Mirrors Node `copilotHome` / - Python `copilot_home`. -- `ClientOptions::tcp_connection_token: Option` (and - `with_tcp_connection_token`) — optional auth token for TCP transport. - Sent in the new `connect` JSON-RPC handshake (with backward-compat - fall-back to `ping` for legacy CLI servers) and exported as - `COPILOT_CONNECTION_TOKEN` to spawned CLI processes. When the SDK - spawns its own CLI in TCP mode and this is left unset, a UUID is - generated automatically so the loopback listener is safe by default. - Combining with `Transport::Stdio` returns - `Error::InvalidConfig` from `Client::start`. -- `SessionConfig::instruction_directories: Option>` and - `ResumeSessionConfig::instruction_directories` (plus - `with_instruction_directories` builders on both) — additional - directories searched for custom instruction files. Distinct from - `skill_directories`. Forwarded to the CLI on session create / resume. -- `Error::InvalidConfig(String)` variant for client-construction errors - that surface from `Client::start` (e.g. `tcp_connection_token` paired - with `Transport::Stdio`, empty token, etc). - -### Documentation -- `README.md` with quickstart, architecture diagram, and feature matrix. -- Examples under `examples/`: `chat`, `hooks`, `tool_server`, - `lifecycle_observer`. -- `RELEASING.md` operational runbook for maintainers. - -#### Builder ergonomics -- `ClientOptions::new()` plus a chainable `with_*` builder per public - field (`with_program`, `with_prefix_args`, `with_cwd`, `with_env`, - `with_env_remove`, `with_extra_args`, `with_transport`, - `with_github_token`, `with_use_logged_in_user`, `with_log_level`, - `with_session_idle_timeout_seconds`, `with_list_models_handler`, - `with_session_fs`, `with_trace_context_provider`, `with_telemetry`). - Mirrors the existing [`MessageOptions::new`] / `with_*` shape and - closes the cross-crate ergonomics gap on `#[non_exhaustive]` — - external callers no longer need to write - `let mut opts = ClientOptions::default(); opts.field = ...;` for - every field they touch. Existing `ClientOptions::default()` and - mut-let-and-assign continue to work unchanged. -- `Tool::new(name)` plus `with_namespaced_name`, `with_description`, - `with_instructions`, `with_parameters`, `with_overrides_built_in_tool`, - `with_skip_permission` for tool definitions. Same rationale — - `Tool` is the most-instantiated `#[non_exhaustive]` type at consumer - call sites in real-world consumer code, where the - builder shape replaces the per-consumer `make_tool(name, desc, - params)` helper that consumers were writing to smooth over the - mut-let pattern. -- Per-field `with_*` builder methods on `SessionConfig` and - `ResumeSessionConfig` covering every public scalar, vector, and - optional-struct field (~30 new methods on each). Mirrors the - `ClientOptions` / `Tool` shape; existing closure-installing - chains (`with_handler`, `with_hooks`, `with_transform`, - `with_commands`, `with_session_fs_provider`, - `approve_all_permissions`, etc.) continue to work unchanged. The - primary win: external session-construction sites collapse from - `let mut cfg = ResumeSessionConfig::new(id); cfg.client_name = - Some("...".into()); cfg.streaming = Some(true); ...` (10-15 - lines per site) to a single fluent chain. -- Round out builder coverage on the remaining consumer-facing - config structs: `CustomAgentConfig::new(name, prompt)` plus - `with_display_name`, `with_description`, `with_tools`, - `with_mcp_servers`, `with_infer`, `with_skills`; - `InfiniteSessionConfig::new()` plus `with_enabled`, - `with_background_compaction_threshold`, - `with_buffer_exhaustion_threshold`; - `ProviderConfig::new(base_url)` plus `with_provider_type`, - `with_wire_api`, `with_api_key`, `with_bearer_token`, - `with_azure`, `with_headers`, `with_model_id`, `with_wire_model`, - `with_max_prompt_tokens`, `with_max_output_tokens`; `SystemMessageConfig::new()` plus - `with_mode`, `with_content`, `with_sections`; - `TelemetryConfig::new()` plus `with_otlp_endpoint`, - `with_file_path`, `with_exporter_type`, `with_source_name`, - `with_capture_content`. `TraceContext` also gains a symmetric - `new()` + `with_traceparent` pair alongside the existing - `from_traceparent` shorthand. -- Documented the direct-field-assignment escape hatch on - `SessionConfig` and `ResumeSessionConfig` for callers forwarding - `Option` values from upstream code (matches the - `http::request::Parts` / `hyper::Body::Builder` convention; per- - field `with_*_opt` setters intentionally omitted to keep the - primary API surface small). - -#### Build infrastructure -- `build.rs` no longer shells out to `curl` for the bundled-CLI - download. The `embedded-cli` feature now downloads the - `SHA256SUMS.txt` and platform tarball through `ureq` (rustls TLS, - pure-Rust, no system dependencies). Removes the implicit `curl`- - on-PATH requirement that previously broke the build on minimal - Windows / container environments. Includes bounded retries with - exponential backoff (1s/2s/4s) on transient failures (5xx, - connect/read timeouts, transport errors) — 4xx responses still - fail fast as before. - -### Fixed -- `SessionEvent` and `TypedSessionEvent` now expose the `agentId` - envelope field added to `session-events.schema.json` upstream - (`f8cf846`, "Derive session event envelopes from schema"). Sub-agent - events were silently dropping the attribution at the deserialization - boundary; consumers had no way to distinguish events emitted by the - root agent from events emitted by a sub-agent. Other SDKs (Node, - Python, Go, .NET) all carry this field. Round-trip parity test added - in `types::tests::session_event_round_trips_agent_id_on_envelope`. -- `Session::user_input` no longer double-dispatches when the CLI sends - both a `user_input.requested` notification (for observers) and a - `userInput.request` JSON-RPC call (the actual prompt) for the same - prompt. The notification path is now a no-op; the JSON-RPC path - remains authoritative. Matches Python / Go / .NET / Node SDK - behavior, all of which only register the JSON-RPC handler. Fixes - github/github-app#4249, where consumers saw duplicate `ask_user` - and `exit_plan` widgets on every prompt. -- `SessionUi::elicitation` (and the `confirm` / `select` / `input` - convenience helpers that delegate through it) now sends the user-supplied - JSON Schema as `requestedSchema` on the wire, matching the - `session.ui.elicitation` request shape that all other SDKs ship and that - this crate's own generated `UIElicitationRequest` type expects. The - hand-authored convenience layer was sending it as `schema`, so every UI - helper call was effectively dead — the CLI saw a missing required - `requestedSchema` field. The mock-server test for elicitation - round-tripped through the same misnamed field, so the bug slipped past - unit tests; the test now asserts on `requestedSchema` and explicitly - rejects a stray `schema` key. -- `Client::list_sessions` now wraps the optional filter under `params.filter` - on the wire, matching the `session.list` request shape that Node, Python, - Go, and .NET ship. The hand-authored implementation was flattening the - filter fields directly onto `params`, which the runtime silently ignored - — so `list_sessions(Some(filter))` was functionally equivalent to - `list_sessions(None)` in 0.0.x. Same class of bug as the elicitation - wire fix above: the existing mock-server test asserted on the flat shape - it observed rather than the schema's wrapped shape, so the bug - round-tripped through both ends. The test now asserts the wrapped path - (`params.filter.repository`) and explicitly rejects the flattened - fallback (`params.repository`). -- `Client::get_status` and `Client::get_auth_status` now use the - correct wire method names (`status.get` and `auth.getStatus`) - matching Node, Go, Python, and .NET. The hand-authored - implementation was sending `getStatus` and `getAuthStatus` — names - that aren't registered on the CLI runtime — so both calls would - have returned a "method not found" error (or a misleading no-such- - method log) instead of the expected status payload. Same class of - bug as the elicitation `requestedSchema` and `list_sessions` - filter-wrapping fixes above: the mock-server test for these - methods asserted on the wrong-name strings the implementation - used, so the bugs round-tripped through both ends. The test now - asserts on the canonical wire names AND explicitly rejects the - hand-authored aliases (`assert_ne!(request["method"], "getStatus")` - / `"getAuthStatus"`). - -### Notes -- Minimum supported Rust version (MSRV): 1.94.0 (pinned via - `rust-toolchain.toml`). -- No `Client::actual_port` accessor — this SDK is strictly stream-based, - so the concept doesn't apply. See `Client::from_streams` rustdoc. -- `cargo semver-checks` runs in `continue-on-error` mode for 0.1.0; will - flip to blocking once 0.1.0 is published and serves as the baseline. -- `infinite_sessions: Option` is wired on both - `SessionConfig` and `ResumeSessionConfig` and follows the same - default-omit-on-the-wire semantics as Node/Go: when `None`, the field - is skipped and the CLI applies its own default. No behavioral - divergence from the other SDKs. -- `Client::stop` returns `Result<(), StopErrors>` and now cooperatively - shuts down each active session via `session.destroy` before killing - the CLI child, aggregating all per-session and child-kill errors into - the returned `StopErrors`. See the entry under "Configuration parity" - above for the migration note. diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 1163de37e..8b130628e 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -340,7 +340,7 @@ dependencies = [ [[package]] name = "github-copilot-sdk" -version = "0.1.0" +version = "0.0.0-dev" dependencies = [ "async-trait", "dirs", diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 0b90cc1ab..4d8831f7e 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "github-copilot-sdk" -version = "0.1.0" +version = "0.0.0-dev" edition = "2024" rust-version = "1.94.0" description = "Rust SDK for programmatic control of the GitHub Copilot CLI via JSON-RPC. Technical preview, pre-1.0." @@ -13,7 +13,6 @@ readme = "README.md" license = "MIT" exclude = [ "RELEASING.md", - "release-plz.toml", "rust-toolchain.toml", ".rustfmt.toml", ".rustfmt.nightly.toml", diff --git a/rust/README.md b/rust/README.md index d6cf17a93..05177132d 100644 --- a/rust/README.md +++ b/rust/README.md @@ -6,6 +6,8 @@ A Rust SDK for programmatic access to the GitHub Copilot CLI. See [github/copilot-sdk](https://github.com/github/copilot-sdk) for the equivalent SDKs in TypeScript, Python, Go, and .NET. The Rust SDK seeks parity with those SDKs; see [Differences From Other SDKs](#differences-from-other-sdks) below for the small set of intentional divergences. +**Releases:** [github.com/github/copilot-sdk/releases?q=rust%2F](https://github.com/github/copilot-sdk/releases?q=rust%2F) — per-version release notes for the Rust crate. + ## Quick Start ```rust,no_run diff --git a/rust/RELEASING.md b/rust/RELEASING.md index 5361591d2..de0252de8 100644 --- a/rust/RELEASING.md +++ b/rust/RELEASING.md @@ -1,192 +1,95 @@ # Releasing `github-copilot-sdk` -This document describes how to cut a release of the `github-copilot-sdk` Rust crate -and publish it to [crates.io]. It is the operational counterpart to the -workflow files under `../.github/workflows/rust-*.yml` (which run the actual -mechanics). - -If you are adding code to the SDK, you do not need to read this. This is for -maintainers cutting a release. - -[crates.io]: https://crates.io/crates/github-copilot-sdk - ---- +The Rust crate ships through the same unified `publish.yml` workflow +as the Node, .NET, and Python SDKs. There is no Rust-specific release +workflow. ## TL;DR -1. Land your changes on `main` using conventional-commit messages. -2. Trigger the **Rust SDK: Create Release PR** workflow manually - (`workflow_dispatch`). -3. Review and merge the PR that release-plz opens. -4. The **Rust SDK: Publish Release** workflow runs automatically when that - PR merges, publishes to crates.io, tags `rust-vX.Y.Z`, and creates a - GitHub Release. - -The first 0.1.0 publish requires a one-time `CARGO_REGISTRY_TOKEN` secret -setup — see [First-time setup](#first-time-setup) below. - ---- - -## How releases are cut - -The crate uses [release-plz] in a two-PR workflow. Both PRs run unattended -through GitHub Actions; the only manual step is reviewing and merging. - -[release-plz]: https://release-plz.dev/ - -### Step 1 — `release-plz release-pr` - -Workflow: `.github/workflows/rust-release-pr.yml` (`workflow_dispatch` only). - -When you trigger it, release-plz: - -- Reads conventional-commit history since the last `rust-vX.Y.Z` tag. -- Decides the next version (patch / minor / major) per SemVer rules. -- Bumps `rust/Cargo.toml`'s `version` field. -- Renames `## [Unreleased]` in `rust/CHANGELOG.md` to `## [X.Y.Z] - - ` and prepends a fresh empty `## [Unreleased]` above it. -- Opens a PR with those changes. - -Review the PR. The CHANGELOG entry is the one users see on crates.io and on -the GitHub Release page, so make sure it reads well. Edit the PR directly if -the auto-generated entry needs tweaking. - -> **First-publish note.** The hand-curated 0.1.0 entry currently lives -> under `## [Unreleased]` so release-plz will rename it cleanly on the -> first run. If release-plz instead generates a *second* entry from -> conventional commits and prepends it above the curated one (depends on -> the configured `body` template), delete the auto-generated stub in the -> PR and keep the curated entry — you only want one 0.1.0 section. - -### Step 2 — `release-plz release` (publish) - -Workflow: `.github/workflows/rust-publish-release.yml` (auto-runs on push -to `main` when `rust/Cargo.toml`, `rust/Cargo.lock`, or `rust/release-plz.toml` -changes). - -When the release-PR from step 1 merges, this workflow detects that -`rust/Cargo.toml`'s version is newer than the latest `rust-vX.Y.Z` tag and: - -- Runs `cargo publish` to upload to crates.io. -- Creates a `rust-vX.Y.Z` git tag. -- Creates a GitHub Release with the CHANGELOG entry as the body. - -The workflow is a no-op on non-release commits, so it's safe to run on every -push. - ---- - -## First-time setup - -Before the first 0.1.0 publish, complete this checklist exactly once: - -1. **Reserve the crate name.** Have a maintainer with crates.io 2FA log in - to crates.io and run `cargo publish` for an empty stub OR claim the name - via the "New Crate" form. The owner account should be a service account - (preferred) or a senior maintainer. -2. **Generate a scoped API token.** crates.io → Account Settings → API - Tokens → New Token. Scope it to publish `github-copilot-sdk` *only* — do not - issue an unscoped token. -3. **Add the secret.** GitHub repo Settings → Secrets and variables → - Actions → New repository secret named `CARGO_REGISTRY_TOKEN`, value = - the token from step 2. -4. **Rotation.** Rotate the token annually and whenever the maintainer set - changes. There's no automated reminder for this — set a calendar event. - -Until this checklist is complete, `cargo publish` in the workflow will fail. -That's intentional: it keeps accidental publishes from happening before the -repo is ready. - ---- - -## Versioning policy - -The crate follows [SemVer]. Pre-1.0 we treat **0.x.0** as breaking and -**0.x.y** as additive — same as the Rust ecosystem convention. - -[SemVer]: https://semver.org/ - -Two CI checks defend the API surface: - -- **`cargo semver-checks`** (`.github/workflows/rust-sdk-tests.yml`) — - detects breaking changes against the latest *published* version on - crates.io. Currently `continue-on-error: true` because there's no - baseline yet. **Flip it to `false` after 0.1.0 ships** to make SemVer - enforcement blocking. - -For ad-hoc public-surface inspection, `cargo public-api -sss --features -derive,test-support` is handy — but the surface is not snapshotted in the -repo. The rendered docs on [docs.rs](https://docs.rs/github-copilot-sdk) are the -canonical reference; `cargo-semver-checks` is the gate. - -For 0.x → 1.0, do an explicit API review pass (compare against the -language siblings under `../{nodejs,python,go,dotnet}/`), -remove anything `#[doc(hidden)]` you don't intend to keep public, and -write out the 1.0 commitment in the CHANGELOG. - ---- - -## Public-disclosure gate +1. Land your changes on `main`. +2. Trigger the **Publish SDK packages** workflow + (`.github/workflows/publish.yml`) via `workflow_dispatch`. +3. Pick `dist-tag`: + - `latest` — stable release (e.g. `1.0.0`). + - `prerelease` — beta release (e.g. `1.0.0-beta.4`). Lands on + crates.io as a prerelease; users must opt in with an explicit + prerelease version requirement to install it. + - `unstable` — skipped for Rust (Cargo doesn't have a clean + equivalent of npm's `unstable` dist-tag). +4. The workflow publishes all four SDKs at the shared computed + version, tags `rust/vX.Y.Z`, and creates a Rust-scoped GitHub + Release with auto-generated notes since the previous Rust tag. + +## Version, tag, and release notes + +- **Crate version:** the in-tree `rust/Cargo.toml` carries `0.0.0-dev` + as a placeholder. CI overrides it at publish time with the version + computed by `publish.yml` (or an explicit `version` workflow input). +- **Tag:** `rust/vX.Y.Z` (matches the `go/vX.Y.Z` style used elsewhere + in this repo). The historical `rust-v0.1.0` tag from the + release-plz era stays valid as a starting point for auto-generated + release notes. +- **Release notes:** auto-generated by `gh release --generate-notes` + from PR titles between the previous Rust tag and the new one. + Write descriptive PR titles for any change that touches the Rust + surface; that's the only place those changes will be visible to + Rust users. + +## Cargo prerelease semantics + +`cargo add github-copilot-sdk` and `version = "1"` requirements skip +prereleases by default. Users who want to opt in to a beta must +write an explicit prerelease requirement: + +```toml +github-copilot-sdk = "1.0.0-beta.4" +``` -The Rust SDK release-prep work happens on `tclem/rust-sdk-release-prep` -and is held *unpushed* until product/comms gives explicit OK. Do not push -the branch, open a PR, or otherwise expose the work without that signal — -even if CI looks ready. +This matches Cargo's standard semver behavior and means a +prerelease-channel publish won't surprise stable users. -Ways to keep moving without pushing: +## Yanking a release -- Land work in local commits on the prep branch. -- Use `cargo publish --dry-run --allow-dirty` to validate package contents. -- Use `cargo public-api -sss --features derive,test-support` for ad-hoc - surface inspection. +If a published version contains a critical bug, yank it from +crates.io to prevent new installs: -When the gate opens: +```sh +cargo yank --version X.Y.Z github-copilot-sdk +``` -1. Push `tclem/rust-sdk-release-prep`. -2. Open a PR titled "Rust SDK: prepare for 0.1.0 release" (or similar). -3. Once it merges, trigger the **Rust SDK: Create Release PR** workflow and - proceed with the publish flow above. +Yanking does *not* delete the version — existing `Cargo.lock` files +keep working — but it stops new resolutions from picking it. Follow +up with a patch release that fixes the bug, and add a note to the +yanked version's GitHub Release explaining why. ---- +Reverse with `cargo yank --undo --version X.Y.Z github-copilot-sdk` +if the yank was a mistake. ## Manual publish (emergency only) -If GitHub Actions is unavailable, a maintainer with crates.io credentials -can publish locally: +If GitHub Actions is unavailable, a maintainer with crates.io +credentials can publish locally: ```sh cd rust -# Verify the package contents first. +# Set the real version (replace X.Y.Z). +perl -i -pe 's/^version = ".*"$/version = "X.Y.Z"/' Cargo.toml + +# Verify package contents. cargo publish --dry-run # Publish for real. cargo publish # Tag and push. -git tag rust-v$(cargo metadata --no-deps --format-version=1 \ - | jq -r '.packages[] | select(.name=="github-copilot-sdk") | .version' | head -1) -git push origin --tags -``` - -Manual publishes skip the release-PR review step, so write the CHANGELOG -entry by hand before publishing and commit it on `main` first. - ---- +git tag rust/vX.Y.Z +git push origin rust/vX.Y.Z -## Yanking a release - -If a published version contains a critical bug (security, data loss, panic -on common input), yank it from crates.io to prevent new installs: - -```sh -cargo yank --version X.Y.Z github-copilot-sdk +# Restore the placeholder. +perl -i -pe 's/^version = ".*"$/version = "0.0.0-dev"/' Cargo.toml ``` -Yanking does *not* delete the version — existing `Cargo.lock` files keep -working — but it stops new resolutions from picking it. Follow up with a -patch release that fixes the bug, and add a note to the yanked version's -GitHub Release explaining why. - -Reverse with `cargo yank --undo --version X.Y.Z github-copilot-sdk` if the yank -was a mistake. +Manual publishes skip the auto-generated GitHub Release. Run +`gh release create rust/vX.Y.Z --generate-notes` after pushing the +tag. diff --git a/rust/release-plz.toml b/rust/release-plz.toml deleted file mode 100644 index 82c38ffd7..000000000 --- a/rust/release-plz.toml +++ /dev/null @@ -1,35 +0,0 @@ -[workspace] -# release-plz config for the Rust github-copilot-sdk crate. -# -# The crate lives in the `rust/` subdirectory of the monorepo, so -# invoke release-plz from this directory (via the release-plz workflows -# under `.github/workflows/`). release-plz will: -# -# 1. `release-plz release-pr`: open a PR updating `rust/Cargo.toml`'s -# version and `rust/CHANGELOG.md` based on conventional-commit -# history on `tclem/rust-sdk-release-prep`-style branches. -# 2. `release-plz release`: after that PR is merged to main, publish -# the tagged version to crates.io and create a `rust-vX.Y.Z` git -# tag. -# -# Publishing requires a `CARGO_REGISTRY_TOKEN` repository secret scoped -# to the `github-copilot-sdk` crate owner account. See -# `.github/workflows/rust-publish-release.yml` for the setup checklist. -# -# Reference: https://release-plz.dev/docs/config -changelog_update = true -dependencies_update = false -git_release_enable = true -# Prefix crate git tags so they don't collide with the monorepo's -# top-level `vX.Y.Z` tags used by the other SDKs. -git_tag_name = "rust-v{{ version }}" -git_release_name = "rust-v{{ version }}" - -[[package]] -name = "github-copilot-sdk" -changelog_path = "CHANGELOG.md" -# Mark pre-1.0 publishes as prereleases on the GitHub release page so -# consumers don't pick them up as "stable" by default. Maintainers -# should flip this (or remove it) when cutting 1.0. -git_release_type = "auto" -