@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.
- package/CHANGELOG.md +63 -2
- package/README.md +36 -5
- package/dist/agent/child-runtime.js +80 -0
- package/dist/agent/contracts.js +15 -24
- package/dist/agent/host.js +3 -16
- package/dist/agent/index.js +212 -192
- package/dist/agent/journal-tail.js +115 -156
- package/dist/agent/launch.js +20 -8
- package/dist/agent/legacy.js +65 -23
- package/dist/agent/notifications.js +138 -47
- package/dist/agent/observation-state.js +246 -0
- package/dist/agent/observation-view.js +258 -0
- package/dist/agent/observation.js +350 -0
- package/dist/agent/observe-card.js +243 -0
- package/dist/agent/observe-chrome.js +85 -0
- package/dist/agent/observe-client.js +285 -0
- package/dist/agent/observe-layout.js +65 -0
- package/dist/agent/observe-reading.js +84 -0
- package/dist/agent/observe-screen.js +400 -96
- package/dist/agent/observe-transcript.js +382 -0
- package/dist/agent/observe.js +250 -43
- package/dist/agent/parking.js +253 -0
- package/dist/agent/process.js +228 -28
- package/dist/agent/receipts.js +92 -20
- package/dist/agent/runner.js +229 -126
- package/dist/agent/shell.js +2 -1
- package/dist/agent/storage.js +47 -12
- package/dist/agent/tool-schemas.js +20 -0
- package/dist/agent/typebox.js +10 -5
- package/dist/agent/usage.js +0 -115
- package/dist/agent/view.js +46 -16
- package/dist/agent/wake.js +99 -0
- package/dist/build-info.js +1 -1
- package/dist/intercom-client.d.ts +26 -0
- package/dist/intercom-client.js +45 -0
- package/dist/pi-intercom/agent-dir.d.ts +1 -0
- package/dist/pi-intercom/bridge-session.js +2 -1
- package/dist/pi-intercom/broker/broker.js +62 -43
- package/dist/pi-intercom/broker/client-last.d.ts +24 -0
- package/dist/pi-intercom/broker/client-last.js +42 -5
- package/dist/pi-intercom/broker/client-park.d.ts +9 -0
- package/dist/pi-intercom/broker/client-park.js +21 -0
- package/dist/pi-intercom/broker/client.d.ts +59 -0
- package/dist/pi-intercom/broker/client.js +55 -29
- package/dist/pi-intercom/broker/connection.d.ts +29 -0
- package/dist/pi-intercom/broker/framing.d.ts +17 -0
- package/dist/pi-intercom/broker/framing.js +10 -7
- package/dist/pi-intercom/broker/guard.js +23 -0
- package/dist/pi-intercom/broker/last.d.ts +30 -0
- package/dist/pi-intercom/broker/last.js +87 -40
- package/dist/pi-intercom/broker/parked.js +107 -0
- package/dist/pi-intercom/broker/paths.d.ts +13 -0
- package/dist/pi-intercom/broker/paths.js +35 -12
- package/dist/pi-intercom/broker/pid.js +5 -1
- package/dist/pi-intercom/broker/server-connection.js +20 -1
- package/dist/pi-intercom/broker/snapshot-reader.d.ts +9 -0
- package/dist/pi-intercom/broker/snapshots.d.ts +29 -0
- package/dist/pi-intercom/broker/targets.d.ts +9 -0
- package/dist/pi-intercom/connection.js +71 -20
- package/dist/pi-intercom/identity.js +6 -5
- package/dist/pi-intercom/inbound-delivery.js +16 -60
- package/dist/pi-intercom/inbound-journal.js +83 -6
- package/dist/pi-intercom/inbound-record.js +18 -1
- package/dist/pi-intercom/inbound.js +22 -37
- package/dist/pi-intercom/index.js +41 -0
- package/dist/pi-intercom/last-message.js +4 -16
- package/dist/pi-intercom/lifecycle.js +88 -3
- package/dist/pi-intercom/outbound.js +5 -15
- package/dist/pi-intercom/reply-tracker.js +7 -6
- package/dist/pi-intercom/reply-wait.js +2 -2
- package/dist/pi-intercom/session-targets.d.ts +24 -0
- package/dist/pi-intercom/tool-registration.js +4 -1
- package/dist/pi-intercom/tool-results.js +5 -7
- package/dist/pi-intercom/tool-schemas.js +12 -26
- package/dist/pi-intercom/types.d.ts +212 -0
- package/dist/pi-intercom/types.js +54 -3
- package/dist/pi-intercom/validation.d.ts +12 -0
- package/dist/pi-intercom/validation.js +3 -0
- package/dist/shared/bounded-json.js +151 -0
- package/dist/shared/compact-cards.js +66 -0
- package/dist/shared/journal-frames.js +3 -6
- package/dist/shared/json-projection.js +267 -129
- package/dist/shared/native-journal.js +123 -56
- package/dist/shared/parking.js +12 -0
- package/dist/shared/post-exit-stdio-guard.js +120 -7
- package/dist/shared/tui-action.js +29 -0
- package/dist/shared/unknown.d.ts +9 -0
- package/docs/code-quality.md +5 -3
- package/docs/development.md +42 -3
- package/docs/intercom-bridge.md +9 -4
- package/docs/intercom.md +228 -7
- package/docs/performance.md +118 -14
- package/docs/reference.md +168 -20
- package/docs/retired-history-maintenance.md +252 -0
- package/package.json +28 -15
- package/scripts/archive-retired-history.mjs +464 -0
- package/scripts/build.mjs +48 -28
- package/scripts/measure-size.mjs +1 -1
- package/scripts/native-package-smoke.mjs +153 -12
- package/scripts/package-smoke.mjs +80 -11
- package/scripts/prepare.mjs +2 -2
- package/scripts/real-pi-live.mjs +377 -0
- package/scripts/real-pi-processes.mjs +6 -1
- package/scripts/real-pi-smoke.mjs +6 -282
- package/scripts/run-tests.mjs +4 -2
- package/scripts/typescript.mjs +35 -0
- package/skills/pi-intercom/SKILL.md +2 -1
- package/skills/pi-subagents/SKILL.md +23 -5
- package/src/agent/child-runtime.ts +105 -0
- package/src/agent/contracts.ts +18 -34
- package/src/agent/host.ts +39 -20
- package/src/agent/index.ts +234 -207
- package/src/agent/journal-tail.ts +141 -153
- package/src/agent/launch.ts +33 -9
- package/src/agent/legacy.ts +85 -31
- package/src/agent/notifications.ts +192 -67
- package/src/agent/observation-state.ts +277 -0
- package/src/agent/observation-view.ts +267 -0
- package/src/agent/observation.ts +409 -0
- package/src/agent/observe-card.ts +304 -0
- package/src/agent/observe-chrome.ts +170 -0
- package/src/agent/observe-client.ts +318 -0
- package/src/agent/observe-layout.ts +79 -0
- package/src/agent/observe-reading.ts +97 -0
- package/src/agent/observe-screen.ts +443 -129
- package/src/agent/observe-transcript.ts +434 -0
- package/src/agent/observe.ts +304 -71
- package/src/agent/parking.ts +341 -0
- package/src/agent/process.ts +280 -37
- package/src/agent/receipts.ts +114 -24
- package/src/agent/runner.ts +227 -149
- package/src/agent/shell.ts +2 -1
- package/src/agent/storage.ts +44 -11
- package/src/agent/tool-schemas.ts +33 -0
- package/src/agent/typebox.ts +12 -7
- package/src/agent/usage.ts +0 -130
- package/src/agent/view.ts +70 -20
- package/src/agent/wake.ts +107 -0
- package/src/intercom-client.ts +108 -0
- package/src/pi-intercom/bridge-session.ts +2 -2
- package/src/pi-intercom/broker/broker.ts +64 -53
- package/src/pi-intercom/broker/client-last.ts +65 -12
- package/src/pi-intercom/broker/client-park.ts +23 -0
- package/src/pi-intercom/broker/client.ts +63 -45
- package/src/pi-intercom/broker/framing.ts +11 -8
- package/src/pi-intercom/broker/guard.ts +33 -0
- package/src/pi-intercom/broker/last.ts +131 -43
- package/src/pi-intercom/broker/parked.ts +130 -0
- package/src/pi-intercom/broker/paths.ts +39 -12
- package/src/pi-intercom/broker/pid.ts +6 -1
- package/src/pi-intercom/broker/server-connection.ts +27 -2
- package/src/pi-intercom/connection.ts +103 -39
- package/src/pi-intercom/identity.ts +8 -5
- package/src/pi-intercom/inbound-delivery.ts +20 -66
- package/src/pi-intercom/inbound-journal.ts +103 -7
- package/src/pi-intercom/inbound-record.ts +21 -4
- package/src/pi-intercom/inbound.ts +32 -49
- package/src/pi-intercom/index.ts +44 -0
- package/src/pi-intercom/last-message.ts +11 -20
- package/src/pi-intercom/lifecycle.ts +117 -14
- package/src/pi-intercom/outbound.ts +7 -16
- package/src/pi-intercom/reply-tracker.ts +8 -6
- package/src/pi-intercom/reply-wait.ts +3 -2
- package/src/pi-intercom/runtime-types.ts +0 -1
- package/src/pi-intercom/tool-registration.ts +4 -1
- package/src/pi-intercom/tool-results.ts +10 -9
- package/src/pi-intercom/tool-schemas.ts +12 -44
- package/src/pi-intercom/types.ts +115 -4
- package/src/pi-intercom/validation.ts +4 -0
- package/src/shared/bounded-json.ts +162 -0
- package/src/shared/compact-cards.ts +118 -0
- package/src/shared/journal-frames.ts +3 -19
- package/src/shared/json-projection.ts +267 -147
- package/src/shared/native-journal.ts +157 -75
- package/src/shared/parking.ts +22 -0
- package/src/shared/post-exit-stdio-guard.ts +165 -7
- package/src/shared/tui-action.ts +39 -0
- package/tsconfig.client.json +8 -0
- package/tsconfig.json +1 -0
- package/src/shared/stream-json.d.ts +0 -10
|
@@ -1,65 +1,116 @@
|
|
|
1
|
-
import { jsonParser } from "stream-json/core/parser.js";
|
|
2
|
-
import { none } from "stream-chain/defs.js";
|
|
3
1
|
import { isRecord } from "./unknown.js";
|
|
2
|
+
// Grammar positions between tokens, then the two scalar states that can span chunks.
|
|
3
|
+
const VALUE = 0;
|
|
4
|
+
const FIRST_VALUE = 1;
|
|
5
|
+
const KEY = 2;
|
|
6
|
+
const FIRST_KEY = 3;
|
|
7
|
+
const COLON = 4;
|
|
8
|
+
const AFTER = 5;
|
|
9
|
+
const DONE = 6;
|
|
10
|
+
const STRING = 7;
|
|
11
|
+
const NUMBER = 8;
|
|
12
|
+
// Unescaped units exclude quote, backslash and C0 controls. Native regexp code skips a bounded
|
|
13
|
+
// run of them and valid escapes, so JavaScript handles only the unit that stopped it.
|
|
14
|
+
const BODY = /[ !#-[\]-\uffff]*(?:\\(?:["\\/bfnrt]|u[\da-fA-F]{4})[ !#-[\]-\uffff]*){0,1024}/y;
|
|
15
|
+
const LITERALS = new Map([
|
|
16
|
+
[102, ["false", false]],
|
|
17
|
+
[110, ["null", null]],
|
|
18
|
+
[116, ["true", true]],
|
|
19
|
+
]);
|
|
20
|
+
// Number states: start, sign, zero, integer, point, fraction, e, exponent sign, exponent.
|
|
21
|
+
// Columns: "0", "1"-"9", ".", "e"/"E", "+"/"-". A missing transition ends the number;
|
|
22
|
+
// only "-" reaches the start state's sign column because values dispatch on their first unit.
|
|
23
|
+
const NUMBER_NEXT = [
|
|
24
|
+
[2, 3, -1, -1, 1],
|
|
25
|
+
[2, 3],
|
|
26
|
+
[-1, -1, 4, 6],
|
|
27
|
+
[3, 3, 4, 6],
|
|
28
|
+
[5, 5],
|
|
29
|
+
[5, 5, -1, 6],
|
|
30
|
+
[8, 8, -1, -1, 7],
|
|
31
|
+
[8, 8],
|
|
32
|
+
[8, 8],
|
|
33
|
+
];
|
|
34
|
+
const NUMBER_END = new Set([2, 3, 5, 8]);
|
|
35
|
+
const NUMBER_COLUMN = new Int8Array(128).fill(-1);
|
|
36
|
+
for (const [column, units] of ["0", "123456789", ".", "eE", "+-"].entries()) {
|
|
37
|
+
for (const unit of units) {
|
|
38
|
+
NUMBER_COLUMN[unit.charCodeAt(0)] = column;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Classify where BODY stopped short of a closing quote. True means the chunk ends at or inside an
|
|
43
|
+
* escape, so the rest carries; false means a bounded run ended at a valid escape. Controls throw,
|
|
44
|
+
* and so does a complete escape BODY made no progress at, because BODY consumes any valid one.
|
|
45
|
+
*/
|
|
46
|
+
function chunkEnds(text, end, progressed) {
|
|
47
|
+
if (end === text.length) {
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
if (text.charCodeAt(end) !== 92) {
|
|
51
|
+
throw new SyntaxError("Bad control character in JSON string");
|
|
52
|
+
}
|
|
53
|
+
if (end + (text.charCodeAt(end + 1) === 117 ? 6 : 2) > text.length) {
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
if (!progressed) {
|
|
57
|
+
throw new SyntaxError("Bad escaped character in JSON string");
|
|
58
|
+
}
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
function unexpected() {
|
|
62
|
+
return new SyntaxError("Unexpected character in JSON");
|
|
63
|
+
}
|
|
4
64
|
function retained(keep) {
|
|
5
65
|
return keep === true || (typeof keep === "number" && keep !== 0 && !Number.isNaN(keep));
|
|
6
66
|
}
|
|
7
|
-
/** Validate all
|
|
67
|
+
/** Validate all JSON text, assembling selected values only. Skipped strings are never decoded. */
|
|
8
68
|
export class JsonProjection {
|
|
9
|
-
parse = jsonParser({ packValues: false });
|
|
10
69
|
stack = [];
|
|
11
|
-
|
|
70
|
+
state = VALUE;
|
|
71
|
+
carry = "";
|
|
72
|
+
path = [];
|
|
12
73
|
key = false;
|
|
13
|
-
|
|
14
|
-
|
|
74
|
+
textCap = 0;
|
|
75
|
+
text = "";
|
|
76
|
+
numberState = 0;
|
|
15
77
|
select;
|
|
16
78
|
stringChunk;
|
|
17
79
|
keys;
|
|
18
|
-
limits;
|
|
19
80
|
value;
|
|
20
|
-
constructor(select, stringChunk, keys = () => 4096
|
|
81
|
+
constructor(select, stringChunk, keys = () => 4096) {
|
|
21
82
|
this.select = select;
|
|
22
83
|
this.stringChunk = stringChunk;
|
|
23
84
|
this.keys = keys;
|
|
24
|
-
this.limits = limits;
|
|
25
85
|
}
|
|
26
86
|
root() {
|
|
27
87
|
return isRecord(this.value) ? this.value : undefined;
|
|
28
88
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
if (!parent) {
|
|
32
|
-
throw new SyntaxError("JSON token requires a containing object");
|
|
33
|
-
}
|
|
34
|
-
return parent;
|
|
35
|
-
}
|
|
36
|
-
selected(path) {
|
|
37
|
-
const parent = this.stack.at(-1);
|
|
38
|
-
const keep = parent && parent.value === undefined ? false : this.select(path, this.root());
|
|
39
|
-
if (retained(keep) && this.limits && ++this.nodes > this.limits.nodes) {
|
|
40
|
-
throw new RangeError("JSON projection exceeds its assembled-node budget.");
|
|
41
|
-
}
|
|
42
|
-
return keep;
|
|
89
|
+
selected() {
|
|
90
|
+
return this.select(this.path, this.root());
|
|
43
91
|
}
|
|
44
|
-
|
|
92
|
+
/** Paths inside skipped containers are only built for string observers, never selected. */
|
|
93
|
+
start() {
|
|
45
94
|
const parent = this.stack.at(-1);
|
|
46
|
-
if (this.limits &&
|
|
47
|
-
(this.stack.length > this.limits.depth || (parent && parent.index >= this.limits.arrayLength))) {
|
|
48
|
-
throw new RangeError("JSON projection exceeds its depth or array-position budget.");
|
|
49
|
-
}
|
|
50
95
|
if (!parent) {
|
|
51
|
-
|
|
96
|
+
this.path = [];
|
|
97
|
+
return this.selected();
|
|
52
98
|
}
|
|
53
|
-
|
|
99
|
+
const step = parent.array ? parent.index++ : parent.key;
|
|
100
|
+
if (parent.value !== undefined) {
|
|
101
|
+
this.path = [...parent.path, step];
|
|
102
|
+
return this.selected();
|
|
103
|
+
}
|
|
104
|
+
this.path = this.stringChunk ? [...parent.path, step] : parent.path;
|
|
105
|
+
return false;
|
|
54
106
|
}
|
|
55
|
-
put(
|
|
107
|
+
put(value) {
|
|
56
108
|
const parent = this.stack.at(-1);
|
|
109
|
+
const key = this.path.at(-1);
|
|
57
110
|
if (!parent) {
|
|
58
111
|
this.value = value;
|
|
59
|
-
return;
|
|
60
112
|
}
|
|
61
|
-
|
|
62
|
-
if (parent.value !== undefined && key !== undefined) {
|
|
113
|
+
else if (parent.value !== undefined && key !== undefined) {
|
|
63
114
|
Object.defineProperty(parent.value, key, {
|
|
64
115
|
value,
|
|
65
116
|
enumerable: true,
|
|
@@ -68,124 +119,211 @@ export class JsonProjection {
|
|
|
68
119
|
});
|
|
69
120
|
}
|
|
70
121
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
122
|
+
ended() {
|
|
123
|
+
this.state = this.stack.length === 0 ? DONE : AFTER;
|
|
124
|
+
}
|
|
125
|
+
close(index) {
|
|
126
|
+
this.stack.pop();
|
|
127
|
+
this.ended();
|
|
128
|
+
return index + 1;
|
|
129
|
+
}
|
|
130
|
+
scalar(state, key, keep) {
|
|
131
|
+
const cap = keep === true ? Infinity : Number(keep);
|
|
132
|
+
this.state = state;
|
|
133
|
+
this.key = key;
|
|
134
|
+
this.textCap = Number.isNaN(cap) ? 0 : cap;
|
|
135
|
+
this.text = "";
|
|
136
|
+
this.numberState = 0;
|
|
137
|
+
}
|
|
138
|
+
append(text) {
|
|
139
|
+
if (this.text.length < this.textCap) {
|
|
140
|
+
this.text += text.slice(0, this.textCap - this.text.length);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
container(array) {
|
|
74
144
|
let value;
|
|
75
|
-
if (retained(
|
|
145
|
+
if (retained(this.start())) {
|
|
76
146
|
value = array ? [] : {};
|
|
77
|
-
this.put(
|
|
147
|
+
this.put(value);
|
|
78
148
|
}
|
|
79
|
-
this.stack.push({ path, value, key: "", index:
|
|
149
|
+
this.stack.push({ path: this.path, value, array, key: "", index: 0 });
|
|
150
|
+
this.state = array ? FIRST_VALUE : FIRST_KEY;
|
|
80
151
|
}
|
|
81
|
-
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
152
|
+
literal(text, index, code) {
|
|
153
|
+
const literal = LITERALS.get(code);
|
|
154
|
+
if (!literal) {
|
|
155
|
+
throw unexpected();
|
|
156
|
+
}
|
|
157
|
+
const [word, value] = literal;
|
|
158
|
+
if (text.startsWith(word, index)) {
|
|
159
|
+
if (retained(this.start())) {
|
|
160
|
+
this.put(value);
|
|
161
|
+
}
|
|
162
|
+
this.ended();
|
|
163
|
+
return index + word.length;
|
|
164
|
+
}
|
|
165
|
+
if (text.length - index < word.length && word.startsWith(text.slice(index))) {
|
|
166
|
+
this.carry = text.slice(index);
|
|
167
|
+
return text.length;
|
|
168
|
+
}
|
|
169
|
+
throw unexpected();
|
|
87
170
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
parent.key.length + text.length > this.limits.keyLength) {
|
|
93
|
-
throw new RangeError("JSON projection exceeds its property-key budget.");
|
|
171
|
+
startValue(text, index, code) {
|
|
172
|
+
if (code === 34) {
|
|
173
|
+
this.scalar(STRING, false, this.start());
|
|
174
|
+
return index + 1;
|
|
94
175
|
}
|
|
95
|
-
if (
|
|
96
|
-
|
|
176
|
+
if (code === 45 || (code >= 48 && code <= 57)) {
|
|
177
|
+
this.scalar(NUMBER, false, this.start());
|
|
178
|
+
return index;
|
|
97
179
|
}
|
|
180
|
+
if (code === 123 || code === 91) {
|
|
181
|
+
this.container(code === 91);
|
|
182
|
+
return index + 1;
|
|
183
|
+
}
|
|
184
|
+
return this.literal(text, index, code);
|
|
98
185
|
}
|
|
99
|
-
|
|
100
|
-
const
|
|
101
|
-
if (
|
|
102
|
-
return;
|
|
186
|
+
member(index, code) {
|
|
187
|
+
const parent = this.stack.at(-1);
|
|
188
|
+
if (code === 125 && this.state === FIRST_KEY) {
|
|
189
|
+
return this.close(index);
|
|
190
|
+
}
|
|
191
|
+
if (code !== 34 || !parent) {
|
|
192
|
+
throw unexpected();
|
|
103
193
|
}
|
|
104
|
-
|
|
105
|
-
|
|
194
|
+
this.scalar(STRING, true, parent.value === undefined ? 0 : this.keys(parent.path, this.root()));
|
|
195
|
+
return index + 1;
|
|
196
|
+
}
|
|
197
|
+
after(index, code) {
|
|
198
|
+
const parent = this.stack.at(-1);
|
|
199
|
+
if (parent && code === 44) {
|
|
200
|
+
this.state = parent.array ? VALUE : KEY;
|
|
201
|
+
return index + 1;
|
|
106
202
|
}
|
|
107
|
-
if (
|
|
108
|
-
|
|
203
|
+
if (parent && code === (parent.array ? 93 : 125)) {
|
|
204
|
+
return this.close(index);
|
|
109
205
|
}
|
|
206
|
+
throw unexpected();
|
|
110
207
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
208
|
+
structure(text, index, code) {
|
|
209
|
+
switch (this.state) {
|
|
210
|
+
case VALUE:
|
|
211
|
+
return this.startValue(text, index, code);
|
|
212
|
+
case FIRST_VALUE:
|
|
213
|
+
return code === 93 ? this.close(index) : this.startValue(text, index, code);
|
|
214
|
+
case KEY:
|
|
215
|
+
case FIRST_KEY:
|
|
216
|
+
return this.member(index, code);
|
|
217
|
+
case COLON:
|
|
218
|
+
if (code !== 58) {
|
|
219
|
+
throw unexpected();
|
|
220
|
+
}
|
|
221
|
+
this.state = VALUE;
|
|
222
|
+
return index + 1;
|
|
223
|
+
case AFTER:
|
|
224
|
+
return this.after(index, code);
|
|
225
|
+
default:
|
|
226
|
+
throw unexpected();
|
|
115
227
|
}
|
|
116
|
-
this.scalar = undefined;
|
|
117
228
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
229
|
+
observed(decoded) {
|
|
230
|
+
if (decoded === "") {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
if (this.stringChunk && !this.key) {
|
|
234
|
+
this.stringChunk(this.path, decoded, this.root());
|
|
235
|
+
}
|
|
236
|
+
this.append(decoded);
|
|
237
|
+
}
|
|
238
|
+
closeString() {
|
|
239
|
+
const parent = this.stack.at(-1);
|
|
240
|
+
if (this.key && parent) {
|
|
241
|
+
parent.key = this.text;
|
|
242
|
+
this.state = COLON;
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
if (this.textCap !== 0) {
|
|
246
|
+
this.put(this.text);
|
|
126
247
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
this.
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
case "nullValue": {
|
|
162
|
-
const path = this.nextPath();
|
|
163
|
-
const keep = this.selected(path);
|
|
164
|
-
if (retained(keep)) {
|
|
165
|
-
this.put(path, token.value);
|
|
166
|
-
}
|
|
248
|
+
this.ended();
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
/** Observed values and unfinished selections need text; others are only validated. */
|
|
252
|
+
decoding() {
|
|
253
|
+
return (this.stringChunk !== undefined && !this.key) || this.text.length < this.textCap;
|
|
254
|
+
}
|
|
255
|
+
string(text, start) {
|
|
256
|
+
for (let index = start;;) {
|
|
257
|
+
BODY.lastIndex = index;
|
|
258
|
+
BODY.test(text);
|
|
259
|
+
const end = BODY.lastIndex;
|
|
260
|
+
if (end > index && this.decoding()) {
|
|
261
|
+
const raw = text.slice(index, end);
|
|
262
|
+
// A matched run is a complete valid string body no longer than this chunk.
|
|
263
|
+
this.observed(raw.includes("\\") ? String(JSON.parse(`"${raw}"`)) : raw);
|
|
264
|
+
}
|
|
265
|
+
if (text.charCodeAt(end) === 34) {
|
|
266
|
+
this.closeString();
|
|
267
|
+
return end + 1;
|
|
268
|
+
}
|
|
269
|
+
if (chunkEnds(text, end, end > index)) {
|
|
270
|
+
this.carry = text.slice(end);
|
|
271
|
+
return text.length;
|
|
272
|
+
}
|
|
273
|
+
index = end;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
number(text, start, final) {
|
|
277
|
+
let state = this.numberState;
|
|
278
|
+
let index = start;
|
|
279
|
+
for (; index < text.length; index++) {
|
|
280
|
+
const next = NUMBER_NEXT[state]?.[NUMBER_COLUMN[text.charCodeAt(index)] ?? -1] ?? -1;
|
|
281
|
+
if (next < 0) {
|
|
167
282
|
break;
|
|
168
283
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
284
|
+
state = next;
|
|
285
|
+
}
|
|
286
|
+
this.numberState = state;
|
|
287
|
+
this.append(text.slice(start, index));
|
|
288
|
+
if (index === text.length && !final) {
|
|
289
|
+
return index;
|
|
174
290
|
}
|
|
291
|
+
if (!NUMBER_END.has(state)) {
|
|
292
|
+
throw new SyntaxError("Incomplete number in JSON");
|
|
293
|
+
}
|
|
294
|
+
if (this.textCap !== 0) {
|
|
295
|
+
this.put(Number(this.text));
|
|
296
|
+
}
|
|
297
|
+
this.ended();
|
|
298
|
+
return index;
|
|
175
299
|
}
|
|
176
300
|
write(chunk) {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
this.
|
|
301
|
+
const text = this.carry + chunk;
|
|
302
|
+
this.carry = "";
|
|
303
|
+
let index = 0;
|
|
304
|
+
while (index < text.length) {
|
|
305
|
+
const code = text.charCodeAt(index);
|
|
306
|
+
if (this.state === STRING) {
|
|
307
|
+
index = this.string(text, index);
|
|
308
|
+
}
|
|
309
|
+
else if (this.state === NUMBER) {
|
|
310
|
+
index = this.number(text, index, false);
|
|
311
|
+
}
|
|
312
|
+
else if (code === 32 || code === 10 || code === 13 || code === 9) {
|
|
313
|
+
index++;
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
316
|
+
index = this.structure(text, index, code);
|
|
184
317
|
}
|
|
185
318
|
}
|
|
186
319
|
}
|
|
187
320
|
finish() {
|
|
188
|
-
this.
|
|
321
|
+
if (this.state === NUMBER) {
|
|
322
|
+
this.number("", 0, true);
|
|
323
|
+
}
|
|
324
|
+
if (this.state !== DONE || this.carry !== "") {
|
|
325
|
+
throw new SyntaxError("Unexpected end of JSON input");
|
|
326
|
+
}
|
|
189
327
|
return this.value;
|
|
190
328
|
}
|
|
191
329
|
}
|