diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c1332d7..2af97694 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,40 @@ # Changelog +## v0.11.0 - 2026-08-17 + +OpenTag 0.11.0 fixes a fail-open edge in zero-config governed completion. A +GitHub-backed pull-request run now remains incomplete until authoritative API +evidence proves that the current-head check rollup is both non-empty and +complete. All 18 public packages are coordinated at `0.11.0`. + +### Fixed + +- Empty check maps no longer satisfy the default observed-checks gate. +- Truncated GitHub check-run or commit-status pages no longer appear fully + passing; reconciliation compares each returned page with its provider + `total_count` and verifies every entry belongs to the current head. +- Missing rollup-completeness evidence defaults to incomplete at the dispatcher + ingestion boundary, preserving fail-closed behavior across mixed deployments. + +### Changed + +- `GitHubCompletionApi.listCheckRunsForRef` now returns + `{ totalCount, checkRuns }`, and `getCombinedStatusForRef` returns + `{ totalCount, statuses }`. +- `GitHubVerifiedPullRequestSnapshot` now requires `checksComplete`, and that + value participates in semantic evidence digests and completion assessment. +- The OpenTag skill pins executable install paths to the reviewed 0.11.0 CLI, + clarifies Hosted Control V1 registration and relay trust, and corrects the + Microsoft Teams conversation-binding source. + +### Compatibility and migration + +- This pre-1.0 minor release intentionally changes exported TypeScript + contracts. Custom `GitHubCompletionApi` implementations must return the new + page objects, and custom snapshot producers must provide `checksComplete`. +- Existing explicit repository completion policies remain authoritative, and + runs without a pull request retain executor-success semantics. + ## v0.10.0 - 2026-08-17 Source manifests are prepared as the coordinated `0.10.0` release for all 18 diff --git a/README.md b/README.md index 4b07ab9a..762e8670 100644 --- a/README.md +++ b/README.md @@ -326,10 +326,10 @@ opentag-dev setup ## Packages -Package source release: `v0.10.0`. This source state is prepared for +Package source release: `v0.11.0`. This source state is prepared for local release validation only; it is not evidence that the release was published. npm dist-tags remain authoritative for public channel versions, and -`0.9.0` remains the documented stable release until registry evidence says +`0.10.0` remains the documented stable release until registry evidence says otherwise. The coordinated package family contains 18 public packages under the `@opentag` scope. diff --git a/README.zh-CN.md b/README.zh-CN.md index a687b0e1..f5e5efc8 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -309,9 +309,9 @@ opentag-dev setup ## 软件包 -当前源码发布版本:`v0.10.0`。此源码状态只表示已准备本地发布验证, +当前源码发布版本:`v0.11.0`。此源码状态只表示已准备本地发布验证, 不代表该版本已经发布;npm dist-tag 仍是公开通道版本的权威来源,在注册表 -证据表明发生变化前,`0.9.0` 仍是文档所述的稳定版本。OpenTag 在 +证据表明发生变化前,`0.10.0` 仍是文档所述的稳定版本。OpenTag 在 `@opentag` scope 下协调发布 18 个公开软件包。 | 包 | 用途 | diff --git a/docs/live-e2e-smoke-harness.md b/docs/live-e2e-smoke-harness.md index 3f991bc9..1a06bbbe 100644 --- a/docs/live-e2e-smoke-harness.md +++ b/docs/live-e2e-smoke-harness.md @@ -55,7 +55,7 @@ smoke_root="$(mktemp -d)" set -euo pipefail cd "$smoke_root" npm init -y >/dev/null - npm install --no-audit --no-fund @opentag/cli@0.10.0 + npm install --no-audit --no-fund @opentag/cli@0.11.0 ./node_modules/.bin/opentag --version ) ``` diff --git a/docs/npm-release.md b/docs/npm-release.md index 150db945..f20ef1b5 100644 --- a/docs/npm-release.md +++ b/docs/npm-release.md @@ -7,27 +7,17 @@ version. ## Target release ```text -0.10.0 +0.11.0 ``` The release is first published on the npm `next` dist-tag, tested from the registry, then promoted to `latest`. The exact commit that produced the npm -artifacts must also receive the matching `v0.10.0` git tag and GitHub Release. - -The public release set contains 18 packages, including the first publications -of `@opentag/control-protocol` and `@opentag/delivery-contract`. The other 16 -packages have a coordinated `0.9.0` release. Publishing `0.10.0` with -`--tag next` must leave each existing package's `latest` pointer unchanged -until the complete registry, ACP, governance, factory, and live-platform gate -passes. - -First-publication exception: `@opentag/control-protocol` and -`@opentag/delivery-contract` have never been published, so they have no -`0.9.0` baseline. Their first `--tag next` publish creates only the `next` -dist-tag, so they have no pre-promotion `latest` value to snapshot or restore. -The snapshot, promotion, and rollback loops below encode this exception -explicitly; do not "fix" a missing first-publication `latest` tag before -promotion. +artifacts must also receive the matching `v0.11.0` git tag and GitHub Release. + +The public release set contains 18 packages. Every package has a coordinated +`0.10.0` stable baseline. Publishing `0.11.0` with `--tag next` must leave each +package's `latest` pointer at `0.10.0` until the complete registry, ACP, +governance, factory, and live-platform gate passes. ## Public package discovery and order @@ -54,7 +44,7 @@ plan. ## Release gate Start from the intended release commit with a clean working tree. Confirm that -all 18 public manifests use `0.10.0` and that the frozen lockfile is current, +all 18 public manifests use `0.11.0` and that the frozen lockfile is current, then run the verification ladder in this order: ```bash @@ -125,7 +115,7 @@ authority, then confirm npm access and publish from that same commit: set -euo pipefail test -z "$(git status --porcelain)" - release_state_dir=".omx/releases/0.10.0" + release_state_dir=".omx/releases/0.11.0" release_commit_file="$release_state_dir/release-commit-sha" current_release_commit="$(git rev-parse HEAD)" mkdir -p "$release_state_dir" @@ -151,7 +141,7 @@ authority, then confirm npm access and publish from that same commit: The publish command uses the same automatic publication set and topological order as `release:check`. A coordinated release is incomplete until all 18 -packages exist at `0.10.0`; do not promote a partial package family. Preserve +packages exist at `0.11.0`; do not promote a partial package family. Preserve the exact `release-commit-sha` file with the release record. Every later lock, tag, rollback, and release check reads that authority instead of recapturing the current `HEAD`. @@ -184,14 +174,14 @@ smoke_root="$(mktemp -d)" cd "$smoke_root" npm init --yes >/dev/null - npm install --no-audit --no-fund @opentag/cli@0.10.0 - test "$("$smoke_root/node_modules/.bin/opentag" --version)" = "0.10.0" + npm install --no-audit --no-fund @opentag/cli@0.11.0 + test "$("$smoke_root/node_modules/.bin/opentag" --version)" = "0.11.0" "$smoke_root/node_modules/.bin/opentag" --help npm audit --prefix "$smoke_root" --omit=dev --audit-level=high ) ``` -The version must be `0.10.0`. With isolated config and state directories, run +The version must be `0.11.0`. With isolated config and state directories, run the setup, doctor, and foreground-start path for one platform that has real test credentials: @@ -229,12 +219,12 @@ Also verify every package and its canary tag before promotion: ( set -euo pipefail - test "$("$smoke_root/node_modules/.bin/opentag" --version)" = "0.10.0" + test "$("$smoke_root/node_modules/.bin/opentag" --version)" = "0.11.0" for manifest in packages/*/package.json; do [ "$(jq -r '.publishConfig.access // ""' "$manifest")" = "public" ] || continue package="$(jq -r '.name' "$manifest")" - test "$(npm view "$package@0.10.0" version)" = "0.10.0" - test "$(npm view "$package" dist-tags.next)" = "0.10.0" + test "$(npm view "$package@0.11.0" version)" = "0.11.0" + test "$(npm view "$package" dist-tags.next)" = "0.11.0" npm view "$package" dist-tags --json done ) @@ -251,7 +241,7 @@ window: ( set -euo pipefail - release_state_dir=".omx/releases/0.10.0" + release_state_dir=".omx/releases/0.11.0" release_commit_file="$release_state_dir/release-commit-sha" lock_owner_file="$release_state_dir/npm-dist-tags.lock-sha" test -f "$release_commit_file" @@ -302,7 +292,7 @@ retry cannot replace the original rollback authority: ( set -euo pipefail - release_state_dir=".omx/releases/0.10.0" + release_state_dir=".omx/releases/0.11.0" release_commit_file="$release_state_dir/release-commit-sha" lock_owner_file="$release_state_dir/npm-dist-tags.lock-sha" test -f "$release_commit_file" @@ -323,37 +313,24 @@ retry cannot replace the original rollback authority: [ "$(jq -r '.publishConfig.access // ""' "$manifest")" = "public" ] || continue package="$(jq -r '.name' "$manifest")" dist_tags_json="$(npm view "$package" dist-tags --json)" - case "$package" in - "@opentag/control-protocol"|"@opentag/delivery-contract") - previous_latest="$(jq -r '.latest // "absent"' <<<"$dist_tags_json")" - case "$previous_latest" in - absent|"0.10.0") ;; - *) echo "Refusing unexpected first-publication $package latest=$previous_latest" >&2; exit 1 ;; - esac - ;; - *) - previous_latest="$(jq -er '.latest | select(type == "string" and length > 0)' <<<"$dist_tags_json")" - test "$previous_latest" = "0.9.0" - ;; - esac + previous_latest="$(jq -er '.latest | select(type == "string" and length > 0)' <<<"$dist_tags_json")" + test "$previous_latest" = "0.10.0" printf '%s\t%s\n' "$package" "$previous_latest" >>"$snapshot_tmp" done test "$(wc -l <"$snapshot_tmp" | tr -d ' ')" = "18" test "$(cut -f1 "$snapshot_tmp" | sort -u | wc -l | tr -d ' ')" = "18" - test "$(awk -F '\t' '$1 != "@opentag/control-protocol" && $1 != "@opentag/delivery-contract" { print $2 }' "$snapshot_tmp" | sort -u)" = "0.9.0" + test "$(cut -f2 "$snapshot_tmp" | sort -u)" = "0.10.0" mv -n "$snapshot_tmp" "$rollback_file" test ! -e "$snapshot_tmp" ) ``` Keep that exact file until the release is complete. It records the actual -pre-promotion `latest` target for every package and fails unless the 16 -previously published packages are still on the known `0.9.0` baseline; the -never-published `@opentag/control-protocol` and `@opentag/delivery-contract` -record `absent` (or `0.10.0` on a partial-promotion retry). A registry lookup -failure or a missing/unexpected tag on any other package stops the release; it -is never interpreted as rollback authority. Back the snapshot up outside the -ephemeral shell session before changing any dist-tag. +pre-promotion `latest` target for every package and fails unless all 18 packages +are still on the known `0.10.0` baseline. A registry lookup failure or a +missing/unexpected tag stops the release; it is never interpreted as rollback +authority. Back the snapshot up outside the ephemeral shell session before +changing any dist-tag. The following promotion loop is retryable. Every first attempt and retry must reuse the original `rollback_file`; never rerun the snapshot block after any @@ -363,7 +340,7 @@ package has been promoted: ( set -euo pipefail - release_state_dir=".omx/releases/0.10.0" + release_state_dir=".omx/releases/0.11.0" release_commit_file="$release_state_dir/release-commit-sha" lock_owner_file="$release_state_dir/npm-dist-tags.lock-sha" test -f "$release_commit_file" @@ -373,83 +350,80 @@ package has been promoted: lock_commit="$(<"$lock_owner_file")" test "$(gh api repos/amplifthq/opentag/git/ref/heads/release-lock/npm-dist-tags --jq '.object.sha')" = "$lock_commit" test "$(gh api "repos/amplifthq/opentag/git/commits/$lock_commit" --jq '.parents[0].sha')" = "$release_commit" - rollback_file=".omx/releases/0.10.0/pre-promotion-latest.tsv" + rollback_file=".omx/releases/0.11.0/pre-promotion-latest.tsv" test -f "$rollback_file" test "$(wc -l <"$rollback_file" | tr -d ' ')" = "18" test "$(cut -f1 "$rollback_file" | sort -u | wc -l | tr -d ' ')" = "18" - test "$(awk -F '\t' '$1 != "@opentag/control-protocol" && $1 != "@opentag/delivery-contract" { print $2 }' "$rollback_file" | sort -u)" = "0.9.0" + test "$(cut -f2 "$rollback_file" | sort -u)" = "0.10.0" for manifest in packages/*/package.json; do [ "$(jq -r '.publishConfig.access // ""' "$manifest")" = "public" ] || continue package="$(jq -r '.name' "$manifest")" previous_latest="$(awk -F '\t' -v package="$package" '$1 == package { print $2 }' "$rollback_file")" + test "$previous_latest" = "0.10.0" current_tags_json="$(npm view "$package" dist-tags --json)" current_next="$(jq -er '.next | select(type == "string" and length > 0)' <<<"$current_tags_json")" - test "$current_next" = "0.10.0" - case "$package" in - "@opentag/control-protocol"|"@opentag/delivery-contract") - case "$previous_latest" in absent|"0.10.0") ;; *) echo "Refusing corrupt snapshot for $package" >&2; exit 1 ;; esac - current_latest="$(jq -r '.latest // "absent"' <<<"$current_tags_json")" - case "$current_latest" in - absent) npm dist-tag add "$package@0.10.0" latest ;; - "0.10.0") ;; - *) echo "Refusing to replace drifted $package latest=$current_latest" >&2; exit 1 ;; - esac - ;; - *) - test "$previous_latest" = "0.9.0" - current_latest="$(jq -er '.latest | select(type == "string" and length > 0)' <<<"$current_tags_json")" - case "$current_latest" in - "$previous_latest") npm dist-tag add "$package@0.10.0" latest ;; - "0.10.0") ;; - *) echo "Refusing to replace drifted $package latest=$current_latest" >&2; exit 1 ;; - esac - ;; + test "$current_next" = "0.11.0" + current_latest="$(jq -er '.latest | select(type == "string" and length > 0)' <<<"$current_tags_json")" + case "$current_latest" in + "$previous_latest") npm dist-tag add "$package@0.11.0" latest ;; + "0.11.0") ;; + *) echo "Refusing to replace drifted $package latest=$current_latest" >&2; exit 1 ;; esac - test "$(npm view "$package" dist-tags.latest)" = "0.10.0" - test "$(npm view "$package" dist-tags.next)" = "0.10.0" + test "$(npm view "$package" dist-tags.latest)" = "0.11.0" + test "$(npm view "$package" dist-tags.next)" = "0.11.0" done ) ``` Rerun the package loop from the registry-verification section and confirm both -`next` and `latest` point at `0.10.0` for all 18 packages. +`next` and `latest` point at `0.11.0` for all 18 packages. ## Create the matching source release Create the source tag from the exact clean commit used for `release:publish`. -Copy the `v0.10.0` section of `CHANGELOG.md` into a temporary release-notes file, -then run: +The block extracts the `v0.11.0` changelog section into a unique, validated +temporary release-notes file: ```bash ( set -euo pipefail - release_commit_file=".omx/releases/0.10.0/release-commit-sha" + release_commit_file=".omx/releases/0.11.0/release-commit-sha" test -f "$release_commit_file" release_commit="$(<"$release_commit_file")" test "$(git rev-parse HEAD)" = "$release_commit" test -z "$(git status --porcelain)" + release_notes_file="$(mktemp)" + release_tag_probe="" + trap 'rm -f -- "$release_notes_file"; if [ -n "$release_tag_probe" ]; then rm -f -- "$release_tag_probe"; fi' EXIT + awk ' + /^## v0\.11\.0 - / { in_release = 1; next } + in_release && /^## v/ { exit } + in_release { print } + ' CHANGELOG.md >"$release_notes_file" + test -s "$release_notes_file" + release_tag_probe="$(mktemp)" - if ! gh api --include --silent repos/amplifthq/opentag/git/ref/tags/v0.10.0 >"$release_tag_probe"; then + if ! gh api --include --silent repos/amplifthq/opentag/git/ref/tags/v0.11.0 >"$release_tag_probe"; then : # Inspect the HTTP status below; only a confirmed 404 permits tag creation. fi release_tag_status="$(awk 'toupper($1) ~ /^HTTP\// {status=$2} END {print status}' "$release_tag_probe")" - rm -f "$release_tag_probe" + rm -f -- "$release_tag_probe" case "$release_tag_status" in 200) - release_tag_ref="$(gh api repos/amplifthq/opentag/git/ref/tags/v0.10.0)" + release_tag_ref="$(gh api repos/amplifthq/opentag/git/ref/tags/v0.11.0)" ;; 404) - if git show-ref --verify --quiet refs/tags/v0.10.0; then - test "$(git cat-file -t refs/tags/v0.10.0)" = "tag" - test "$(git rev-parse 'v0.10.0^{}')" = "$release_commit" + if git show-ref --verify --quiet refs/tags/v0.11.0; then + test "$(git cat-file -t refs/tags/v0.11.0)" = "tag" + test "$(git rev-parse 'v0.11.0^{}')" = "$release_commit" else - git tag -a v0.10.0 "$release_commit" -m "OpenTag v0.10.0" + git tag -a v0.11.0 "$release_commit" -m "OpenTag v0.11.0" fi - git push origin refs/tags/v0.10.0 - release_tag_ref="$(gh api repos/amplifthq/opentag/git/ref/tags/v0.10.0)" + git push origin refs/tags/v0.11.0 + release_tag_ref="$(gh api repos/amplifthq/opentag/git/ref/tags/v0.11.0)" ;; *) echo "Refusing tag creation after upstream lookup returned HTTP ${release_tag_status:-unavailable}" >&2 @@ -460,19 +434,19 @@ then run: release_tag_object="$(jq -r '.object.sha' <<<"$release_tag_ref")" test "$(gh api "repos/amplifthq/opentag/git/tags/$release_tag_object" --jq '.object.sha')" = "$release_commit" existing_release_state="$(gh api --paginate 'repos/amplifthq/opentag/releases?per_page=100' \ - --jq '.[] | select(.tag_name == "v0.10.0") | [.tag_name, .draft, .prerelease, (.published_at != null)] | @tsv')" + --jq '.[] | select(.tag_name == "v0.11.0") | [.tag_name, .draft, .prerelease, (.published_at != null)] | @tsv')" case "$existing_release_state" in "") - gh release create v0.10.0 \ + gh release create v0.11.0 \ --verify-tag \ - --title "OpenTag v0.10.0" \ - --notes-file /tmp/opentag-v0.10.0-release-notes.md + --title "OpenTag v0.11.0" \ + --notes-file "$release_notes_file" ;; - $'v0.10.0\tfalse\tfalse\ttrue') ;; - *) echo "Refusing conflicting draft, prerelease, unpublished, or duplicate v0.10.0 GitHub Release state" >&2; exit 1 ;; + $'v0.11.0\tfalse\tfalse\ttrue') ;; + *) echo "Refusing conflicting draft, prerelease, unpublished, or duplicate v0.11.0 GitHub Release state" >&2; exit 1 ;; esac - release_state="$(gh api repos/amplifthq/opentag/releases/tags/v0.10.0)" - test "$(jq -r '.tag_name' <<<"$release_state")" = "v0.10.0" + release_state="$(gh api repos/amplifthq/opentag/releases/tags/v0.11.0)" + test "$(jq -r '.tag_name' <<<"$release_state")" = "v0.11.0" test "$(jq -r '.draft' <<<"$release_state")" = "false" test "$(jq -r '.prerelease' <<<"$release_state")" = "false" jq -er '.published_at | select(type == "string" and length > 0)' <<<"$release_state" >/dev/null @@ -485,11 +459,11 @@ the pushed remote tag must also be annotated and target that commit. The paginated release lookup must succeed before an absent release is created, so a network or API failure is never misread as authoritative absence. An existing draft, prerelease, unpublished object, or duplicate match is conflicting state: -stop and inspect it rather than treating it as the completed `v0.10.0` release. +stop and inspect it rather than treating it as the completed `v0.11.0` release. Verify that the GitHub Release tag resolves to the same commit that produced the npm tarballs. The release is not complete until npm, git, and GitHub all -identify version `0.10.0`. After that verification—or after a completed and +identify version `0.11.0`. After that verification—or after a completed and verified rollback—release the exclusive window only when it still points at your release commit: @@ -497,7 +471,7 @@ your release commit: ( set -euo pipefail - release_state_dir=".omx/releases/0.10.0" + release_state_dir=".omx/releases/0.11.0" release_commit_file="$release_state_dir/release-commit-sha" lock_owner_file="$release_state_dir/npm-dist-tags.lock-sha" test -f "$release_commit_file" @@ -520,15 +494,15 @@ Do not unpublish immutable package versions during rollback. `latest` tag unchanged and stop the rollout. Preserve `next` for diagnosis or move it to the corrected version. - If `latest` promotion fails partway, first finish or retry only the idempotent - promotion loop with the original snapshot. If 0.10.0 itself must be withdrawn, - restore each package's recorded pre-promotion target and leave 0.10.0 on `next` + promotion loop with the original snapshot. If 0.11.0 itself must be withdrawn, + restore each package's recorded pre-promotion target and leave 0.11.0 on `next` for diagnosis: ```bash ( set -euo pipefail - release_state_dir=".omx/releases/0.10.0" + release_state_dir=".omx/releases/0.11.0" release_commit_file="$release_state_dir/release-commit-sha" lock_owner_file="$release_state_dir/npm-dist-tags.lock-sha" test -f "$release_commit_file" @@ -538,56 +512,32 @@ Do not unpublish immutable package versions during rollback. lock_commit="$(<"$lock_owner_file")" test "$(gh api repos/amplifthq/opentag/git/ref/heads/release-lock/npm-dist-tags --jq '.object.sha')" = "$lock_commit" test "$(gh api "repos/amplifthq/opentag/git/commits/$lock_commit" --jq '.parents[0].sha')" = "$release_commit" - rollback_file=".omx/releases/0.10.0/pre-promotion-latest.tsv" + rollback_file=".omx/releases/0.11.0/pre-promotion-latest.tsv" test -f "$rollback_file" test "$(wc -l <"$rollback_file" | tr -d ' ')" = "18" test "$(cut -f1 "$rollback_file" | sort -u | wc -l | tr -d ' ')" = "18" - test "$(awk -F '\t' '$1 != "@opentag/control-protocol" && $1 != "@opentag/delivery-contract" { print $2 }' "$rollback_file" | sort -u)" = "0.9.0" + test "$(cut -f2 "$rollback_file" | sort -u)" = "0.10.0" for manifest in packages/*/package.json; do [ "$(jq -r '.publishConfig.access // ""' "$manifest")" = "public" ] || continue package="$(jq -r '.name' "$manifest")" - case "$package" in - "@opentag/control-protocol"|"@opentag/delivery-contract") - previous_latest="$(awk -F '\t' -v package="$package" '$1 == package { print $2 }' "$rollback_file")" - case "$previous_latest" in - absent|"0.10.0") ;; - *) echo "Refusing corrupt snapshot for $package" >&2; exit 1 ;; - esac - current_tags_json="$(npm view "$package" dist-tags --json)" - test "$(jq -er '.next | select(type == "string" and length > 0)' <<<"$current_tags_json")" = "0.10.0" - current_latest="$(jq -r '.latest // "absent"' <<<"$current_tags_json")" - case "$previous_latest:$current_latest" in - absent:absent|absent:0.10.0|0.10.0:0.10.0) ;; - *) echo "Refusing unexpected $package latest=$current_latest" >&2; exit 1 ;; - esac - # First publication: there is no previous `latest` to restore, and npm - # refuses to delete a package's `latest` tag. After validation, leave - # the tags unchanged (`latest` stays absent or 0.10.0) and record the - # withdrawal in the incident note. - continue - ;; - esac previous_latest="$(awk -F '\t' -v package="$package" '$1 == package { print $2 }' "$rollback_file")" - test "$previous_latest" = "0.9.0" + test "$previous_latest" = "0.10.0" test "$(npm view "$package@$previous_latest" version)" = "$previous_latest" current_tags_json="$(npm view "$package" dist-tags --json)" current_latest="$(jq -er '.latest | select(type == "string" and length > 0)' <<<"$current_tags_json")" current_next="$(jq -er '.next | select(type == "string" and length > 0)' <<<"$current_tags_json")" - test "$current_next" = "0.10.0" + test "$current_next" = "0.11.0" case "$current_latest" in "$previous_latest") ;; - "0.10.0") npm dist-tag add "$package@$previous_latest" latest ;; + "0.11.0") npm dist-tag add "$package@$previous_latest" latest ;; *) echo "Refusing to replace drifted $package latest=$current_latest" >&2; exit 1 ;; esac test "$(npm view "$package" dist-tags.latest)" = "$previous_latest" - test "$(npm view "$package" dist-tags.next)" = "0.10.0" + test "$(npm view "$package" dist-tags.next)" = "0.11.0" done ) ``` Verify all dist-tags after rollback, publish a clear incident note, then release -the exclusive window with the guarded command above. The incident note must -state that `@opentag/control-protocol` and `@opentag/delivery-contract` keep -`latest` absent or at `0.10.0` (both are valid rollback outcomes, depending on -whether promotion reached them) because a first publication has no earlier -stable target. A later fix must use a new version; never overwrite `0.10.0`. +the exclusive window with the guarded command above. A later fix must use a new +version; never overwrite `0.11.0`. diff --git a/docs/versioning.md b/docs/versioning.md index 61e4b117..d496e95e 100644 --- a/docs/versioning.md +++ b/docs/versioning.md @@ -34,9 +34,9 @@ Private runnable apps are not published: ## Pre-1.0 Policy -The source package family is prepared as the coordinated `0.10.0` release. +The source package family is prepared as the coordinated `0.11.0` release. Source manifests are preparation evidence only: npm dist-tags remain -authoritative for published channel versions, and `0.9.0` remains the +authoritative for published channel versions, and `0.10.0` remains the documented stable release until registry evidence says otherwise. The public API is still settling, so all releases remain in the `0.x` line until the package contracts are stable enough for `1.0.0`. @@ -59,8 +59,12 @@ and introduces an optional self-hosted Control Plane distributed as a private OCI image. Its release procedure is documented in [`npm-release.md`](npm-release.md); the earlier `0.10.0-next.0` candidate procedure in [`npm-prerelease.md`](npm-prerelease.md) was superseded before -publication. Preparing this source state does not assert that npm publication, -provider-live validation, or stable promotion has occurred. +publication. +The `0.11.0` release makes zero-config governed completion fail closed until +GitHub proves a non-empty, complete current-head check rollup. It also updates +the exported `GitHubCompletionApi` page-return contracts and adds the required +`checksComplete` field to `GitHubVerifiedPullRequestSnapshot`; these pre-1.0 +TypeScript contract changes are documented in the changelog. For each npm release: diff --git a/packages/cli/package.json b/packages/cli/package.json index bfbb1f43..75633cd5 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@opentag/cli", - "version": "0.10.0", + "version": "0.11.0", "description": "OpenTag command line interface.", "type": "module", "engines": { diff --git a/packages/cli/test/docs-contract.test.ts b/packages/cli/test/docs-contract.test.ts index 3717a100..32af555c 100644 --- a/packages/cli/test/docs-contract.test.ts +++ b/packages/cli/test/docs-contract.test.ts @@ -49,16 +49,22 @@ describe("platform setup docs contract", () => { expect(normalizedPrereleaseGuide).toContain( "The `0.10.0-next.0` candidate described here was never published" ); - expect(versioningGuide).toContain("coordinated `0.10.0` release"); + expect(versioningGuide).toContain("The `0.10.0` release"); expect(readme).toContain("[npm prerelease candidate guide](docs/npm-prerelease.md)"); expect(readmeZh).toContain("[npm prerelease 候选发布指南](docs/npm-prerelease.md)"); }); - it("keeps the 0.10.0 release procedure explicit and concurrency-safe", () => { + it("keeps the 0.11.0 release procedure explicit and concurrency-safe", () => { const releaseGuide = repoFile("docs/npm-release.md"); const liveGuide = repoFile("docs/live-e2e-smoke-harness.md"); + const versioningGuide = repoFile("docs/versioning.md"); + const changelog = repoFile("CHANGELOG.md"); - expect(liveGuide).toContain("npm install --no-audit --no-fund @opentag/cli@0.10.0"); + expect(liveGuide).toContain("npm install --no-audit --no-fund @opentag/cli@0.11.0"); + expect(versioningGuide).toContain("coordinated `0.11.0` release"); + expect(changelog).toContain("## v0.11.0 - 2026-08-17"); + expect(changelog).toContain("GitHubCompletionApi"); + expect(changelog).toContain("checksComplete"); expect(liveGuide).toContain('smoke_root="$(mktemp -d)"\n(\n set -euo pipefail'); expect(releaseGuide).toContain("refs/heads/release-lock/npm-dist-tags"); expect(releaseGuide).toContain("npm-dist-tags.lock-sha"); @@ -69,42 +75,45 @@ describe("platform setup docs contract", () => { expect(releaseGuide).toContain('= "$lock_commit"'); expect(releaseGuide).toContain('current_latest="$(jq -er'); expect(releaseGuide).toContain('current_next="$(jq -er'); - expect(releaseGuide).toContain('test "$current_next" = "0.10.0"'); - expect(releaseGuide).toContain("First-publication exception"); - expect( - releaseGuide.match(/"@opentag\/control-protocol"\|"@opentag\/delivery-contract"\)/gu) - ).toHaveLength(3); - expect(releaseGuide).toContain("no previous `latest` to restore"); - expect(releaseGuide.match(/test "\$previous_latest" = "0\.9\.0"/gu)).toHaveLength(3); + expect(releaseGuide).toContain('test "$current_next" = "0.11.0"'); + expect(releaseGuide).not.toContain("First-publication exception"); + expect(releaseGuide).not.toContain('"@opentag/control-protocol"|"@opentag/delivery-contract")'); + expect(releaseGuide).not.toContain("no previous `latest` to restore"); + expect(releaseGuide.match(/test "\$previous_latest" = "0\.10\.0"/gu)).toHaveLength(3); expect( releaseGuide.match( - /awk -F '\\t' '\$1 != "@opentag\/control-protocol" && \$1 != "@opentag\/delivery-contract" \{ print \$2 \}' "\$(?:snapshot_tmp|rollback_file)" \| sort -u\)" = "0\.9\.0"/gu + /test "\$\(cut -f2 "\$(?:snapshot_tmp|rollback_file)" \| sort -u\)" = "0\.10\.0"/gu ) ).toHaveLength(3); - expect(releaseGuide).not.toContain('"0.8.0"'); - expect(releaseGuide.match(/test "\$\("\$smoke_root\/node_modules\/\.bin\/opentag" --version\)" = "0\.10\.0"/gu)) + expect(releaseGuide).not.toContain('"0.9.0"'); + expect(releaseGuide.match(/test "\$\("\$smoke_root\/node_modules\/\.bin\/opentag" --version\)" = "0\.11\.0"/gu)) .toHaveLength(2); expect(releaseGuide).toContain('smoke_root="$(mktemp -d)"\n(\n set -euo pipefail'); expect(releaseGuide).toContain( 'Also verify every package and its canary tag before promotion:\n\n```bash\n(\n set -euo pipefail' ); - expect(releaseGuide).toContain('git tag -a v0.10.0 "$release_commit" -m "OpenTag v0.10.0"'); + expect(releaseGuide).toContain('git tag -a v0.11.0 "$release_commit" -m "OpenTag v0.11.0"'); expect(releaseGuide).toContain( - "if ! gh api --include --silent repos/amplifthq/opentag/git/ref/tags/v0.10.0" + "if ! gh api --include --silent repos/amplifthq/opentag/git/ref/tags/v0.11.0" ); expect(releaseGuide).toContain("only a confirmed 404 permits tag creation"); expect(releaseGuide).toContain("release_tag_status=\"$(awk 'toupper($1) ~ /^HTTP\\//"); expect(releaseGuide).toContain('case "$release_tag_status" in\n 200)'); - expect(releaseGuide).toContain(" 404)\n if git show-ref --verify --quiet refs/tags/v0.10.0; then"); + expect(releaseGuide).toContain(" 404)\n if git show-ref --verify --quiet refs/tags/v0.11.0; then"); expect(releaseGuide).toContain("Refusing tag creation after upstream lookup returned HTTP"); - expect(releaseGuide).toContain("git show-ref --verify --quiet refs/tags/v0.10.0"); - expect(releaseGuide).toContain("git cat-file -t refs/tags/v0.10.0"); - expect(releaseGuide).toContain('git rev-parse \'v0.10.0^{}\''); - expect(releaseGuide).toContain("git push origin refs/tags/v0.10.0"); + expect(releaseGuide).toContain("git show-ref --verify --quiet refs/tags/v0.11.0"); + expect(releaseGuide).toContain("git cat-file -t refs/tags/v0.11.0"); + expect(releaseGuide).toContain('git rev-parse \'v0.11.0^{}\''); + expect(releaseGuide).toContain("git push origin refs/tags/v0.11.0"); expect(releaseGuide).toContain('git/tags/$release_tag_object'); expect(releaseGuide).toContain("gh api --paginate 'repos/amplifthq/opentag/releases?per_page=100'"); expect(releaseGuide).toContain('case "$existing_release_state" in'); - expect(releaseGuide).toContain("$'v0.10.0\\tfalse\\tfalse\\ttrue'"); + expect(releaseGuide).toContain("$'v0.11.0\\tfalse\\tfalse\\ttrue'"); + expect(releaseGuide).toContain('release_notes_file="$(mktemp)"'); + expect(releaseGuide).toContain('test -s "$release_notes_file"'); + expect(releaseGuide).toContain("trap 'rm -f -- \"$release_notes_file\""); + expect(releaseGuide).toContain('--notes-file "$release_notes_file"'); + expect(releaseGuide).not.toContain("/tmp/opentag-v0.11.0-release-notes.md"); expect(releaseGuide).toContain("'.draft'"); expect(releaseGuide).toContain("'.prerelease'"); expect(releaseGuide).toContain('.published_at | select(type == "string" and length > 0)'); @@ -145,12 +154,13 @@ describe("platform setup docs contract", () => { const controlPlane = repoFile("skills/opentag/references/control-plane.md"); const completion = repoFile("skills/opentag/references/completion-governance.md"); expect(skillDocs).not.toContain("@opentag/cli@latest"); + expect(skillDocs).not.toContain("@opentag/cli@0.10.0"); expect(skillDocs).not.toMatch(/\bnpx(?: --yes)? @opentag\/cli(?:\s|$)/u); expect(skillDocs).not.toMatch(/\bnpm install -g @opentag\/cli(?:\s|$)/u); - expect(skill).toContain("npm install -g @opentag/cli@0.10.0"); - expect(skill).toContain("npx @opentag/cli@0.10.0 setup"); + expect(skill).toContain("npm install -g @opentag/cli@0.11.0"); + expect(skill).toContain("npx @opentag/cli@0.11.0 setup"); expect(skill).toContain("For a global install, verify with `opentag --version`"); - expect(skill).toContain("For the no-global path, verify with `npx @opentag/cli@0.10.0 --version`"); + expect(skill).toContain("For the no-global path, verify with `npx @opentag/cli@0.11.0 --version`"); expect(skill).toContain("request_user_input"); expect(skill).toContain("askhuman"); expect(skill).toContain("Codex Plan mode"); @@ -182,7 +192,7 @@ describe("platform setup docs contract", () => { 'HTTPS_PROXY="" HTTP_PROXY="" npm view @opentag/cli version --fetch-timeout=15000' ); expect(skill).toContain("Only after npm registry metadata is reachable"); - expect(skill).toContain("npx --yes @opentag/cli@0.10.0 --help"); + expect(skill).toContain("npx --yes @opentag/cli@0.11.0 --help"); expect(skill).toContain("do not permanently change `npm config` without explicit user confirmation"); expect(skill).toContain("Only use a proxy URL the user provides or that is already active in the environment"); expect(skill).toContain("npm cache metadata exists"); diff --git a/packages/client/package.json b/packages/client/package.json index 09fc12c2..7416a189 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@opentag/client", - "version": "0.10.0", + "version": "0.11.0", "description": "HTTP client SDK for creating, claiming, and updating OpenTag dispatcher runs.", "type": "module", "engines": { diff --git a/packages/control-protocol/package.json b/packages/control-protocol/package.json index 6fd6eb82..414c7713 100644 --- a/packages/control-protocol/package.json +++ b/packages/control-protocol/package.json @@ -1,6 +1,6 @@ { "name": "@opentag/control-protocol", - "version": "0.10.0", + "version": "0.11.0", "description": "Canonical OpenTag Control V1 schemas, types, and digest helpers.", "type": "module", "engines": { diff --git a/packages/core/package.json b/packages/core/package.json index eda1aaf2..1a8fdb35 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@opentag/core", - "version": "0.10.0", + "version": "0.11.0", "description": "Core OpenTag protocol schemas, types, JSON Schema, and mention parsing.", "type": "module", "engines": { diff --git a/packages/delivery-contract/package.json b/packages/delivery-contract/package.json index 0f11dbb0..38af4d11 100644 --- a/packages/delivery-contract/package.json +++ b/packages/delivery-contract/package.json @@ -1,6 +1,6 @@ { "name": "@opentag/delivery-contract", - "version": "0.10.0", + "version": "0.11.0", "description": "Canonical OpenTag side-effect intent and delivery observation contracts.", "type": "module", "engines": { diff --git a/packages/discord/package.json b/packages/discord/package.json index e4bdb298..c88c88ed 100644 --- a/packages/discord/package.json +++ b/packages/discord/package.json @@ -1,6 +1,6 @@ { "name": "@opentag/discord", - "version": "0.10.0", + "version": "0.11.0", "description": "Discord interactions normalization and callback rendering for OpenTag.", "type": "module", "engines": { diff --git a/packages/dispatcher/package.json b/packages/dispatcher/package.json index a8825b9e..d4223518 100644 --- a/packages/dispatcher/package.json +++ b/packages/dispatcher/package.json @@ -1,6 +1,6 @@ { "name": "@opentag/dispatcher", - "version": "0.10.0", + "version": "0.11.0", "description": "Embeddable OpenTag dispatcher Hono app and durable delivery coordination.", "type": "module", "engines": { diff --git a/packages/github/package.json b/packages/github/package.json index 2598c6f9..0db97a26 100644 --- a/packages/github/package.json +++ b/packages/github/package.json @@ -1,6 +1,6 @@ { "name": "@opentag/github", - "version": "0.10.0", + "version": "0.11.0", "description": "GitHub event normalization and callback rendering for OpenTag.", "type": "module", "engines": { diff --git a/packages/gitlab/package.json b/packages/gitlab/package.json index fc917f02..16441b00 100644 --- a/packages/gitlab/package.json +++ b/packages/gitlab/package.json @@ -1,6 +1,6 @@ { "name": "@opentag/gitlab", - "version": "0.10.0", + "version": "0.11.0", "description": "GitLab webhook normalization and callback rendering for OpenTag.", "type": "module", "engines": { diff --git a/packages/governance/package.json b/packages/governance/package.json index 46343c4a..78f4a29e 100644 --- a/packages/governance/package.json +++ b/packages/governance/package.json @@ -1,6 +1,6 @@ { "name": "@opentag/governance", - "version": "0.10.0", + "version": "0.11.0", "description": "Deterministic execution governance for OpenTag work loops.", "type": "module", "engines": { diff --git a/packages/lark/package.json b/packages/lark/package.json index f87e40c9..3e9861ed 100644 --- a/packages/lark/package.json +++ b/packages/lark/package.json @@ -1,6 +1,6 @@ { "name": "@opentag/lark", - "version": "0.10.0", + "version": "0.11.0", "description": "Lark/Feishu message normalization and callback helpers for OpenTag.", "type": "module", "engines": { diff --git a/packages/linear/package.json b/packages/linear/package.json index 605bbaad..c72fc1f2 100644 --- a/packages/linear/package.json +++ b/packages/linear/package.json @@ -1,6 +1,6 @@ { "name": "@opentag/linear", - "version": "0.10.0", + "version": "0.11.0", "description": "Linear webhook normalization, callback rendering, and issue mutation helpers for OpenTag.", "type": "module", "engines": { diff --git a/packages/local-runtime/package.json b/packages/local-runtime/package.json index c51f34b0..752eedaf 100644 --- a/packages/local-runtime/package.json +++ b/packages/local-runtime/package.json @@ -1,6 +1,6 @@ { "name": "@opentag/local-runtime", - "version": "0.10.0", + "version": "0.11.0", "description": "Local OpenTag dispatcher, daemon, and diagnostics runtime helpers.", "type": "module", "engines": { diff --git a/packages/runner/package.json b/packages/runner/package.json index 2d5b1881..24013948 100644 --- a/packages/runner/package.json +++ b/packages/runner/package.json @@ -1,6 +1,6 @@ { "name": "@opentag/runner", - "version": "0.10.0", + "version": "0.11.0", "description": "Executor contracts and built-in runner adapters for OpenTag.", "type": "module", "engines": { diff --git a/packages/slack/package.json b/packages/slack/package.json index 3b19ae1b..94731951 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opentag/slack", - "version": "0.10.0", + "version": "0.11.0", "description": "Slack app mention normalization and callback helpers for OpenTag.", "type": "module", "engines": { diff --git a/packages/store/package.json b/packages/store/package.json index b1990267..31a84a66 100644 --- a/packages/store/package.json +++ b/packages/store/package.json @@ -1,6 +1,6 @@ { "name": "@opentag/store", - "version": "0.10.0", + "version": "0.11.0", "description": "SQLite and Drizzle persistence primitives for OpenTag runs and leases.", "type": "module", "engines": { diff --git a/packages/teams/package.json b/packages/teams/package.json index 237912da..8aca88b7 100644 --- a/packages/teams/package.json +++ b/packages/teams/package.json @@ -1,6 +1,6 @@ { "name": "@opentag/teams", - "version": "0.10.0", + "version": "0.11.0", "description": "Microsoft Teams activity normalization and callback rendering for OpenTag.", "type": "module", "engines": { "node": ">=20" }, diff --git a/packages/telegram/package.json b/packages/telegram/package.json index 0770ade6..e0496d5a 100644 --- a/packages/telegram/package.json +++ b/packages/telegram/package.json @@ -1,6 +1,6 @@ { "name": "@opentag/telegram", - "version": "0.10.0", + "version": "0.11.0", "description": "Telegram message normalization and callback helpers for OpenTag.", "type": "module", "engines": { diff --git a/scripts/dev/run-slack-linear-backlog-live-test.ts b/scripts/dev/run-slack-linear-backlog-live-test.ts index 4e3a289b..fe78f8ee 100644 --- a/scripts/dev/run-slack-linear-backlog-live-test.ts +++ b/scripts/dev/run-slack-linear-backlog-live-test.ts @@ -329,7 +329,7 @@ async function waitForSlackReply(input: { async function main(): Promise { const rootDir = resolve(dirname(fileURLToPath(import.meta.url)), "../.."); - const expectedVersion = optionalEnv("OPENTAG_SLACK_LINEAR_EXPECTED_CLI_VERSION") ?? "0.10.0"; + const expectedVersion = optionalEnv("OPENTAG_SLACK_LINEAR_EXPECTED_CLI_VERSION") ?? "0.11.0"; const configSourcePath = resolve(requiredEnv("OPENTAG_CONFIG_PATH")); const botToken = requiredEnv("OPENTAG_SLACK_BOT_TOKEN"); const appToken = requiredEnv("OPENTAG_SLACK_APP_TOKEN"); diff --git a/skills/opentag/SKILL.md b/skills/opentag/SKILL.md index b0ec809f..7abc6439 100644 --- a/skills/opentag/SKILL.md +++ b/skills/opentag/SKILL.md @@ -14,7 +14,7 @@ Use the published CLI first. Do not start from repo-internal apps, old shell scr Recommended user path: ```bash -npm install -g @opentag/cli@0.10.0 +npm install -g @opentag/cli@0.11.0 opentag setup opentag start ``` @@ -22,8 +22,8 @@ opentag start No global install: ```bash -npx @opentag/cli@0.10.0 setup -npx @opentag/cli@0.10.0 start +npx @opentag/cli@0.11.0 setup +npx @opentag/cli@0.11.0 start ``` ## Route The Request @@ -53,7 +53,7 @@ For platform credential steps, use the repository docs as the source of truth: ## Working Rules - Keep setup user-led. Never invent tokens, app IDs, Slack team/channel IDs, GitHub owner/repo names, or local project paths. -- Use the reviewed CLI version `0.10.0` consistently in install and `npx` commands. For a global install, verify with `opentag --version`. For the no-global path, verify with `npx @opentag/cli@0.10.0 --version`. Update the pin only after reviewing a newer release. +- Use the reviewed CLI version `0.11.0` consistently in install and `npx` commands. For a global install, verify with `opentag --version`. For the no-global path, verify with `npx @opentag/cli@0.11.0 --version`. Update the pin only after reviewing a newer release. - Prefer Slack, then GitHub, then GitLab, then Linear, then Lark / Feishu when listing established paths; label Telegram, Discord, and Microsoft Teams as previews. - Ask the user which platform and coding agent they want if it is not already clear outside Codex. - In Codex Plan mode, use `request_user_input` / askhuman to collect non-secret setup choices before running `opentag setup`, then pass those choices as CLI flags so the terminal wizard does not silently choose defaults. @@ -70,7 +70,7 @@ For platform credential steps, use the repository docs as the source of truth: ## Npm Registry And Network Failures -If `npm install -g @opentag/cli@0.10.0` or `npx @opentag/cli@0.10.0 ...` fails before the OpenTag CLI starts, keep the exact npm error and diagnose the package delivery path before giving up. Treat errors such as `ENOTFOUND`, `EAI_AGAIN`, `ETIMEDOUT`, `ECONNRESET`, `fetch failed`, proxy connection failures, and TLS certificate errors as network or npm-environment issues, not as OpenTag setup failures. +If `npm install -g @opentag/cli@0.11.0` or `npx @opentag/cli@0.11.0 ...` fails before the OpenTag CLI starts, keep the exact npm error and diagnose the package delivery path before giving up. Treat errors such as `ENOTFOUND`, `EAI_AGAIN`, `ETIMEDOUT`, `ECONNRESET`, `fetch failed`, proxy connection failures, and TLS certificate errors as network or npm-environment issues, not as OpenTag setup failures. Use safe, non-secret checks first: @@ -94,7 +94,7 @@ HTTPS_PROXY="" HTTP_PROXY="" npm view @opentag/cli version Only after npm registry metadata is reachable, retry the CLI help command: ```bash -npx --yes @opentag/cli@0.10.0 --help +npx --yes @opentag/cli@0.11.0 --help ``` Only use a proxy URL the user provides or that is already active in the environment. Do not invent proxy hosts, tokens, certificates, or registry credentials. If npm cache metadata exists but `npx --offline` or `npm pack --offline` still fails, do not claim the CLI is available offline; report that the cache is not executable and wait for registry access to recover. @@ -119,7 +119,7 @@ After the user chooses, run `opentag setup` with matching flags, for example `-- 2. Install or run the CLI. If npm cannot reach the published package, follow "Npm Registry And Network Failures" before treating setup as blocked. - Completion: `opentag --help` or `npx @opentag/cli@0.10.0 --help` works. + Completion: `opentag --help` or `npx @opentag/cli@0.11.0 --help` works. 3. Run setup. Completion: `opentag setup` has collected platform, executor, project path, and credentials. diff --git a/skills/opentag/references/codex-runner.md b/skills/opentag/references/codex-runner.md index e8f2219a..b6d66726 100644 --- a/skills/opentag/references/codex-runner.md +++ b/skills/opentag/references/codex-runner.md @@ -33,7 +33,7 @@ The user also needs a local project checkout that the chosen executor can safely ## User Path ```bash -npm install -g @opentag/cli@0.10.0 +npm install -g @opentag/cli@0.11.0 opentag setup ``` diff --git a/skills/opentag/references/github-setup.md b/skills/opentag/references/github-setup.md index f09a967f..9070c630 100644 --- a/skills/opentag/references/github-setup.md +++ b/skills/opentag/references/github-setup.md @@ -28,7 +28,7 @@ Never invent tokens, owner names, repository names, webhook secrets, or project ## User Path ```bash -npm install -g @opentag/cli@0.10.0 +npm install -g @opentag/cli@0.11.0 opentag setup ``` diff --git a/skills/opentag/references/local-echo.md b/skills/opentag/references/local-echo.md index 874fa8c0..e4b9709f 100644 --- a/skills/opentag/references/local-echo.md +++ b/skills/opentag/references/local-echo.md @@ -13,7 +13,7 @@ Do not recommend Echo for real use unless the user explicitly wants a smoke test Install or run the CLI: ```bash -npm install -g @opentag/cli@0.10.0 +npm install -g @opentag/cli@0.11.0 opentag setup ``` diff --git a/skills/opentag/references/slack-setup.md b/skills/opentag/references/slack-setup.md index d457fd55..6909346c 100644 --- a/skills/opentag/references/slack-setup.md +++ b/skills/opentag/references/slack-setup.md @@ -37,7 +37,7 @@ Never invent these values. Walk the user through Slack's app page and ask them t ## User Path ```bash -npm install -g @opentag/cli@0.10.0 +npm install -g @opentag/cli@0.11.0 opentag setup ```