Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "axme-code",
"version": "0.5.0",
"version": "0.6.1",
"description": "(Alpha) Persistent memory, architectural decisions, and safety guardrails for Claude Code. Your agent starts every session with full project context — stack, decisions, patterns, safety rules, and a handoff from the previous session.",
"author": {
"name": "AXME AI",
Expand Down
16 changes: 16 additions & 0 deletions .github/workflows/publish-extension.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,22 @@ jobs:
steps:
- uses: actions/checkout@v4

# Guard against tag/manifest drift (same class as the v0.6.0 incident:
# extension-v0.1.5 was first tagged before the version-bump PR merged,
# so the workflow built a 0.1.4-manifest .vsix and Open VSX rejected it
# as already published). Fail before building.
- name: Verify tag matches extension manifest
if: startsWith(github.ref, 'refs/tags/extension-v')
shell: bash
run: |
tag="${GITHUB_REF#refs/tags/extension-v}"
ver="$(jq -r .version extension/package.json)"
if [ "$tag" != "$ver" ]; then
echo "::error::Version drift: tag extension-v${tag} vs extension/package.json ${ver}. Merge the release PR before pushing the tag, then re-tag on the merged commit."
exit 1
fi
echo "Extension manifest consistent: extension-v${tag}"

- uses: actions/setup-node@v4
with:
node-version: 20
Expand Down
18 changes: 18 additions & 0 deletions .github/workflows/release-binary.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,24 @@ jobs:
- name: Checkout
uses: actions/checkout@v4

# Guard against tag/manifest drift. June 2026 postmortem: the v0.6.0
# tag was pushed before the release PR merged (binaries said 0.6.0,
# package.json said 0.5.0), and .claude-plugin/plugin.json was not
# bumped at all for two releases — Claude Code keys plugin update
# detection on that version, so plugin users were stuck. Fail the
# whole release BEFORE building anything if the three disagree.
- name: Verify tag matches version manifests
if: startsWith(github.ref, 'refs/tags/v')
run: |
tag="${GITHUB_REF#refs/tags/v}"
pkg="$(jq -r .version package.json)"
plugin="$(jq -r .version .claude-plugin/plugin.json)"
if [ "$tag" != "$pkg" ] || [ "$tag" != "$plugin" ]; then
echo "::error::Version drift: tag v${tag} vs package.json ${pkg} vs .claude-plugin/plugin.json ${plugin}. Merge the release PR (which bumps all manifests in lockstep) BEFORE pushing the tag, then re-tag on the merged commit."
exit 1
fi
echo "Version manifests consistent: v${tag}"

- name: Setup Node
uses: actions/setup-node@v4
with:
Expand Down
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,29 @@

## [Unreleased]

## [0.6.1] - 2026-06-11

Launch-readiness release. A four-agent audit of every distribution channel (standalone binary, npm, Claude Code plugin, Cursor extension) — with findings reproduced against the released v0.6.0 / extension-v0.1.5 artifacts — surfaced a set of first-run and channel-health bugs. This release fixes all of them and adds release-process guards so the channel breakages cannot silently recur.

### Fixed

- **Plugin audit pipeline was dead for plugin installs.** The detached audit-worker spawner reused `process.argv[1]`, which for plugin installs is `server.mjs` (no CLI dispatch) — finalize-close, disconnect cleanup, and orphan recovery booted a second MCP server that exited immediately instead of running the audit. Sessions were never audited and orphan recovery re-queued them forever. The spawner now resolves the sibling `cli.mjs` when argv[1] is a server entry.
- **Auto-update silently disabled for all binary installs.** `fetchLatestRelease()` used `/releases/latest`, which resolves to whichever release was published most recently — currently `extension-v0.1.5` — so the semver comparison hit NaN and no update ever happened. Same bug class as the install.sh 404 fixed in v0.6.0; same fix (release-list endpoint filtered to `^v[0-9]`).
- **`axme-code setup --help` ran a full paid LLM scan into a literal `--help/` directory.** Unknown flags fell through to the positional-path slot (reproduced: $0.49 and $0.77 of API spend). Setup now rejects unknown flags (exit 2), prints usage for `--help`/`-h`, rejects nonexistent paths, and rejects extra positionals.
- **Setup destroyed user config when a JSON file was hand-edited.** Invalid JSON in `.claude/settings.json`, `.mcp.json`, `.cursor/mcp.json`, or `.cursor/hooks.json` hit a `catch { … = {} }` fallback and the file was silently rewritten — wiping the user's permissions, env, other MCP servers, and their own hooks. All writers (CLI and extension) now refuse with an actionable error and leave the file untouched.
- **Interrupted setup permanently bricked setup.** `setup.lock` removal was skipped on any scanner exception; `--force` didn't bypass the lock; the rerun printed a misleading "Already initialized … Done!" (exit 0). The lock is now held in try/finally, self-expires after 15 minutes, `--force` bypasses it, and a genuine lock-skip reports honestly (exit 1 with recovery instructions).
- **First-run setup created duplicate decision IDs.** Preset bundles and the init scanner both numbered from D-001, so D-001..D-009 were written twice and every later lookup/supersede by id was ambiguous. `saveDecisions` now renumbers colliding ids past the max stored id (including superseded ones).
- **Cursor extension (Windows): hooks duplicated on every restart and could not be removed.** The dedupe/uninstall filter matched only `axme-code`, but Windows hook commands reference `axme-hook.cmd` — every activation appended three more entries, and Reset/uninstall left them behind pointing at a deleted wrapper. The filter now matches both shapes; with it fixed, the per-activation rewrite also self-heals stale version-dir paths after extension updates.
- **Cursor extension (macOS/Linux): Node-less machines got an unexplained dead extension.** The bundled CLI is a `#!/usr/bin/env node` shim and Cursor spawns the MCP server outside the extension host — without Node 20+ on PATH users saw "MCP server does not exist" and silently failing hooks. New soft-fail activation preflight surfaces an actionable error (with an Open-nodejs.org button) and a `Node` line in the activation report. install.sh now performs the same check at install time (`AXME_SKIP_NODE_CHECK=1` to bypass), and the README documents the Node 20+ requirement for Linux/macOS.
- **Extension-spawned setup wrote duplicate/stale project-level Cursor config.** `setup --ide cursor` wrote `.cursor/mcp.json` (a same-name `axme` server with a PATH-dependent command that extension-only users can't run) and `.cursor/hooks.json` (absolute paths into the version-numbered extension dir — stale after every update, double-firing on top of user-level hooks). The extension now passes `AXME_SETUP_FROM_EXTENSION=1` and the CLI skips both writers under it.
- **Contradictory "not initialized" instructions.** The server instructions said "EXECUTE inline setup", `axme_context` said "do NOT run setup", and the plugin-written CLAUDE.md said "run `axme-code setup --plugin` via Bash immediately" (impossible for plugin installs — the binary is not on PATH). All surfaces now tell one story: offer the user setup, on consent execute the inline `axme_save_*` flow; never invoke `axme-code` via Bash. Also removed the "runs inline on your Cursor subscription" wording shown to Claude Code users, fixed `axme_status`'s reference to the long-removed `axme_init`, and the hooks summary line now mentions PreToolUse.
- **MCP `serverInfo.version` was hardcoded `0.1.0`.** Now reports the real release version.
- **`.claude-plugin/plugin.json` version catch-up (0.5.0 → 0.6.1).** The v0.6.0 release was prepared manually, bypassing `scripts/release.sh`, so the plugin manifest (and the plugin README badge) stayed at 0.5.0 — and Claude Code keys plugin update detection on that version.

### Added

- **Release-process guards.** `release-binary.yml` fails before building if the tag, `package.json`, and `.claude-plugin/plugin.json` versions disagree; `publish-extension.yml` does the same for `extension/package.json`. Either guard would have caught both June-3 release incidents (tag pushed before the release PR merged; plugin manifest drift). `scripts/release.sh` postflight now also verifies the **community-marketplace SHA pin** — `claude plugin install axme-code@claude-community` installs the commit pinned in `anthropics/claude-plugins-community`, not our plugin repo HEAD, and that pin still pointed at April's v0.2.9 until this release cycle. The check prints exact instructions for the marketplace bump PR until it lands.

## [0.6.0] - 2026-06-03

A multi-IDE / multi-host release. Adds first-class Cursor support (hook adapter, transcript parser, AgentSdk factory), upgrades telemetry attribution for setup failures, fixes a long-standing pile of search-mode-on-Windows installation issues, hardens the scanners against credential reads, and makes the `axme_finalize_close` schema produce actionable errors when an agent omits a required field.
Expand Down
2 changes: 1 addition & 1 deletion extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "axme-code",
"displayName": "AXME Code",
"description": "Persistent memory, decisions, and safety guardrails for Cursor, GitHub Copilot, Cline, Continue, Roo Code, Windsurf, and VS Code chat agents",
"version": "0.1.5",
"version": "0.1.6",
"publisher": "AxmeAI",
"repository": {
"type": "git",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@axme/code",
"version": "0.6.0",
"version": "0.6.1",
"description": "Persistent memory, decisions, and safety guardrails for Claude Code",
"type": "module",
"main": "./dist/server.js",
Expand Down
31 changes: 30 additions & 1 deletion scripts/release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,18 @@
# 3. Open release PR (release/vX.Y.Z), commit "release: bump version to X.Y.Z"
# 4. Wait for user to merge the PR (script pauses)
# 5. After merge: tag, push, watch chained workflow (build → release → npm → plugin sync)
# 6. Postflight verify: npm version, GitHub release, plugin repo plugin.json
# 6. Postflight verify: npm version, GitHub release, plugin repo plugin.json,
# AND the community-marketplace SHA pin (see below)
#
# IMPORTANT — the Claude Code marketplace pins us by SHA:
# `claude plugin install axme-code@claude-community` reads
# anthropics/claude-plugins-community/.claude-plugin/marketplace.json,
# which pins our plugin to a COMMIT SHA of AxmeAI/axme-code-plugin. Our
# sync job updates the plugin repo, but new users keep getting the pinned
# SHA until someone opens a PR to claude-plugins-community bumping it.
# (Discovered 2026-06-11: the pin still pointed at v0.2.9 from April —
# every release since had been invisible to plugin installers.) The
# postflight check below fails loudly until the marketplace PR lands.
#
# Why this exists:
# The v0.2.7 release took ~5 retries because of drift between manual steps:
Expand Down Expand Up @@ -422,6 +433,24 @@ else
err " Check the workflow run logs for sync-plugin-repo job"
fi

# 4. Community marketplace SHA pin — the part of the chain we do NOT own.
# `claude plugin install axme-code@claude-community` installs the commit
# pinned in anthropics/claude-plugins-community, NOT our plugin repo HEAD.
# Without a marketplace PR every release is invisible to new plugin users.
echo " checking anthropics/claude-plugins-community SHA pin..."
plugin_head="$(gh api "repos/${PLUGIN_REPO}/commits/main" --jq '.sha' 2>/dev/null || echo "FETCH_FAILED")"
pinned_sha="$(curl -fsSL "https://raw.githubusercontent.com/anthropics/claude-plugins-community/main/.claude-plugin/marketplace.json" 2>/dev/null \
| jq -r '.plugins[] | select(.name == "axme-code") | .source.sha' 2>/dev/null || echo "FETCH_FAILED")"
if [ "$pinned_sha" = "$plugin_head" ] && [ "$pinned_sha" != "FETCH_FAILED" ]; then
ok "marketplace pin is current ($pinned_sha)"
else
err "marketplace pins $pinned_sha but $PLUGIN_REPO main is $plugin_head"
err " New plugin installs will keep getting the OLD version until this lands:"
err " 1. Fork anthropics/claude-plugins-community"
err " 2. In .claude-plugin/marketplace.json set axme-code .source.sha = $plugin_head"
err " 3. Open a PR (their CI + maintainers review it)"
fi

# --- Done ---

step "Release ${new_tag} complete"
Expand Down
2 changes: 1 addition & 1 deletion templates/plugin-README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
Persistent memory, architectural decisions, and safety guardrails for Claude Code. Your agent starts every session with full project context — stack, decisions, patterns, safety rules, and a handoff from the previous session.

[![Alpha](https://img.shields.io/badge/status-alpha-orange)]()
[![Version](https://img.shields.io/badge/version-0.5.0-blue)]()
[![Version](https://img.shields.io/badge/version-0.6.1-blue)]()
[![License: MIT](https://img.shields.io/badge/license-MIT-blue)](LICENSE)

**[Main Repository](https://github.com/AxmeAI/axme-code)** · **[Website](https://code.axme.ai)** · **[Issues](https://github.com/AxmeAI/axme-code/issues)**
Expand Down
Loading