From ab2838aabb9976dcee25ea4b1acd0fc6c6e39ebf Mon Sep 17 00:00:00 2001 From: Rafael Richards Date: Sun, 10 May 2026 21:55:34 -0400 Subject: [PATCH 1/2] phase2-onboarding: adopt Phase 0 contract for tree-sitter-m MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tier-2 onboarding per .github/docs/AI-discoverability-plan.md §3.4 and phase1-plan.md §9. tree-sitter-m now ships the same machine- readable surface as the tier-1 repos. What landed: - AGENTS.md adopted as canonical (renamed from CLAUDE.md, symlinked back). Frontmatter refreshed (github: rafael5 → m-dev-tools; location: ~/projects → ~/m-dev-tools). The five Phase-0 required sections (Setup / Test / Build / Verify / Guardrails) appended; existing project context preserved verbatim. - dist/repo.meta.json — Phase-0 contract. $schema points at the org-level repo.meta.schema.json. exposes three already-committed tree-sitter-generated artefacts: - node_types → src/node-types.json (90 AST node entries) - grammar → src/grammar.json (full tree-sitter grammar) - grammar_metadata → src/grammar-metadata.json (m-standard-pinned) Consumes m-standard (build-time data input). License AGPL-3.0. - Makefile — three new targets: - manifest no-op pointer (artifacts are tree-sitter-generated) - check-manifest → tools/check-manifest.py - check-docs-prose cross-repo prose-only gate - tools/check-manifest.py — stdlib-only validator. Parses the manifest, asserts required fields, asserts each exposes.* path exists. Optional full jsonschema validation when the lib is available + the canonical schema URL is reachable. - .github/workflows/ci.yml — two new steps in the existing `grammar` job: "Phase-0 manifest contract gate" + "docs/ prose-only gate". Sits next to the existing parser-drift gate, same conceptual layer. Verification, all green: - make manifest informational pointer - make check-manifest ✓ (manifest valid + all 3 paths present) - make check-docs-prose ✓ (docs/ has only .md prose) - canonical Track-A validator OK: dist/repo.meta.json Once .github ships build-catalog.py (Phase-1 Track B) and adds tree-sitter-m to its TIER_2 list, this repo's manifest will be picked up by the org catalog automatically. --- .github/workflows/ci.yml | 11 ++ AGENTS.md | 236 +++++++++++++++++++++++++++++++++++++++ CLAUDE.md | 165 +-------------------------- Makefile | 40 ++++++- tools/check-manifest.py | 108 ++++++++++++++++++ 5 files changed, 395 insertions(+), 165 deletions(-) create mode 100644 AGENTS.md mode change 100644 => 120000 CLAUDE.md create mode 100755 tools/check-manifest.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 941c25d..75b55ab 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,6 +35,17 @@ jobs: exit 1 fi + - name: Phase-0 manifest contract gate + # Asserts dist/repo.meta.json parses, carries all required fields, + # and every exposes.* path resolves on disk. Cross-repo tier-2 + # contract per .github/docs/AI-discoverability-plan.md §3.4. + run: make check-manifest + + - name: docs/ prose-only gate + # Cross-repo guardrail: docs/ holds only human-readable prose. + # Non-prose artifacts belong elsewhere. + run: make check-docs-prose + node: name: node (${{ matrix.os }}) runs-on: ${{ matrix.os }} diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..eceffbc --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,236 @@ +--- +# Machine-readable project descriptor — schema v1 (2026-05-05). +name: tree-sitter-m +kind: [parser, grammar, library] +status: active # B5 done; B6 bindings + CI wired; remaining: publish + per-tier coverage gate +languages: [javascript, c, rust, python, go, typescript] + +runtime: + needs: + - "node>=18 (for tree-sitter CLI + bindings build)" + optional: + - "rust toolchain (rust binding)" + - "python>=3.10 (python binding)" + - "go (go binding)" + excludes: [] + +distribution: + pypi: null # python binding consumed via wheels attached to GitHub releases + npm: null # node binding present but not yet on npm + cargo: null + github: m-dev-tools/tree-sitter-m + +location: ~/m-dev-tools/tree-sitter-m + +exposes: + grammar: "grammar.js (committed; generated from m-standard's grammar-surface.json)" + parser: "src/parser.c (generated, committed)" + bindings: + - "bindings/node/" + - "bindings/rust/" + - "bindings/python/" + - "bindings/go/" + wasm: "tree-sitter-m.wasm build artefact (consumed by tree-sitter-m-vscode)" + formats_produced: + - "AST + grammar-metadata.json (for downstream tools)" + +consumes: + formats: [".m", ".mac", ".int"] + services: [] + upstream_data: + - "m-standard/integrated/grammar-surface.json (commands, ISVs, functions, etc.)" + +companions: + - project: m-standard + relation: "input — grammar-surface.json drives the build-grammar.js code generator; rebuild grammar when m-standard updates" + - project: m-cli + relation: "consumer — m-cli's lint/fmt rules walk the tree-sitter AST" + - project: tree-sitter-m-vscode + relation: "consumer — loads the WASM build for VS Code syntax highlighting" + - project: vista-meta + relation: "primary validation corpus — 39,330 routines at ~/vista-meta/vista/vista-m-host/Packages (99.06% clean as of B5)" + - project: m-modern-corpus + relation: "secondary validation corpus — confirms grammar handles modern non-VistA idioms" + +incompatibilities: + - "ObjectScript out of scope — M only." + - "Generated `src/parser.c` is committed so consumers don't need tree-sitter-cli or m-standard at install time." + +docs: + primary: README.md + spec: docs/spec.md +--- + +# Claude project context — tree-sitter-m + +## What this is +A tree-sitter grammar for M (MUMPS). Specification phase only — no +code yet. Full design in `docs/spec.md`. + +## Where things will live +- `tools/build-grammar.js` — code-generator that consumes + `m-standard/integrated/grammar-surface.json` and emits the + data-driven half of `grammar.js`. +- `grammar.js` — generated tree-sitter grammar definition. +- `src/parser.c` — generated by `tree-sitter generate` from + grammar.js. Both are committed so consumers don't need + tree-sitter-cli or m-standard to install. +- `bindings/` — Node, Rust, Python, Go bindings. +- `test/corpus/` — tree-sitter corpus tests + real M routines from + m-standard's sources. + +## Pipeline +``` +m-standard/integrated/grammar-surface.json + │ + ▼ +tools/build-grammar.js (run on m-standard updates) + │ + ▼ +grammar.js (committed) + │ + ▼ +tree-sitter generate (run on grammar.js changes) + │ + ▼ +src/parser.c + src/grammar-metadata.json (committed) + │ + ▼ +tree-sitter test (corpus tests, per-tier coverage gate) + │ + ▼ +bindings/{node,rust,python,go} (compiled per platform) +``` + +## Hard rules +- **Read `docs/tree-sitter-notes.md` before adding grammar rules + that involve overlapping regex tokens, keyword vs identifier + disambiguation, or context-sensitive recognition.** Two non- + obvious tree-sitter constraints have already cost us debugging + time: token precedence is dominant (not a tiebreaker for length), + and the regex engine has no look-around. The notes document + records the workaround patterns we've adopted (GLR parser + alternatives, external-scanner byte-level lookahead, disjoint-by- + required-structure regexes) and when to pick which. +- **The parser recognises the union of all sources.** Subsetting + belongs in the linter layer (`tree-sitter-m-lint`), not the + grammar. See `docs/spec.md` AD-01. +- **Hand-code language structure; data-drive the keyword tables.** + Line shape, comments, strings, postconditionals, indirection, + dot-blocks are invariant across sources and live in `grammar.js`. + Commands / functions / ISVs / operators / pattern codes come + from `m-standard`. See AD-02. +- **Stamp `standard_status` on every keyword node.** Per-token + tier metadata is what lets downstream linters work without + re-parsing. See AD-03. +- **Pin the m-standard schema_version.** When m-standard ships a + breaking schema change, tree-sitter-m adopts deliberately and bumps + major version. CI fails if the consumed file's + `schema_version` doesn't match the pin. See AD-04. + +## Source for grammar data +**Always** `~/projects/m-standard/integrated/grammar-surface.json`, +read at build time only. Never the per-source TSVs, never the +pragmatic / SAC / operational standards. Those serve different +consumers (the linter, not the parser). + +## Conventions +- AGPL-3.0 (matches m-standard). +- Generated artifacts (`grammar.js`, `src/parser.c`) ARE committed + so installs don't need build tools. +- Tree-sitter version pinned in `package.json`; no surprise upgrades. +- Bindings use tree-sitter's standard scaffold; no bespoke binding + code. +- Tests use tree-sitter's standard corpus format + (`test/corpus/*.txt` with `===` separators). + +## Toolchain +- Node.js ≥ 20 (tree-sitter-cli) +- C compiler (gcc/clang/MSVC) for the generated parser +- No m-standard runtime dependency — tree-sitter-m ships pre-generated + artifacts. m-standard is a build-time data input only. + +## What this is NOT +- A linter. That's `tree-sitter-m-lint` (sibling project). +- A formatter. That's a separate downstream consumer. +- A compiler / interpreter. M execution belongs to YottaDB / IRIS. +- A semantic analyzer. The parser produces a parse tree; type + inference, control flow, cross-routine resolution all live above. +- A parser for **InterSystems ObjectScript** (`##class`, `&sql`, + `obj.method()`, `obj.property=val`, `##super`, etc.). ObjectScript + is a separate scripting language layered on top of M's runtime; + if you want to parse it, build a sibling grammar + (`tree-sitter-objectscript`). tree-sitter-m covers M and M dialects + (AnnoStd, YottaDB, IRIS's M layer) only. + +## Setup + +```bash +npm ci # install tree-sitter-cli + bindings deps +``` + +Node ≥ 18, plus a C compiler for the generated parser. For the Python +binding specifically, install from a tagged release's prebuilt wheel +(no C toolchain needed) — see `RELEASE.md` for URL templates. + +## Test + +```bash +make test # tree-sitter corpus tests (test/corpus/*.txt) +make parse-rate-check # VistA-corpus parse-rate gate (≤ 1.0% errors by default) +npm test # full Node side: corpus + lib + coverage gate +``` + +`make parse-rate-check` requires the VistA corpus at +`$VISTA_DIR/Packages/` (defaults to `~/vista-meta/vista/vista-m-host/Packages/`). +Skip locally if you don't have that checkout — CI runs it. + +## Build / generate + +The parser artefacts under `src/` are committed so consumers can install +without tree-sitter-cli or m-standard. Regenerate when grammar or +m-standard changes: + +```bash +tree-sitter generate # → src/parser.c, src/grammar.json, src/node-types.json +node tools/build-grammar.js # → grammar.js, keywords.generated.js, src/grammar-metadata.json + # (requires sibling m-standard checkout) +make all # → libtree-sitter-m.{a,so} + pkg-config (C consumers) +``` + +The `make manifest` target in this Makefile is a no-op pointer — the +exposed `dist/repo.meta.json` payloads (`src/node-types.json`, +`src/grammar.json`, `src/grammar-metadata.json`) are tree-sitter outputs +already gated by `make test`. + +## Verify + +The `verification_commands` declared in `dist/repo.meta.json`: + +```bash +make test # corpus tests pass +make check-manifest # repo.meta.json validates + every exposes.* path exists +``` + +Cross-repo guardrail: + +```bash +make check-docs-prose # docs/ holds only prose +``` + +## Guardrails + +- **Do not hand-edit `src/parser.c`, `src/grammar.json`, + `src/node-types.json`, or `keywords.generated.js`.** They are + `tree-sitter generate` and `tools/build-grammar.js` outputs. +- **Do not hand-edit `src/grammar-metadata.json`.** It is the + build-grammar tool's emission, pinned by `schema_version` against + m-standard's `grammar-surface.json`. +- **Generated artefacts are committed.** This is deliberate — consumers + install without needing tree-sitter-cli + Node + an m-standard + sibling checkout. Don't `.gitignore` them. +- **ObjectScript is out of scope.** Don't add `##class` / `&sql` / + `obj.method()` to grammar.js. That belongs in a sibling + `tree-sitter-objectscript` grammar. +- **m-standard is a build-time data input only.** No runtime dep, + no install-time dep, no PyPI/npm dep on it. diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 3cb6b44..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,164 +0,0 @@ ---- -# Machine-readable project descriptor — schema v1 (2026-05-05). -name: tree-sitter-m -kind: [parser, grammar, library] -status: active # B5 done; B6 bindings + CI wired; remaining: publish + per-tier coverage gate -languages: [javascript, c, rust, python, go, typescript] - -runtime: - needs: - - "node>=18 (for tree-sitter CLI + bindings build)" - optional: - - "rust toolchain (rust binding)" - - "python>=3.10 (python binding)" - - "go (go binding)" - excludes: [] - -distribution: - pypi: null # python binding consumed via local checkout (no PyPI publication planned) - npm: null # node binding present but not yet on npm - cargo: null - github: rafael5/tree-sitter-m - -location: ~/projects/tree-sitter-m - -exposes: - grammar: "grammar.js (committed; generated from m-standard's grammar-surface.json)" - parser: "src/parser.c (generated, committed)" - bindings: - - "bindings/node/" - - "bindings/rust/" - - "bindings/python/" - - "bindings/go/" - wasm: "tree-sitter-m.wasm build artefact (consumed by tree-sitter-m-vscode)" - formats_produced: - - "AST + grammar-metadata.json (for downstream tools)" - -consumes: - formats: [".m", ".mac", ".int"] - services: [] - upstream_data: - - "m-standard/integrated/grammar-surface.json (commands, ISVs, functions, etc.)" - -companions: - - project: m-standard - relation: "input — grammar-surface.json drives the build-grammar.js code generator; rebuild grammar when m-standard updates" - - project: m-cli - relation: "consumer — m-cli's lint/fmt rules walk the tree-sitter AST" - - project: tree-sitter-m-vscode - relation: "consumer — loads the WASM build for VS Code syntax highlighting" - - project: vista-meta - relation: "primary validation corpus — 39,330 routines at ~/vista-meta/vista/vista-m-host/Packages (99.06% clean as of B5)" - - project: m-modern-corpus - relation: "secondary validation corpus — confirms grammar handles modern non-VistA idioms" - -incompatibilities: - - "ObjectScript out of scope — M only." - - "Generated `src/parser.c` is committed so consumers don't need tree-sitter-cli or m-standard at install time." - -docs: - primary: README.md - spec: docs/spec.md ---- - -# Claude project context — tree-sitter-m - -## What this is -A tree-sitter grammar for M (MUMPS). Specification phase only — no -code yet. Full design in `docs/spec.md`. - -## Where things will live -- `tools/build-grammar.js` — code-generator that consumes - `m-standard/integrated/grammar-surface.json` and emits the - data-driven half of `grammar.js`. -- `grammar.js` — generated tree-sitter grammar definition. -- `src/parser.c` — generated by `tree-sitter generate` from - grammar.js. Both are committed so consumers don't need - tree-sitter-cli or m-standard to install. -- `bindings/` — Node, Rust, Python, Go bindings. -- `test/corpus/` — tree-sitter corpus tests + real M routines from - m-standard's sources. - -## Pipeline -``` -m-standard/integrated/grammar-surface.json - │ - ▼ -tools/build-grammar.js (run on m-standard updates) - │ - ▼ -grammar.js (committed) - │ - ▼ -tree-sitter generate (run on grammar.js changes) - │ - ▼ -src/parser.c + src/grammar-metadata.json (committed) - │ - ▼ -tree-sitter test (corpus tests, per-tier coverage gate) - │ - ▼ -bindings/{node,rust,python,go} (compiled per platform) -``` - -## Hard rules -- **Read `docs/tree-sitter-notes.md` before adding grammar rules - that involve overlapping regex tokens, keyword vs identifier - disambiguation, or context-sensitive recognition.** Two non- - obvious tree-sitter constraints have already cost us debugging - time: token precedence is dominant (not a tiebreaker for length), - and the regex engine has no look-around. The notes document - records the workaround patterns we've adopted (GLR parser - alternatives, external-scanner byte-level lookahead, disjoint-by- - required-structure regexes) and when to pick which. -- **The parser recognises the union of all sources.** Subsetting - belongs in the linter layer (`tree-sitter-m-lint`), not the - grammar. See `docs/spec.md` AD-01. -- **Hand-code language structure; data-drive the keyword tables.** - Line shape, comments, strings, postconditionals, indirection, - dot-blocks are invariant across sources and live in `grammar.js`. - Commands / functions / ISVs / operators / pattern codes come - from `m-standard`. See AD-02. -- **Stamp `standard_status` on every keyword node.** Per-token - tier metadata is what lets downstream linters work without - re-parsing. See AD-03. -- **Pin the m-standard schema_version.** When m-standard ships a - breaking schema change, tree-sitter-m adopts deliberately and bumps - major version. CI fails if the consumed file's - `schema_version` doesn't match the pin. See AD-04. - -## Source for grammar data -**Always** `~/projects/m-standard/integrated/grammar-surface.json`, -read at build time only. Never the per-source TSVs, never the -pragmatic / SAC / operational standards. Those serve different -consumers (the linter, not the parser). - -## Conventions -- AGPL-3.0 (matches m-standard). -- Generated artifacts (`grammar.js`, `src/parser.c`) ARE committed - so installs don't need build tools. -- Tree-sitter version pinned in `package.json`; no surprise upgrades. -- Bindings use tree-sitter's standard scaffold; no bespoke binding - code. -- Tests use tree-sitter's standard corpus format - (`test/corpus/*.txt` with `===` separators). - -## Toolchain -- Node.js ≥ 20 (tree-sitter-cli) -- C compiler (gcc/clang/MSVC) for the generated parser -- No m-standard runtime dependency — tree-sitter-m ships pre-generated - artifacts. m-standard is a build-time data input only. - -## What this is NOT -- A linter. That's `tree-sitter-m-lint` (sibling project). -- A formatter. That's a separate downstream consumer. -- A compiler / interpreter. M execution belongs to YottaDB / IRIS. -- A semantic analyzer. The parser produces a parse tree; type - inference, control flow, cross-routine resolution all live above. -- A parser for **InterSystems ObjectScript** (`##class`, `&sql`, - `obj.method()`, `obj.property=val`, `##super`, etc.). ObjectScript - is a separate scripting language layered on top of M's runtime; - if you want to parse it, build a sibling grammar - (`tree-sitter-objectscript`). tree-sitter-m covers M and M dialects - (AnnoStd, YottaDB, IRIS's M layer) only. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 120000 index 0000000..47dc3e3 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file diff --git a/Makefile b/Makefile index a4f092d..6336a85 100644 --- a/Makefile +++ b/Makefile @@ -106,4 +106,42 @@ test: parse-rate-check: ./scripts/vista-parse-rate.sh -.PHONY: all install uninstall clean test parse-rate-check +# ── Phase-0 AI-discoverability contract ─────────────────────────────── +# +# Tier-2 entry to the org catalog. See +# https://github.com/m-dev-tools/.github/blob/main/docs/AI-discoverability-plan.md +# +# The exposed `src/{node-types,grammar,grammar-metadata}.json` files +# are tree-sitter-generated and already committed; there's no separate +# `make manifest` step that regenerates them outside the existing +# `tree-sitter generate` / `tools/build-grammar.js` chain (gated by +# `make test`). `make manifest` is therefore a no-op pointer — it +# exists only so verification_commands in dist/repo.meta.json line up +# with the other org repos. + +manifest: + @echo "tree-sitter-m: dist/repo.meta.json exposes are tree-sitter-generated under src/." + @echo " - 'tree-sitter generate' → src/{parser.c,grammar.json,node-types.json}" + @echo " - 'node tools/build-grammar.js' → grammar.js + src/grammar-metadata.json" + @echo " (the build-grammar step requires a sibling m-standard checkout)" + +check-manifest: + python3 tools/check-manifest.py + +# Guardrail: docs/ holds only human-readable prose. Same target name +# as the tier-1 repos so cross-repo muscle memory works. +check-docs-prose: + @if [ ! -d docs ]; then echo "check-docs-prose: no docs/ directory ✓"; exit 0; fi; \ + violations=$$(find docs -type f \ + ! -name '*.md' ! -name '*.markdown' \ + ! -name '*.png' ! -name '*.jpg' ! -name '*.jpeg' \ + ! -name '*.gif' ! -name '*.svg' ! -name '*.webp' \ + ! -name '.gitkeep'); \ + if [ -n "$$violations" ]; then \ + echo "ERROR: non-prose files under docs/ — move to a top-level domain dir:" >&2; \ + echo "$$violations" >&2; \ + exit 1; \ + fi; \ + echo "check-docs-prose: docs/ is prose-only ✓" + +.PHONY: all install uninstall clean test parse-rate-check manifest check-manifest check-docs-prose diff --git a/tools/check-manifest.py b/tools/check-manifest.py new file mode 100755 index 0000000..f01d59a --- /dev/null +++ b/tools/check-manifest.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python3 +"""Phase-0 contract gate for dist/repo.meta.json. + +Validates that: + 1. dist/repo.meta.json parses as JSON. + 2. Required fields from the org-level repo.meta.schema.json contract + are present. + 3. Each path under `exposes.*` resolves on disk. + 4. (Best-effort) full schema validation if jsonschema is available + and the canonical schema URL is reachable. + +Exits 0 on success; non-zero with structured stderr on failure. + +Engine-free, no Node, no Python deps beyond the standard library +unless jsonschema happens to be installed. +""" + +from __future__ import annotations + +import json +import sys +import urllib.request +from pathlib import Path + +MANIFEST = Path("dist/repo.meta.json") + +REQUIRED_FIELDS = ( + "id", + "repo", + "role", + "language", + "license", + "agent_instructions", + "verified_on", + "exposes", + "verification_commands", +) + + +def main() -> int: + if not MANIFEST.exists(): + print(f"ERROR: {MANIFEST} not found", file=sys.stderr) + return 1 + + try: + data = json.loads(MANIFEST.read_text(encoding="utf-8")) + except json.JSONDecodeError as exc: + print(f"ERROR: {MANIFEST} is invalid JSON: {exc}", file=sys.stderr) + return 1 + + missing = [f for f in REQUIRED_FIELDS if f not in data] + if missing: + print(f"ERROR: missing required fields: {missing}", file=sys.stderr) + return 1 + + fail = False + for key, rel_path in data["exposes"].items(): + if rel_path.startswith(("http://", "https://")): + continue + if not Path(rel_path).exists(): + print( + f"ERROR: exposes.{key} payload missing on disk: {rel_path}", + file=sys.stderr, + ) + fail = True + if fail: + return 1 + + # Best-effort full schema validation. Skipped silently if jsonschema + # isn't available (the canonical Track-A validator runs in the org + # smoke test against the same manifest). + try: + from jsonschema import Draft202012Validator # type: ignore + except ImportError: + print( + "check-manifest: dist/repo.meta.json valid; " + "all exposes.* present ✓ (jsonschema not installed — " + "skipping full schema validation)" + ) + return 0 + + schema_uri = data.get("$schema", "") + try: + with urllib.request.urlopen(schema_uri, timeout=5) as resp: + schema = json.load(resp) + except Exception as exc: # noqa: BLE001 + print( + f"check-manifest: dist/repo.meta.json valid; all exposes.* " + f"present ✓ (skipped live schema fetch: {exc})" + ) + return 0 + + errors = list(Draft202012Validator(schema).iter_errors(data)) + if errors: + for err in errors: + path = "/".join(str(p) for p in err.absolute_path) or "" + print(f"SCHEMA ERROR at {path}: {err.message}", file=sys.stderr) + return 1 + + print( + "check-manifest: dist/repo.meta.json valid against org schema; " + "all exposes.* present ✓" + ) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) From ade59d663d292e37018d2a84aefda9a16d4c02ef Mon Sep 17 00:00:00 2001 From: Rafael Richards Date: Sun, 10 May 2026 21:56:20 -0400 Subject: [PATCH 2/2] phase2-onboarding: track dist/repo.meta.json (was hidden by .gitignore) dist/ is ignored at line 20 for Python artifacts; the manifest got silently dropped from the previous commit. Adds a !dist/repo.meta.json exception so the Phase-0 contract file lands in git (the org catalog fetches it by raw URL). Same pattern m-standard used during its Phase-0 onboarding. --- .gitignore | 5 ++++- dist/repo.meta.json | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 dist/repo.meta.json diff --git a/.gitignore b/.gitignore index 8f3d24f..1071425 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,10 @@ _obj/ # Python artifacts .venv/ -dist/ +dist/* +# Phase-0 contract: org catalog fetches this by raw URL; track it +# despite the broader dist/ ignore. +!dist/repo.meta.json *.egg-info *.whl diff --git a/dist/repo.meta.json b/dist/repo.meta.json new file mode 100644 index 0000000..401f9d3 --- /dev/null +++ b/dist/repo.meta.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://raw.githubusercontent.com/m-dev-tools/.github/main/profile/repo.meta.schema.json", + "id": "tool:tree-sitter-m", + "repo": "https://github.com/m-dev-tools/tree-sitter-m", + "role": "Tree-sitter grammar for M (MUMPS) — parser + AST node-types + grammar-metadata, generated from m-standard's grammar-surface.json", + "language": ["javascript", "c", "rust", "python", "go"], + "license": "AGPL-3.0", + "agent_instructions": "AGENTS.md", + "verified_on": "2026-05-10", + "exposes": { + "node_types": "src/node-types.json", + "grammar": "src/grammar.json", + "grammar_metadata": "src/grammar-metadata.json" + }, + "consumes": ["tool:m-standard"], + "verification_commands": ["make test", "make check-manifest"], + "status": "active", + "notes": "Parser artefacts under src/ are committed — consumers don't need tree-sitter-cli or an m-standard sibling checkout. m-standard is a build-time data input only (consumed by tools/build-grammar.js when regenerating the grammar)." +}