@plurnk/plurnk-service 1.4.0 → 1.6.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/.env.defaults +37 -31
- package/INSTALL.md +16 -11
- package/README.md +1 -0
- package/SPEC.md +631 -397
- package/dist/Paths.d.ts.map +1 -1
- package/dist/Paths.js +2 -3
- package/dist/Paths.js.map +1 -1
- package/dist/build-info.json +1 -1
- package/dist/content/edit-collision.d.ts +5 -0
- package/dist/content/edit-collision.d.ts.map +1 -0
- package/dist/content/edit-collision.js +14 -0
- package/dist/content/edit-collision.js.map +1 -0
- package/dist/content/edit-receipt.d.ts +3 -2
- package/dist/content/edit-receipt.d.ts.map +1 -1
- package/dist/content/edit-receipt.js +58 -13
- package/dist/content/edit-receipt.js.map +1 -1
- package/dist/content/index.d.ts +5 -1
- package/dist/content/index.d.ts.map +1 -1
- package/dist/content/index.js +4 -1
- package/dist/content/index.js.map +1 -1
- package/dist/content/line-anchors.d.ts +41 -0
- package/dist/content/line-anchors.d.ts.map +1 -0
- package/dist/content/line-anchors.js +191 -0
- package/dist/content/line-anchors.js.map +1 -0
- package/dist/content/line-marker.d.ts +7 -3
- package/dist/content/line-marker.d.ts.map +1 -1
- package/dist/content/line-marker.js +2 -1
- package/dist/content/line-marker.js.map +1 -1
- package/dist/content/matcher.d.ts +1 -1
- package/dist/content/matcher.d.ts.map +1 -1
- package/dist/content/matcher.js +2 -2
- package/dist/content/matcher.js.map +1 -1
- package/dist/content/read-projector.d.ts +20 -0
- package/dist/content/read-projector.d.ts.map +1 -0
- package/dist/content/read-projector.js +122 -0
- package/dist/content/read-projector.js.map +1 -0
- package/dist/content/read-resolve.d.ts +2 -7
- package/dist/content/read-resolve.d.ts.map +1 -1
- package/dist/content/read-resolve.js +32 -107
- package/dist/content/read-resolve.js.map +1 -1
- package/dist/core/BranchReceipt.d.ts +0 -1
- package/dist/core/BranchReceipt.d.ts.map +1 -1
- package/dist/core/BranchReceipt.js +0 -3
- package/dist/core/BranchReceipt.js.map +1 -1
- package/dist/core/BudgetReadout.d.ts.map +1 -1
- package/dist/core/BudgetReadout.js +9 -2
- package/dist/core/BudgetReadout.js.map +1 -1
- package/dist/core/ChannelWrite.d.ts +3 -0
- package/dist/core/ChannelWrite.d.ts.map +1 -1
- package/dist/core/ChannelWrite.js +3 -3
- package/dist/core/ChannelWrite.js.map +1 -1
- package/dist/core/ChannelWrite.sql +4 -3
- package/dist/core/CoreSchemeServices.d.ts +10 -2
- package/dist/core/CoreSchemeServices.d.ts.map +1 -1
- package/dist/core/CoreSchemeServices.js.map +1 -1
- package/dist/core/Dispatcher.d.ts +14 -8
- package/dist/core/Dispatcher.d.ts.map +1 -1
- package/dist/core/Dispatcher.js +656 -312
- package/dist/core/Dispatcher.js.map +1 -1
- package/dist/core/DurableStatement.d.ts.map +1 -1
- package/dist/core/DurableStatement.js +2 -0
- package/dist/core/DurableStatement.js.map +1 -1
- package/dist/core/Engine.d.ts +24 -18
- package/dist/core/Engine.d.ts.map +1 -1
- package/dist/core/Engine.js +620 -392
- package/dist/core/Engine.js.map +1 -1
- package/dist/core/Engine.sql +188 -119
- package/dist/core/ExecutableTools.d.ts +10 -0
- package/dist/core/ExecutableTools.d.ts.map +1 -0
- package/dist/core/ExecutableTools.js +41 -0
- package/dist/core/ExecutableTools.js.map +1 -0
- package/dist/core/ExecutorRegistry.d.ts +3 -3
- package/dist/core/ExecutorRegistry.d.ts.map +1 -1
- package/dist/core/ExecutorRegistry.js +2 -2
- package/dist/core/ExecutorRegistry.js.map +1 -1
- package/dist/core/LogBody.d.ts +4 -1
- package/dist/core/LogBody.d.ts.map +1 -1
- package/dist/core/LogBody.js +46 -2
- package/dist/core/LogBody.js.map +1 -1
- package/dist/core/LogEntryProjection.d.ts +14 -0
- package/dist/core/LogEntryProjection.d.ts.map +1 -0
- package/dist/core/LogEntryProjection.js +38 -0
- package/dist/core/LogEntryProjection.js.map +1 -0
- package/dist/core/LoopLifecycle.d.ts +1 -2
- package/dist/core/LoopLifecycle.d.ts.map +1 -1
- package/dist/core/LoopLifecycle.js +1 -4
- package/dist/core/LoopLifecycle.js.map +1 -1
- package/dist/core/LoopLifecycle.sql +1 -4
- package/dist/core/ModelCall.d.ts +27 -0
- package/dist/core/ModelCall.d.ts.map +1 -0
- package/dist/core/ModelCall.js +125 -0
- package/dist/core/ModelCall.js.map +1 -0
- package/dist/core/PacketBuilder.d.ts +13 -12
- package/dist/core/PacketBuilder.d.ts.map +1 -1
- package/dist/core/PacketBuilder.js +146 -118
- package/dist/core/PacketBuilder.js.map +1 -1
- package/dist/core/ProblemLog.d.ts.map +1 -1
- package/dist/core/ProblemLog.js +1 -0
- package/dist/core/ProblemLog.js.map +1 -1
- package/dist/core/ProposalLifecycle.d.ts.map +1 -1
- package/dist/core/ProposalLifecycle.js +3 -4
- package/dist/core/ProposalLifecycle.js.map +1 -1
- package/dist/core/ProviderInstantiate.d.ts.map +1 -1
- package/dist/core/ProviderInstantiate.js +23 -6
- package/dist/core/ProviderInstantiate.js.map +1 -1
- package/dist/core/SchemeRegistry.js +7 -7
- package/dist/core/SchemeRegistry.js.map +1 -1
- package/dist/core/StrikeRail.d.ts +5 -2
- package/dist/core/StrikeRail.d.ts.map +1 -1
- package/dist/core/StrikeRail.js +10 -7
- package/dist/core/StrikeRail.js.map +1 -1
- package/dist/core/TerminalResult.d.ts +16 -0
- package/dist/core/TerminalResult.d.ts.map +1 -0
- package/dist/core/TerminalResult.js +49 -0
- package/dist/core/TerminalResult.js.map +1 -0
- package/dist/core/caps/CapsResolve.d.ts +5 -1
- package/dist/core/caps/CapsResolve.d.ts.map +1 -1
- package/dist/core/caps/CapsResolve.js +9 -5
- package/dist/core/caps/CapsResolve.js.map +1 -1
- package/dist/core/caps/DbChannelCaps.d.ts +1 -1
- package/dist/core/caps/DbChannelCaps.d.ts.map +1 -1
- package/dist/core/caps/DbChannelCaps.js +6 -4
- package/dist/core/caps/DbChannelCaps.js.map +1 -1
- package/dist/core/caps/DbEntryCaps.d.ts +2 -1
- package/dist/core/caps/DbEntryCaps.d.ts.map +1 -1
- package/dist/core/caps/DbEntryCaps.js +21 -8
- package/dist/core/caps/DbEntryCaps.js.map +1 -1
- package/dist/core/caps/DbNotifyCaps.d.ts +1 -1
- package/dist/core/caps/DbNotifyCaps.d.ts.map +1 -1
- package/dist/core/caps/DbNotifyCaps.js +6 -4
- package/dist/core/caps/DbNotifyCaps.js.map +1 -1
- package/dist/core/caps/DbProjectionCaps.d.ts +1 -0
- package/dist/core/caps/DbProjectionCaps.d.ts.map +1 -1
- package/dist/core/caps/DbProjectionCaps.js +29 -0
- package/dist/core/caps/DbProjectionCaps.js.map +1 -1
- package/dist/core/caps/DbSubscriptionCaps.d.ts +4 -6
- package/dist/core/caps/DbSubscriptionCaps.d.ts.map +1 -1
- package/dist/core/caps/DbSubscriptionCaps.js +27 -13
- package/dist/core/caps/DbSubscriptionCaps.js.map +1 -1
- package/dist/core/caps/SchemeCtxImpl.d.ts +11 -3
- package/dist/core/caps/SchemeCtxImpl.d.ts.map +1 -1
- package/dist/core/caps/SchemeCtxImpl.js +10 -8
- package/dist/core/caps/SchemeCtxImpl.js.map +1 -1
- package/dist/core/fork.d.ts.map +1 -1
- package/dist/core/fork.js +23 -7
- package/dist/core/fork.js.map +1 -1
- package/dist/core/fork.sql +35 -14
- package/dist/core/git-iso.d.ts +3 -2
- package/dist/core/git-iso.d.ts.map +1 -1
- package/dist/core/git-iso.js +27 -12
- package/dist/core/git-iso.js.map +1 -1
- package/dist/core/git-membership.d.ts +1 -0
- package/dist/core/git-membership.d.ts.map +1 -1
- package/dist/core/git-membership.js +87 -26
- package/dist/core/git-membership.js.map +1 -1
- package/dist/core/git-state.d.ts +8 -1
- package/dist/core/git-state.d.ts.map +1 -1
- package/dist/core/git-state.js +36 -17
- package/dist/core/git-state.js.map +1 -1
- package/dist/core/namespace.d.ts +1 -0
- package/dist/core/namespace.d.ts.map +1 -1
- package/dist/core/namespace.js +20 -0
- package/dist/core/namespace.js.map +1 -1
- package/dist/core/optimistic-settlement.d.ts +2 -0
- package/dist/core/optimistic-settlement.d.ts.map +1 -0
- package/dist/core/optimistic-settlement.js +14 -0
- package/dist/core/optimistic-settlement.js.map +1 -0
- package/dist/core/packet-wire.d.ts +5 -2
- package/dist/core/packet-wire.d.ts.map +1 -1
- package/dist/core/packet-wire.js +318 -114
- package/dist/core/packet-wire.js.map +1 -1
- package/dist/core/provider-accounting.d.ts +24 -0
- package/dist/core/provider-accounting.d.ts.map +1 -0
- package/dist/core/provider-accounting.js +76 -0
- package/dist/core/provider-accounting.js.map +1 -0
- package/dist/core/results.d.ts +4 -2
- package/dist/core/results.d.ts.map +1 -1
- package/dist/core/results.js +6 -0
- package/dist/core/results.js.map +1 -1
- package/dist/core/scheme-types.d.ts +0 -12
- package/dist/core/scheme-types.d.ts.map +1 -1
- package/dist/core/scheme-types.js.map +1 -1
- package/dist/core/search-gate.d.ts +2 -2
- package/dist/core/search-gate.d.ts.map +1 -1
- package/dist/core/search-gate.js +8 -8
- package/dist/core/search-gate.js.map +1 -1
- package/dist/core/token-ruler.js +1 -1
- package/dist/core/token-ruler.js.map +1 -1
- package/dist/core/turn-scheduler.js +1 -1
- package/dist/core/turn-scheduler.js.map +1 -1
- package/dist/core/worker-ops.sql +4 -4
- package/dist/core/workspace-settings.js +1 -1
- package/dist/core/workspace-settings.js.map +1 -1
- package/dist/digest/Digest.d.ts.map +1 -1
- package/dist/digest/Digest.js +349 -76
- package/dist/digest/Digest.js.map +1 -1
- package/dist/digest/digest.sql +42 -16
- package/dist/schemes/Exec.d.ts +4 -4
- package/dist/schemes/Exec.d.ts.map +1 -1
- package/dist/schemes/Exec.js +167 -134
- package/dist/schemes/Exec.js.map +1 -1
- package/dist/schemes/ExecOutputScheme.d.ts +4 -5
- package/dist/schemes/ExecOutputScheme.d.ts.map +1 -1
- package/dist/schemes/ExecOutputScheme.js +12 -20
- package/dist/schemes/ExecOutputScheme.js.map +1 -1
- package/dist/schemes/File.d.ts +5 -6
- package/dist/schemes/File.d.ts.map +1 -1
- package/dist/schemes/File.js +35 -41
- package/dist/schemes/File.js.map +1 -1
- package/dist/schemes/Log.d.ts +16 -5
- package/dist/schemes/Log.d.ts.map +1 -1
- package/dist/schemes/Log.js +229 -262
- package/dist/schemes/Log.js.map +1 -1
- package/dist/schemes/Log.sql +50 -27
- package/dist/schemes/Prompt.d.ts +3 -4
- package/dist/schemes/Prompt.d.ts.map +1 -1
- package/dist/schemes/Prompt.js +5 -5
- package/dist/schemes/Prompt.js.map +1 -1
- package/dist/schemes/Skill.d.ts +4 -5
- package/dist/schemes/Skill.d.ts.map +1 -1
- package/dist/schemes/Skill.js +3 -3
- package/dist/schemes/Skill.js.map +1 -1
- package/dist/schemes/Worker.d.ts +7 -7
- package/dist/schemes/Worker.d.ts.map +1 -1
- package/dist/schemes/Worker.js +99 -84
- package/dist/schemes/Worker.js.map +1 -1
- package/dist/schemes/_entry-crud.d.ts +2 -2
- package/dist/schemes/_entry-crud.d.ts.map +1 -1
- package/dist/schemes/_entry-crud.js +29 -10
- package/dist/schemes/_entry-crud.js.map +1 -1
- package/dist/schemes/_entry-crud.sql +11 -17
- package/dist/schemes/_entry-find.d.ts +41 -14
- package/dist/schemes/_entry-find.d.ts.map +1 -1
- package/dist/schemes/_entry-find.js +159 -166
- package/dist/schemes/_entry-find.js.map +1 -1
- package/dist/schemes/_entry-find.sql +2 -21
- package/dist/schemes/_entry-graph.sql +1 -1
- package/dist/schemes/_entry-manifest.d.ts +5 -17
- package/dist/schemes/_entry-manifest.d.ts.map +1 -1
- package/dist/schemes/_entry-manifest.js +28 -24
- package/dist/schemes/_entry-manifest.js.map +1 -1
- package/dist/schemes/_entry-ops.d.ts +13 -8
- package/dist/schemes/_entry-ops.d.ts.map +1 -1
- package/dist/schemes/_entry-ops.js +98 -119
- package/dist/schemes/_entry-ops.js.map +1 -1
- package/dist/schemes/_entry-ops.sql +31 -6
- package/dist/schemes/_entry-semantic.d.ts +5 -7
- package/dist/schemes/_entry-semantic.d.ts.map +1 -1
- package/dist/schemes/_entry-semantic.js +10 -31
- package/dist/schemes/_entry-semantic.js.map +1 -1
- package/dist/schemes/_entry-semantic.sql +2 -2
- package/dist/schemes/_entry-send.js +4 -4
- package/dist/schemes/_entry-send.js.map +1 -1
- package/dist/schemes/_search-index.d.ts.map +1 -1
- package/dist/schemes/_search-index.js +16 -6
- package/dist/schemes/_search-index.js.map +1 -1
- package/dist/schemes/exec-abort.js +2 -2
- package/dist/schemes/exec-abort.js.map +1 -1
- package/dist/server/BranchBatches.d.ts +1 -0
- package/dist/server/BranchBatches.d.ts.map +1 -1
- package/dist/server/BranchBatches.js +1 -0
- package/dist/server/BranchBatches.js.map +1 -1
- package/dist/server/Daemon.d.ts +6 -8
- package/dist/server/Daemon.d.ts.map +1 -1
- package/dist/server/Daemon.js +238 -68
- package/dist/server/Daemon.js.map +1 -1
- package/dist/server/DaemonModule.d.ts +3 -3
- package/dist/server/DaemonModule.d.ts.map +1 -1
- package/dist/server/branch-batch.sql +3 -1
- package/dist/server/client-input.d.ts +2 -1
- package/dist/server/client-input.d.ts.map +1 -1
- package/dist/server/client-input.js +7 -1
- package/dist/server/client-input.js.map +1 -1
- package/dist/server/drain.sql +8 -7
- package/dist/server/envelope.d.ts +0 -2
- package/dist/server/envelope.d.ts.map +1 -1
- package/dist/server/envelope.js +0 -1
- package/dist/server/envelope.js.map +1 -1
- package/dist/server/envelope.sql +3 -4
- package/dist/server/lifecycle-recovery.sql +44 -1
- package/dist/server/logEntry.d.ts +2 -1
- package/dist/server/logEntry.d.ts.map +1 -1
- package/dist/server/logEntry.js +15 -2
- package/dist/server/logEntry.js.map +1 -1
- package/dist/server/logEntry.sql +5 -1
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +13 -1
- package/dist/service.js.map +1 -1
- package/migrations/001_schema.sql +730 -221
- package/package.json +53 -46
- package/dist/core/BudgetOverflow.d.ts +0 -23
- package/dist/core/BudgetOverflow.d.ts.map +0 -1
- package/dist/core/BudgetOverflow.js +0 -61
- package/dist/core/BudgetOverflow.js.map +0 -1
- package/dist/core/caps/DbTagCaps.d.ts +0 -10
- package/dist/core/caps/DbTagCaps.d.ts.map +0 -1
- package/dist/core/caps/DbTagCaps.js +0 -44
- package/dist/core/caps/DbTagCaps.js.map +0 -1
- package/dist/matrix/live-specimen.d.ts +0 -9
- package/dist/matrix/live-specimen.d.ts.map +0 -1
- package/dist/matrix/live-specimen.js +0 -37
- package/dist/matrix/live-specimen.js.map +0 -1
package/dist/core/packet-wire.js
CHANGED
|
@@ -7,10 +7,11 @@
|
|
|
7
7
|
// Format and omission rules are owned by {§packet-markdown}. Section producers
|
|
8
8
|
// supply names and typed content; this projection preserves their ordered evidence.
|
|
9
9
|
import { Validator } from "@plurnk/plurnk-contracts";
|
|
10
|
-
import {
|
|
10
|
+
import { TextCoordinates } from "@plurnk/plurnk-mimetypes";
|
|
11
11
|
import { renderTarget } from "./plurnk-uri.js";
|
|
12
12
|
import LogBody from "./LogBody.js";
|
|
13
|
-
import
|
|
13
|
+
import LogEntryProjection from "./LogEntryProjection.js";
|
|
14
|
+
import { assertEditReceipt, assertResourceEffects, LineAnchors, } from "../content/index.js";
|
|
14
15
|
const editReceiptRevisionChars = () => {
|
|
15
16
|
const raw = process.env.PLURNK_SERVICE_EDIT_RECEIPT_REVISION_CHARS;
|
|
16
17
|
const value = Number(raw);
|
|
@@ -91,23 +92,24 @@ export default class PacketWire {
|
|
|
91
92
|
return items.map((r) => `* ${String(r.status)} ${String(r.path)}`).join("\n");
|
|
92
93
|
}
|
|
93
94
|
// The git section content: the working-tree summary. "" when absent.
|
|
94
|
-
static renderGit(git) {
|
|
95
|
-
|
|
95
|
+
static renderGit(git, assignedBranch = null) {
|
|
96
|
+
const status = git === null || git === undefined ? "" : PacketWire.#renderGitState(git);
|
|
97
|
+
const assignment = assignedBranch === null
|
|
98
|
+
? ""
|
|
99
|
+
: `assigned branch \`${assignedBranch}\` — commit any project changes and leave the checkout clean before concluding`;
|
|
100
|
+
return [status, assignment].filter((line) => line.length > 0).join("\n");
|
|
96
101
|
}
|
|
97
102
|
// The log section's content: the model's curated rows as a fenced `jsonplurnk` array ({§jsonplurnk}).
|
|
98
103
|
// Data only — no prose leads the fence (the log carries rules for no one). Empty log → ""
|
|
99
104
|
// (the section is omitted).
|
|
100
|
-
static renderLog(entries, countTokens) {
|
|
105
|
+
static renderLog(entries, countTokens, options = {}) {
|
|
101
106
|
const log = Array.isArray(entries) ? entries : [];
|
|
102
107
|
if (log.length === 0)
|
|
103
108
|
return "";
|
|
104
|
-
const items = PacketWire.#renderLogEntries(log, countTokens);
|
|
105
|
-
//
|
|
106
|
-
//
|
|
107
|
-
|
|
108
|
-
const longestTicks = Math.max(0, ...[...items.matchAll(/`+/g)].map((m) => m[0].length));
|
|
109
|
-
const fence = "`".repeat(Math.max(3, longestTicks + 1));
|
|
110
|
-
return `${fence}jsonplurnk\n[\n${items}\n]\n${fence}`;
|
|
109
|
+
const items = PacketWire.#renderLogEntries(log, countTokens, options);
|
|
110
|
+
// Every source line is coordinate-prefixed, so source backticks never occupy the
|
|
111
|
+
// CommonMark closing-fence position. The fixed opener keeps the packet prefix cache-stable.
|
|
112
|
+
return `\`\`\`jsonplurnk\n[\n${items}\n]\n\`\`\``;
|
|
111
113
|
}
|
|
112
114
|
// Read one section's content by name off a packet (Engine's or re-parsed).
|
|
113
115
|
// The legible accessor — consumers name the section they want instead of
|
|
@@ -126,31 +128,33 @@ export default class PacketWire {
|
|
|
126
128
|
{ role: "user", content: PacketWire.renderSlot(sections, "user") },
|
|
127
129
|
];
|
|
128
130
|
}
|
|
129
|
-
// Number
|
|
131
|
+
// Number a non-READ body line as `<N>:<line>` — a bare `N:` prefix, NO separator whitespace
|
|
130
132
|
// ({§render-rule-line-navigable-prefix}): the leading digit prevents column-zero fence collisions and gives
|
|
131
|
-
// the model line refs for free (
|
|
133
|
+
// the model line refs for free (`## READ0 (...) <42-46>`), while the absence of any separator means a
|
|
132
134
|
// reproduced line has nothing between `N:` and the content to copy — the hard-tab separator used
|
|
133
135
|
// to leak into edit bodies and corrupt indentation. The content's OWN leading whitespace is
|
|
134
136
|
// content, preserved verbatim.
|
|
135
137
|
// Used for READ@200 content; index-preview numbering is the framework's
|
|
136
|
-
// job now (baked into the preview string
|
|
138
|
+
// job now (baked into the preview string).
|
|
137
139
|
static #numberLines(body, start = 1) {
|
|
138
140
|
let line = start;
|
|
139
|
-
return body.replace(/(
|
|
141
|
+
return `${line++}:${body.replace(/(\r\n|\r(?!\n)|\n)(?=[\s\S])/g, (separator) => `${separator}${line++}:`)}`;
|
|
140
142
|
}
|
|
141
|
-
// The single content-body renderer EVERY output-emitting op routes through
|
|
142
|
-
//
|
|
143
|
-
//
|
|
144
|
-
//
|
|
145
|
-
static #renderContentBody(
|
|
143
|
+
// The single content-body renderer EVERY output-emitting op routes through.
|
|
144
|
+
// Exact READ content receives source-width-aligned `@hash N:`; other textual bodies receive `N:`.
|
|
145
|
+
// Matchers consume canonical content before this presentation projection.
|
|
146
|
+
// Empty content produces no body.
|
|
147
|
+
static #renderContentBody(content, startLine = 1, lineAnchors = null, lineNumberWidth = null) {
|
|
146
148
|
if (content.length === 0)
|
|
147
149
|
return "";
|
|
148
150
|
// `startLine === null` means the producer already supplied numbered
|
|
149
151
|
// content; re-numbering would duplicate its coordinates.
|
|
150
152
|
const rendered = startLine !== null
|
|
151
|
-
?
|
|
153
|
+
? lineAnchors === null
|
|
154
|
+
? PacketWire.#numberLines(content, startLine)
|
|
155
|
+
: LineAnchors.render(content, startLine, lineAnchors, lineNumberWidth ?? 0)
|
|
152
156
|
: content;
|
|
153
|
-
return PacketWire.#
|
|
157
|
+
return PacketWire.#quoteBody(rendered);
|
|
154
158
|
}
|
|
155
159
|
// Tolerant JSON parser for log entries' persisted rx/tx strings. The engine
|
|
156
160
|
// pre-parses application/json mimetypes; malformed stored text is not JSON.
|
|
@@ -176,6 +180,7 @@ export default class PacketWire {
|
|
|
176
180
|
const head = {
|
|
177
181
|
rev: receipt.revision.slice(0, editReceiptRevisionChars()),
|
|
178
182
|
extent: `${receipt.unit} ${receipt.before}->${receipt.after}`,
|
|
183
|
+
...(receipt.parseIssues === undefined ? {} : { parseIssues: receipt.parseIssues }),
|
|
179
184
|
};
|
|
180
185
|
if ("effect" in receipt) {
|
|
181
186
|
return {
|
|
@@ -196,18 +201,19 @@ export default class PacketWire {
|
|
|
196
201
|
}),
|
|
197
202
|
};
|
|
198
203
|
}
|
|
199
|
-
//
|
|
200
|
-
//
|
|
201
|
-
//
|
|
202
|
-
//
|
|
203
|
-
//
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
204
|
+
// {§jsonplurnk} One deliberately raw multiline JSON string. The physical
|
|
205
|
+
// newline after the opening quote and every positive numeric or anchored coordinate prefix
|
|
206
|
+
// make the closing quote at column zero unambiguous without an invented
|
|
207
|
+
// delimiter for source text to imitate. Already-numbered producer output is
|
|
208
|
+
// checked here too: malformed bodies fail at the one projection boundary.
|
|
209
|
+
static #quoteBody(body) {
|
|
210
|
+
const endsWithLineBreak = /(?:\r\n|\r|\n)$/.test(body);
|
|
211
|
+
const lines = body.split(/\r\n|\r|\n/);
|
|
212
|
+
const contentLines = endsWithLineBreak ? lines.slice(0, -1) : lines;
|
|
213
|
+
if (contentLines.length === 0 || contentLines.some((line) => !/^[1-9]\d*:/.test(line) && !LineAnchors.isAnchoredLine(line))) {
|
|
214
|
+
throw new TypeError("A raw jsonplurnk body requires a positive coordinate prefix on every physical line.");
|
|
215
|
+
}
|
|
216
|
+
return `"\n${body}${endsWithLineBreak ? "" : "\n"}"`;
|
|
211
217
|
}
|
|
212
218
|
// Render one Log entry → a single bullet line carrying the meta JSON.
|
|
213
219
|
// No body, no fence — every meaningful field is in the JSON. Naming
|
|
@@ -229,38 +235,180 @@ export default class PacketWire {
|
|
|
229
235
|
return null;
|
|
230
236
|
return op !== null ? `log:///${coordinate}/${op}` : `log:///${coordinate}`;
|
|
231
237
|
}
|
|
238
|
+
static #offsetAfterCharacters(text, count) {
|
|
239
|
+
let offset = 0;
|
|
240
|
+
let consumed = 0;
|
|
241
|
+
while (offset < text.length && consumed < count) {
|
|
242
|
+
if (text.startsWith("\r\n", offset)) {
|
|
243
|
+
offset += 2;
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
const codePoint = text.codePointAt(offset);
|
|
247
|
+
if (codePoint === undefined)
|
|
248
|
+
break;
|
|
249
|
+
offset += String.fromCodePoint(codePoint).length;
|
|
250
|
+
}
|
|
251
|
+
consumed++;
|
|
252
|
+
}
|
|
253
|
+
return offset;
|
|
254
|
+
}
|
|
232
255
|
// One preview function for every bounded model-facing projection. Lines
|
|
233
|
-
// protect ordinary documents and
|
|
256
|
+
// protect ordinary documents and Unicode characters protect a single-line
|
|
257
|
+
// bomb. Once a physical line is complete, a character cut retreats to that
|
|
258
|
+
// line boundary rather than exposing a partial coordinate prefix.
|
|
234
259
|
static #preview(text) {
|
|
235
260
|
const { lines: maxLines, chars: maxChars } = previewBounds();
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
261
|
+
const coordinates = new TextCoordinates(text);
|
|
262
|
+
const physicalLines = coordinates.logicalLines();
|
|
263
|
+
const lineEnd = physicalLines.length > maxLines
|
|
264
|
+
? physicalLines[maxLines - 1].end
|
|
265
|
+
: text.length;
|
|
266
|
+
const characterEnd = PacketWire.#offsetAfterCharacters(text, maxChars);
|
|
267
|
+
let end = Math.min(lineEnd, characterEnd);
|
|
268
|
+
if (characterEnd < text.length && characterEnd <= lineEnd) {
|
|
269
|
+
const completeLine = physicalLines.findLast((line) => line.separator.length > 0 && line.end <= characterEnd);
|
|
270
|
+
if (completeLine !== undefined)
|
|
271
|
+
end = completeLine.end;
|
|
272
|
+
}
|
|
273
|
+
const cut = end < text.length;
|
|
274
|
+
return {
|
|
275
|
+
text: text.slice(0, end),
|
|
276
|
+
cut,
|
|
277
|
+
chunk: cut ? PacketWire.#chunk(coordinates, physicalLines, end, text.length) : null,
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
static #formatRegion(region) {
|
|
281
|
+
return `<${region.startLine},${region.startColumn},${region.endLine},${region.endColumn}>`;
|
|
282
|
+
}
|
|
283
|
+
static #chunk(coordinates, lines, end, completeEnd) {
|
|
284
|
+
const finalCompleteLine = lines.findIndex((line) => line.separator.length > 0 && line.end === end);
|
|
285
|
+
if (finalCompleteLine !== -1) {
|
|
286
|
+
const selected = `<1,${finalCompleteLine + 1}>`;
|
|
287
|
+
const complete = `<1,${lines.length}>`;
|
|
288
|
+
if (selected === complete) {
|
|
289
|
+
throw new Error("a bounded body chunk must differ from its complete line extent");
|
|
290
|
+
}
|
|
291
|
+
return `showing ${selected} of ${complete}`;
|
|
292
|
+
}
|
|
293
|
+
const selectedRegion = coordinates.regionFromOffsets(0, end);
|
|
294
|
+
const completeRegion = coordinates.regionFromOffsets(0, completeEnd);
|
|
295
|
+
if (selectedRegion === null || completeRegion === null) {
|
|
296
|
+
throw new Error("a character-bound body chunk must resolve to exact text coordinates");
|
|
297
|
+
}
|
|
298
|
+
const selected = PacketWire.#formatRegion(selectedRegion);
|
|
299
|
+
const complete = PacketWire.#formatRegion(completeRegion);
|
|
300
|
+
if (selected === complete) {
|
|
301
|
+
throw new Error("a bounded body chunk must differ from its complete text extent");
|
|
302
|
+
}
|
|
303
|
+
return `showing ${selected} of ${complete}`;
|
|
304
|
+
}
|
|
305
|
+
static #promptProjection(body, budget, countTokens) {
|
|
306
|
+
const weightAt = (end) => countTokens(PacketWire.#renderContentBody(body.content.slice(0, end), body.startLine, null));
|
|
307
|
+
if (weightAt(body.content.length) <= budget) {
|
|
308
|
+
return { text: body.content, cut: false, chunk: null };
|
|
309
|
+
}
|
|
310
|
+
if (budget <= 0)
|
|
311
|
+
return { text: "", cut: true, chunk: null };
|
|
312
|
+
const coordinates = new TextCoordinates(body.content);
|
|
313
|
+
const lines = coordinates.logicalLines();
|
|
314
|
+
const completeLineEnds = lines
|
|
315
|
+
.filter((line) => line.separator.length > 0 && line.end < body.content.length)
|
|
316
|
+
.map((line) => line.end);
|
|
317
|
+
let low = 0;
|
|
318
|
+
let high = completeLineEnds.length;
|
|
319
|
+
while (low < high) {
|
|
320
|
+
const middle = Math.floor((low + high) / 2);
|
|
321
|
+
if (weightAt(completeLineEnds[middle]) <= budget)
|
|
322
|
+
low = middle + 1;
|
|
323
|
+
else
|
|
324
|
+
high = middle;
|
|
325
|
+
}
|
|
326
|
+
const completeLineEnd = low === 0 ? 0 : completeLineEnds[low - 1];
|
|
327
|
+
if (completeLineEnd > 0) {
|
|
328
|
+
return {
|
|
329
|
+
text: body.content.slice(0, completeLineEnd),
|
|
330
|
+
cut: true,
|
|
331
|
+
chunk: PacketWire.#chunk(coordinates, lines, completeLineEnd, body.content.length),
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
const firstLineEnd = lines[0]?.contentEnd ?? body.content.length;
|
|
335
|
+
const offsets = [0];
|
|
336
|
+
let offset = 0;
|
|
337
|
+
for (const codePoint of body.content.slice(0, firstLineEnd)) {
|
|
338
|
+
offset += codePoint.length;
|
|
339
|
+
offsets.push(offset);
|
|
340
|
+
}
|
|
341
|
+
low = 0;
|
|
342
|
+
high = offsets.length;
|
|
343
|
+
while (low < high) {
|
|
344
|
+
const middle = Math.floor((low + high) / 2);
|
|
345
|
+
if (weightAt(offsets[middle]) <= budget)
|
|
346
|
+
low = middle + 1;
|
|
347
|
+
else
|
|
348
|
+
high = middle;
|
|
349
|
+
}
|
|
350
|
+
const characterEnd = low === 0 ? 0 : offsets[low - 1];
|
|
351
|
+
if (characterEnd === 0)
|
|
352
|
+
return { text: "", cut: true, chunk: null };
|
|
353
|
+
return {
|
|
354
|
+
text: body.content.slice(0, characterEnd),
|
|
355
|
+
cut: true,
|
|
356
|
+
chunk: PacketWire.#chunk(coordinates, lines, characterEnd, body.content.length),
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
static #promptBudgets(entries, bodies, countTokens, budget) {
|
|
360
|
+
if (budget === undefined)
|
|
361
|
+
return new Map();
|
|
362
|
+
if (!Number.isSafeInteger(budget) || budget < 0) {
|
|
363
|
+
throw new RangeError(`promptProjectionBudget must be a non-negative safe integer, got ${JSON.stringify(budget)}`);
|
|
364
|
+
}
|
|
365
|
+
const costs = entries.flatMap((entry, index) => {
|
|
366
|
+
if (entry.op !== "prompt" || entry.folded === true || bodies[index].content.length === 0)
|
|
367
|
+
return [];
|
|
368
|
+
const rendered = PacketWire.#renderContentBody(bodies[index].content, bodies[index].startLine, null);
|
|
369
|
+
return [{ index, cost: countTokens(rendered) }];
|
|
370
|
+
});
|
|
371
|
+
const allocations = new Map();
|
|
372
|
+
let remaining = budget;
|
|
373
|
+
let active = costs;
|
|
374
|
+
while (active.length > 0) {
|
|
375
|
+
const share = Math.floor(remaining / active.length);
|
|
376
|
+
const complete = active.filter(({ cost }) => cost <= share);
|
|
377
|
+
if (complete.length === 0) {
|
|
378
|
+
const extra = remaining % active.length;
|
|
379
|
+
active.forEach(({ index }, position) => allocations.set(index, share + (position < extra ? 1 : 0)));
|
|
241
380
|
break;
|
|
242
|
-
|
|
243
|
-
|
|
381
|
+
}
|
|
382
|
+
for (const { index, cost } of complete) {
|
|
383
|
+
allocations.set(index, cost);
|
|
384
|
+
remaining -= cost;
|
|
385
|
+
}
|
|
386
|
+
const completed = new Set(complete.map(({ index }) => index));
|
|
387
|
+
active = active.filter(({ index }) => !completed.has(index));
|
|
244
388
|
}
|
|
245
|
-
|
|
246
|
-
return { text: text.slice(0, end), cut: end < text.length };
|
|
389
|
+
return allocations;
|
|
247
390
|
}
|
|
248
|
-
static #renderLogEntries(entries, countTokens) {
|
|
249
|
-
|
|
391
|
+
static #renderLogEntries(entries, countTokens, options) {
|
|
392
|
+
const bodies = entries.map((e) => {
|
|
393
|
+
const op = typeof e.op === "string" && e.op.length > 0 ? e.op : null;
|
|
394
|
+
return LogBody.resolve({
|
|
395
|
+
op,
|
|
396
|
+
attrs: e.attrs,
|
|
397
|
+
tx: e.tx,
|
|
398
|
+
rx: e.rx,
|
|
399
|
+
mimetypeTx: typeof e.mimetype_tx === "string" ? e.mimetype_tx : undefined,
|
|
400
|
+
mimetypeRx: typeof e.mimetype_rx === "string" ? e.mimetype_rx : undefined,
|
|
401
|
+
});
|
|
402
|
+
});
|
|
403
|
+
const promptBudgets = PacketWire.#promptBudgets(entries, bodies, countTokens, options.promptProjectionBudget);
|
|
404
|
+
return entries.map((e, index) => {
|
|
250
405
|
const meta = {};
|
|
251
406
|
const coordinate = typeof e.coordinate === "string" ? e.coordinate : null;
|
|
252
407
|
const op = typeof e.op === "string" && e.op.length > 0 ? e.op : null;
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
// the available operation instead of implying that the model or another
|
|
258
|
-
// agent authored a mutation. The coordinate still resolves the same
|
|
259
|
-
// underlying row; the typed attrs preserve exact replay/client semantics.
|
|
260
|
-
const materializedEntry = e.origin === "plurnk" && op === "EDIT"
|
|
261
|
-
&& e.attrs !== null && typeof e.attrs === "object"
|
|
262
|
-
&& e.attrs.kind === "entry_materialized";
|
|
263
|
-
const renderedOp = materializedEntry ? "READ" : op;
|
|
408
|
+
const renderedOp = LogEntryProjection.op(e);
|
|
409
|
+
const actionlessKind = op === null
|
|
410
|
+
? LogBody.actionlessKind({ op, attrs: e.attrs })
|
|
411
|
+
: null;
|
|
264
412
|
const path = PacketWire.#entryPath(coordinate, renderedOp);
|
|
265
413
|
if (path !== null)
|
|
266
414
|
meta.path = path;
|
|
@@ -270,10 +418,29 @@ export default class PacketWire {
|
|
|
270
418
|
// subsystem token when present; absence means the owning worker.
|
|
271
419
|
if (typeof e.source === "string" && e.source.length > 0)
|
|
272
420
|
meta.source = e.source;
|
|
273
|
-
if (
|
|
274
|
-
meta.
|
|
421
|
+
if (actionlessKind !== null)
|
|
422
|
+
meta.kind = actionlessKind;
|
|
423
|
+
if (e.source === "file" && e.attrs !== null && typeof e.attrs === "object" && "git" in e.attrs) {
|
|
424
|
+
const git = e.attrs.git;
|
|
425
|
+
if (typeof git !== "string" || git.length !== 2) {
|
|
426
|
+
throw new TypeError("A source=file log row carries malformed Git XY metadata.");
|
|
427
|
+
}
|
|
428
|
+
meta.git = git;
|
|
429
|
+
}
|
|
275
430
|
if (typeof e.status === "number")
|
|
276
431
|
meta.status = e.status;
|
|
432
|
+
if (e.tags !== undefined) {
|
|
433
|
+
const storedTags = e.tags;
|
|
434
|
+
if (!Array.isArray(storedTags) || !storedTags.every((tag) => typeof tag === "string" && tag.length > 0)) {
|
|
435
|
+
throw new TypeError("A log row carries malformed folksonomic tags.");
|
|
436
|
+
}
|
|
437
|
+
const tags = [...new Set(storedTags)].toSorted();
|
|
438
|
+
if (tags.length !== storedTags.length || tags.some((tag, index) => tag !== storedTags[index])) {
|
|
439
|
+
throw new TypeError("A log row's folksonomic tags must be unique and sorted.");
|
|
440
|
+
}
|
|
441
|
+
if (tags.length > 0)
|
|
442
|
+
meta.tags = tags;
|
|
443
|
+
}
|
|
277
444
|
const tx = (typeof e.tx === "string" ? PacketWire.#safeParse(e.tx) : e.tx);
|
|
278
445
|
const target = PacketWire.#renderActionTarget(e.target);
|
|
279
446
|
if (op === "COPY" || op === "MOVE") {
|
|
@@ -297,7 +464,7 @@ export default class PacketWire {
|
|
|
297
464
|
meta.target = target;
|
|
298
465
|
}
|
|
299
466
|
// EXEC's output is a separate stream entry ({§exec-stream}); its address rides in a
|
|
300
|
-
// `stream` link, distinct from
|
|
467
|
+
// `stream` link, distinct from the runtime-owned invocation target.
|
|
301
468
|
if (op === "EXEC" && e.attrs !== null && typeof e.attrs === "object" && typeof e.attrs.stream === "string") {
|
|
302
469
|
meta.stream = e.attrs.stream;
|
|
303
470
|
}
|
|
@@ -310,107 +477,144 @@ export default class PacketWire {
|
|
|
310
477
|
Validator.assertProblemDetails(problem);
|
|
311
478
|
meta.problem = problem;
|
|
312
479
|
}
|
|
313
|
-
//
|
|
314
|
-
//
|
|
315
|
-
|
|
316
|
-
let items = null;
|
|
480
|
+
// {§retrieval-packet-metadata}: one extent/coordinate owner plus
|
|
481
|
+
// only FIND aggregates that add information beyond that extent.
|
|
482
|
+
let findItems = null;
|
|
317
483
|
if (op === "READ" || op === "FIND") {
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
484
|
+
const findMatcher = op === "FIND"
|
|
485
|
+
&& tx !== null
|
|
486
|
+
&& tx !== undefined
|
|
487
|
+
&& typeof tx === "object"
|
|
488
|
+
&& tx.body !== null
|
|
489
|
+
&& typeof tx.body === "object";
|
|
490
|
+
if (findMatcher) {
|
|
491
|
+
const body = tx?.body;
|
|
492
|
+
if (body !== null && typeof body === "object" && typeof body.raw === "string") {
|
|
493
|
+
meta.matcher = body.raw;
|
|
494
|
+
}
|
|
321
495
|
}
|
|
322
|
-
if (op === "FIND" && rx !== null && typeof rx === "object" && typeof rx.
|
|
323
|
-
items = rx.omittedItems; // {§find-count-not-contents} - selected-resource count, though rows were not enumerated
|
|
324
|
-
}
|
|
325
|
-
else if (op === "FIND" && rx !== null && typeof rx === "object" && typeof rx.content === "string") {
|
|
496
|
+
if (op === "FIND" && rx !== null && typeof rx === "object" && typeof rx.content === "string") {
|
|
326
497
|
const parsed = PacketWire.#safeParse(rx.content);
|
|
327
498
|
if (Array.isArray(parsed))
|
|
328
|
-
|
|
499
|
+
findItems = parsed.length;
|
|
500
|
+
}
|
|
501
|
+
const range = rx !== null && typeof rx === "object" && rx.range !== undefined
|
|
502
|
+
? rx.range
|
|
503
|
+
: undefined;
|
|
504
|
+
const problemOwnsRange = typeof e.status === "number"
|
|
505
|
+
&& e.status >= 400
|
|
506
|
+
&& meta.problem !== null
|
|
507
|
+
&& typeof meta.problem === "object"
|
|
508
|
+
&& Object.hasOwn(meta.problem, "range");
|
|
509
|
+
if (problemOwnsRange) {
|
|
510
|
+
Validator.assertRangeExtent(meta.problem.range);
|
|
329
511
|
}
|
|
330
|
-
if (
|
|
331
|
-
meta.
|
|
512
|
+
if (range !== undefined && !problemOwnsRange) {
|
|
513
|
+
meta.range = Validator.assertRangeExtent(range);
|
|
332
514
|
}
|
|
333
|
-
if (op === "READ" && rx !== null && typeof rx === "object" && rx.region !== undefined) {
|
|
515
|
+
else if (op === "READ" && rx !== null && typeof rx === "object" && rx.region !== undefined) {
|
|
334
516
|
meta.region = Validator.assertTextRegion(rx.region);
|
|
335
517
|
}
|
|
336
|
-
//
|
|
337
|
-
//
|
|
338
|
-
if (op === "FIND" && rx !== null && typeof rx === "object" && typeof rx.itemsTokenTotal === "number") {
|
|
518
|
+
// These are underlying selected-content weights, distinct from
|
|
519
|
+
// the emitted body's generic `tokens` measurement.
|
|
520
|
+
if (op === "FIND" && rx !== null && typeof rx === "object" && typeof rx.itemsTokenTotal === "number" && rx.itemsTokenTotal > 0) {
|
|
339
521
|
meta.itemsTokenTotal = rx.itemsTokenTotal;
|
|
340
522
|
}
|
|
523
|
+
if (op === "FIND"
|
|
524
|
+
&& rx !== null
|
|
525
|
+
&& typeof rx === "object"
|
|
526
|
+
&& typeof rx.returnedItemsTokenTotal === "number"
|
|
527
|
+
&& rx.returnedItemsTokenTotal > 0
|
|
528
|
+
&& rx.returnedItemsTokenTotal !== rx.itemsTokenTotal) {
|
|
529
|
+
meta.returnedItemsTokenTotal = rx.returnedItemsTokenTotal;
|
|
530
|
+
}
|
|
531
|
+
if (findMatcher
|
|
532
|
+
&& range !== null
|
|
533
|
+
&& typeof range === "object"
|
|
534
|
+
&& range.unit === "resource"
|
|
535
|
+
&& rx !== null
|
|
536
|
+
&& typeof rx === "object"
|
|
537
|
+
&& typeof rx.matchLocationCount === "number"
|
|
538
|
+
&& rx.matchLocationCount > 0) {
|
|
539
|
+
meta.matchLocationCount = rx.matchLocationCount;
|
|
540
|
+
}
|
|
341
541
|
}
|
|
342
542
|
// {§edit-result-receipt-projection} {§edit-result-copy-move-effects}
|
|
343
543
|
// Mutations expose compact, validated outcome metadata. EDIT owns
|
|
344
544
|
// one receipt; COPY/MOVE own ordered resource effects whose
|
|
345
545
|
// optional receipts describe scoped textual materializations.
|
|
546
|
+
let structuredMutationReceipt = false;
|
|
346
547
|
if (op === "EDIT" && rx !== null && typeof rx === "object" && Object.hasOwn(rx, "receipt")) {
|
|
347
548
|
Object.assign(meta, PacketWire.#receiptMeta(rx.receipt));
|
|
549
|
+
structuredMutationReceipt = true;
|
|
348
550
|
}
|
|
349
551
|
if ((op === "COPY" || op === "MOVE")
|
|
350
552
|
&& rx !== null
|
|
351
553
|
&& typeof rx === "object"
|
|
352
554
|
&& Object.hasOwn(rx, "effects")) {
|
|
353
|
-
|
|
555
|
+
const effects = assertResourceEffects(rx.effects);
|
|
556
|
+
meta.effects = effects.map((effect) => ({
|
|
354
557
|
target: effect.target,
|
|
355
558
|
action: effect.action,
|
|
356
559
|
...(effect.receipt === undefined
|
|
357
560
|
? {}
|
|
358
561
|
: PacketWire.#receiptMeta(effect.receipt)),
|
|
359
562
|
}));
|
|
563
|
+
structuredMutationReceipt = effects.some((effect) => effect.receipt !== undefined);
|
|
360
564
|
}
|
|
361
|
-
// The canonical full body is shared with READ
|
|
362
|
-
// and search derivation.
|
|
363
|
-
//
|
|
364
|
-
//
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
const
|
|
373
|
-
const
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|| op === "prompt";
|
|
379
|
-
const bodyFence = resourceBody ? (target ?? path) : path;
|
|
565
|
+
// The canonical full body is shared with log READ, log FIND,
|
|
566
|
+
// and search derivation. READ/FIND own selection bounds, PLAN is
|
|
567
|
+
// persistent working memory, and prompt rows share their packet
|
|
568
|
+
// allowance. Structured mutation receipts own their join bound;
|
|
569
|
+
// every remaining body uses the ordinary fixed preview.
|
|
570
|
+
const fullBody = bodies[index];
|
|
571
|
+
const emptyFind = op === "FIND" && e.status === 200 && findItems === 0;
|
|
572
|
+
const previewExempt = op === "READ"
|
|
573
|
+
|| op === "FIND"
|
|
574
|
+
|| op === "PLAN"
|
|
575
|
+
|| structuredMutationReceipt;
|
|
576
|
+
const promptBudget = promptBudgets.get(index);
|
|
577
|
+
const projection = promptBudget !== undefined
|
|
578
|
+
? PacketWire.#promptProjection(fullBody, promptBudget, countTokens)
|
|
579
|
+
: previewExempt
|
|
580
|
+
? { text: fullBody.content, cut: false, chunk: null }
|
|
581
|
+
: PacketWire.#preview(fullBody.content);
|
|
380
582
|
if (projection.cut && path === null) {
|
|
381
583
|
throw new Error("a previewed log body requires an addressable log path");
|
|
382
584
|
}
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
}
|
|
585
|
+
const lineAnchors = op === "READ" ? e.lineAnchors ?? null : null;
|
|
586
|
+
const lineNumberWidth = op === "READ" ? e.lineNumberWidth ?? null : null;
|
|
386
587
|
const body = emptyFind || projection.text.length === 0
|
|
387
588
|
? ""
|
|
388
|
-
: PacketWire.#renderContentBody(
|
|
589
|
+
: PacketWire.#renderContentBody(projection.text, fullBody.startLine, lineAnchors, lineNumberWidth);
|
|
389
590
|
// tokens on EVERY row (0 when there's genuinely no body) so the model can always weigh
|
|
390
|
-
// it; for a folded row this is the room an OPEN would add.
|
|
391
|
-
if (items !== null)
|
|
392
|
-
meta.items = items;
|
|
591
|
+
// it; for a folded row this is the room an OPEN would add.
|
|
393
592
|
// 0 for a genuinely empty body — never call countTokens("") (some providers return
|
|
394
593
|
// undefined for it, which JSON.stringify would drop, leaving the row with no tokens).
|
|
395
594
|
meta.tokens = body.length > 0 ? countTokens(body) : 0;
|
|
396
|
-
// lines beside tokens on
|
|
397
|
-
// lines (fences and unnumbered prose don't count), so the model can plan
|
|
398
|
-
// slice before paying for an OPEN.
|
|
399
|
-
if (body.length > 0) {
|
|
595
|
+
// lines beside tokens on a non-retrieval row with a navigable body — the count of
|
|
596
|
+
// `N:`-numbered lines (fences and unnumbered prose don't count), so the model can plan
|
|
597
|
+
// a <start,end> slice before paying for an OPEN. READ/FIND own typed extents instead.
|
|
598
|
+
if (body.length > 0 && op !== "READ" && op !== "FIND") {
|
|
400
599
|
const navigable = body.split("\n").filter((l) => /^\d+:/.test(l)).length;
|
|
401
600
|
if (navigable > 0)
|
|
402
601
|
meta.lines = navigable;
|
|
403
602
|
}
|
|
404
603
|
// {§jsonplurnk} — `display` describes the three body states: `none` carries an explicit
|
|
405
604
|
// empty JSON string, `folded` withholds an existing body, and `open` appends that body as
|
|
406
|
-
// the format's one
|
|
605
|
+
// the format's one raw multiline string. The explicit empty body keeps
|
|
407
606
|
// every state self-describing; OPEN/FOLD remain friendly no-ops on `none`.
|
|
408
607
|
const display = body.length === 0 ? "none" : e.folded === true ? "folded" : "open";
|
|
409
608
|
meta.display = display;
|
|
410
609
|
if (display === "none")
|
|
411
610
|
meta.body = "";
|
|
412
611
|
const obj = PacketWire.#canonicalJson(meta);
|
|
413
|
-
|
|
612
|
+
if (display !== "open")
|
|
613
|
+
return obj;
|
|
614
|
+
const chunk = projection.chunk !== null
|
|
615
|
+
? `,"chunk":${JSON.stringify(projection.chunk)}`
|
|
616
|
+
: "";
|
|
617
|
+
return obj.replace(/\}$/, `,"body":${body}${chunk}}`);
|
|
414
618
|
}).join(",\n");
|
|
415
619
|
}
|
|
416
620
|
static #renderActionTarget(target) {
|
|
@@ -437,9 +641,9 @@ export default class PacketWire {
|
|
|
437
641
|
return null;
|
|
438
642
|
if (marker === null || marker === undefined)
|
|
439
643
|
return address;
|
|
440
|
-
const validation = Validator.
|
|
644
|
+
const validation = Validator.validateTextLineMarker(marker);
|
|
441
645
|
if (!validation.valid) {
|
|
442
|
-
throw new TypeError("A COPY/MOVE operand contains an invalid line marker.");
|
|
646
|
+
throw new TypeError("A COPY/MOVE operand contains an invalid text line marker.");
|
|
443
647
|
}
|
|
444
648
|
return `${address}<${marker.marks.join(",")}>`;
|
|
445
649
|
}
|