Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
8ffcad9
Merge pull request #494 from aimasteracc/release/v0.1.19
aimasteracc Jun 3, 2026
dab8712
docs: align doc claims with code (tool count + RFC-0100/-0102 accepta…
aimasteracc Jun 3, 2026
83b56f1
feat(budget): RFC-0102 nested budget{} response object + BudgetMode t…
aimasteracc Jun 3, 2026
21eef1a
feat(budget): RFC-0102 per-call budget override knob on mycelium_cont…
aimasteracc Jun 3, 2026
4135c21
fix(budget): RFC-0102 cap callee_paths/caller_paths/dead_symbols/isol…
aimasteracc Jun 3, 2026
5538d33
docs(rfc): RFC-0109 graph-list output-shape parity + budget roll-out,…
aimasteracc Jun 3, 2026
468893c
feat(queries): RFC-0109 get_callees shared builder + object shape + b…
aimasteracc Jun 3, 2026
e43088c
feat(queries): RFC-0109 get_callers shared builder + object shape + b…
aimasteracc Jun 3, 2026
9d1de48
feat(queries): RFC-0109 get_dead_symbols shared builder + object shap…
aimasteracc Jun 3, 2026
2cc7654
docs(adr): ADR-0010 — reject live LSP, prefer static SCIP/LSIF ingestion
aimasteracc Jun 3, 2026
9c0089b
feat(queries): RFC-0109 get_isolated_symbols shared builder + object …
aimasteracc Jun 3, 2026
8e1ca4e
feat(queries): RFC-0109 get_reachable shared builder + per-call budge…
aimasteracc Jun 3, 2026
164d382
feat(queries): RFC-0109 get_reachable_to reuses reachable_payload + b…
aimasteracc Jun 3, 2026
55b628e
fix(ci): bump sla_ancestors_100k macOS limit 30ms → 100ms (#508)
aimasteracc Jun 4, 2026
26f922c
feat(queries): RFC-0109 get_all_symbols object shape + budget knob (7…
aimasteracc Jun 4, 2026
fc2bd94
chore(pm): dispatch v28 — develop CI fix PR #508; ADR-0010 merged; v0…
aimasteracc Jun 4, 2026
3ca68d9
chore(pm): dispatch v29 — PRs #508+#513 merged; RFC-0109 7/7 complete
aimasteracc Jun 4, 2026
bb2f672
feat(npm): RFC-0110 npm/bun CLI distribution scaffolding — Increment …
aimasteracc Jun 4, 2026
ff23ee3
ci(release): RFC-0110 build CLI binaries matrix + attach to GitHub Re…
aimasteracc Jun 4, 2026
5218170
ci(release): RFC-0110 publish-npm rewire + npm smoke test — Implement…
aimasteracc Jun 4, 2026
0a28be9
chore(release): bump version 0.1.19 → 0.2.0; seal CHANGELOG
aimasteracc Jun 4, 2026
29b01dc
ci(release): make npm-token preflight a graceful warning, not a hard …
aimasteracc Jun 4, 2026
63c0c49
ci(release): build darwin-x64 on macos-14 (cross-compile) not macos-13
aimasteracc Jun 4, 2026
66f91cb
ci(release): graceful npm publish for E404 scope-not-found
claude Jun 4, 2026
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
22 changes: 22 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,28 @@ jobs:
- uses: Swatinem/rust-cache@v2
- run: cargo build --release --workspace --all-features

# RFC-0110: validate the npm packaging path end-to-end on every PR using
# the just-built linux-x64 binary — assemble the packages, install them
# (--install-links copies like a registry install), and run the launcher.
# Catches packaging/launcher regressions without a real publish.
- uses: actions/setup-node@v6
with:
node-version: '20'
- name: npm launcher unit tests
run: node --test
working-directory: npm/mycelium
- name: npm packaging smoke test (assemble → install → run)
run: |
set -euo pipefail
mkdir -p dist-bin/linux-x64
cp target/release/mycelium dist-bin/linux-x64/mycelium
node npm/scripts/build-npm.mjs --version 0.0.0-ci --bin-dir dist-bin --out dist-npm
mkdir -p smoke && cd smoke && npm init -y >/dev/null
npm install --install-links ../dist-npm/mycelium-linux-x64-gnu ../dist-npm/mycelium >/dev/null
OUT="$(node_modules/.bin/mycelium --version)"
echo "launcher output: $OUT"
echo "$OUT" | grep -qi mycelium

doc-build:
name: docs (rustdoc + mdbook)
needs: [unit]
Expand Down
176 changes: 164 additions & 12 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,35 @@ jobs:
needs: validate
uses: ./.github/workflows/ci.yml

check-npm-token:
# Preflight (RFC-0110): warn when NPM_TOKEN is absent so the operator sees
# a clear diagnostic before the publish jobs run. Graceful exit (no hard
# failure) so a missing token produces a SKIPPED npm publish rather than a
# failing release — crates.io and PyPI can still complete independently.
# Charter §5.12: every check must be SUCCESS or SKIPPED before merging
# release/* to main, so this job must never exit non-zero.
name: preflight (npm token present)
needs: validate
runs-on: ubuntu-latest
environment: npm
steps:
- name: Verify NPM_TOKEN is configured
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
if [ -z "${NPM_TOKEN:-}" ]; then
echo "::warning::NPM_TOKEN is not set in the 'npm' environment — npm publish will be skipped. Configure it in repo Settings → Environments → npm."
else
echo "NPM_TOKEN present."
fi

publish-crates:
name: publish to crates.io
needs: [validate, quality-recheck]
# Gate the first irreversible publish on the CLI binaries building
# successfully (RFC-0110 / Codex #519 P1): if any platform build fails we
# must NOT publish to a registry, or the release is partial (crates live but
# binaries missing). npm/pypi are gated on publish-crates.
needs: [validate, quality-recheck, build-cli-binaries]
runs-on: ubuntu-latest
timeout-minutes: 60
environment: crates-io
Expand Down Expand Up @@ -145,28 +171,74 @@ jobs:

publish-npm:
name: publish to npm
needs: [validate, quality-recheck, publish-crates]
# RFC-0110: assemble the per-platform + launcher packages from the prebuilt
# binaries and publish them. needs build-cli-binaries for the artifacts.
needs: [validate, quality-recheck, publish-crates, build-cli-binaries]
runs-on: ubuntu-latest
timeout-minutes: 30
environment: npm
permissions:
id-token: write # for provenance
env:
VERSION: ${{ needs.validate.outputs.version }}
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- run: |
if [ -d "bindings/node" ]; then
cd bindings/node
npm ci
npm publish --access public --provenance
else
echo "no bindings/node yet — skipping"
fi
- name: Download CLI binaries
uses: actions/download-artifact@v7
with:
pattern: cli-*
path: dl
- name: Reshape artifacts into a platform-keyed bin dir
run: |
mkdir -p dist-bin
for d in dl/cli-*; do
key="${d#dl/cli-}"
mkdir -p "dist-bin/$key"
cp "$d"/* "dist-bin/$key/"
done
ls -R dist-bin
- name: Assemble npm packages
run: node npm/scripts/build-npm.mjs --version "$VERSION" --bin-dir dist-bin --out dist-npm
- name: Publish packages (idempotent — platform packages first)
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
if [ -z "${NODE_AUTH_TOKEN:-}" ]; then
echo "::warning::NPM_TOKEN is not set — skipping npm publish. Configure it in repo Settings → Environments → npm."
exit 0
fi
publish_one() {
dir="$1"
name=$(node -p "require('./$dir/package.json').name")
ver=$(node -p "require('./$dir/package.json').version")
if npm view "$name@$ver" version >/dev/null 2>&1; then
echo "$name@$ver already on npm; skipping"
return 0
fi
if ! ( cd "$dir" && npm publish --access public --provenance ) 2>/tmp/npm_pub_err.log; then
npm_err=$(cat /tmp/npm_pub_err.log)
# Graceful degradation: scope not yet registered on npmjs.com
# (E404 "Scope not found"). Token is present and valid; the @aimasteracc
# scope simply needs to be created once via the npmjs.com UI.
# Allow ceremony to proceed; npm distribution re-enabled next release.
if echo "$npm_err" | grep -qE "E404|Scope not found"; then
echo "::warning::npm publish skipped for $name — @aimasteracc scope not yet registered on npmjs.com. See Issue #525."
return 0
fi
echo "$npm_err" >&2
return 1
fi
}
# Platform packages must exist before the main package (whose
# optionalDependencies reference them).
for dir in dist-npm/mycelium-*; do
[ -d "$dir" ] && publish_one "$dir"
done
publish_one "dist-npm/mycelium"

publish-pypi:
name: publish to PyPI
Expand All @@ -190,6 +262,61 @@ jobs:
echo "no bindings/python yet — skipping"
fi

build-cli-binaries:
# RFC-0110: cross-compile the `mycelium` CLI for each distributed platform,
# upload each as a workflow artifact (consumed by publish-npm in a follow-up
# and attached to the GitHub Release below). Native builds for 4 targets;
# `cross` handles the linux-arm64 C toolchain (tree-sitter grammars are C).
name: build CLI binary (${{ matrix.key }})
needs: [validate, quality-recheck]
runs-on: ${{ matrix.os }}
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
# Both macOS targets build on macos-14 (arm64, plentiful runners): arm64
# natively, x86_64 by cross-compiling with the universal Apple toolchain
# (`cargo build --target x86_64-apple-darwin` — verified locally to
# produce an x86_64 Mach-O incl. tree-sitter C). Avoids the deprecated /
# scarce macos-13 (Intel) runner queue that stalled the release ~20min.
include:
- { key: darwin-arm64, os: macos-14, target: aarch64-apple-darwin, exe: mycelium, cross: false }
- { key: darwin-x64, os: macos-14, target: x86_64-apple-darwin, exe: mycelium, cross: false }
- { key: linux-x64, os: ubuntu-latest, target: x86_64-unknown-linux-gnu, exe: mycelium, cross: false }
- { key: linux-arm64, os: ubuntu-latest, target: aarch64-unknown-linux-gnu, exe: mycelium, cross: true }
- { key: win32-x64, os: windows-latest, target: x86_64-pc-windows-msvc, exe: mycelium.exe, cross: false }
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- uses: Swatinem/rust-cache@v2
with:
key: release-${{ matrix.target }}
- name: Install cross (linux-arm64)
if: ${{ matrix.cross }}
uses: taiki-e/install-action@v2
with:
tool: cross
- name: Build release binary
shell: bash
run: |
if [ "${{ matrix.cross }}" = "true" ]; then
cross build --release -p mycelium-rcig-cli --target ${{ matrix.target }}
else
cargo build --release -p mycelium-rcig-cli --target ${{ matrix.target }}
fi
- name: Stage binary under its platform key
shell: bash
run: |
mkdir -p "dist-bin/${{ matrix.key }}"
cp "target/${{ matrix.target }}/release/${{ matrix.exe }}" "dist-bin/${{ matrix.key }}/${{ matrix.exe }}"
- uses: actions/upload-artifact@v7
with:
name: cli-${{ matrix.key }}
path: dist-bin/${{ matrix.key }}/${{ matrix.exe }}
if-no-files-found: error

finalize:
name: merge to main, tag, GitHub Release
# Charter §5.12: touching main requires founder authorization.
Expand All @@ -198,7 +325,7 @@ jobs:
# (scripts/release-ceremony.sh) or a manual workflow_dispatch serves as
# the explicit human authorization step.
if: github.event_name == 'workflow_dispatch'
needs: [validate, publish-crates, publish-npm, publish-pypi]
needs: [validate, publish-crates, publish-npm, publish-pypi, build-cli-binaries]
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
Expand Down Expand Up @@ -263,13 +390,38 @@ jobs:
git tag -a "v$VERSION" -m "Release v$VERSION"
git push origin "v$VERSION"

# Step D — Create the GitHub Release on the tag reachable from main.
# Step D — Download the per-platform CLI binaries and rename them with a
# platform suffix (the raw artifacts are all named `mycelium`/`.exe`, which
# would collide as release assets). RFC-0110.
- name: Download CLI binaries
uses: actions/download-artifact@v7
with:
pattern: cli-*
path: dist-release
- name: Collect release assets
shell: bash
run: |
mkdir -p release-assets
for d in dist-release/cli-*; do
key="${d#dist-release/cli-}"
if [ -f "$d/mycelium.exe" ]; then
cp "$d/mycelium.exe" "release-assets/mycelium-$key.exe"
elif [ -f "$d/mycelium" ]; then
cp "$d/mycelium" "release-assets/mycelium-$key"
fi
done
ls -la release-assets

# Step E — Create the GitHub Release on the tag reachable from main,
# attaching the per-platform binaries (a download path for users who do
# not use npm/bun/cargo).
- name: Create GitHub Release
uses: softprops/action-gh-release@v3
with:
tag_name: v${{ env.VERSION }}
generate_release_notes: true
target_commitish: main
files: release-assets/*
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Expand Down
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
**/*.rs.bk
Cargo.lock.bak

# npm distribution build artifacts (RFC-0110) — assembled in CI, never committed
/dist-bin/
/dist-npm/
node_modules/

# IDE
/.idea/
/.vscode/*
Expand Down
1 change: 1 addition & 0 deletions .hive/memory/anti-patterns.jsonl
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,4 @@
{"ts":"2026-06-03T05:30:00Z","agent":"orchestrator","domain":"release-ci","pattern":"Diagnosing crate publish failures without checking the API URL encoding first","why-bad":"When crates.io returns 404, the error looks like a timeout or propagation delay. Three successive PM runs (v13: timeout, v15: wait extension, v16: max_version API field) all addressed symptoms (response interpretation) rather than the root cause (URL encoding). `tr '-' '_'` in crate_published() produced `/crates/mycelium_rcig_pack` instead of `/crates/mycelium-rcig-pack`. crates.io REST API expects hyphens — underscore names return 404, so crate_published() always returned false even for already-published crates, causing wait_for_crate to loop until timeout on every release.","instead":"When a crates.io API call always returns 404 or empty, first verify the URL structure by running `curl -s https://crates.io/api/v1/crates/<name>` with the exact hyphenated crate name and ensure the script does not mangle the name. Check for tr/sed/awk name transforms before assuming propagation delay or API field issues."}
{"ts":"2026-06-03T08:00:00Z","agent":"code-reviewer","domain":"async","pattern":"Calling tokio::sync::RwLock::blocking_read() or blocking_write() from inside an async Tokio task","why-bad":"blocking_read() parks the OS thread, which starves the Tokio executor: under any write-lock contention the entire runtime can deadlock; even without contention it reduces throughput. The on_batch FnMut closure inside WatchEngine::drive() is called from an async task — this is the exact failure mode.","instead":"Use try_read() for snapshot-and-continue semantics (skip the batch if briefly contended), or restructure to async read().await before entering the sync callback."}
{"ts":"2026-06-03T09:11:30Z","agent":"orchestrator","domain":"release-governance","pattern":"release.yml auto-closes the release→main PR on every release without merging (v0.1.6–v0.1.18 all affected)","why-bad":"Creates orphan crates.io/npm/PyPI published versions with no corresponding git tag or main branch commit. Ceremony is left in a broken state requiring manual founder repair every single release. RELEASE_BOT_TOKEN was configured 2026-06-01 but merge step still fails silently and closes the PR.","instead":"Either (1) switch release.yml merge step from gh API to `git push origin release/vX.Y.Z:main` (direct branch push — requires branch protection bypass token), or (2) remove the auto-merge step entirely and let the ceremony script do the merge + tag + release, or (3) use gh pr merge --admin in the workflow with a token that has admin rights. Until fixed, the ceremony script is the only reliable repair path."}
{"ts":"2026-06-03T19:56:48Z","domain":"git-workflow","pattern":"Committing directly onto local develop after a post-merge 'git checkout develop && pull' sync, because the next increment's branch was never created","why-bad":"Violates the Charter hard rule 'never commit to develop; all work via PR'. The sync step (checkout develop) silently leaves HEAD on develop, so the first commit of the next increment lands on develop. Caught here before push (origin/develop untouched), but a push would have bypassed PR + CI + Codex.","instead":"After merging a PR and syncing develop, IMMEDIATELY 'git checkout -b feature/<next>' before any edit. Or check 'git branch --show-current' is not develop/main before the first commit of an increment."}
Loading
Loading