@geml/geml 1.7.1 → 1.7.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 +20 -4
- package/dist/block-edit.js +15 -1
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +2433 -0
- package/dist/from-md.js +1 -1
- package/dist/geml.d.ts +32 -0
- package/dist/geml.js +172 -2038
- package/dist/history.js +7 -3
- package/dist/mcp.js +46 -8
- package/dist/render-html.d.ts +1 -1
- package/dist/render.d.ts +1 -1
- package/dist/render.js +180 -15
- package/dist/selector.d.ts +7 -0
- package/dist/selector.js +41 -1
- package/package.json +67 -67
- package/skill/SKILL.md +25 -0
- package/skill/references/authoring.geml +6 -1
package/README.md
CHANGED
|
@@ -96,8 +96,11 @@ Every command reads a file path, or `-` for stdin. Exit codes: `0` ok ·
|
|
|
96
96
|
```sh
|
|
97
97
|
geml doc.geml # document-model JSON (default --to json)
|
|
98
98
|
geml doc.geml --to md|html|geml # convert; geml notes.md -> GEML
|
|
99
|
+
geml list doc.geml # CALL FIRST: every block, its address, kind, line range
|
|
100
|
+
geml find "text" doc.geml|dir # search block CONTENT -> file<TAB>address; exit 1 = no hit
|
|
99
101
|
geml get doc.geml ['<selector>'] # list addressable blocks, or print what the selector matches
|
|
100
|
-
geml
|
|
102
|
+
geml get doc.geml '#sec' --intro # a section cuts three ways: --head | --intro | --body
|
|
103
|
+
geml set doc.geml '<selector>' [--head|--intro|--body] [--in F[#src]] # replace ONE block's content
|
|
101
104
|
geml add doc.geml (--append|--before #id|--after #id) [--in F[#src]] # insert a fragment
|
|
102
105
|
geml delete doc.geml '#id' ['#id2' …] # remove one or more blocks
|
|
103
106
|
geml rename doc.geml '#old' '#new' # rename an id + every reference to it
|
|
@@ -126,9 +129,22 @@ The agent loop: `geml get` a block → `set`/`add`/`delete`/`rename` it →
|
|
|
126
129
|
|
|
127
130
|
`get` answers with N contents when N match (document order, count on stderr);
|
|
128
131
|
`set` writes ONE block, so a selector matching several is refused (exit 2) with
|
|
129
|
-
the unique address of each candidate.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
+
the unique address of each candidate. A section cuts three ways: `--head` is the
|
|
133
|
+
heading line, `--intro` its opening region — everything under it up to its first
|
|
134
|
+
subheading — and `--body` everything under it, so `--body` always contains
|
|
135
|
+
`--intro`, and equals it when the section has no subheading. All three
|
|
136
|
+
round-trip — `geml get f X --body | geml set f X --body` leaves the file
|
|
137
|
+
byte-identical — and `--intro` is how a section's opening is edited without
|
|
138
|
+
pulling its subsections into context. A block has no intro; asking for one is a
|
|
139
|
+
usage error rather than a quiet fall back to the body.
|
|
140
|
+
|
|
141
|
+
A write is refused when it would break the document, never merely because it
|
|
142
|
+
removes something. A replacement that drops blocks is carried out and the
|
|
143
|
+
dropped blocks are named on stderr — unnamed ones counted, references left
|
|
144
|
+
dangling reported — with `geml revert` as the way back. That is the same stance
|
|
145
|
+
`delete` takes, so removing content has one rule rather than two, and no region
|
|
146
|
+
becomes uneditable because something inside it happens to carry an id. The
|
|
147
|
+
round trip above drops nothing: the blocks came back in the text you sent.
|
|
132
148
|
|
|
133
149
|
A `@<hex>` **content address** is the first 8 hex of the SHA-256 of the block's
|
|
134
150
|
own text (line endings normalized to LF, no trailing newline), with `~1`, `~2`…
|
package/dist/block-edit.js
CHANGED
|
@@ -25,6 +25,20 @@ function splitLines(source) {
|
|
|
25
25
|
function stripEnding(line) {
|
|
26
26
|
return line.replace(/(\r\n|\r|\n)$/, "");
|
|
27
27
|
}
|
|
28
|
+
// A local mirror of geml.ts's trimSpaceTabEnd — geml.ts already imports THIS
|
|
29
|
+
// module (normalizeBlockId), so importing back would close a cycle. Linear on
|
|
30
|
+
// purpose: `/[ \t]+$/` restarts the run at every index inside a run that never
|
|
31
|
+
// reaches the end of the line, which is quadratic in the line's length.
|
|
32
|
+
function trimSpaceTabEnd(s) {
|
|
33
|
+
let i = s.length;
|
|
34
|
+
while (i > 0) {
|
|
35
|
+
const c = s.charCodeAt(i - 1);
|
|
36
|
+
if (c !== 0x20 && c !== 0x09)
|
|
37
|
+
break;
|
|
38
|
+
i--;
|
|
39
|
+
}
|
|
40
|
+
return i === s.length ? s : s.slice(0, i);
|
|
41
|
+
}
|
|
28
42
|
// Rewrite the id inside a `{…}` attribute block to `#newId`, keeping the braces
|
|
29
43
|
// and every other class/attr byte. If no id is present, insert `#newId` as the
|
|
30
44
|
// first token. The id token sits at a token boundary (`{` or whitespace) and
|
|
@@ -98,7 +112,7 @@ export function normalizeBlockId(blockSrc, newId) {
|
|
|
98
112
|
const openLen = /^=+/.exec(f[1])[0].length;
|
|
99
113
|
for (let j = hi + 1; j < lines.length; j++) {
|
|
100
114
|
const ct = stripEnding(lines[j]);
|
|
101
|
-
const trimmed = ct
|
|
115
|
+
const trimmed = trimSpaceTabEnd(ct);
|
|
102
116
|
if (/^=+$/.test(trimmed) && trimmed.length === openLen)
|
|
103
117
|
break; // plain close: done
|
|
104
118
|
const cm = /^(={3,}[ \t]+#)([^\s}]+)([ \t]*)$/.exec(ct);
|
package/dist/cli.d.ts
ADDED