@plurnk/plurnk-grammar 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 PossumTech Laboratories, LLC
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,184 @@
1
+ # plurnk-grammar
2
+
3
+ Parser for the Plurnk protocol — a HEREDOC-style DSL for LLM agents.
4
+
5
+ ## install
6
+
7
+ ```
8
+ npm install @plurnk/plurnk-grammar
9
+ ```
10
+
11
+ Requires Node ≥ 23.6 (native TypeScript support).
12
+
13
+ ## use
14
+
15
+ ```ts
16
+ import { parse } from "plurnk-grammar";
17
+ const result = parse(input);
18
+ // result.items: Array<{kind:"statement"|"error"|"text", ...}>
19
+ // result.unparsedTail?: { from, reason }
20
+ ```
21
+
22
+ Discriminate on `item.kind`. For `statement` items, narrow on `statement.op` (one of `FIND READ EDIT COPY MOVE SHOW HIDE SEND EXEC`) to access per-OP typed fields. Full API: [SPEC.md §12](SPEC.md#12-public-api).
23
+
24
+ ## cli
25
+
26
+ ```
27
+ plurnk [file] parse to JSON; file or stdin
28
+ plurnk --help
29
+ ```
30
+
31
+ Exit `0` on clean parse, `1` on any error or unparsed tail.
32
+
33
+ ## syntax
34
+
35
+ ```
36
+ <<OPsuffix [signal]? (path)? <L>? : body? :OPsuffix
37
+ ```
38
+
39
+ | slot | shape |
40
+ |----------|----------------------------------------------------|
41
+ | `OP` | `FIND READ EDIT COPY MOVE SHOW HIDE SEND EXEC` |
42
+ | `suffix` | `[A-Za-z0-9_]*` glued to `OP`; used for nesting |
43
+ | `[…]` | optional CSV; per-OP semantics |
44
+ | `(…)` | optional URI |
45
+ | `<L>` | optional `<N>` or `<N-M>`; N, M ∈ signed integers |
46
+ | `:body:` | optional; opaque between fences |
47
+
48
+ | OP | signal | body | line marker |
49
+ |------|------------------|-----------------------|--------------------|
50
+ | FIND | tag filter | matcher | result-set range |
51
+ | READ | tag filter | matcher | per-entry lines |
52
+ | EDIT | tags | content (empty=clear) | entry lines |
53
+ | COPY | tags-to-apply | destination URI | entry lines |
54
+ | MOVE | tags-to-apply | destination URI | entry lines |
55
+ | SHOW | tag filter | matcher | result-set range |
56
+ | HIDE | tag filter | matcher | result-set range |
57
+ | SEND | HTTP status int | payload (JSON conv.) | n/a |
58
+ | EXEC | runtime tag | command or code | n/a |
59
+
60
+ Matcher body dialect by leading char: `//` xpath · `/…/flags` regex · `$` jsonpath · else glob.
61
+
62
+ Path scheme detection: `[a-z][a-z0-9+.-]*://` → URL (fully decomposed); else local (raw). Bare paths default to `file://` at runtime.
63
+
64
+ Nesting: outer body may contain inner `<<OP:…:OP` statements; outer must use a non-empty suffix so its close `:OPsuffix` is distinct.
65
+
66
+ ## examples
67
+
68
+ 1. List all xml files containing the admin user role.
69
+ <<FIND(config/**/*.xml)://user[@role='admin']:FIND
70
+
71
+ 2. Read hello in every language
72
+ <<READ(lang/??.json):$.greeting:READ
73
+
74
+ 3. Write a known entry to the index
75
+ <<EDIT[philosophy,existentialism](known://philosophy/existentialism/meaning):The meaning of life is 42:EDIT
76
+
77
+ 4. Read an entry in full
78
+ <<READ(https://www.britannica.com/biography/Donald-Rumsfeld)::READ
79
+
80
+ 5. Read lines 426–465 of a long article
81
+ <<READ(https://en.wikipedia.org/wiki/Donald_Rumsfeld)<426-465>::READ
82
+
83
+ 6. Create an unknown entry with tags
84
+ <<EDIT[france,geography](unknown://countries/france/capital):What is the capital of France?:EDIT
85
+
86
+ 7. Create a multi-line plan
87
+ <<EDIT[plan,france,task](known://plan):
88
+ - [ ] Decompose prompt into unknowns
89
+ - [ ] Discover capital of France
90
+ - [ ] Deliver
91
+ :EDIT
92
+
93
+ 8. Mark a plan step complete (single-line replace)
94
+ <<EDIT(known://plan)<2>:- [x] Discover capital of France:EDIT
95
+
96
+ 9. Replace a range of lines
97
+ <<EDIT(known://countries/france/capital)<4-5>:
98
+ The capital of France is Paris, on the river Seine.
99
+ Paris has been the continuous capital of France since 987 CE.
100
+ :EDIT
101
+
102
+ 10. Append content to an existing entry
103
+ <<EDIT(known://countries/france/capital)<-1>:[Wikipedia: Paris](https://en.wikipedia.org/wiki/Paris):EDIT
104
+
105
+ 11. Prepend content to an existing entry
106
+ <<EDIT(known://countries/france/capital)<0>:[Wikipedia: Paris](https://en.wikipedia.org/wiki/Paris):EDIT
107
+
108
+ 12. Clear entry contents (empty body between two colons)
109
+ <<EDIT(known://countries/france/capital)::EDIT
110
+
111
+ 13. Archive every distilled fetch log
112
+ <<HIDE(log://1/*/*/get)::HIDE
113
+
114
+ 14. Restore archived entries by tag filter
115
+ <<SHOW[france](known://**)::SHOW
116
+
117
+ 15. Rename a draft entry
118
+ <<MOVE(known://draft):known://final/answer:MOVE
119
+
120
+ 16. Run a shell command in the project root
121
+ <<EXEC(./):node --test:EXEC
122
+
123
+ 17. Continue the loop
124
+ <<SEND[102]:decomposed prompt; plan initialized:SEND
125
+
126
+ 18. Deliver the final answer
127
+ <<SEND[200]:Paris:SEND
128
+
129
+ 19. Search logs for timeout errors (case-insensitive regex body)
130
+ <<FIND(log://**/error):/timeout|deadline exceeded/i:FIND
131
+
132
+ 20. Find entries whose content begins with "Paris" (glob body)
133
+ <<FIND(known://countries/**):Paris*:FIND
134
+
135
+ 21. List the first 20 entries under a broad path (result-set pagination)
136
+ <<FIND(known://**)<1-20>::FIND
137
+
138
+ 22. Read the first five lines of a local file (bare path → file://)
139
+ <<READ(./README.md)<1-5>::READ
140
+
141
+ 23. Copy a draft entry to a dated archive location
142
+ <<COPY(known://draft):known://archive/2026-05-14/draft:COPY
143
+
144
+ 24. Run an inline node script
145
+ <<EXEC[node](./):
146
+ const sum = [1, 2, 3].reduce((a, b) => a + b, 0);
147
+ console.log(sum);
148
+ :EXEC
149
+
150
+ 25. Restore entries tagged france that contain "Paris" (combined filters)
151
+ <<SHOW[france](known://countries/**):Paris*:SHOW
152
+
153
+ 26. Archive the second hundred of stale fetch logs (pagination)
154
+ <<HIDE(log://**/get)<101-200>::HIDE
155
+
156
+ 27. Deliver a structured answer (JSON body)
157
+ <<SEND[200]:{"answer":"Paris","confidence":0.95}:SEND
158
+
159
+ 28. Report a client error (JSON body the model can traverse with jsonpath)
160
+ <<SEND[400]:{"reason":"unrecognized OP","got":"FOOBAR","expected":["FIND","READ","EDIT","COPY","MOVE","SHOW","HIDE","SEND","EXEC"]}:SEND
161
+
162
+ 29. Report a server error with explicit recipient
163
+ <<SEND[503](log://errors):{"reason":"git unavailable","command":"git status"}:SEND
164
+
165
+ 30. Direct an informational message at a named agent
166
+ <<SEND[102](agent://supervisor):decomposition complete; awaiting clearance:SEND
167
+
168
+ 31. Quote a plurnk operation inside another (nesting via suffix discipline)
169
+ <<EDITouter(known://demo):
170
+ The following is a quoted plurnk operation, preserved verbatim:
171
+ <<EDIT(known://inner):hello world:EDIT
172
+ :EDITouter
173
+
174
+ ## error format
175
+
176
+ Errors are JSON-serializable. Shape: `{ line, column, source, message }` where `source` ∈ `lexer | parser | visitor`. Messages use protocol vocabulary (`unrecognized character '<<' in path`, `expected close tag; got end of input`).
177
+
178
+ ## spec
179
+
180
+ [SPEC.md](SPEC.md) — full grammar specification: canonical form, per-OP semantics, matcher dialects, path decomposition, error model, whitespace rules, implementation notes.
181
+
182
+ ## license
183
+
184
+ MIT.