@geml/geml 1.1.1 → 1.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -7,11 +7,13 @@
7
7
 
8
8
  # @geml/geml
9
9
 
10
- Reference parser, validator, renderer, and CLI for **GEML** — the General
11
- Expressive Markup Language: a plain-text document format that stays legible to
12
- people and reliable for machines. Every kind of structured content code,
13
- tables, diagrams, math, callouts, metadata — is carried on **one** primitive,
14
- the typed block:
10
+ The reference parser, validator, renderer, and CLI for **GEML** (General
11
+ Expressive Markup Language) **one format, two readers.** People and AI agents
12
+ co-write the same document: plain text that stays legible for people, and
13
+ **addressable, verifiable, and versioned** for machines.
14
+
15
+ Every kind of structured content — code, tables, diagrams, math, callouts,
16
+ metadata — rides on **one** primitive, the typed block:
15
17
 
16
18
  ```
17
19
  === code {#hello lang=python}
@@ -19,9 +21,18 @@ print("hi")
19
21
  ===
20
22
  ```
21
23
 
22
- References are checked at build time (a dangling `#id` is an error, not a silent
23
- dead link), and the parser emits a document-model JSON with `diagnostics`, so
24
- agents and CI get a structured pass/fail signal.
24
+ - **Addressable** every block has an `#id`; `geml get` / `geml set '#id'`
25
+ read or patch one section without re-emitting the whole file (on this repo's
26
+ own spec, ~**31× less context** than shipping the whole document).
27
+ - **Verifiable** — references are checked at build time (a dangling `#id` is an
28
+ error, not a silent dead link), and the parser emits a document-model JSON
29
+ with a `diagnostics` array, so agents and CI get a structured pass/fail signal.
30
+ - **Versioned** — `geml history` and `geml revert` snapshot and rewind
31
+ revisions over a plain-text `.gemlhistory` sidecar.
32
+
33
+ Try the format in the [playground](https://geml-spec.github.io/geml/playground/)
34
+ — no install. Full pitch, spec, and format comparison live in the
35
+ [repository](https://github.com/geml-spec/geml).
25
36
 
26
37
  ## Install
27
38
 
@@ -31,7 +42,7 @@ npm install -g @geml/geml # global CLI — installs the `geml` command
31
42
  npm install @geml/geml # library + local bin
32
43
  ```
33
44
 
34
- Requires Node ≥ 18.
45
+ Requires Node ≥ 22.
35
46
 
36
47
  ## CLI
37
48
 
@@ -39,18 +50,37 @@ Every command reads a file path, or `-` for stdin. Exit codes: `0` ok ·
39
50
  `1` document/operation error · `2` usage error.
40
51
 
41
52
  ```sh
53
+ geml get file.geml '#id' # print ONE block by id — a heading id yields its whole section
54
+ geml set file.geml '#id' --from new.geml # replace just that block; re-parsed, refused if it breaks the doc
42
55
  geml check file.geml # validate only: diagnostics + exit code
43
56
  geml check --json file.geml # machine-readable: diagnostics array (or {"error":…} on IO failure)
44
57
  geml file.geml # full document-model JSON
58
+ geml history <commit|verify|show|restore|log> file.geml [...] # .gemlhistory version sidecar
59
+ geml revert file.geml '#id' [--to -1] # roll ONE block back to an earlier revision (-N | latest | id)
45
60
  geml render file.geml -o out.html # one self-contained, interactive HTML file
46
61
  geml export file.geml -o out.md # project to GitHub-Flavored Markdown (lossy; notes on stderr)
47
62
  geml convert in.md -o out.geml # Markdown -> GEML
48
63
  geml fmt file.geml # canonical re-format (idempotent)
49
- geml history <commit|verify|show|restore> file.geml [...] # .gemlhistory sidecar
64
+ geml codemap <build|verify|render|serve|refresh|find|mcp> # your codebase's call graph as GEML docs
50
65
  geml --help | --version # --version --json prints {"parser","spec"}
51
66
  ```
52
67
 
53
- The agent loop: write `.geml` → `geml check` fix on non-zero done.
68
+ The agent loop: `geml get` a block edit it → `geml set` (guarded splice)
69
+ `geml check` → `geml history commit` — small, precise, verifiable edits.
70
+
71
+ A **heading's** `#id` addresses its whole **section** — the heading line through
72
+ the line before the next heading of the same-or-higher level — so the prose
73
+ under a heading is block-editable with no extra syntax.
74
+ Spans overlap: blocks nested in the section keep their own ids, and a `set` on
75
+ the section that drops one of them is refused by the guard. `get --json` on a
76
+ heading covers the same content as the raw span: a section envelope
77
+ `{kind:"section", id, level, blocks:[heading, …its section's blocks]}` (a
78
+ block/footnote id still prints its single model node). `--head` narrows
79
+ `get`/`set`/`revert` to ANY id's head line — a heading's line, or a typed
80
+ block's opening fence line, so an agent renames a heading or edits a block's
81
+ attributes (caption, compute, …) without touching the body. Convention: keep
82
+ the document title in `=== meta` (`title = "…"`), not an H1 — a lone top-level
83
+ `#` section is the whole document, the telltale that it is really a title.
54
84
 
55
85
  ## Library
56
86
 
@@ -21,6 +21,17 @@ const EDGE_KIND = {
21
21
 
22
22
  export function extract({ db: dbPath, root }) {
23
23
  const db = new DatabaseSync(dbPath);
24
+ try {
25
+ return extractFrom(db, root);
26
+ } finally {
27
+ // Always release the handle: an open DatabaseSync keeps graph.db locked for
28
+ // the process lifetime, so on Windows the caller cannot delete or replace
29
+ // it (EPERM). try/finally closes it even if extraction throws.
30
+ db.close();
31
+ }
32
+ }
33
+
34
+ function extractFrom(db, root) {
24
35
  const rootFs = root.replace(/\\/g, "/").replace(/\/?$/, "/");
25
36
  const rel = (p) => {
26
37
  p = String(p).replace(/\\/g, "/");