Skip to content
Closed
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
4 changes: 4 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.git
build
graph-ui/node_modules
**/node_modules
168 changes: 168 additions & 0 deletions .github/workflows/fork-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
# Fork release: build every platform, smoke-test, publish a GitHub release.
#
# release.yml is upstream's pipeline and publishes through accounts a fork does
# not have (VirusTotal, npm, PyPI, MCP Registry). This workflow keeps exactly
# what the installers need: the eight platform archives (+ MCPB bundles) and
# checksums.txt on a NON-prerelease "latest" release, which is what
# install.sh / install.ps1 -> https://github.com/<repo>/releases/latest/download/...
# resolve. GitHub never treats a prerelease as "latest", so every release made
# here is a full release, including versions like v0.12.1-neo4j.1.
#
# Run: Actions -> Fork Release -> Run workflow (on main).
name: Fork Release

on:
workflow_dispatch:
inputs:
version:
description: "Release version, v-prefixed (e.g. v0.12.1-neo4j.1)"
required: true
type: string
release_notes:
description: "Release notes (optional; generated from commits when empty)"
required: false
type: string
virustotal:
description: "VirusTotal-scan the binaries (needs the VIRUS_TOTAL_SCANNER_API_KEY secret)"
required: false
type: boolean
default: false
skip_smoke:
description: "Skip the smoke tests of the built binaries"
required: false
type: boolean
default: false
replace:
description: "Replace an existing release with the same version"
required: false
type: boolean
default: false

permissions:
contents: read

concurrency:
group: fork-release
cancel-in-progress: false

