@plurnk/plurnk-service 0.17.0 → 0.20.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.
Files changed (59) hide show
  1. package/SPEC.md +39 -15
  2. package/bin/plurnk-service.ts +1 -0
  3. package/dist/core/ChannelWrite.d.ts +4 -0
  4. package/dist/core/ChannelWrite.d.ts.map +1 -1
  5. package/dist/core/ChannelWrite.js +8 -0
  6. package/dist/core/ChannelWrite.js.map +1 -1
  7. package/dist/core/Engine.d.ts +1 -1
  8. package/dist/core/Engine.d.ts.map +1 -1
  9. package/dist/core/Engine.js +39 -17
  10. package/dist/core/Engine.js.map +1 -1
  11. package/dist/core/git-membership.d.ts.map +1 -1
  12. package/dist/core/git-membership.js +12 -5
  13. package/dist/core/git-membership.js.map +1 -1
  14. package/dist/schemes/Exec.d.ts +2 -2
  15. package/dist/schemes/Exec.d.ts.map +1 -1
  16. package/dist/schemes/Exec.js +13 -6
  17. package/dist/schemes/Exec.js.map +1 -1
  18. package/dist/schemes/File.d.ts +10 -3
  19. package/dist/schemes/File.d.ts.map +1 -1
  20. package/dist/schemes/File.js +81 -114
  21. package/dist/schemes/File.js.map +1 -1
  22. package/dist/schemes/Log.d.ts.map +1 -1
  23. package/dist/schemes/Log.js +43 -10
  24. package/dist/schemes/Log.js.map +1 -1
  25. package/dist/schemes/Plurnk.js +1 -1
  26. package/dist/schemes/_entry-crud.d.ts +2 -0
  27. package/dist/schemes/_entry-crud.d.ts.map +1 -1
  28. package/dist/schemes/_entry-crud.js +4 -0
  29. package/dist/schemes/_entry-crud.js.map +1 -1
  30. package/dist/schemes/_entry-find.d.ts.map +1 -1
  31. package/dist/schemes/_entry-find.js +25 -5
  32. package/dist/schemes/_entry-find.js.map +1 -1
  33. package/dist/schemes/_entry-graph.d.ts +11 -0
  34. package/dist/schemes/_entry-graph.d.ts.map +1 -0
  35. package/dist/schemes/_entry-graph.js +81 -0
  36. package/dist/schemes/_entry-graph.js.map +1 -0
  37. package/dist/schemes/_entry-manifest.d.ts.map +1 -1
  38. package/dist/schemes/_entry-manifest.js +46 -4
  39. package/dist/schemes/_entry-manifest.js.map +1 -1
  40. package/dist/schemes/_entry-ops.d.ts.map +1 -1
  41. package/dist/schemes/_entry-ops.js +12 -1
  42. package/dist/schemes/_entry-ops.js.map +1 -1
  43. package/dist/schemes/_entry-semantic.d.ts +13 -0
  44. package/dist/schemes/_entry-semantic.d.ts.map +1 -0
  45. package/dist/schemes/_entry-semantic.js +67 -0
  46. package/dist/schemes/_entry-semantic.js.map +1 -0
  47. package/dist/schemes/cosine.d.ts +4 -0
  48. package/dist/schemes/cosine.d.ts.map +1 -0
  49. package/dist/schemes/cosine.js +9 -0
  50. package/dist/schemes/cosine.js.map +1 -0
  51. package/dist/server/envelope.d.ts +1 -0
  52. package/dist/server/envelope.d.ts.map +1 -1
  53. package/dist/server/envelope.js +8 -0
  54. package/dist/server/envelope.js.map +1 -1
  55. package/dist/server/methods/session_attach.d.ts.map +1 -1
  56. package/dist/server/methods/session_attach.js +3 -0
  57. package/dist/server/methods/session_attach.js.map +1 -1
  58. package/migrations/0000-00-00.01_schema.sql +67 -1
  59. package/package.json +110 -109
package/SPEC.md CHANGED
@@ -50,9 +50,9 @@ Independent axes on entries and channels. Confusion across them is a recurring s
50
50
 
51
51
  | Term | Meaning |
52
52
  |---|---|
53
- | **writer** | The identity authoring a write. One of `model \| client \| system \| plugin`. Carried on `ctx.writer` for schemes; engine enforces `manifest.writableBy`. |
53
+ | **writer** | The identity authoring a write. One of `model \| client \| plurnk \| plugin`. Carried on `ctx.writer` for schemes; engine enforces `manifest.writableBy`. |
54
54
  | **origin** | Synonym for writer in log_entries (`log_entries.origin`). Historical naming; treat as equivalent. |
