@plurnk/plurnk-service 0.16.0 → 0.17.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 (60) hide show
  1. package/SPEC.md +10 -2
  2. package/dist/Paths.d.ts +1 -0
  3. package/dist/Paths.d.ts.map +1 -1
  4. package/dist/Paths.js +5 -0
  5. package/dist/Paths.js.map +1 -1
  6. package/dist/core/Engine.d.ts +5 -0
  7. package/dist/core/Engine.d.ts.map +1 -1
  8. package/dist/core/Engine.js +106 -9
  9. package/dist/core/Engine.js.map +1 -1
  10. package/dist/core/ExecutorRegistry.d.ts +9 -1
  11. package/dist/core/ExecutorRegistry.d.ts.map +1 -1
  12. package/dist/core/ExecutorRegistry.js +21 -28
  13. package/dist/core/ExecutorRegistry.js.map +1 -1
  14. package/dist/core/SchemeRegistry.d.ts +2 -0
  15. package/dist/core/SchemeRegistry.d.ts.map +1 -1
  16. package/dist/core/SchemeRegistry.js +52 -0
  17. package/dist/core/SchemeRegistry.js.map +1 -1
  18. package/dist/core/git-state.d.ts +15 -0
  19. package/dist/core/git-state.d.ts.map +1 -0
  20. package/dist/core/git-state.js +65 -0
  21. package/dist/core/git-state.js.map +1 -0
  22. package/dist/core/packet-wire.d.ts +1 -0
  23. package/dist/core/packet-wire.d.ts.map +1 -1
  24. package/dist/core/packet-wire.js +8 -1
  25. package/dist/core/packet-wire.js.map +1 -1
  26. package/dist/core/scheme-types.d.ts +9 -0
  27. package/dist/core/scheme-types.d.ts.map +1 -1
  28. package/dist/schemes/Exec.d.ts +4 -0
  29. package/dist/schemes/Exec.d.ts.map +1 -1
  30. package/dist/schemes/Exec.js +17 -1
  31. package/dist/schemes/Exec.js.map +1 -1
  32. package/dist/schemes/File.d.ts +2 -11
  33. package/dist/schemes/File.d.ts.map +1 -1
  34. package/dist/schemes/File.js.map +1 -1
  35. package/dist/schemes/Log.d.ts +2 -10
  36. package/dist/schemes/Log.d.ts.map +1 -1
  37. package/dist/schemes/Log.js.map +1 -1
  38. package/dist/schemes/_entry-manifest.d.ts.map +1 -1
  39. package/dist/schemes/_entry-manifest.js +5 -1
  40. package/dist/schemes/_entry-manifest.js.map +1 -1
  41. package/dist/server/ClientConnection.d.ts.map +1 -1
  42. package/dist/server/ClientConnection.js +5 -2
  43. package/dist/server/ClientConnection.js.map +1 -1
  44. package/dist/server/Daemon.d.ts.map +1 -1
  45. package/dist/server/Daemon.js +8 -0
  46. package/dist/server/Daemon.js.map +1 -1
  47. package/dist/server/MethodRegistry.d.ts +5 -0
  48. package/dist/server/MethodRegistry.d.ts.map +1 -1
  49. package/dist/server/MethodRegistry.js.map +1 -1
  50. package/dist/server/methods/loop_run.d.ts.map +1 -1
  51. package/dist/server/methods/loop_run.js +1 -0
  52. package/dist/server/methods/loop_run.js.map +1 -1
  53. package/dist/server/methods/session_attach.d.ts.map +1 -1
  54. package/dist/server/methods/session_attach.js +0 -3
  55. package/dist/server/methods/session_attach.js.map +1 -1
  56. package/dist/server/methods/session_create.d.ts.map +1 -1
  57. package/dist/server/methods/session_create.js +1 -3
  58. package/dist/server/methods/session_create.js.map +1 -1
  59. package/migrations/0000-00-00.01_schema.sql +1 -1
  60. package/package.json +11 -15
package/SPEC.md CHANGED
@@ -338,7 +338,7 @@ Every entry is uniformly listed in `plurnk://manifest.json` (§15) and READable
338
338
 
