@geml/geml 1.7.6 → 1.7.8
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/dist/render.js +35 -27
- package/package.json +1 -1
- package/skill/SKILL.md +33 -30
- package/skill/references/authoring.geml +22 -0
package/dist/render.js
CHANGED
|
@@ -562,17 +562,27 @@ export class RenderCtx {
|
|
|
562
562
|
return `<figure${idAttr}><p class="table-note">external data <code>${esc(src)}</code> — loaded at render time</p>${cap0}</figure>`;
|
|
563
563
|
}
|
|
564
564
|
}
|
|
565
|
+
// Overflow FOLDS; it is never dropped. `--to html` is a CONVERSION, and
|
|
566
|
+
// a conversion that loses data is not one — the old behaviour kept the
|
|
567
|
+
// first 500 lines and said "the complete data is in the document
|
|
568
|
+
// source", which is no help at all to someone holding only the HTML.
|
|
569
|
+
// The bound belongs to what is OPEN, not to what is present: the rest
|
|
570
|
+
// sits in a collapsed <details>, so the page is exactly as short as
|
|
571
|
+
// before and the block is complete. There is no ceiling above which
|
|
572
|
+
// lines vanish again, because a <pre> is a single text node — the cost
|
|
573
|
+
// of keeping them is bytes on disk, which is what not losing data
|
|
574
|
+
// costs.
|
|
565
575
|
const tail = fmt === "jsonl" && lines.length > limit;
|
|
566
576
|
const shown = tail ? lines.slice(-limit) : lines.slice(0, limit);
|
|
567
|
-
const
|
|
568
|
-
const note = omitted > 0
|
|
569
|
-
? `<p class="table-note">${tail
|
|
570
|
-
? `showing the last ${shown.length} of ${lines.length} lines — earlier lines are in the document source`
|
|
571
|
-
: `showing the first ${shown.length} of ${lines.length} lines — the complete data is in the document source`}</p>`
|
|
572
|
-
: "";
|
|
577
|
+
const rest = tail ? lines.slice(0, lines.length - shown.length) : lines.slice(shown.length);
|
|
573
578
|
const cap = caption ? `<figcaption>${esc(caption)}</figcaption>` : "";
|
|
574
|
-
const pre = `<pre class="data-src" data-format="${escAttr(fmt)}">${esc(
|
|
575
|
-
|
|
579
|
+
const pre = (ls) => `<pre class="data-src" data-format="${escAttr(fmt)}">${esc(ls.join("\n"))}</pre>`;
|
|
580
|
+
if (rest.length === 0)
|
|
581
|
+
return `<figure${idAttr}>${pre(shown)}${cap}</figure>`;
|
|
582
|
+
// jsonl reads as an append-log, so its open end is the NEWEST lines and
|
|
583
|
+
// the fold holds the earlier ones, above; json reads from the top.
|
|
584
|
+
const more = `<details class="data-more"><summary>${rest.length} ${tail ? "earlier" : "more"} line${rest.length === 1 ? "" : "s"} of ${lines.length}</summary>${pre(rest)}</details>`;
|
|
585
|
+
return `<figure${idAttr}>${tail ? more + pre(shown) : pre(shown) + more}${cap}</figure>`;
|
|
576
586
|
}
|
|
577
587
|
case "table":
|
|
578
588
|
return b.table ? this.table(b.table, b.id, caption) : `<p class="render-error">table failed to parse</p>`;
|
|
@@ -636,17 +646,20 @@ export class RenderCtx {
|
|
|
636
646
|
table(t, id, caption) {
|
|
637
647
|
const idAttr = id ? ` id="${escAttr(id)}"` : "";
|
|
638
648
|
const alignStyle = (a) => (a ? ` style="text-align:${a}"` : "");
|
|
639
|
-
//
|
|
640
|
-
//
|
|
641
|
-
//
|
|
642
|
-
//
|
|
643
|
-
//
|
|
644
|
-
//
|
|
645
|
-
//
|
|
646
|
-
//
|
|
647
|
-
|
|
649
|
+
// Laying out tens of thousands of <table> rows OPEN freezes the page for
|
|
650
|
+
// seconds, so a long table renders folded shut — the codemap's edge tables
|
|
651
|
+
// (#calls / #called-by) are the ones that get there. Its #modules table is
|
|
652
|
+
// the page's content, the inventory people came to scan and filter, so that
|
|
653
|
+
// one stays open at any size.
|
|
654
|
+
//
|
|
655
|
+
// EVERY row is rendered. `tableRows` bounds what is OPEN, never what is
|
|
656
|
+
// present: past it the whole table goes inside a collapsed <details>, which
|
|
657
|
+
// costs the reader one click and costs the document nothing. It used to
|
|
658
|
+
// slice the rows away and say the complete table was in the source, which
|
|
659
|
+
// made `--to html` a lossy conversion of a table the model holds in full.
|
|
660
|
+
const foldAbove = this.isCodemapDoc && id === "modules" ? Infinity : (this.opts.tableRows ?? 500);
|
|
648
661
|
const allRows = t.rows;
|
|
649
|
-
const rows = allRows
|
|
662
|
+
const rows = allRows;
|
|
650
663
|
const thead = t.header
|
|
651
664
|
? `<thead><tr>${t.columns.map((col, c) => `<th${alignStyle(t.align[c])}>${esc(col)}</th>`).join("")}</tr></thead>`
|
|
652
665
|
: "";
|
|
@@ -666,15 +679,10 @@ export class RenderCtx {
|
|
|
666
679
|
: "";
|
|
667
680
|
const cap = caption ? `<figcaption>${esc(caption)}</figcaption>` : "";
|
|
668
681
|
const tools = `<div class="table-tools"><input class="table-filter" type="search" placeholder="Filter rows…" aria-label="Filter table rows"></div>`;
|
|
669
|
-
if (allRows.length >
|
|
670
|
-
const
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
return `<figure class="table-figure"${idAttr}><details><summary>${summary}</summary>${tools}` +
|
|
674
|
-
`<div class="table-scroll"><table class="geml-table">${thead}<tbody>\n${bodyRows}\n</tbody>${tfoot}</table></div>${note}</details>${cap}</figure>`;
|
|
675
|
-
}
|
|
676
|
-
return `<figure class="table-figure"${idAttr}>${tools}` +
|
|
677
|
-
`<div class="table-scroll"><table class="geml-table">${thead}<tbody>\n${bodyRows}\n</tbody>${tfoot}</table></div>${note}${cap}</figure>`;
|
|
682
|
+
if (allRows.length > foldAbove) {
|
|
683
|
+
const summary = `${esc(id ? "#" + id : "table")} · ${allRows.length} rows`;
|
|
684
|
+
return `<figure class="table-figure"${idAttr}><details><summary>${summary}</summary>${tools}` +
|
|
685
|
+
`<div class="table-scroll"><table class="geml-table">${thead}<tbody>\n${bodyRows}\n</tbody>${tfoot}</table></div></details>${cap}</figure>`;
|
|
678
686
|
}
|
|
679
687
|
return `<figure class="table-figure"${idAttr}>${tools}` +
|
|
680
688
|
`<div class="table-scroll"><table class="geml-table">${thead}<tbody>\n${bodyRows}\n</tbody>${tfoot}</table></div>${cap}</figure>`;
|
package/package.json
CHANGED
package/skill/SKILL.md
CHANGED
|
@@ -53,6 +53,23 @@ file stay what it is.
|
|
|
53
53
|
If `geml --version` does not answer, none of this is available. Read and edit
|
|
54
54
|
the ordinary way, and do not tell anyone to install anything.
|
|
55
55
|
|
|
56
|
+
## A project moving TO GEML
|
|
57
|
+
|
|
58
|
+
"This project's documents are GEML now" means new documents are authored as
|
|
59
|
+
`.geml` — notes, plans, findings, reports — in one directory (`docs/geml/`
|
|
60
|
+
unless the project says otherwise), one file per topic, with an `index.geml`
|
|
61
|
+
saying what is there and why. It does not mean converting what is already
|
|
62
|
+
written, and nobody has to say "leave the existing files alone" for that to
|
|
63
|
+
hold.
|
|
64
|
+
|
|
65
|
+
**Add, never replace.** Writing a `.geml` version of a document is not licence
|
|
66
|
+
to delete the Markdown it was drawn from — however completely the content was
|
|
67
|
+
carried across, and whatever a "one home per topic" convention seems to imply.
|
|
68
|
+
Deleting a file is a request a person makes, never an inference from a
|
|
69
|
+
convention. When both exist, say in each what it is for and name one of them as
|
|
70
|
+
the place a given fact is maintained: two documents describing a project is
|
|
71
|
+
fine, two documents maintaining the same fact is what drifts.
|
|
72
|
+
|
|
56
73
|
## A GEML document — get the syntax right
|
|
57
74
|
|
|
58
75
|
GEML expresses **every** kind of structured content — code, tables, diagrams,
|
|
@@ -75,9 +92,12 @@ GEML file is correct only when `geml check` reports **no error diagnostics**
|
|
|
75
92
|
`---` breaks, no YAML frontmatter — metadata is a `=== meta` block, and the
|
|
76
93
|
document TITLE lives there (`title = "…"`), not in an H1. A heading may
|
|
77
94
|
carry a stable explicit id: `## Title {#sec}`.
|
|
78
|
-
4. **
|
|
79
|
-
|
|
80
|
-
`other.geml#id`. An
|
|
95
|
+
4. **Give every section a stable `{#id}`** — `## Findings {#findings}` — then
|
|
96
|
+
keep ids unique per document, with **every reference resolving**:
|
|
97
|
+
`[t](#id)`, `[[#id]]`, `[^id]`, `src=`, `data=`, `other.geml#id`. An
|
|
98
|
+
unresolved reference is a build **error**. Naming them is the part that pays
|
|
99
|
+
later: a document with no ids costs what Markdown costs, because there is
|
|
100
|
+
nothing for `geml get` to read or `geml set` to replace short of the file.
|
|
81
101
|
5. **No raw HTML.** Notes → `=== note`, comments → `%%` lines, hidden content
|
|
82
102
|
→ `{hidden}`, addressable prose → `=== text`, verified data → `=== data`
|
|
83
103
|
(json/jsonl; `code` shows text, `data` IS data).
|
|
@@ -108,38 +128,21 @@ geml find "text" file|dir # search block CONTENT -> file<TAB>address
|
|
|
108
128
|
# a directory walks *.geml only
|
|
109
129
|
geml get file.geml '#id' # read ONE block (a heading id = its whole section)
|
|
110
130
|
geml set file.geml '#id' --in f # replace ONE block (re-parsed; never writes a broken doc)
|
|
111
|
-
geml replace file.geml OLD NEW # EXPERIMENTAL literal swap; --within '#id' to narrow
|
|
112
131
|
geml history save file.geml -m "…" # snapshot to .gemlhistory after each meaningful edit
|
|
113
132
|
geml revert file.geml '#id' # roll ONE block back (--rev -2 | changed | <rev-id>)
|
|
114
133
|
```
|
|
115
134
|
|
|
116
135
|
Address a block, never a line range: `#id` · `'## Heading'` (its whole section)
|
|
117
|
-
· `
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
empty one writes an opening where the section had none.
|
|
128
|
-
|
|
129
|
-
When the exact old text is already known and nothing needs reading — a version
|
|
130
|
-
string in six places, a renamed term — `geml replace` is the cheap path, and the
|
|
131
|
-
one to prefer over dropping to `sed`: same two short strings, but the result is
|
|
132
|
-
re-parsed before it lands, the blocks it touched are named back to you, and it
|
|
133
|
-
is in `.gemlhistory` to revert. It swaps a LITERAL, never a pattern, and refuses
|
|
134
|
-
a swap that would rename an id (use `geml rename`, which fixes the references
|
|
135
|
-
too). **It is EXPERIMENTAL and may be withdrawn** — reach for it, but do not
|
|
136
|
-
build anything on it that cannot change.
|
|
137
|
-
|
|
138
|
-
A write is refused when it would break the document, never merely because it
|
|
139
|
-
removes something: a replacement that drops blocks is carried out and NAMED on
|
|
140
|
-
stderr — unnamed blocks included — with `geml revert` as the way back. Read,
|
|
141
|
-
edit, write back, and nothing is dropped, because `get` handed those blocks to
|
|
142
|
-
you. Send content that omits them only when removing them is the point.
|
|
136
|
+
· `L27-58` (the smallest block holding those lines — how a line number from an
|
|
137
|
+
editor, a linter or a diff hunk becomes an address). `list` and `find` print
|
|
138
|
+
addresses that paste straight into the others, so neither `grep` nor a line
|
|
139
|
+
count is needed to locate anything.
|
|
140
|
+
|
|
141
|
+
The rest is one `geml get` away in the reference below, and stays there because
|
|
142
|
+
it is needed rarely and this page is read every time: the remaining address
|
|
143
|
+
forms in `#cli`, and in `#editing` the three ways to cut a section
|
|
144
|
+
(`--head`/`--intro`/`--body`), the experimental `replace`, and what a write that
|
|
145
|
+
drops blocks does.
|
|
143
146
|
|
|
144
147
|
## Full reference — pull ONE section, not the whole file
|
|
145
148
|
|
|
@@ -293,6 +293,28 @@ geml revert file.geml '#intro' --rev changed # …the block's last ACTUAL chang
|
|
|
293
293
|
block) and `history`/`revert` (version and rewind it) let an agent revise a
|
|
294
294
|
document incrementally and undo any single section.
|
|
295
295
|
|
|
296
|
+
**A section can be cut three ways**, on `get` and `set` alike: `--head` (the
|
|
297
|
+
heading line), `--intro` (what it says before its first subheading — empty when
|
|
298
|
+
one follows immediately, the whole body when none does), `--body` (everything
|
|
299
|
+
under it, so it always contains the intro). `--intro` is how you edit a
|
|
300
|
+
section's opening without pulling its subsections into context, and setting an
|
|
301
|
+
empty one writes an opening where the section had none.
|
|
302
|
+
|
|
303
|
+
**When the exact old text is already known** and nothing needs reading — a
|
|
304
|
+
version string in six places, a renamed term — `geml replace` is the cheap path,
|
|
305
|
+
and the one to prefer over dropping to `sed`: the same two short strings, but
|
|
306
|
+
the result is re-parsed before it lands, the blocks it touched are named back to
|
|
307
|
+
you, and it is in `.gemlhistory` to revert. It swaps a LITERAL, never a pattern,
|
|
308
|
+
and refuses a swap that would rename an id (use `geml rename`, which fixes the
|
|
309
|
+
references too). **It is EXPERIMENTAL and may be withdrawn** — reach for it, but
|
|
310
|
+
do not build anything on it that cannot change.
|
|
311
|
+
|
|
312
|
+
**A write is refused when it would BREAK the document**, never merely because it
|
|
313
|
+
removes something: a replacement that drops blocks is carried out and NAMED on
|
|
314
|
+
stderr — unnamed blocks included — with `geml revert` as the way back. Read,
|
|
315
|
+
edit, write back, and nothing is dropped, because `get` handed those blocks to
|
|
316
|
+
you. Send content that omits them only when removing them is the point.
|
|
317
|
+
|
|
296
318
|
**Where sidecars do NOT belong:** a doc that git already versions — config
|
|
297
319
|
docs especially — usually needs no `.gemlhistory`; do not create one there
|
|
298
320
|
unless the user asks for finer-than-commit history.
|