@plurnk/plurnk-grammar 0.40.0 → 0.44.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/README.md CHANGED
@@ -21,7 +21,7 @@ const result = PlurnkParser.parse(input);
21
21
 
22
22
  Discriminate on `item.kind`. For `statement` items, narrow on `statement.op` (one of `FIND READ EDIT COPY MOVE OPEN FOLD SEND EXEC KILL PLAN`) to access per-OP typed fields. Full API: [SPEC.md §12](SPEC.md#12-public-api).
23
23
 
24
- `parsePath(raw)` is a top-level helper that decomposes a path/URI string into a `ParsedPath` (the same decomposition applied to `(target)` slots). Reach for it to resolve a **COPY destination**: COPY's body is an opaque string — a destination URI for an entry copy, a prompt for a run fork (`run://`) — so the consumer interprets it by scheme and calls `parsePath` for the destination case. (MOVE destinations arrive pre-parsed; COPY's don't, because its body is polymorphic.)
24
+ `parsePath(raw)` is a top-level helper that decomposes a path/URI string into a `ParsedPath` (the same decomposition applied to `(target)` slots). Reach for it to resolve a **COPY destination**: COPY's body is an opaque string — a destination URI for an entry copy, a prompt for a run fork (`run:///`) — so the consumer interprets it by scheme and calls `parsePath` for the destination case. (MOVE destinations arrive pre-parsed; COPY's don't, because its body is polymorphic.)
25
25
 
26
26
  ## cli
27
27
 
@@ -76,7 +76,7 @@ Nesting: outer body may contain inner `<<OP:…:OP` statements; outer must use a
76
76
  <<READ(lang/??.json):$.greeting:READ
77
77
 
78
78
  3. Write a known entry
79
- <<EDIT[philosophy,existentialism](known://philosophy/existentialism/meaning):The meaning of life is 42:EDIT
79
+ <<EDIT[philosophy,existentialism](known:///philosophy/existentialism/meaning):The meaning of life is 42:EDIT
80
80
 
81
81
  4. Read an entry in full
82
82
  <<READ(https://www.britannica.com/biography/Donald-Rumsfeld)::READ
@@ -85,41 +85,41 @@ Nesting: outer body may contain inner `<<OP:…:OP` statements; outer must use a
85
85
  <<READ(https://en.wikipedia.org/wiki/Donald_Rumsfeld)<426-465>::READ
86
86
 
87
87
  6. Create an unknown entry with tags
88
- <<EDIT[france,geography](unknown://countries/france/capital):What is the capital of France?:EDIT
88
+ <<EDIT[france,geography](unknown:///countries/france/capital):What is the capital of France?:EDIT
89
89
 
90
90
  7. Create a multi-line plan
91
- <<EDIT[plan,france,task](known://plan):
91
+ <<EDIT[plan,france,task](known:///plan):
92
92
  - [ ] Decompose prompt into unknowns
93
93
  - [ ] Discover capital of France
94
94
  - [ ] Deliver
95
95
  :EDIT
96
96
 
97
97
  8. Mark a plan step complete (single-line replace)
98
- <<EDIT(known://plan)<2>:- [x] Discover capital of France:EDIT
98
+ <<EDIT(known:///plan)<2>:- [x] Discover capital of France:EDIT
99
99
 
100
100
  9. Replace a range of lines
101
- <<EDIT(known://countries/france/capital)<4-5>:
101
+ <<EDIT(known:///countries/france/capital)<4-5>:
102
102
  The capital of France is Paris, on the river Seine.
103
103
  Paris has been the continuous capital of France since 987 CE.
104
104
  :EDIT
105
105
 
106
106
  10. Append content to an existing entry
107
- <<EDIT(known://countries/france/capital)<-1>:[Wikipedia: Paris](https://en.wikipedia.org/wiki/Paris):EDIT
107
+ <<EDIT(known:///countries/france/capital)<-1>:[Wikipedia: Paris](https://en.wikipedia.org/wiki/Paris):EDIT
108
108
 
109
109
  11. Prepend content to an existing entry
110
- <<EDIT(known://countries/france/capital)<0>:[Wikipedia: Paris](https://en.wikipedia.org/wiki/Paris):EDIT
110
+ <<EDIT(known:///countries/france/capital)<0>:[Wikipedia: Paris](https://en.wikipedia.org/wiki/Paris):EDIT
111
111
 
112
112
  12. Clear entry contents (empty body between two colons)
113
- <<EDIT(known://countries/france/capital)::EDIT
113
+ <<EDIT(known:///countries/france/capital)::EDIT
114
114
 
115
115
  13. Collapse every distilled fetch-log row
116
- <<FOLD(log://1/*/*/get)::FOLD
116
+ <<FOLD(log:///1/*/*/get)::FOLD
117
117
 
118
118
  14. Restore collapsed log rows by tag filter
119
- <<OPEN[france](log://**)::OPEN
119
+ <<OPEN[france](log:///**)::OPEN
120
120
 
121
121
  15. Rename a draft entry
122
- <<MOVE(known://draft):known://final/answer:MOVE
122
+ <<MOVE(known:///draft):known:///final/answer:MOVE
123
123
 
124
124
  16. Run a shell command in the project root
125
125
  <<EXEC(./):node --test:EXEC
@@ -131,19 +131,19 @@ Nesting: outer body may contain inner `<<OP:…:OP` statements; outer must use a
131
131
  <<SEND[200]:Paris:SEND
132
132
 
133
133
  19. Search logs for timeout errors (case-insensitive regex body)
134
- <<FIND(log://**/error):/timeout|deadline exceeded/i:FIND
134
+ <<FIND(log:///**/error):/timeout|deadline exceeded/i:FIND
135
135
 
136
136
  20. Find entries whose content begins with "Paris" (glob body)
137
- <<FIND(known://countries/**):Paris*:FIND
137
+ <<FIND(known:///countries/**):Paris*:FIND
138
138
 
139
139
  21. List the first 20 entries under a broad path (result-set pagination)
140
- <<FIND(known://**)<1-20>::FIND
140
+ <<FIND(known:///**)<1-20>::FIND
141
141
 
142
142
  22. Read the first five lines of a local file (bare path → file://)
143
143
  <<READ(./README.md)<1-5>::READ
144
144
 
145
145
  23. Copy a draft entry to a dated archive location
146
- <<COPY(known://draft):known://archive/2026-05-14/draft:COPY
146
+ <<COPY(known:///draft):known:///archive/2026-05-14/draft:COPY
147
147
 
148
148
  24. Run an inline node script
149
149
  <<EXEC[node](./):
@@ -152,10 +152,10 @@ Nesting: outer body may contain inner `<<OP:…:OP` statements; outer must use a
152
152
  :EXEC
153
153
 
154
154
  25. Restore log rows tagged france whose content matches (combined filters)
155
- <<OPEN[france](log://**):Paris*:OPEN
155
+ <<OPEN[france](log:///**):Paris*:OPEN
156
156
 
157
157
  26. Collapse the second hundred of stale fetch-log rows (pagination)
158
- <<FOLD(log://**/get)<101-200>::FOLD
158
+ <<FOLD(log:///**/get)<101-200>::FOLD
159
159
 
160
160
  27. Deliver a structured answer (JSON body)
161
161
  <<SEND[200]:{"answer":"Paris","confidence":0.95}:SEND
@@ -164,30 +164,30 @@ Nesting: outer body may contain inner `<<OP:…:OP` statements; outer must use a
164
164
  <<SEND[400]:{"reason":"unrecognized OP","got":"FOOBAR","expected":["FIND","READ","EDIT","COPY","MOVE","OPEN","FOLD","SEND","EXEC","KILL","PLAN"]}:SEND
165
165
 
166
166
  29. Report a server error with explicit recipient
167
- <<SEND[503](log://errors):{"reason":"git unavailable","command":"git status"}:SEND
167
+ <<SEND[503](log:///errors):{"reason":"git unavailable","command":"git status"}:SEND
168
168
 
169
169
  30. Direct an informational message at a named agent
170
170
  <<SEND[102](agent://supervisor):decomposition complete; awaiting clearance:SEND
171
171
 
172
172
  31. Kill a runaway process
173
- <<KILL(exec://3/1/2)::KILL
173
+ <<KILL(exec:///3/1/2)::KILL
174
174
 
175
175
  32. Permanently delete an entry
176
- <<KILL(known://obsolete/note)::KILL
176
+ <<KILL(known:///obsolete/note)::KILL
177
177
 
178
178
  33. Think aloud — reasoning recorded to the log
179
179
  <<PLAN:Need the capital fact; discover via wiki, record to known, deliver.:PLAN
180
180
 
181
181
  34. Insert a line between lines 2 and 3 (decimal = between; replaces nothing)
182
- <<EDIT(known://plan)<2.5>:- [ ] Verify against a second source:EDIT
182
+ <<EDIT(known:///plan)<2.5>:- [ ] Verify against a second source:EDIT
183
183
 
184
184
  35. Semantic search with a similarity threshold (decimal = minimum score)
185
- <<FIND(known://**)<0.7>:~territorial concessions:FIND
185
+ <<FIND(known:///**)<0.7>:~territorial concessions:FIND
186
186
 
187
187
  36. Quote a plurnk operation inside another (nesting via suffix discipline)
188
- <<EDITouter(known://demo):
188
+ <<EDITouter(known:///demo):
189
189
  The following is a quoted plurnk operation, preserved verbatim:
190
- <<EDIT(known://inner):hello world:EDIT
190
+ <<EDIT(known:///inner):hello world:EDIT
191
191
  :EDITouter
192
192
 
193
193
  ## error format
@@ -202,6 +202,7 @@ Four generated [GBNF](https://github.com/ggml-org/llama.cpp/blob/master/grammars
202
202
  - **`plurnk-free.gbnf`** — free text and statements interleave with `<<` escapable to text: an opener-lookalike that never completes a real keyword stays inert text. The permissive fallback if the hard commit bites.
203
203
  - **`plurnk-closed.gbnf`** — free-style text, but the turn must close with a final pathless `SEND[102]`/`SEND[200]` (forced EOS). For models that ramble past optional stopping points.
204
204
  - **`plurnk-strict.gbnf`** — ops only, bounded newline separators. The tightest rail, for models that don't reason.
205
+ - **`plurnk-plan.gbnf`** — exactly `plurnk-strict`, but the turn must open with a `<<PLAN:` op: forces a reasoning step before any action.
205
206
 
206
207
  The parser remains the permissive contract — everything any of the three can generate, the parser accepts (interstatement text surfaces as `kind: "text"` items).
207
208
 
@@ -819,7 +819,7 @@ tag ::= [A-Za-z0-9_.-]+
819
819
  tag-rest ::= "," tag
820
820
  target ::= "(" path ")"
821
821
  path ::= uri | bare
822
- uri ::= scheme "://" [a-z0-9*.-]+ uri-rest?
822
+ uri ::= scheme "://" [a-z0-9*.-]* uri-rest?
823
823
  scheme ::= [a-z] [a-z0-9+.-]*
824
824
  uri-rest ::= [/?#] [A-Za-z0-9._~!$&'*+,;=:@%?#/\[\]-]*
825
825
  bare ::= [A-Za-z0-9._~!$&'*+,;=@%?#/\[\]-]+
@@ -820,7 +820,7 @@ tag ::= [A-Za-z0-9_.-]+
820
820
  tag-rest ::= "," tag
821
821
  target ::= "(" path ")"
822
822
  path ::= uri | bare
823
- uri ::= scheme "://" [a-z0-9*.-]+ uri-rest?
823
+ uri ::= scheme "://" [a-z0-9*.-]* uri-rest?
824
824
  scheme ::= [a-z] [a-z0-9+.-]*
825
825
  uri-rest ::= [/?#] [A-Za-z0-9._~!$&'*+,;=:@%?#/\[\]-]*
826
826
  bare ::= [A-Za-z0-9._~!$&'*+,;=@%?#/\[\]-]+