339
339
  Mimetype is declared by scheme manifest (§3.1) or supplied per-call for dynamic schemes. Writing a channel without a declared mimetype throws. No default mimetype anywhere.
340
340
 
341
- - Cross-mimetype COPY/MOVE → 415, never coerces (§6.4).
341
+ - Cross-mimetype COPY/MOVE → 415, never coerces (§6.4). {§5.3-cross-mimetype-415}
342
342
 
343
343
  ### §5.5 Channel selection in the DSL
344
344
 
@@ -730,12 +730,17 @@ registry.register("loop.run", {
730
730
 
731
731
  | Method | Params | Result | Notes |
732
732
  |------------------------|---------------------|-------------------|-------|
733
- | `session.create` | `name?: string`, `projectRoot?: string`, `persona?: string` | `{ id, name, projectRoot, persona }` | Creates new session; auto-name if unprovided. Optional `projectRoot` pins the workspace (null/omitted = headless). Optional `persona` sets the session-level persona override. |
733
+ | `session.create` | `name?: string`, `projectRoot?: string`, `persona?: string` | `{ id, name, runId, runName, projectRoot, persona }` | Creates new session + its first run; auto-name if unprovided. Returns the auto-created run's identity so clients skip the pending-dance ({§13.5-session-create}). Optional `projectRoot` pins the workspace (null/omitted = headless). Optional `persona` sets the session-level persona override. |
734
734
  | `session.list` | none | `{ sessions: Session[] }` | Lists all sessions. |
735
735
  | `session.attach` | `id: number`, `runId?: number`, `runName?: string`, `persona?: string` | `{ id, name, runId, runName }` | Binds this connection to an existing session. Optional `runId` resumes that specific run (must belong to the session). Optional `runName` reuses-or-creates by name within the session. Both omitted → new auto-named run. Optional `persona` sets run-level persona only when a NEW run is created. {§13.5-session-attach} |
736
736
  | `session.runs` | `id?: number` | `{ runs: Run[] }` | Lists runs in a session (defaults to attached session); most-recent first. |
737
737
  | `session.set_root` | `projectRoot: string \| null` | `{ projectRoot }` | Update the workspace pointer on the attached session. Null reverts to headless. |
738
738
  | `session.set_persona` | `persona: string \| null` | `{ persona }` | Update the session-level persona. Null clears the override (falls through to PLURNK_PERSONA file). |
739
+ | `session.constrain` | `effect: "add" \| "ignore" \| "read-only"`, `glob: string` | `{ effect, glob }` | Add a workspace membership constraint (§14.3 overlay): `add` admits files git misses, `ignore` drops tracked matches, `read-only` admits for read but refuses edits. Immediate. |
740
+ | `session.unconstrain` | `effect: "add" \| "ignore" \| "read-only"`, `glob: string` | `{ effect, glob }` | Remove a membership constraint — the inverse of `session.constrain`. Immediate. |
741
+ | `session.constraints` | none | `{ constraints }` | List the attached session's membership constraints. |
742
+
743
+ **Re-binding.** `session.create` and `session.attach` may be called on a connection that already has a session attached — the connection switches in place, releasing the prior client loop (closed at 200). No reconnect needed to change session or run. {§13.5-rebind}
739
744
 
740
745
  **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}
741
746
 
@@ -745,6 +750,7 @@ registry.register("loop.run", {
745
750
  |-------------------|-------------------------------------|------------------------|-------|
746
751
  | `loop.run` | `prompt: string`, `maxTurns?: number`, `alias?: string`, `flags?: LoopFlags`, `persona?: string` | `{ loopId, turnIds, finalStatus, hitMaxTurns, reason }` | Model-driven loop. Optional `alias` overrides the boot-time `PLURNK_MODEL`. Optional `flags` carries per-loop flags (currently `{yolo?: boolean}`; more arrive as wired — see §0.5). Optional `persona` sets the loop-level persona (highest precedence in the cascade). Streams `log/entry` and `loop/proposal` notifications during. `longRunning: true`. {§13.5-loop-run} |
747
752
  | `loop.resolve` | `logEntryId: number`, `decision: "accept" \| "reject" \| "cancel"`, `body?: string`, `outcome?: string` | `{ status, logEntryId }` | Resolve a pending proposal (status=202 log entry). Engine.dispatch unpauses on resolution. |
753
+ | `loop.cancel` | `reason?: string` | `{ cancelled, runId, reason }` | Abort the attached run's active drain. `{cancelled: true}` if a drain was running, `{false}` if idle. Cancelled loops close at 499; queued-but-unclaimed loops stay enqueued. Default reason `user_cancelled`. {§13.5-loop-cancel} |
748
754
  | `providers.list` | none | `{ aliases: ProviderAlias[] }` | Lists configured `PLURNK_MODEL_<alias>` entries with `{alias, provider, model, active}`. Clients use to populate model-selection UI. |
749
755
 
750
756
  **Reads**
@@ -791,6 +797,8 @@ Server-initiated events on the same WebSocket.
791
797
  | `loop/proposal` | `{ logEntryId, sessionId, runId, loopId, turnId, op, target, body, attrs, flags }` | Dispatch pauses on status=202. Carries `flags` so server-YOLO clients can suppress review UI. Client responds with `loop.resolve` (or `PLURNK_PROPOSAL_TIMEOUT_MS` fires). |
792
798
  | `session/created` | `{ id, name, projectRoot, persona }` | Any client creates a session. |
793
799
  | `stream/event` | `{ entryId, channel, state, contentLength }` | Channel content grows or state transitions. {§13.6-stream-event-on-channel-change} |
800
+ | `stream/concluded` | `{ entryId, target, subscriptionId, scheme, closeStatus, summary, wakeAction, wakeLoopId? }` | A streaming subscription closed (subprocess finished / errored / cancelled). `wakeAction` says whether the daemon opened a fresh loop to surface the conclusion to the model. {§13.6-stream-concluded} |
801
+ | `telemetry/event` | `{ loopId, event: TelemetryEvent }` | A TelemetryEvent (parse error, engine-rail strike/cycle/sudden-death, scheme/provider failure) was buffered — the same envelope the model sees on the next packet, delivered live for client surfacing. {§13.6-telemetry-event} |
794
802
 
795
803
  `stream/event` carries metadata only, never content. Clients fetch via `entry.read({target})`. **Every notification envelope carries its `sessionId`** (and `runId` where the emitter has it) so a multi-session client — one connection, many sessions — can route it ({§13.6-envelope-carries-sessionid}); the broadcast stays session-scoped too.
796
804
 
package/dist/Paths.d.ts CHANGED
@@ -2,6 +2,7 @@ export default class Paths {
2
2
  #private;
3
3
  static migrations: string;
4
4
  static instructionsSystem: string;
5
+ static grammarGbnf: string;
5
6
  static defaultPersona: string;
6
7
  static defaultRequirements: string;
7
8
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Paths.d.ts","sourceRoot":"","sources":["../src/Paths.ts"],"names":[],"mappings":"AAaA,MAAM,CAAC,OAAO,OAAO,KAAK;;IAItB,MAAM,CAAC,UAAU,SAA8C;IAC/D,MAAM,CAAC,kBAAkB,SAA6C;IAKtE,MAAM,CAAC,cAAc,SAAkC;IAIvD,MAAM,CAAC,mBAAmB,SAAuC;CAuBpE"}
1
+ {"version":3,"file":"Paths.d.ts","sourceRoot":"","sources":["../src/Paths.ts"],"names":[],"mappings":"AAaA,MAAM,CAAC,OAAO,OAAO,KAAK;;IAItB,MAAM,CAAC,UAAU,SAA8C;IAC/D,MAAM,CAAC,kBAAkB,SAA6C;IAKtE,MAAM,CAAC,WAAW,SAAoD;IAKtE,MAAM,CAAC,cAAc,SAAkC;IAIvD,MAAM,CAAC,mBAAmB,SAAuC;CAuBpE"}
package/dist/Paths.js CHANGED
@@ -14,6 +14,11 @@ export default class Paths {
14
14
  static #GRAMMAR_ROOT = dirname(fileURLToPath(import.meta.resolve("@plurnk/plurnk-grammar/package.json")));
15
15
  static migrations = resolve(Paths.#PACKAGE_ROOT, "migrations");
16
16
  static instructionsSystem = resolve(Paths.#GRAMMAR_ROOT, "plurnk.md");
17
+ // The GBNF artifact (the full multi-op root) for grammar-constrained
18
+ // sampling, resolved from the grammar package like the sysprompt above.
19
+ // Plumbed to the provider per generate() when PLURNK_PROVIDERS_GBNF is
20
+ // enabled; the service holds no opinion about its content or root.
21
+ static grammarGbnf = resolve(Paths.#GRAMMAR_ROOT, "dist/plurnk.gbnf");
17
22
  // packet.system.persona DEFAULT. Cascade at packet-build time is
18
23
  // loops.persona > runs.persona > sessions.persona > this file
19
24
  // RPC overrides on loop.run / session.attach / session.create populate
package/dist/Paths.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Paths.js","sourceRoot":"","sources":["../src/Paths.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,EAAE;AACF,gDAAgD;AAChD,+EAA+E;AAC/E,6EAA6E;AAC7E,oCAAoC;AACpC,EAAE;AACF,8EAA8E;AAC9E,mDAAmD;AAEnD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE7C,MAAM,CAAC,OAAO,OAAO,KAAK;IACtB,MAAM,CAAC,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;IAC9E,MAAM,CAAC,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,qCAAqC,CAAC,CAAC,CAAC,CAAC;IAE1G,MAAM,CAAC,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC;IAC/D,MAAM,CAAC,kBAAkB,GAAG,OAAO,CAAC,KAAK,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;IACtE,iEAAiE;IACjE,gEAAgE;IAChE,uEAAuE;IACvE,iEAAiE;IACjE,MAAM,CAAC,cAAc,GAAG,KAAK,CAAC,sBAAsB,EAAE,CAAC;IACvD,uEAAuE;IACvE,uEAAuE;IACvE,0EAA0E;IAC1E,MAAM,CAAC,mBAAmB,GAAG,KAAK,CAAC,2BAA2B,EAAE,CAAC;IAEjE,yEAAyE;IACzE,kEAAkE;IAClE,mEAAmE;IACnE,oDAAoD;IACpD,MAAM,CAAC,sBAAsB;QACzB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;QACvC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5C,OAAO,OAAO,CAAC,KAAK,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;QAC7C,CAAC;QACD,OAAO,OAAO,CAAC,KAAK,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC;IACtD,CAAC;IAED,4EAA4E;IAC5E,2EAA2E;IAC3E,MAAM,CAAC,2BAA2B;QAC9B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;QAC5C,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5C,OAAO,OAAO,CAAC,KAAK,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;QAC7C,CAAC;QACD,OAAO,OAAO,CAAC,KAAK,CAAC,aAAa,EAAE,iBAAiB,CAAC,CAAC;IAC3D,CAAC"}
1
+ {"version":3,"file":"Paths.js","sourceRoot":"","sources":["../src/Paths.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,EAAE;AACF,gDAAgD;AAChD,+EAA+E;AAC/E,6EAA6E;AAC7E,oCAAoC;AACpC,EAAE;AACF,8EAA8E;AAC9E,mDAAmD;AAEnD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE7C,MAAM,CAAC,OAAO,OAAO,KAAK;IACtB,MAAM,CAAC,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;IAC9E,MAAM,CAAC,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,qCAAqC,CAAC,CAAC,CAAC,CAAC;IAE1G,MAAM,CAAC,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC;IAC/D,MAAM,CAAC,kBAAkB,GAAG,OAAO,CAAC,KAAK,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;IACtE,qEAAqE;IACrE,wEAAwE;IACxE,uEAAuE;IACvE,mEAAmE;IACnE,MAAM,CAAC,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,aAAa,EAAE,kBAAkB,CAAC,CAAC;IACtE,iEAAiE;IACjE,gEAAgE;IAChE,uEAAuE;IACvE,iEAAiE;IACjE,MAAM,CAAC,cAAc,GAAG,KAAK,CAAC,sBAAsB,EAAE,CAAC;IACvD,uEAAuE;IACvE,uEAAuE;IACvE,0EAA0E;IAC1E,MAAM,CAAC,mBAAmB,GAAG,KAAK,CAAC,2BAA2B,EAAE,CAAC;IAEjE,yEAAyE;IACzE,kEAAkE;IAClE,mEAAmE;IACnE,oDAAoD;IACpD,MAAM,CAAC,sBAAsB;QACzB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;QACvC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5C,OAAO,OAAO,CAAC,KAAK,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;QAC7C,CAAC;QACD,OAAO,OAAO,CAAC,KAAK,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC;IACtD,CAAC;IAED,4EAA4E;IAC5E,2EAA2E;IAC3E,MAAM,CAAC,2BAA2B;QAC9B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;QAC5C,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5C,OAAO,OAAO,CAAC,KAAK,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;QAC7C,CAAC;QACD,OAAO,OAAO,CAAC,KAAK,CAAC,aAAa,EAAE,iBAAiB,CAAC,CAAC;IAC3D,CAAC"}
@@ -68,6 +68,11 @@ export default class Engine {
68
68
  tokenize?: (text: string) => number;
69
69
  });
70
70
  setExecutors(executors: ExecutorRegistry): void;
71
+ loopUsage(loopId: number): Promise<{
72
+ promptTokens: number;
73
+ completionTokens: number;
74
+ costPico: number;
75
+ }>;
71
76
  runLoop({ provider, messages, persona, requirements, sessionId, runId, loopId, maxTurns, maxStrikes, minCycles, maxCyclePeriod, origin, signal, onDispatch, }: {
72
77
  provider: Provider;
73
78
  messages: ChatMessage[];
@@ -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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"}
@@ -4,15 +4,19 @@ import { Mimetypes, emptyRegistry } from "@plurnk/plurnk-mimetypes";
4
4
  import EntryCrud from "../schemes/_entry-crud.js";
5
5
  import EntryManifest from "../schemes/_entry-manifest.js";
6
6
  import GitMembership from "./git-membership.js";
7
+ import GitState from "./git-state.js";
7
8
  import { DEFAULT_LOOP_FLAGS } from "./scheme-types.js";
8
9
  import { LineMarkerOps, MimetypeBinary, editedSpan } from "../content/index.js";
10
+ import { readFile } from "node:fs/promises";
11
+ import Paths from "../Paths.js";
12
+ import SchemeCtxImpl from "./caps/SchemeCtxImpl.js";
9
13
  // Shared module imported by both Engine and bin/digest.ts, so wire
10
14
  // projection and digest projection are structurally one function — no
11
15
  // drift between wire and digest possible.
12
16
  import PacketWire from "./packet-wire.js";
13
17
  // SPEC §3.6: writer must be in target scheme's manifest.writableBy.
14
18
  // OPEN/FOLD/READ/FIND are not gated — they curate the log or read, never mutating an entry.
15
- const MUTATING_OPS = new Set(["EDIT", "SEND", "COPY", "MOVE", "EXEC"]);
19
+ const MUTATING_OPS = new Set(["EDIT", "SEND", "COPY", "MOVE", "EXEC", "KILL"]);
16
20
  const DEFAULT_MAX_STRIKES = 3;
17
21
  const DEFAULT_MAX_COMMANDS = 99;
18
22
  const DEFAULT_BUDGET_CEILING = 0.9;
@@ -228,6 +232,8 @@ class Engine {
228
232
  // status code but has no way to surface why the loop degraded.
229
233
  // Per-grammar 0.17.0 protocol — see SPEC §15.1.
230
234
  #telemetryEventNotify;
235
+ // Cached plurnk GBNF — read once on the first constrained generate (#189).
236
+ #gbnfCache = null;
231
237
  constructor({ db, schemes, mimetypes, streamEventNotify, wakeRunNotify, telemetryEventNotify, tokenize }) {
232
238
  this.#db = db;
233
239
  this.#schemes = schemes;
@@ -252,6 +258,28 @@ class Engine {
252
258
  setExecutors(executors) {
253
259
  this.#executors = executors;
254
260
  }
261
+ // Grammar-constrained sampling (#189): when PLURNK_PROVIDERS_GBNF is enabled
262
+ // (the only knob — default-on in .env.example), hand the provider the plurnk
263
+ // GBNF (the full shipped multi-op root, read once + cached). The provider
264
+ // attaches it iff the backend supports it and silently drops it otherwise —
265
+ // capability is providers' concern, not ours. Pure plumbing grammar→provider.
266
+ async #grammarConstraint() {
267
+ if (process.env.PLURNK_PROVIDERS_GBNF !== "1")
268
+ return undefined;
269
+ this.#gbnfCache ??= await readFile(Paths.grammarGbnf, "utf8");
270
+ return this.#gbnfCache;
271
+ }
272
+ // Per-loop usage totals (#197): SUM the loop's turns (usage is stored per
273
+ // turn, §14.2). Surfaced on loop.run + loop/terminated so clients render real
274
+ // token/cost numbers. costPico is the stored pico-dollar unit.
275
+ async loopUsage(loopId) {
276
+ const row = await this.#db.engine_loop_usage.get({ loop_id: loopId });
277
+ return {
278
+ promptTokens: row?.prompt ?? 0,
279
+ completionTokens: row?.completion ?? 0,
280
+ costPico: row?.cost_pico ?? 0,
281
+ };
282
+ }
255
283
  #pushTelemetry(sessionId, loopId, event) {
256
284
  const existing = this.#telemetryBuffer.get(loopId);
257
285
  if (existing === undefined)
@@ -450,7 +478,7 @@ class Engine {
450
478
  };
451
479
  await this.dispatch({
452
480
  statement: promptStmt, sessionId, runId, loopId, turnId,
453
- sequence: nextActionIndex, origin: "system",
481
+ sequence: nextActionIndex, origin: "system", onDispatch,
454
482
  });
455
483
  nextActionIndex++;
456
484
  }
@@ -487,19 +515,23 @@ class Engine {
487
515
  // reconciled) as system EDIT rows, before the packet composes; advance
488
516
  // the action index past them so model ops continue after.
489
517
  nextActionIndex += await this.#materializeEnvironmentDeltas({ sessionId, runId, loopId, turnId, fromSequence: nextActionIndex });
518
+ // SPEC §15.1 — git working-tree state for the telemetry section, read once
519
+ // (a service-side `git status` shell-out) and threaded into the budget
520
+ // rebuild too so it isn't re-shelled on overflow.
521
+ const gitStatus = await GitState.status(this.#db, sessionId, this.#loopAborts.get(loopId)?.signal);
490
522
  // Build the spec'd packet (Packet.json) request half. #buildLog
491
523
  // queries log_entries scoped to the run — the prompt entry just
492
524
  // written (if turn 1) is part of that query result.
493
525
  let requestPacket = await this.#buildRequestPacket({
494
526
  initialMessages: messages, persona, requirements, runId, loopId,
495
- currentTurnSeq: seq, provider,
527
+ currentTurnSeq: seq, provider, gitStatus,
496
528
  });
497
529
  // SPEC §14.4 — budget grinder, pre-LLM: reclaim window on actual overflow.
498
530
  const enforced = await this.#enforceBudget({
499
531
  packet: requestPacket, provider, runId, loopId, turnId, sessionId, turnNumber,
500
532
  rebuild: (telemetryErrors) => this.#buildRequestPacket({
501
533
  initialMessages: messages, persona, requirements, runId, loopId,
502
- currentTurnSeq: seq, provider, telemetryErrors,
534
+ currentTurnSeq: seq, provider, telemetryErrors, gitStatus,
503
535
  }),
504
536
  });
505
537
  requestPacket = enforced.packet;
@@ -515,7 +547,13 @@ class Engine {
515
547
  return { turnId, status: 413, statuses: [], fingerprint: "", budgetStruck: enforced.struck, budgetHardStop: true };
516
548
  }
517
549
  const modelMessages = this.#packetToWireMessages(requestPacket);
518
- const response = await provider.generate({ messages: modelMessages, signal });
550
+ // maxTokens = remaining context window (loop policy, plurnk-providers#10).
551
+ // The 0.28.0 EOS-forcing root terminates the turn at the status SEND, but a
552
+ // grammar can't bound degeneration *inside* a statement body — this caps the
553
+ // decode at the free window so a runaway can't reach the context wall.
554
+ const genCeiling = _a.computeCeiling(provider.contextSize, this.#budgetCeiling);
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 });
519
557
  // Engine splits wire-level response: emission (content, reasoning,
520
558
  // parsed ops) → packet.assistant per Packet.json §assistant;
521
559
  // call-metadata (usage, finishReason, model) → Turn columns per
@@ -676,7 +714,7 @@ class Engine {
676
714
  // and §user) BEFORE the provider call. The same packet object is then
677
715
  // completed with assistant + assistantRaw after the model responds, so
678
716
  // the stored packet and the wire payload share one source of truth.
679
- async #buildRequestPacket({ initialMessages, persona: defaultPersona, requirements, runId, loopId, currentTurnSeq, provider, telemetryErrors: presetTelemetry, }) {
717
+ async #buildRequestPacket({ initialMessages, persona: defaultPersona, requirements, runId, loopId, currentTurnSeq, provider, gitStatus, telemetryErrors: presetTelemetry, }) {
680
718
  const byRole = (role) => initialMessages.filter((m) => m.role === role).map((m) => m.content).join("\n\n");
681
719
  const system_definition = byRole("system");
682
720
  // user.prompt sources from the loop's most recent prompt entry first
@@ -711,7 +749,7 @@ class Engine {
711
749
  const ceiling = _a.computeCeiling(provider.contextSize, this.#budgetCeiling);
712
750
  const scratch = {
713
751
  system: { system_definition, persona, log },
714
- user: { prompt, telemetry: { budget: "", errors: telemetryErrors }, system_requirements: requirements },
752
+ user: { prompt, telemetry: { budget: "", errors: telemetryErrors, git: gitStatus }, system_requirements: requirements },
715
753
  };
716
754
  const sections = PacketWire.measureBudgetSections(scratch, countTokens);
717
755
  scratch.user.telemetry.budget = this.#renderBudget(sections, ceiling);
@@ -725,7 +763,7 @@ class Engine {
725
763
  .replace(TOKEN_PERCENT_PLACEHOLDER, String(percent))
726
764
  .replace(TOKENS_FREE_PLACEHOLDER, String(tokensFree));
727
765
  const system = { tokens: 0, system_definition, persona, log };
728
- const user = { tokens: 0, prompt, telemetry: { budget, errors: telemetryErrors }, system_requirements: requirements };
766
+ const user = { tokens: 0, prompt, telemetry: { budget, errors: telemetryErrors, git: gitStatus }, system_requirements: requirements };
729
767
  system.tokens = countTokens(PacketWire.renderSystemContent(system));
730
768
  user.tokens = countTokens(PacketWire.renderUserContent(user));
731
769
  return { system, user };
@@ -955,6 +993,12 @@ class Engine {
955
993
  else if (statement.op === "MOVE") {
956
994
  result = await this.#handleMove(statement, schemeCtx);
957
995
  }
996
+ else if (statement.op === "KILL") {
997
+ result = await this.#handleKill(statement, schemeCtx);
998
+ }
999
+ else if (statement.op === "PLAN") {
1000
+ result = this.#handlePlan(statement);
1001
+ }
958
1002
  else if (statement.op === "EXEC") {
959
1003
  // EXEC's target slot is `cwd`, not a scheme address.
960
1004
  // Per plurnk.md the op routes unconditionally to the
@@ -1339,6 +1383,51 @@ class Engine {
1339
1383
  return { status: delResult.status };
1340
1384
  return copyResult;
1341
1385
  }
1386
+ // KILL — scheme-polymorphic destroy (plurnk-grammar#203 / 0.28.0). Entry-KILL
1387
+ // permanently deletes the entry: the canonical delete now, MOVE→/dev/null
1388
+ // retired from the model's vocabulary. Process-KILL (exec://) aborts the
1389
+ // running spawn's controller (the same teardown loop.cancel rides), addressed
1390
+ // by coordinate pathname (#203). The KILL body is an opaque
1391
+ // annotation with no runtime meaning; it survives into the log row's tx for
1392
+ // free via the statement serialization. Status: 200 killed · 404 unknown ·
1393
+ // 405 log:// (append-only) · 403 writableBy (the #checkWritable gate, KILL ∈
1394
+ // MUTATING_OPS) · 200/404 exec (killed / not running) · 501 no-kill/delete scheme.
1395
+ async #handleKill(statement, ctx) {
1396
+ if (statement.op !== "KILL")
1397
+ throw new Error("unreachable");
1398
+ const path = statement.target;
1399
+ if (path === null)
1400
+ return { status: 400, error: "KILL requires a target path" };
1401
+ const schemeName = this.#schemeNameOf(path);
1402
+ if (schemeName === null)
1403
+ return { status: 400, error: "KILL target must be a URL path with a scheme" };
1404
+ if (schemeName === "log")
1405
+ return { status: 405, error: "log:// is append-only; KILL must bounce" };
1406
+ if (schemeName === "exec") {
1407
+ const execHandler = this.#schemes.get("exec");
1408
+ if (execHandler === undefined || typeof execHandler.kill !== "function")
1409
+ return { status: 501 };
1410
+ return execHandler.kill(pathnameFromPath(path));
1411
+ }
1412
+ const handler = this.#schemes.get(schemeName);
1413
+ if (handler === undefined || typeof handler.deleteEntry !== "function")
1414
+ return { status: 501 };
1415
+ const delResult = await handler.deleteEntry(pathnameFromPath(path), ctx);
1416
+ return { status: delResult.status };
1417
+ }
1418
+ // PLAN — undocumented reasoning op (plurnk-grammar 0.30.0, the 11th op). A pure
1419
+ // no-op: the body is the model's in-content reasoning, which lands in the log
1420
+ // row's tx for free via statement serialization, no runtime effect (PLAN ∉
1421
+ // MUTATING_OPS). NOT taught in plurnk.md by design — reserved for a future model
1422
+ // that must reason in the content field (no separate reasoning channel). gemma
1423
+ // reasons on its own channel via the relaxed root, is never shown PLAN, and never
1424
+ // emits it; this handler exists only so the op resolves cleanly if we ever
1425
+ // deliberately reach for it (which would also require a plurnk.md override).
1426
+ #handlePlan(statement) {
1427
+ if (statement.op !== "PLAN")
1428
+ throw new Error("unreachable");
1429
+ return { status: 200 };
1430
+ }
1342
1431
  async #copyOrchestration({ statement, srcPath, dstPath, ctx }) {
1343
1432
  const srcSchemeName = this.#schemeNameOf(srcPath);
1344
1433
  const dstSchemeName = this.#schemeNameOf(dstPath);
@@ -1433,6 +1522,13 @@ class Engine {
1433
1522
  const method = handler[methodName];
1434
1523
  if (typeof method !== "function")
1435
1524
  return { status: 501 };
1525
+ // External @plurnk/plurnk-schemes-* siblings receive the DB-free SchemeCtx
1526
+ // (caps), never the raw PlurnkSchemeContext (schemes SPEC §5). The dynamic
1527
+ // dispatch is typed for in-tree schemes; the cast bridges the ctx shapes —
1528
+ // the sibling reads caps, the in-tree handler reads db.
1529
+ if (this.#schemes.isExternal(schemeName)) {
1530
+ return method.call(handler, statement, new SchemeCtxImpl(ctx, schemeName));
1531
+ }
1436
1532
  return method.call(handler, statement, ctx);
1437
1533
  }
1438
1534
  // Bare paths default to the file scheme per plurnk.md (grammar sysprompt):
@@ -1441,8 +1537,9 @@ class Engine {
1441
1537
  #schemeNameOf(path) {
1442
1538
  if (path === null)
1443
1539
  return null;
1540
+ // http + https are one scheme — the http sibling owns both prefixes (#195).
1444
1541
  if (path.kind === "url")
1445
- return path.scheme;
1542
+ return path.scheme === "https" ? "http" : path.scheme;
1446
1543
  return "file"; // local (bare) → file
1447
1544
  }
1448
1545
  async #writeLog({ statement, result, runId, loopId, turnId, sequence, origin, }) {