jobs:
preflight:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
# The installers fetch releases/latest/download/<archive>; the tag is the
# version verbatim, so a bare "0.12.1" would publish an unreachable tag.
- name: Enforce v-prefixed semver version input
env:
VERSION: ${{ inputs.version }}
run: |
if [[ "$VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+([-.][0-9A-Za-z.]+)?$ ]]; then
echo "version OK: $VERSION"
else
echo "::error::version must be v-prefixed semver (vX.Y.Z[-suffix]), got '$VERSION'"
exit 1
fi

build:
needs: [preflight]
permissions:
contents: read
id-token: write
attestations: write
uses: ./.github/workflows/_build.yml
with:
version: ${{ inputs.version }}
attest: false
scan_candidates: ${{ inputs.virustotal }}
secrets: inherit

smoke:
needs: [build]
if: ${{ !cancelled() && needs.build.result == 'success' && !inputs.skip_smoke }}
uses: ./.github/workflows/_smoke.yml
with:
broad_platforms: false

publish:
needs: [build, smoke]
# A skipped smoke is accepted only when it was skipped on request.
if: >-
${{ !cancelled()
&& needs.build.result == 'success'
&& (needs.smoke.result == 'success'
|| (inputs.skip_smoke && needs.smoke.result == 'skipped')) }}
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Download the packaged containers
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
pattern: binaries-*
merge-multiple: true
path: dist

- name: List artifacts and require every platform
working-directory: dist
run: |
ls -la
for target in linux-amd64 linux-arm64 linux-amd64-portable linux-arm64-portable \
darwin-amd64 darwin-arm64; do
test -f "codebase-memory-mcp-$target.tar.gz" || { echo "::error::missing $target archive"; exit 1; }
done
for target in windows-amd64 windows-arm64; do
test -f "codebase-memory-mcp-$target.zip" || { echo "::error::missing $target archive"; exit 1; }
done

# install.sh / install.ps1 refuse any archive whose SHA-256 is not listed
# here, so this file is what makes the release installable.
- name: Generate checksums
working-directory: dist
run: |
shopt -s nullglob
sha256sum *.tar.gz *.zip *.mcpb > checksums.txt
cat checksums.txt

- name: Delete existing release
if: ${{ inputs.replace }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERSION: ${{ inputs.version }}
run: gh release delete "$VERSION" --yes --cleanup-tag --repo "$GITHUB_REPOSITORY" || true

# Tag the dispatched commit (the one the binaries were built from), not
# whatever main points at by now.
- name: Publish the release
working-directory: dist
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERSION: ${{ inputs.version }}
NOTES: ${{ inputs.release_notes }}
run: |
shopt -s nullglob
notes_args=(--generate-notes)
if [ -n "$NOTES" ]; then notes_args=(--notes "$NOTES"); fi
gh release create "$VERSION" \
--repo "$GITHUB_REPOSITORY" \
--target "$GITHUB_SHA" \
--title "$VERSION" \
--latest \
"${notes_args[@]}" \
*.tar.gz *.zip *.mcpb checksums.txt
{
echo "### Released $VERSION"
echo
echo '```bash'
echo "curl -fsSL https://raw.githubusercontent.com/$GITHUB_REPOSITORY/main/install.sh | bash"
echo '```'
echo '```powershell'
echo "Invoke-WebRequest -Uri https://raw.githubusercontent.com/$GITHUB_REPOSITORY/main/install.ps1 -OutFile install.ps1"
echo 'Unblock-File .\install.ps1'
echo 'PowerShell -ExecutionPolicy Bypass -File .\install.ps1'
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
13 changes: 13 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ permissions:
jobs:
# ── Security (starts immediately, blocks only verify) ───────────
security:
# Upstream-only: forks release through fork-release.yml (see preflight).
if: ${{ github.repository == 'DeusData/codebase-memory-mcp' }}
uses: ./.github/workflows/_security.yml
# No job in _security.yml reads code scanning or the Actions API any more
# (the CodeQL gate moved to codeql.yml), so the token stays read-only.
Expand All @@ -57,6 +59,7 @@ jobs:
# a called workflow cannot request more than its caller grants, so
# withholding either permission fails the whole run at startup.
codeql:
if: ${{ github.repository == 'DeusData/codebase-memory-mcp' }}
uses: ./.github/workflows/codeql.yml
permissions:
contents: read
Expand All @@ -72,6 +75,15 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
# This pipeline publishes through upstream's VirusTotal, npm, PyPI and
# MCP Registry accounts, which a fork does not have. Stop at once with a
# pointer instead of failing hours later.
- name: Refuse to run outside the upstream repository
if: ${{ !(github.repository == 'DeusData/codebase-memory-mcp') }}
run: |
echo "::error::release.yml is upstream's pipeline. On this fork run the 'Fork Release' workflow (.github/workflows/fork-release.yml) instead."
exit 1

- name: Enforce v-prefixed semver version input
env:
VERSION: ${{ inputs.version }}
Expand Down Expand Up @@ -160,6 +172,7 @@ jobs:
# release-draft's needs: the report is evidence for the release notes, never
# a publication gate.
memwaste:
if: ${{ github.repository == 'DeusData/codebase-memory-mcp' }}
uses: ./.github/workflows/_memwaste.yml
with:
mode: full
Expand Down
12 changes: 8 additions & 4 deletions Makefile.cbm
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ ifeq ($(IS_MINGW),yes)
# two Windows builds of identical source are never byte-identical and every
# release is a brand-new file to a reputation system. Same motivation as the
# mimalloc __DATE__ patch; ELF and Mach-O have no equivalent field to clear.
WIN32_LIBS := -lws2_32 -lpsapi -lshell32 -ladvapi32 -lbcrypt -Wl,--allow-multiple-definition -Wl,--stack,8388608 -Wl,--no-insert-timestamp -static
WIN32_LIBS := -lws2_32 -lwinhttp -lpsapi -lshell32 -ladvapi32 -lbcrypt -Wl,--allow-multiple-definition -Wl,--stack,8388608 -Wl,--no-insert-timestamp -static
endif

# STATIC=1 produces a fully static binary (for Alpine/musl portable builds)
Expand Down Expand Up @@ -454,6 +454,9 @@ STORE_SRCS = src/store/store.c src/store/graph_mem.c src/store/architecture_proj
# Cypher module (new)
CYPHER_SRCS = src/cypher/cypher.c

# Neo4j graph backend (HTTP API client, sync, remote store reads)
NEO4J_SRCS = src/neo4j/neo4j_http.c src/neo4j/neo4j_client.c src/neo4j/neo4j_sync.c src/neo4j/neo4j_store.c

# MCP server module (new)
MCP_SRCS = src/mcp/mcp.c src/mcp/index_supervisor.c src/mcp/compact_out.c src/mcp/architecture_jobs.c \
src/mcp/test_impact.c src/mcp/test_impact_diff.c src/mcp/test_impact_classify.c src/mcp/test_impact_source.c src/mcp/test_impact_seed.c src/mcp/test_impact_engine.c src/mcp/test_impact_engine_snapshot.c src/mcp/test_impact_engine_reach.c src/mcp/test_impact_engine_artifact.c src/mcp/test_impact_cli.c src/mcp/test_impact_artifact.c src/mcp/test_impact_changes.c src/mcp/test_impact_origins.c src/mcp/test_impact_coverage.c src/mcp/test_impact_config.c src/mcp/test_impact_select.c src/mcp/test_impact_policy.c src/mcp/test_impact_git.c src/mcp/test_impact_inventory.c src/mcp/test_impact_inventory_input.c src/mcp/test_impact_tree.c src/mcp/test_impact_tree_audit.c src/mcp/test_impact_tree_read.c src/mcp/test_impact_tree_batch.c src/mcp/test_impact_tree_digest.c src/mcp/test_impact_tree_names.c src/mcp/test_impact_tree_plan.c src/mcp/test_impact_tree_posix.c src/mcp/test_impact_tree_posix_acl.c src/mcp/test_impact_tree_posix_io.c src/mcp/test_impact_tree_util.c src/mcp/test_impact_tree_windows.c src/mcp/test_impact_tree_windows_acl.c src/mcp/test_impact_tree_windows_io.c \
Expand Down Expand Up @@ -689,7 +692,7 @@ TRE_CFLAGS = -std=c11 -g -O1 -w -Ivendored/tre
YYJSON_SRC = vendored/yyjson/yyjson.c

# All production sources
PROD_SRCS = $(MEMWASTE_SRCS) $(FOUNDATION_SRCS) $(STORE_SRCS) $(CYPHER_SRCS) $(MCP_SRCS) $(DAEMON_SRCS) $(DISCOVER_SRCS) $(GRAPH_BUFFER_SRCS) $(PIPELINE_SRCS) $(SIMHASH_SRCS) $(SEMANTIC_SRCS) $(TRACES_SRCS) $(WATCHER_SRCS) $(GIT_SRCS) $(CLI_SRCS) $(UI_SRCS) $(YYJSON_SRC)
PROD_SRCS = $(MEMWASTE_SRCS) $(FOUNDATION_SRCS) $(STORE_SRCS) $(CYPHER_SRCS) $(NEO4J_SRCS) $(MCP_SRCS) $(DAEMON_SRCS) $(DISCOVER_SRCS) $(GRAPH_BUFFER_SRCS) $(PIPELINE_SRCS) $(SIMHASH_SRCS) $(SEMANTIC_SRCS) $(TRACES_SRCS) $(WATCHER_SRCS) $(GIT_SRCS) $(CLI_SRCS) $(UI_SRCS) $(YYJSON_SRC)
EXISTING_C_SRCS = $(EXTRACTION_SRCS) $(LSP_SRCS) $(TS_RUNTIME_SRC) \
$(GRAMMAR_SRCS) $(AC_LZ4_SRCS) $(ZSTD_SRCS) $(SQLITE_WRITER_SRC)

Expand Down Expand Up @@ -754,7 +757,8 @@ TEST_STORE_SRCS = \
tests/test_store_bulk.c \
tests/test_store_pragmas.c \
tests/test_store_checkpoint.c \
tests/test_dump_verify_io.c
tests/test_dump_verify_io.c \
tests/test_neo4j.c

TEST_CYPHER_SRCS = \
tests/test_cypher.c
Expand Down Expand Up @@ -1392,7 +1396,7 @@ SYSROOT = $(shell xcrun --show-sdk-path 2>/dev/null)
SYSROOT_FLAG = $(if $(SYSROOT),-isysroot $(SYSROOT),)

# Our source files (excluding vendored, grammars, tree-sitter runtime)
LINT_SRCS = $(FOUNDATION_SRCS) $(STORE_SRCS) $(CYPHER_SRCS) $(MCP_SRCS) $(DAEMON_SRCS) \
LINT_SRCS = $(FOUNDATION_SRCS) $(STORE_SRCS) $(CYPHER_SRCS) $(NEO4J_SRCS) $(MCP_SRCS) $(DAEMON_SRCS) \
$(DISCOVER_SRCS) $(GRAPH_BUFFER_SRCS) $(PIPELINE_SRCS) $(SIMHASH_SRCS) $(SEMANTIC_SRCS) \
$(TRACES_SRCS) $(WATCHER_SRCS) $(CLI_SRCS) $(EXTRACTION_SRCS) $(AC_LZ4_SRCS) \
$(ZSTD_SRCS) $(SQLITE_WRITER_SRC) $(MAIN_SRC)
Expand Down
Loading
Loading