@fitchmultz/pi-subagents 0.50.0 → 0.52.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 (180) hide show
  1. package/CHANGELOG.md +63 -2
  2. package/README.md +36 -5
  3. package/dist/agent/child-runtime.js +80 -0
  4. package/dist/agent/contracts.js +15 -24
  5. package/dist/agent/host.js +3 -16
  6. package/dist/agent/index.js +212 -192
  7. package/dist/agent/journal-tail.js +115 -156
  8. package/dist/agent/launch.js +20 -8
  9. package/dist/agent/legacy.js +65 -23
  10. package/dist/agent/notifications.js +138 -47
  11. package/dist/agent/observation-state.js +246 -0
  12. package/dist/agent/observation-view.js +258 -0
  13. package/dist/agent/observation.js +350 -0
  14. package/dist/agent/observe-card.js +243 -0
  15. package/dist/agent/observe-chrome.js +85 -0
  16. package/dist/agent/observe-client.js +285 -0
  17. package/dist/agent/observe-layout.js +65 -0
  18. package/dist/agent/observe-reading.js +84 -0
  19. package/dist/agent/observe-screen.js +400 -96
  20. package/dist/agent/observe-transcript.js +382 -0
  21. package/dist/agent/observe.js +250 -43
  22. package/dist/agent/parking.js +253 -0
  23. package/dist/agent/process.js +228 -28
  24. package/dist/agent/receipts.js +92 -20
  25. package/dist/agent/runner.js +229 -126
  26. package/dist/agent/shell.js +2 -1
  27. package/dist/agent/storage.js +47 -12
  28. package/dist/agent/tool-schemas.js +20 -0
  29. package/dist/agent/typebox.js +10 -5
  30. package/dist/agent/usage.js +0 -115
  31. package/dist/agent/view.js +46 -16
  32. package/dist/agent/wake.js +99 -0
  33. package/dist/build-info.js +1 -1
  34. package/dist/intercom-client.d.ts +26 -0
  35. package/dist/intercom-client.js +45 -0
  36. package/dist/pi-intercom/agent-dir.d.ts +1 -0
  37. package/dist/pi-intercom/bridge-session.js +2 -1
  38. package/dist/pi-intercom/broker/broker.js +62 -43
  39. package/dist/pi-intercom/broker/client-last.d.ts +24 -0
  40. package/dist/pi-intercom/broker/client-last.js +42 -5
  41. package/dist/pi-intercom/broker/client-park.d.ts +9 -0
  42. package/dist/pi-intercom/broker/client-park.js +21 -0
  43. package/dist/pi-intercom/broker/client.d.ts +59 -0
  44. package/dist/pi-intercom/broker/client.js +55 -29
  45. package/dist/pi-intercom/broker/connection.d.ts +29 -0
  46. package/dist/pi-intercom/broker/framing.d.ts +17 -0
  47. package/dist/pi-intercom/broker/framing.js +10 -7
  48. package/dist/pi-intercom/broker/guard.js +23 -0
  49. package/dist/pi-intercom/broker/last.d.ts +30 -0
  50. package/dist/pi-intercom/broker/last.js +87 -40
  51. package/dist/pi-intercom/broker/parked.js +107 -0
  52. package/dist/pi-intercom/broker/paths.d.ts +13 -0
  53. package/dist/pi-intercom/broker/paths.js +35 -12
  54. package/dist/pi-intercom/broker/pid.js +5 -1
  55. package/dist/pi-intercom/broker/server-connection.js +20 -1
  56. package/dist/pi-intercom/broker/snapshot-reader.d.ts +9 -0
  57. package/dist/pi-intercom/broker/snapshots.d.ts +29 -0
  58. package/dist/pi-intercom/broker/targets.d.ts +9 -0
  59. package/dist/pi-intercom/connection.js +71 -20
  60. package/dist/pi-intercom/identity.js +6 -5
  61. package/dist/pi-intercom/inbound-delivery.js +16 -60
  62. package/dist/pi-intercom/inbound-journal.js +83 -6
  63. package/dist/pi-intercom/inbound-record.js +18 -1
  64. package/dist/pi-intercom/inbound.js +22 -37
  65. package/dist/pi-intercom/index.js +41 -0
  66. package/dist/pi-intercom/last-message.js +4 -16
  67. package/dist/pi-intercom/lifecycle.js +88 -3
  68. package/dist/pi-intercom/outbound.js +5 -15
  69. package/dist/pi-intercom/reply-tracker.js +7 -6
  70. package/dist/pi-intercom/reply-wait.js +2 -2
  71. package/dist/pi-intercom/session-targets.d.ts +24 -0
  72. package/dist/pi-intercom/tool-registration.js +4 -1
  73. package/dist/pi-intercom/tool-results.js +5 -7
  74. package/dist/pi-intercom/tool-schemas.js +12 -26
  75. package/dist/pi-intercom/types.d.ts +212 -0
  76. package/dist/pi-intercom/types.js +54 -3
  77. package/dist/pi-intercom/validation.d.ts +12 -0
  78. package/dist/pi-intercom/validation.js +3 -0
  79. package/dist/shared/bounded-json.js +151 -0
  80. package/dist/shared/compact-cards.js +66 -0
  81. package/dist/shared/journal-frames.js +3 -6
  82. package/dist/shared/json-projection.js +267 -129
  83. package/dist/shared/native-journal.js +123 -56
  84. package/dist/shared/parking.js +12 -0
  85. package/dist/shared/post-exit-stdio-guard.js +120 -7
  86. package/dist/shared/tui-action.js +29 -0
  87. package/dist/shared/unknown.d.ts +9 -0
  88. package/docs/code-quality.md +5 -3
  89. package/docs/development.md +42 -3
  90. package/docs/intercom-bridge.md +9 -4
  91. package/docs/intercom.md +228 -7
  92. package/docs/performance.md +118 -14
  93. package/docs/reference.md +168 -20
  94. package/docs/retired-history-maintenance.md +252 -0
  95. package/package.json +28 -15
  96. package/scripts/archive-retired-history.mjs +464 -0
  97. package/scripts/build.mjs +48 -28
  98. package/scripts/measure-size.mjs +1 -1
  99. package/scripts/native-package-smoke.mjs +153 -12
  100. package/scripts/package-smoke.mjs +80 -11
  101. package/scripts/prepare.mjs +2 -2
  102. package/scripts/real-pi-live.mjs +377 -0
  103. package/scripts/real-pi-processes.mjs +6 -1
  104. package/scripts/real-pi-smoke.mjs +6 -282
  105. package/scripts/run-tests.mjs +4 -2
  106. package/scripts/typescript.mjs +35 -0
  107. package/skills/pi-intercom/SKILL.md +2 -1
  108. package/skills/pi-subagents/SKILL.md +23 -5
  109. package/src/agent/child-runtime.ts +105 -0
  110. package/src/agent/contracts.ts +18 -34
  111. package/src/agent/host.ts +39 -20
  112. package/src/agent/index.ts +234 -207
  113. package/src/agent/journal-tail.ts +141 -153
  114. package/src/agent/launch.ts +33 -9
  115. package/src/agent/legacy.ts +85 -31
  116. package/src/agent/notifications.ts +192 -67
  117. package/src/agent/observation-state.ts +277 -0
  118. package/src/agent/observation-view.ts +267 -0
  119. package/src/agent/observation.ts +409 -0
  120. package/src/agent/observe-card.ts +304 -0
  121. package/src/agent/observe-chrome.ts +170 -0
  122. package/src/agent/observe-client.ts +318 -0
  123. package/src/agent/observe-layout.ts +79 -0
  124. package/src/agent/observe-reading.ts +97 -0
  125. package/src/agent/observe-screen.ts +443 -129
  126. package/src/agent/observe-transcript.ts +434 -0
  127. package/src/agent/observe.ts +304 -71
  128. package/src/agent/parking.ts +341 -0
  129. package/src/agent/process.ts +280 -37
  130. package/src/agent/receipts.ts +114 -24
  131. package/src/agent/runner.ts +227 -149
  132. package/src/agent/shell.ts +2 -1
  133. package/src/agent/storage.ts +44 -11
  134. package/src/agent/tool-schemas.ts +33 -0
  135. package/src/agent/typebox.ts +12 -7
  136. package/src/agent/usage.ts +0 -130
  137. package/src/agent/view.ts +70 -20
  138. package/src/agent/wake.ts +107 -0
  139. package/src/intercom-client.ts +108 -0
  140. package/src/pi-intercom/bridge-session.ts +2 -2
  141. package/src/pi-intercom/broker/broker.ts +64 -53
  142. package/src/pi-intercom/broker/client-last.ts +65 -12
  143. package/src/pi-intercom/broker/client-park.ts +23 -0
  144. package/src/pi-intercom/broker/client.ts +63 -45
  145. package/src/pi-intercom/broker/framing.ts +11 -8
  146. package/src/pi-intercom/broker/guard.ts +33 -0
  147. package/src/pi-intercom/broker/last.ts +131 -43
  148. package/src/pi-intercom/broker/parked.ts +130 -0
  149. package/src/pi-intercom/broker/paths.ts +39 -12
  150. package/src/pi-intercom/broker/pid.ts +6 -1
  151. package/src/pi-intercom/broker/server-connection.ts +27 -2
  152. package/src/pi-intercom/connection.ts +103 -39
  153. package/src/pi-intercom/identity.ts +8 -5
  154. package/src/pi-intercom/inbound-delivery.ts +20 -66
  155. package/src/pi-intercom/inbound-journal.ts +103 -7
  156. package/src/pi-intercom/inbound-record.ts +21 -4
  157. package/src/pi-intercom/inbound.ts +32 -49
  158. package/src/pi-intercom/index.ts +44 -0
  159. package/src/pi-intercom/last-message.ts +11 -20
  160. package/src/pi-intercom/lifecycle.ts +117 -14
  161. package/src/pi-intercom/outbound.ts +7 -16
  162. package/src/pi-intercom/reply-tracker.ts +8 -6
  163. package/src/pi-intercom/reply-wait.ts +3 -2
  164. package/src/pi-intercom/runtime-types.ts +0 -1
  165. package/src/pi-intercom/tool-registration.ts +4 -1
  166. package/src/pi-intercom/tool-results.ts +10 -9
  167. package/src/pi-intercom/tool-schemas.ts +12 -44
  168. package/src/pi-intercom/types.ts +115 -4
  169. package/src/pi-intercom/validation.ts +4 -0
  170. package/src/shared/bounded-json.ts +162 -0
  171. package/src/shared/compact-cards.ts +118 -0
  172. package/src/shared/journal-frames.ts +3 -19
  173. package/src/shared/json-projection.ts +267 -147
  174. package/src/shared/native-journal.ts +157 -75
  175. package/src/shared/parking.ts +22 -0
  176. package/src/shared/post-exit-stdio-guard.ts +165 -7
  177. package/src/shared/tui-action.ts +39 -0
  178. package/tsconfig.client.json +8 -0
  179. package/tsconfig.json +1 -0
  180. package/src/shared/stream-json.d.ts +0 -10
