@plurnk/plurnk-service 0.16.0 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SPEC.md +17 -8
- package/dist/Paths.d.ts +1 -0
- package/dist/Paths.d.ts.map +1 -1
- package/dist/Paths.js +5 -0
- package/dist/Paths.js.map +1 -1
- package/dist/core/ChannelWrite.d.ts +4 -0
- package/dist/core/ChannelWrite.d.ts.map +1 -1
- package/dist/core/ChannelWrite.js +8 -0
- package/dist/core/ChannelWrite.js.map +1 -1
- package/dist/core/Engine.d.ts +5 -0
- package/dist/core/Engine.d.ts.map +1 -1
- package/dist/core/Engine.js +137 -18
- package/dist/core/Engine.js.map +1 -1
- package/dist/core/ExecutorRegistry.d.ts +9 -1
- package/dist/core/ExecutorRegistry.d.ts.map +1 -1
- package/dist/core/ExecutorRegistry.js +21 -28
- package/dist/core/ExecutorRegistry.js.map +1 -1
- package/dist/core/SchemeRegistry.d.ts +2 -0
- package/dist/core/SchemeRegistry.d.ts.map +1 -1
- package/dist/core/SchemeRegistry.js +52 -0
- package/dist/core/SchemeRegistry.js.map +1 -1
- package/dist/core/git-membership.d.ts.map +1 -1
- package/dist/core/git-membership.js +10 -3
- package/dist/core/git-membership.js.map +1 -1
- package/dist/core/git-state.d.ts +15 -0
- package/dist/core/git-state.d.ts.map +1 -0
- package/dist/core/git-state.js +65 -0
- package/dist/core/git-state.js.map +1 -0
- package/dist/core/packet-wire.d.ts +1 -0
- package/dist/core/packet-wire.d.ts.map +1 -1
- package/dist/core/packet-wire.js +8 -1
- package/dist/core/packet-wire.js.map +1 -1
- package/dist/core/scheme-types.d.ts +9 -0
- package/dist/core/scheme-types.d.ts.map +1 -1
- package/dist/schemes/Exec.d.ts +4 -0
- package/dist/schemes/Exec.d.ts.map +1 -1
- package/dist/schemes/Exec.js +24 -1
- package/dist/schemes/Exec.js.map +1 -1
- package/dist/schemes/File.d.ts +8 -10
- package/dist/schemes/File.d.ts.map +1 -1
- package/dist/schemes/File.js +81 -114
- package/dist/schemes/File.js.map +1 -1
- package/dist/schemes/Log.d.ts +2 -10
- package/dist/schemes/Log.d.ts.map +1 -1
- package/dist/schemes/Log.js +42 -9
- package/dist/schemes/Log.js.map +1 -1
- package/dist/schemes/_entry-crud.d.ts +2 -0
- package/dist/schemes/_entry-crud.d.ts.map +1 -1
- package/dist/schemes/_entry-crud.js +4 -0
- package/dist/schemes/_entry-crud.js.map +1 -1
- package/dist/schemes/_entry-find.d.ts.map +1 -1
- package/dist/schemes/_entry-find.js +15 -1
- package/dist/schemes/_entry-find.js.map +1 -1
- package/dist/schemes/_entry-graph.d.ts +11 -0
- package/dist/schemes/_entry-graph.d.ts.map +1 -0
- package/dist/schemes/_entry-graph.js +81 -0
- package/dist/schemes/_entry-graph.js.map +1 -0
- package/dist/schemes/_entry-manifest.d.ts.map +1 -1
- package/dist/schemes/_entry-manifest.js +32 -5
- package/dist/schemes/_entry-manifest.js.map +1 -1
- package/dist/schemes/_entry-ops.d.ts.map +1 -1
- package/dist/schemes/_entry-ops.js +12 -1
- package/dist/schemes/_entry-ops.js.map +1 -1
- package/dist/server/ClientConnection.d.ts.map +1 -1
- package/dist/server/ClientConnection.js +5 -2
- package/dist/server/ClientConnection.js.map +1 -1
- package/dist/server/Daemon.d.ts.map +1 -1
- package/dist/server/Daemon.js +8 -0
- package/dist/server/Daemon.js.map +1 -1
- package/dist/server/MethodRegistry.d.ts +5 -0
- package/dist/server/MethodRegistry.d.ts.map +1 -1
- package/dist/server/MethodRegistry.js.map +1 -1
- package/dist/server/methods/loop_run.d.ts.map +1 -1
- package/dist/server/methods/loop_run.js +1 -0
- package/dist/server/methods/loop_run.js.map +1 -1
- package/dist/server/methods/session_attach.d.ts.map +1 -1
- package/dist/server/methods/session_attach.js +0 -3
- package/dist/server/methods/session_attach.js.map +1 -1
- package/dist/server/methods/session_create.d.ts.map +1 -1
- package/dist/server/methods/session_create.js +1 -3
- package/dist/server/methods/session_create.js.map +1 -1
- package/migrations/0000-00-00.01_schema.sql +39 -1
- package/package.json +109 -113
package/SPEC.md
CHANGED
|
@@ -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
|
|
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
|
|
|
@@ -305,14 +305,15 @@ new Mimetypes({
|
|
|
305
305
|
|
|
306
306
|
Fallback heuristic is a boot-before-provider-resolved tripwire.
|
|
307
307
|
|
|
308
|
-
**Manifest build.** `EntryManifest.buildManifestBody` calls `process({ content, hint })` per channel
|
|
308
|
+
**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
309
|
|
|
310
310
|
```ts
|
|
311
|
-
const result = await mimetypes.process({ content: r.content, hint: r.mimetype });
|
|
311
|
+
const result = await mimetypes.process({ content: r.content, hint: r.mimetype }, { channels: ["symbols", "references"] });
|
|
312
312
|
entry.channels[r.channel] = { mimetype: r.mimetype, tokens: tokenize(r.content), lines: result.totalLines };
|
|
313
|
+
if (isBody) await EntryGraph.populateFrom(db, sessionId, r.entry_id, result.symbols ?? [], result.references ?? []);
|
|
313
314
|
```
|
|
314
315
|
|
|
315
|
-
`hint` short-circuits detection. The service consumes
|
|
316
|
+
`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
317
|
|
|
317
318
|
**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
319
|
|
|
@@ -338,7 +339,7 @@ Every entry is uniformly listed in `plurnk://manifest.json` (§15) and READable
|
|
|
338
339
|
|
|
339
340
|
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
341
|
|
|
341
|
-
- Cross-mimetype COPY/MOVE → 415, never coerces (§6.4).
|
|
342
|
+
- Cross-mimetype COPY/MOVE → 415, never coerces (§6.4). {§5.3-cross-mimetype-415}
|
|
342
343
|
|
|
343
344
|
### §5.5 Channel selection in the DSL
|
|
344
345
|
|
|
@@ -436,8 +437,8 @@ Returns 201 on success. Same- and cross-scheme COPY share the orchestrator. {§6
|
|
|
436
437
|
|
|
437
438
|
AST: `{ op: "MOVE", target (source), body: dest | null, signal: tags | null, lineMarker? }`.
|
|
438
439
|
|
|
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
|
-
- **
|
|
440
|
+
- **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}
|
|
441
|
+
- **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
442
|
|
|
442
443
|
Log history preserved — `log_entries` stores path tuple as text, not FK to `entries.id`.
|
|
443
444
|
|
|
@@ -730,12 +731,17 @@ registry.register("loop.run", {
|
|
|
730
731
|
|
|
731
732
|
| Method | Params | Result | Notes |
|
|
732
733
|
|------------------------|---------------------|-------------------|-------|
|
|
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. |
|
|
734
|
+
| `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
735
|
| `session.list` | none | `{ sessions: Session[] }` | Lists all sessions. |
|
|
735
736
|
| `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
737
|
| `session.runs` | `id?: number` | `{ runs: Run[] }` | Lists runs in a session (defaults to attached session); most-recent first. |
|
|
737
738
|
| `session.set_root` | `projectRoot: string \| null` | `{ projectRoot }` | Update the workspace pointer on the attached session. Null reverts to headless. |
|
|
738
739
|
| `session.set_persona` | `persona: string \| null` | `{ persona }` | Update the session-level persona. Null clears the override (falls through to PLURNK_PERSONA file). |
|
|
740
|
+
| `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. |
|
|
741
|
+
| `session.unconstrain` | `effect: "add" \| "ignore" \| "read-only"`, `glob: string` | `{ effect, glob }` | Remove a membership constraint — the inverse of `session.constrain`. Immediate. |
|
|
742
|
+
| `session.constraints` | none | `{ constraints }` | List the attached session's membership constraints. |
|
|
743
|
+
|
|
744
|
+
**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
745
|
|
|
740
746
|
**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
747
|
|
|
@@ -745,6 +751,7 @@ registry.register("loop.run", {
|
|
|
745
751
|
|-------------------|-------------------------------------|------------------------|-------|
|
|
746
752
|
| `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
753
|
| `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. |
|
|
754
|
+
| `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
755
|
| `providers.list` | none | `{ aliases: ProviderAlias[] }` | Lists configured `PLURNK_MODEL_<alias>` entries with `{alias, provider, model, active}`. Clients use to populate model-selection UI. |
|
|
749
756
|
|
|
750
757
|
**Reads**
|
|
@@ -791,6 +798,8 @@ Server-initiated events on the same WebSocket.
|
|
|
791
798
|
| `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
799
|
| `session/created` | `{ id, name, projectRoot, persona }` | Any client creates a session. |
|
|
793
800
|
| `stream/event` | `{ entryId, channel, state, contentLength }` | Channel content grows or state transitions. {§13.6-stream-event-on-channel-change} |
|
|
801
|
+
| `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} |
|
|
802
|
+
| `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
803
|
|
|
795
804
|
`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
805
|
|
package/dist/Paths.d.ts
CHANGED
package/dist/Paths.d.ts.map
CHANGED
|
@@ -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"}
|
|
@@ -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;;
|
|
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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"}
|
package/dist/core/Engine.d.ts
CHANGED
|
@@ -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":"AACA,OAAO,KAAK,EAAE,eAAe,EAA4D,MAAM,wBAAwB,CAAC;AAMxH,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAiB,MAAM,0BAA0B,CAAC;AACpE,OAAO,KAAK,EAAE,EAAE,EAAc,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"Engine.d.ts","sourceRoot":"","sources":["../../src/core/Engine.ts"],"names":[],"mappings":"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"}
|
package/dist/core/Engine.js
CHANGED
|
@@ -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
|
-
|
|
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, runId: String(runId), 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
|
|
@@ -1022,6 +1066,16 @@ class Engine {
|
|
|
1022
1066
|
// with the failure outcome — engine treats it like a client
|
|
1023
1067
|
// rejection.
|
|
1024
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
|
+
}
|
|
1025
1079
|
const post = await this.#applyResolution(logEntryId, effective);
|
|
1026
1080
|
return post;
|
|
1027
1081
|
}
|
|
@@ -1034,7 +1088,11 @@ class Engine {
|
|
|
1034
1088
|
// EXEC routes to the exec scheme regardless of target (cwd, not
|
|
1035
1089
|
// a scheme address). All other ops resolve their handler from
|
|
1036
1090
|
// statement.target's scheme.
|
|
1037
|
-
|
|
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);
|
|
1038
1096
|
if (schemeName === null)
|
|
1039
1097
|
return resolution;
|
|
1040
1098
|
const handler = this.#schemes.get(schemeName);
|
|
@@ -1316,29 +1374,78 @@ class Engine {
|
|
|
1316
1374
|
const dstPath = statement.body;
|
|
1317
1375
|
if (srcPath === null)
|
|
1318
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" };
|
|
1319
1381
|
const srcSchemeName = this.#schemeNameOf(srcPath);
|
|
1320
1382
|
if (srcSchemeName === null)
|
|
1321
1383
|
return { status: 400, error: "MOVE source must be a URL path with a scheme" };
|
|
1322
1384
|
const srcHandler = this.#schemes.get(srcSchemeName);
|
|
1323
1385
|
if (srcHandler === undefined || typeof srcHandler.deleteEntry !== "function")
|
|
1324
1386
|
return { status: 501 };
|
|
1325
|
-
//
|
|
1326
|
-
// MOVE deletes the source entry. SPEC §6.5.
|
|
1327
|
-
if (dstPath === null || pathnameFromPath(dstPath) === "/dev/null") {
|
|
1328
|
-
const srcPathname = pathnameFromPath(srcPath);
|
|
1329
|
-
const delResult = await srcHandler.deleteEntry(srcPathname, ctx);
|
|
1330
|
-
return { status: delResult.status };
|
|
1331
|
-
}
|
|
1332
|
-
// Relocation: COPY then DELETE source
|
|
1387
|
+
// Relocation: COPY then DELETE source.
|
|
1333
1388
|
const copyResult = await this.#copyOrchestration({ statement, srcPath, dstPath, ctx });
|
|
1334
1389
|
if (copyResult.status >= 400)
|
|
1335
1390
|
return copyResult;
|
|
1336
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
|
+
}
|
|
1337
1399
|
const delResult = await srcHandler.deleteEntry(srcPathname, ctx);
|
|
1338
1400
|
if (delResult.status >= 400)
|
|
1339
1401
|
return { status: delResult.status };
|
|
1340
1402
|
return copyResult;
|
|
1341
1403
|
}
|
|
1404
|
+
// KILL — scheme-polymorphic destroy (plurnk-grammar#203 / 0.28.0). Entry-KILL
|
|
1405
|
+
// permanently deletes the entry: the canonical delete now, MOVE→/dev/null
|
|
1406
|
+
// retired from the model's vocabulary. Process-KILL (exec://) aborts the
|
|
1407
|
+
// running spawn's controller (the same teardown loop.cancel rides), addressed
|
|
1408
|
+
// by coordinate pathname (#203). The KILL body is an opaque
|
|
1409
|
+
// annotation with no runtime meaning; it survives into the log row's tx for
|
|
1410
|
+
// free via the statement serialization. Status: 200 killed · 404 unknown ·
|
|
1411
|
+
// 405 log:// (append-only) · 403 writableBy (the #checkWritable gate, KILL ∈
|
|
1412
|
+
// MUTATING_OPS) · 200/410/304/404 exec (killed / killed-earlier / exited / unknown) · 501 no-kill/delete scheme.
|
|
1413
|
+
async #handleKill(statement, ctx) {
|
|
1414
|
+
if (statement.op !== "KILL")
|
|
1415
|
+
throw new Error("unreachable");
|
|
1416
|
+
const path = statement.target;
|
|
1417
|
+
if (path === null)
|
|
1418
|
+
return { status: 400, error: "KILL requires a target path" };
|
|
1419
|
+
const schemeName = this.#schemeNameOf(path);
|
|
1420
|
+
if (schemeName === null)
|
|
1421
|
+
return { status: 400, error: "KILL target must be a URL path with a scheme" };
|
|
1422
|
+
if (schemeName === "log")
|
|
1423
|
+
return { status: 405, error: "log:// is append-only; KILL must bounce" };
|
|
1424
|
+
if (schemeName === "exec") {
|
|
1425
|
+
const execHandler = this.#schemes.get("exec");
|
|
1426
|
+
if (execHandler === undefined || typeof execHandler.kill !== "function")
|
|
1427
|
+
return { status: 501 };
|
|
1428
|
+
return await execHandler.kill(pathnameFromPath(path), ctx);
|
|
1429
|
+
}
|
|
1430
|
+
const handler = this.#schemes.get(schemeName);
|
|
1431
|
+
if (handler === undefined || typeof handler.deleteEntry !== "function")
|
|
1432
|
+
return { status: 501 };
|
|
1433
|
+
const delResult = await handler.deleteEntry(pathnameFromPath(path), ctx);
|
|
1434
|
+
return { status: delResult.status };
|
|
1435
|
+
}
|
|
1436
|
+
// PLAN — undocumented reasoning op (plurnk-grammar 0.30.0, the 11th op). A pure
|
|
1437
|
+
// no-op: the body is the model's in-content reasoning, which lands in the log
|
|
1438
|
+
// row's tx for free via statement serialization, no runtime effect (PLAN ∉
|
|
1439
|
+
// MUTATING_OPS). NOT taught in plurnk.md by design — reserved for a future model
|
|
1440
|
+
// that must reason in the content field (no separate reasoning channel). gemma
|
|
1441
|
+
// reasons on its own channel via the relaxed root, is never shown PLAN, and never
|
|
1442
|
+
// emits it; this handler exists only so the op resolves cleanly if we ever
|
|
1443
|
+
// deliberately reach for it (which would also require a plurnk.md override).
|
|
1444
|
+
#handlePlan(statement) {
|
|
1445
|
+
if (statement.op !== "PLAN")
|
|
1446
|
+
throw new Error("unreachable");
|
|
1447
|
+
return { status: 200 };
|
|
1448
|
+
}
|
|
1342
1449
|
async #copyOrchestration({ statement, srcPath, dstPath, ctx }) {
|
|
1343
1450
|
const srcSchemeName = this.#schemeNameOf(srcPath);
|
|
1344
1451
|
const dstSchemeName = this.#schemeNameOf(dstPath);
|
|
@@ -1410,6 +1517,10 @@ class Engine {
|
|
|
1410
1517
|
return { status: 409, error: `COPY/MOVE destination exists: ${dstSchemeName}://${dstPathname}` };
|
|
1411
1518
|
}
|
|
1412
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 };
|
|
1413
1524
|
return { status: writeResult.status, entryId: writeResult.entryId, created: writeResult.created };
|
|
1414
1525
|
}
|
|
1415
1526
|
async #handleSendBroadcast(statement, loopId) {
|
|
@@ -1433,6 +1544,13 @@ class Engine {
|
|
|
1433
1544
|
const method = handler[methodName];
|
|
1434
1545
|
if (typeof method !== "function")
|
|
1435
1546
|
return { status: 501 };
|
|
1547
|
+
// External @plurnk/plurnk-schemes-* siblings receive the DB-free SchemeCtx
|
|
1548
|
+
// (caps), never the raw PlurnkSchemeContext (schemes SPEC §5). The dynamic
|
|
1549
|
+
// dispatch is typed for in-tree schemes; the cast bridges the ctx shapes —
|
|
1550
|
+
// the sibling reads caps, the in-tree handler reads db.
|
|
1551
|
+
if (this.#schemes.isExternal(schemeName)) {
|
|
1552
|
+
return method.call(handler, statement, new SchemeCtxImpl(ctx, schemeName));
|
|
1553
|
+
}
|
|
1436
1554
|
return method.call(handler, statement, ctx);
|
|
1437
1555
|
}
|
|
1438
1556
|
// Bare paths default to the file scheme per plurnk.md (grammar sysprompt):
|
|
@@ -1441,8 +1559,9 @@ class Engine {
|
|
|
1441
1559
|
#schemeNameOf(path) {
|
|
1442
1560
|
if (path === null)
|
|
1443
1561
|
return null;
|
|
1562
|
+
// http + https are one scheme — the http sibling owns both prefixes (#195).
|
|
1444
1563
|
if (path.kind === "url")
|
|
1445
|
-
return path.scheme;
|
|
1564
|
+
return path.scheme === "https" ? "http" : path.scheme;
|
|
1446
1565
|
return "file"; // local (bare) → file
|
|
1447
1566
|
}
|
|
1448
1567
|
async #writeLog({ statement, result, runId, loopId, turnId, sequence, origin, }) {
|