55
- | **writable_by** | The set of writers a scheme accepts. Subset of `{model, client, system, plugin}`. Engine rejects writes outside the set with 403; the rejection is logged as the action-entry (§7.1 action-entry-as-outcome). |
55
+ | **writable_by** | The set of writers a scheme accepts. Subset of `{model, client, plurnk, plugin}`. Engine rejects writes outside the set with 403; the rejection is logged as the action-entry (§7.1 action-entry-as-outcome). |
56
56
 
57
57
  ### §0.5 Engine rails
58
58
 
@@ -207,7 +207,7 @@ Directed SEND (non-null path) routes to scheme's `send`. Status = intent:
207
207
  - `SEND[200](path)` — write body into resource (WS message, exec stdin).
208
208
  - `SEND[499](path)` — cancel active subscription (§7).
209
209
 
210
- `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 MOVE to `/dev/null` (§6.5).
210
+ `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 (the MOVE→`/dev/null` idiom is retired, §6.5).
211
211
 
212
212
  Other status codes return 501 from entry-bearing schemes by default. {§3.5-entry-schemes-501-on-non-410}
213
213
 
@@ -224,7 +224,7 @@ interface PlurnkSchemeContext {
224
224
  readonly runId: number;
225
225
  readonly loopId: number;
226
226
  readonly turnId: number;
227
- readonly writer: "model" | "client" | "system" | "plugin";
227
+ readonly writer: "model" | "client" | "plurnk" | "plugin";
228
228
  readonly signal: AbortSignal | undefined;
229
229
  readonly streamEventNotify?: StreamEventNotify;
230
230
  readonly wakeRunNotify?: WakeRunNotify;
@@ -258,10 +258,11 @@ Per author contract. Manifest declares `kind: "mimetype"`; handler class declare
258
258
 
259
259
  ### §4.2 Methods
260
260
 
261
- Author contract owned by plurnk-mimetypes. plurnk-service consumes through two entry points:
261
+ Author contract owned by plurnk-mimetypes. plurnk-service consumes ONE entry point:
262
262
 
263
- - `Mimetypes.process(input)` — projection entry point; returns the structural projections + extent (`deepJson`/`deepXml` for matching, `totalLines` for the catalog). {§4.2-process-entry-point}
264
- - `Mimetypes.query(input, expression)` — body-matcher dispatch (§16.1); returns `QueryMatch[]`.
263
+ - `Mimetypes.process(input)` — the projection entry point; returns the structural projections (`deepJson` / `deepXml` / `symbols` / `references`) + extent (`totalLines`). {§4.2-process-entry-point}
264
+
265
+ **The daughter projects; the service queries.** `Mimetypes.query()` exists in the author contract, but plurnk-service does NOT consume it. The service owns **all** dialect matching — glob, regex, jsonpath, xpath, `@graph`, `~semantic` — resolved in-tree over those projections plus its own indexes (`symbol_defs`/`symbol_refs`, FTS5, vectors). mimetypes is mimetype-*literate* (content→structure); the service is dialect-*literate* (structure→matches). The pattern-matching DSL is plurnk's defining surface — the service's authority, never a daughter's.
265
266
 
266
267
  Cross-cutting promises service relies on:
267
268
 
@@ -305,14 +306,15 @@ new Mimetypes({
305
306
 
306
307
  Fallback heuristic is a boot-before-provider-resolved tripwire.
307
308
 
308
- **Manifest build.** `EntryManifest.buildManifestBody` calls `process({ content, hint })` per channel and reads `result.totalLines` for the catalog's `lines`:
309
+ **Manifest build.** `EntryManifest.buildManifestBody` is the engine-side packet-assembly pass (the §4 firing point) that walks **every** entry. It calls `process({ content, hint })` per channel for the catalog's `lines` (`totalLines`) and, for the body channel, pulls `symbols`+`references` from the *same* call to (re)build the `@graph` symbol index (`symbol_defs`/`symbol_refs`) via `EntryGraph.populateFrom` — one parse, two projections:
309
310
 
310
311
  ```ts
311
- const result = await mimetypes.process({ content: r.content, hint: r.mimetype });
312
+ const result = await mimetypes.process({ content: r.content, hint: r.mimetype }, { channels: ["symbols", "references"] });
312
313
  entry.channels[r.channel] = { mimetype: r.mimetype, tokens: tokenize(r.content), lines: result.totalLines };
314
+ if (isBody) await EntryGraph.populateFrom(db, sessionId, r.entry_id, result.symbols ?? [], result.references ?? []);
313
315
  ```
314
316
 
315
- `hint` short-circuits detection. The service consumes only `totalLines` (extent) and the structural channels (`deepJson`/`deepXml`, for matcher dispatch); never a rendered preview — content reaches the model on READ.
317
+ `hint` short-circuits detection. The service consumes `totalLines` (extent), `symbols`/`references` (the `@graph` index), and `deepJson`/`deepXml` (matcher dispatch); never a rendered preview — content reaches the model on READ. Because this pass runs every assembly over every entry, any content change — by any writer — is reflected in the next packet's index. The `@graph` index is NOT engine *ranking* (the anti-pattern): it's a complete, unranked index the model queries via `FIND @<sym`, the manifest paradigm applied to structure, uniform across schemes (`file://` is the primary case).
316
318
 
317
319
  **Conformance.** Mimetype-specific behavioral tests live in each handler's own surface. plurnk-service intg covers integration: the engine routes through `Mimetypes.process` with the right hint and the catalog reflects `totalLines`; tests use auto-discovery (production handler set); a custom-handler test injects a stub `BaseHandler` via `loader + discovery`.
318
320
 
@@ -436,8 +438,8 @@ Returns 201 on success. Same- and cross-scheme COPY share the orchestrator. {§6
436
438
 
437
439
  AST: `{ op: "MOVE", target (source), body: dest | null, signal: tags | null, lineMarker? }`.
438
440
 
439
- - **Relocation** (`body` non-null): COPY (§6.4) + `src_scheme.deleteEntry` in one transaction. 201 on success. {§6.5-relocation-deletes-source} Cross-scheme same as same-scheme. {§6.5-cross-scheme-move}
440
- - **Deletion** (`body: null`, or `body` = `/dev/null`): `src_scheme.deleteEntry` directly. {§6.5-null-body-deletes} 200 on success, 404 if absent. {§6.5-missing-source-404} `/dev/null` is the model-facing delete idiom the grammar teaches; a null body is its programmatic equivalent. {§6.5-dev-null-deletes}
441
+ - **Relocation** (`body` non-null, resolvable dest): COPY (§6.4) + `src_scheme.deleteEntry` in one transaction. 201 on success. {§6.5-relocation-deletes-source} Cross-scheme same as same-scheme. {§6.5-cross-scheme-move} Missing source → 404. {§6.5-missing-source-404}
442
+ - **MOVE never deletes.** A null body 400 (a destination is required). {§6.5-null-body-400} `/dev/null` carries no special meaning — the MOVE→/dev/null delete idiom is retired; KILL is the canonical delete. {§6.5-dev-null-not-special}
441
443
 
442
444
  Log history preserved — `log_entries` stores path tuple as text, not FK to `entries.id`.
443
445
 
@@ -744,6 +746,8 @@ registry.register("loop.run", {
744
746
 
745
747
  **Auto-envelope.** Clients calling a `requiresInit: true` method without first attaching get auto-created session → run → client loop. Records persist normally; auto-created ≠ auto-deleted. Cleanup is a future `session.delete` / `session.archive` endpoint. {§13.5-auto-envelope}
746
748
 
749
+ **Reserved run names.** `plurnk` is reserved for the runtime actor (§0.4). `session.attach` rejects it — case-insensitively, *before* the lookup-or-create — so a client can neither forge a `plurnk` run nor resume the runtime's, closing impersonation of `origin=plurnk`. The auto-namer never emits a reserved name. {§13.5-run-name-reserved}
750
+
747
751
  **Loops (model-driven)**
748
752
 
749
753
  | Method | Params | Result | Notes |
@@ -952,9 +956,9 @@ Each entry: question, answer, rationale, migration path.
952
956
 
953
957
  **Question.** The manifest (§15) is a live directory of what *exists*, re-derived each turn — but it carries *state*, not *events*. When a session entry changes out-of-band between turns — an exec stream grows, a sibling run edits a shared entry, a tracked file diverges on disk (§14.3) — the model's prior READ is now stale, and the manifest's new line count is a fact it must *diff against its own memory* to notice. The manifest also cannot say *who* changed it; with more than one actor in a session, provenance is load-bearing. What surfaces change — losslessly, attributably, without curating?
954
958
 
955
- **Decision — a per-run delta of system-authored EDITs.** When a session entry changes out-of-band, the engine records it the way the model records its *own* edits: a `log_entries` row, op=`EDIT`, `origin=system`, carrying the new `source` attribution (the cause). The body is exactly an EDIT's body — **the edited area as it looks now, line-numbered, with a couple lines of context** (the result-rendering all EDITs share, §14.6). The set is **exhaustive and unranked** — every change, no relevance order — but **not content-free**: showing the edited region of a change that *happened* is a faithful record, not the index regrowing. The engine may inform (the §14.3 EMI divergence is the precedent), never rank or select what the model retains; the one line it must never cross is *ranking*. Volume is the model's to manage by FOLD (and the grinder's under budget), not the engine's to manage by gutting the payload.
959
+ **Decision — a per-run delta of plurnk-authored EDITs.** When a session entry changes out-of-band, the engine records it the way the model records its *own* edits: a `log_entries` row, op=`EDIT`, `origin=plurnk`, carrying the new `source` attribution (the cause). The body is exactly an EDIT's body — **the edited area as it looks now, line-numbered, with a couple lines of context** (the result-rendering all EDITs share, §14.6). The set is **exhaustive and unranked** — every change, no relevance order — but **not content-free**: showing the edited region of a change that *happened* is a faithful record, not the index regrowing. The engine may inform (the §14.3 EMI divergence is the precedent), never rank or select what the model retains; the one line it must never cross is *ranking*. Volume is the model's to manage by FOLD (and the grinder's under budget), not the engine's to manage by gutting the payload.
956
960
 
957
- **Form — a log entry, `origin=system`, the change translated to DSL.** A delta is a `log_entries` row: an **`EDIT`** ("an EDIT happened to X"), `origin=system`, carrying the new **`source`** column — the cause. A log entry, not a transient frame section, because a run's timeline must be **self-contained** (a forked run carries everything it observed). `source` renders as `run="<id>"` / `run="file"` in the meta line, **omitted when the cause is the owning run itself**. It is a third attribution axis, distinct from `run_id` (whose log owns the row) and `origin` (the actor *type*).
961
+ **Form — a log entry, `origin=plurnk`, the change translated to DSL.** A delta is a `log_entries` row: an **`EDIT`** ("an EDIT happened to X"), `origin=plurnk`, carrying the new **`source`** column — the cause. A log entry, not a transient frame section, because a run's timeline must be **self-contained** (a forked run carries everything it observed). `source` renders as `run="<id>"` / `run="file"` in the meta line, **omitted when the cause is the owning run itself**. It is a third attribution axis, distinct from `run_id` (whose log owns the row) and `origin` (the actor *type*).
958
962
 
959
963
  **Passive — computed at build, never forces a turn.** A delta materializes only while a packet is being assembled, so a change has nowhere to land until something else has already started a turn — it cannot wake an idle model. "Inform, never override," as mechanism. Urgency that genuinely needs the model routes through the *voice* door (an inject), never the environment door promoting itself to a turn.
960
964
 
@@ -976,6 +980,26 @@ Each entry: question, answer, rationale, migration path.
976
980
 
977
981
  **Migration path.** Changes what EDIT rows *show* (input → output); the op surface and EDIT's behaviour are unchanged. Tests asserting the input-heredoc render move to the resulting-span render.
978
982
 
983
+ ### §14.7 The actor boundary: isolation by run, two doors, self-hosting
984
+
985
+ **Question.** A session holds many runs — model, client, plurnk (§0.1, §0.4) — over one shared manifest. What keeps one run's activity out of another's conversation; what are the *only* ways a run's work reaches another; and does the engine's own work obey the boundary or get a privileged back channel?
986
+
987
+ **Decision — isolation by run; the model is not privileged.** A packet renders exactly one run's log — the assembling run's — against the session's shared manifest (§15). A run cannot see another's log: isolation is *structural*, a consequence of "a run owns its log entries" (§0.1) and "one packet, one run," never an `origin` filter at render time. `origin` (§0.4) is **attribution** — the delta's provenance (§14.5) — never read to hide a row. {§14.7-isolation} {§14.7-origin-not-filter}
988
+
989
+ **Two doors, and only two.** A run's work reaches another run by exactly two channels, and a private log is reachable no other way:
990
+ - the **environment door** — a write to a *shared entry* surfaces to every run sharing it as a folded, attributed delta (§14.5). *State.*
991
+ - the **voice door** — an **inject** delivers a turn into a *specific* run's log; `btw` is the user's mid-loop inject. *Message.*
992
+
993
+ {§14.7-two-doors}
994
+
995
+ **Wild west — no mutual exclusion.** Runs share the manifest without locks. Coordination is cooperative (tags + the shared workspace convention) and softly fenced (the §14.3 `read-only` overlay scopes a run's writable surface); a conflict *surfaces* as a delta rather than being prevented. Inform, never override. {§14.7-no-mutex}
996
+
997
+ **Passive wake.** An idle run wakes on exactly two events — a prompt injected into it (voice; user or system) or a stream-status transition it subscribes to (§5.6). A delta never wakes a run; it queues and drains at the next turn one of those produces (§14.5). {§14.7-passive-wake}
998
+
999
+ **Self-hosting — the runtime is an actor, not a back channel.** Runtime-initiated work (fs reconciliation §14.3, git auto-add) is an **ephemeral `plurnk` run** firing ordinary ops, seen by other runs through the environment door like any actor's — not a privileged engine pathway. The engine keeps only the irreducible kernel runs stand on (spawn, dispatch, packet assembly, the budget rails §14.4, the fs-watch); everything expressible as ops on session entries is a run doing ops, through the same `op.*` surface (§13.5) the service offers clients. Dogfooding is the architecture, not a test mode. {§14.7-self-hosting}
1000
+
1001
+ **Migration path.** Largely realized: `Engine.dispatch` is origin-agnostic; client ops run in a per-connection client loop (`_dispatchAsClient`); plurnk EDITs already carry `origin=plurnk`. What remains is *repatriation* — the inline plurnk dispatches (the §14.5 materialization, today bolted into the model's loop) move into ephemeral plurnk runs via a headless spawn primitive mirroring `_dispatchAsClient`. Once every mutation is a run-scoped action, SAVEPOINT-nested rollback (run → loop → turn → action) falls out uniformly.
1002
+
979
1003
  ---
980
1004
 
981
1005
  ## §15 Packet shape
@@ -1003,7 +1027,7 @@ type Packet = {
1003
1027
  };
1004
1028
  ```
1005
1029
 
1006
- **Prompt as a first-class entry.** Each loop's prompt is written on loop start as a system-origin `EDIT` against `plurnk://prompt/<loop_id>` (indexable, body channel, text/markdown). At render time the current loop's prompt body materializes into `packet.user.prompt`; the entry itself stays READ/FOLD-able like any other.
1030
+ **Prompt as a first-class entry.** Each loop's prompt is written on loop start as a plurnk-origin `EDIT` against `plurnk://prompt/<loop_id>` (indexable, body channel, text/markdown). At render time the current loop's prompt body materializes into `packet.user.prompt`; the entry itself stays READ/FOLD-able like any other.
1007
1031
 
1008
1032
  **The entry catalog.** `plurnk://manifest.json` is a real session entry the model READs to discover what's available — rewritten every turn as a live view of the full entry set. Built in the schemes layer (`_entry-manifest`) and materialized like any entry (the engine only orchestrates the per-turn write — the same pattern as git membership), so it's READable and queryable. Body is `application/json`: a flat, **complete, unranked** array — one item per entry across all schemes, every entry listed in no relevance order, each `{ path, channels: { <name>: { mimetype, tokens, lines } } }`. The model ranks and filters the catalog itself by querying it (task-aware); the catalog never ranks for it — the instant it did, it would be an index again. `tokens` is the provider's write-time count (budget depth), `lines` the content extent from `Mimetypes.process().totalLines`. The engine counts neither. It does not list itself. {§15-manifest-catalog}
1009
1033
 
@@ -40,6 +40,7 @@ export default class Cli {
40
40
  const db = await SqlRite.open({
41
41
  path: dbPath,
42
42
  dir: [resolve(Cli.#projectRoot, "migrations"), resolve(Cli.#projectRoot, "src")],
43
+ functions: [resolve(Cli.#projectRoot, "src/schemes/cosine.ts")],
43
44
  });
44
45
  return db as unknown as Db;
45
46
  }
@@ -48,6 +48,10 @@ export default class ChannelWrite {
48
48
  subscriptionId: number;
49
49
  status: number;
50
50
  }): Promise<void>;
51
+ static execTerminalStatus(db: Db, { sessionId, pathname }: {
52
+ sessionId: number;
53
+ pathname: string;
54
+ }): Promise<number | null>;
51
55
  static findActiveSubscription(db: Db, { runId, entryId }: {
52
56
  runId: number;
53
57
  entryId: number;
@@ -1 +1 @@
1
- {"version":3,"file":"ChannelWrite.d.ts","sourceRoot":"","sources":["../../src/core/ChannelWrite.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,EAAE,EAAc,MAAM,SAAS,CAAC;AAE9C,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEtE,MAAM,WAAW,kBAAkB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,YAAY,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,iBAAiB,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;AAQvF,MAAM,WAAW,cAAc;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;AAQ9D,MAAM,WAAW,qBAAqB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,oBAAoB,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,qBAAqB,KAAK,IAAI,CAAC;AAU/F,MAAM,CAAC,OAAO,OAAO,YAAY;;WAehB,eAAe,CACxB,EAAE,EAAE,EAAE,EACN,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,iBAAiB,CAAA;KAAE,GACrH,OAAO,CAAC,IAAI,CAAC;WASH,eAAe,CACxB,EAAE,EAAE,EAAE,EACN,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,YAAY,CAAC;QAAC,MAAM,CAAC,EAAE,iBAAiB,CAAA;KAAE,GAC3H,OAAO,CAAC,IAAI,CAAC;WASH,gBAAgB,CACzB,EAAE,EAAE,EAAE,EACN,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GACvG,OAAO,CAAC,MAAM,CAAC;WAML,iBAAiB,CAC1B,EAAE,EAAE,EAAE,EACN,EAAE,cAAc,EAAE,MAAM,EAAE,EAAE;QAAE,cAAc,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GACvE,OAAO,CAAC,IAAI,CAAC;WAIH,sBAAsB,CAC/B,EAAE,EAAE,EAAE,EACN,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GACvD,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAIpE"}
1
+ {"version":3,"file":"ChannelWrite.d.ts","sourceRoot":"","sources":["../../src/core/ChannelWrite.ts"],"names":[],"mappings":"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"}
@@ -12,6 +12,7 @@ export default class ChannelWrite {
12
12
  static #openSubStmt(db) { return db.open_subscription; }
13
13
  static #closeSubStmt(db) { return db.close_subscription; }
14
14
  static #findActiveStmt(db) { return db.find_active_subscription; }
15
+ static #execTerminalStmt(db) { return db.find_exec_close_status; }
15
16
  // The entry's target URI for stream notifications (#179). A NULL scheme is
16
17
  // a filesystem entry (the file scheme stores scheme=NULL), so it decodes to
17
18
  // file://.
@@ -49,6 +50,13 @@ export default class ChannelWrite {
49
50
  static async closeSubscription(db, { subscriptionId, status }) {
50
51
  await ChannelWrite.#closeSubStmt(db).run({ status, subscription_id: subscriptionId });
51
52
  }
53
+ // Terminal close_status of a finished exec stream, by coordinate pathname —
54
+ // the KILL-on-a-non-running-exec lookup (Exec.kill). null = no closed
55
+ // subscription for that coordinate (unknown exec).
56
+ static async execTerminalStatus(db, { sessionId, pathname }) {
57
+ const row = await ChannelWrite.#execTerminalStmt(db).get({ session_id: sessionId, pathname });
58
+ return row?.close_status ?? null;
59
+ }
52
60
  static async findActiveSubscription(db, { runId, entryId }) {
53
61
  const row = await ChannelWrite.#findActiveStmt(db).get({ run_id: runId, entry_id: entryId });
54
62
  return row ?? null;
@@ -1 +1 @@
1
- {"version":3,"file":"ChannelWrite.js","sourceRoot":"","sources":["../../src/core/ChannelWrite.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ChannelWrite.js","sourceRoot":"","sources":["../../src/core/ChannelWrite.ts"],"names":[],"mappings":"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"}
@@ -5,7 +5,7 @@ import type { Db } from "./Db.ts";
5
5
  import type { LoopFlags } from "./scheme-types.ts";
6
6
  import type ExecutorRegistry from "./ExecutorRegistry.ts";
7
7
  import type { StreamEventNotify, TelemetryEventNotify, WakeRunNotify } from "./ChannelWrite.ts";
8
- type Origin = "model" | "client" | "system" | "plugin";
8
+ type Origin = "model" | "client" | "plurnk" | "plugin";
9
9
  type ChatMessage = {
10
10
  role: "system" | "user" | "assistant";
11
11
  content: string;
@@ -1 +1 @@
1
- {"version":3,"file":"Engine.d.ts","sourceRoot":"","sources":["../../src/core/Engine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Engine.d.ts","sourceRoot":"","sources":["../../src/core/Engine.ts"],"names":[],"mappings":"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"}
@@ -478,7 +478,7 @@ class Engine {
478
478
  };
479
479
  await this.dispatch({
480
480
  statement: promptStmt, sessionId, runId, loopId, turnId,
481
- sequence: nextActionIndex, origin: "system", onDispatch,
481
+ sequence: nextActionIndex, origin: "plurnk", onDispatch,
482
482
  });
483
483
  nextActionIndex++;
484
484
  }
@@ -491,7 +491,7 @@ class Engine {
491
491
  // per-turn write. Does not list itself.
492
492
  const systemCtx = {
493
493
  db: this.#db, sessionId, runId, loopId, turnId,
494
- writer: "system",
494
+ writer: "plurnk",
495
495
  signal: this.#loopAborts.get(loopId)?.signal,
496
496
  streamEventNotify: this.#streamEventNotify,
497
497
  wakeRunNotify: this.#wakeRunNotify,
@@ -553,7 +553,7 @@ class Engine {
553
553
  // decode at the free window so a runaway can't reach the context wall.
554
554
  const genCeiling = _a.computeCeiling(provider.contextSize, this.#budgetCeiling);
555
555
  const maxTokens = genCeiling === null ? undefined : Math.max(1, genCeiling - requestPacket.system.tokens - requestPacket.user.tokens);
556
- const response = await provider.generate({ messages: modelMessages, signal, grammar: await this.#grammarConstraint(), maxTokens });
556
+ const response = await provider.generate({ messages: modelMessages, runId: String(runId), signal, grammar: await this.#grammarConstraint(), maxTokens });
557
557
  // Engine splits wire-level response: emission (content, reasoning,
558
558
  // parsed ops) → packet.assistant per Packet.json §assistant;
559
559
  // call-metadata (usage, finishReason, model) → Turn columns per
@@ -917,7 +917,7 @@ class Engine {
917
917
  }
918
918
  // §14.5 — at pre-turn build, reconcile each session entry against this run's
919
919
  // watermark. First sight sets it silently; a content change materializes a
920
- // delta-EDIT (origin=system, the §14.6 result span) at the next sequence and
920
+ // delta-EDIT (origin=plurnk, the §14.6 result span) at the next sequence and
921
921
  // advances the mark. Excludes plurnk:// (manifest/prompt) and bare/file
922
922
  // entries (scheme NULL — the EMI's territory). Returns the count so the
923
923
  // caller advances nextActionIndex past the pre-seeded deltas.
@@ -943,7 +943,7 @@ class Engine {
943
943
  const span = editedSpan(wm.content, r.content);
944
944
  await this.#db.engine_insert_log_entry.get({
945
945
  run_id: runId, loop_id: loopId, turn_id: turnId,
946
- sequence: fromSequence + written, origin: "system", source: r.scheme === null ? "file" : null,
946
+ sequence: fromSequence + written, origin: "plurnk", source: r.scheme === null ? "file" : null,
947
947
  op: "EDIT", suffix: "", signal: null,
948
948
  scheme: r.scheme, username: null, password: null, hostname: null, port: null,
949
949
  pathname: r.pathname, params: null, fragment: null, lineMarker: null,
@@ -1066,6 +1066,16 @@ class Engine {
1066
1066
  // with the failure outcome — engine treats it like a client
1067
1067
  // rejection.
1068
1068
  const effective = await this.#runApplyResolution(statement, result, resolution, { sessionId, runId, loopId, turnId });
1069
+ // MOVE into a proposed dest: the deferred source-delete fires ONLY now,
1070
+ // after the dest write landed (accept). On reject the source survives.
1071
+ if (effective.decision === "accept") {
1072
+ const moveSource = result.attrs?.moveSource;
1073
+ if (moveSource !== undefined) {
1074
+ const srcHandler = this.#schemes.get(moveSource.scheme);
1075
+ if (srcHandler !== undefined && typeof srcHandler.deleteEntry === "function")
1076
+ await srcHandler.deleteEntry(moveSource.pathname, schemeCtx);
1077
+ }
1078
+ }
1069
1079
  const post = await this.#applyResolution(logEntryId, effective);
1070
1080
  return post;
1071
1081
  }
@@ -1078,7 +1088,11 @@ class Engine {
1078
1088
  // EXEC routes to the exec scheme regardless of target (cwd, not
1079
1089
  // a scheme address). All other ops resolve their handler from
1080
1090
  // statement.target's scheme.
1081
- const schemeName = statement.op === "EXEC" ? "exec" : this.#schemeNameOf(statement.target);
1091
+ // COPY/MOVE write the DEST (statement.body), not the source (target): the
1092
+ // accept must reach the dest scheme's applyResolution (File writes disk).
1093
+ const schemeName = statement.op === "EXEC" ? "exec"
1094
+ : (statement.op === "COPY" || statement.op === "MOVE") ? this.#schemeNameOf(statement.body)
1095
+ : this.#schemeNameOf(statement.target);
1082
1096
  if (schemeName === null)
1083
1097
  return resolution;
1084
1098
  const handler = this.#schemes.get(schemeName);
@@ -1181,7 +1195,7 @@ class Engine {
1181
1195
  const ctx = {
1182
1196
  db: this.#db, sessionId: sessionRow.session_id, runId, loopId,
1183
1197
  turnId: 0, // no turn open at inject time; entries don't pin turnId
1184
- writer: "system",
1198
+ writer: "plurnk",
1185
1199
  signal: this.#loopAborts.get(loopId)?.signal,
1186
1200
  streamEventNotify: this.#streamEventNotify,
1187
1201
  wakeRunNotify: this.#wakeRunNotify,
@@ -1360,24 +1374,28 @@ class Engine {
1360
1374
  const dstPath = statement.body;
1361
1375
  if (srcPath === null)
1362
1376
  return { status: 400, error: "MOVE requires source path" };
1377
+ // MOVE is relocation only — deletion is KILL's job (§6.5). The /dev/null
1378
+ // and null-body delete-by-MOVE back-compat is retired: no silent debt.
1379
+ if (dstPath === null)
1380
+ return { status: 400, error: "MOVE requires a destination; use KILL to delete" };
1363
1381
  const srcSchemeName = this.#schemeNameOf(srcPath);
1364
1382
  if (srcSchemeName === null)
1365
1383
  return { status: 400, error: "MOVE source must be a URL path with a scheme" };
1366
1384
  const srcHandler = this.#schemes.get(srcSchemeName);
1367
1385
  if (srcHandler === undefined || typeof srcHandler.deleteEntry !== "function")
1368
1386
  return { status: 501 };
1369
- // MOVE to /dev/null (the grammar's idiomatic delete) or a null-body
1370
- // MOVE deletes the source entry. SPEC §6.5.
1371
- if (dstPath === null || pathnameFromPath(dstPath) === "/dev/null") {
1372
- const srcPathname = pathnameFromPath(srcPath);
1373
- const delResult = await srcHandler.deleteEntry(srcPathname, ctx);
1374
- return { status: delResult.status };
1375
- }
1376
- // Relocation: COPY then DELETE source
1387
+ // Relocation: COPY then DELETE source.
1377
1388
  const copyResult = await this.#copyOrchestration({ statement, srcPath, dstPath, ctx });
1378
1389
  if (copyResult.status >= 400)
1379
1390
  return copyResult;
1380
1391
  const srcPathname = pathnameFromPath(srcPath);
1392
+ // If the dest write is a pending proposal (file dest → §14.3 review), the
1393
+ // source-delete MUST wait until the dest actually lands — a rejected
1394
+ // proposal would otherwise lose the source. Thread it into the resolution:
1395
+ // dispatch deletes the source AFTER the dest applies on accept.
1396
+ if (copyResult.status === 202) {
1397
+ return { ...copyResult, attrs: { ...copyResult.attrs, moveSource: { scheme: srcSchemeName, pathname: srcPathname } } };
1398
+ }
1381
1399
  const delResult = await srcHandler.deleteEntry(srcPathname, ctx);
1382
1400
  if (delResult.status >= 400)
1383
1401
  return { status: delResult.status };
@@ -1391,7 +1409,7 @@ class Engine {
1391
1409
  // annotation with no runtime meaning; it survives into the log row's tx for
1392
1410
  // free via the statement serialization. Status: 200 killed · 404 unknown ·
1393
1411
  // 405 log:// (append-only) · 403 writableBy (the #checkWritable gate, KILL ∈
1394
- // MUTATING_OPS) · 200/404 exec (killed / not running) · 501 no-kill/delete scheme.
1412
+ // MUTATING_OPS) · 200/410/304/404 exec (killed / killed-earlier / exited / unknown) · 501 no-kill/delete scheme.
1395
1413
  async #handleKill(statement, ctx) {
1396
1414
  if (statement.op !== "KILL")
1397
1415
  throw new Error("unreachable");
@@ -1407,7 +1425,7 @@ class Engine {
1407
1425
  const execHandler = this.#schemes.get("exec");
1408
1426
  if (execHandler === undefined || typeof execHandler.kill !== "function")
1409
1427
  return { status: 501 };
1410
- return execHandler.kill(pathnameFromPath(path));
1428
+ return await execHandler.kill(pathnameFromPath(path), ctx);
1411
1429
  }
1412
1430
  const handler = this.#schemes.get(schemeName);
1413
1431
  if (handler === undefined || typeof handler.deleteEntry !== "function")
@@ -1499,6 +1517,10 @@ class Engine {
1499
1517
  return { status: 409, error: `COPY/MOVE destination exists: ${dstSchemeName}://${dstPathname}` };
1500
1518
  }
1501
1519
  const writeResult = await dstHandler.writeEntry(dstPathname, { channels, tags }, ctx);
1520
+ // A file dest returns 202 (disk write → §14.3 review): propagate the
1521
+ // proposal so dispatch runs the gate + routes applyResolution to the dest.
1522
+ if (writeResult.status === 202)
1523
+ return { status: 202, attrs: writeResult.attrs, body: writeResult.body };
1502
1524
  return { status: writeResult.status, entryId: writeResult.entryId, created: writeResult.created };
1503
1525
  }
1504
1526
  async #handleSendBroadcast(statement, loopId) {