mirror of
https://github.com/aaronsb/obsidian-mcp-plugin.git
synced 2026-07-22 06:45:14 +00:00
Bundles the three reported bugs plus an unreported under-blocking bug found while writing the tests for #250, and adds the coverage tooling that would have caught all four. #250 — .mcpignore negation was inverted The parser stripped the leading '!' before Minimatch saw it, so .negate was always false and the branch reading it was dead code. '!folder/*' compiled into a positive exclusion: negation did not merely fail, it inverted. Under-blocking (found while testing the above, not reported) Patterns were handed to Minimatch raw, so two gitignore rules were never implemented: a slash-less pattern matches at any depth ('*.secret' must hide 'a/b/creds.secret'), and a directory match covers its contents ('private/' must hide 'private/notes.md'). No consumer of isExcluded() checks ancestors — every caller passes a full file path — so nothing compensated downstream. The plugin's own shipped .mcpignore template promises both behaviours, so a user following it believed private files were hidden while they were being served to the model. Patterns are now translated into the globs that implement gitignore semantics, and negation is interpreted here rather than by Minimatch. #252 — min TLS 1.3 crashed the server secureProtocol mapped 1.3 to 'TLSv1_3_method', which OpenSSL never shipped, so context creation threw "Unknown method: TLSv1_3_method". Switched to minVersion, which also fixes a second latent bug: secureProtocol PINS one version, so "minimum TLS 1.2" was silently refusing TLS 1.3 clients. The setting now behaves as the floor it is labelled. #253 — rename dropped the extension 'newName' was concatenated onto the source directory verbatim, so renaming 'note.md' to 'renamed' produced an extension-less file that drops out of markdown views. The source extension is now carried over when newName omits one, before the overwrite guard so it checks the right path. Coverage + test contract All four bugs shipped through code paths with zero coverage. Adds `make coverage` / `coverage-map` / `coverage-gate`, a ratcheting coverageThreshold (security boundary held to a far higher floor than global, since a hole there leaks vault content), and tests/test-contract.test.ts enforcing that a green run means something: no .only, no .skip, every file asserts, no tautologies. The contract immediately caught an `expect(true).toBe(true)` placeholder in the path-validator suite, now replaced with real assertions. BREAKING (.mcpignore, both intended): - The double-'!' workaround for #250 now correctly parses as a double negation (net exclude) and will stop working. - A bare '*' now excludes at every depth, per gitignore, rather than top-level only. This is what makes the '*' + '!keep/**' whitelist idiom work.
114 lines
4 KiB
Makefile
114 lines
4 KiB
Makefile
.PHONY: help build dev test coverage coverage-map coverage-gate lint lint-fix check clean install \
|
|
release-patch release-minor release-major release publish promote sync-version mcpb scorecard set-description
|
|
|
|
MIN_OBSIDIAN := 1.6.6
|
|
|
|
help: ## Show this help
|
|
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
|
|
awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-15s\033[0m %s\n", $$1, $$2}'
|
|
|
|
# --- Development ---
|
|
|
|
install: ## Install dependencies
|
|
npm install
|
|
|
|
dev: ## Start dev mode (watch + rebuild)
|
|
npm run dev
|
|
|
|
build: ## Build plugin (typecheck + bundle)
|
|
npm run build
|
|
|
|
# --- Quality ---
|
|
|
|
lint: ## Run ESLint
|
|
npm run lint
|
|
|
|
lint-fix: ## Run ESLint with auto-fix
|
|
npm run lint:fix
|
|
|
|
test: ## Run test suite
|
|
npm test
|
|
|
|
coverage: ## Run tests with coverage + print the per-file map (html report in coverage/)
|
|
npm run test:coverage
|
|
@node scripts/coverage-map.mjs
|
|
|
|
coverage-map: ## Print the per-file coverage map from the last run (no re-run)
|
|
@node scripts/coverage-map.mjs
|
|
|
|
coverage-gate: ## Enforce the coverage floors in jest.config.js (exit 1 on backslide)
|
|
npm run test:coverage
|
|
|
|
check: build lint coverage-gate ## Run all quality gates (build + lint + tests + coverage floors)
|
|
|
|
# --- Release ---
|
|
# Full cycle: bump → sync → update versions.json → commit → push → trigger workflow
|
|
|
|
release-patch: ## Release patch (0.0.x) — check, bump, publish
|
|
$(MAKE) check
|
|
npm version patch --no-git-tag-version
|
|
$(MAKE) _update-versions-json
|
|
$(MAKE) _commit-and-publish
|
|
|
|
release-minor: ## Release minor (0.x.0) — check, bump, publish
|
|
$(MAKE) check
|
|
npm version minor --no-git-tag-version
|
|
$(MAKE) _update-versions-json
|
|
$(MAKE) _commit-and-publish
|
|
|
|
release-major: ## Release major (x.0.0) — check, bump, publish
|
|
$(MAKE) check
|
|
npm version major --no-git-tag-version
|
|
$(MAKE) _update-versions-json
|
|
$(MAKE) _commit-and-publish
|
|
|
|
publish: ## Trigger GitHub Actions release for current version
|
|
@VERSION=$$(jq -r .version package.json); \
|
|
echo "Publishing version $$VERSION..."; \
|
|
gh workflow run release.yml --field release_notes="$${RELEASE_NOTES:-}"
|
|
|
|
promote: ## Promote a release from prerelease to stable+Latest (defaults to current package.json version; override with TAG=X.Y.Z)
|
|
@TAG=$${TAG:-$$(jq -r .version package.json)}; \
|
|
echo "Promoting release $$TAG to stable + Latest..."; \
|
|
gh release edit "$$TAG" --prerelease=false --latest; \
|
|
echo "✅ $$TAG is now the Latest release"
|
|
|
|
# Internal targets (not in help)
|
|
|
|
_update-versions-json:
|
|
@VERSION=$$(jq -r .version package.json); \
|
|
jq --arg v "$$VERSION" --arg m "$(MIN_OBSIDIAN)" '. + {($$v): $$m}' versions.json > versions.json.tmp && \
|
|
mv versions.json.tmp versions.json; \
|
|
echo "Updated versions.json with $$VERSION → $(MIN_OBSIDIAN)"
|
|
|
|
_commit-and-publish:
|
|
@VERSION=$$(jq -r .version package.json); \
|
|
git add package.json package-lock.json manifest.json mcpb/manifest.json src/version.ts versions.json; \
|
|
git commit -m "chore: Bump version to $$VERSION"; \
|
|
git push origin HEAD; \
|
|
echo "Triggering release for $$VERSION..."; \
|
|
gh workflow run release.yml --field release_notes="$${RELEASE_NOTES:-}"
|
|
|
|
# --- Utility ---
|
|
|
|
clean: ## Remove build artifacts
|
|
rm -rf main.js main.js.map dist/ obsidian-mcp-*.mcpb obsidian-mcp.mcpb
|
|
|
|
sync-version: ## Sync version + description from package.json to manifest.json, mcpb, version.ts
|
|
node sync-version.mjs
|
|
|
|
mcpb: ## Build MCPB bundle (obsidian-mcp-<version>.mcpb) for Claude Desktop
|
|
node scripts/build-mcpb.mjs
|
|
|
|
scorecard: ## Pull the Obsidian community portal scorecard + freshness delta (free post-release signal)
|
|
@node scripts/scorecard.mjs
|
|
|
|
scorecard-gate: ## Diff the live scorecard vs the committed baseline (exit 1 = regression, 3 = drift)
|
|
@node scripts/scorecard-gate.mjs
|
|
|
|
scorecard-baseline: ## DELIBERATELY re-snapshot scorecard-baseline.json (only after an ACCEPTED change; commit it)
|
|
@node scripts/scorecard-baseline.mjs
|
|
|
|
set-description: ## Set plugin description (SoT: package.json) + sync. Usage: make set-description DESC='...'
|
|
@node scripts/set-description.mjs "$(DESC)"
|
|
@node sync-version.mjs
|