@@ -1,4 +1,4 @@
1
- import { finiteNumber, isRecord, isUnknownArray, optionalBoolean, optionalFiniteNumber, optionalLabel, safeLabel, safeText, } from "./validation.js";
1
+ import { finiteNumber, isRecord, isUnknownArray, nonNegativeInteger, optionalBoolean, optionalFiniteNumber, optionalLabel, safeLabel, safeText, } from "./validation.js";
2
2
  export function isTopicSubscription(value) {
3
3
  return (isRecord(value) &&
4
4
  typeof value.topic === "string" &&
@@ -30,6 +30,23 @@ export function isTopicUpdate(value) {
30
30
  finiteNumber(value.updatedAt) &&
31
31
  validTopicOwnership(value));
32
32
  }
33
+ export function isContextTarget(value) {
34
+ return (isRecord(value) &&
35
+ ["rootSessionId", "peerId", "incarnation"].every((key) => safeLabel(value[key])));
36
+ }
37
+ export function isDeliveryGuard(value) {
38
+ return isContextTarget(value) && "applicationGuard" in value && safeLabel(value.applicationGuard);
39
+ }
40
+ export function isPublicationReplyHint(value) {
41
+ return (isRecord(value) &&
42
+ typeof value.tool === "string" &&
43
+ /^[a-zA-Z_][a-zA-Z0-9_]{0,79}$/.test(value.tool) &&
44
+ typeof value.commandId === "string" &&
45
+ /^[a-f0-9]{8}(?:-[a-f0-9]{4}){3}-[a-f0-9]{12}$/.test(value.commandId) &&
46
+ (value.commandFingerprint === undefined ||
47
+ (typeof value.commandFingerprint === "string" &&
48
+ /^[a-f0-9]{64}$/.test(value.commandFingerprint))));
49
+ }
33
50
  export function isHumanMessageOrigin(value) {
34
51
  if (!isRecord(value)) {
35
52
  return false;
@@ -50,6 +67,9 @@ export function isAttachment(value) {
50
67
  return (validType && safeLabel(value.name) && safeText(value.content) && optionalLabel(value.language));
51
68
  }
52
69
  function validMessageOrigin(message) {
70
+ if (!validMessageGuard(message)) {
71
+ return false;
72
+ }
53
73
  if (message.human !== undefined && !isHumanMessageOrigin(message.human)) {
54
74
  return false;
55
75
  }
@@ -61,6 +81,17 @@ function validMessageOrigin(message) {
61
81
  (message.expectsReply === undefined || message.expectsReply === false) &&
62
82
  message.replyTo === undefined);
63
83
  }
84
+ function validMessageGuard(message) {
85
+ if (message.guard === undefined) {
86
+ return message.replyHint === undefined;
87
+ }
88
+ return (isDeliveryGuard(message.guard) &&
89
+ message.expectsReply === false &&
90
+ message.replyTo === undefined &&
91
+ message.human === undefined &&
92
+ message.topic === undefined &&
93
+ (message.replyHint === undefined || isPublicationReplyHint(message.replyHint)));
94
+ }
64
95
  function validDelivery(message) {
65
96
  if (message.delivery !== undefined &&
66
97
  message.delivery !== "queue" &&
@@ -136,8 +167,11 @@ function validSessionTopics(session) {
136
167
  (isUnknownArray(session.topics) && session.topics.every(isTopicUpdate))));
137
168
  }
138
169
  function validSessionLineage(value) {
139
- return (optionalLabel(value.rootSessionId) &&
140
- optionalLabel(value.parentSessionId) &&
170
+ return (["rootSessionId", "parentSessionId", "incarnation", "applicationGuard"].every((key) => optionalLabel(value[key])) &&
171
+ (value.guardedDelivery === undefined ||
172
+ (value.guardedDelivery === 1 &&
173
+ safeLabel(value.incarnation) &&
174
+ safeLabel(value.rootSessionId))) &&
141
175
  (value.parentSessionId === undefined || value.rootSessionId === value.parentSessionId));
142
176
  }
143
177
  function validSessionProject(value) {
@@ -205,3 +239,20 @@ export function normalizeMessage(value) {
205
239
  };
206
240
  return isMessage(restored) ? restored : null;
207
241
  }
242
+ export const LAST_MESSAGE_PAGE_LIMIT = 16384;
243
+ function optionalEntryId(value) {
244
+ return value === undefined || (typeof value === "string" && value.length > 0);
245
+ }
246
+ export function isLastMessageQuery(value) {
247
+ return (isRecord(value) &&
248
+ value.messageId === undefined &&
249
+ optionalEntryId(value.entryId) &&
250
+ (value.offset === undefined || nonNegativeInteger(value.offset)) &&
251
+ (value.limit === undefined ||
252
+ (nonNegativeInteger(value.limit) &&
253
+ value.limit > 0 &&
254
+ value.limit <= LAST_MESSAGE_PAGE_LIMIT)));
255
+ }
256
+ export function isReceiptQuery(value) {
257
+ return isRecord(value) && [value.rootSessionId, value.messageId].every(safeLabel);
258
+ }
@@ -0,0 +1,12 @@
1
+ /** JSON objects are untrusted at the broker and journal boundaries. */
2
+ export declare function isRecord(value: unknown): value is Readonly<Record<string, unknown>>;
3
+ export declare function isUnknownArray(value: unknown): value is readonly unknown[];
4
+ export declare function errorMessage(error: unknown): string;
5
+ export declare function asError(error: unknown): Error;
6
+ export declare function safeText(value: unknown): boolean;
7
+ export declare function safeLabel(value: unknown): boolean;
8
+ export declare function optionalLabel(value: unknown): boolean;
9
+ export declare function optionalBoolean(value: unknown): boolean;
10
+ export declare function finiteNumber(value: unknown): value is number;
11
+ export declare function nonNegativeInteger(value: unknown): value is number;
12
+ export declare function optionalFiniteNumber(value: unknown): boolean;
@@ -54,6 +54,9 @@ export function optionalBoolean(value) {
54
54
  export function finiteNumber(value) {
55
55
  return typeof value === "number" && Number.isFinite(value);
56
56
  }
57
+ export function nonNegativeInteger(value) {
58
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
59
+ }
57
60
  export function optionalFiniteNumber(value) {
58
61
  return value === undefined || finiteNumber(value);
59
62
  }
@@ -0,0 +1,151 @@
1
+ import { types } from "node:util";
2
+ class Limit extends Error {
3
+ reason;
4
+ constructor(reason) {
5
+ super(reason);
6
+ this.reason = reason;
7
+ }
8
+ }
9
+ /**
10
+ * Proxies, accessors and custom serializers would run arbitrary code inside the actor; binary
11
+ * values allocate their full representation. None of them is read.
12
+ */
13
+ function opaque(value) {
14
+ return (types.isProxy(value) ||
15
+ ArrayBuffer.isView(value) ||
16
+ types.isAnyArrayBuffer(value) ||
17
+ "toJSON" in value);
18
+ }
19
+ /** An own data property's value, without invoking a getter. */
20
+ function data(value, key) {
21
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
22
+ if (descriptor !== undefined && !("value" in descriptor)) {
23
+ throw new Limit("unsupported");
24
+ }
25
+ return descriptor?.value;
26
+ }
27
+ /** Serialize like JSON.stringify within byte, node and depth limits, without first cloning. */
28
+ class Writer {
29
+ parts = [];
30
+ bytes = 0;
31
+ nodes = 0;
32
+ ancestors = new Set();
33
+ budget;
34
+ constructor(budget) {
35
+ this.budget = budget;
36
+ }
37
+ text() {
38
+ return this.parts.join("");
39
+ }
40
+ add(text, bytes = text.length) {
41
+ this.bytes += bytes;
42
+ if (this.bytes > this.budget.bytes) {
43
+ throw new Limit("oversize");
44
+ }
45
+ this.parts.push(text);
46
+ }
47
+ string(value) {
48
+ // A string never encodes to fewer bytes than code units; refuse before copying it.
49
+ if (value.length > this.budget.bytes - this.bytes) {
50
+ throw new Limit("oversize");
51
+ }
52
+ const json = JSON.stringify(value);
53
+ this.add(json, Buffer.byteLength(json));
54
+ }
55
+ /** Returns false for values JSON omits from objects and nulls in arrays. */
56
+ value(value, depth) {
57
+ if (++this.nodes > this.budget.nodes) {
58
+ throw new Limit("oversize");
59
+ }
60
+ switch (typeof value) {
61
+ case "string":
62
+ this.string(value);
63
+ return true;
64
+ case "number":
65
+ this.add(Number.isFinite(value) ? String(value) : "null");
66
+ return true;
67
+ case "boolean":
68
+ this.add(String(value));
69
+ return true;
70
+ case "bigint":
71
+ throw new Limit("unsupported");
72
+ case "object":
73
+ this.object(value, depth);
74
+ return true;
75
+ case "undefined":
76
+ case "function":
77
+ case "symbol":
78
+ return false;
79
+ }
80
+ }
81
+ object(value, depth) {
82
+ if (value === null) {
83
+ this.add("null");
84
+ return;
85
+ }
86
+ if (depth >= this.budget.depth) {
87
+ throw new Limit("oversize");
88
+ }
89
+ if (this.ancestors.has(value)) {
90
+ throw new Limit("cyclic");
91
+ }
92
+ if (types.isDate(value) && !types.isProxy(value)) {
93
+ const time = Date.prototype.getTime.call(value);
94
+ this.add(Number.isNaN(time) ? "null" : JSON.stringify(new Date(time).toISOString()));
95
+ return;
96
+ }
97
+ if (opaque(value)) {
98
+ throw new Limit("unsupported");
99
+ }
100
+ this.ancestors.add(value);
101
+ if (Array.isArray(value)) {
102
+ this.array(value, depth + 1);
103
+ }
104
+ else {
105
+ this.record(value, depth + 1);
106
+ }
107
+ this.ancestors.delete(value);
108
+ }
109
+ array(value, depth) {
110
+ this.add("[");
111
+ for (let index = 0; index < value.length; index++) {
112
+ if (index > 0) {
113
+ this.add(",");
114
+ }
115
+ if (!this.value(data(value, String(index)), depth)) {
116
+ this.add("null");
117
+ }
118
+ }
119
+ this.add("]");
120
+ }
121
+ record(value, depth) {
122
+ this.add("{");
123
+ let first = true;
124
+ for (const key of Object.keys(value)) {
125
+ const mark = { parts: this.parts.length, bytes: this.bytes };
126
+ if (!first) {
127
+ this.add(",");
128
+ }
129
+ this.string(key);
130
+ this.add(":");
131
+ if (this.value(data(value, key), depth)) {
132
+ first = false;
133
+ }
134
+ else {
135
+ this.parts.length = mark.parts;
136
+ this.bytes = mark.bytes;
137
+ }
138
+ }
139
+ this.add("}");
140
+ }
141
+ }
142
+ export function boundedJson(value, budget) {
143
+ const writer = new Writer(budget);
144
+ try {
145
+ return writer.value(value, 0) ? { json: writer.text() } : { unavailable: "unsupported" };
146
+ }
147
+ catch (error) {
148
+ // Getters, proxies and revoked proxies are untrusted tool data, not observer failures.
149
+ return { unavailable: error instanceof Limit ? error.reason : "unreadable" };
150
+ }
151
+ }
@@ -0,0 +1,66 @@
1
+ import { getMarkdownTheme, keyHint, truncateToVisualLines, } from "@earendil-works/pi-coding-agent";
2
+ import { Box, Container, Markdown, Spacer, Text, truncateToWidth, } from "@earendil-works/pi-tui";
3
+ import { actionText } from "./tui-action.js";
4
+ function preview(content, expanded, theme, showHint = true) {
5
+ if (expanded) {
6
+ return content;
7
+ }
8
+ let cache;
9
+ return {
10
+ render(width) {
11
+ if (cache?.width !== width) {
12
+ const { visualLines, skippedCount } = truncateToVisualLines(content.render(width).join("\n"), 4, width, 0, "start");
13
+ const hint = theme.fg("dim", `… ${skippedCount} more lines${showHint ? ` · ${keyHint("app.tools.expand", "to expand")}` : ""}`);
14
+ cache = {
15
+ width,
16
+ lines: skippedCount > 0 ? [...visualLines, truncateToWidth(hint, width)] : visualLines,
17
+ };
18
+ }
19
+ return cache.lines;
20
+ },
21
+ invalidate() {
22
+ cache = undefined;
23
+ content.invalidate();
24
+ },
25
+ };
26
+ }
27
+ export const renderCompactResult = (result, { expanded }, theme) => preview(new Text(theme.fg("toolOutput", result.content
28
+ .filter((block) => block.type === "text")
29
+ .map((block) => block.text)
30
+ .join("\n")), 0, 0), expanded, theme);
31
+ export function registerCompactMessages(pi, types) {
32
+ let ui;
33
+ pi.on("session_start", (_event, ctx) => {
34
+ ui = ctx.mode === "tui" ? ctx.ui : undefined;
35
+ });
36
+ pi.on("session_shutdown", () => {
37
+ ui = undefined;
38
+ });
39
+ for (const type of types) {
40
+ pi.registerMessageRenderer(type, (message, { expanded, outputPad }, theme) => {
41
+ const text = typeof message.content === "string"
42
+ ? message.content
43
+ : message.content
44
+ .filter((block) => block.type === "text")
45
+ .map((block) => block.text)
46
+ .join("\n");
47
+ const box = new Box(outputPad, 1, (line) => theme.bg("customMessageBg", line));
48
+ const markdown = new Markdown(text, 0, 0, getMarkdownTheme(), {
49
+ color: (line) => theme.fg("customMessageText", line),
50
+ });
51
+ box.addChild(new (class extends Container {
52
+ render(width) {
53
+ this.clear();
54
+ const label = theme.fg("customMessageLabel", theme.bold(`[${type}]`));
55
+ this.addChild(markdown.render(width).length > 4
56
+ ? actionText(`${label} · ${keyHint("app.tools.expand", expanded ? "to collapse" : "to expand")}`, () => ui?.setToolsExpanded(!expanded))
57
+ : new Text(label, 0, 0));
58
+ return super.render(width);
59
+ }
60
+ })());
61
+ box.addChild(new Spacer(1));
62
+ box.addChild(preview(markdown, expanded, theme, false));
63
+ return box;
64
+ });
65
+ }
66
+ }
@@ -1,5 +1,5 @@
1
1
  import * as fs from "node:fs";
2
- import { JsonProjection, } from "./json-projection.js";
2
+ import { JsonProjection } from "./json-projection.js";
3
3
  import { errorDescription, isRecord } from "./unknown.js";
4
4
  /** Byte-framed JSONL. Publication framing is independent of malformed-record tolerance. */
5
5
  export class JournalFrames {
@@ -26,7 +26,7 @@ export class JournalFrames {
26
26
  this.projection = this.newProjection();
27
27
  }
28
28
  newProjection() {
29
- return new JsonProjection(this.select, this.options.stringChunk, this.options.keys, this.options.limits);
29
+ return new JsonProjection(this.select, this.options.stringChunk);
30
30
  }
31
31
  part(bytes) {
32
32
  if (!this.nonblank && bytes.some((byte) => ![9, 10, 13, 32].includes(byte))) {
@@ -76,10 +76,7 @@ export class JournalFrames {
76
76
  this.error = undefined;
77
77
  this.failed = false;
78
78
  this.nonblank = false;
79
- if (failed) {
80
- this.options.malformed?.(start, end, error);
81
- }
82
- else if (record) {
79
+ if (!failed && record) {
83
80
  this.record(record);
84
81
  }
85
82
  }