@plurnk/plurnk-service 1.3.3 → 1.3.4
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/.env.defaults +16 -3
- package/INSTALL.md +7 -3
- package/SPEC.md +35 -19
- package/dist/build-info.json +1 -1
- package/dist/content/edit-receipt.d.ts +35 -0
- package/dist/content/edit-receipt.d.ts.map +1 -0
- package/dist/content/edit-receipt.js +158 -0
- package/dist/content/edit-receipt.js.map +1 -0
- package/dist/content/index.d.ts +2 -0
- package/dist/content/index.d.ts.map +1 -1
- package/dist/content/index.js +1 -0
- package/dist/content/index.js.map +1 -1
- package/dist/content/line-marker.d.ts +3 -1
- package/dist/content/line-marker.d.ts.map +1 -1
- package/dist/content/line-marker.js +2 -0
- package/dist/content/line-marker.js.map +1 -1
- package/dist/core/ChannelWrite.d.ts.map +1 -1
- package/dist/core/ChannelWrite.js.map +1 -1
- package/dist/core/Db.d.ts +2 -13
- package/dist/core/Db.d.ts.map +1 -1
- package/dist/core/Db.js +0 -5
- package/dist/core/Db.js.map +1 -1
- package/dist/core/Dispatcher.d.ts +2 -1
- package/dist/core/Dispatcher.d.ts.map +1 -1
- package/dist/core/Dispatcher.js +151 -26
- package/dist/core/Dispatcher.js.map +1 -1
- package/dist/core/Engine.d.ts.map +1 -1
- package/dist/core/Engine.js +26 -27
- package/dist/core/Engine.js.map +1 -1
- package/dist/core/Engine.sql +25 -0
- package/dist/core/LoopLifecycle.d.ts.map +1 -1
- package/dist/core/LoopLifecycle.js.map +1 -1
- package/dist/core/Owner.d.ts.map +1 -1
- package/dist/core/Owner.js.map +1 -1
- package/dist/core/PacketBuilder.d.ts.map +1 -1
- package/dist/core/PacketBuilder.js.map +1 -1
- package/dist/core/ProposalLifecycle.d.ts +1 -0
- package/dist/core/ProposalLifecycle.d.ts.map +1 -1
- package/dist/core/ProposalLifecycle.js +8 -4
- package/dist/core/ProposalLifecycle.js.map +1 -1
- package/dist/core/ProviderInstantiate.d.ts.map +1 -1
- package/dist/core/ProviderInstantiate.js +10 -22
- package/dist/core/ProviderInstantiate.js.map +1 -1
- package/dist/core/TelemetryChannel.d.ts.map +1 -1
- package/dist/core/TelemetryChannel.js.map +1 -1
- package/dist/core/caps/CapsResolve.d.ts.map +1 -1
- package/dist/core/caps/CapsResolve.js.map +1 -1
- package/dist/core/caps/DbChannelCaps.d.ts.map +1 -1
- package/dist/core/caps/DbChannelCaps.js.map +1 -1
- package/dist/core/caps/DbEntryCaps.d.ts.map +1 -1
- package/dist/core/caps/DbEntryCaps.js +8 -4
- package/dist/core/caps/DbEntryCaps.js.map +1 -1
- package/dist/core/caps/DbSubscriptionCaps.d.ts.map +1 -1
- package/dist/core/caps/DbSubscriptionCaps.js.map +1 -1
- package/dist/core/caps/DbTagCaps.d.ts.map +1 -1
- package/dist/core/caps/DbTagCaps.js.map +1 -1
- package/dist/core/fork.d.ts.map +1 -1
- package/dist/core/fork.js.map +1 -1
- package/dist/core/git-iso.d.ts +3 -0
- package/dist/core/git-iso.d.ts.map +1 -1
- package/dist/core/git-iso.js +35 -4
- package/dist/core/git-iso.js.map +1 -1
- package/dist/core/git-membership.d.ts.map +1 -1
- package/dist/core/git-membership.js.map +1 -1
- package/dist/core/git-state.d.ts.map +1 -1
- package/dist/core/git-state.js +3 -6
- package/dist/core/git-state.js.map +1 -1
- package/dist/core/packet-wire.d.ts.map +1 -1
- package/dist/core/packet-wire.js +37 -11
- package/dist/core/packet-wire.js.map +1 -1
- package/dist/core/turn-scheduler.d.ts +3 -0
- package/dist/core/turn-scheduler.d.ts.map +1 -0
- package/dist/core/turn-scheduler.js +20 -0
- package/dist/core/turn-scheduler.js.map +1 -0
- package/dist/core/worker-cap.d.ts.map +1 -1
- package/dist/core/worker-cap.js.map +1 -1
- package/dist/core/workspace-settings.d.ts.map +1 -1
- package/dist/core/workspace-settings.js.map +1 -1
- package/dist/core/world-state.d.ts.map +1 -1
- package/dist/core/world-state.js.map +1 -1
- package/dist/digest/Digest.d.ts.map +1 -1
- package/dist/digest/Digest.js +4 -6
- package/dist/digest/Digest.js.map +1 -1
- package/dist/schemes/Exec.d.ts.map +1 -1
- package/dist/schemes/Exec.js +5 -1
- package/dist/schemes/Exec.js.map +1 -1
- package/dist/schemes/File.d.ts +5 -0
- package/dist/schemes/File.d.ts.map +1 -1
- package/dist/schemes/File.js +51 -10
- package/dist/schemes/File.js.map +1 -1
- package/dist/schemes/Log.d.ts.map +1 -1
- package/dist/schemes/Log.js +9 -1
- package/dist/schemes/Log.js.map +1 -1
- package/dist/schemes/Prompt.d.ts +1 -1
- package/dist/schemes/Prompt.d.ts.map +1 -1
- package/dist/schemes/Prompt.js +2 -2
- package/dist/schemes/Prompt.js.map +1 -1
- package/dist/schemes/Skill.d.ts +1 -0
- package/dist/schemes/Skill.d.ts.map +1 -1
- package/dist/schemes/Skill.js +4 -1
- package/dist/schemes/Skill.js.map +1 -1
- package/dist/schemes/Worker.d.ts +3 -0
- package/dist/schemes/Worker.d.ts.map +1 -1
- package/dist/schemes/Worker.js +11 -2
- package/dist/schemes/Worker.js.map +1 -1
- package/dist/schemes/_entry-crud.d.ts.map +1 -1
- package/dist/schemes/_entry-crud.js.map +1 -1
- package/dist/schemes/_entry-find.d.ts +8 -8
- package/dist/schemes/_entry-find.d.ts.map +1 -1
- package/dist/schemes/_entry-find.js +76 -23
- package/dist/schemes/_entry-find.js.map +1 -1
- package/dist/schemes/_entry-find.sql +20 -0
- package/dist/schemes/_entry-graph.d.ts.map +1 -1
- package/dist/schemes/_entry-graph.js.map +1 -1
- package/dist/schemes/_entry-manifest.d.ts.map +1 -1
- package/dist/schemes/_entry-manifest.js.map +1 -1
- package/dist/schemes/_entry-ops.d.ts +3 -2
- package/dist/schemes/_entry-ops.d.ts.map +1 -1
- package/dist/schemes/_entry-ops.js +41 -13
- package/dist/schemes/_entry-ops.js.map +1 -1
- package/dist/schemes/_entry-semantic.d.ts +2 -1
- package/dist/schemes/_entry-semantic.d.ts.map +1 -1
- package/dist/schemes/_entry-semantic.js +15 -4
- package/dist/schemes/_entry-semantic.js.map +1 -1
- package/dist/schemes/_entry-semantic.sql +3 -0
- package/dist/schemes/_entry-send.d.ts.map +1 -1
- package/dist/schemes/_entry-send.js.map +1 -1
- package/dist/server/Daemon.d.ts.map +1 -1
- package/dist/server/Daemon.js.map +1 -1
- package/dist/server/clientTurn.d.ts.map +1 -1
- package/dist/server/clientTurn.js.map +1 -1
- package/dist/server/envelope.d.ts.map +1 -1
- package/dist/server/envelope.js.map +1 -1
- package/dist/server/logEntry.d.ts.map +1 -1
- package/dist/server/logEntry.js.map +1 -1
- package/package.json +20 -18
package/.env.defaults
CHANGED
|
@@ -110,11 +110,12 @@ PLURNK_SERVICE_GIT_AUTO=1
|
|
|
110
110
|
# PLURNK_SERVICE_GIT_NATIVE — git READ backend. Default (0) = in-process isomorphic-git:
|
|
111
111
|
# portable, sandbox-safe, no subprocess, hermetic by construction. =1 routes membership +
|
|
112
112
|
# status to the system git binary — in-process membership measures ~8x native (~130ms at
|
|
113
|
-
# 20k files) and the status read ~55x
|
|
113
|
+
# 20k files) and the status read ~55x. Native is also the explicit remedy when
|
|
114
|
+
# isomorphic-git cannot read a repository shape; it requires the git binary.
|
|
114
115
|
PLURNK_SERVICE_GIT_NATIVE=0
|
|
115
116
|
|
|
116
117
|
# PLURNK_SERVICE_ARRIVAL_PREVIEW_LINES — the arrival law (§arrival-law, #499): content another
|
|
117
|
-
# actor pushes at a worker (a prompt, a child's deliverable) rides OPEN only up to this many
|
|
118
|
+
# actor pushes at a worker (a prompt, a child's deliverable, terminal stream output) rides OPEN only up to this many
|
|
118
119
|
# lines AND 80×N chars (the char cap guards single-line bombs); over, a bounded head + the
|
|
119
120
|
# address + the full price ride instead. Self-invited content (a worker's own READ/FIND) is
|
|
120
121
|
# budget-bounded, never previewed. 16 = generous but not dangerous.
|
|
@@ -140,6 +141,15 @@ PLURNK_SERVICE_ARRIVAL_PREVIEW_LINES=16
|
|
|
140
141
|
# settings.filesItems (#231).
|
|
141
142
|
PLURNK_SERVICE_FILES_ITEMS=-1
|
|
142
143
|
|
|
144
|
+
# Number of full SHA-256 revision characters rendered on each model-facing
|
|
145
|
+
# EDIT receipt. The durable operation result retains all 64 characters; this
|
|
146
|
+
# abbreviation is display correlation only, never identity or comparison.
|
|
147
|
+
PLURNK_SERVICE_EDIT_RECEIPT_REVISION_CHARS=8
|
|
148
|
+
|
|
149
|
+
# Number of neighboring lines (or top-level JSON items) rendered on each side
|
|
150
|
+
# of an EDIT's resulting range. The model can READ for arbitrary final content.
|
|
151
|
+
PLURNK_SERVICE_EDIT_RECEIPT_CONTEXT_LINES=2
|
|
152
|
+
|
|
143
153
|
# Workspace-tier ceiling on CONCURRENT active runs (a run with a non-terminal loop)
|
|
144
154
|
# — the fork-bomb / destabilization brake. -1 = no cap (default); only concurrency
|
|
145
155
|
# is bounded, never lifetime, since workspaces persist for months. A spawn/fork past
|
|
@@ -213,8 +223,11 @@ PLURNK_SERVICE_DOCS_EXCLUDE="plurnk,file,exec"
|
|
|
213
223
|
# --- Semantic search (~query chunking) ---
|
|
214
224
|
# Project Semantics tiles each entry into <=window chunks so a large body is fully
|
|
215
225
|
# searchable, not truncated. ACTIVE only when the installed embedder reports its
|
|
216
|
-
# tokenizer; otherwise one whole-entry chunk (today's behavior).
|
|
226
|
+
# tokenizer; otherwise one whole-entry chunk (today's behavior). The chunk knobs are read
|
|
217
227
|
# only when chunking is active.
|
|
228
|
+
# Ranked results returned by a markerless `FIND(...):~query:FIND`. A positive
|
|
229
|
+
# integer `<K>` overrides this count; a decimal marker selects by similarity.
|
|
230
|
+
PLURNK_SERVICE_SEMANTIC_TOP_K=10
|
|
218
231
|
# Chunk budget in TOKENS. EMPTY (the default) = the installed embedder's reported
|
|
219
232
|
# window — NO model-specific number is assumed, so it scales to whatever embedder you
|
|
220
233
|
# install. Set a positive value ONLY to cap below the window (e.g. to sweep
|
package/INSTALL.md
CHANGED
|
@@ -39,13 +39,17 @@ These are relationships *between* flags. Set them as a unit.
|
|
|
39
39
|
|
|
40
40
|
- **The window partition is exact.** `promptBudget = min(PLURNK_SERVICE_CONTEXT_WINDOW, real window) − REASONING − COMPLETION − SAFETY`; `REASONING + COMPLETION` is the per-call `max_tokens`. Shipped invariant: any window ≥ 77Ki partitions to **exactly 65536** prompt tokens (`78848 − 4096 − 8192 − 1024`). Reserves exceeding the window fail the boot. *(Pinned: `Engine.budget` / `shipped-defaults`.)*
|
|
41
41
|
- **Reasoning capacity is one number in three places.** `PLURNK_SERVICE_REASONING` (the partition's reserve) **must equal** `PLURNK_PROVIDERS_THINKING_CAPACITY` (the provider's thinking cap) **must equal** the serving box's `--reasoning-budget` launch flag. llama-server ignores per-request numeric budgets, so only the launch flag clamps it; a mismatch makes the reserve fiction. The daemon warns at boot when thinking is on. *(Pinned: `shipped-defaults` asserts the first equality.)*
|
|
42
|
-
- **
|
|
42
|
+
- **Local GBNF is optional.** The PLURNK language is always parsed normally.
|
|
43
|
+
Local llama-server users may set `PLURNK_PROVIDERS_GBNF_<alias>`; transport
|
|
44
|
+
and enforcement are verified at boot. Cloud and endpoint-managed aliases
|
|
45
|
+
leave it unset. Pin `PLURNK_PROVIDERS_LLAMA_SERVER_<alias>=1` only when a
|
|
46
|
+
llama-server cannot be fingerprinted reliably.
|
|
43
47
|
- **A think-trained model must think somewhere.** `PLURNK_PROVIDERS_THINKING=off` reroutes a reasoning model's thought into the grammar's legal free zone as prose. Keep it `on` with a capacity; providers auto-clamp thinking on in-band grammar backends, so one setting is right everywhere.
|
|
44
48
|
|
|
45
49
|
## Profiles (examples, not a decision tree — adapt to the real box)
|
|
46
50
|
|
|
47
51
|
- **Local GPU (llama-server).** `PLURNK_MODEL_local="openai/<name>"`, `OPENAI_BASE_URL=http://127.0.0.1:<port>`, `PLURNK_MODEL=local`, `PLURNK_PROVIDERS_LLAMA_SERVER_local=1`, thinking `on`/`4096` **with the box launched `--reasoning-budget 4096`**. Full rails, exact tokenization.
|
|
48
|
-
- **Cloud, bring-your-own-key.** `PLURNK_MODEL_cloud="openrouter/<model>"`, `OPENROUTER_API_KEY=…`, `PLURNK_MODEL=cloud`. No `LLAMA_SERVER` pin
|
|
52
|
+
- **Cloud, bring-your-own-key.** `PLURNK_MODEL_cloud="openrouter/<model>"`, `OPENROUTER_API_KEY=…`, `PLURNK_MODEL=cloud`. No local GBNF or `LLAMA_SERVER` pin.
|
|
49
53
|
- **plurnk.ai endpoint.** `PLURNK_MODEL_plurnk="plurnk/plurnk"`, `PLURNK_API_KEY=…`, `PLURNK_MODEL=plurnk`.
|
|
50
54
|
- **Headless / CI / constrained container.** A CPU-only box should NOT disable semantic search — it should point derivation at a real embedder: `PLURNK_MIMETYPES_EMBED_BASE_URL` (any OpenAI-compatible `/v1/embeddings` — a host GPU turns a CPU-hours corpus grind into seconds). Weak hardware is the target workload, not a reason to shed capability; `PLURNK_SERVICE_EMBED_DISABLE=1` exists for test lanes that deterministically assert non-semantic behavior, nothing else. Consider `PLURNK_SERVICE_MAX_TURNS=<n>` as a cost cap, `PLURNK_SERVICE_GIT_ALLOWED=0` to lock out git in a sandbox.
|
|
51
55
|
|
|
@@ -62,7 +66,7 @@ Each mirrors a `# --- section ---` in the floor; consult the floor for exact def
|
|
|
62
66
|
- **Providers** — `PLURNK_PROVIDERS_THINKING`/`_THINKING_CAPACITY`, `_TEMPERATURE`, `_REPEAT_PENALTY`, `_FETCH_TIMEOUT`, `_RETRY_ATTEMPTS`/`_RETRY_DELAY`, `_PROBE_ATTEMPTS`/`_PROBE_DELAY`, `_GBNF` (grammar variant), `_LLAMA_SERVER_<alias>`, `_CONTEXT_SIZE`, `_GBNF_DEBUG`. Alias-scopable: any knob takes a `_<alias>` suffix that wins over the bare fallback.
|
|
63
67
|
- **The window partition** — `PLURNK_SERVICE_CONTEXT_WINDOW`/`_REASONING`/`_ASSISTANT`/`_SAFETY` (see Couplings).
|
|
64
68
|
- **Plugins** — bare `PLURNK_PLUGINS_TRUSTED_ONLY` (0/unset = load all installed; a value = `@plurnk/*` plus an allowlist).
|
|
65
|
-
- **Semantic search** — `
|
|
69
|
+
- **Semantic search** — `PLURNK_SERVICE_SEMANTIC_TOP_K` (markerless result count), `_SEMANTIC_CHUNK_TOKENS`/`_CHUNK_OVERLAP` (service-side chunking), `PLURNK_SERVICE_EMBED_DISABLE` (FTS-only), `PLURNK_MIMETYPES_EMBED_WORKERS` (the embedder's pool — mimetypes-owned).
|
|
66
70
|
- **Schemes: http** — `PLURNK_SCHEMES_HTTP_FETCH_TIMEOUT`/`_SALVAGE_MIN_BODY_CHARS`/`_IDLE_TIMEOUT` (required on the HTML render path), optional Playwright/Chromium knobs.
|
|
67
71
|
- **Execs** — `PLURNK_EXECS_<runtime>=0` disables a runtime; `PLURNK_EXECS_MCP_<server>` bridges an MCP server; `PLURNK_EXECS_SEARCH_SEARXNG_URL` enables web search (unset = search off).
|
|
68
72
|
|
package/SPEC.md
CHANGED
|
@@ -223,7 +223,7 @@ The lifecycle store admits only the guarded transitions shown above: `100 → 10
|
|
|
223
223
|
- **A cancelled run is not resurrected by its own torn-down work.** A stream conclusion delivered to a cancelled, idle worker starts no fresh drain: an aborted (499) conclusion is skipped, and a straggler that concluded cleanly surfaces its deliverable as an environment delta (§env-delta), never a revived loop. The cancel was deliberate; only an explicit `loop.run` resumes the worker. {§worker-lifecycle-no-resurrection}
|
|
224
224
|
- **A stream conclusion always reaches its worker.** When a backgrounded stream concludes, the daemon routes it through the same inject seam as any loop source (§actor-boundary-passive-wake): an active worker folds the conclusion into its next turn; a worker **blocked on a 202 wait** for that stream (§wait-obligation-matrix) **awakens that loop in place** — the blocked loop *is* the continuation, so there is no fresh loop and no summary-as-prompt fiction. The result is never lost: a blocked loop sleeps rather than ending, and the stream's status-transition is the arrival (§actor-boundary-passive-wake) that wakes it; on resume it reads the concluded stream's own state, not a synthetic prompt. {§worker-lifecycle-wake-liveness}
|
|
225
225
|
- **A child worker concluding wakes a parent blocked on it — the topology join.** `worker://` spawn/fork records `parent_worker_id` (§lifecycle-terms). When a worker's drain exits having **concluded** — no `202`-blocked loop, no open stream — the daemon resumes its parent **in place** if the parent is blocked on the join (`#onDrainExit` → the shared `#wakeParkedWorker`, the same 202→100 resume a stream conclusion uses). So a parent that spawns work and blocks (`SEND[202]`) is woken the moment its child finishes; on resume it reads the child's deliverable from the §worker-scheme-collect delta in its own log — a control edge, **never an injected prompt**. The wake recurses upward via the parent's own drain-exit. A child still running — or itself blocked at 202 — is not *concluded*, so it does not wake the parent (it's still a live thing the subtree holds). This is the structured-concurrency join: streams and child workers are the same kind of "live thing a worker holds," driving premature-terminate (§send-premature-terminate), the wake edge, and the collect delta identically. A worker conclusion is a **bounded, un-loseable** wake: if the conclusion fires while the parent is mid-turn (before its block commits), `#wakeParkedWorker` finds it not-yet-slept and records an **owed wake**, which the drain honors when the parent blocks — so a wait awaiting workers **always returns**, never dead-blocks on a conclude-before-block race. (Only a live exec stream, unbounded absent a timeout, may legitimately hold a wait open.) {§worker-lifecycle-child-wake}
|
|
226
|
-
- **An idle run concludes; it does not park.** A loop
|
|
226
|
+
- **An idle run concludes; it does not park.** A loop is idle only when it has neither live obligations nor completed results awaiting their first packet. A live child or stream blocks a `SEND[202]` join; a completed stream, child result, or same-turn retrieval continues directly to the next packet where it is observed. Only after those sets are drained does `SEND[202]` resolve like `SEND[200]`. There is no held-open idle loop and no `loop/quiesced` soft signal. A concluded worker is durable working history and an addressed arrival reawakens it as a new loop. {§worker-lifecycle-idle-is-concluded}
|
|
227
227
|
- **A loop is never stranded by a drain's exit.** A drain relinquishes its registry slot only after a lock-held re-claim confirms the queue is empty; a loop enqueued during that teardown is either re-claimed by the exiting drain or claimed by a fresh drain that a later inject starts. The relinquish and the start are serialized, so neither the lost-loop hang nor a transient double-drain can occur. {§worker-lifecycle-no-lost-loop}
|
|
228
228
|
- **Restart is owner-loss reconciliation, not replay.** {§worker-lifecycle-restart-recovery} Before opening client transports, the service holds an exclusive database-adjacent daemon lock; a second live owner fails before touching SQLite, while a dead-PID crash claim is replaced atomically without a timeout lease. Boot preserves accepted `100` loops and restores their drains. A `102` loop belonged to a vanished drain/provider call, so it settles `500` with the interruption on its durable row—never replayed across an unknown effect boundary. Every durable-open subscription likewise belonged to a vanished callable: active channels become errored and its row closes `500`. A `202` continuation survives only while a live child obligation remains; after reconciliation, an unblocked park requeues `202→100` and resumes in place. Child terminalization wakes its parked parent on every outcome, including provider exceptions, cancellation, and restart interruption, recursively through the durable parent edges. These operations are idempotent, so an interrupted recovery safely repeats.
|
|
229
229
|
|
|
@@ -275,9 +275,20 @@ Deferred (#249): grounding the attribution value in real per-turn value flow rat
|
|
|
275
275
|
|
|
276
276
|
Model alias parsing (`parseAliasesFromEnv` / `resolveActiveAlias`) lives in [`@plurnk/plurnk-providers`](https://github.com/plurnk/plurnk-providers). {§provider-instantiation-alias-resolution} Dynamic provider instantiation (`instantiateProvider` / `loadActiveProvider`) lives in `src/core/ProviderInstantiate.ts` here — `import()` resolves package specifiers relative to the calling module, so the dynamic-import path stays in the consumer where the `@plurnk/plurnk-providers-<vendor>` packages are installed.
|
|
277
277
|
|
|
278
|
-
**
|
|
279
|
-
|
|
280
|
-
|
|
278
|
+
**Optional local GBNF is verified at boot.** {§grammar-enforcement-verified-at-boot}
|
|
279
|
+
The ANTLR grammar always defines and validates the PLURNK language. Separately,
|
|
280
|
+
an operator may configure `PLURNK_PROVIDERS_GBNF_<alias>` for a local
|
|
281
|
+
llama-server. The provider must advertise GBNF transport and satisfy a forcing
|
|
282
|
+
probe (`root ::= "PLURNK-RAILS-LIVE"`) or boot fails. The setting is resolved
|
|
283
|
+
per alias and is unset by default. Configuring it on a cloud or endpoint-managed
|
|
284
|
+
provider is an error, not a request for best-effort filtering.
|
|
285
|
+
|
|
286
|
+
**Local constraint truth is independently observed.** {§rail-truth-engine-verdict}
|
|
287
|
+
For a configured local GBNF, the engine independently validates every completed
|
|
288
|
+
emission and stamps `railsAttached: "client"` plus `railsVerdict`. A non-accept
|
|
289
|
+
verdict emits `grammar_unenforced` telemetry if the provider did not already
|
|
290
|
+
report it. With no local GBNF, core adds no rail state and makes no claim about
|
|
291
|
+
endpoint-owned settings; any endpoint telemetry remains provider metadata.
|
|
281
292
|
|
|
282
293
|
```
|
|
283
294
|
PLURNK_MODEL_gemma=openai/macher.gguf
|
|
@@ -302,7 +313,7 @@ Author-facing contract: [plurnk-schemes#1](https://github.com/plurnk/plurnk-sche
|
|
|
302
313
|
Every op targets a URI; the entry key is `(workspace, owner, scheme, pathname)` ({§entry-identity-no-null}). The URI parses per RFC 3986 (`scheme://[authority]/path`). Handler routing and resource identity are separate:
|
|
303
314
|
|
|
304
315
|
- A **registered** scheme is a plurnk namespace: its authority is a leading path segment, folded into the pathname (`Dispatcher.#extractTarget` → `foldAuthorityIntoPath`). So `known://x`, `known:///x`, and pathname `/x` are the same entry — the authority is never a host, and the two-slash and three-slash forms are not distinct resources. {§scheme-address-namespace-fold}
|
|
305
|
-
- A **network resource** keeps its addressed protocol while folding the host into the storage pathname: `https://example.com/page` → `(https, /example.com/page)`. `https` may route through the registered `http` handler, just as `ws` routes through `wss`; that implementation alias never aliases identities. Absolute network URLs are single resources even when their path ends `/` — folder/glob expansion belongs to entry namespaces, never an HTTP origin.
|
|
316
|
+
- A **network resource** keeps its addressed protocol while folding the host into the storage pathname: `https://example.com/page` → `(https, /example.com/page)`. `https` may route through the registered `http` handler, just as `ws` routes through `wss`; that implementation alias never aliases identities. The `SchemeCtx.entries` direct CRUD and standard operation caps both bind to the addressed protocol, regardless of the handler manifest's canonical name. Absolute network URLs are single resources even when their path ends `/` — folder/glob expansion belongs to entry namespaces, never an HTTP origin.
|
|
306
317
|
- The **`file` class is the workspace filesystem** — a mount namespace with its own resolution and naming law, specified below.
|
|
307
318
|
|
|
308
319
|
**The workspace is a mount namespace; `project_root` is the model's `/`.** {§fs-namespace} Chroot semantics: host paths do not exist inside the jail, and no engine surface ever folds a host-absolute spelling onto a member (the convenience fold was run59's biography — #545). The root is **fixed immutably at workspace creation** (headless is forever); the namespace's mount table changes only through the declared membership overlay (§membership), never by re-rooting. At `project_root = /` the jail is the whole filesystem and every rule below degenerates to identity — the design's proof case, and the common benchmark topology.
|
|
@@ -331,9 +342,13 @@ Per author contract (`readEntry` / `writeEntry` / `deleteEntry`). Engine drives
|
|
|
331
342
|
|
|
332
343
|
### §op-methods Op methods
|
|
333
344
|
|
|
334
|
-
Per author contract (`
|
|
345
|
+
Per author contract (`editBatch`/`read`/`open`/`fold`/`find`/`send`/`exec?`). Engine dispatches EDIT resource batches through `editBatch`; every other op dispatches by its lowercased `PlurnkStatement.op`. {§op-methods-op-dispatch} COPY and MOVE are NOT scheme methods — engine orchestrates over CRUD primitives (§copy/§move).
|
|
346
|
+
|
|
347
|
+
- **A continuing turn executes in MODE phases.** {§op-mode-phases} A model turn describes intended effects and requested observations; it is not an imperative program whose later statements can consume invisible same-turn results. The engine therefore performs four stable phases: **Mutate** (`EDIT`, `COPY`, `MOVE`, `KILL`, `FOLD`), **Observe** (`FIND`, `READ`, `OPEN`), **Do** (all remaining non-terminal actions, including `EXEC`, `WORK`, `FORK`, and directed `SEND`), then **End** (the terminal `SEND`). `PLAN` remains the turn anchor and is recorded before those phases. Authored order is preserved within each phase. A result still lands in the next packet; phasing makes that result describe settled state instead of an accidental intermediate state.
|
|
348
|
+
|
|
349
|
+
- **Decisive operations settle before the next scheduled operation.** {§op-synchronous} The dispatcher `await`s every decisive operation. The only operations that return tracked work still in flight are the operations whose purpose is to create concurrency: `FORK`, `WORK`, and stream-producing `EXEC` handlers. MODE changes scheduling, not completion semantics. This is why a same-turn `KILL + SEND[200]` concludes (§send-premature-terminate): `KILL` synchronously flips the worker's live loops terminal (`engine_terminate_worker_live_loops`) before the End phase judges the pending set, while the physical scope reap rides `cancelWorker` asynchronously and invisibly.
|
|
335
350
|
|
|
336
|
-
- **
|
|
351
|
+
- **Same-resource EDITs are one mutation.** {§edit-batch} Every EDIT targeting the same canonical resource and channel in one turn applies to the resource's one pre-turn snapshot. The scheme validates the complete batch before writing, applies disjoint ranges from the highest original coordinate downward, and commits its one resulting revision atomically; reversing the statements cannot change that revision. A failing statement rejects that resource batch without a partial write; independent resource batches remain independent. Whole-resource replacement or creation cannot coexist with another EDIT in the same batch, selected ranges may not overlap, and a boundary insertion may occur at most once at each boundary. Prepend (`<0>`), append (`<-1>`), and fractional insertions name distinct snapshot boundaries and compose with non-overlapping ranges; two insertions naming the same boundary fail rather than acquiring an authored-order meaning. Proposal-gated schemes expose one proposal for the resource batch and accept all or none. The public scheme contract is batch-shaped: a scheme must never emulate this guarantee by applying individual EDITs sequentially.
|
|
337
352
|
|
|
338
353
|
### §orchestration Cross-scheme orchestration
|
|
339
354
|
|
|
@@ -364,7 +379,7 @@ Directed SEND (non-null path) routes to scheme's `send`. Status = intent:
|
|
|
364
379
|
|
|
365
380
|
- **Log speaks the universal query contract** {§log-uniform-query} — `FIND(log://…)` works like every scheme's FIND (the jumbo model ran the canon-documented `FIND(log:///**):#…#` six times into a bare 501 — log was the one scheme outside the universal paradigm, by accident not decision). Candidates are the worker's rows scoped by the coordinate hierarchy ({§log-coordinate-hierarchy}); each is projected EXACTLY as READ shows it (the rx unwrap — FIND must match what the model can retrieve); the shared `Matcher.matchCandidates` ({§find-source-agnostic}) applies any content dialect; results are catalog-shaped items keyed `log:///loop/turn/seq/OP` with `{mimetype, tokens, lines}`, and the fan-out retargets per-row READs so `READ(log://…):matcher` composes identically to entries (#286). A tag signal filters candidates by the model's own region tags ({§log-region-tagging}); log rows carry no symbol channels (`@graph` 501, an honest absence). `~semantic` is an HONEST 501 until log rows receive the same exhaustive vector coverage as entries; storage stays the event stream (the Q3/Option-B decision: uniform QUERY contract, honest distinct storage).
|
|
366
381
|
- **The content matcher is source-agnostic** {§find-source-agnostic} — `Matcher.matchCandidates(body, candidates, mimetypes)` applies a content matcher (regex/jsonpath/xpath/glob) to candidates from ANY source, keyed by the caller's own identity (a pathname for entries, a `loop/turn/seq` coordinate for log). The matcher never cares what table the content came from, so FIND/READ with every content dialect works uniformly across schemes BY CONSTRUCTION — `EntryFind` and `Log.find` run the ONE shared primitive rather than re-implementing per scheme. This is the query-layer half of the log-uniformity decision (Q3, Option B): log stays its own event stream, but its rows are candidates the shared matcher covers like any entry's content.
|
|
367
|
-
- **
|
|
382
|
+
- **Matching carries provenance and navigation coordinates** {§matcher-selection-signal} — a pattern match returns the SOURCE LINE containing it, with its line number (`42:I bought Alice some flowers`, never `1:Alice`), and its FIND item carries both that source footprint and the corresponding rows accepted by scoped READ. `matchSpan` is `{lineStart,lineEnd,rowStart,rowEnd}`; rows equal lines for line-navigable text and identify top-level readable items for structured content. `matchPath` remains the hit's canonical dialect coordinate (for example `$['users'][0]['name']`) when available. A matcher READ writes its internal FIND as a selection-summary row before its span-deduplicated deliveries, so minified or otherwise shared-line hits remain distinguishable without changing the returned source content. The teaching half is grammar's canon (grammar#56).
|
|
368
383
|
|
|
369
384
|
`SEND[410](path[#fragment])` also deletes the target entry/channel — an implemented side-effect, NOT taught to the model and with no live/demo surface. The model-facing delete idiom is KILL (§move).
|
|
370
385
|
|
|
@@ -642,9 +657,10 @@ AST: `{ op: "FIND", target (scope), body: MatcherBody | null (predicate), signal
|
|
|
642
657
|
|
|
643
658
|
- Filters entries within scope. A **bare** path is the exact entry; an explicit **glob** expands to a scope; `#regex#` filters by pathname. A trailing slash is a folder scope only for a scheme whose manifest declares `folderScopes: true`; otherwise it is ordinary resource syntax and READ dispatches it directly. This is an explicit plugin contract, never inferred from URL punctuation: new schemes cannot accidentally turn a root resource into unbounded fan-out. For declared folder schemes the same target contract governs FIND and READ — bare = the entry, folder/glob = a scope (#286). {§find-scope-prefix-filter}
|
|
644
659
|
- `body` matcher operates on entry content (glob/regex/jsonpath/xpath), per grammar plurnk.md §"Body matcher dispatch"; the path-glob lives in the (target), not the body. {§find-glob-filter-on-content}
|
|
660
|
+
- Every matcher operates only over the candidate set selected by `(target)` and `[tags]`; relation matchers do not bypass that selection. Semantic ranking is exhaustive within that candidate set, then applies its result policy—never rank the wider corpus and discard out-of-scope hits afterward, which changes top-K meaning and leaks entries across an exact target. A semantic matcher with no `<scope>` returns the configured `PLURNK_SERVICE_SEMANTIC_TOP_K` highest-ranked results. An integer scope overrides that count; a leading decimal is a minimum cosine-similarity threshold, optionally followed by a result cap. The ordinary FIND render budget remains independent of semantic ranking. {§find-semantic-default-top-k}
|
|
645
661
|
- `signal` is a tag filter; entries match if they have ALL listed tags. {§find-tag-filter-and-semantics}
|
|
646
662
|
- Workspace + scheme scoped — no cross-workspace/cross-scheme leakage. {§find-scoped-isolation}
|
|
647
|
-
- Returns `FindResult { status, content, mimetype, results: MatchItem[], matches, pathnames }`. The matcher sets the unit (#286). A **body-less** FIND is the **catalog**: one item per *entry* — `{ path, seconds?, tags?, channels: { <uri>: { mimetype, tokens, lines } } }` (the addressable path, per-channel `{mimetype, tokens, lines}` keyed by URI — default channel → the bare path, non-default → `path#channel` — plus `tags` and a live `seconds` stream age), the manifest's per-scheme slice. A **matcher** FIND resolves to one item per *match*: the entry's catalog row plus the `matchSpan` `{lineStart,
|
|
663
|
+
- Returns `FindResult { status, content, mimetype, results: MatchItem[], matches, pathnames }`. The matcher sets the unit (#286). A **body-less** FIND is the **catalog**: one item per *entry* — `{ path, seconds?, tags?, channels: { <uri>: { mimetype, tokens, lines } } }` (the addressable path, per-channel `{mimetype, tokens, lines}` keyed by URI — default channel → the bare path, non-default → `path#channel` — plus `tags` and a live `seconds` stream age), the manifest's per-scheme slice. A **matcher** FIND resolves to one item per *match*: the entry's catalog row plus the `matchSpan` `{lineStart,lineEnd,rowStart,rowEnd}` it hit. The line pair records source provenance; the row pair is directly reusable as scoped READ input. **A file with N matches yields N items** — the same row repeated, one span each; there is no `matchLines` array. The unit is uniform across every dialect — glob/regex/jsonpath/xpath select source spans, `~`semantic the ranked chunk's span, `@`graph the matched symbol's span — and the mimetype handler maps each to readable rows. Order is match order (rank for `~`semantic, source order otherwise); a miss contributes nothing; identical source spans dedup. `content` is the items as a JSON array (`application/json`). {§find-result-catalog-rows} **Over the render budget, FIND returns a count, not contents** (#418, `PLURNK_SERVICE_FIND_MAX_MATCHES`): a repo-scale `FIND(**)` over a 19k-entry workspace can't enumerate — materializing every match overflows the window, and a clean grind must not be a crash-and-recover. When the match set exceeds the budget the result carries `overflow: N` and its `content` states the fact (`"N entries match, exceeding the render budget — not enumerated"`), `text/markdown` not the JSON array; its enumerated `results`, `matches`, and `pathnames` arrays are EMPTY so no caller can perform hidden work from content the model was denied, while `overflow` and `itemsTokenTotal` report the full count and aggregate weight. INDEPENDENT of window size — even a 256k window should not render a whole repo's catalog into one turn. `0`/unset = no gate (small workspaces enumerate as before). {§find-count-not-contents}
|
|
648
664
|
|
|
649
665
|
### §send SEND
|
|
650
666
|
|
|
@@ -670,7 +686,7 @@ The engine's failure terminals — **500** (strike threshold) and **508** (cycle
|
|
|
670
686
|
**Three engine error states verify the claim.** None is a status code the model learns; all are engine machinery (§engine-rails), pushed to the model as a steering hint on the next packet and **never** as the strike itself (the model sees errors that happened, never the engine's accounting — the gamification policy, §engine-rails). Each strikes (`turnErrors`) and lets the loop continue so the model can correct; a model that ignores the hint and keeps offending spins out to the engine's 500, seeing only the repeated hint, never the count. (All live at `Engine.runLoop`'s turn close.)
|
|
671
687
|
|
|
672
688
|
- **Idle turn** {§send-idle-turn} — a continuing turn (102) whose ops are only PLAN/SEND — no work op. The model continued with nothing to do. The steer, verbatim: *"If your work is done, conclude with 200. If you're waiting on a child or stream you spawned, SEND[202] to block on it — a 202 with nothing to wait on simply concludes."*
|
|
673
|
-
- **Premature terminate — the pending set** {§send-premature-terminate} — `SEND[200]`
|
|
689
|
+
- **Premature terminate — the pending set** {§send-premature-terminate} — `SEND[200]` is gated by one rule: *nothing pending may be silently discarded*. Pending work has two states: **live obligations** (open streams/spawns and live child workers) and **completed-but-unobserved results** (same-turn READ/FIND/OPEN results, terminal stream output without a terminal foisted READ, and child results queued for the next packet). Completion is not delivery; a result becomes observed only after crossing a packet boundary. The set is judged at the terminal's own dispatch, after earlier operations in the emission. `[200]` over any member is refused 409 and the loop continues; `[499]` deliberately abandons regardless. `SEND[202]` parks only on live obligations. If work has completed but is unobserved, it continues directly to the next packet because the wake edge has already fired; only a genuinely empty set resolves immediately like `[200]`. {§send-undelivered-child-term}
|
|
674
690
|
- **SEND[300] is an operator question — a PROPOSAL, the stop-the-world system file edits and MCP auths ride** (owner ruling, #346). Enablement cascades: `PLURNK_QUESTIONS=0` is a servicewide ceiling; otherwise the client affirmatively requests per workspace (`settings.questions: true` at workspace.create), which ALSO injects the questions.md teaching — capability and teaching gate as one. Enabled: the `;`-delimited body parses leniently (first segment the question, the rest choices; zero choices = an open question — never malformed), and the ask raises a proposal: dispatch stops the world, `loop/proposal` carries `{question, choices}` in attrs, and the client's `loop.resolve {decision:"accept", body}` delivers the ANSWER — written into the ask's own model-facing rx (`{"status":200,"body":…}`), read next packet. Reject/timeout resolve through the standard §proposal semantics; the turn records a continue either way (never a 300 terminal), and the loop simply proceeds. Loop auto never auto-answers a question — it exists precisely to stop the world for a human, and the workspace opted in. Disabled: refused 409 with a self-decide steer, never a park into the void. {§send-300-choices}
|
|
675
691
|
|
|
676
692
|
### §exec EXEC
|
|
@@ -693,7 +709,7 @@ Engine routes unconditionally to `exec` scheme (the `(target)` slot is a local p
|
|
|
693
709
|
|
|
694
710
|
A `read` runtime (observes external state, e.g. search) or `pure` runtime (no observable effect, e.g. `:memory:` sqlite) is side-effect-free → **auto-run**: no proposal, no human gate, no notification. It skips the gate a host command faces, but it does NOT resolve in-band — like every exec it backgrounds and streams, its output reaching the model through the environment-observation injector (a foisted READ of the stream's new bytes each turn, §exec-stream), never a same-turn receipt. {§exec-readpure-ungated}
|
|
695
711
|
|
|
696
|
-
**Stream surfacing.** An exec's output is *observed, not fetched*. Each turn the environment-observation injector
|
|
712
|
+
**Stream surfacing.** An exec's output is *observed, not fetched*. Each turn the environment-observation injector reads each owned channel from its byte cursor and foists the new bytes as an `origin=plurnk` READ at `<runtime>:///<coord>#<channel>`. Streaming deltas are folded; the terminal delta is born OPEN. Because this is pushed content, the OPEN body obeys `PLURNK_SERVICE_ARRIVAL_PREVIEW_LINES`; a cut names the full stream address for an explicit READ. A stream that closes before a same-turn wait remains pending until this terminal READ crosses the next packet boundary. The EXEC row separately records the command. {§exec-stream}
|
|
697
713
|
|
|
698
714
|
`SEND[499](exec:///<loop>/<turn>/<seq>)` cancels the in-flight subprocess via the subscription registry's stored `AbortController` — the coordinate addresses the spawn (`exec://` is the process-control face); the `<runtime>://` output entry delegates the same KILL to the one `Exec` handler that owns the abort state (§stream-control).
|
|
699
715
|
|
|
@@ -903,7 +919,7 @@ Model selection: separate alias cascade in `ProviderRegistry` (§provider-instan
|
|
|
903
919
|
| `PLURNK_SERVICE_MD_<ALIAS>` | (unset) | Operator reference doc: materializes `<path>` as `plurnk:///<ALIAS>.md`, auto-READ into every model worker's turn 0 (§actor-boundary). `~` expands to home. |
|
|
904
920
|
| `PLURNK_SERVICE_FILES_ITEMS` | `-1` | Turn-0 catalog preview, one `FIND(scheme:///**)` per scheme. Memory/scratch/docs always full; the first-`N` cap applies **only** to the `file` list. `-1` = all full; positive `N` = file list first-N (memory still full); `0` / unset = off (§actor-boundary-catalog-preview). |
|
|
905
921
|
| `PLURNK_SERVICE_PROPOSAL_TIMEOUT_MS` | (empty — waits indefinitely) | ms wait for a proposed entry (status=202) to be resolved before timing out. |
|
|
906
|
-
| `PLURNK_PROVIDERS_REASONING` + `_BUDGET` | `adaptive` / (unset) | The activation/budget split (a numeric budget silently flipping template flags was secret flag-setting). `off | adaptive | on`; budget (tokens) REQUIRED when on.
|
|
922
|
+
| `PLURNK_PROVIDERS_REASONING` + `_BUDGET` | `adaptive` / (unset) | The activation/budget split (a numeric budget silently flipping template flags was secret flag-setting). `off | adaptive | on`; budget (tokens) REQUIRED when on. F7 coupling: llama-server honors only the box's `--reasoning-budget` launch flag (must equal the budget; boot-warned). |
|
|
907
923
|
| `PLURNK_PROVIDERS_FETCH_TIMEOUT` | `600000` | Service-wide ms ceiling on any outbound request (providers, future http schemes). Module-specific overrides are allowed below the ceiling. |
|
|
908
924
|
|
|
909
925
|
Every knob listed is enforced — the engine reads and acts on it; `.env.defaults` is the authoritative default (reader-declares, §operator-config-env-defaults).
|
|
@@ -912,7 +928,7 @@ Every knob listed is enforced — the engine reads and acts on it; `.env.default
|
|
|
912
928
|
- **Ceiling** (most-restrictive-wins) — an operator-set hard bound nothing downstream may exceed: not a lower-precedence file, not a per-workspace constraint, not a per-call RPC arg. `PLURNK_SERVICE_GIT_ALLOWED` (`=0` flatly denies git service-wide, §membership), `PLURNK_SERVICE_MAX_COMMANDS`, `PLURNK_SERVICE_MAX_STRIKES`, `PLURNK_PROVIDERS_FETCH_TIMEOUT` (module overrides allowed only *below* it), and `PLURNK_SERVICE_MAX_TURNS` (`-1` ships it off; a positive value caps the per-call request). The sandbox/cost guarantee: the operator caps it; no client widens it.
|
|
913
929
|
- **Default** (explicit-wins) — a fallback the most-specific setter replaces freely: `PLURNK_MODEL` (a `loop.run({alias})` overrides it), `PLURNK_SERVICE_REQUIREMENTS` (the per-call requirements default), and the config-time vars (`HOST` / `PORT` / `DB_PATH`).
|
|
914
930
|
|
|
915
|
-
**The shipped `.env.defaults` is itself under test** (no active `PLURNK_SERVICE_MD_*` doc alias — the policy is a SECTION, a doc default double-injects it; no active `PLURNK_MODEL`;
|
|
931
|
+
**The shipped `.env.defaults` is itself under test** (no active `PLURNK_SERVICE_MD_*` doc alias — the policy is a SECTION, a doc default double-injects it; no active `PLURNK_MODEL`; no active local GBNF constraint; the policy renders in exactly one packet section): every other tier runs the test cascade, so shipped-default regressions are invisible to it by construction. {§operator-config-shipped-defaults} Its companion **flag-parity** check binds code and template both ways: every `PLURNK_SERVICE_*` the service reads has a `.env.defaults` line (a floor, a `--flag`, a legend entry) and every declared `PLURNK_SERVICE_*` is read — so a half-landed rename (a missed file, a script-glob gap) fails a test instead of a user's boot, and a dead knob can't ship. {§operator-config-flag-parity}
|
|
916
932
|
|
|
917
933
|
Enforcement is per-use-site — no central most-restrictive pass; each ceiling is checked where it bites. `PLURNK_SERVICE_MAX_TURNS` ships **off** (`-1` = no cap; the loop ends via SEND, budget, strikes, or cycle detection) and, when an operator sets a positive value, the per-call request is `min()`-capped against it. {§operator-config-max-turns-ceiling}
|
|
918
934
|
|
|
@@ -1172,7 +1188,7 @@ Search prefetch and direct HTTP READ materialize the same resource contract: pro
|
|
|
1172
1188
|
|
|
1173
1189
|
Coverage protects the composition at distinct seams: HTTP unit tests pin fragmentless-body publication and explicit auxiliary selection; integration tests pin search→materialize→FIND/matcher READ and persistence/publication separation; deterministic model demos require a model-originated fragmentless HTTPS READ whose returned body contains facts absent from search snippets; a live positive-control demo requires a model-originated HTTPS READ and substantive answer from a real sanitized page. Live discovery demos remain diagnostic and may expose model judgment failures without weakening these assertions. **The search gates** (#406, owner ruling) are rail-family accounting — in-memory per-loop state cleaned at the same seam as strikes, restart-drop accepted (a post-restart duplicate re-fetches; the TTL makes it cheap): an IDENTICAL duplicate (same runtime + command in one loop) **strikes and serves** — status 409 (the strike rail counts the turn failure) carrying the prior ranked digest re-read live from the original exec entry, no re-fetch, no provenance prose; the per-turn CAP (`PLURNK_SERVICE_SEARCH_MAX_PER_TURN`) is flood control — 429 with a legible steer, nothing served. {§search-gate}
|
|
1174
1190
|
|
|
1175
|
-
**git is the substrate.** {§membership-git-membership} git-tracked files (`git ls-files` semantics) are members with no explicit overlay — channel-less markers, disk is truth. git absent → no fs-walk (non-git/headless get no substrate membership); `pick` is then the sole source. **Every core git read is in-process by default** {§git-portable-default}: isomorphic-git (exact-pinned), an explicit-`dir` library read — no subprocess, no ambient `GIT_*`, no global/system config — so the read is hermetic
|
|
1191
|
+
**git is the substrate.** {§membership-git-membership} git-tracked files (`git ls-files` semantics) are members with no explicit overlay — channel-less markers, disk is truth. git absent → no fs-walk (non-git/headless get no substrate membership); `pick` is then the sole source. **Every core git read is in-process by default** {§git-portable-default}: isomorphic-git (exact-pinned), an explicit-`dir` library read — no subprocess, no ambient `GIT_*`, no global/system config — so the read is hermetic by construction and works on a sandboxed or git-less host. Covered repository shapes include ordinary and linked worktrees, submodule boundaries, and the differential gitignore corpus. When isomorphic-git cannot read an actual repository shape, membership and status fail with one core-owned error that preserves the upstream cause and names `PLURNK_SERVICE_GIT_NATIVE=1`; an explicit backend change is reproducible, while an automatic retry would depend on whether a system binary happens to exist. The untracked scan is a pruning ignore-walk, **differential-gated**: it must reproduce native `ls-files --others --exclude-standard` across a gitignore edge-case corpus (negations, anchors, nested `.gitignore` precedence, `.git/info/exclude`, dir-vs-glob patterns, embedded-repo boundaries) or it does not ship. `PLURNK_SERVICE_GIT_NATIVE=1` routes membership + status to the system git binary {§git-native-flag} — in-process membership measures ~8× native (~130ms at 20k files) and the status read ~55× (statusMatrix hashes the workdir), so a large or unsupported repo with git installed can select the native backend. **That native arm scrubs ambient `GIT_*`** (#401): a process launched from a git hook inherits `GIT_DIR` — absolute in a worktree checkout — which retargets every child git at the enclosing repo regardless of cwd; project git state binds to the workspace's `project_root`, never to whoever spawned the daemon. One boundary (`git-env.hermeticGitEnv`), threaded through the native arm and every shell-git test fixture. {§membership-git-hermetic}
|
|
1176
1192
|
|
|
1177
1193
|
**Membership is a declared forest of repos.** {§membership-forest} A workspace is not one git repo but a **forest**: membership is the union, over a workspace-declared set of repos, of each repo's `ls-files` (gitlinks/mode-160000 filtered), each path-prefixed by the repo's path relative to `project_root`. The root need not itself be a repo — a non-git parent of ninety repos resolves to all ninety. A worktree, a submodule, a buried repo are not special cases: each is just another declared repo, resolved `rev-parse --show-toplevel` → `ls-files` in the tree it points at.
|
|
1178
1194
|
- **Membership-gated edits.** {§membership-edit-membership-gate} EDIT is bounded by membership exactly as READ is. An existing **member**'s baseline is its entry snapshot — the body channel the model READ, not a fresh disk read — so the diff is naive against the view the model saw, never empty (the write-side CAS, §membership-edit-write-cas, prevents the silent overwrite of out-of-band drift). An existing **non-member** is refused (403) *before* any read or write: the model never reads a file it can't see (no leak into the proposal) and never overwrites one (no wiping a gitignored `.env` it never added). A **new path** stays open — proposal→accept adds it to the manifest. Reaching past membership is `EXEC[sh]`'s job, not the file scheme's.
|
|
@@ -1256,15 +1272,15 @@ The CAS is the **hard backstop**, at the moment of writing, on every accept path
|
|
|
1256
1272
|
|
|
1257
1273
|
**Migration path.** Built. The per-worker world-snapshot the architecture forbade (§machine-processes) is **deleted**; its `[§machine-processes-worker-is-its-log]` conformance test is now green. The pull + the `plurnk`-run fs narration replace it.
|
|
1258
1274
|
|
|
1259
|
-
### §edit-result-render EDIT log rows render
|
|
1275
|
+
### §edit-result-render EDIT log rows render a bounded effect receipt
|
|
1260
1276
|
|
|
1261
1277
|
**Question.** An EDIT's log row exists so the model has a record of what it did. Re-emitting the model's *input* statement (the tx heredoc) records the *intent* but not the *outcome* — the model still has to READ the entry back to confirm "did it land, what does it look like now." And a system delta-EDIT (§env-delta) has no input statement at all. What should an EDIT row's body be?
|
|
1262
1278
|
|
|
1263
|
-
**Decision —
|
|
1279
|
+
**Decision — effect, revision, and bounded join context.** A model-authored EDIT row renders compact metadata (`rev`, `extent`, `change`, and `range`) plus bounded numbered context around that edit's resulting join. The durable result retains the full SHA-256 revision; `rev` abbreviates it to `PLURNK_SERVICE_EDIT_RECEIPT_REVISION_CHARS` for display correlation only and is never an identity, lookup key, or compare-and-swap token. Every row in one resource batch carries the same revision and extent but its own requested marker, normalized source/result ranges, removed/inserted counts, and context. The receipt proves what landed without copying an arbitrarily large changed region into the next packet. A deliberate READ in the same turn is scheduled after mutation (§op-mode-phases) and remains the universal way to request arbitrary current content.
|
|
1264
1280
|
|
|
1265
|
-
**Scope.** The
|
|
1281
|
+
**Scope.** The receipt is computed from the one pre-turn snapshot and committed result and stored structurally on the EDIT's `rx`; reviewer-modified proposals recompute it from the content that actually lands. Text resources report lines; structural JSON resources report top-level items. `PLURNK_SERVICE_EDIT_RECEIPT_CONTEXT_LINES` bounds neighboring lines/items independently for each row. Environment-delta EDITs remain factual state-diff events and carry their resulting span (§env-delta); COPY/MOVE likewise retain their resulting span.
|
|
1266
1282
|
|
|
1267
|
-
**Migration path.**
|
|
1283
|
+
**Migration path.** Built with MODE scheduling and atomic resource batches; the former unbounded resulting-span confirmation is removed from model-authored EDITs.
|
|
1268
1284
|
|
|
1269
1285
|
### §proposal-ownership Loop auto and client YOLO
|
|
1270
1286
|
|
|
@@ -1507,7 +1523,7 @@ Same rule applies across Known, Unknown, Skill, Plurnk, File. Effective mimetype
|
|
|
1507
1523
|
|
|
1508
1524
|
A log row renders its **result body** for the content-returning ops — `READ@200` (the content it pulled) and `FIND@200` (the catalog rows / matched entries it returned) — under the query's fence, mimetype-driven per the rules above; every other op re-emits its statement. FIND included: the model must see what a find *returned*, not just its echoed query, and the turn-0 foisted `FIND(scheme:///**)` reaches the packet through this branch — without it the catalog preview is invisible. {§render-rule-find-renders-result}
|
|
1509
1525
|
|
|
1510
|
-
An `EDIT` log row renders its **
|
|
1526
|
+
An `EDIT` log row renders its bounded **effect receipt** (`rx.receipt`) as row metadata and join context, not its input statement. Proposal-gated file EDITs compute the accepted receipt from what actually lands. Environment-delta EDITs and COPY/MOVE rows render their resulting `rx.span`. {§edit-result-render}
|
|
1511
1527
|
|
|
1512
1528
|
The `N:` prefix is presentation/reference per plurnk.md ("not part of the source"); stripped before any matcher operation on the log entry.
|
|
1513
1529
|
|
package/dist/build-info.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"package":"@plurnk/plurnk-service","version":"1.3.
|
|
1
|
+
{"package":"@plurnk/plurnk-service","version":"1.3.3","revision":"3352dea7a51575d4a1e7804428397e4d649f5c57","dirty":false}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { LineMarker } from "@plurnk/plurnk-grammar";
|
|
2
|
+
export interface ReceiptEdit {
|
|
3
|
+
readonly marker: LineMarker;
|
|
4
|
+
readonly body: string;
|
|
5
|
+
}
|
|
6
|
+
interface ReceiptOptions {
|
|
7
|
+
readonly unit?: "lines" | "items";
|
|
8
|
+
}
|
|
9
|
+
export interface EditEffectReceipt {
|
|
10
|
+
readonly requested: string;
|
|
11
|
+
readonly source: string;
|
|
12
|
+
readonly result: string;
|
|
13
|
+
readonly removed: number;
|
|
14
|
+
readonly inserted: number;
|
|
15
|
+
readonly context: string;
|
|
16
|
+
}
|
|
17
|
+
export interface EditBatchReceipt {
|
|
18
|
+
readonly revision: string;
|
|
19
|
+
readonly unit: "lines" | "items";
|
|
20
|
+
readonly before: number;
|
|
21
|
+
readonly after: number;
|
|
22
|
+
readonly effects: readonly EditEffectReceipt[];
|
|
23
|
+
}
|
|
24
|
+
export interface EditReceipt {
|
|
25
|
+
readonly revision: string;
|
|
26
|
+
readonly unit: "lines" | "items";
|
|
27
|
+
readonly before: number;
|
|
28
|
+
readonly after: number;
|
|
29
|
+
readonly effect: EditEffectReceipt;
|
|
30
|
+
}
|
|
31
|
+
export declare const editReceiptUnit: (structuralJson: boolean, original: string, updated: string) => "lines" | "items";
|
|
32
|
+
export declare const projectEditReceipt: (receipt: EditBatchReceipt, index: number) => EditReceipt;
|
|
33
|
+
export declare const editReceipt: (original: string, updated: string, edits: readonly ReceiptEdit[], options?: ReceiptOptions) => EditBatchReceipt;
|
|
34
|
+
export {};
|
|
35
|
+
//# sourceMappingURL=edit-receipt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit-receipt.d.ts","sourceRoot":"","sources":["../../src/content/edit-receipt.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEzD,MAAM,WAAW,WAAW;IACxB,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACzB;AAED,UAAU,cAAc;IACpB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;CACrC;AAED,MAAM,WAAW,iBAAiB;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,gBAAgB;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,SAAS,iBAAiB,EAAE,CAAC;CAClD;AAED,MAAM,WAAW,WAAW;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;CACtC;AAED,eAAO,MAAM,eAAe,mBACR,OAAO,YACb,MAAM,WACP,MAAM,KAChB,OAAO,GAAG,OASZ,CAAC;AAEF,eAAO,MAAM,kBAAkB,YAAa,gBAAgB,SAAS,MAAM,KAAG,WAU7E,CAAC;AA4BF,eAAO,MAAM,WAAW,aACV,MAAM,WACP,MAAM,SACR,SAAS,WAAW,EAAE,YACpB,cAAc,KACxB,gBAqGF,CAAC"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
export const editReceiptUnit = (structuralJson, original, updated) => {
|
|
3
|
+
if (!structuralJson)
|
|
4
|
+
return "lines";
|
|
5
|
+
try {
|
|
6
|
+
if (original.length > 0)
|
|
7
|
+
JSON.parse(original);
|
|
8
|
+
if (updated.length > 0)
|
|
9
|
+
JSON.parse(updated);
|
|
10
|
+
return "items";
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return "lines";
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
export const projectEditReceipt = (receipt, index) => {
|
|
17
|
+
const effect = receipt.effects[index];
|
|
18
|
+
if (effect === undefined)
|
|
19
|
+
throw new Error(`EDIT receipt has no effect at index ${index}`);
|
|
20
|
+
return {
|
|
21
|
+
revision: receipt.revision,
|
|
22
|
+
unit: receipt.unit,
|
|
23
|
+
before: receipt.before,
|
|
24
|
+
after: receipt.after,
|
|
25
|
+
effect,
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
const splitLines = (content) => {
|
|
29
|
+
if (content.length === 0)
|
|
30
|
+
return [];
|
|
31
|
+
const lines = content.split("\n");
|
|
32
|
+
if (content.endsWith("\n"))
|
|
33
|
+
lines.pop();
|
|
34
|
+
return lines;
|
|
35
|
+
};
|
|
36
|
+
const markerText = ({ marks }) => `<${marks.join(",")}>`;
|
|
37
|
+
const sourceRange = (marker, total) => {
|
|
38
|
+
const first = marker.marks[0];
|
|
39
|
+
const last = marker.marks[1];
|
|
40
|
+
if (last !== undefined) {
|
|
41
|
+
const start = first === 0 ? 1 : first;
|
|
42
|
+
const end = last === -1 ? total : last;
|
|
43
|
+
return { start, end, removed: Math.max(0, end - start + 1) };
|
|
44
|
+
}
|
|
45
|
+
if (first === 0)
|
|
46
|
+
return { start: 1, end: 0, removed: 0 };
|
|
47
|
+
if (first === -1)
|
|
48
|
+
return { start: total + 1, end: total, removed: 0 };
|
|
49
|
+
if (!Number.isInteger(first)) {
|
|
50
|
+
const start = Math.floor(first) + 1;
|
|
51
|
+
return { start, end: start - 1, removed: 0 };
|
|
52
|
+
}
|
|
53
|
+
return { start: first, end: first, removed: 1 };
|
|
54
|
+
};
|
|
55
|
+
export const editReceipt = (original, updated, edits, options = {}) => {
|
|
56
|
+
const { unit = "lines" } = options;
|
|
57
|
+
const before = splitLines(original);
|
|
58
|
+
const after = splitLines(updated);
|
|
59
|
+
let sourceShape = "scalar";
|
|
60
|
+
const itemCount = (content) => {
|
|
61
|
+
if (content.length === 0)
|
|
62
|
+
return 0;
|
|
63
|
+
const parsed = JSON.parse(content);
|
|
64
|
+
if (Array.isArray(parsed))
|
|
65
|
+
return parsed.length;
|
|
66
|
+
if (parsed !== null && typeof parsed === "object")
|
|
67
|
+
return Object.keys(parsed).length;
|
|
68
|
+
return 1;
|
|
69
|
+
};
|
|
70
|
+
if (unit === "items" && (original.length > 0 || updated.length > 0)) {
|
|
71
|
+
const parsed = JSON.parse(original.length > 0 ? original : updated);
|
|
72
|
+
sourceShape = Array.isArray(parsed) ? "array" : parsed !== null && typeof parsed === "object" ? "object" : "scalar";
|
|
73
|
+
}
|
|
74
|
+
const countBody = (body) => {
|
|
75
|
+
if (unit === "lines")
|
|
76
|
+
return splitLines(body).length;
|
|
77
|
+
if (body.length === 0)
|
|
78
|
+
return 0;
|
|
79
|
+
const parsed = JSON.parse(body);
|
|
80
|
+
if (sourceShape === "array")
|
|
81
|
+
return Array.isArray(parsed) ? parsed.length : 1;
|
|
82
|
+
if (sourceShape === "object") {
|
|
83
|
+
const values = Array.isArray(parsed) ? parsed : [parsed];
|
|
84
|
+
return values.reduce((count, value) => count + (value !== null && typeof value === "object" && !Array.isArray(value) ? Object.keys(value).length : 0), 0);
|
|
85
|
+
}
|
|
86
|
+
return Array.isArray(parsed) ? parsed.length : 1;
|
|
87
|
+
};
|
|
88
|
+
const beforeExtent = unit === "lines" ? before.length : itemCount(original);
|
|
89
|
+
const afterExtent = unit === "lines" ? after.length : itemCount(updated);
|
|
90
|
+
let offset = 0;
|
|
91
|
+
const effectsByIndex = new Array(edits.length);
|
|
92
|
+
edits
|
|
93
|
+
.map((edit, index) => ({ edit, index, source: sourceRange(edit.marker, beforeExtent) }))
|
|
94
|
+
.sort((a, b) => a.source.start - b.source.start)
|
|
95
|
+
.forEach(({ edit, index, source }) => {
|
|
96
|
+
const inserted = countBody(edit.body);
|
|
97
|
+
const resultStart = source.start + offset;
|
|
98
|
+
const resultEnd = inserted === 0 ? resultStart - 1 : resultStart + inserted - 1;
|
|
99
|
+
offset += inserted - source.removed;
|
|
100
|
+
effectsByIndex[index] = {
|
|
101
|
+
marker: markerText(edit.marker),
|
|
102
|
+
source,
|
|
103
|
+
inserted,
|
|
104
|
+
resultStart,
|
|
105
|
+
resultEnd,
|
|
106
|
+
};
|
|
107
|
+
});
|
|
108
|
+
const effects = effectsByIndex.map((effect, index) => {
|
|
109
|
+
if (effect === undefined)
|
|
110
|
+
throw new Error(`EDIT receipt calculation omitted effect ${index}`);
|
|
111
|
+
return effect;
|
|
112
|
+
});
|
|
113
|
+
const joinRadiusRaw = process.env.PLURNK_SERVICE_EDIT_RECEIPT_CONTEXT_LINES;
|
|
114
|
+
const joinRadius = Number(joinRadiusRaw);
|
|
115
|
+
if (!Number.isSafeInteger(joinRadius) || joinRadius < 0) {
|
|
116
|
+
throw new Error(`PLURNK_SERVICE_EDIT_RECEIPT_CONTEXT_LINES must be a non-negative safe integer, got ${JSON.stringify(joinRadiusRaw)}`);
|
|
117
|
+
}
|
|
118
|
+
const contextItems = unit === "lines"
|
|
119
|
+
? after
|
|
120
|
+
: (() => {
|
|
121
|
+
if (updated.length === 0)
|
|
122
|
+
return [];
|
|
123
|
+
const parsed = JSON.parse(updated);
|
|
124
|
+
if (Array.isArray(parsed))
|
|
125
|
+
return parsed.map((item) => JSON.stringify(item));
|
|
126
|
+
if (parsed !== null && typeof parsed === "object")
|
|
127
|
+
return Object.entries(parsed).map(([key, value]) => JSON.stringify({ [key]: value }));
|
|
128
|
+
return [JSON.stringify(parsed)];
|
|
129
|
+
})();
|
|
130
|
+
const withContext = effects.map((effect) => {
|
|
131
|
+
const visible = new Set();
|
|
132
|
+
const join = Math.min(Math.max(effect.resultStart, 1), Math.max(contextItems.length, 1));
|
|
133
|
+
const end = Math.max(join, effect.resultEnd);
|
|
134
|
+
for (let line = Math.max(1, join - joinRadius); line <= Math.min(contextItems.length, end + joinRadius); line += 1) {
|
|
135
|
+
visible.add(line);
|
|
136
|
+
}
|
|
137
|
+
const contextRows = [...visible].sort((a, b) => a - b).map((line) => `${line}:${contextItems[line - 1]}`);
|
|
138
|
+
const sourceText = effect.source.removed === 0 ? `${effect.source.start}^` : effect.source.start === effect.source.end ? `${effect.source.start}` : `${effect.source.start}-${effect.source.end}`;
|
|
139
|
+
const resultText = effect.resultEnd < effect.resultStart ? `${effect.resultStart}^` : effect.resultStart === effect.resultEnd ? `${effect.resultStart}` : `${effect.resultStart}-${effect.resultEnd}`;
|
|
140
|
+
return {
|
|
141
|
+
requested: effect.marker,
|
|
142
|
+
source: sourceText,
|
|
143
|
+
result: resultText,
|
|
144
|
+
removed: effect.source.removed,
|
|
145
|
+
inserted: effect.inserted,
|
|
146
|
+
context: contextRows.join("\n"),
|
|
147
|
+
};
|
|
148
|
+
});
|
|
149
|
+
const revision = createHash("sha256").update(updated).digest("hex");
|
|
150
|
+
return {
|
|
151
|
+
revision,
|
|
152
|
+
unit,
|
|
153
|
+
before: beforeExtent,
|
|
154
|
+
after: afterExtent,
|
|
155
|
+
effects: withContext,
|
|
156
|
+
};
|
|
157
|
+
};
|
|
158
|
+
//# sourceMappingURL=edit-receipt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit-receipt.js","sourceRoot":"","sources":["../../src/content/edit-receipt.ts"],"names":[],"mappings":"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"}
|
package/dist/content/index.d.ts
CHANGED
|
@@ -7,4 +7,6 @@ export type { MatchResult } from "./matcher.ts";
|
|
|
7
7
|
export { default as ReadResolve } from "./read-resolve.ts";
|
|
8
8
|
export type { ReadSliceResult } from "./read-resolve.ts";
|
|
9
9
|
export { editedSpan } from "./edited-span.ts";
|
|
10
|
+
export { editReceipt, editReceiptUnit, projectEditReceipt } from "./edit-receipt.ts";
|
|
11
|
+
export type { EditBatchReceipt, EditEffectReceipt, EditReceipt, ReceiptEdit } from "./edit-receipt.ts";
|
|
10
12
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/content/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEjE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC5D,YAAY,EAAE,UAAU,IAAI,cAAc,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEnG,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE7D,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,cAAc,CAAC;AAClD,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC3D,YAAY,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/content/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEjE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC5D,YAAY,EAAE,UAAU,IAAI,cAAc,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEnG,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE7D,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,cAAc,CAAC;AAClD,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC3D,YAAY,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACrF,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/content/index.js
CHANGED
|
@@ -8,4 +8,5 @@ export { default as PathMimetype } from "./path-mimetype.js";
|
|
|
8
8
|
export { default as Matcher } from "./matcher.js";
|
|
9
9
|
export { default as ReadResolve } from "./read-resolve.js";
|
|
10
10
|
export { editedSpan } from "./edited-span.js";
|
|
11
|
+
export { editReceipt, editReceiptUnit, projectEditReceipt } from "./edit-receipt.js";
|
|
11
12
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/content/index.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,2EAA2E;AAC3E,qEAAqE;AACrE,wEAAwE;AAExE,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEjE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAG5D,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE7D,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,cAAc,CAAC;AAGlD,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAG3D,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/content/index.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,2EAA2E;AAC3E,qEAAqE;AACrE,wEAAwE;AAExE,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEjE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAG5D,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE7D,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,cAAc,CAAC;AAGlD,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAG3D,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC"}
|