Sign In

@geml/geml

Package Overview
Dependencies
Maintainers
1
Versions
30
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@geml/geml - npm Package Compare versions

Comparing version
1.7.2
to
1.7.3
+6
-0
codemap/build.mjs

@@ -516,2 +516,8 @@ #!/usr/bin/env node

);
// A build that deletes files says which ones. Silence here is how the orphans
// accumulated in the first place — name them, so a rename that drops a whole
// naming scheme is visible in the log rather than three renamings later.
if (stats.pruned?.length) {
console.error(` pruned ${stats.pruned.length} document(s) no longer produced: ${stats.pruned.join(", ")}`);
}

@@ -518,0 +524,0 @@ // --history: snapshot every changed document into its .gemlhistory sidecar —

+31
-1

@@ -16,3 +16,3 @@ // geml-code-graph emit — exchange-format symbols/edges → the codemap document

import { createHash } from "node:crypto";
import { mkdirSync, readFileSync, writeFileSync, existsSync } from "node:fs";
import { mkdirSync, readFileSync, writeFileSync, existsSync, readdirSync, statSync, unlinkSync } from "node:fs";
import { dirname, join, posix } from "node:path";

@@ -465,2 +465,31 @@ import { buildNormalizer } from "./normalize.mjs";

// ---- prune documents this build no longer produces ----
// A container that stops yielding symbols simply gets no document; without
// this, the one written by an earlier build stays behind describing code that
// is gone. Those orphans are not inert: `geml check` reads their `src=` line
// ranges and fails the build-time reference check, which is how nine of them
// — across two renamings of the naming scheme — went unnoticed until one
// orphan's source file happened to SHRINK past its recorded line numbers.
//
// `allDocs` is the authoritative set: every .geml this run emitted, written
// or byte-identical. Anything else at the top level of outDir is an orphan.
// Two guards keep this from eating a file it does not own: only the top level
// is scanned (never _index/, _build/, or any subtree), and a candidate must
// carry the generated-document marker `resolution-default` in its head — a
// hand-placed .geml parked in the directory is left alone.
const pruned = [];
const keep = new Set(allDocs);
let present = [];
try { present = readdirSync(outDir); } catch { present = []; }
for (const f of present) {
if (!f.endsWith(".geml") || keep.has(f)) continue;
const p = join(outDir, f);
try {
if (!statSync(p).isFile()) continue;
if (!/^===\s*meta\b[\s\S]*?\bresolution-default\s*=/.test(readFileSync(p, "utf8").slice(0, 2000))) continue;
unlinkSync(p);
pruned.push(f);
} catch { /* unreadable or already gone — not this build's problem */ }
}
return {

@@ -470,2 +499,3 @@ ...stats,

writtenDocs,
pruned,
containers: containers.size,

@@ -472,0 +502,0 @@ symbols: symbols.length,

@@ -11,3 +11,3 @@ #!/usr/bin/env node

// stale, use `geml codemap serve` instead.
import { readdirSync, readFileSync, writeFileSync, realpathSync } from "node:fs";
import { readdirSync, readFileSync, writeFileSync, realpathSync, unlinkSync } from "node:fs";
import { join, basename, sep, resolve as resolvePath } from "node:path";

@@ -77,3 +77,16 @@ import { parse, renderHtml } from "../dist/geml.js";

}
// Each tool prunes what it owns: build removes the documents it no longer
// produces, and this removes the pages whose document is gone. An orphan page
// is worse than a stale one — it is unreachable from index.html yet still
// served, so a copied folder ships a page describing deleted code with no way
// to notice. Only a `<base>.html` whose `<base>.geml` is absent qualifies, so
// nothing that has a document behind it is ever touched.
const prunedPages = [];
for (const f of files) {
if (!f.endsWith(".html")) continue;
if (files.includes(f.replace(/\.html$/, ".geml"))) continue;
try { unlinkSync(join(dir, f)); prunedPages.push(f); } catch { /* already gone */ }
}
console.error(`rendered ${n} page(s) -> ${dir}${failed.length ? `; FAILED: ${failed.join(", ")}` : ""}`);
if (prunedPages.length) console.error(` pruned ${prunedPages.length} orphan page(s): ${prunedPages.join(", ")}`);
process.exit(failed.length ? 1 : 0);
+1
-1
{
"name": "@geml/geml",
"version": "1.7.2",
"version": "1.7.3",
"mcpName": "io.github.geml-spec/geml",

@@ -5,0 +5,0 @@ "publishConfig": {

@@ -27,3 +27,4 @@ <p align="center">

read or patch one section without re-emitting the whole file (on this repo's
own spec, ~**66× less context** than shipping the whole document).
own spec, ~**120× less context** than shipping the whole document — the block
is ~590 chars whatever the document grows to).
- **Verifiable** — references are checked at build time (a dangling `#id` is an

@@ -105,2 +106,3 @@ error, not a silent dead link), and the parser emits a document-model JSON

geml set doc.geml '<selector>' [--head|--intro|--body] [--in F[#src]] # replace ONE block's content
geml replace doc.geml OLD NEW [--within '<selector>'] # EXPERIMENTAL: literal swap, checked and reported
geml add doc.geml (--append|--before #id|--after #id) [--in F[#src]] # insert a fragment

@@ -112,3 +114,4 @@ geml delete doc.geml '#id' ['#id2' …] # remove one or more blocks

geml history <save|get|restore|verify> doc.geml [...] # .gemlhistory version sidecar (get = list revisions, or print one)
geml codemap <build|verify|render|serve|refresh|find|mcp> # your codebase's call graph as GEML docs
geml codemap <build|verify|render|serve|refresh|find> # your codebase's call graph as GEML docs
geml mcp --root <dir> [--graph <dir>] # serve documents (+ the code graph) over MCP
geml --help | --version # --version --json prints {"parser","spec"}

@@ -144,2 +147,11 @@ ```

`replace` is the cheap path when the exact old text is already known and nothing
needs reading — a version string in six places, a term renamed. It is the one
operation where GEML can beat `sed` outright rather than imitate it: the same
two short strings, but the result is re-parsed before it lands, the blocks it
touched are named back to you, and it is in `.gemlhistory` to revert. It swaps a
LITERAL, never a pattern, and refuses a swap that would rename an id — that is
`geml rename`, which fixes the references too. **It is EXPERIMENTAL and may be
withdrawn**; build nothing on it that cannot change.
A write is refused when it would break the document, never merely because it

@@ -241,5 +253,9 @@ removes something. A replacement that drops blocks is carried out and the

```sh
/mcp add npx -y @geml/geml@latest mcp --root /absolute/path/to/your/docs
claude mcp add geml -- npx -y @geml/geml@latest mcp --root /absolute/path/to/your/docs
```
With a code graph under `--root` (`geml codemap build`), the same server also
serves four read-only `geml_codemap_*` tools. Every tool and option:
[`docs/mcp-guide.md`](https://github.com/geml-spec/geml/blob/main/docs/mcp-guide.md).
## Library

@@ -267,4 +283,9 @@

What changed between releases:
[`CHANGELOG.md`](https://github.com/geml-spec/geml/blob/main/CHANGELOG.md).
The parser and the specification version independently — `geml --version --json`
prints both.
## License
MIT.

@@ -64,2 +64,3 @@ ---

geml set file.geml '#id' --in f # replace ONE block (re-parsed; never writes a broken doc)
geml replace file.geml OLD NEW # EXPERIMENTAL literal swap; --within '#id' to narrow
geml history save file.geml -m "…" # snapshot to .gemlhistory after each meaningful edit

@@ -82,2 +83,11 @@ geml revert file.geml '#id' # roll ONE block back (--rev -2 | changed | <rev-id>)

When the exact old text is already known and nothing needs reading — a version
string in six places, a renamed term — `geml replace` is the cheap path, and the
one to prefer over dropping to `sed`: same two short strings, but the result is
re-parsed before it lands, the blocks it touched are named back to you, and it
is in `.gemlhistory` to revert. It swaps a LITERAL, never a pattern, and refuses
a swap that would rename an id (use `geml rename`, which fixes the references
too). **It is EXPERIMENTAL and may be withdrawn** — reach for it, but do not
build anything on it that cannot change.
A write is refused when it would break the document, never merely because it

@@ -84,0 +94,0 @@ removes something: a replacement that drops blocks is carried out and NAMED on

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet