diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index da38833..c8d8250 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -50,7 +50,7 @@ jobs: shell: bash run: | make clean - make -j2 CFLAGS_EXTRA='-DCBM_VERSION="${{ steps.version.outputs.value }}"' + make -j2 CBM_VERSION="${{ steps.version.outputs.value }}" chmod +x install.sh scripts/package-release.sh copilot-skill/scripts/install.sh scripts/package-release.sh "${{ steps.version.outputs.value }}" build/c/copilot-memory-mcp @@ -59,7 +59,7 @@ jobs: shell: msys2 {0} run: | make clean - make -j2 CC=gcc CXX=g++ CFLAGS_EXTRA='-DCBM_VERSION=\"${{ steps.version.outputs.value }}\"' + make -j2 CC=gcc CXX=g++ CBM_VERSION="${{ steps.version.outputs.value }}" if [ -f build/c/copilot-memory-mcp.exe ]; then : else diff --git a/Jenkinsfile b/Jenkinsfile index 6678374..d33bf45 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -44,7 +44,7 @@ pipeline { sh 'make clean' sh ''' set -eu - make -j2 CFLAGS_EXTRA='-DCBM_VERSION=\"'"$EFFECTIVE_RELEASE_VERSION"'\"' + make -j2 CBM_VERSION="$EFFECTIVE_RELEASE_VERSION" ''' } } diff --git a/Makefile b/Makefile index a2cf593..403b3dc 100644 --- a/Makefile +++ b/Makefile @@ -15,6 +15,8 @@ TS_SRC = $(CBM_DIR)/vendored/ts_runtime/src # ── Common flags ───────────────────────────────────────────────── +CBM_VERSION ?= dev + CFLAGS_COMMON = -std=c11 -D_DEFAULT_SOURCE -D_GNU_SOURCE -Wall -Wextra -Werror \ -Wno-unused-parameter -Wno-sign-compare \ -Wno-unused-result \ @@ -22,12 +24,16 @@ CFLAGS_COMMON = -std=c11 -D_DEFAULT_SOURCE -D_GNU_SOURCE -Wall -Wextra -Werror \ -Isrc -Ivendored -Ivendored/sqlite3 -Ivendored/mimalloc/include \ -I$(CBM_DIR) -I$(TS_INCLUDE) -I$(TS_SRC) -I$(TS_SRC)/unicode -ifneq (,$(findstring gcc,$(notdir $(CC)))) +# GCC-family compilers complain on a few legitimate fixed-size formatting paths +# that the release workflow keeps as warnings only; Clang does not accept those +# suppressions, so probe the compiler itself instead of relying on the CC name. +CC_IS_CLANG := $(shell printf '' | $(CC) -dM -E -x c - 2>/dev/null | grep -q '__clang__' && echo yes || echo no) +ifeq ($(CC_IS_CLANG),no) CFLAGS_COMMON += -Wno-format-truncation CFLAGS_COMMON += -Wno-stringop-truncation endif -CFLAGS_PROD = $(CFLAGS_COMMON) -O2 $(CFLAGS_EXTRA) +CFLAGS_PROD = $(CFLAGS_COMMON) -O2 -DCBM_VERSION=\"$(CBM_VERSION)\" $(CFLAGS_EXTRA) # ── Minimal source files ───────────────────────────────────────── @@ -170,7 +176,7 @@ GRAMMAR_SRCS = \ # ── Vendored library compilation flags (relaxed warnings) ──────── SQLITE3_CFLAGS = -std=c11 -O2 -w -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=1 -DSQLITE_ENABLE_FTS5 -GRAMMAR_CFLAGS = -std=c11 -D_DEFAULT_SOURCE -O2 -w -Wno-unused-value -I$(CBM_DIR) -I$(TS_INCLUDE) +GRAMMAR_CFLAGS = -std=c11 -D_DEFAULT_SOURCE -O2 -w -Wno-unused-value -I$(CBM_DIR) -I$(TS_INCLUDE) -I$(TS_SRC) -I$(TS_SRC)/unicode # ── Linker flags ───────────────────────────────────────────────── @@ -231,13 +237,21 @@ $(BUILD_DIR)/lz4hc.o: internal/cbm/vendored/lz4/lz4hc.c | $(BUILD_DIR) $(BUILD_DIR)/zstd.o: internal/cbm/vendored/zstd/zstd.c | $(BUILD_DIR) $(CC) -std=c11 -O2 -w -I$(CBM_DIR)/vendored/zstd -c -o $@ $< +# Compile vendored TRE regex library (used on Windows for compat_regex) +$(BUILD_DIR)/tre.o: vendored/tre/tre_all.c | $(BUILD_DIR) + $(CC) -std=c11 -O2 -w -Ivendored/tre -c -o $@ $< + # Assemble nomic vector blob $(BUILD_DIR)/code_vectors_blob.o: vendored/nomic/code_vectors_blob.S | $(BUILD_DIR) $(CC) -c -o $@ $< -# Compile mimalloc +# Compile mimalloc (no malloc override on Windows - not supported in static builds) $(BUILD_DIR)/mimalloc.o: vendored/mimalloc/src/static.c | $(BUILD_DIR) +ifeq ($(OS),Windows_NT) + $(CC) -std=c11 -O2 -w -Ivendored/mimalloc/include -c -o $@ $< +else $(CC) -std=c11 -O2 -w -Ivendored/mimalloc/include -DMI_MALLOC_OVERRIDE -c -o $@ $< +endif # Compile grammar files separately with relaxed warnings GRAMMAR_OBJS = $(patsubst $(GRAMMAR_DIR)/%.c,$(BUILD_DIR)/grammar_%.o,$(GRAMMAR_SRCS)) @@ -247,11 +261,11 @@ $(BUILD_DIR)/grammar_%.o: $(GRAMMAR_DIR)/%.c | $(BUILD_DIR) $(CC) $(GRAMMAR_CFLAGS) -c -o $@ $< # Compile and link (main sources in one pass, pre-compiled objects for grammars/vendored/cpp) -$(BUILD_DIR)/copilot-memory-mcp: $(ALL_SRCS) $(GRAMMAR_OBJS) $(BUILD_DIR)/yyjson.o $(BUILD_DIR)/sqlite3.o $(BUILD_DIR)/ts_runtime.o $(BUILD_DIR)/preprocessor.o $(BUILD_DIR)/lz4.o $(BUILD_DIR)/lz4hc.o $(BUILD_DIR)/zstd.o $(BUILD_DIR)/code_vectors_blob.o $(BUILD_DIR)/mimalloc.o | $(BUILD_DIR) +$(BUILD_DIR)/copilot-memory-mcp: $(ALL_SRCS) $(GRAMMAR_OBJS) $(BUILD_DIR)/yyjson.o $(BUILD_DIR)/sqlite3.o $(BUILD_DIR)/ts_runtime.o $(BUILD_DIR)/preprocessor.o $(BUILD_DIR)/lz4.o $(BUILD_DIR)/lz4hc.o $(BUILD_DIR)/zstd.o $(BUILD_DIR)/tre.o $(BUILD_DIR)/code_vectors_blob.o $(BUILD_DIR)/mimalloc.o | $(BUILD_DIR) $(CC) $(CFLAGS_PROD) -o $@ \ $(ALL_SRCS) \ $(GRAMMAR_OBJS) \ - $(BUILD_DIR)/yyjson.o $(BUILD_DIR)/sqlite3.o $(BUILD_DIR)/ts_runtime.o $(BUILD_DIR)/preprocessor.o $(BUILD_DIR)/lz4.o $(BUILD_DIR)/lz4hc.o $(BUILD_DIR)/zstd.o $(BUILD_DIR)/code_vectors_blob.o $(BUILD_DIR)/mimalloc.o \ + $(BUILD_DIR)/yyjson.o $(BUILD_DIR)/sqlite3.o $(BUILD_DIR)/ts_runtime.o $(BUILD_DIR)/preprocessor.o $(BUILD_DIR)/lz4.o $(BUILD_DIR)/lz4hc.o $(BUILD_DIR)/zstd.o $(BUILD_DIR)/tre.o $(BUILD_DIR)/code_vectors_blob.o $(BUILD_DIR)/mimalloc.o \ $(LDFLAGS) @echo "Built: $(BUILD_DIR)/copilot-memory-mcp" @@ -274,4 +288,4 @@ info: @echo " $(GRAMMARS)" @echo "Component sources: $(words $(COMPONENT_SRCS))" @echo "Grammar sources: $(words $(GRAMMAR_SRCS))" - @echo "Vendored: yyjson, sqlite3, mimalloc, lz4, zstd, tree-sitter" + @echo "Vendored: yyjson, sqlite3, mimalloc, lz4, zstd, tre, tree-sitter" diff --git a/docs/release-fix-plan.md b/docs/release-fix-plan.md new file mode 100644 index 0000000..60d0cb9 --- /dev/null +++ b/docs/release-fix-plan.md @@ -0,0 +1,89 @@ +# Release Fix Plan + +Source of truth: +- latest failing release workflow run: `26006685989` +- affected surface: `.github/workflows/release.yml` +- current release packagers: `scripts/package-release.sh`, `scripts/package-release.ps1` + +## Failure Summary + +1. Linux/macOS release build +- `CBM_VERSION` is reaching the compiler without being a string literal. +- GCC/Clang then expand it as `v0.x.y` tokens and fail in `src/main.c` and `src/cli/cli.c`. +- The workflow shell quoting is the immediate trigger. + +2. macOS release build +- Clang rejects GCC-only warning suppressions when they are passed unconditionally. +- `-Wno-format-truncation` and `-Wno-stringop-truncation` must not be sent to Clang. + +3. Windows release build +- `ts_runtime.o` cannot find `unicode/umachine.h`. +- The shared include path must cover `internal/cbm/vendored/ts_runtime/src`. + +## Phase 1: Fix version propagation + +Goal: +- make `CBM_VERSION` arrive at the compiler as a quoted string on Linux and macOS. + +Work: +- update `.github/workflows/release.yml` +- keep the build command shell-safe for both Bash and MSYS2 +- confirm the compiler sees `-DCBM_VERSION=\"vX.Y.Z\"` + +Acceptance: +- Linux/macOS job compiles `src/main.c` and `src/cli/cli.c` without `CBM_VERSION` token errors. +- package step still receives the same version value. + +## Phase 2: Fix macOS compiler portability + +Goal: +- stop sending GCC-only warning suppressions to Clang. + +Work: +- keep `-Wno-format-truncation` and `-Wno-stringop-truncation` gated to GCC only in `Makefile` +- verify the posix build path still compiles under Clang + +Acceptance: +- macOS job completes the build stage with Clang. +- local `make CC=clang CXX=clang++` reaches link/package stages. + +## Phase 3: Fix Windows include path + +Goal: +- make the vendored tree-sitter runtime compile on MSYS2. + +Work: +- ensure `Makefile` includes `internal/cbm/vendored/ts_runtime/src` +- keep `internal/cbm/vendored/ts_runtime/src/unicode` in the include list + +Acceptance: +- Windows job compiles `build/c/ts_runtime.o` +- `unicode/umachine.h` resolves without manual environment tweaks + +## Phase 4: Package verification + +Goal: +- make sure the packaging scripts still emit the expected assets after the build fixes. + +Work: +- confirm `scripts/package-release.sh` produces the Linux/macOS tarball and checksums +- confirm `scripts/package-release.ps1` produces the Windows zip and checksums +- confirm the release workflow uploads the right artifacts for each platform + +Acceptance: +- Linux/macOS upload `dist/*.tar.gz` and `dist/checksums-*.txt` +- Windows upload `dist/*.zip` and `dist/checksums-*.txt` +- published GitHub release assets match the package scripts + +## Verification Order + +1. local `make clean && make -j2` +2. local `make clean && make -j2 CC=clang CXX=clang++` +3. workflow dispatch or push to `main` +4. confirm the three GitHub Actions jobs pass + +## Notes + +- Keep Jenkins out of this fix unless the Jenkinsfile itself regresses. +- Do not widen scope beyond release build and packaging portability. +- If the workflow still fails after the above, inspect the exact compiler command line before changing package scripts. diff --git a/src/foundation/compat_fs.c b/src/foundation/compat_fs.c index 12e7cbd..08d9640 100644 --- a/src/foundation/compat_fs.c +++ b/src/foundation/compat_fs.c @@ -20,7 +20,8 @@ #endif #include #include /* _mkdir */ -#include /* _unlink */ +#include /* _unlink, _pipe, _open */ +#include /* _O_BINARY, _O_WRONLY */ #include struct cbm_dir { diff --git a/src/mcp/mcp.c b/src/mcp/mcp.c index 06b28bb..4c1e837 100644 --- a/src/mcp/mcp.c +++ b/src/mcp/mcp.c @@ -3286,7 +3286,7 @@ static char *handle_search_code(cbm_mcp_server_t *srv, const char *args) { * Query the graph for distinct file paths, write them to a temp file, * then use xargs to pass them to grep. Falls back to recursive grep if * no indexed files found (project not fully indexed). */ - char filelist[CBM_SZ_256]; + char filelist[CBM_SZ_512]; snprintf(filelist, sizeof(filelist), "%s.files", tmpfile); bool scoped = false; diff --git a/src/watcher/watcher.c b/src/watcher/watcher.c index 9430ecb..261bb4b 100644 --- a/src/watcher/watcher.c +++ b/src/watcher/watcher.c @@ -75,6 +75,22 @@ static int64_t now_ns(void) { return ((int64_t)ts.tv_sec * NS_PER_SEC) + ts.tv_nsec; } +static void copy_head(char *dst, size_t dst_size, const char *src) { + if (!dst || dst_size == 0) { + return; + } + if (!src) { + dst[0] = '\0'; + return; + } + size_t len = strlen(src); + if (len >= dst_size) { + len = dst_size - SKIP_ONE; + } + memcpy(dst, src, len); + dst[len] = '\0'; +} + /* ── Adaptive interval ──────────────────────────────────────────── */ int cbm_watcher_poll_interval_ms(int file_count) { @@ -340,10 +356,10 @@ static bool check_changes(project_state_t *s) { if (git_head(s->root_path, head, sizeof(head)) == 0) { if (s->last_head[0] != '\0' && strcmp(head, s->last_head) != 0) { /* HEAD moved — commit, checkout, pull */ - strncpy(s->last_head, head, sizeof(s->last_head) - 1); + copy_head(s->last_head, sizeof(s->last_head), head); return true; } - strncpy(s->last_head, head, sizeof(s->last_head) - 1); + copy_head(s->last_head, sizeof(s->last_head), head); } /* Check working tree */ diff --git a/vendored/nomic/code_vectors_blob.S b/vendored/nomic/code_vectors_blob.S index b927181..4b90b45 100644 --- a/vendored/nomic/code_vectors_blob.S +++ b/vendored/nomic/code_vectors_blob.S @@ -42,4 +42,6 @@ PRETRAINED_VECTOR_BLOB_END: .p2align 2 PRETRAINED_VECTOR_BLOB_LEN: .long PRETRAINED_VECTOR_BLOB_END - PRETRAINED_VECTOR_BLOB + + .section .note.GNU-stack,"",@progbits #endif