Version not found. Please check the version and try again.

@plurnk/plurnk-schemes 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
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,28 @@
1
+ # plurnk-schemes
2
+
3
+ Framework + contract for `@plurnk/plurnk-schemes-*` URI handler packages. Consumed by [plurnk-service](https://github.com/plurnk/plurnk-service).
4
+
5
+ ## Documentation
6
+
7
+ - [`SPEC.md`](./SPEC.md) — author-facing contract.
8
+ - Constellation: [plurnk-grammar](https://github.com/plurnk/plurnk-grammar), [plurnk-mimetypes](https://github.com/plurnk/plurnk-mimetypes), [plurnk-providers](https://github.com/plurnk/plurnk-providers), [plurnk-execs](https://github.com/plurnk/plurnk-execs).
9
+
10
+ ## Exports
11
+
12
+ ### Types
13
+
14
+ `SchemeManifest`, `SchemeFlagAffinity`, `WriterTier`, `LoopFlags`, `DEFAULT_LOOP_FLAGS`.
15
+
16
+ ### Helpers
17
+
18
+ - `resolveForLoop(handlers, flags)` — active-scheme resolution under loop flags.
19
+ - `isBinaryMimetype` / `isLineNavigableMimetype` / `isJsonMimetype` / `normalizeAutoTextMimetype` / `TEXT_PRIMITIVE_MIMETYPE` — mimetype classification.
20
+ - `sliceLines` / `sliceLinesRaw` / `sliceJsonItems` / `applyLineMarkerEdit` / `applyJsonItemEdit` — `<L>` slicing + structural EDIT.
21
+ - `resolveEntryMimetype(pathname, default, mimetypes)` — path-extension mimetype resolver.
22
+ - `matchAgainstContent(body, content, mimetype, mimetypes, baseLine?)` — body-matcher dispatch adapter over `Mimetypes.query`.
23
+
24
+ DB-coupled helpers (CRUD primitives, entry-op handlers, channel writes, subscription registry) stay in plurnk-service; this repo ships only types and pure helpers. Forward-spec: a namespaced ctx API replaces the v0 split when third-party schemes are an actual concern.
25
+
26
+ ## Tests
27
+
28
+ `test:lint`, `test:unit`.
package/SPEC.md ADDED
@@ -0,0 +1,143 @@
1
+ # plurnk-schemes — Specification
2
+
3
+ Contract for `@plurnk/plurnk-schemes-*` sibling packages. Audience: implementer of a URI scheme handler. Consumer: [plurnk-service](https://github.com/plurnk/plurnk-service) (SPEC.md §3).
4
+
5
+ ## §1 Manifest
6
+
7
+ ```json
8
+ {
9
+ "name": "@plurnk/plurnk-schemes-<name>",
10
+ "plurnk": { "kind": "scheme", "name": "<scheme name>" }
11
+ }
12
+ ```
13
+
14
+ Class-level manifest (static field on the default export):
15
+
16
+ ```ts
17
+ import type { SchemeManifest } from "@plurnk/plurnk-schemes";
18
+
19
+ class Known {
20
+ static manifest: SchemeManifest = {
21
+ name: "known",
22
+ channels: { body: "text/markdown", preview: "text/markdown" },
23
+ defaultChannel: "body",
24
+ category: "data",
25
+ scope: "session",
26
+ writableBy: ["model", "client"],
27
+ volatile: false,
28
+ modelVisible: true,
29
+ flags: { /* optional SchemeFlagAffinity */ },
30
+ };
31
+ }
32
+ ```
33
+
34
+ | Field | Constraint |
35
+ |---|---|
36
+ | `name` | Matches `package.json#plurnk.name`. |
37
+ | `channels` | `Record<channelName, mimetype>`. Channel names lowercase. Empty = dynamic per-call. |
38
+ | `defaultChannel` | Channel name targeted when path has no `#fragment`. Empty when channels is empty. |
39
+ | `category` | `"data"` \| `"logging"`. |
40
+ | `scope` | `"agent"` \| `"session"`. |
41
+ | `writableBy` | Subset of `["model", "client", "system", "plugin"]`. Consumer returns 403 for outside-set writes. |
42
+ | `volatile` | Boolean. |
43
+ | `modelVisible` | Boolean. |
44
+ | `flags?` | Optional `SchemeFlagAffinity`. |
45
+
46
+ ## §2 Interface
47
+
48
+ Sister scheme handlers implement op methods consumed by plurnk-service via dispatch. The expected method shape (per consumer-side §3 of plurnk-service's SPEC):
49
+
50
+ ```ts
51
+ interface PlurnkScheme {
52
+ // CRUD primitives — REQUIRED for entry-bearing schemes.
53
+ readEntry(pathname, ctx): Promise<ReadEntryResult>;
54
+ writeEntry(pathname, entry, ctx): Promise<WriteEntryResult>;
55
+ deleteEntry(pathname, ctx): Promise<DeleteEntryResult>;
56
+
57
+ // Op handlers — OPTIONAL. Absent op = 501.
58
+ edit?(statement, ctx): Promise<EditResult>;
59
+ read?(statement, ctx): Promise<ReadResult>;
60
+ show?(statement, ctx): Promise<ShowHideResult>;
61
+ hide?(statement, ctx): Promise<ShowHideResult>;
62
+ find?(statement, ctx): Promise<FindResult>;
63
+ send?(statement, ctx): Promise<SendResult>;
64
+ exec?(statement, ctx): Promise<ExecResult>;
65
+
66
+ // Proposal lifecycle — OPTIONAL.
67
+ onProposalAccepted?(pathname, proposal, ctx): Promise<OpResult>;
68
+ onProposalRejected?(pathname, proposal, ctx): Promise<void>;
69
+ }
70
+ ```
71
+
72
+ Default export: a class implementing the shape with `static manifest: SchemeManifest`.
73
+
74
+ Result-type definitions (`EditResult`, `ReadResult`, etc.) live in plurnk-service v0 alongside the helpers that produce them. Forward-spec: these migrate to this repo when the namespaced ctx API lands.
75
+
76
+ ## §3 Helpers exported by this repo
77
+
78
+ ### Types
79
+
80
+ - `SchemeManifest`, `SchemeFlagAffinity`, `WriterTier`, `LoopFlags`, `DEFAULT_LOOP_FLAGS`.
81
+
82
+ ### Active-scheme resolution
83
+
84
+ - `resolveForLoop(handlers: Map<string, object>, flags: LoopFlags): Set<string>` — applies `manifest.flags` affinity to each handler and returns names of schemes active under the loop's flags.
85
+
86
+ ### Mimetype classification
87
+
88
+ - `isBinaryMimetype(mimetype)` — enforces 415 boundary on binary entries (text/* is text; application/{json,yaml,toml,xml,javascript,typescript,sql} is text; `+json`/`+xml`/`+yaml` suffix variants are text; everything else with a slash is binary).
89
+ - `isJsonMimetype(mimetype)` — `application/json` plus `+json` variants. Used by `<L>` dispatch.
90
+ - `isLineNavigableMimetype(mimetype)` — render-layer decides whether to prefix lines with `N:\t`.
91
+ - `normalizeAutoTextMimetype(mimetype)` — `text/plain` / null / undefined → `TEXT_PRIMITIVE_MIMETYPE` (`text/markdown`).
92
+ - `TEXT_PRIMITIVE_MIMETYPE` — `"text/markdown"`.
93
+
94
+ ### `<L>` slicing
95
+
96
+ - `sliceLines(content, marker)` — line-navigable slice. Returns `{ status, text?, startLine?, error? }`.
97
+ - `sliceLinesRaw(content, marker)` — same shape; no `N:\t` prefix.
98
+ - `sliceJsonItems(content, marker)` — JSON-source item slice. Returns `{ status, body?, error? }`.
99
+ - `applyLineMarkerEdit(content, marker, body)` — line-navigable EDIT.
100
+ - `applyJsonItemEdit(content, marker, body)` — structural JSON EDIT.
101
+
102
+ ### Path-extension mimetype
103
+
104
+ - `resolveEntryMimetype(pathname, defaultMimetype, mimetypes)` — pathname extension → `Mimetypes.detect({ ext })`; falls back to `defaultMimetype` when no extension. text/plain auto-normalizes to text/markdown.
105
+
106
+ ### Matcher dispatch
107
+
108
+ - `matchAgainstContent(body, content, mimetype, mimetypes, baseLine?)` — body-matcher adapter over `Mimetypes.query`. Maps framework errors:
109
+ - `UnsupportedDialectError` → status 415
110
+ - `InvalidExpressionError` → status 400
111
+ - `QueryParseFailureError` → status 203 (soft fallback: raw content as text/markdown with `reason`)
112
+ - Empty match array → status 204
113
+ - Match array → status 200
114
+
115
+ ## §4 What's NOT in this repo
116
+
117
+ DB-coupled helpers stay in plurnk-service for v0:
118
+
119
+ - `_entry-ops.ts` (read/edit/show/hide session entries)
120
+ - `_entry-crud.ts` (CRUD primitives + write-time tokenization helper)
121
+ - `_entry-send.ts` (SEND[410]/[499] dispatcher)
122
+ - `_entry-find.ts` (pathname-glob FIND)
123
+ - `ChannelWrite.ts` (channel append + subscription registry)
124
+ - `PlurnkSchemeContext` (per-call helper with DB handle)
125
+
126
+ These migrate when the v1 namespaced ctx API lands (entries / channels / visibility / tags / subscriptions / proposals / crossScheme / notify). v0 scope: types + pure helpers only.
127
+
128
+ ## §5 Forbidden (for third-party schemes)
129
+
130
+ | ❌ |
131
+ |---|
132
+ | Imports from `@plurnk/plurnk-service/*` |
133
+ | Direct database access |
134
+ | Writes outside the scheme's own namespace |
135
+ | Direct invocation of peer schemes |
136
+ | Mutating `ctx` |
137
+ | Holding `ctx` references past the op handler's return |
138
+ | Reading or writing `log_entries` directly |
139
+ | Calling consumer-internal methods |
140
+ | Writing to `console`, stdout, stderr |
141
+ | Spawning subprocesses (unless the scheme is specifically a subprocess scheme) |
142
+ | Opening network connections (unless specifically a network scheme) |
143
+ | Caching across op invocations (state in instance fields beyond config) |
@@ -0,0 +1,10 @@
1
+ export type { LoopFlags, SchemeFlagAffinity, SchemeManifest, WriterTier, } from "./types.ts";
2
+ export { DEFAULT_LOOP_FLAGS } from "./types.ts";
3
+ export { resolveForLoop } from "./resolveForLoop.ts";
4
+ export { isBinaryMimetype, isJsonMimetype, isLineNavigableMimetype, normalizeAutoTextMimetype, TEXT_PRIMITIVE_MIMETYPE, } from "./mimetype-binary.ts";
5
+ export { applyJsonItemEdit, applyLineMarkerEdit, sliceJsonItems, sliceLines, sliceLinesRaw, } from "./line-marker.ts";
6
+ export type { EditResult as LineEditResult, JsonSliceResult, SliceResult } from "./line-marker.ts";
7
+ export { resolveEntryMimetype } from "./path-mimetype.ts";
8
+ export { matchAgainstContent } from "./matcher.ts";
9
+ export type { MatchResult } from "./matcher.ts";
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACR,SAAS,EACT,kBAAkB,EAClB,cAAc,EACd,UAAU,GACb,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEhD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,OAAO,EACH,gBAAgB,EAChB,cAAc,EACd,uBAAuB,EACvB,yBAAyB,EACzB,uBAAuB,GAC1B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACH,iBAAiB,EACjB,mBAAmB,EACnB,cAAc,EACd,UAAU,EACV,aAAa,GAChB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,UAAU,IAAI,cAAc,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEnG,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ export { DEFAULT_LOOP_FLAGS } from "./types.js";
2
+ export { resolveForLoop } from "./resolveForLoop.js";
3
+ export { isBinaryMimetype, isJsonMimetype, isLineNavigableMimetype, normalizeAutoTextMimetype, TEXT_PRIMITIVE_MIMETYPE, } from "./mimetype-binary.js";
4
+ export { applyJsonItemEdit, applyLineMarkerEdit, sliceJsonItems, sliceLines, sliceLinesRaw, } from "./line-marker.js";
5
+ export { resolveEntryMimetype } from "./path-mimetype.js";
6
+ export { matchAgainstContent } from "./matcher.js";
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEhD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,OAAO,EACH,gBAAgB,EAChB,cAAc,EACd,uBAAuB,EACvB,yBAAyB,EACzB,uBAAuB,GAC1B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACH,iBAAiB,EACjB,mBAAmB,EACnB,cAAc,EACd,UAAU,EACV,aAAa,GAChB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,23 @@
1
+ import type { LineMarker } from "@plurnk/plurnk-grammar";
2
+ export interface SliceResult {
3
+ status: number;
4
+ text?: string;
5
+ startLine?: number;
6
+ error?: string;
7
+ }
8
+ export declare const sliceLines: (content: string, marker: LineMarker) => SliceResult;
9
+ export interface JsonSliceResult {
10
+ status: number;
11
+ body?: string;
12
+ error?: string;
13
+ }
14
+ export declare const sliceJsonItems: (content: string, marker: LineMarker) => JsonSliceResult;
15
+ export declare const applyJsonItemEdit: (content: string, marker: LineMarker, body: string) => EditResult;
16
+ export declare const sliceLinesRaw: (content: string, marker: LineMarker) => SliceResult;
17
+ export interface EditResult {
18
+ status: number;
19
+ result?: string;
20
+ error?: string;
21
+ }
22
+ export declare const applyLineMarkerEdit: (content: string, marker: LineMarker, body: string) => EditResult;
23
+ //# sourceMappingURL=line-marker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"line-marker.d.ts","sourceRoot":"","sources":["../src/line-marker.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAkCzD,MAAM,WAAW,WAAW;IAAG,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE;AAWlG,eAAO,MAAM,UAAU,GAAI,SAAS,MAAM,EAAE,QAAQ,UAAU,KAAG,WAOhE,CAAC;AAyBF,MAAM,WAAW,eAAe;IAAG,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE;AAElF,eAAO,MAAM,cAAc,GAAI,SAAS,MAAM,EAAE,QAAQ,UAAU,KAAG,eAoBpE,CAAC;AA6GF,eAAO,MAAM,iBAAiB,GAAI,SAAS,MAAM,EAAE,QAAQ,UAAU,EAAE,MAAM,MAAM,KAAG,UAerF,CAAC;AAOF,eAAO,MAAM,aAAa,GAAI,SAAS,MAAM,EAAE,QAAQ,UAAU,KAAG,WAQnE,CAAC;AAEF,MAAM,WAAW,UAAU;IAAG,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE;AAS/E,eAAO,MAAM,mBAAmB,GAAI,SAAS,MAAM,EAAE,QAAQ,UAAU,EAAE,MAAM,MAAM,KAAG,UAiBvF,CAAC"}
@@ -0,0 +1,321 @@
1
+ // `<L>` line-marker semantics (plurnk.md §`<L>`):
2
+ //
3
+ // <N> selects position N (1-indexed)
4
+ // <N,M> selects positions N..M inclusive
5
+ // <0> sentinel: before position 1 (EDIT prepend)
6
+ // <-1> sentinel: after the last position (EDIT append)
7
+ // <1,-1> every position (in range context, -1 normalizes to last line)
8
+ //
9
+ // "N and M are signed integers" — but plurnk.md only documents <0> and
10
+ // <-1> as defined sentinels. Other negatives (<-2>, <-3>) are not
11
+ // specified and rejected as 416. Within a range, -1 as the M endpoint
12
+ // means "include through the last line" (so <1,-1> is whole content).
13
+ const splitLines = (content) => {
14
+ const trailingNewline = content.endsWith("\n");
15
+ if (content === "")
16
+ return { lines: [], trailingNewline: false };
17
+ const lines = content.split("\n");
18
+ if (trailingNewline)
19
+ lines.pop();
20
+ return { lines, trailingNewline };
21
+ };
22
+ const normalize = (marker, totalLines) => {
23
+ const { first, last } = marker;
24
+ if (last === null) {
25
+ if (first === 0)
26
+ return { kind: "before-first", start: 0, end: 0 };
27
+ if (first === -1)
28
+ return { kind: "after-last", start: 0, end: 0 };
29
+ if (first > 0 && first <= totalLines)
30
+ return { kind: "range", start: first, end: first };
31
+ return { error: `line ${first} out of range (1..${totalLines})` };
32
+ }
33
+ let n = first;
34
+ let m = last;
35
+ if (n === 0)
36
+ n = 1;
37
+ if (m === -1)
38
+ m = totalLines;
39
+ if (n < 1 || n > totalLines)
40
+ return { error: `range start ${first} out of range (1..${totalLines})` };
41
+ if (m < 1 || m > totalLines)
42
+ return { error: `range end ${last} out of range (1..${totalLines})` };
43
+ if (n > m)
44
+ return { error: `range start ${first} > end ${last}` };
45
+ return { kind: "range", start: n, end: m };
46
+ };
47
+ // READ a line range. Returns the raw selected lines (no `N:\t` prefix)
48
+ // plus the 1-indexed position of the first selected line. The render
49
+ // layer adds `N:\t` per plurnk.md ("READ output prefixes every line with
50
+ // line numbers, N:\t") starting from `startLine` — keeps numbering as a
51
+ // presentation concern, prevents double-prefixing when the same content
52
+ // passes through the log render.
53
+ //
54
+ // Sentinel positions <0> and <-1> select no content (they're insertion
55
+ // points, not lines) → status 200 with empty text.
56
+ export const sliceLines = (content, marker) => {
57
+ const { lines } = splitLines(content);
58
+ const norm = normalize(marker, lines.length);
59
+ if ("error" in norm)
60
+ return { status: 416, error: norm.error };
61
+ if (norm.kind !== "range")
62
+ return { status: 200, text: "", startLine: undefined };
63
+ const selected = lines.slice(norm.start - 1, norm.end);
64
+ return { status: 200, text: selected.join("\n"), startLine: norm.start };
65
+ };
66
+ // Structural `<L>` slice for JSON sources (plurnk-grammar 0.13.0).
67
+ // "On structured entries, <L> addresses item index, not line number."
68
+ // Every JSON value becomes a list of top-level items:
69
+ // array `[a, b, c]` → items are the array elements
70
+ // object `{k1: v1, ...}` → items are key-value pairs (as single-key objects)
71
+ // scalar `"hello"` / 42 → item is the scalar itself (length-1 list)
72
+ // `<L>` indexes into that list (1-indexed). Result is always a JSON array.
73
+ // Sentinels `<0>` / `<-1>` are insertion points — empty `[]` for READ.
74
+ // Out-of-range positions return 416. Matches the uniform "always JSON
75
+ // array out" shape we settled for matcher results.
76
+ const jsonValueToItems = (parsed) => {
77
+ if (Array.isArray(parsed))
78
+ return parsed;
79
+ if (parsed !== null && typeof parsed === "object") {
80
+ // Object items are single-key {key: value} wrappers, in insertion
81
+ // order. Object.entries preserves spec-guaranteed iteration order
82
+ // for string keys.
83
+ return Object.entries(parsed).map(([k, v]) => ({ [k]: v }));
84
+ }
85
+ // Scalar (string, number, boolean, null): a length-1 list of itself.
86
+ return [parsed];
87
+ };
88
+ export const sliceJsonItems = (content, marker) => {
89
+ let parsed;
90
+ try {
91
+ parsed = JSON.parse(content);
92
+ }
93
+ catch (err) {
94
+ return { status: 400, error: `malformed JSON: ${err instanceof Error ? err.message : String(err)}` };
95
+ }
96
+ const items = jsonValueToItems(parsed);
97
+ const total = items.length;
98
+ const { first, last } = marker;
99
+ if (last === null) {
100
+ if (first === 0 || first === -1)
101
+ return { status: 200, body: "[]" };
102
+ if (first > 0 && first <= total)
103
+ return { status: 200, body: JSON.stringify([items[first - 1]], null, 2) };
104
+ return { status: 416, error: `item ${first} out of range (1..${total})` };
105
+ }
106
+ let n = first;
107
+ let m = last;
108
+ if (n === 0)
109
+ n = 1;
110
+ if (m === -1)
111
+ m = total;
112
+ if (n < 1 || n > total)
113
+ return { status: 416, error: `range start ${first} out of range (1..${total})` };
114
+ if (m < 1 || m > total)
115
+ return { status: 416, error: `range end ${last} out of range (1..${total})` };
116
+ if (n > m)
117
+ return { status: 416, error: `range start ${first} > end ${last}` };
118
+ return { status: 200, body: JSON.stringify(items.slice(n - 1, m), null, 2) };
119
+ };
120
+ // Structural `<L>` EDIT for JSON sources (plurnk-grammar 0.13.0/0.14.0).
121
+ // Source-shape rules (matches sliceJsonItems' item definition):
122
+ // array → items are elements
123
+ // object → items are key-value pairs (single-key fragments)
124
+ // scalar → length-1 list of itself; grow markers (<0>,<-1>) reject
125
+ //
126
+ // Body shape (Resolution B):
127
+ // body parses as JSON array → those are the items to splice in
128
+ // body parses as non-array JSON → single item to splice in
129
+ // empty body → delete the selection
130
+ // body fails JSON parse → 400 (path-extension declares intent; honor it)
131
+ //
132
+ // Marker semantics (parallel to line-EDIT):
133
+ // <N> replace item N with body item(s)
134
+ // <N,M> replace items N..M with body item(s)
135
+ // <0> prepend body item(s)
136
+ // <-1> append body item(s)
137
+ // <1,-1> replace whole top-level with body item(s); empty body clears
138
+ // Empty body on a sentinel insertion (<0> or <-1>) → no-op.
139
+ const itemsFromBody = (body) => {
140
+ if (body === "")
141
+ return { items: [] }; // empty body = delete
142
+ let parsed;
143
+ try {
144
+ parsed = JSON.parse(body);
145
+ }
146
+ catch (err) {
147
+ return { error: `malformed JSON body: ${err instanceof Error ? err.message : String(err)}` };
148
+ }
149
+ if (Array.isArray(parsed))
150
+ return { items: parsed };
151
+ return { items: [parsed] };
152
+ };
153
+ const applyJsonArrayEdit = (source, marker, items) => {
154
+ const total = source.length;
155
+ const { first, last } = marker;
156
+ let result;
157
+ if (last === null) {
158
+ if (first === 0)
159
+ result = [...items, ...source];
160
+ else if (first === -1)
161
+ result = [...source, ...items];
162
+ else if (first > 0 && first <= total)
163
+ result = [...source.slice(0, first - 1), ...items, ...source.slice(first)];
164
+ else
165
+ return { status: 416, error: `position ${first} out of range (1..${total})` };
166
+ }
167
+ else {
168
+ let n = first;
169
+ let m = last;
170
+ if (n === 0)
171
+ n = 1;
172
+ if (m === -1)
173
+ m = total;
174
+ if (total === 0 && (first !== 1 || last !== -1))
175
+ return { status: 416, error: `range on empty array` };
176
+ if (n < 1 || (total > 0 && n > total))
177
+ return { status: 416, error: `range start ${first} out of range (1..${total})` };
178
+ if (m < 1 || (total > 0 && m > total))
179
+ return { status: 416, error: `range end ${last} out of range (1..${total})` };
180
+ if (n > m)
181
+ return { status: 416, error: `range start ${first} > end ${last}` };
182
+ result = [...source.slice(0, n - 1), ...items, ...source.slice(m)];
183
+ }
184
+ return { status: 200, result: JSON.stringify(result, null, 2) };
185
+ };
186
+ const applyJsonObjectEdit = (source, marker, items) => {
187
+ // Object items are key-value pairs. Body items must be objects;
188
+ // each object's entries become kv-pairs to splice in. Items that
189
+ // aren't single objects → 400 (model used wrong body shape for an
190
+ // object source).
191
+ const bodyEntries = [];
192
+ for (const item of items) {
193
+ if (item === null || typeof item !== "object" || Array.isArray(item)) {
194
+ return { status: 400, error: "object source requires body items to be JSON objects (key-value pairs)" };
195
+ }
196
+ bodyEntries.push(...Object.entries(item));
197
+ }
198
+ const entries = Object.entries(source);
199
+ const total = entries.length;
200
+ const { first, last } = marker;
201
+ let result;
202
+ if (last === null) {
203
+ if (first === 0)
204
+ result = [...bodyEntries, ...entries];
205
+ else if (first === -1)
206
+ result = [...entries, ...bodyEntries];
207
+ else if (first > 0 && first <= total)
208
+ result = [...entries.slice(0, first - 1), ...bodyEntries, ...entries.slice(first)];
209
+ else
210
+ return { status: 416, error: `position ${first} out of range (1..${total})` };
211
+ }
212
+ else {
213
+ let n = first;
214
+ let m = last;
215
+ if (n === 0)
216
+ n = 1;
217
+ if (m === -1)
218
+ m = total;
219
+ if (total === 0 && (first !== 1 || last !== -1))
220
+ return { status: 416, error: `range on empty object` };
221
+ if (n < 1 || (total > 0 && n > total))
222
+ return { status: 416, error: `range start ${first} out of range (1..${total})` };
223
+ if (m < 1 || (total > 0 && m > total))
224
+ return { status: 416, error: `range end ${last} out of range (1..${total})` };
225
+ if (n > m)
226
+ return { status: 416, error: `range start ${first} > end ${last}` };
227
+ result = [...entries.slice(0, n - 1), ...bodyEntries, ...entries.slice(m)];
228
+ }
229
+ return { status: 200, result: JSON.stringify(Object.fromEntries(result), null, 2) };
230
+ };
231
+ const applyJsonScalarEdit = (source, marker, items) => {
232
+ // Scalar source is a length-1 list of itself. Only `<1>` replace
233
+ // works cleanly; grow markers (<0>,<-1>) and ranges that imply
234
+ // growth/delete would require type promotion (scalar → array),
235
+ // which is the kind of implicit magic that bites later. Reject.
236
+ const { first, last } = marker;
237
+ if (last === null && first === 1) {
238
+ if (items.length === 0)
239
+ return { status: 200, result: "null" }; // delete the scalar
240
+ if (items.length === 1)
241
+ return { status: 200, result: JSON.stringify(items[0], null, 2) };
242
+ return { status: 400, error: "scalar source: <1> body must produce 0 or 1 items (no implicit promotion to array)" };
243
+ }
244
+ if (last === -1 && first === 1) {
245
+ // <1,-1> = whole content. Same constraints as <1> for scalars.
246
+ if (items.length === 0)
247
+ return { status: 200, result: "null" };
248
+ if (items.length === 1)
249
+ return { status: 200, result: JSON.stringify(items[0], null, 2) };
250
+ return { status: 400, error: "scalar source: <1,-1> body must produce 0 or 1 items (no implicit promotion to array)" };
251
+ }
252
+ return { status: 400, error: "scalar JSON source: only <1> or <1,-1> markers supported (no implicit promotion to array via grow markers)" };
253
+ };
254
+ export const applyJsonItemEdit = (content, marker, body) => {
255
+ let parsed;
256
+ try {
257
+ parsed = JSON.parse(content);
258
+ }
259
+ catch (err) {
260
+ return { status: 400, error: `malformed JSON source: ${err instanceof Error ? err.message : String(err)}` };
261
+ }
262
+ const bodyResult = itemsFromBody(body);
263
+ if ("error" in bodyResult)
264
+ return { status: 400, error: bodyResult.error };
265
+ const items = bodyResult.items;
266
+ // Empty-body sentinel insertion is a no-op (model accidentally
267
+ // emitted no items at an insertion point).
268
+ if (items.length === 0 && marker.last === null && (marker.first === 0 || marker.first === -1)) {
269
+ return { status: 200, result: content };
270
+ }
271
+ if (Array.isArray(parsed))
272
+ return applyJsonArrayEdit(parsed, marker, items);
273
+ if (parsed !== null && typeof parsed === "object")
274
+ return applyJsonObjectEdit(parsed, marker, items);
275
+ return applyJsonScalarEdit(parsed, marker, items);
276
+ };
277
+ // COPY-style raw line slice. Returns the selected lines verbatim (no line-
278
+ // number prefix), trailing newline appended if any lines were selected.
279
+ // Used for COPY/MOVE `<L>` per SPEC.md §16.9 (source range, symmetric
280
+ // with READ but without the READ-output prefix that's a render concern,
281
+ // not a data concern).
282
+ export const sliceLinesRaw = (content, marker) => {
283
+ const { lines } = splitLines(content);
284
+ const norm = normalize(marker, lines.length);
285
+ if ("error" in norm)
286
+ return { status: 416, error: norm.error };
287
+ if (norm.kind !== "range")
288
+ return { status: 200, text: "" };
289
+ const selected = lines.slice(norm.start - 1, norm.end);
290
+ const result = selected.length > 0 ? `${selected.join("\n")}\n` : "";
291
+ return { status: 200, text: result };
292
+ };
293
+ // EDIT applies body at the marker position:
294
+ // <0> prepend body before line 1
295
+ // <-1> append body after the last line
296
+ // <N> replace line N with body
297
+ // <N,M> replace lines N..M with body
298
+ // <1,-1> whole content (replace everything); empty body clears.
299
+ // Empty body with <N>/<N,M> deletes those lines.
300
+ export const applyLineMarkerEdit = (content, marker, body) => {
301
+ const { lines, trailingNewline } = splitLines(content);
302
+ const norm = normalize(marker, lines.length);
303
+ if ("error" in norm)
304
+ return { status: 416, error: norm.error };
305
+ const bodyLines = splitLines(body).lines;
306
+ let newLines;
307
+ if (norm.kind === "before-first") {
308
+ newLines = [...bodyLines, ...lines];
309
+ }
310
+ else if (norm.kind === "after-last") {
311
+ newLines = [...lines, ...bodyLines];
312
+ }
313
+ else {
314
+ newLines = [...lines.slice(0, norm.start - 1), ...bodyLines, ...lines.slice(norm.end)];
315
+ }
316
+ let result = newLines.join("\n");
317
+ if (newLines.length > 0 && trailingNewline)
318
+ result += "\n";
319
+ return { status: 200, result };
320
+ };
321
+ //# sourceMappingURL=line-marker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"line-marker.js","sourceRoot":"","sources":["../src/line-marker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { MatcherBody } from "@plurnk/plurnk-grammar";
2
+ import type { Mimetypes } from "@plurnk/plurnk-mimetypes";
3
+ export interface MatchResult {
4
+ status: number;
5
+ body?: string;
6
+ matches?: number;
7
+ error?: string;
8
+ mimetype?: string;
9
+ reason?: string;
10
+ }
11
+ export declare const matchAgainstContent: (body: MatcherBody, content: string, mimetype: string, mimetypes: Mimetypes, baseLine?: number) => Promise<MatchResult>;
12
+ //# sourceMappingURL=matcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"matcher.d.ts","sourceRoot":"","sources":["../src/matcher.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAc,MAAM,0BAA0B,CAAC;AAQtE,MAAM,WAAW,WAAW;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAcD,eAAO,MAAM,mBAAmB,GAC5B,MAAM,WAAW,EACjB,SAAS,MAAM,EACf,UAAU,MAAM,EAChB,WAAW,SAAS,EACpB,WAAU,MAAU,KACrB,OAAO,CAAC,WAAW,CA2CrB,CAAC"}
@@ -0,0 +1,77 @@
1
+ // Body-matcher adapter — delegates to @plurnk/plurnk-mimetypes for the
2
+ // actual dialect dispatch. The framework parses the matcher's leading
3
+ // prefix internally (xpath `//`, jsonpath `$`, regex `/.../`, glob
4
+ // otherwise) and routes to per-mimetype handlers. plurnk-service catches
5
+ // the framework's typed errors and maps them to HTTP-shaped status codes
6
+ // the model can act on.
7
+ //
8
+ // Status mapping (per plurnk-service#172 + plurnk-grammar#19):
9
+ // UnsupportedDialectError → 415 (dialect not supported for mimetype, or binary content)
10
+ // InvalidExpressionError → 400 (model authored a malformed matcher body)
11
+ // QueryParseFailureError → 203 (source can't be parsed for the dialect;
12
+ // returns raw content as text/markdown with
13
+ // `reason` so the model can fall back to
14
+ // regex/visual parsing on the bytes)
15
+ // Empty match array → 204 (matcher applied, zero results)
16
+ // Match array → 200 (matcher applied, results in body)
17
+ //
18
+ // 203 is HTTP-creative ("Non-Authoritative Information") — the runtime
19
+ // produced content but not in the structured form the matcher requested.
20
+ // Model sees the raw text plus a reason field and decides whether to
21
+ // retry, fall back, or fix source. Choice ratified by user (#172).
22
+ import { UnsupportedDialectError, InvalidExpressionError, QueryParseFailureError, } from "@plurnk/plurnk-mimetypes";
23
+ import { TEXT_PRIMITIVE_MIMETYPE } from "./mimetype-binary.js";
24
+ const prettyJson = (value) => JSON.stringify(value, null, 2);
25
+ // Apply a `<L>`-slice baseLine offset to per-match line numbers. The
26
+ // framework returns line numbers relative to the content it received;
27
+ // when the matcher runs inside an `<L>` slice, those need to be shifted
28
+ // back to original-source coordinates.
29
+ const shiftLines = (matches, baseLine) => {
30
+ if (baseLine === 1)
31
+ return [...matches];
32
+ const offset = baseLine - 1;
33
+ return matches.map((m) => ({ ...m, line: m.line + offset }));
34
+ };
35
+ export const matchAgainstContent = async (body, content, mimetype, mimetypes, baseLine = 1) => {
36
+ try {
37
+ // Framework dispatches dialect by leading prefix of `body.raw`.
38
+ // `hint` carries the source mimetype so the framework selects the
39
+ // right per-mimetype handler without re-detecting from content.
40
+ const rawMatches = await mimetypes.query({ content, hint: mimetype }, body.raw);
41
+ if (rawMatches.length === 0) {
42
+ return { status: 204, matches: 0 };
43
+ }
44
+ const adjusted = shiftLines(rawMatches, baseLine);
45
+ return {
46
+ status: 200,
47
+ body: prettyJson(adjusted),
48
+ matches: adjusted.length,
49
+ };
50
+ }
51
+ catch (err) {
52
+ // Name-based dispatch tolerates dup-copy node_modules layouts where
53
+ // `instanceof` against the framework's exported classes can fail
54
+ // because the consumer loads a different physical copy. The framework
55
+ // sets each error subclass's `.name` to its class name.
56
+ const name = err instanceof Error ? err.name : "";
57
+ if (name === "UnsupportedDialectError" || err instanceof UnsupportedDialectError) {
58
+ return { status: 415, error: err instanceof Error ? err.message : String(err) };
59
+ }
60
+ if (name === "InvalidExpressionError" || err instanceof InvalidExpressionError) {
61
+ return { status: 400, error: err instanceof Error ? err.message : String(err) };
62
+ }
63
+ if (name === "QueryParseFailureError" || err instanceof QueryParseFailureError) {
64
+ // 203 soft fallback: return raw content as text so the model
65
+ // can fall back to regex/visual parsing or fix the source.
66
+ return {
67
+ status: 203,
68
+ body: content,
69
+ mimetype: TEXT_PRIMITIVE_MIMETYPE,
70
+ reason: err instanceof Error ? err.message : String(err),
71
+ };
72
+ }
73
+ // Unexpected — let it propagate so the engine logs it as a 500.
74
+ throw err;
75
+ }
76
+ };
77
+ //# sourceMappingURL=matcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"matcher.js","sourceRoot":"","sources":["../src/matcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export declare const isBinaryMimetype: (mimetype: string) => boolean;
2
+ export declare const isJsonMimetype: (mimetype: string) => boolean;
3
+ export declare const isLineNavigableMimetype: (mimetype: string) => boolean;
4
+ export declare const TEXT_PRIMITIVE_MIMETYPE = "text/markdown";
5
+ export declare const normalizeAutoTextMimetype: (mimetype: string | null | undefined) => string;
6
+ //# sourceMappingURL=mimetype-binary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mimetype-binary.d.ts","sourceRoot":"","sources":["../src/mimetype-binary.ts"],"names":[],"mappings":"AAiCA,eAAO,MAAM,gBAAgB,GAAI,UAAU,MAAM,KAAG,OASnD,CAAC;AAKF,eAAO,MAAM,cAAc,GAAI,UAAU,MAAM,KAAG,OACe,CAAC;AAElE,eAAO,MAAM,uBAAuB,GAAI,UAAU,MAAM,KAAG,OAS1D,CAAC;AAaF,eAAO,MAAM,uBAAuB,kBAAkB,CAAC;AAEvD,eAAO,MAAM,yBAAyB,GAAI,UAAU,MAAM,GAAG,IAAI,GAAG,SAAS,KAAG,MAK/E,CAAC"}
@@ -0,0 +1,82 @@
1
+ // Mimetype classifiers used at op-handler boundaries.
2
+ //
3
+ // `isBinaryMimetype` — enforces 415 on binary entries for READ/EDIT/
4
+ // SHOW/HIDE (SPEC.md §16.9 — binary entries → 415).
5
+ //
6
+ // `isLineNavigableMimetype` — decides whether the render layer prefixes
7
+ // each line with `N:\t` on READ output. Line-oriented mimetypes (text,
8
+ // markdown, source code, line-aligned configs) get `N:\t`. Tree-oriented
9
+ // mimetypes (JSON, XML, HTML) don't — line numbers would conflict with
10
+ // the structural navigation those formats use (jsonpath, xpath).
11
+ //
12
+ // Local heuristic until @plurnk/plurnk-mimetypes exposes per-mimetype
13
+ // metadata via its public API (HandlerInfo flags exist at registry
14
+ // level; not queryable per-mimetype yet — see plurnk-mimetypes#3).
15
+ const TEXT_APPLICATION_MIMETYPES = new Set([
16
+ "application/json",
17
+ "application/yaml",
18
+ "application/toml",
19
+ "application/xml",
20
+ "application/javascript",
21
+ "application/typescript",
22
+ "application/sql",
23
+ ]);
24
+ // Mimetypes that are structurally tree-navigated rather than line-
25
+ // navigated. READ output of these doesn't get `N:\t` prefixes.
26
+ const TREE_NAVIGABLE_MIMETYPES = new Set([
27
+ "application/json",
28
+ "application/xml",
29
+ "text/html",
30
+ ]);
31
+ export const isBinaryMimetype = (mimetype) => {
32
+ if (mimetype.length === 0)
33
+ return false;
34
+ const slash = mimetype.indexOf("/");
35
+ if (slash === -1)
36
+ return true;
37
+ const type = mimetype.slice(0, slash);
38
+ if (type === "text")
39
+ return false;
40
+ if (TEXT_APPLICATION_MIMETYPES.has(mimetype))
41
+ return false;
42
+ if (mimetype.endsWith("+json") || mimetype.endsWith("+xml") || mimetype.endsWith("+yaml"))
43
+ return false;
44
+ return true;
45
+ };
46
+ // JSON-family check — used by `<L>` dispatch to pick structural slicer
47
+ // (sliceJsonItems) over line slicer (sliceLines) for JSON sources.
48
+ // Matches application/json plus +json suffix variants per RFC 6839.
49
+ export const isJsonMimetype = (mimetype) => mimetype === "application/json" || mimetype.endsWith("+json");
50
+ export const isLineNavigableMimetype = (mimetype) => {
51
+ if (mimetype.length === 0)
52
+ return false;
53
+ if (isBinaryMimetype(mimetype))
54
+ return false;
55
+ if (TREE_NAVIGABLE_MIMETYPES.has(mimetype))
56
+ return false;
57
+ if (mimetype.endsWith("+json") || mimetype.endsWith("+xml"))
58
+ return false;
59
+ // Everything text-ish that isn't tree-shaped is line-navigable.
60
+ // text/plain, text/markdown, text/csv, text/javascript, text/typescript,
61
+ // application/yaml, application/toml, application/javascript, etc.
62
+ return true;
63
+ };
64
+ // Text primitive for the agent contract: text/markdown is the default
65
+ // text mimetype anywhere plurnk-service auto-derives a text result.
66
+ // text/plain is reserved for explicit scheme-manifest declarations
67
+ // (exec subprocess streams) and client-set entries. Rationale: markdown
68
+ // is a strict superset of plain text — any plain text is valid markdown
69
+ // — so the agent gets markdown-aware processing capability for free,
70
+ // and never needs to decide "is this markdown enough to mark as
71
+ // markdown?"
72
+ //
73
+ // Use this at any consumer-side auto-derivation point (file scheme
74
+ // extension fallback, log rx wrap, etc.) to normalize text/plain → text/markdown.
75
+ export const TEXT_PRIMITIVE_MIMETYPE = "text/markdown";
76
+ export const normalizeAutoTextMimetype = (mimetype) => {
77
+ if (mimetype === null || mimetype === undefined || mimetype === "" || mimetype === "text/plain") {
78
+ return TEXT_PRIMITIVE_MIMETYPE;
79
+ }
80
+ return mimetype;
81
+ };
82
+ //# sourceMappingURL=mimetype-binary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mimetype-binary.js","sourceRoot":"","sources":["../src/mimetype-binary.ts"],"names":[],"mappings":"AAAA,sDAAsD;AACtD,EAAE;AACF,qEAAqE;AACrE,oDAAoD;AACpD,EAAE;AACF,wEAAwE;AACxE,uEAAuE;AACvE,yEAAyE;AACzE,uEAAuE;AACvE,iEAAiE;AACjE,EAAE;AACF,sEAAsE;AACtE,mEAAmE;AACnE,mEAAmE;AAEnE,MAAM,0BAA0B,GAAwB,IAAI,GAAG,CAAC;IAC5D,kBAAkB;IAClB,kBAAkB;IAClB,kBAAkB;IAClB,iBAAiB;IACjB,wBAAwB;IACxB,wBAAwB;IACxB,iBAAiB;CACpB,CAAC,CAAC;AAEH,mEAAmE;AACnE,+DAA+D;AAC/D,MAAM,wBAAwB,GAAwB,IAAI,GAAG,CAAC;IAC1D,kBAAkB;IAClB,iBAAiB;IACjB,WAAW;CACd,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,QAAgB,EAAW,EAAE;IAC1D,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACxC,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,KAAK,KAAK,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9B,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACtC,IAAI,IAAI,KAAK,MAAM;QAAE,OAAO,KAAK,CAAC;IAClC,IAAI,0BAA0B,CAAC,GAAG,CAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IAC3D,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC;QAAE,OAAO,KAAK,CAAC;IACxG,OAAO,IAAI,CAAC;AAChB,CAAC,CAAC;AAEF,uEAAuE;AACvE,mEAAmE;AACnE,oEAAoE;AACpE,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,QAAgB,EAAW,EAAE,CACxD,QAAQ,KAAK,kBAAkB,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AAElE,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,QAAgB,EAAW,EAAE;IACjE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACxC,IAAI,gBAAgB,CAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IAC7C,IAAI,wBAAwB,CAAC,GAAG,CAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IACzD,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,KAAK,CAAC;IAC1E,gEAAgE;IAChE,yEAAyE;IACzE,mEAAmE;IACnE,OAAO,IAAI,CAAC;AAChB,CAAC,CAAC;AAEF,sEAAsE;AACtE,oEAAoE;AACpE,mEAAmE;AACnE,wEAAwE;AACxE,wEAAwE;AACxE,qEAAqE;AACrE,gEAAgE;AAChE,aAAa;AACb,EAAE;AACF,mEAAmE;AACnE,kFAAkF;AAClF,MAAM,CAAC,MAAM,uBAAuB,GAAG,eAAe,CAAC;AAEvD,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,QAAmC,EAAU,EAAE;IACrF,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,EAAE,IAAI,QAAQ,KAAK,YAAY,EAAE,CAAC;QAC9F,OAAO,uBAAuB,CAAC;IACnC,CAAC;IACD,OAAO,QAAQ,CAAC;AACpB,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Mimetypes } from "@plurnk/plurnk-mimetypes";
2
+ export declare const resolveEntryMimetype: (pathname: string, schemeDefault: string, mimetypes: Mimetypes | undefined) => Promise<string>;
3
+ //# sourceMappingURL=path-mimetype.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-mimetype.d.ts","sourceRoot":"","sources":["../src/path-mimetype.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAmB1D,eAAO,MAAM,oBAAoB,GAC7B,UAAU,MAAM,EAChB,eAAe,MAAM,EACrB,WAAW,SAAS,GAAG,SAAS,KACjC,OAAO,CAAC,MAAM,CAOhB,CAAC"}
@@ -0,0 +1,47 @@
1
+ // Path-extension mimetype resolver for entry schemes per plurnk-grammar
2
+ // 0.14.0 §Paths: "Path suffix (`.json`, `.md`, `.txt`, etc.) declares
3
+ // mimetype; absent suffix defers to scheme default."
4
+ //
5
+ // Plurnk-service implements this uniformly across entry schemes: a
6
+ // pathname's extension drives the effective mimetype (via the sibling
7
+ // Mimetypes detect service), and the scheme manifest's channel default
8
+ // is the fallback when no extension is present.
9
+ //
10
+ // This makes structural ops (`<L>` item-index, matcher dialect dispatch)
11
+ // fire correctly without content-sniffing: a model writing JSON to
12
+ // `known://users.json` opts into JSON treatment via the `.json` suffix,
13
+ // while `known://notes` (no suffix) stays at Known's default of
14
+ // `text/markdown`.
15
+ //
16
+ // Consistent across:
17
+ // - known://users.json → application/json
18
+ // - known://notes.md → text/markdown
19
+ // - known://config.yaml → application/yaml
20
+ // - known://users → scheme default (text/markdown for Known)
21
+ import { normalizeAutoTextMimetype } from "./mimetype-binary.js";
22
+ // Extract the suffix (everything after the last dot in the last segment)
23
+ // from a pathname. Empty if no dot in the last segment.
24
+ const extractExtension = (pathname) => {
25
+ const lastSlash = pathname.lastIndexOf("/");
26
+ const lastSegment = lastSlash === -1 ? pathname : pathname.slice(lastSlash + 1);
27
+ const lastDot = lastSegment.lastIndexOf(".");
28
+ if (lastDot <= 0)
29
+ return ""; // leading-dot files (".env") aren't an extension
30
+ return lastSegment.slice(lastDot); // includes the leading "."
31
+ };
32
+ // Resolve a pathname → effective mimetype.
33
+ // 1. If the pathname has an extension, query Mimetypes.detect({ ext })
34
+ // and use what comes back (normalized via the text-primitive rule —
35
+ // text/plain → text/markdown).
36
+ // 2. Otherwise (no extension or no Mimetypes service), fall back to
37
+ // `schemeDefault` (typically the scheme manifest's channel default).
38
+ export const resolveEntryMimetype = async (pathname, schemeDefault, mimetypes) => {
39
+ const ext = extractExtension(pathname);
40
+ if (ext.length > 0 && mimetypes !== undefined) {
41
+ const detected = await mimetypes.detect({ ext });
42
+ if (detected !== null)
43
+ return normalizeAutoTextMimetype(detected);
44
+ }
45
+ return schemeDefault;
46
+ };
47
+ //# sourceMappingURL=path-mimetype.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-mimetype.js","sourceRoot":"","sources":["../src/path-mimetype.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,sEAAsE;AACtE,qDAAqD;AACrD,EAAE;AACF,mEAAmE;AACnE,sEAAsE;AACtE,uEAAuE;AACvE,gDAAgD;AAChD,EAAE;AACF,yEAAyE;AACzE,mEAAmE;AACnE,wEAAwE;AACxE,gEAAgE;AAChE,mBAAmB;AACnB,EAAE;AACF,qBAAqB;AACrB,gDAAgD;AAChD,6CAA6C;AAC7C,gDAAgD;AAChD,wEAAwE;AAGxE,OAAO,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AAEjE,yEAAyE;AACzE,wDAAwD;AACxD,MAAM,gBAAgB,GAAG,CAAC,QAAgB,EAAU,EAAE;IAClD,MAAM,SAAS,GAAG,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAC5C,MAAM,WAAW,GAAG,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;IAChF,MAAM,OAAO,GAAG,WAAW,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAC7C,IAAI,OAAO,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC,CAAE,iDAAiD;IAC/E,OAAO,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAE,2BAA2B;AACnE,CAAC,CAAC;AAEF,2CAA2C;AAC3C,uEAAuE;AACvE,uEAAuE;AACvE,kCAAkC;AAClC,oEAAoE;AACpE,wEAAwE;AACxE,MAAM,CAAC,MAAM,oBAAoB,GAAG,KAAK,EACrC,QAAgB,EAChB,aAAqB,EACrB,SAAgC,EACjB,EAAE;IACjB,MAAM,GAAG,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IACvC,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5C,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QACjD,IAAI,QAAQ,KAAK,IAAI;YAAE,OAAO,yBAAyB,CAAC,QAAQ,CAAC,CAAC;IACtE,CAAC;IACD,OAAO,aAAa,CAAC;AACzB,CAAC,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { LoopFlags } from "./types.ts";
2
+ /**
3
+ * Given a map of scheme name → handler instance and the active loop's
4
+ * flags, return the set of scheme names eligible to dispatch.
5
+ *
6
+ * - Schemes without `manifest.flags` are always active.
7
+ * - `excludedInAsk` filters out under `mode === "ask"`.
8
+ * - `requiresWeb` / `requiresInteraction` / `proposes` filter out under
9
+ * the corresponding `no*` flag.
10
+ */
11
+ export declare const resolveForLoop: (handlers: ReadonlyMap<string, object>, flags: LoopFlags) => Set<string>;
12
+ //# sourceMappingURL=resolveForLoop.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolveForLoop.d.ts","sourceRoot":"","sources":["../src/resolveForLoop.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAkB,MAAM,YAAY,CAAC;AAM5D;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,GACvB,UAAU,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,EACrC,OAAO,SAAS,KACjB,GAAG,CAAC,MAAM,CAeZ,CAAC"}
@@ -0,0 +1,32 @@
1
+ // Active-scheme resolution under a given loop's flags. Schemes opt into
2
+ // flag affinity via `manifest.flags`; absence = always active.
3
+ /**
4
+ * Given a map of scheme name → handler instance and the active loop's
5
+ * flags, return the set of scheme names eligible to dispatch.
6
+ *
7
+ * - Schemes without `manifest.flags` are always active.
8
+ * - `excludedInAsk` filters out under `mode === "ask"`.
9
+ * - `requiresWeb` / `requiresInteraction` / `proposes` filter out under
10
+ * the corresponding `no*` flag.
11
+ */
12
+ export const resolveForLoop = (handlers, flags) => {
13
+ const active = new Set();
14
+ for (const [name, handler] of handlers.entries()) {
15
+ const affinity = handler.constructor.manifest?.flags;
16
+ if (affinity === undefined) {
17
+ active.add(name);
18
+ continue;
19
+ }
20
+ if (flags.mode === "ask" && affinity.excludedInAsk)
21
+ continue;
22
+ if (flags.noWeb && affinity.requiresWeb)
23
+ continue;
24
+ if (flags.noInteraction && affinity.requiresInteraction)
25
+ continue;
26
+ if (flags.noProposals && affinity.proposes)
27
+ continue;
28
+ active.add(name);
29
+ }
30
+ return active;
31
+ };
32
+ //# sourceMappingURL=resolveForLoop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolveForLoop.js","sourceRoot":"","sources":["../src/resolveForLoop.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,+DAA+D;AAQ/D;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAC1B,QAAqC,EACrC,KAAgB,EACL,EAAE;IACb,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;IACjC,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC;QAC/C,MAAM,QAAQ,GAAI,OAA8B,CAAC,WAAW,CAAC,QAAQ,EAAE,KAAK,CAAC;QAC7E,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YACzB,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACjB,SAAS;QACb,CAAC;QACD,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,IAAI,QAAQ,CAAC,aAAa;YAAE,SAAS;QAC7D,IAAI,KAAK,CAAC,KAAK,IAAI,QAAQ,CAAC,WAAW;YAAE,SAAS;QAClD,IAAI,KAAK,CAAC,aAAa,IAAI,QAAQ,CAAC,mBAAmB;YAAE,SAAS;QAClE,IAAI,KAAK,CAAC,WAAW,IAAI,QAAQ,CAAC,QAAQ;YAAE,SAAS;QACrD,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACrB,CAAC;IACD,OAAO,MAAM,CAAC;AAClB,CAAC,CAAC"}
@@ -0,0 +1,27 @@
1
+ export type WriterTier = "model" | "client" | "system" | "plugin";
2
+ export interface SchemeFlagAffinity {
3
+ readonly excludedInAsk?: boolean;
4
+ readonly requiresWeb?: boolean;
5
+ readonly requiresInteraction?: boolean;
6
+ readonly proposes?: boolean;
7
+ }
8
+ export interface SchemeManifest {
9
+ readonly name: string;
10
+ readonly channels: Record<string, string>;
11
+ readonly defaultChannel: string;
12
+ readonly category: "data" | "logging";
13
+ readonly scope: "agent" | "session";
14
+ readonly writableBy: ReadonlyArray<WriterTier>;
15
+ readonly volatile: boolean;
16
+ readonly modelVisible: boolean;
17
+ readonly flags?: SchemeFlagAffinity;
18
+ }
19
+ export interface LoopFlags {
20
+ readonly mode: "ask" | "act";
21
+ readonly yolo: boolean;
22
+ readonly noWeb: boolean;
23
+ readonly noInteraction: boolean;
24
+ readonly noProposals: boolean;
25
+ }
26
+ export declare const DEFAULT_LOOP_FLAGS: LoopFlags;
27
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAElE,MAAM,WAAW,kBAAkB;IAC/B,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;IACjC,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IACvC,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,MAAM,WAAW,cAAc;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;IAC/C,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,KAAK,CAAC,EAAE,kBAAkB,CAAC;CACvC;AAED,MAAM,WAAW,SAAS;IACtB,QAAQ,CAAC,IAAI,EAAE,KAAK,GAAG,KAAK,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;CACjC;AAED,eAAO,MAAM,kBAAkB,EAAE,SAMhC,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1,17 @@
1
+ // Framework-grade types shared by every `@plurnk/plurnk-schemes-*` sibling
2
+ // and its consumer (plurnk-service).
3
+ //
4
+ // Notably absent from this surface: `PlurnkSchemeContext`. The full per-call
5
+ // context shape (which includes the database handle, channel-write notifier,
6
+ // wake-on-completion notifier, etc.) is plurnk-service-coupled and lives
7
+ // in the consumer. Sister schemes consume the parts of ctx the engine
8
+ // supplies them per dispatch; this repo ships only the manifest + flag
9
+ // types every sibling needs to declare itself.
10
+ export const DEFAULT_LOOP_FLAGS = {
11
+ mode: "act",
12
+ yolo: false,
13
+ noWeb: false,
14
+ noInteraction: false,
15
+ noProposals: false,
16
+ };
17
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,qCAAqC;AACrC,EAAE;AACF,6EAA6E;AAC7E,6EAA6E;AAC7E,yEAAyE;AACzE,sEAAsE;AACtE,uEAAuE;AACvE,+CAA+C;AA+B/C,MAAM,CAAC,MAAM,kBAAkB,GAAc;IACzC,IAAI,EAAE,KAAK;IACX,IAAI,EAAE,KAAK;IACX,KAAK,EAAE,KAAK;IACZ,aAAa,EAAE,KAAK;IACpB,WAAW,EAAE,KAAK;CACrB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@plurnk/plurnk-schemes",
3
+ "version": "0.1.0",
4
+ "description": "Framework + contract for the @plurnk/plurnk-schemes-* URI handler family.",
5
+ "keywords": ["plurnk", "scheme", "uri"],
6
+ "homepage": "https://github.com/plurnk/plurnk-schemes#readme",
7
+ "bugs": {
8
+ "url": "https://github.com/plurnk/plurnk-schemes/issues"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/plurnk/plurnk-schemes.git"
13
+ },
14
+ "engines": {
15
+ "node": ">=25"
16
+ },
17
+ "license": "MIT",
18
+ "author": "@wikitopian",
19
+ "type": "module",
20
+ "publishConfig": {
21
+ "access": "public"
22
+ },
23
+ "exports": {
24
+ ".": {
25
+ "types": "./dist/index.d.ts",
26
+ "default": "./dist/index.js"
27
+ },
28
+ "./package.json": "./package.json"
29
+ },
30
+ "files": [
31
+ "dist/**/*",
32
+ "README.md",
33
+ "SPEC.md"
34
+ ],
35
+ "scripts": {
36
+ "test:lint": "tsc --noEmit",
37
+ "test:unit": "node --test src/**/*.test.ts",
38
+ "test": "npm run test:lint && npm run test:unit",
39
+ "build:dist": "tsc -p tsconfig.build.json",
40
+ "build": "npm run build:dist",
41
+ "prepare": "npm run build"
42
+ },
43
+ "peerDependencies": {
44
+ "@plurnk/plurnk-grammar": "^0.15.0",
45
+ "@plurnk/plurnk-mimetypes": "^0.7.0"
46
+ },
47
+ "devDependencies": {
48
+ "@plurnk/plurnk-grammar": "^0.15.0",
49
+ "@plurnk/plurnk-mimetypes": "^0.7.0",
50
+ "@types/node": "^25.8.0",
51
+ "typescript": "^6.0.3"
52
+ }
53
+ }