@corca-org/ceal-host-linux-arm64 1.0.18 → 1.0.20
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/bin/ceal-host +0 -0
- package/libexec/ceal-host/claude-hook.mjs +2041 -514
- package/libexec/ceal-host/claude-invocation-authentication.mjs +1899 -330
- package/libexec/ceal-host/claude-producer.mjs +1860 -406
- package/libexec/ceal-host/codex-hook.mjs +1618 -1013
- package/libexec/ceal-host/codex-invocation-authentication.mjs +3222 -505
- package/libexec/ceal-host/codex-producer.mjs +1126 -581
- package/libexec/ceal-host/control.mjs +2857 -1134
- package/libexec/ceal-host/relay.mjs +559 -116
- package/package.json +1 -1
- package/share/ceal-host/bundle-manifest.json +12 -12
- package/share/ceal-host/bundle-manifest.sigstore.json +1 -1
|
@@ -1,6 +1,2036 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire as __cealCreateRequire } from "node:module";
|
|
3
3
|
const require = __cealCreateRequire(import.meta.url);
|
|
4
|
+
var __create = Object.create;
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
8
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
9
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
10
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
11
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
12
|
+
}) : x)(function(x) {
|
|
13
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
14
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
15
|
+
});
|
|
16
|
+
var __commonJS = (cb, mod) => function __require2() {
|
|
17
|
+
try {
|
|
18
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
19
|
+
} catch (e) {
|
|
20
|
+
throw mod = 0, e;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
var __copyProps = (to, from, except, desc) => {
|
|
24
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
25
|
+
for (let key of __getOwnPropNames(from))
|
|
26
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
27
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
28
|
+
}
|
|
29
|
+
return to;
|
|
30
|
+
};
|
|
31
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
32
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
33
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
34
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
35
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
36
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
37
|
+
mod
|
|
38
|
+
));
|
|
39
|
+
|
|
40
|
+
// node_modules/.pnpm/@iarna+toml@2.2.5/node_modules/@iarna/toml/lib/parser.js
|
|
41
|
+
var require_parser = __commonJS({
|
|
42
|
+
"node_modules/.pnpm/@iarna+toml@2.2.5/node_modules/@iarna/toml/lib/parser.js"(exports2, module2) {
|
|
43
|
+
"use strict";
|
|
44
|
+
var ParserEND = 1114112;
|
|
45
|
+
var ParserError = class _ParserError extends Error {
|
|
46
|
+
/* istanbul ignore next */
|
|
47
|
+
constructor(msg, filename, linenumber) {
|
|
48
|
+
super("[ParserError] " + msg, filename, linenumber);
|
|
49
|
+
this.name = "ParserError";
|
|
50
|
+
this.code = "ParserError";
|
|
51
|
+
if (Error.captureStackTrace) Error.captureStackTrace(this, _ParserError);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
var State = class {
|
|
55
|
+
constructor(parser) {
|
|
56
|
+
this.parser = parser;
|
|
57
|
+
this.buf = "";
|
|
58
|
+
this.returned = null;
|
|
59
|
+
this.result = null;
|
|
60
|
+
this.resultTable = null;
|
|
61
|
+
this.resultArr = null;
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
var Parser = class {
|
|
65
|
+
constructor() {
|
|
66
|
+
this.pos = 0;
|
|
67
|
+
this.col = 0;
|
|
68
|
+
this.line = 0;
|
|
69
|
+
this.obj = {};
|
|
70
|
+
this.ctx = this.obj;
|
|
71
|
+
this.stack = [];
|
|
72
|
+
this._buf = "";
|
|
73
|
+
this.char = null;
|
|
74
|
+
this.ii = 0;
|
|
75
|
+
this.state = new State(this.parseStart);
|
|
76
|
+
}
|
|
77
|
+
parse(str) {
|
|
78
|
+
if (str.length === 0 || str.length == null) return;
|
|
79
|
+
this._buf = String(str);
|
|
80
|
+
this.ii = -1;
|
|
81
|
+
this.char = -1;
|
|
82
|
+
let getNext;
|
|
83
|
+
while (getNext === false || this.nextChar()) {
|
|
84
|
+
getNext = this.runOne();
|
|
85
|
+
}
|
|
86
|
+
this._buf = null;
|
|
87
|
+
}
|
|
88
|
+
nextChar() {
|
|
89
|
+
if (this.char === 10) {
|
|
90
|
+
++this.line;
|
|
91
|
+
this.col = -1;
|
|
92
|
+
}
|
|
93
|
+
++this.ii;
|
|
94
|
+
this.char = this._buf.codePointAt(this.ii);
|
|
95
|
+
++this.pos;
|
|
96
|
+
++this.col;
|
|
97
|
+
return this.haveBuffer();
|
|
98
|
+
}
|
|
99
|
+
haveBuffer() {
|
|
100
|
+
return this.ii < this._buf.length;
|
|
101
|
+
}
|
|
102
|
+
runOne() {
|
|
103
|
+
return this.state.parser.call(this, this.state.returned);
|
|
104
|
+
}
|
|
105
|
+
finish() {
|
|
106
|
+
this.char = ParserEND;
|
|
107
|
+
let last;
|
|
108
|
+
do {
|
|
109
|
+
last = this.state.parser;
|
|
110
|
+
this.runOne();
|
|
111
|
+
} while (this.state.parser !== last);
|
|
112
|
+
this.ctx = null;
|
|
113
|
+
this.state = null;
|
|
114
|
+
this._buf = null;
|
|
115
|
+
return this.obj;
|
|
116
|
+
}
|
|
117
|
+
next(fn) {
|
|
118
|
+
if (typeof fn !== "function") throw new ParserError("Tried to set state to non-existent state: " + JSON.stringify(fn));
|
|
119
|
+
this.state.parser = fn;
|
|
120
|
+
}
|
|
121
|
+
goto(fn) {
|
|
122
|
+
this.next(fn);
|
|
123
|
+
return this.runOne();
|
|
124
|
+
}
|
|
125
|
+
call(fn, returnWith) {
|
|
126
|
+
if (returnWith) this.next(returnWith);
|
|
127
|
+
this.stack.push(this.state);
|
|
128
|
+
this.state = new State(fn);
|
|
129
|
+
}
|
|
130
|
+
callNow(fn, returnWith) {
|
|
131
|
+
this.call(fn, returnWith);
|
|
132
|
+
return this.runOne();
|
|
133
|
+
}
|
|
134
|
+
return(value) {
|
|
135
|
+
if (this.stack.length === 0) throw this.error(new ParserError("Stack underflow"));
|
|
136
|
+
if (value === void 0) value = this.state.buf;
|
|
137
|
+
this.state = this.stack.pop();
|
|
138
|
+
this.state.returned = value;
|
|
139
|
+
}
|
|
140
|
+
returnNow(value) {
|
|
141
|
+
this.return(value);
|
|
142
|
+
return this.runOne();
|
|
143
|
+
}
|
|
144
|
+
consume() {
|
|
145
|
+
if (this.char === ParserEND) throw this.error(new ParserError("Unexpected end-of-buffer"));
|
|
146
|
+
this.state.buf += this._buf[this.ii];
|
|
147
|
+
}
|
|
148
|
+
error(err) {
|
|
149
|
+
err.line = this.line;
|
|
150
|
+
err.col = this.col;
|
|
151
|
+
err.pos = this.pos;
|
|
152
|
+
return err;
|
|
153
|
+
}
|
|
154
|
+
/* istanbul ignore next */
|
|
155
|
+
parseStart() {
|
|
156
|
+
throw new ParserError("Must declare a parseStart method");
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
Parser.END = ParserEND;
|
|
160
|
+
Parser.Error = ParserError;
|
|
161
|
+
module2.exports = Parser;
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// node_modules/.pnpm/@iarna+toml@2.2.5/node_modules/@iarna/toml/lib/create-datetime.js
|
|
166
|
+
var require_create_datetime = __commonJS({
|
|
167
|
+
"node_modules/.pnpm/@iarna+toml@2.2.5/node_modules/@iarna/toml/lib/create-datetime.js"(exports2, module2) {
|
|
168
|
+
"use strict";
|
|
169
|
+
module2.exports = (value) => {
|
|
170
|
+
const date = new Date(value);
|
|
171
|
+
if (isNaN(date)) {
|
|
172
|
+
throw new TypeError("Invalid Datetime");
|
|
173
|
+
} else {
|
|
174
|
+
return date;
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// node_modules/.pnpm/@iarna+toml@2.2.5/node_modules/@iarna/toml/lib/format-num.js
|
|
181
|
+
var require_format_num = __commonJS({
|
|
182
|
+
"node_modules/.pnpm/@iarna+toml@2.2.5/node_modules/@iarna/toml/lib/format-num.js"(exports2, module2) {
|
|
183
|
+
"use strict";
|
|
184
|
+
module2.exports = (d, num) => {
|
|
185
|
+
num = String(num);
|
|
186
|
+
while (num.length < d) num = "0" + num;
|
|
187
|
+
return num;
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// node_modules/.pnpm/@iarna+toml@2.2.5/node_modules/@iarna/toml/lib/create-datetime-float.js
|
|
193
|
+
var require_create_datetime_float = __commonJS({
|
|
194
|
+
"node_modules/.pnpm/@iarna+toml@2.2.5/node_modules/@iarna/toml/lib/create-datetime-float.js"(exports2, module2) {
|
|
195
|
+
"use strict";
|
|
196
|
+
var f = require_format_num();
|
|
197
|
+
var FloatingDateTime = class extends Date {
|
|
198
|
+
constructor(value) {
|
|
199
|
+
super(value + "Z");
|
|
200
|
+
this.isFloating = true;
|
|
201
|
+
}
|
|
202
|
+
toISOString() {
|
|
203
|
+
const date = `${this.getUTCFullYear()}-${f(2, this.getUTCMonth() + 1)}-${f(2, this.getUTCDate())}`;
|
|
204
|
+
const time = `${f(2, this.getUTCHours())}:${f(2, this.getUTCMinutes())}:${f(2, this.getUTCSeconds())}.${f(3, this.getUTCMilliseconds())}`;
|
|
205
|
+
return `${date}T${time}`;
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
module2.exports = (value) => {
|
|
209
|
+
const date = new FloatingDateTime(value);
|
|
210
|
+
if (isNaN(date)) {
|
|
211
|
+
throw new TypeError("Invalid Datetime");
|
|
212
|
+
} else {
|
|
213
|
+
return date;
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
// node_modules/.pnpm/@iarna+toml@2.2.5/node_modules/@iarna/toml/lib/create-date.js
|
|
220
|
+
var require_create_date = __commonJS({
|
|
221
|
+
"node_modules/.pnpm/@iarna+toml@2.2.5/node_modules/@iarna/toml/lib/create-date.js"(exports2, module2) {
|
|
222
|
+
"use strict";
|
|
223
|
+
var f = require_format_num();
|
|
224
|
+
var DateTime = global.Date;
|
|
225
|
+
var Date2 = class extends DateTime {
|
|
226
|
+
constructor(value) {
|
|
227
|
+
super(value);
|
|
228
|
+
this.isDate = true;
|
|
229
|
+
}
|
|
230
|
+
toISOString() {
|
|
231
|
+
return `${this.getUTCFullYear()}-${f(2, this.getUTCMonth() + 1)}-${f(2, this.getUTCDate())}`;
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
module2.exports = (value) => {
|
|
235
|
+
const date = new Date2(value);
|
|
236
|
+
if (isNaN(date)) {
|
|
237
|
+
throw new TypeError("Invalid Datetime");
|
|
238
|
+
} else {
|
|
239
|
+
return date;
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
// node_modules/.pnpm/@iarna+toml@2.2.5/node_modules/@iarna/toml/lib/create-time.js
|
|
246
|
+
var require_create_time = __commonJS({
|
|
247
|
+
"node_modules/.pnpm/@iarna+toml@2.2.5/node_modules/@iarna/toml/lib/create-time.js"(exports2, module2) {
|
|
248
|
+
"use strict";
|
|
249
|
+
var f = require_format_num();
|
|
250
|
+
var Time = class extends Date {
|
|
251
|
+
constructor(value) {
|
|
252
|
+
super(`0000-01-01T${value}Z`);
|
|
253
|
+
this.isTime = true;
|
|
254
|
+
}
|
|
255
|
+
toISOString() {
|
|
256
|
+
return `${f(2, this.getUTCHours())}:${f(2, this.getUTCMinutes())}:${f(2, this.getUTCSeconds())}.${f(3, this.getUTCMilliseconds())}`;
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
module2.exports = (value) => {
|
|
260
|
+
const date = new Time(value);
|
|
261
|
+
if (isNaN(date)) {
|
|
262
|
+
throw new TypeError("Invalid Datetime");
|
|
263
|
+
} else {
|
|
264
|
+
return date;
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
// node_modules/.pnpm/@iarna+toml@2.2.5/node_modules/@iarna/toml/lib/toml-parser.js
|
|
271
|
+
var require_toml_parser = __commonJS({
|
|
272
|
+
"node_modules/.pnpm/@iarna+toml@2.2.5/node_modules/@iarna/toml/lib/toml-parser.js"(exports, module) {
|
|
273
|
+
"use strict";
|
|
274
|
+
module.exports = makeParserClass(require_parser());
|
|
275
|
+
module.exports.makeParserClass = makeParserClass;
|
|
276
|
+
var TomlError = class _TomlError extends Error {
|
|
277
|
+
constructor(msg) {
|
|
278
|
+
super(msg);
|
|
279
|
+
this.name = "TomlError";
|
|
280
|
+
if (Error.captureStackTrace) Error.captureStackTrace(this, _TomlError);
|
|
281
|
+
this.fromTOML = true;
|
|
282
|
+
this.wrapped = null;
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
TomlError.wrap = (err) => {
|
|
286
|
+
const terr = new TomlError(err.message);
|
|
287
|
+
terr.code = err.code;
|
|
288
|
+
terr.wrapped = err;
|
|
289
|
+
return terr;
|
|
290
|
+
};
|
|
291
|
+
module.exports.TomlError = TomlError;
|
|
292
|
+
var createDateTime = require_create_datetime();
|
|
293
|
+
var createDateTimeFloat = require_create_datetime_float();
|
|
294
|
+
var createDate = require_create_date();
|
|
295
|
+
var createTime = require_create_time();
|
|
296
|
+
var CTRL_I = 9;
|
|
297
|
+
var CTRL_J = 10;
|
|
298
|
+
var CTRL_M = 13;
|
|
299
|
+
var CTRL_CHAR_BOUNDARY = 31;
|
|
300
|
+
var CHAR_SP = 32;
|
|
301
|
+
var CHAR_QUOT = 34;
|
|
302
|
+
var CHAR_NUM = 35;
|
|
303
|
+
var CHAR_APOS = 39;
|
|
304
|
+
var CHAR_PLUS = 43;
|
|
305
|
+
var CHAR_COMMA = 44;
|
|
306
|
+
var CHAR_HYPHEN = 45;
|
|
307
|
+
var CHAR_PERIOD = 46;
|
|
308
|
+
var CHAR_0 = 48;
|
|
309
|
+
var CHAR_1 = 49;
|
|
310
|
+
var CHAR_7 = 55;
|
|
311
|
+
var CHAR_9 = 57;
|
|
312
|
+
var CHAR_COLON = 58;
|
|
313
|
+
var CHAR_EQUALS = 61;
|
|
314
|
+
var CHAR_A = 65;
|
|
315
|
+
var CHAR_E = 69;
|
|
316
|
+
var CHAR_F = 70;
|
|
317
|
+
var CHAR_T = 84;
|
|
318
|
+
var CHAR_U = 85;
|
|
319
|
+
var CHAR_Z = 90;
|
|
320
|
+
var CHAR_LOWBAR = 95;
|
|
321
|
+
var CHAR_a = 97;
|
|
322
|
+
var CHAR_b = 98;
|
|
323
|
+
var CHAR_e = 101;
|
|
324
|
+
var CHAR_f = 102;
|
|
325
|
+
var CHAR_i = 105;
|
|
326
|
+
var CHAR_l = 108;
|
|
327
|
+
var CHAR_n = 110;
|
|
328
|
+
var CHAR_o = 111;
|
|
329
|
+
var CHAR_r = 114;
|
|
330
|
+
var CHAR_s = 115;
|
|
331
|
+
var CHAR_t = 116;
|
|
332
|
+
var CHAR_u = 117;
|
|
333
|
+
var CHAR_x = 120;
|
|
334
|
+
var CHAR_z = 122;
|
|
335
|
+
var CHAR_LCUB = 123;
|
|
336
|
+
var CHAR_RCUB = 125;
|
|
337
|
+
var CHAR_LSQB = 91;
|
|
338
|
+
var CHAR_BSOL = 92;
|
|
339
|
+
var CHAR_RSQB = 93;
|
|
340
|
+
var CHAR_DEL = 127;
|
|
341
|
+
var SURROGATE_FIRST = 55296;
|
|
342
|
+
var SURROGATE_LAST = 57343;
|
|
343
|
+
var escapes = {
|
|
344
|
+
[CHAR_b]: "\b",
|
|
345
|
+
[CHAR_t]: " ",
|
|
346
|
+
[CHAR_n]: "\n",
|
|
347
|
+
[CHAR_f]: "\f",
|
|
348
|
+
[CHAR_r]: "\r",
|
|
349
|
+
[CHAR_QUOT]: '"',
|
|
350
|
+
[CHAR_BSOL]: "\\"
|
|
351
|
+
};
|
|
352
|
+
function isDigit(cp) {
|
|
353
|
+
return cp >= CHAR_0 && cp <= CHAR_9;
|
|
354
|
+
}
|
|
355
|
+
function isHexit(cp) {
|
|
356
|
+
return cp >= CHAR_A && cp <= CHAR_F || cp >= CHAR_a && cp <= CHAR_f || cp >= CHAR_0 && cp <= CHAR_9;
|
|
357
|
+
}
|
|
358
|
+
function isBit(cp) {
|
|
359
|
+
return cp === CHAR_1 || cp === CHAR_0;
|
|
360
|
+
}
|
|
361
|
+
function isOctit(cp) {
|
|
362
|
+
return cp >= CHAR_0 && cp <= CHAR_7;
|
|
363
|
+
}
|
|
364
|
+
function isAlphaNumQuoteHyphen(cp) {
|
|
365
|
+
return cp >= CHAR_A && cp <= CHAR_Z || cp >= CHAR_a && cp <= CHAR_z || cp >= CHAR_0 && cp <= CHAR_9 || cp === CHAR_APOS || cp === CHAR_QUOT || cp === CHAR_LOWBAR || cp === CHAR_HYPHEN;
|
|
366
|
+
}
|
|
367
|
+
function isAlphaNumHyphen(cp) {
|
|
368
|
+
return cp >= CHAR_A && cp <= CHAR_Z || cp >= CHAR_a && cp <= CHAR_z || cp >= CHAR_0 && cp <= CHAR_9 || cp === CHAR_LOWBAR || cp === CHAR_HYPHEN;
|
|
369
|
+
}
|
|
370
|
+
var _type = /* @__PURE__ */ Symbol("type");
|
|
371
|
+
var _declared = /* @__PURE__ */ Symbol("declared");
|
|
372
|
+
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
373
|
+
var defineProperty = Object.defineProperty;
|
|
374
|
+
var descriptor = { configurable: true, enumerable: true, writable: true, value: void 0 };
|
|
375
|
+
function hasKey(obj, key) {
|
|
376
|
+
if (hasOwnProperty.call(obj, key)) return true;
|
|
377
|
+
if (key === "__proto__") defineProperty(obj, "__proto__", descriptor);
|
|
378
|
+
return false;
|
|
379
|
+
}
|
|
380
|
+
var INLINE_TABLE = /* @__PURE__ */ Symbol("inline-table");
|
|
381
|
+
function InlineTable() {
|
|
382
|
+
return Object.defineProperties({}, {
|
|
383
|
+
[_type]: { value: INLINE_TABLE }
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
function isInlineTable(obj) {
|
|
387
|
+
if (obj === null || typeof obj !== "object") return false;
|
|
388
|
+
return obj[_type] === INLINE_TABLE;
|
|
389
|
+
}
|
|
390
|
+
var TABLE = /* @__PURE__ */ Symbol("table");
|
|
391
|
+
function Table() {
|
|
392
|
+
return Object.defineProperties({}, {
|
|
393
|
+
[_type]: { value: TABLE },
|
|
394
|
+
[_declared]: { value: false, writable: true }
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
function isTable(obj) {
|
|
398
|
+
if (obj === null || typeof obj !== "object") return false;
|
|
399
|
+
return obj[_type] === TABLE;
|
|
400
|
+
}
|
|
401
|
+
var _contentType = /* @__PURE__ */ Symbol("content-type");
|
|
402
|
+
var INLINE_LIST = /* @__PURE__ */ Symbol("inline-list");
|
|
403
|
+
function InlineList(type) {
|
|
404
|
+
return Object.defineProperties([], {
|
|
405
|
+
[_type]: { value: INLINE_LIST },
|
|
406
|
+
[_contentType]: { value: type }
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
function isInlineList(obj) {
|
|
410
|
+
if (obj === null || typeof obj !== "object") return false;
|
|
411
|
+
return obj[_type] === INLINE_LIST;
|
|
412
|
+
}
|
|
413
|
+
var LIST = /* @__PURE__ */ Symbol("list");
|
|
414
|
+
function List() {
|
|
415
|
+
return Object.defineProperties([], {
|
|
416
|
+
[_type]: { value: LIST }
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
function isList(obj) {
|
|
420
|
+
if (obj === null || typeof obj !== "object") return false;
|
|
421
|
+
return obj[_type] === LIST;
|
|
422
|
+
}
|
|
423
|
+
var _custom;
|
|
424
|
+
try {
|
|
425
|
+
const utilInspect = eval("require('util').inspect");
|
|
426
|
+
_custom = utilInspect.custom;
|
|
427
|
+
} catch (_) {
|
|
428
|
+
}
|
|
429
|
+
var _inspect = _custom || "inspect";
|
|
430
|
+
var BoxedBigInt = class {
|
|
431
|
+
constructor(value) {
|
|
432
|
+
try {
|
|
433
|
+
this.value = global.BigInt.asIntN(64, value);
|
|
434
|
+
} catch (_) {
|
|
435
|
+
this.value = null;
|
|
436
|
+
}
|
|
437
|
+
Object.defineProperty(this, _type, { value: INTEGER });
|
|
438
|
+
}
|
|
439
|
+
isNaN() {
|
|
440
|
+
return this.value === null;
|
|
441
|
+
}
|
|
442
|
+
/* istanbul ignore next */
|
|
443
|
+
toString() {
|
|
444
|
+
return String(this.value);
|
|
445
|
+
}
|
|
446
|
+
/* istanbul ignore next */
|
|
447
|
+
[_inspect]() {
|
|
448
|
+
return `[BigInt: ${this.toString()}]}`;
|
|
449
|
+
}
|
|
450
|
+
valueOf() {
|
|
451
|
+
return this.value;
|
|
452
|
+
}
|
|
453
|
+
};
|
|
454
|
+
var INTEGER = /* @__PURE__ */ Symbol("integer");
|
|
455
|
+
function Integer(value) {
|
|
456
|
+
let num = Number(value);
|
|
457
|
+
if (Object.is(num, -0)) num = 0;
|
|
458
|
+
if (global.BigInt && !Number.isSafeInteger(num)) {
|
|
459
|
+
return new BoxedBigInt(value);
|
|
460
|
+
} else {
|
|
461
|
+
return Object.defineProperties(new Number(num), {
|
|
462
|
+
isNaN: { value: function() {
|
|
463
|
+
return isNaN(this);
|
|
464
|
+
} },
|
|
465
|
+
[_type]: { value: INTEGER },
|
|
466
|
+
[_inspect]: { value: () => `[Integer: ${value}]` }
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
function isInteger(obj) {
|
|
471
|
+
if (obj === null || typeof obj !== "object") return false;
|
|
472
|
+
return obj[_type] === INTEGER;
|
|
473
|
+
}
|
|
474
|
+
var FLOAT = /* @__PURE__ */ Symbol("float");
|
|
475
|
+
function Float(value) {
|
|
476
|
+
return Object.defineProperties(new Number(value), {
|
|
477
|
+
[_type]: { value: FLOAT },
|
|
478
|
+
[_inspect]: { value: () => `[Float: ${value}]` }
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
function isFloat(obj) {
|
|
482
|
+
if (obj === null || typeof obj !== "object") return false;
|
|
483
|
+
return obj[_type] === FLOAT;
|
|
484
|
+
}
|
|
485
|
+
function tomlType(value) {
|
|
486
|
+
const type = typeof value;
|
|
487
|
+
if (type === "object") {
|
|
488
|
+
if (value === null) return "null";
|
|
489
|
+
if (value instanceof Date) return "datetime";
|
|
490
|
+
if (_type in value) {
|
|
491
|
+
switch (value[_type]) {
|
|
492
|
+
case INLINE_TABLE:
|
|
493
|
+
return "inline-table";
|
|
494
|
+
case INLINE_LIST:
|
|
495
|
+
return "inline-list";
|
|
496
|
+
/* istanbul ignore next */
|
|
497
|
+
case TABLE:
|
|
498
|
+
return "table";
|
|
499
|
+
/* istanbul ignore next */
|
|
500
|
+
case LIST:
|
|
501
|
+
return "list";
|
|
502
|
+
case FLOAT:
|
|
503
|
+
return "float";
|
|
504
|
+
case INTEGER:
|
|
505
|
+
return "integer";
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
return type;
|
|
510
|
+
}
|
|
511
|
+
function makeParserClass(Parser) {
|
|
512
|
+
class TOMLParser extends Parser {
|
|
513
|
+
constructor() {
|
|
514
|
+
super();
|
|
515
|
+
this.ctx = this.obj = Table();
|
|
516
|
+
}
|
|
517
|
+
/* MATCH HELPER */
|
|
518
|
+
atEndOfWord() {
|
|
519
|
+
return this.char === CHAR_NUM || this.char === CTRL_I || this.char === CHAR_SP || this.atEndOfLine();
|
|
520
|
+
}
|
|
521
|
+
atEndOfLine() {
|
|
522
|
+
return this.char === Parser.END || this.char === CTRL_J || this.char === CTRL_M;
|
|
523
|
+
}
|
|
524
|
+
parseStart() {
|
|
525
|
+
if (this.char === Parser.END) {
|
|
526
|
+
return null;
|
|
527
|
+
} else if (this.char === CHAR_LSQB) {
|
|
528
|
+
return this.call(this.parseTableOrList);
|
|
529
|
+
} else if (this.char === CHAR_NUM) {
|
|
530
|
+
return this.call(this.parseComment);
|
|
531
|
+
} else if (this.char === CTRL_J || this.char === CHAR_SP || this.char === CTRL_I || this.char === CTRL_M) {
|
|
532
|
+
return null;
|
|
533
|
+
} else if (isAlphaNumQuoteHyphen(this.char)) {
|
|
534
|
+
return this.callNow(this.parseAssignStatement);
|
|
535
|
+
} else {
|
|
536
|
+
throw this.error(new TomlError(`Unknown character "${this.char}"`));
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
// HELPER, this strips any whitespace and comments to the end of the line
|
|
540
|
+
// then RETURNS. Last state in a production.
|
|
541
|
+
parseWhitespaceToEOL() {
|
|
542
|
+
if (this.char === CHAR_SP || this.char === CTRL_I || this.char === CTRL_M) {
|
|
543
|
+
return null;
|
|
544
|
+
} else if (this.char === CHAR_NUM) {
|
|
545
|
+
return this.goto(this.parseComment);
|
|
546
|
+
} else if (this.char === Parser.END || this.char === CTRL_J) {
|
|
547
|
+
return this.return();
|
|
548
|
+
} else {
|
|
549
|
+
throw this.error(new TomlError("Unexpected character, expected only whitespace or comments till end of line"));
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
/* ASSIGNMENT: key = value */
|
|
553
|
+
parseAssignStatement() {
|
|
554
|
+
return this.callNow(this.parseAssign, this.recordAssignStatement);
|
|
555
|
+
}
|
|
556
|
+
recordAssignStatement(kv) {
|
|
557
|
+
let target = this.ctx;
|
|
558
|
+
let finalKey = kv.key.pop();
|
|
559
|
+
for (let kw of kv.key) {
|
|
560
|
+
if (hasKey(target, kw) && (!isTable(target[kw]) || target[kw][_declared])) {
|
|
561
|
+
throw this.error(new TomlError("Can't redefine existing key"));
|
|
562
|
+
}
|
|
563
|
+
target = target[kw] = target[kw] || Table();
|
|
564
|
+
}
|
|
565
|
+
if (hasKey(target, finalKey)) {
|
|
566
|
+
throw this.error(new TomlError("Can't redefine existing key"));
|
|
567
|
+
}
|
|
568
|
+
if (isInteger(kv.value) || isFloat(kv.value)) {
|
|
569
|
+
target[finalKey] = kv.value.valueOf();
|
|
570
|
+
} else {
|
|
571
|
+
target[finalKey] = kv.value;
|
|
572
|
+
}
|
|
573
|
+
return this.goto(this.parseWhitespaceToEOL);
|
|
574
|
+
}
|
|
575
|
+
/* ASSSIGNMENT expression, key = value possibly inside an inline table */
|
|
576
|
+
parseAssign() {
|
|
577
|
+
return this.callNow(this.parseKeyword, this.recordAssignKeyword);
|
|
578
|
+
}
|
|
579
|
+
recordAssignKeyword(key) {
|
|
580
|
+
if (this.state.resultTable) {
|
|
581
|
+
this.state.resultTable.push(key);
|
|
582
|
+
} else {
|
|
583
|
+
this.state.resultTable = [key];
|
|
584
|
+
}
|
|
585
|
+
return this.goto(this.parseAssignKeywordPreDot);
|
|
586
|
+
}
|
|
587
|
+
parseAssignKeywordPreDot() {
|
|
588
|
+
if (this.char === CHAR_PERIOD) {
|
|
589
|
+
return this.next(this.parseAssignKeywordPostDot);
|
|
590
|
+
} else if (this.char !== CHAR_SP && this.char !== CTRL_I) {
|
|
591
|
+
return this.goto(this.parseAssignEqual);
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
parseAssignKeywordPostDot() {
|
|
595
|
+
if (this.char !== CHAR_SP && this.char !== CTRL_I) {
|
|
596
|
+
return this.callNow(this.parseKeyword, this.recordAssignKeyword);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
parseAssignEqual() {
|
|
600
|
+
if (this.char === CHAR_EQUALS) {
|
|
601
|
+
return this.next(this.parseAssignPreValue);
|
|
602
|
+
} else {
|
|
603
|
+
throw this.error(new TomlError('Invalid character, expected "="'));
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
parseAssignPreValue() {
|
|
607
|
+
if (this.char === CHAR_SP || this.char === CTRL_I) {
|
|
608
|
+
return null;
|
|
609
|
+
} else {
|
|
610
|
+
return this.callNow(this.parseValue, this.recordAssignValue);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
recordAssignValue(value) {
|
|
614
|
+
return this.returnNow({ key: this.state.resultTable, value });
|
|
615
|
+
}
|
|
616
|
+
/* COMMENTS: #...eol */
|
|
617
|
+
parseComment() {
|
|
618
|
+
do {
|
|
619
|
+
if (this.char === Parser.END || this.char === CTRL_J) {
|
|
620
|
+
return this.return();
|
|
621
|
+
}
|
|
622
|
+
} while (this.nextChar());
|
|
623
|
+
}
|
|
624
|
+
/* TABLES AND LISTS, [foo] and [[foo]] */
|
|
625
|
+
parseTableOrList() {
|
|
626
|
+
if (this.char === CHAR_LSQB) {
|
|
627
|
+
this.next(this.parseList);
|
|
628
|
+
} else {
|
|
629
|
+
return this.goto(this.parseTable);
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
/* TABLE [foo.bar.baz] */
|
|
633
|
+
parseTable() {
|
|
634
|
+
this.ctx = this.obj;
|
|
635
|
+
return this.goto(this.parseTableNext);
|
|
636
|
+
}
|
|
637
|
+
parseTableNext() {
|
|
638
|
+
if (this.char === CHAR_SP || this.char === CTRL_I) {
|
|
639
|
+
return null;
|
|
640
|
+
} else {
|
|
641
|
+
return this.callNow(this.parseKeyword, this.parseTableMore);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
parseTableMore(keyword) {
|
|
645
|
+
if (this.char === CHAR_SP || this.char === CTRL_I) {
|
|
646
|
+
return null;
|
|
647
|
+
} else if (this.char === CHAR_RSQB) {
|
|
648
|
+
if (hasKey(this.ctx, keyword) && (!isTable(this.ctx[keyword]) || this.ctx[keyword][_declared])) {
|
|
649
|
+
throw this.error(new TomlError("Can't redefine existing key"));
|
|
650
|
+
} else {
|
|
651
|
+
this.ctx = this.ctx[keyword] = this.ctx[keyword] || Table();
|
|
652
|
+
this.ctx[_declared] = true;
|
|
653
|
+
}
|
|
654
|
+
return this.next(this.parseWhitespaceToEOL);
|
|
655
|
+
} else if (this.char === CHAR_PERIOD) {
|
|
656
|
+
if (!hasKey(this.ctx, keyword)) {
|
|
657
|
+
this.ctx = this.ctx[keyword] = Table();
|
|
658
|
+
} else if (isTable(this.ctx[keyword])) {
|
|
659
|
+
this.ctx = this.ctx[keyword];
|
|
660
|
+
} else if (isList(this.ctx[keyword])) {
|
|
661
|
+
this.ctx = this.ctx[keyword][this.ctx[keyword].length - 1];
|
|
662
|
+
} else {
|
|
663
|
+
throw this.error(new TomlError("Can't redefine existing key"));
|
|
664
|
+
}
|
|
665
|
+
return this.next(this.parseTableNext);
|
|
666
|
+
} else {
|
|
667
|
+
throw this.error(new TomlError("Unexpected character, expected whitespace, . or ]"));
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
/* LIST [[a.b.c]] */
|
|
671
|
+
parseList() {
|
|
672
|
+
this.ctx = this.obj;
|
|
673
|
+
return this.goto(this.parseListNext);
|
|
674
|
+
}
|
|
675
|
+
parseListNext() {
|
|
676
|
+
if (this.char === CHAR_SP || this.char === CTRL_I) {
|
|
677
|
+
return null;
|
|
678
|
+
} else {
|
|
679
|
+
return this.callNow(this.parseKeyword, this.parseListMore);
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
parseListMore(keyword) {
|
|
683
|
+
if (this.char === CHAR_SP || this.char === CTRL_I) {
|
|
684
|
+
return null;
|
|
685
|
+
} else if (this.char === CHAR_RSQB) {
|
|
686
|
+
if (!hasKey(this.ctx, keyword)) {
|
|
687
|
+
this.ctx[keyword] = List();
|
|
688
|
+
}
|
|
689
|
+
if (isInlineList(this.ctx[keyword])) {
|
|
690
|
+
throw this.error(new TomlError("Can't extend an inline array"));
|
|
691
|
+
} else if (isList(this.ctx[keyword])) {
|
|
692
|
+
const next = Table();
|
|
693
|
+
this.ctx[keyword].push(next);
|
|
694
|
+
this.ctx = next;
|
|
695
|
+
} else {
|
|
696
|
+
throw this.error(new TomlError("Can't redefine an existing key"));
|
|
697
|
+
}
|
|
698
|
+
return this.next(this.parseListEnd);
|
|
699
|
+
} else if (this.char === CHAR_PERIOD) {
|
|
700
|
+
if (!hasKey(this.ctx, keyword)) {
|
|
701
|
+
this.ctx = this.ctx[keyword] = Table();
|
|
702
|
+
} else if (isInlineList(this.ctx[keyword])) {
|
|
703
|
+
throw this.error(new TomlError("Can't extend an inline array"));
|
|
704
|
+
} else if (isInlineTable(this.ctx[keyword])) {
|
|
705
|
+
throw this.error(new TomlError("Can't extend an inline table"));
|
|
706
|
+
} else if (isList(this.ctx[keyword])) {
|
|
707
|
+
this.ctx = this.ctx[keyword][this.ctx[keyword].length - 1];
|
|
708
|
+
} else if (isTable(this.ctx[keyword])) {
|
|
709
|
+
this.ctx = this.ctx[keyword];
|
|
710
|
+
} else {
|
|
711
|
+
throw this.error(new TomlError("Can't redefine an existing key"));
|
|
712
|
+
}
|
|
713
|
+
return this.next(this.parseListNext);
|
|
714
|
+
} else {
|
|
715
|
+
throw this.error(new TomlError("Unexpected character, expected whitespace, . or ]"));
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
parseListEnd(keyword) {
|
|
719
|
+
if (this.char === CHAR_RSQB) {
|
|
720
|
+
return this.next(this.parseWhitespaceToEOL);
|
|
721
|
+
} else {
|
|
722
|
+
throw this.error(new TomlError("Unexpected character, expected whitespace, . or ]"));
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
/* VALUE string, number, boolean, inline list, inline object */
|
|
726
|
+
parseValue() {
|
|
727
|
+
if (this.char === Parser.END) {
|
|
728
|
+
throw this.error(new TomlError("Key without value"));
|
|
729
|
+
} else if (this.char === CHAR_QUOT) {
|
|
730
|
+
return this.next(this.parseDoubleString);
|
|
731
|
+
}
|
|
732
|
+
if (this.char === CHAR_APOS) {
|
|
733
|
+
return this.next(this.parseSingleString);
|
|
734
|
+
} else if (this.char === CHAR_HYPHEN || this.char === CHAR_PLUS) {
|
|
735
|
+
return this.goto(this.parseNumberSign);
|
|
736
|
+
} else if (this.char === CHAR_i) {
|
|
737
|
+
return this.next(this.parseInf);
|
|
738
|
+
} else if (this.char === CHAR_n) {
|
|
739
|
+
return this.next(this.parseNan);
|
|
740
|
+
} else if (isDigit(this.char)) {
|
|
741
|
+
return this.goto(this.parseNumberOrDateTime);
|
|
742
|
+
} else if (this.char === CHAR_t || this.char === CHAR_f) {
|
|
743
|
+
return this.goto(this.parseBoolean);
|
|
744
|
+
} else if (this.char === CHAR_LSQB) {
|
|
745
|
+
return this.call(this.parseInlineList, this.recordValue);
|
|
746
|
+
} else if (this.char === CHAR_LCUB) {
|
|
747
|
+
return this.call(this.parseInlineTable, this.recordValue);
|
|
748
|
+
} else {
|
|
749
|
+
throw this.error(new TomlError("Unexpected character, expecting string, number, datetime, boolean, inline array or inline table"));
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
recordValue(value) {
|
|
753
|
+
return this.returnNow(value);
|
|
754
|
+
}
|
|
755
|
+
parseInf() {
|
|
756
|
+
if (this.char === CHAR_n) {
|
|
757
|
+
return this.next(this.parseInf2);
|
|
758
|
+
} else {
|
|
759
|
+
throw this.error(new TomlError('Unexpected character, expected "inf", "+inf" or "-inf"'));
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
parseInf2() {
|
|
763
|
+
if (this.char === CHAR_f) {
|
|
764
|
+
if (this.state.buf === "-") {
|
|
765
|
+
return this.return(-Infinity);
|
|
766
|
+
} else {
|
|
767
|
+
return this.return(Infinity);
|
|
768
|
+
}
|
|
769
|
+
} else {
|
|
770
|
+
throw this.error(new TomlError('Unexpected character, expected "inf", "+inf" or "-inf"'));
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
parseNan() {
|
|
774
|
+
if (this.char === CHAR_a) {
|
|
775
|
+
return this.next(this.parseNan2);
|
|
776
|
+
} else {
|
|
777
|
+
throw this.error(new TomlError('Unexpected character, expected "nan"'));
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
parseNan2() {
|
|
781
|
+
if (this.char === CHAR_n) {
|
|
782
|
+
return this.return(NaN);
|
|
783
|
+
} else {
|
|
784
|
+
throw this.error(new TomlError('Unexpected character, expected "nan"'));
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
/* KEYS, barewords or basic, literal, or dotted */
|
|
788
|
+
parseKeyword() {
|
|
789
|
+
if (this.char === CHAR_QUOT) {
|
|
790
|
+
return this.next(this.parseBasicString);
|
|
791
|
+
} else if (this.char === CHAR_APOS) {
|
|
792
|
+
return this.next(this.parseLiteralString);
|
|
793
|
+
} else {
|
|
794
|
+
return this.goto(this.parseBareKey);
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
/* KEYS: barewords */
|
|
798
|
+
parseBareKey() {
|
|
799
|
+
do {
|
|
800
|
+
if (this.char === Parser.END) {
|
|
801
|
+
throw this.error(new TomlError("Key ended without value"));
|
|
802
|
+
} else if (isAlphaNumHyphen(this.char)) {
|
|
803
|
+
this.consume();
|
|
804
|
+
} else if (this.state.buf.length === 0) {
|
|
805
|
+
throw this.error(new TomlError("Empty bare keys are not allowed"));
|
|
806
|
+
} else {
|
|
807
|
+
return this.returnNow();
|
|
808
|
+
}
|
|
809
|
+
} while (this.nextChar());
|
|
810
|
+
}
|
|
811
|
+
/* STRINGS, single quoted (literal) */
|
|
812
|
+
parseSingleString() {
|
|
813
|
+
if (this.char === CHAR_APOS) {
|
|
814
|
+
return this.next(this.parseLiteralMultiStringMaybe);
|
|
815
|
+
} else {
|
|
816
|
+
return this.goto(this.parseLiteralString);
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
parseLiteralString() {
|
|
820
|
+
do {
|
|
821
|
+
if (this.char === CHAR_APOS) {
|
|
822
|
+
return this.return();
|
|
823
|
+
} else if (this.atEndOfLine()) {
|
|
824
|
+
throw this.error(new TomlError("Unterminated string"));
|
|
825
|
+
} else if (this.char === CHAR_DEL || this.char <= CTRL_CHAR_BOUNDARY && this.char !== CTRL_I) {
|
|
826
|
+
throw this.errorControlCharInString();
|
|
827
|
+
} else {
|
|
828
|
+
this.consume();
|
|
829
|
+
}
|
|
830
|
+
} while (this.nextChar());
|
|
831
|
+
}
|
|
832
|
+
parseLiteralMultiStringMaybe() {
|
|
833
|
+
if (this.char === CHAR_APOS) {
|
|
834
|
+
return this.next(this.parseLiteralMultiString);
|
|
835
|
+
} else {
|
|
836
|
+
return this.returnNow();
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
parseLiteralMultiString() {
|
|
840
|
+
if (this.char === CTRL_M) {
|
|
841
|
+
return null;
|
|
842
|
+
} else if (this.char === CTRL_J) {
|
|
843
|
+
return this.next(this.parseLiteralMultiStringContent);
|
|
844
|
+
} else {
|
|
845
|
+
return this.goto(this.parseLiteralMultiStringContent);
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
parseLiteralMultiStringContent() {
|
|
849
|
+
do {
|
|
850
|
+
if (this.char === CHAR_APOS) {
|
|
851
|
+
return this.next(this.parseLiteralMultiEnd);
|
|
852
|
+
} else if (this.char === Parser.END) {
|
|
853
|
+
throw this.error(new TomlError("Unterminated multi-line string"));
|
|
854
|
+
} else if (this.char === CHAR_DEL || this.char <= CTRL_CHAR_BOUNDARY && this.char !== CTRL_I && this.char !== CTRL_J && this.char !== CTRL_M) {
|
|
855
|
+
throw this.errorControlCharInString();
|
|
856
|
+
} else {
|
|
857
|
+
this.consume();
|
|
858
|
+
}
|
|
859
|
+
} while (this.nextChar());
|
|
860
|
+
}
|
|
861
|
+
parseLiteralMultiEnd() {
|
|
862
|
+
if (this.char === CHAR_APOS) {
|
|
863
|
+
return this.next(this.parseLiteralMultiEnd2);
|
|
864
|
+
} else {
|
|
865
|
+
this.state.buf += "'";
|
|
866
|
+
return this.goto(this.parseLiteralMultiStringContent);
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
parseLiteralMultiEnd2() {
|
|
870
|
+
if (this.char === CHAR_APOS) {
|
|
871
|
+
return this.return();
|
|
872
|
+
} else {
|
|
873
|
+
this.state.buf += "''";
|
|
874
|
+
return this.goto(this.parseLiteralMultiStringContent);
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
/* STRINGS double quoted */
|
|
878
|
+
parseDoubleString() {
|
|
879
|
+
if (this.char === CHAR_QUOT) {
|
|
880
|
+
return this.next(this.parseMultiStringMaybe);
|
|
881
|
+
} else {
|
|
882
|
+
return this.goto(this.parseBasicString);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
parseBasicString() {
|
|
886
|
+
do {
|
|
887
|
+
if (this.char === CHAR_BSOL) {
|
|
888
|
+
return this.call(this.parseEscape, this.recordEscapeReplacement);
|
|
889
|
+
} else if (this.char === CHAR_QUOT) {
|
|
890
|
+
return this.return();
|
|
891
|
+
} else if (this.atEndOfLine()) {
|
|
892
|
+
throw this.error(new TomlError("Unterminated string"));
|
|
893
|
+
} else if (this.char === CHAR_DEL || this.char <= CTRL_CHAR_BOUNDARY && this.char !== CTRL_I) {
|
|
894
|
+
throw this.errorControlCharInString();
|
|
895
|
+
} else {
|
|
896
|
+
this.consume();
|
|
897
|
+
}
|
|
898
|
+
} while (this.nextChar());
|
|
899
|
+
}
|
|
900
|
+
recordEscapeReplacement(replacement) {
|
|
901
|
+
this.state.buf += replacement;
|
|
902
|
+
return this.goto(this.parseBasicString);
|
|
903
|
+
}
|
|
904
|
+
parseMultiStringMaybe() {
|
|
905
|
+
if (this.char === CHAR_QUOT) {
|
|
906
|
+
return this.next(this.parseMultiString);
|
|
907
|
+
} else {
|
|
908
|
+
return this.returnNow();
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
parseMultiString() {
|
|
912
|
+
if (this.char === CTRL_M) {
|
|
913
|
+
return null;
|
|
914
|
+
} else if (this.char === CTRL_J) {
|
|
915
|
+
return this.next(this.parseMultiStringContent);
|
|
916
|
+
} else {
|
|
917
|
+
return this.goto(this.parseMultiStringContent);
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
parseMultiStringContent() {
|
|
921
|
+
do {
|
|
922
|
+
if (this.char === CHAR_BSOL) {
|
|
923
|
+
return this.call(this.parseMultiEscape, this.recordMultiEscapeReplacement);
|
|
924
|
+
} else if (this.char === CHAR_QUOT) {
|
|
925
|
+
return this.next(this.parseMultiEnd);
|
|
926
|
+
} else if (this.char === Parser.END) {
|
|
927
|
+
throw this.error(new TomlError("Unterminated multi-line string"));
|
|
928
|
+
} else if (this.char === CHAR_DEL || this.char <= CTRL_CHAR_BOUNDARY && this.char !== CTRL_I && this.char !== CTRL_J && this.char !== CTRL_M) {
|
|
929
|
+
throw this.errorControlCharInString();
|
|
930
|
+
} else {
|
|
931
|
+
this.consume();
|
|
932
|
+
}
|
|
933
|
+
} while (this.nextChar());
|
|
934
|
+
}
|
|
935
|
+
errorControlCharInString() {
|
|
936
|
+
let displayCode = "\\u00";
|
|
937
|
+
if (this.char < 16) {
|
|
938
|
+
displayCode += "0";
|
|
939
|
+
}
|
|
940
|
+
displayCode += this.char.toString(16);
|
|
941
|
+
return this.error(new TomlError(`Control characters (codes < 0x1f and 0x7f) are not allowed in strings, use ${displayCode} instead`));
|
|
942
|
+
}
|
|
943
|
+
recordMultiEscapeReplacement(replacement) {
|
|
944
|
+
this.state.buf += replacement;
|
|
945
|
+
return this.goto(this.parseMultiStringContent);
|
|
946
|
+
}
|
|
947
|
+
parseMultiEnd() {
|
|
948
|
+
if (this.char === CHAR_QUOT) {
|
|
949
|
+
return this.next(this.parseMultiEnd2);
|
|
950
|
+
} else {
|
|
951
|
+
this.state.buf += '"';
|
|
952
|
+
return this.goto(this.parseMultiStringContent);
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
parseMultiEnd2() {
|
|
956
|
+
if (this.char === CHAR_QUOT) {
|
|
957
|
+
return this.return();
|
|
958
|
+
} else {
|
|
959
|
+
this.state.buf += '""';
|
|
960
|
+
return this.goto(this.parseMultiStringContent);
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
parseMultiEscape() {
|
|
964
|
+
if (this.char === CTRL_M || this.char === CTRL_J) {
|
|
965
|
+
return this.next(this.parseMultiTrim);
|
|
966
|
+
} else if (this.char === CHAR_SP || this.char === CTRL_I) {
|
|
967
|
+
return this.next(this.parsePreMultiTrim);
|
|
968
|
+
} else {
|
|
969
|
+
return this.goto(this.parseEscape);
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
parsePreMultiTrim() {
|
|
973
|
+
if (this.char === CHAR_SP || this.char === CTRL_I) {
|
|
974
|
+
return null;
|
|
975
|
+
} else if (this.char === CTRL_M || this.char === CTRL_J) {
|
|
976
|
+
return this.next(this.parseMultiTrim);
|
|
977
|
+
} else {
|
|
978
|
+
throw this.error(new TomlError("Can't escape whitespace"));
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
parseMultiTrim() {
|
|
982
|
+
if (this.char === CTRL_J || this.char === CHAR_SP || this.char === CTRL_I || this.char === CTRL_M) {
|
|
983
|
+
return null;
|
|
984
|
+
} else {
|
|
985
|
+
return this.returnNow();
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
parseEscape() {
|
|
989
|
+
if (this.char in escapes) {
|
|
990
|
+
return this.return(escapes[this.char]);
|
|
991
|
+
} else if (this.char === CHAR_u) {
|
|
992
|
+
return this.call(this.parseSmallUnicode, this.parseUnicodeReturn);
|
|
993
|
+
} else if (this.char === CHAR_U) {
|
|
994
|
+
return this.call(this.parseLargeUnicode, this.parseUnicodeReturn);
|
|
995
|
+
} else {
|
|
996
|
+
throw this.error(new TomlError("Unknown escape character: " + this.char));
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
parseUnicodeReturn(char) {
|
|
1000
|
+
try {
|
|
1001
|
+
const codePoint = parseInt(char, 16);
|
|
1002
|
+
if (codePoint >= SURROGATE_FIRST && codePoint <= SURROGATE_LAST) {
|
|
1003
|
+
throw this.error(new TomlError("Invalid unicode, character in range 0xD800 - 0xDFFF is reserved"));
|
|
1004
|
+
}
|
|
1005
|
+
return this.returnNow(String.fromCodePoint(codePoint));
|
|
1006
|
+
} catch (err) {
|
|
1007
|
+
throw this.error(TomlError.wrap(err));
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
parseSmallUnicode() {
|
|
1011
|
+
if (!isHexit(this.char)) {
|
|
1012
|
+
throw this.error(new TomlError("Invalid character in unicode sequence, expected hex"));
|
|
1013
|
+
} else {
|
|
1014
|
+
this.consume();
|
|
1015
|
+
if (this.state.buf.length >= 4) return this.return();
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
parseLargeUnicode() {
|
|
1019
|
+
if (!isHexit(this.char)) {
|
|
1020
|
+
throw this.error(new TomlError("Invalid character in unicode sequence, expected hex"));
|
|
1021
|
+
} else {
|
|
1022
|
+
this.consume();
|
|
1023
|
+
if (this.state.buf.length >= 8) return this.return();
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
/* NUMBERS */
|
|
1027
|
+
parseNumberSign() {
|
|
1028
|
+
this.consume();
|
|
1029
|
+
return this.next(this.parseMaybeSignedInfOrNan);
|
|
1030
|
+
}
|
|
1031
|
+
parseMaybeSignedInfOrNan() {
|
|
1032
|
+
if (this.char === CHAR_i) {
|
|
1033
|
+
return this.next(this.parseInf);
|
|
1034
|
+
} else if (this.char === CHAR_n) {
|
|
1035
|
+
return this.next(this.parseNan);
|
|
1036
|
+
} else {
|
|
1037
|
+
return this.callNow(this.parseNoUnder, this.parseNumberIntegerStart);
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
parseNumberIntegerStart() {
|
|
1041
|
+
if (this.char === CHAR_0) {
|
|
1042
|
+
this.consume();
|
|
1043
|
+
return this.next(this.parseNumberIntegerExponentOrDecimal);
|
|
1044
|
+
} else {
|
|
1045
|
+
return this.goto(this.parseNumberInteger);
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
parseNumberIntegerExponentOrDecimal() {
|
|
1049
|
+
if (this.char === CHAR_PERIOD) {
|
|
1050
|
+
this.consume();
|
|
1051
|
+
return this.call(this.parseNoUnder, this.parseNumberFloat);
|
|
1052
|
+
} else if (this.char === CHAR_E || this.char === CHAR_e) {
|
|
1053
|
+
this.consume();
|
|
1054
|
+
return this.next(this.parseNumberExponentSign);
|
|
1055
|
+
} else {
|
|
1056
|
+
return this.returnNow(Integer(this.state.buf));
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
parseNumberInteger() {
|
|
1060
|
+
if (isDigit(this.char)) {
|
|
1061
|
+
this.consume();
|
|
1062
|
+
} else if (this.char === CHAR_LOWBAR) {
|
|
1063
|
+
return this.call(this.parseNoUnder);
|
|
1064
|
+
} else if (this.char === CHAR_E || this.char === CHAR_e) {
|
|
1065
|
+
this.consume();
|
|
1066
|
+
return this.next(this.parseNumberExponentSign);
|
|
1067
|
+
} else if (this.char === CHAR_PERIOD) {
|
|
1068
|
+
this.consume();
|
|
1069
|
+
return this.call(this.parseNoUnder, this.parseNumberFloat);
|
|
1070
|
+
} else {
|
|
1071
|
+
const result = Integer(this.state.buf);
|
|
1072
|
+
if (result.isNaN()) {
|
|
1073
|
+
throw this.error(new TomlError("Invalid number"));
|
|
1074
|
+
} else {
|
|
1075
|
+
return this.returnNow(result);
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
parseNoUnder() {
|
|
1080
|
+
if (this.char === CHAR_LOWBAR || this.char === CHAR_PERIOD || this.char === CHAR_E || this.char === CHAR_e) {
|
|
1081
|
+
throw this.error(new TomlError("Unexpected character, expected digit"));
|
|
1082
|
+
} else if (this.atEndOfWord()) {
|
|
1083
|
+
throw this.error(new TomlError("Incomplete number"));
|
|
1084
|
+
}
|
|
1085
|
+
return this.returnNow();
|
|
1086
|
+
}
|
|
1087
|
+
parseNoUnderHexOctBinLiteral() {
|
|
1088
|
+
if (this.char === CHAR_LOWBAR || this.char === CHAR_PERIOD) {
|
|
1089
|
+
throw this.error(new TomlError("Unexpected character, expected digit"));
|
|
1090
|
+
} else if (this.atEndOfWord()) {
|
|
1091
|
+
throw this.error(new TomlError("Incomplete number"));
|
|
1092
|
+
}
|
|
1093
|
+
return this.returnNow();
|
|
1094
|
+
}
|
|
1095
|
+
parseNumberFloat() {
|
|
1096
|
+
if (this.char === CHAR_LOWBAR) {
|
|
1097
|
+
return this.call(this.parseNoUnder, this.parseNumberFloat);
|
|
1098
|
+
} else if (isDigit(this.char)) {
|
|
1099
|
+
this.consume();
|
|
1100
|
+
} else if (this.char === CHAR_E || this.char === CHAR_e) {
|
|
1101
|
+
this.consume();
|
|
1102
|
+
return this.next(this.parseNumberExponentSign);
|
|
1103
|
+
} else {
|
|
1104
|
+
return this.returnNow(Float(this.state.buf));
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
parseNumberExponentSign() {
|
|
1108
|
+
if (isDigit(this.char)) {
|
|
1109
|
+
return this.goto(this.parseNumberExponent);
|
|
1110
|
+
} else if (this.char === CHAR_HYPHEN || this.char === CHAR_PLUS) {
|
|
1111
|
+
this.consume();
|
|
1112
|
+
this.call(this.parseNoUnder, this.parseNumberExponent);
|
|
1113
|
+
} else {
|
|
1114
|
+
throw this.error(new TomlError("Unexpected character, expected -, + or digit"));
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
parseNumberExponent() {
|
|
1118
|
+
if (isDigit(this.char)) {
|
|
1119
|
+
this.consume();
|
|
1120
|
+
} else if (this.char === CHAR_LOWBAR) {
|
|
1121
|
+
return this.call(this.parseNoUnder);
|
|
1122
|
+
} else {
|
|
1123
|
+
return this.returnNow(Float(this.state.buf));
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
/* NUMBERS or DATETIMES */
|
|
1127
|
+
parseNumberOrDateTime() {
|
|
1128
|
+
if (this.char === CHAR_0) {
|
|
1129
|
+
this.consume();
|
|
1130
|
+
return this.next(this.parseNumberBaseOrDateTime);
|
|
1131
|
+
} else {
|
|
1132
|
+
return this.goto(this.parseNumberOrDateTimeOnly);
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
parseNumberOrDateTimeOnly() {
|
|
1136
|
+
if (this.char === CHAR_LOWBAR) {
|
|
1137
|
+
return this.call(this.parseNoUnder, this.parseNumberInteger);
|
|
1138
|
+
} else if (isDigit(this.char)) {
|
|
1139
|
+
this.consume();
|
|
1140
|
+
if (this.state.buf.length > 4) this.next(this.parseNumberInteger);
|
|
1141
|
+
} else if (this.char === CHAR_E || this.char === CHAR_e) {
|
|
1142
|
+
this.consume();
|
|
1143
|
+
return this.next(this.parseNumberExponentSign);
|
|
1144
|
+
} else if (this.char === CHAR_PERIOD) {
|
|
1145
|
+
this.consume();
|
|
1146
|
+
return this.call(this.parseNoUnder, this.parseNumberFloat);
|
|
1147
|
+
} else if (this.char === CHAR_HYPHEN) {
|
|
1148
|
+
return this.goto(this.parseDateTime);
|
|
1149
|
+
} else if (this.char === CHAR_COLON) {
|
|
1150
|
+
return this.goto(this.parseOnlyTimeHour);
|
|
1151
|
+
} else {
|
|
1152
|
+
return this.returnNow(Integer(this.state.buf));
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
parseDateTimeOnly() {
|
|
1156
|
+
if (this.state.buf.length < 4) {
|
|
1157
|
+
if (isDigit(this.char)) {
|
|
1158
|
+
return this.consume();
|
|
1159
|
+
} else if (this.char === CHAR_COLON) {
|
|
1160
|
+
return this.goto(this.parseOnlyTimeHour);
|
|
1161
|
+
} else {
|
|
1162
|
+
throw this.error(new TomlError("Expected digit while parsing year part of a date"));
|
|
1163
|
+
}
|
|
1164
|
+
} else {
|
|
1165
|
+
if (this.char === CHAR_HYPHEN) {
|
|
1166
|
+
return this.goto(this.parseDateTime);
|
|
1167
|
+
} else {
|
|
1168
|
+
throw this.error(new TomlError("Expected hyphen (-) while parsing year part of date"));
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
parseNumberBaseOrDateTime() {
|
|
1173
|
+
if (this.char === CHAR_b) {
|
|
1174
|
+
this.consume();
|
|
1175
|
+
return this.call(this.parseNoUnderHexOctBinLiteral, this.parseIntegerBin);
|
|
1176
|
+
} else if (this.char === CHAR_o) {
|
|
1177
|
+
this.consume();
|
|
1178
|
+
return this.call(this.parseNoUnderHexOctBinLiteral, this.parseIntegerOct);
|
|
1179
|
+
} else if (this.char === CHAR_x) {
|
|
1180
|
+
this.consume();
|
|
1181
|
+
return this.call(this.parseNoUnderHexOctBinLiteral, this.parseIntegerHex);
|
|
1182
|
+
} else if (this.char === CHAR_PERIOD) {
|
|
1183
|
+
return this.goto(this.parseNumberInteger);
|
|
1184
|
+
} else if (isDigit(this.char)) {
|
|
1185
|
+
return this.goto(this.parseDateTimeOnly);
|
|
1186
|
+
} else {
|
|
1187
|
+
return this.returnNow(Integer(this.state.buf));
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
parseIntegerHex() {
|
|
1191
|
+
if (isHexit(this.char)) {
|
|
1192
|
+
this.consume();
|
|
1193
|
+
} else if (this.char === CHAR_LOWBAR) {
|
|
1194
|
+
return this.call(this.parseNoUnderHexOctBinLiteral);
|
|
1195
|
+
} else {
|
|
1196
|
+
const result = Integer(this.state.buf);
|
|
1197
|
+
if (result.isNaN()) {
|
|
1198
|
+
throw this.error(new TomlError("Invalid number"));
|
|
1199
|
+
} else {
|
|
1200
|
+
return this.returnNow(result);
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
parseIntegerOct() {
|
|
1205
|
+
if (isOctit(this.char)) {
|
|
1206
|
+
this.consume();
|
|
1207
|
+
} else if (this.char === CHAR_LOWBAR) {
|
|
1208
|
+
return this.call(this.parseNoUnderHexOctBinLiteral);
|
|
1209
|
+
} else {
|
|
1210
|
+
const result = Integer(this.state.buf);
|
|
1211
|
+
if (result.isNaN()) {
|
|
1212
|
+
throw this.error(new TomlError("Invalid number"));
|
|
1213
|
+
} else {
|
|
1214
|
+
return this.returnNow(result);
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
parseIntegerBin() {
|
|
1219
|
+
if (isBit(this.char)) {
|
|
1220
|
+
this.consume();
|
|
1221
|
+
} else if (this.char === CHAR_LOWBAR) {
|
|
1222
|
+
return this.call(this.parseNoUnderHexOctBinLiteral);
|
|
1223
|
+
} else {
|
|
1224
|
+
const result = Integer(this.state.buf);
|
|
1225
|
+
if (result.isNaN()) {
|
|
1226
|
+
throw this.error(new TomlError("Invalid number"));
|
|
1227
|
+
} else {
|
|
1228
|
+
return this.returnNow(result);
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
/* DATETIME */
|
|
1233
|
+
parseDateTime() {
|
|
1234
|
+
if (this.state.buf.length < 4) {
|
|
1235
|
+
throw this.error(new TomlError("Years less than 1000 must be zero padded to four characters"));
|
|
1236
|
+
}
|
|
1237
|
+
this.state.result = this.state.buf;
|
|
1238
|
+
this.state.buf = "";
|
|
1239
|
+
return this.next(this.parseDateMonth);
|
|
1240
|
+
}
|
|
1241
|
+
parseDateMonth() {
|
|
1242
|
+
if (this.char === CHAR_HYPHEN) {
|
|
1243
|
+
if (this.state.buf.length < 2) {
|
|
1244
|
+
throw this.error(new TomlError("Months less than 10 must be zero padded to two characters"));
|
|
1245
|
+
}
|
|
1246
|
+
this.state.result += "-" + this.state.buf;
|
|
1247
|
+
this.state.buf = "";
|
|
1248
|
+
return this.next(this.parseDateDay);
|
|
1249
|
+
} else if (isDigit(this.char)) {
|
|
1250
|
+
this.consume();
|
|
1251
|
+
} else {
|
|
1252
|
+
throw this.error(new TomlError("Incomplete datetime"));
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
parseDateDay() {
|
|
1256
|
+
if (this.char === CHAR_T || this.char === CHAR_SP) {
|
|
1257
|
+
if (this.state.buf.length < 2) {
|
|
1258
|
+
throw this.error(new TomlError("Days less than 10 must be zero padded to two characters"));
|
|
1259
|
+
}
|
|
1260
|
+
this.state.result += "-" + this.state.buf;
|
|
1261
|
+
this.state.buf = "";
|
|
1262
|
+
return this.next(this.parseStartTimeHour);
|
|
1263
|
+
} else if (this.atEndOfWord()) {
|
|
1264
|
+
return this.returnNow(createDate(this.state.result + "-" + this.state.buf));
|
|
1265
|
+
} else if (isDigit(this.char)) {
|
|
1266
|
+
this.consume();
|
|
1267
|
+
} else {
|
|
1268
|
+
throw this.error(new TomlError("Incomplete datetime"));
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
parseStartTimeHour() {
|
|
1272
|
+
if (this.atEndOfWord()) {
|
|
1273
|
+
return this.returnNow(createDate(this.state.result));
|
|
1274
|
+
} else {
|
|
1275
|
+
return this.goto(this.parseTimeHour);
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
parseTimeHour() {
|
|
1279
|
+
if (this.char === CHAR_COLON) {
|
|
1280
|
+
if (this.state.buf.length < 2) {
|
|
1281
|
+
throw this.error(new TomlError("Hours less than 10 must be zero padded to two characters"));
|
|
1282
|
+
}
|
|
1283
|
+
this.state.result += "T" + this.state.buf;
|
|
1284
|
+
this.state.buf = "";
|
|
1285
|
+
return this.next(this.parseTimeMin);
|
|
1286
|
+
} else if (isDigit(this.char)) {
|
|
1287
|
+
this.consume();
|
|
1288
|
+
} else {
|
|
1289
|
+
throw this.error(new TomlError("Incomplete datetime"));
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
parseTimeMin() {
|
|
1293
|
+
if (this.state.buf.length < 2 && isDigit(this.char)) {
|
|
1294
|
+
this.consume();
|
|
1295
|
+
} else if (this.state.buf.length === 2 && this.char === CHAR_COLON) {
|
|
1296
|
+
this.state.result += ":" + this.state.buf;
|
|
1297
|
+
this.state.buf = "";
|
|
1298
|
+
return this.next(this.parseTimeSec);
|
|
1299
|
+
} else {
|
|
1300
|
+
throw this.error(new TomlError("Incomplete datetime"));
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
parseTimeSec() {
|
|
1304
|
+
if (isDigit(this.char)) {
|
|
1305
|
+
this.consume();
|
|
1306
|
+
if (this.state.buf.length === 2) {
|
|
1307
|
+
this.state.result += ":" + this.state.buf;
|
|
1308
|
+
this.state.buf = "";
|
|
1309
|
+
return this.next(this.parseTimeZoneOrFraction);
|
|
1310
|
+
}
|
|
1311
|
+
} else {
|
|
1312
|
+
throw this.error(new TomlError("Incomplete datetime"));
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
parseOnlyTimeHour() {
|
|
1316
|
+
if (this.char === CHAR_COLON) {
|
|
1317
|
+
if (this.state.buf.length < 2) {
|
|
1318
|
+
throw this.error(new TomlError("Hours less than 10 must be zero padded to two characters"));
|
|
1319
|
+
}
|
|
1320
|
+
this.state.result = this.state.buf;
|
|
1321
|
+
this.state.buf = "";
|
|
1322
|
+
return this.next(this.parseOnlyTimeMin);
|
|
1323
|
+
} else {
|
|
1324
|
+
throw this.error(new TomlError("Incomplete time"));
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
parseOnlyTimeMin() {
|
|
1328
|
+
if (this.state.buf.length < 2 && isDigit(this.char)) {
|
|
1329
|
+
this.consume();
|
|
1330
|
+
} else if (this.state.buf.length === 2 && this.char === CHAR_COLON) {
|
|
1331
|
+
this.state.result += ":" + this.state.buf;
|
|
1332
|
+
this.state.buf = "";
|
|
1333
|
+
return this.next(this.parseOnlyTimeSec);
|
|
1334
|
+
} else {
|
|
1335
|
+
throw this.error(new TomlError("Incomplete time"));
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
parseOnlyTimeSec() {
|
|
1339
|
+
if (isDigit(this.char)) {
|
|
1340
|
+
this.consume();
|
|
1341
|
+
if (this.state.buf.length === 2) {
|
|
1342
|
+
return this.next(this.parseOnlyTimeFractionMaybe);
|
|
1343
|
+
}
|
|
1344
|
+
} else {
|
|
1345
|
+
throw this.error(new TomlError("Incomplete time"));
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
parseOnlyTimeFractionMaybe() {
|
|
1349
|
+
this.state.result += ":" + this.state.buf;
|
|
1350
|
+
if (this.char === CHAR_PERIOD) {
|
|
1351
|
+
this.state.buf = "";
|
|
1352
|
+
this.next(this.parseOnlyTimeFraction);
|
|
1353
|
+
} else {
|
|
1354
|
+
return this.return(createTime(this.state.result));
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
parseOnlyTimeFraction() {
|
|
1358
|
+
if (isDigit(this.char)) {
|
|
1359
|
+
this.consume();
|
|
1360
|
+
} else if (this.atEndOfWord()) {
|
|
1361
|
+
if (this.state.buf.length === 0) throw this.error(new TomlError("Expected digit in milliseconds"));
|
|
1362
|
+
return this.returnNow(createTime(this.state.result + "." + this.state.buf));
|
|
1363
|
+
} else {
|
|
1364
|
+
throw this.error(new TomlError("Unexpected character in datetime, expected period (.), minus (-), plus (+) or Z"));
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
parseTimeZoneOrFraction() {
|
|
1368
|
+
if (this.char === CHAR_PERIOD) {
|
|
1369
|
+
this.consume();
|
|
1370
|
+
this.next(this.parseDateTimeFraction);
|
|
1371
|
+
} else if (this.char === CHAR_HYPHEN || this.char === CHAR_PLUS) {
|
|
1372
|
+
this.consume();
|
|
1373
|
+
this.next(this.parseTimeZoneHour);
|
|
1374
|
+
} else if (this.char === CHAR_Z) {
|
|
1375
|
+
this.consume();
|
|
1376
|
+
return this.return(createDateTime(this.state.result + this.state.buf));
|
|
1377
|
+
} else if (this.atEndOfWord()) {
|
|
1378
|
+
return this.returnNow(createDateTimeFloat(this.state.result + this.state.buf));
|
|
1379
|
+
} else {
|
|
1380
|
+
throw this.error(new TomlError("Unexpected character in datetime, expected period (.), minus (-), plus (+) or Z"));
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
parseDateTimeFraction() {
|
|
1384
|
+
if (isDigit(this.char)) {
|
|
1385
|
+
this.consume();
|
|
1386
|
+
} else if (this.state.buf.length === 1) {
|
|
1387
|
+
throw this.error(new TomlError("Expected digit in milliseconds"));
|
|
1388
|
+
} else if (this.char === CHAR_HYPHEN || this.char === CHAR_PLUS) {
|
|
1389
|
+
this.consume();
|
|
1390
|
+
this.next(this.parseTimeZoneHour);
|
|
1391
|
+
} else if (this.char === CHAR_Z) {
|
|
1392
|
+
this.consume();
|
|
1393
|
+
return this.return(createDateTime(this.state.result + this.state.buf));
|
|
1394
|
+
} else if (this.atEndOfWord()) {
|
|
1395
|
+
return this.returnNow(createDateTimeFloat(this.state.result + this.state.buf));
|
|
1396
|
+
} else {
|
|
1397
|
+
throw this.error(new TomlError("Unexpected character in datetime, expected period (.), minus (-), plus (+) or Z"));
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
parseTimeZoneHour() {
|
|
1401
|
+
if (isDigit(this.char)) {
|
|
1402
|
+
this.consume();
|
|
1403
|
+
if (/\d\d$/.test(this.state.buf)) return this.next(this.parseTimeZoneSep);
|
|
1404
|
+
} else {
|
|
1405
|
+
throw this.error(new TomlError("Unexpected character in datetime, expected digit"));
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
parseTimeZoneSep() {
|
|
1409
|
+
if (this.char === CHAR_COLON) {
|
|
1410
|
+
this.consume();
|
|
1411
|
+
this.next(this.parseTimeZoneMin);
|
|
1412
|
+
} else {
|
|
1413
|
+
throw this.error(new TomlError("Unexpected character in datetime, expected colon"));
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
parseTimeZoneMin() {
|
|
1417
|
+
if (isDigit(this.char)) {
|
|
1418
|
+
this.consume();
|
|
1419
|
+
if (/\d\d$/.test(this.state.buf)) return this.return(createDateTime(this.state.result + this.state.buf));
|
|
1420
|
+
} else {
|
|
1421
|
+
throw this.error(new TomlError("Unexpected character in datetime, expected digit"));
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
/* BOOLEAN */
|
|
1425
|
+
parseBoolean() {
|
|
1426
|
+
if (this.char === CHAR_t) {
|
|
1427
|
+
this.consume();
|
|
1428
|
+
return this.next(this.parseTrue_r);
|
|
1429
|
+
} else if (this.char === CHAR_f) {
|
|
1430
|
+
this.consume();
|
|
1431
|
+
return this.next(this.parseFalse_a);
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
parseTrue_r() {
|
|
1435
|
+
if (this.char === CHAR_r) {
|
|
1436
|
+
this.consume();
|
|
1437
|
+
return this.next(this.parseTrue_u);
|
|
1438
|
+
} else {
|
|
1439
|
+
throw this.error(new TomlError("Invalid boolean, expected true or false"));
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
parseTrue_u() {
|
|
1443
|
+
if (this.char === CHAR_u) {
|
|
1444
|
+
this.consume();
|
|
1445
|
+
return this.next(this.parseTrue_e);
|
|
1446
|
+
} else {
|
|
1447
|
+
throw this.error(new TomlError("Invalid boolean, expected true or false"));
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
parseTrue_e() {
|
|
1451
|
+
if (this.char === CHAR_e) {
|
|
1452
|
+
return this.return(true);
|
|
1453
|
+
} else {
|
|
1454
|
+
throw this.error(new TomlError("Invalid boolean, expected true or false"));
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
parseFalse_a() {
|
|
1458
|
+
if (this.char === CHAR_a) {
|
|
1459
|
+
this.consume();
|
|
1460
|
+
return this.next(this.parseFalse_l);
|
|
1461
|
+
} else {
|
|
1462
|
+
throw this.error(new TomlError("Invalid boolean, expected true or false"));
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
parseFalse_l() {
|
|
1466
|
+
if (this.char === CHAR_l) {
|
|
1467
|
+
this.consume();
|
|
1468
|
+
return this.next(this.parseFalse_s);
|
|
1469
|
+
} else {
|
|
1470
|
+
throw this.error(new TomlError("Invalid boolean, expected true or false"));
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1473
|
+
parseFalse_s() {
|
|
1474
|
+
if (this.char === CHAR_s) {
|
|
1475
|
+
this.consume();
|
|
1476
|
+
return this.next(this.parseFalse_e);
|
|
1477
|
+
} else {
|
|
1478
|
+
throw this.error(new TomlError("Invalid boolean, expected true or false"));
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
parseFalse_e() {
|
|
1482
|
+
if (this.char === CHAR_e) {
|
|
1483
|
+
return this.return(false);
|
|
1484
|
+
} else {
|
|
1485
|
+
throw this.error(new TomlError("Invalid boolean, expected true or false"));
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
/* INLINE LISTS */
|
|
1489
|
+
parseInlineList() {
|
|
1490
|
+
if (this.char === CHAR_SP || this.char === CTRL_I || this.char === CTRL_M || this.char === CTRL_J) {
|
|
1491
|
+
return null;
|
|
1492
|
+
} else if (this.char === Parser.END) {
|
|
1493
|
+
throw this.error(new TomlError("Unterminated inline array"));
|
|
1494
|
+
} else if (this.char === CHAR_NUM) {
|
|
1495
|
+
return this.call(this.parseComment);
|
|
1496
|
+
} else if (this.char === CHAR_RSQB) {
|
|
1497
|
+
return this.return(this.state.resultArr || InlineList());
|
|
1498
|
+
} else {
|
|
1499
|
+
return this.callNow(this.parseValue, this.recordInlineListValue);
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
recordInlineListValue(value) {
|
|
1503
|
+
if (this.state.resultArr) {
|
|
1504
|
+
const listType = this.state.resultArr[_contentType];
|
|
1505
|
+
const valueType = tomlType(value);
|
|
1506
|
+
if (listType !== valueType) {
|
|
1507
|
+
throw this.error(new TomlError(`Inline lists must be a single type, not a mix of ${listType} and ${valueType}`));
|
|
1508
|
+
}
|
|
1509
|
+
} else {
|
|
1510
|
+
this.state.resultArr = InlineList(tomlType(value));
|
|
1511
|
+
}
|
|
1512
|
+
if (isFloat(value) || isInteger(value)) {
|
|
1513
|
+
this.state.resultArr.push(value.valueOf());
|
|
1514
|
+
} else {
|
|
1515
|
+
this.state.resultArr.push(value);
|
|
1516
|
+
}
|
|
1517
|
+
return this.goto(this.parseInlineListNext);
|
|
1518
|
+
}
|
|
1519
|
+
parseInlineListNext() {
|
|
1520
|
+
if (this.char === CHAR_SP || this.char === CTRL_I || this.char === CTRL_M || this.char === CTRL_J) {
|
|
1521
|
+
return null;
|
|
1522
|
+
} else if (this.char === CHAR_NUM) {
|
|
1523
|
+
return this.call(this.parseComment);
|
|
1524
|
+
} else if (this.char === CHAR_COMMA) {
|
|
1525
|
+
return this.next(this.parseInlineList);
|
|
1526
|
+
} else if (this.char === CHAR_RSQB) {
|
|
1527
|
+
return this.goto(this.parseInlineList);
|
|
1528
|
+
} else {
|
|
1529
|
+
throw this.error(new TomlError("Invalid character, expected whitespace, comma (,) or close bracket (])"));
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
/* INLINE TABLE */
|
|
1533
|
+
parseInlineTable() {
|
|
1534
|
+
if (this.char === CHAR_SP || this.char === CTRL_I) {
|
|
1535
|
+
return null;
|
|
1536
|
+
} else if (this.char === Parser.END || this.char === CHAR_NUM || this.char === CTRL_J || this.char === CTRL_M) {
|
|
1537
|
+
throw this.error(new TomlError("Unterminated inline array"));
|
|
1538
|
+
} else if (this.char === CHAR_RCUB) {
|
|
1539
|
+
return this.return(this.state.resultTable || InlineTable());
|
|
1540
|
+
} else {
|
|
1541
|
+
if (!this.state.resultTable) this.state.resultTable = InlineTable();
|
|
1542
|
+
return this.callNow(this.parseAssign, this.recordInlineTableValue);
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
recordInlineTableValue(kv) {
|
|
1546
|
+
let target = this.state.resultTable;
|
|
1547
|
+
let finalKey = kv.key.pop();
|
|
1548
|
+
for (let kw of kv.key) {
|
|
1549
|
+
if (hasKey(target, kw) && (!isTable(target[kw]) || target[kw][_declared])) {
|
|
1550
|
+
throw this.error(new TomlError("Can't redefine existing key"));
|
|
1551
|
+
}
|
|
1552
|
+
target = target[kw] = target[kw] || Table();
|
|
1553
|
+
}
|
|
1554
|
+
if (hasKey(target, finalKey)) {
|
|
1555
|
+
throw this.error(new TomlError("Can't redefine existing key"));
|
|
1556
|
+
}
|
|
1557
|
+
if (isInteger(kv.value) || isFloat(kv.value)) {
|
|
1558
|
+
target[finalKey] = kv.value.valueOf();
|
|
1559
|
+
} else {
|
|
1560
|
+
target[finalKey] = kv.value;
|
|
1561
|
+
}
|
|
1562
|
+
return this.goto(this.parseInlineTableNext);
|
|
1563
|
+
}
|
|
1564
|
+
parseInlineTableNext() {
|
|
1565
|
+
if (this.char === CHAR_SP || this.char === CTRL_I) {
|
|
1566
|
+
return null;
|
|
1567
|
+
} else if (this.char === Parser.END || this.char === CHAR_NUM || this.char === CTRL_J || this.char === CTRL_M) {
|
|
1568
|
+
throw this.error(new TomlError("Unterminated inline array"));
|
|
1569
|
+
} else if (this.char === CHAR_COMMA) {
|
|
1570
|
+
return this.next(this.parseInlineTable);
|
|
1571
|
+
} else if (this.char === CHAR_RCUB) {
|
|
1572
|
+
return this.goto(this.parseInlineTable);
|
|
1573
|
+
} else {
|
|
1574
|
+
throw this.error(new TomlError("Invalid character, expected whitespace, comma (,) or close bracket (])"));
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
return TOMLParser;
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
});
|
|
1582
|
+
|
|
1583
|
+
// node_modules/.pnpm/@iarna+toml@2.2.5/node_modules/@iarna/toml/parse-pretty-error.js
|
|
1584
|
+
var require_parse_pretty_error = __commonJS({
|
|
1585
|
+
"node_modules/.pnpm/@iarna+toml@2.2.5/node_modules/@iarna/toml/parse-pretty-error.js"(exports2, module2) {
|
|
1586
|
+
"use strict";
|
|
1587
|
+
module2.exports = prettyError;
|
|
1588
|
+
function prettyError(err, buf) {
|
|
1589
|
+
if (err.pos == null || err.line == null) return err;
|
|
1590
|
+
let msg = err.message;
|
|
1591
|
+
msg += ` at row ${err.line + 1}, col ${err.col + 1}, pos ${err.pos}:
|
|
1592
|
+
`;
|
|
1593
|
+
if (buf && buf.split) {
|
|
1594
|
+
const lines = buf.split(/\n/);
|
|
1595
|
+
const lineNumWidth = String(Math.min(lines.length, err.line + 3)).length;
|
|
1596
|
+
let linePadding = " ";
|
|
1597
|
+
while (linePadding.length < lineNumWidth) linePadding += " ";
|
|
1598
|
+
for (let ii = Math.max(0, err.line - 1); ii < Math.min(lines.length, err.line + 2); ++ii) {
|
|
1599
|
+
let lineNum = String(ii + 1);
|
|
1600
|
+
if (lineNum.length < lineNumWidth) lineNum = " " + lineNum;
|
|
1601
|
+
if (err.line === ii) {
|
|
1602
|
+
msg += lineNum + "> " + lines[ii] + "\n";
|
|
1603
|
+
msg += linePadding + " ";
|
|
1604
|
+
for (let hh = 0; hh < err.col; ++hh) {
|
|
1605
|
+
msg += " ";
|
|
1606
|
+
}
|
|
1607
|
+
msg += "^\n";
|
|
1608
|
+
} else {
|
|
1609
|
+
msg += lineNum + ": " + lines[ii] + "\n";
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
err.message = msg + "\n";
|
|
1614
|
+
return err;
|
|
1615
|
+
}
|
|
1616
|
+
}
|
|
1617
|
+
});
|
|
1618
|
+
|
|
1619
|
+
// node_modules/.pnpm/@iarna+toml@2.2.5/node_modules/@iarna/toml/parse-string.js
|
|
1620
|
+
var require_parse_string = __commonJS({
|
|
1621
|
+
"node_modules/.pnpm/@iarna+toml@2.2.5/node_modules/@iarna/toml/parse-string.js"(exports2, module2) {
|
|
1622
|
+
"use strict";
|
|
1623
|
+
module2.exports = parseString;
|
|
1624
|
+
var TOMLParser = require_toml_parser();
|
|
1625
|
+
var prettyError = require_parse_pretty_error();
|
|
1626
|
+
function parseString(str) {
|
|
1627
|
+
if (global.Buffer && global.Buffer.isBuffer(str)) {
|
|
1628
|
+
str = str.toString("utf8");
|
|
1629
|
+
}
|
|
1630
|
+
const parser = new TOMLParser();
|
|
1631
|
+
try {
|
|
1632
|
+
parser.parse(str);
|
|
1633
|
+
return parser.finish();
|
|
1634
|
+
} catch (err) {
|
|
1635
|
+
throw prettyError(err, str);
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
}
|
|
1639
|
+
});
|
|
1640
|
+
|
|
1641
|
+
// node_modules/.pnpm/@iarna+toml@2.2.5/node_modules/@iarna/toml/parse-async.js
|
|
1642
|
+
var require_parse_async = __commonJS({
|
|
1643
|
+
"node_modules/.pnpm/@iarna+toml@2.2.5/node_modules/@iarna/toml/parse-async.js"(exports2, module2) {
|
|
1644
|
+
"use strict";
|
|
1645
|
+
module2.exports = parseAsync;
|
|
1646
|
+
var TOMLParser = require_toml_parser();
|
|
1647
|
+
var prettyError = require_parse_pretty_error();
|
|
1648
|
+
function parseAsync(str, opts) {
|
|
1649
|
+
if (!opts) opts = {};
|
|
1650
|
+
const index = 0;
|
|
1651
|
+
const blocksize = opts.blocksize || 40960;
|
|
1652
|
+
const parser = new TOMLParser();
|
|
1653
|
+
return new Promise((resolve, reject2) => {
|
|
1654
|
+
setImmediate(parseAsyncNext, index, blocksize, resolve, reject2);
|
|
1655
|
+
});
|
|
1656
|
+
function parseAsyncNext(index2, blocksize2, resolve, reject2) {
|
|
1657
|
+
if (index2 >= str.length) {
|
|
1658
|
+
try {
|
|
1659
|
+
return resolve(parser.finish());
|
|
1660
|
+
} catch (err) {
|
|
1661
|
+
return reject2(prettyError(err, str));
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
try {
|
|
1665
|
+
parser.parse(str.slice(index2, index2 + blocksize2));
|
|
1666
|
+
setImmediate(parseAsyncNext, index2 + blocksize2, blocksize2, resolve, reject2);
|
|
1667
|
+
} catch (err) {
|
|
1668
|
+
reject2(prettyError(err, str));
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1673
|
+
});
|
|
1674
|
+
|
|
1675
|
+
// node_modules/.pnpm/@iarna+toml@2.2.5/node_modules/@iarna/toml/parse-stream.js
|
|
1676
|
+
var require_parse_stream = __commonJS({
|
|
1677
|
+
"node_modules/.pnpm/@iarna+toml@2.2.5/node_modules/@iarna/toml/parse-stream.js"(exports2, module2) {
|
|
1678
|
+
"use strict";
|
|
1679
|
+
module2.exports = parseStream;
|
|
1680
|
+
var stream = __require("stream");
|
|
1681
|
+
var TOMLParser = require_toml_parser();
|
|
1682
|
+
function parseStream(stm) {
|
|
1683
|
+
if (stm) {
|
|
1684
|
+
return parseReadable(stm);
|
|
1685
|
+
} else {
|
|
1686
|
+
return parseTransform(stm);
|
|
1687
|
+
}
|
|
1688
|
+
}
|
|
1689
|
+
function parseReadable(stm) {
|
|
1690
|
+
const parser = new TOMLParser();
|
|
1691
|
+
stm.setEncoding("utf8");
|
|
1692
|
+
return new Promise((resolve, reject2) => {
|
|
1693
|
+
let readable;
|
|
1694
|
+
let ended = false;
|
|
1695
|
+
let errored = false;
|
|
1696
|
+
function finish() {
|
|
1697
|
+
ended = true;
|
|
1698
|
+
if (readable) return;
|
|
1699
|
+
try {
|
|
1700
|
+
resolve(parser.finish());
|
|
1701
|
+
} catch (err) {
|
|
1702
|
+
reject2(err);
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1705
|
+
function error(err) {
|
|
1706
|
+
errored = true;
|
|
1707
|
+
reject2(err);
|
|
1708
|
+
}
|
|
1709
|
+
stm.once("end", finish);
|
|
1710
|
+
stm.once("error", error);
|
|
1711
|
+
readNext();
|
|
1712
|
+
function readNext() {
|
|
1713
|
+
readable = true;
|
|
1714
|
+
let data;
|
|
1715
|
+
while ((data = stm.read()) !== null) {
|
|
1716
|
+
try {
|
|
1717
|
+
parser.parse(data);
|
|
1718
|
+
} catch (err) {
|
|
1719
|
+
return error(err);
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
readable = false;
|
|
1723
|
+
if (ended) return finish();
|
|
1724
|
+
if (errored) return;
|
|
1725
|
+
stm.once("readable", readNext);
|
|
1726
|
+
}
|
|
1727
|
+
});
|
|
1728
|
+
}
|
|
1729
|
+
function parseTransform() {
|
|
1730
|
+
const parser = new TOMLParser();
|
|
1731
|
+
return new stream.Transform({
|
|
1732
|
+
objectMode: true,
|
|
1733
|
+
transform(chunk, encoding, cb) {
|
|
1734
|
+
try {
|
|
1735
|
+
parser.parse(chunk.toString(encoding));
|
|
1736
|
+
} catch (err) {
|
|
1737
|
+
this.emit("error", err);
|
|
1738
|
+
}
|
|
1739
|
+
cb();
|
|
1740
|
+
},
|
|
1741
|
+
flush(cb) {
|
|
1742
|
+
try {
|
|
1743
|
+
this.push(parser.finish());
|
|
1744
|
+
} catch (err) {
|
|
1745
|
+
this.emit("error", err);
|
|
1746
|
+
}
|
|
1747
|
+
cb();
|
|
1748
|
+
}
|
|
1749
|
+
});
|
|
1750
|
+
}
|
|
1751
|
+
}
|
|
1752
|
+
});
|
|
1753
|
+
|
|
1754
|
+
// node_modules/.pnpm/@iarna+toml@2.2.5/node_modules/@iarna/toml/parse.js
|
|
1755
|
+
var require_parse = __commonJS({
|
|
1756
|
+
"node_modules/.pnpm/@iarna+toml@2.2.5/node_modules/@iarna/toml/parse.js"(exports2, module2) {
|
|
1757
|
+
"use strict";
|
|
1758
|
+
module2.exports = require_parse_string();
|
|
1759
|
+
module2.exports.async = require_parse_async();
|
|
1760
|
+
module2.exports.stream = require_parse_stream();
|
|
1761
|
+
module2.exports.prettyError = require_parse_pretty_error();
|
|
1762
|
+
}
|
|
1763
|
+
});
|
|
1764
|
+
|
|
1765
|
+
// node_modules/.pnpm/@iarna+toml@2.2.5/node_modules/@iarna/toml/stringify.js
|
|
1766
|
+
var require_stringify = __commonJS({
|
|
1767
|
+
"node_modules/.pnpm/@iarna+toml@2.2.5/node_modules/@iarna/toml/stringify.js"(exports2, module2) {
|
|
1768
|
+
"use strict";
|
|
1769
|
+
module2.exports = stringify;
|
|
1770
|
+
module2.exports.value = stringifyInline;
|
|
1771
|
+
function stringify(obj) {
|
|
1772
|
+
if (obj === null) throw typeError("null");
|
|
1773
|
+
if (obj === void 0) throw typeError("undefined");
|
|
1774
|
+
if (typeof obj !== "object") throw typeError(typeof obj);
|
|
1775
|
+
if (typeof obj.toJSON === "function") obj = obj.toJSON();
|
|
1776
|
+
if (obj == null) return null;
|
|
1777
|
+
const type = tomlType2(obj);
|
|
1778
|
+
if (type !== "table") throw typeError(type);
|
|
1779
|
+
return stringifyObject("", "", obj);
|
|
1780
|
+
}
|
|
1781
|
+
function typeError(type) {
|
|
1782
|
+
return new Error("Can only stringify objects, not " + type);
|
|
1783
|
+
}
|
|
1784
|
+
function arrayOneTypeError() {
|
|
1785
|
+
return new Error("Array values can't have mixed types");
|
|
1786
|
+
}
|
|
1787
|
+
function getInlineKeys(obj) {
|
|
1788
|
+
return Object.keys(obj).filter((key) => isInline(obj[key]));
|
|
1789
|
+
}
|
|
1790
|
+
function getComplexKeys(obj) {
|
|
1791
|
+
return Object.keys(obj).filter((key) => !isInline(obj[key]));
|
|
1792
|
+
}
|
|
1793
|
+
function toJSON(obj) {
|
|
1794
|
+
let nobj = Array.isArray(obj) ? [] : Object.prototype.hasOwnProperty.call(obj, "__proto__") ? { ["__proto__"]: void 0 } : {};
|
|
1795
|
+
for (let prop of Object.keys(obj)) {
|
|
1796
|
+
if (obj[prop] && typeof obj[prop].toJSON === "function" && !("toISOString" in obj[prop])) {
|
|
1797
|
+
nobj[prop] = obj[prop].toJSON();
|
|
1798
|
+
} else {
|
|
1799
|
+
nobj[prop] = obj[prop];
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1802
|
+
return nobj;
|
|
1803
|
+
}
|
|
1804
|
+
function stringifyObject(prefix, indent, obj) {
|
|
1805
|
+
obj = toJSON(obj);
|
|
1806
|
+
var inlineKeys;
|
|
1807
|
+
var complexKeys;
|
|
1808
|
+
inlineKeys = getInlineKeys(obj);
|
|
1809
|
+
complexKeys = getComplexKeys(obj);
|
|
1810
|
+
var result = [];
|
|
1811
|
+
var inlineIndent = indent || "";
|
|
1812
|
+
inlineKeys.forEach((key) => {
|
|
1813
|
+
var type = tomlType2(obj[key]);
|
|
1814
|
+
if (type !== "undefined" && type !== "null") {
|
|
1815
|
+
result.push(inlineIndent + stringifyKey(key) + " = " + stringifyAnyInline(obj[key], true));
|
|
1816
|
+
}
|
|
1817
|
+
});
|
|
1818
|
+
if (result.length > 0) result.push("");
|
|
1819
|
+
var complexIndent = prefix && inlineKeys.length > 0 ? indent + " " : "";
|
|
1820
|
+
complexKeys.forEach((key) => {
|
|
1821
|
+
result.push(stringifyComplex(prefix, complexIndent, key, obj[key]));
|
|
1822
|
+
});
|
|
1823
|
+
return result.join("\n");
|
|
1824
|
+
}
|
|
1825
|
+
function isInline(value) {
|
|
1826
|
+
switch (tomlType2(value)) {
|
|
1827
|
+
case "undefined":
|
|
1828
|
+
case "null":
|
|
1829
|
+
case "integer":
|
|
1830
|
+
case "nan":
|
|
1831
|
+
case "float":
|
|
1832
|
+
case "boolean":
|
|
1833
|
+
case "string":
|
|
1834
|
+
case "datetime":
|
|
1835
|
+
return true;
|
|
1836
|
+
case "array":
|
|
1837
|
+
return value.length === 0 || tomlType2(value[0]) !== "table";
|
|
1838
|
+
case "table":
|
|
1839
|
+
return Object.keys(value).length === 0;
|
|
1840
|
+
/* istanbul ignore next */
|
|
1841
|
+
default:
|
|
1842
|
+
return false;
|
|
1843
|
+
}
|
|
1844
|
+
}
|
|
1845
|
+
function tomlType2(value) {
|
|
1846
|
+
if (value === void 0) {
|
|
1847
|
+
return "undefined";
|
|
1848
|
+
} else if (value === null) {
|
|
1849
|
+
return "null";
|
|
1850
|
+
} else if (typeof value === "bigint" || Number.isInteger(value) && !Object.is(value, -0)) {
|
|
1851
|
+
return "integer";
|
|
1852
|
+
} else if (typeof value === "number") {
|
|
1853
|
+
return "float";
|
|
1854
|
+
} else if (typeof value === "boolean") {
|
|
1855
|
+
return "boolean";
|
|
1856
|
+
} else if (typeof value === "string") {
|
|
1857
|
+
return "string";
|
|
1858
|
+
} else if ("toISOString" in value) {
|
|
1859
|
+
return isNaN(value) ? "undefined" : "datetime";
|
|
1860
|
+
} else if (Array.isArray(value)) {
|
|
1861
|
+
return "array";
|
|
1862
|
+
} else {
|
|
1863
|
+
return "table";
|
|
1864
|
+
}
|
|
1865
|
+
}
|
|
1866
|
+
function stringifyKey(key) {
|
|
1867
|
+
var keyStr = String(key);
|
|
1868
|
+
if (/^[-A-Za-z0-9_]+$/.test(keyStr)) {
|
|
1869
|
+
return keyStr;
|
|
1870
|
+
} else {
|
|
1871
|
+
return stringifyBasicString(keyStr);
|
|
1872
|
+
}
|
|
1873
|
+
}
|
|
1874
|
+
function stringifyBasicString(str) {
|
|
1875
|
+
return '"' + escapeString(str).replace(/"/g, '\\"') + '"';
|
|
1876
|
+
}
|
|
1877
|
+
function stringifyLiteralString(str) {
|
|
1878
|
+
return "'" + str + "'";
|
|
1879
|
+
}
|
|
1880
|
+
function numpad(num, str) {
|
|
1881
|
+
while (str.length < num) str = "0" + str;
|
|
1882
|
+
return str;
|
|
1883
|
+
}
|
|
1884
|
+
function escapeString(str) {
|
|
1885
|
+
return str.replace(/\\/g, "\\\\").replace(/[\b]/g, "\\b").replace(/\t/g, "\\t").replace(/\n/g, "\\n").replace(/\f/g, "\\f").replace(/\r/g, "\\r").replace(/([\u0000-\u001f\u007f])/, (c) => "\\u" + numpad(4, c.codePointAt(0).toString(16)));
|
|
1886
|
+
}
|
|
1887
|
+
function stringifyMultilineString(str) {
|
|
1888
|
+
let escaped = str.split(/\n/).map((str2) => {
|
|
1889
|
+
return escapeString(str2).replace(/"(?="")/g, '\\"');
|
|
1890
|
+
}).join("\n");
|
|
1891
|
+
if (escaped.slice(-1) === '"') escaped += "\\\n";
|
|
1892
|
+
return '"""\n' + escaped + '"""';
|
|
1893
|
+
}
|
|
1894
|
+
function stringifyAnyInline(value, multilineOk) {
|
|
1895
|
+
let type = tomlType2(value);
|
|
1896
|
+
if (type === "string") {
|
|
1897
|
+
if (multilineOk && /\n/.test(value)) {
|
|
1898
|
+
type = "string-multiline";
|
|
1899
|
+
} else if (!/[\b\t\n\f\r']/.test(value) && /"/.test(value)) {
|
|
1900
|
+
type = "string-literal";
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
return stringifyInline(value, type);
|
|
1904
|
+
}
|
|
1905
|
+
function stringifyInline(value, type) {
|
|
1906
|
+
if (!type) type = tomlType2(value);
|
|
1907
|
+
switch (type) {
|
|
1908
|
+
case "string-multiline":
|
|
1909
|
+
return stringifyMultilineString(value);
|
|
1910
|
+
case "string":
|
|
1911
|
+
return stringifyBasicString(value);
|
|
1912
|
+
case "string-literal":
|
|
1913
|
+
return stringifyLiteralString(value);
|
|
1914
|
+
case "integer":
|
|
1915
|
+
return stringifyInteger(value);
|
|
1916
|
+
case "float":
|
|
1917
|
+
return stringifyFloat(value);
|
|
1918
|
+
case "boolean":
|
|
1919
|
+
return stringifyBoolean(value);
|
|
1920
|
+
case "datetime":
|
|
1921
|
+
return stringifyDatetime(value);
|
|
1922
|
+
case "array":
|
|
1923
|
+
return stringifyInlineArray(value.filter((_) => tomlType2(_) !== "null" && tomlType2(_) !== "undefined" && tomlType2(_) !== "nan"));
|
|
1924
|
+
case "table":
|
|
1925
|
+
return stringifyInlineTable(value);
|
|
1926
|
+
/* istanbul ignore next */
|
|
1927
|
+
default:
|
|
1928
|
+
throw typeError(type);
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
function stringifyInteger(value) {
|
|
1932
|
+
return String(value).replace(/\B(?=(\d{3})+(?!\d))/g, "_");
|
|
1933
|
+
}
|
|
1934
|
+
function stringifyFloat(value) {
|
|
1935
|
+
if (value === Infinity) {
|
|
1936
|
+
return "inf";
|
|
1937
|
+
} else if (value === -Infinity) {
|
|
1938
|
+
return "-inf";
|
|
1939
|
+
} else if (Object.is(value, NaN)) {
|
|
1940
|
+
return "nan";
|
|
1941
|
+
} else if (Object.is(value, -0)) {
|
|
1942
|
+
return "-0.0";
|
|
1943
|
+
}
|
|
1944
|
+
var chunks = String(value).split(".");
|
|
1945
|
+
var int = chunks[0];
|
|
1946
|
+
var dec = chunks[1] || 0;
|
|
1947
|
+
return stringifyInteger(int) + "." + dec;
|
|
1948
|
+
}
|
|
1949
|
+
function stringifyBoolean(value) {
|
|
1950
|
+
return String(value);
|
|
1951
|
+
}
|
|
1952
|
+
function stringifyDatetime(value) {
|
|
1953
|
+
return value.toISOString();
|
|
1954
|
+
}
|
|
1955
|
+
function isNumber(type) {
|
|
1956
|
+
return type === "float" || type === "integer";
|
|
1957
|
+
}
|
|
1958
|
+
function arrayType(values) {
|
|
1959
|
+
var contentType = tomlType2(values[0]);
|
|
1960
|
+
if (values.every((_) => tomlType2(_) === contentType)) return contentType;
|
|
1961
|
+
if (values.every((_) => isNumber(tomlType2(_)))) return "float";
|
|
1962
|
+
return "mixed";
|
|
1963
|
+
}
|
|
1964
|
+
function validateArray(values) {
|
|
1965
|
+
const type = arrayType(values);
|
|
1966
|
+
if (type === "mixed") {
|
|
1967
|
+
throw arrayOneTypeError();
|
|
1968
|
+
}
|
|
1969
|
+
return type;
|
|
1970
|
+
}
|
|
1971
|
+
function stringifyInlineArray(values) {
|
|
1972
|
+
values = toJSON(values);
|
|
1973
|
+
const type = validateArray(values);
|
|
1974
|
+
var result = "[";
|
|
1975
|
+
var stringified = values.map((_) => stringifyInline(_, type));
|
|
1976
|
+
if (stringified.join(", ").length > 60 || /\n/.test(stringified)) {
|
|
1977
|
+
result += "\n " + stringified.join(",\n ") + "\n";
|
|
1978
|
+
} else {
|
|
1979
|
+
result += " " + stringified.join(", ") + (stringified.length > 0 ? " " : "");
|
|
1980
|
+
}
|
|
1981
|
+
return result + "]";
|
|
1982
|
+
}
|
|
1983
|
+
function stringifyInlineTable(value) {
|
|
1984
|
+
value = toJSON(value);
|
|
1985
|
+
var result = [];
|
|
1986
|
+
Object.keys(value).forEach((key) => {
|
|
1987
|
+
result.push(stringifyKey(key) + " = " + stringifyAnyInline(value[key], false));
|
|
1988
|
+
});
|
|
1989
|
+
return "{ " + result.join(", ") + (result.length > 0 ? " " : "") + "}";
|
|
1990
|
+
}
|
|
1991
|
+
function stringifyComplex(prefix, indent, key, value) {
|
|
1992
|
+
var valueType = tomlType2(value);
|
|
1993
|
+
if (valueType === "array") {
|
|
1994
|
+
return stringifyArrayOfTables(prefix, indent, key, value);
|
|
1995
|
+
} else if (valueType === "table") {
|
|
1996
|
+
return stringifyComplexTable(prefix, indent, key, value);
|
|
1997
|
+
} else {
|
|
1998
|
+
throw typeError(valueType);
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2001
|
+
function stringifyArrayOfTables(prefix, indent, key, values) {
|
|
2002
|
+
values = toJSON(values);
|
|
2003
|
+
validateArray(values);
|
|
2004
|
+
var firstValueType = tomlType2(values[0]);
|
|
2005
|
+
if (firstValueType !== "table") throw typeError(firstValueType);
|
|
2006
|
+
var fullKey = prefix + stringifyKey(key);
|
|
2007
|
+
var result = "";
|
|
2008
|
+
values.forEach((table) => {
|
|
2009
|
+
if (result.length > 0) result += "\n";
|
|
2010
|
+
result += indent + "[[" + fullKey + "]]\n";
|
|
2011
|
+
result += stringifyObject(fullKey + ".", indent, table);
|
|
2012
|
+
});
|
|
2013
|
+
return result;
|
|
2014
|
+
}
|
|
2015
|
+
function stringifyComplexTable(prefix, indent, key, value) {
|
|
2016
|
+
var fullKey = prefix + stringifyKey(key);
|
|
2017
|
+
var result = "";
|
|
2018
|
+
if (getInlineKeys(value).length > 0) {
|
|
2019
|
+
result += indent + "[" + fullKey + "]\n";
|
|
2020
|
+
}
|
|
2021
|
+
return result + stringifyObject(fullKey + ".", indent, value);
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
2024
|
+
});
|
|
2025
|
+
|
|
2026
|
+
// node_modules/.pnpm/@iarna+toml@2.2.5/node_modules/@iarna/toml/toml.js
|
|
2027
|
+
var require_toml = __commonJS({
|
|
2028
|
+
"node_modules/.pnpm/@iarna+toml@2.2.5/node_modules/@iarna/toml/toml.js"(exports2) {
|
|
2029
|
+
"use strict";
|
|
2030
|
+
exports2.parse = require_parse();
|
|
2031
|
+
exports2.stringify = require_stringify();
|
|
2032
|
+
}
|
|
2033
|
+
});
|
|
4
2034
|
|
|
5
2035
|
// packages/ceal-client-protocol/src/canonical-json.ts
|
|
6
2036
|
function cealCanonicalJson(value) {
|
|
@@ -109,6 +2139,9 @@ var client_wire_contract_default = {
|
|
|
109
2139
|
"document"
|
|
110
2140
|
],
|
|
111
2141
|
optional_fields: [
|
|
2142
|
+
"operation_id",
|
|
2143
|
+
"visible_output_max_bytes",
|
|
2144
|
+
"local_delivery",
|
|
112
2145
|
"verified_artifact"
|
|
113
2146
|
],
|
|
114
2147
|
bare_document_fields: [
|
|
@@ -195,6 +2228,7 @@ var CEAL_COMMAND_RESPONSE_FOCUSED_PROMPT_CONTINUATION_DOCUMENT_FIELDS = Object.f
|
|
|
195
2228
|
var CEAL_COMMAND_RESPONSE_DISCOVERY_COMMAND = response.discovery_command;
|
|
196
2229
|
var CEAL_COMMAND_RESPONSE_DISCOVERY_MANIFEST_SCHEMA_VERSION = response.discovery_manifest_schema_version;
|
|
197
2230
|
var CEAL_COMMAND_RESPONSE_DISCOVERY_MANIFEST_DOCUMENT_FIELDS = Object.freeze([...response.discovery_manifest_document_fields]);
|
|
2231
|
+
var CEAL_COMMAND_RESPONSE_MAX_BYTES = CEAL_ENCODED_JSON_DOCUMENT_MAX_BYTES;
|
|
198
2232
|
|
|
199
2233
|
// packages/ceal-client-protocol/src/vocabulary.ts
|
|
200
2234
|
function vocabulary(words) {
|
|
@@ -225,6 +2259,7 @@ var CEAL_WRITE_RECEIPT_PROVIDER_STATES = vocabulary(["outcome_unknown", "verifie
|
|
|
225
2259
|
var CEAL_WRITE_RECEIPT_PROVIDER_READBACKS = vocabulary(["outcome_unknown", "verified", "not_applied"]);
|
|
226
2260
|
var CEAL_PROTOCOL_VERSION = "1.4.0";
|
|
227
2261
|
var CEAL_OPERATION_ACCESS_SCHEMA_VERSION = "ceal.operation_access.v1";
|
|
2262
|
+
var CEAL_GATEWAY_CONTINUATION_CURSOR_PHASES = vocabulary(["scan", "delivery", "terminal"]);
|
|
228
2263
|
var CEAL_GATEWAY_ACTIVE_CALL_PHASES = vocabulary([
|
|
229
2264
|
"audited_call_pending",
|
|
230
2265
|
"continuation_read_pending",
|
|
@@ -248,6 +2283,7 @@ var CEAL_GATEWAY_ORGANIZATION_ROUTE_FACT_CALL_KEYS = Object.freeze([
|
|
|
248
2283
|
// packages/ceal-client-protocol/src/operation-next-actions.ts
|
|
249
2284
|
var CEAL_REPEAT_REQUEST_NEXT_ACTION = "repeat_request";
|
|
250
2285
|
var CEAL_INSPECT_RECEIPT_NEXT_ACTION = "inspect_receipt";
|
|
2286
|
+
var CEAL_ANSWER_WITH_GAP_NEXT_ACTION = "answer_with_gap";
|
|
251
2287
|
var CALLER_RECOVERABLE_NEXT_ACTION_VALUES = [
|
|
252
2288
|
"select_did_you_mean",
|
|
253
2289
|
"choose_new_output_path",
|
|
@@ -301,10 +2337,20 @@ var CALLER_RECOVERABLE_NEXT_ACTION_VALUES = [
|
|
|
301
2337
|
"retry_after",
|
|
302
2338
|
// The ref names a container of rows (a Notion database or data source), which
|
|
303
2339
|
// has no body of its own; the caller searches its rows instead of reading it.
|
|
304
|
-
"search_container_rows"
|
|
2340
|
+
"search_container_rows",
|
|
2341
|
+
// A settled unknown write names the exact receipt Operation that can inspect
|
|
2342
|
+
// its outcome without issuing another provider mutation.
|
|
2343
|
+
"write_receipt.get",
|
|
2344
|
+
// Command resolution carries the exact required Operation sequence beside
|
|
2345
|
+
// this action, so the caller can execute each declared input in order.
|
|
2346
|
+
"follow_required_action_sequence",
|
|
2347
|
+
// The command needs caller-owned local materialization (for example an
|
|
2348
|
+
// @path file) before the Gateway can receive the argument.
|
|
2349
|
+
"materialize_local_argument"
|
|
305
2350
|
];
|
|
306
2351
|
var CEAL_CALLER_RECOVERABLE_NEXT_ACTIONS = Object.freeze(CALLER_RECOVERABLE_NEXT_ACTION_VALUES);
|
|
307
2352
|
var NON_REMEDY_NEXT_ACTION_VALUES = [
|
|
2353
|
+
CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
|
|
308
2354
|
// Only an administrator can take the named step -- approving a place for an
|
|
309
2355
|
// Operation, granting a withheld capability -- so a non-administrator asks
|
|
310
2356
|
// one. The refusal names the administrator step; this word is the ask.
|
|
@@ -352,7 +2398,58 @@ var NON_REMEDY_NEXT_ACTION_VALUES = [
|
|
|
352
2398
|
"select_exact_approval"
|
|
353
2399
|
];
|
|
354
2400
|
var CEAL_NON_REMEDY_NEXT_ACTIONS = Object.freeze(NON_REMEDY_NEXT_ACTION_VALUES);
|
|
355
|
-
var
|
|
2401
|
+
var CEAL_DECLARED_NEXT_ACTIONS = Object.freeze([...CEAL_CALLER_RECOVERABLE_NEXT_ACTIONS, ...CEAL_NON_REMEDY_NEXT_ACTIONS]);
|
|
2402
|
+
var DECLARED = new Set(CEAL_DECLARED_NEXT_ACTIONS);
|
|
2403
|
+
function defineCealNonModelNextActions(actions) {
|
|
2404
|
+
return actions;
|
|
2405
|
+
}
|
|
2406
|
+
var NON_MODEL_NEXT_ACTION_VALUES = defineCealNonModelNextActions([
|
|
2407
|
+
CEAL_INSPECT_RECEIPT_NEXT_ACTION,
|
|
2408
|
+
"await_pending_approval",
|
|
2409
|
+
"inspect_gateway",
|
|
2410
|
+
"operator_action",
|
|
2411
|
+
"none",
|
|
2412
|
+
"check_gateway",
|
|
2413
|
+
"inspect_context_store",
|
|
2414
|
+
"inspect_local_cache",
|
|
2415
|
+
"inspect_local_client",
|
|
2416
|
+
"inspect_local_command",
|
|
2417
|
+
"inspect_local_output",
|
|
2418
|
+
"inspect_local_route",
|
|
2419
|
+
"inspect_request",
|
|
2420
|
+
"reconcile",
|
|
2421
|
+
"reconcile_occurrence",
|
|
2422
|
+
"retry_after_owner_recovery",
|
|
2423
|
+
"select_exact_approval"
|
|
2424
|
+
]);
|
|
2425
|
+
var NON_MODEL_NEXT_ACTIONS = new Set(NON_MODEL_NEXT_ACTION_VALUES);
|
|
2426
|
+
function isCealModelActionableNonRemedyNextAction(action) {
|
|
2427
|
+
return !NON_MODEL_NEXT_ACTIONS.has(action);
|
|
2428
|
+
}
|
|
2429
|
+
var CEAL_MODEL_ACTIONABLE_NEXT_ACTIONS = Object.freeze([
|
|
2430
|
+
...CEAL_CALLER_RECOVERABLE_NEXT_ACTIONS,
|
|
2431
|
+
...CEAL_NON_REMEDY_NEXT_ACTIONS.filter(isCealModelActionableNonRemedyNextAction)
|
|
2432
|
+
]);
|
|
2433
|
+
var MODEL_ACTIONABLE = new Set(CEAL_MODEL_ACTIONABLE_NEXT_ACTIONS);
|
|
2434
|
+
var NON_MODEL_ACTION_TO_MODEL_ACTION = Object.freeze({
|
|
2435
|
+
[CEAL_INSPECT_RECEIPT_NEXT_ACTION]: CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
|
|
2436
|
+
await_pending_approval: "ask_admin",
|
|
2437
|
+
inspect_gateway: CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
|
|
2438
|
+
operator_action: "ask_admin",
|
|
2439
|
+
none: CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
|
|
2440
|
+
check_gateway: "ask_admin",
|
|
2441
|
+
inspect_context_store: CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
|
|
2442
|
+
inspect_local_cache: CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
|
|
2443
|
+
inspect_local_client: CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
|
|
2444
|
+
inspect_local_command: CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
|
|
2445
|
+
inspect_local_output: CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
|
|
2446
|
+
inspect_local_route: CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
|
|
2447
|
+
inspect_request: CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
|
|
2448
|
+
reconcile: CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
|
|
2449
|
+
reconcile_occurrence: "ask_admin",
|
|
2450
|
+
retry_after_owner_recovery: "ask_admin",
|
|
2451
|
+
select_exact_approval: "ask_admin"
|
|
2452
|
+
});
|
|
356
2453
|
var RETRY_PROMISE_NEXT_ACTIONS = ["retry", "retry_after"];
|
|
357
2454
|
var RETRY_PROMISE = new Set(RETRY_PROMISE_NEXT_ACTIONS);
|
|
358
2455
|
var RECOVERABLE = new Set(CEAL_CALLER_RECOVERABLE_NEXT_ACTIONS);
|
|
@@ -622,21 +2719,15 @@ var CEAL_OPERATION_ACCESS_CLASSES = vocabulary(["read", "write"]);
|
|
|
622
2719
|
// packages/ceal-client-protocol/src/domain-vocabulary.ts
|
|
623
2720
|
var CEAL_CONNECTOR_STATUSES = vocabulary(["active", "disabled", "disconnected"]);
|
|
624
2721
|
var CEAL_CONNECTOR_CUSTODIES = vocabulary(["organization", "personal"]);
|
|
625
|
-
var CEAL_PROVIDER_BOUNDARY_KINDS = vocabulary([
|
|
626
|
-
"github_account",
|
|
627
|
-
"github_organization",
|
|
628
|
-
"google_workspace_domain",
|
|
629
|
-
"notion_workspace",
|
|
630
|
-
"slack_workspace"
|
|
631
|
-
]);
|
|
632
|
-
var CEAL_PROVIDER_BOUNDARY_EVIDENCE = vocabulary(["provider_readback", "operator_stated"]);
|
|
633
2722
|
var CEAL_ACCESS_LEVELS = vocabulary(["none", "read", "read_write"]);
|
|
634
2723
|
var CEAL_PERSONAL_ACCESS_CEILINGS = vocabulary(["disabled", "read", "read_write"]);
|
|
635
2724
|
var CEAL_TARGET_REF_PATTERN = "^[^\\p{Cc}]+$";
|
|
636
2725
|
var TARGET_REF = new RegExp(CEAL_TARGET_REF_PATTERN, "u");
|
|
637
2726
|
var CEAL_TARGET_VISIBILITIES = vocabulary(["public", "private"]);
|
|
638
|
-
var CEAL_PRINCIPAL_KINDS = vocabulary(["human", "
|
|
2727
|
+
var CEAL_PRINCIPAL_KINDS = vocabulary(["human", "runtime"]);
|
|
2728
|
+
var CEAL_PERSISTED_PRINCIPAL_KINDS = vocabulary(["human", "service", "runtime"]);
|
|
639
2729
|
var CEAL_ORGANIZATION_ROLES = vocabulary(["member", "admin"]);
|
|
2730
|
+
var CEAL_CALENDAR_PERIODS = vocabulary(["day", "week", "month"]);
|
|
640
2731
|
var LABEL_EXPECTATION = `public-safe display text of at most ${CEAL_PUBLIC_DISPLAY_NAME_MAX_BYTES} bytes`;
|
|
641
2732
|
|
|
642
2733
|
// packages/ceal-client-protocol/src/safe-json-budget.ts
|
|
@@ -812,7 +2903,7 @@ var CEAL_SCHEMA_LITERALS = [
|
|
|
812
2903
|
"ceal.operation_receipt.v1",
|
|
813
2904
|
"ceal.operation_result.v1",
|
|
814
2905
|
"ceal.operation_result.compact.v1",
|
|
815
|
-
"ceal.
|
|
2906
|
+
"ceal.local_result_file.v1",
|
|
816
2907
|
"ceal.local_result_root.v1",
|
|
817
2908
|
"ceal.owner_bootstrap_exchange_request.v1",
|
|
818
2909
|
"ceal.owner_bootstrap_exchange_result.v1",
|
|
@@ -842,6 +2933,9 @@ var CEAL_BOUNDED_SERIES_CATALOG = Object.freeze({
|
|
|
842
2933
|
gateway_personal_client_access_audit: (root) => join(root, "access-audit.jsonl")
|
|
843
2934
|
});
|
|
844
2935
|
|
|
2936
|
+
// packages/ceal-client-protocol/src/canonical-http-boundary.ts
|
|
2937
|
+
var CEAL_CANONICAL_HTTP_MAX_RESPONSE_BYTES = CEAL_COMMAND_RESPONSE_MAX_BYTES;
|
|
2938
|
+
|
|
845
2939
|
// packages/ceal-client-protocol/src/gateway-installation-activation.ts
|
|
846
2940
|
var CEAL_GATEWAY_INSTALLATION_ACTIVATION_CODE_DATA_CHARACTERS = 32;
|
|
847
2941
|
var CEAL_GATEWAY_INSTALLATION_ACTIVATION_CODE_CHECK_CHARACTERS = 8;
|
|
@@ -906,41 +3000,6 @@ var CEAL_VERIFIED_ARTIFACT_DESCRIPTOR_JSON_SCHEMA = Object.freeze({
|
|
|
906
3000
|
}
|
|
907
3001
|
});
|
|
908
3002
|
|
|
909
|
-
// packages/ceal-client-protocol/src/provider-operation-vocabulary.ts
|
|
910
|
-
var CEAL_FILE_TYPE_FAMILIES = vocabulary(["all", "image", "pdf"]);
|
|
911
|
-
var CEAL_GITHUB_ISSUE_STATES = vocabulary(["open", "closed", "all"]);
|
|
912
|
-
var CEAL_NOTION_UPDATABLE_BLOCK_TYPES = vocabulary([
|
|
913
|
-
"paragraph",
|
|
914
|
-
"heading_1",
|
|
915
|
-
"heading_2",
|
|
916
|
-
"heading_3",
|
|
917
|
-
"bulleted_list_item",
|
|
918
|
-
"numbered_list_item",
|
|
919
|
-
"to_do",
|
|
920
|
-
"code"
|
|
921
|
-
]);
|
|
922
|
-
var CEAL_NOTION_NEUTRAL_TYPES = vocabulary([
|
|
923
|
-
"text",
|
|
924
|
-
"number",
|
|
925
|
-
"boolean",
|
|
926
|
-
"date",
|
|
927
|
-
"select",
|
|
928
|
-
"multi_select",
|
|
929
|
-
"people",
|
|
930
|
-
"url",
|
|
931
|
-
"email",
|
|
932
|
-
"phone",
|
|
933
|
-
"unsupported"
|
|
934
|
-
]);
|
|
935
|
-
var CEAL_NOTION_IDENTITY_GAP_REASONS = vocabulary([
|
|
936
|
-
"identity_unavailable",
|
|
937
|
-
"identity_stale",
|
|
938
|
-
"identity_ambiguous",
|
|
939
|
-
"identity_revoked",
|
|
940
|
-
"identity_unlinked"
|
|
941
|
-
]);
|
|
942
|
-
var CEAL_NOTION_STRING_VALUE_TYPES = vocabulary(["text", "select", "url", "email", "phone"]);
|
|
943
|
-
|
|
944
3003
|
// packages/ceal-client-protocol/src/opaque-reference.ts
|
|
945
3004
|
var CEAL_OPAQUE_HANDLE_KINDS = vocabulary(["target", "message", "thread", "artifact", "document", "block", "object"]);
|
|
946
3005
|
var CEAL_OPAQUE_REF_KINDS = vocabulary([...CEAL_OPAQUE_HANDLE_KINDS, "result", "operation-receipt", "reply-receipt", "field", "notion-data-source"]);
|
|
@@ -950,6 +3009,7 @@ var REQUIRED_FIELDS = CEAL_CLIENT_WIRE_CONTRACT.command_response.bare_document_f
|
|
|
950
3009
|
var OPTIONAL_FIELDS = CEAL_CLIENT_WIRE_CONTRACT.command_response.bare_document_optional_fields;
|
|
951
3010
|
|
|
952
3011
|
// packages/ceal-client-protocol/src/resource-row.ts
|
|
3012
|
+
var CEAL_RESOURCE_ROW_TITLE_MATCH_DISPOSITIONS = vocabulary(["exact", "not_exact", "unknown"]);
|
|
953
3013
|
var CEAL_RESOURCE_SEARCH_ORDERS = vocabulary(["relevance", "modified", "viewed", "created"]);
|
|
954
3014
|
var CEAL_RESOURCE_SEARCH_DIRECTIONS = vocabulary(["ascending", "descending"]);
|
|
955
3015
|
var CEAL_RESOURCE_SEARCH_FILTERS = vocabulary(["query", "modified_since", "since", "until", "authored_by_me", "authored_by", "include_replies", "kinds", "container_ref", "container_refs", "container_names", "addressed_to_me", "unread"]);
|
|
@@ -973,6 +3033,7 @@ var CEAL_ACTIVITY_TIMESTAMP_BASES = vocabulary([
|
|
|
973
3033
|
"resource_modified"
|
|
974
3034
|
]);
|
|
975
3035
|
var CEAL_ACTIVITY_CONNECTOR_KINDS = vocabulary(["slack", "github", "google-calendar", "google-drive", "notion"]);
|
|
3036
|
+
var CEAL_ACTIVITY_UNSUPPORTED_EVENT_KIND_CODE = "unsupported_event_kind";
|
|
976
3037
|
var CEAL_ACTIVITY_GAP_CODES = vocabulary([
|
|
977
3038
|
"provider_page_budget",
|
|
978
3039
|
"call_deadline",
|
|
@@ -980,7 +3041,7 @@ var CEAL_ACTIVITY_GAP_CODES = vocabulary([
|
|
|
980
3041
|
"provider_cursor_unavailable",
|
|
981
3042
|
"malformed_provider_page",
|
|
982
3043
|
"visibility_incomplete",
|
|
983
|
-
|
|
3044
|
+
CEAL_ACTIVITY_UNSUPPORTED_EVENT_KIND_CODE,
|
|
984
3045
|
"direct_messages_excluded"
|
|
985
3046
|
]);
|
|
986
3047
|
var CEAL_ACTIVITY_EVENT_KINDS = vocabulary([
|
|
@@ -1032,6 +3093,7 @@ var RESOURCE_ROW_KEY_RULES = Object.freeze({
|
|
|
1032
3093
|
next: { required: true, timestamp: false },
|
|
1033
3094
|
kind: { required: true, timestamp: false },
|
|
1034
3095
|
matched_kinds: { required: false, timestamp: false },
|
|
3096
|
+
title_match: { required: false, timestamp: false },
|
|
1035
3097
|
title: { required: true, timestamp: false },
|
|
1036
3098
|
container_label: { required: true, timestamp: false },
|
|
1037
3099
|
container_ref: { required: false, timestamp: false },
|
|
@@ -1045,6 +3107,8 @@ var RESOURCE_ROW_KEY_RULES = Object.freeze({
|
|
|
1045
3107
|
modified_at: { required: false, timestamp: true },
|
|
1046
3108
|
modified_at_local: { required: false, timestamp: true },
|
|
1047
3109
|
viewed_by_me_at: { required: false, timestamp: true },
|
|
3110
|
+
own_ceal_write: { required: false, timestamp: false },
|
|
3111
|
+
owned_by_me: { required: false, timestamp: false },
|
|
1048
3112
|
visibility: { required: false, timestamp: false },
|
|
1049
3113
|
start: { required: false, timestamp: false },
|
|
1050
3114
|
end: { required: false, timestamp: false },
|
|
@@ -1078,6 +3142,15 @@ function cealExcludedTargetCoverageJsonSchema() {
|
|
|
1078
3142
|
};
|
|
1079
3143
|
}
|
|
1080
3144
|
|
|
3145
|
+
// packages/ceal-client-protocol/src/gateway-write-identity.ts
|
|
3146
|
+
var CEAL_GATEWAY_WRITE_IDENTITY_ROLES = Object.freeze(["replay_identity", "lookup_handle", "collision_evidence"]);
|
|
3147
|
+
var CEAL_GATEWAY_WRITE_REQUEST_REF_PATTERN = /^gateway-write-request:[a-f0-9]{8}-(?:[a-f0-9]{4}-){3}[a-f0-9]{12}$/u;
|
|
3148
|
+
var CEAL_GATEWAY_WRITE_IDENTITY_FIELDS = Object.freeze({
|
|
3149
|
+
replay_identity: "idempotency_claim_sha256",
|
|
3150
|
+
lookup_handle: "write_request_sha256",
|
|
3151
|
+
collision_evidence: "normalized_mutation_sha256"
|
|
3152
|
+
});
|
|
3153
|
+
|
|
1081
3154
|
// packages/ceal-client-protocol/src/write-safety-finding.ts
|
|
1082
3155
|
var CEAL_WRITE_SAFETY_FINDING_STATUSES = vocabulary(["warning", "unchecked"]);
|
|
1083
3156
|
var CEAL_WRITE_SAFETY_AUDIENCES = vocabulary(["workspace", "person", "members", "unknown"]);
|
|
@@ -1105,7 +3178,11 @@ var CEAL_REFRESH_FAILURE_CODES = vocabulary([
|
|
|
1105
3178
|
"refresh_revoked",
|
|
1106
3179
|
"authority_replaced",
|
|
1107
3180
|
"refresh_recovery_unavailable",
|
|
1108
|
-
"refresh_recovery_expired"
|
|
3181
|
+
"refresh_recovery_expired",
|
|
3182
|
+
// The serving gate answers this while the Gateway is still starting and the
|
|
3183
|
+
// refresh was never attempted; the same attempt stays retryable. It is never
|
|
3184
|
+
// stored by the session owner, only answered at the serving edge.
|
|
3185
|
+
"gateway_starting"
|
|
1109
3186
|
]);
|
|
1110
3187
|
|
|
1111
3188
|
// packages/ceal-client-protocol/src/request-validation-primitives.ts
|
|
@@ -1138,7 +3215,7 @@ var CANCELLATION_STATES = vocabulary(["requested", "cancelled"]);
|
|
|
1138
3215
|
var CEAL_REQUEST_KEYS = Object.freeze(["schema_version", "ceal_request_ref", "created_at", "authority", "prompt_ref", "host_session_ref", "host_turn_ref", "host_source_ref"]);
|
|
1139
3216
|
var CEAL_REQUEST_JSON_SCHEMA = {
|
|
1140
3217
|
type: "object",
|
|
1141
|
-
maxProperties:
|
|
3218
|
+
maxProperties: 11,
|
|
1142
3219
|
additionalProperties: false,
|
|
1143
3220
|
properties: {
|
|
1144
3221
|
schema_version: { type: "string", const: CEAL_REQUEST_SCHEMA_VERSION, maxLength: 32 },
|
|
@@ -1162,7 +3239,8 @@ var CEAL_REQUEST_JSON_SCHEMA = {
|
|
|
1162
3239
|
host_turn_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
|
|
1163
3240
|
host_input_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
|
|
1164
3241
|
host_source_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
|
|
1165
|
-
requester_timezone: { type: "string", minLength: 1, maxLength: 128, description: "IANA timezone observed for the requester on this Request." }
|
|
3242
|
+
requester_timezone: { type: "string", minLength: 1, maxLength: 128, description: "IANA timezone observed for the requester on this Request." },
|
|
3243
|
+
device_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source, description: "Device that submitted this Request through its client session; absent for Host turns and older records." }
|
|
1166
3244
|
},
|
|
1167
3245
|
required: CEAL_REQUEST_KEYS
|
|
1168
3246
|
};
|
|
@@ -1221,6 +3299,7 @@ var REQUEST_EXECUTION_PREPARE_REFUSAL_PROPERTIES = {
|
|
|
1221
3299
|
retryable: { type: "boolean" },
|
|
1222
3300
|
source: { type: "string", enum: ["provider", "gateway"] },
|
|
1223
3301
|
retry_after_ms: { type: "integer", minimum: 0, maximum: CEAL_RETRY_AFTER_MAX_MS },
|
|
3302
|
+
write_request_ref: { type: "string", pattern: CEAL_GATEWAY_WRITE_REQUEST_REF_PATTERN.source, maxLength: 128 },
|
|
1224
3303
|
excluded_targets: cealExcludedTargetCoverageJsonSchema(),
|
|
1225
3304
|
repaired_input: {},
|
|
1226
3305
|
unrepaired_pointers: { type: "array", maxItems: 128, items: { type: "string", minLength: 1, maxLength: 256 } },
|
|
@@ -1285,6 +3364,43 @@ function cealHostObservationRef(producer, digest2) {
|
|
|
1285
3364
|
if (!HOST_OBSERVATION_PRODUCER.test(producer) || !HOST_OBSERVATION_DIGEST.test(digest2)) invalid("Ceal Host observation reference parts are invalid.");
|
|
1286
3365
|
return `${CEAL_HOST_OBSERVATION_REF_PREFIX}${producer}-${digest2}`;
|
|
1287
3366
|
}
|
|
3367
|
+
var HOST_TOKEN_OBSERVATION_BREAKDOWN_KEYS = vocabulary(["cached_input", "cache_write_input", "reasoning_output"]);
|
|
3368
|
+
function createHostTokenObservationValue(counts, source) {
|
|
3369
|
+
const core = validTokenCore(counts);
|
|
3370
|
+
if (typeof source !== "string" || source.length === 0 || source.length > 256) invalid("Ceal Host token observation source is invalid.");
|
|
3371
|
+
const value = { status: "available", unit: "tokens", input: core.input, output: core.output, total: core.total, source };
|
|
3372
|
+
for (const breakdown of validTokenBreakdowns(counts)) value[breakdown.key] = breakdown.tokens;
|
|
3373
|
+
assertHostObservationValue(value, "token");
|
|
3374
|
+
return value;
|
|
3375
|
+
}
|
|
3376
|
+
function validTokenCore(counts) {
|
|
3377
|
+
if (!isOperationRecord(counts) || !safeCount(counts.input) || !safeCount(counts.output) || !safeCount(counts.total)) invalid("Ceal Host token observation counts are invalid.");
|
|
3378
|
+
if (counts.total !== counts.input + counts.output) invalid("Ceal Host token observation counts are invalid.");
|
|
3379
|
+
return { input: counts.input, output: counts.output, total: counts.total };
|
|
3380
|
+
}
|
|
3381
|
+
function validTokenBreakdowns(counts) {
|
|
3382
|
+
const breakdowns = [
|
|
3383
|
+
{ key: "cached_input", tokens: counts.cached_input },
|
|
3384
|
+
{ key: "cache_write_input", tokens: counts.cache_write_input },
|
|
3385
|
+
{ key: "reasoning_output", tokens: counts.reasoning_output }
|
|
3386
|
+
];
|
|
3387
|
+
const stated = breakdowns.filter((breakdown) => breakdown.tokens !== void 0).map((breakdown) => ({ key: breakdown.key, tokens: Number(breakdown.tokens) }));
|
|
3388
|
+
for (const breakdown of stated) {
|
|
3389
|
+
if (!safeCount(breakdown.tokens)) invalid("Ceal Host token observation counts are invalid.");
|
|
3390
|
+
}
|
|
3391
|
+
const cached = counts.cached_input ?? 0;
|
|
3392
|
+
const created = counts.cache_write_input ?? 0;
|
|
3393
|
+
const reasoning = counts.reasoning_output ?? 0;
|
|
3394
|
+
if (cached + created > counts.input || reasoning > counts.output) invalid("Ceal Host token observation counts are invalid.");
|
|
3395
|
+
return stated;
|
|
3396
|
+
}
|
|
3397
|
+
function hostObservationNotRecorded(reason) {
|
|
3398
|
+
if (typeof reason !== "string" || reason.length === 0 || reason.length > 256) invalid("Ceal Host observation gap reason is invalid.");
|
|
3399
|
+
return { status: "not_recorded", reason };
|
|
3400
|
+
}
|
|
3401
|
+
function safeCount(value) {
|
|
3402
|
+
return Number.isSafeInteger(value) && Number(value) >= 0;
|
|
3403
|
+
}
|
|
1288
3404
|
function validateCealHostObservationDraft(value) {
|
|
1289
3405
|
const record3 = operationRecord(value, "Ceal Host observation draft is invalid.");
|
|
1290
3406
|
requirePrefixedRef(record3.observation_ref, CEAL_HOST_OBSERVATION_REF_PREFIX, "Ceal Host observation reference is invalid.");
|
|
@@ -1437,6 +3553,55 @@ var CEAL_HOST_MINT_REQUEST_CONTEXT_REFUSAL_REASONS = vocabulary([
|
|
|
1437
3553
|
"host_input_mismatch",
|
|
1438
3554
|
"host_prompt_mismatch"
|
|
1439
3555
|
]);
|
|
3556
|
+
var CEAL_HOST_AUTHENTICATION_CAUSES = vocabulary([
|
|
3557
|
+
"invalid_arguments",
|
|
3558
|
+
"options_invalid",
|
|
3559
|
+
"session_unavailable",
|
|
3560
|
+
"context_unavailable",
|
|
3561
|
+
"context_replaced",
|
|
3562
|
+
"no_binding",
|
|
3563
|
+
"context_stale",
|
|
3564
|
+
"context_expired",
|
|
3565
|
+
"host_source_refused",
|
|
3566
|
+
"host_credential_refused",
|
|
3567
|
+
"gateway_unavailable",
|
|
3568
|
+
"gateway_rate_limited",
|
|
3569
|
+
"gateway_refused",
|
|
3570
|
+
"gateway_response_invalid",
|
|
3571
|
+
"producer_frame_invalid",
|
|
3572
|
+
"relay_permission_denied",
|
|
3573
|
+
"relay_unavailable",
|
|
3574
|
+
"transient_retryable",
|
|
3575
|
+
"mint_failed",
|
|
3576
|
+
"relay_failed",
|
|
3577
|
+
"host_refusal_invalid"
|
|
3578
|
+
]);
|
|
3579
|
+
var CEAL_HOST_AUTHENTICATION_POLICY = Object.freeze({
|
|
3580
|
+
invalid_arguments: Object.freeze({ classification: "host_arguments_invalid", next_action: "answer_with_gap" }),
|
|
3581
|
+
options_invalid: Object.freeze({ classification: "host_configuration_invalid", next_action: "answer_with_gap" }),
|
|
3582
|
+
session_unavailable: Object.freeze({ classification: "host_session_unavailable", next_action: "answer_with_gap" }),
|
|
3583
|
+
context_unavailable: Object.freeze({ classification: "host_context_unavailable", next_action: "refresh_host_invocation_context", remedy: "the Host has no invocation context from the current transcript turn; send a new message to start a fresh Host turn, then retry this command on that turn (run `ceal-host install` only if the Host hook registration is missing or drifted)" }),
|
|
3584
|
+
context_replaced: Object.freeze({ classification: "host_invocation_context_stale", next_action: "refresh_host_invocation_context" }),
|
|
3585
|
+
no_binding: Object.freeze({ classification: "host_binding_unavailable", next_action: "refresh_host_invocation_context" }),
|
|
3586
|
+
context_stale: Object.freeze({ classification: "host_invocation_context_stale", next_action: "refresh_host_invocation_context" }),
|
|
3587
|
+
context_expired: Object.freeze({ classification: "host_invocation_context_expired", next_action: "refresh_host_invocation_context" }),
|
|
3588
|
+
host_source_refused: Object.freeze({ classification: "host_source_refused", next_action: "answer_with_gap" }),
|
|
3589
|
+
host_credential_refused: Object.freeze({ classification: "host_registration_credential_refused", next_action: "ask_admin" }),
|
|
3590
|
+
gateway_unavailable: Object.freeze({ classification: "host_mint_gateway_unavailable", next_action: "ask_admin" }),
|
|
3591
|
+
gateway_rate_limited: Object.freeze({ classification: "host_mint_gateway_rate_limited", next_action: "answer_with_gap" }),
|
|
3592
|
+
gateway_refused: Object.freeze({ classification: "host_mint_gateway_refused", next_action: "answer_with_gap" }),
|
|
3593
|
+
gateway_response_invalid: Object.freeze({ classification: "host_mint_gateway_response_invalid", next_action: "answer_with_gap" }),
|
|
3594
|
+
producer_frame_invalid: Object.freeze({ classification: "host_producer_frame_invalid", next_action: "ask_admin", remedy: "ask an administrator to inspect and repair the producer frame, then start a fresh Host turn" }),
|
|
3595
|
+
relay_permission_denied: Object.freeze({ classification: "host_relay_permission_denied", next_action: "rerun_outside_agent_sandbox", remedy: "an agent sandbox denied the Host Relay socket; run `ceal` as the only command, with no pipe, redirect, or `&&`, so the Host allow rule runs it outside the sandbox" }),
|
|
3596
|
+
relay_unavailable: Object.freeze({ classification: "host_relay_unavailable", next_action: "answer_with_gap" }),
|
|
3597
|
+
transient_retryable: Object.freeze({ classification: "host_mint_transient_retryable", next_action: "retry" }),
|
|
3598
|
+
mint_failed: Object.freeze({ classification: "host_mint_failed", next_action: "answer_with_gap" }),
|
|
3599
|
+
relay_failed: Object.freeze({ classification: "host_relay_failed", next_action: "answer_with_gap" }),
|
|
3600
|
+
host_refusal_invalid: Object.freeze({ classification: "host_refusal_invalid", next_action: "answer_with_gap" })
|
|
3601
|
+
});
|
|
3602
|
+
function isCealHostAuthenticationCause(value) {
|
|
3603
|
+
return isVocabularyWord(CEAL_HOST_AUTHENTICATION_CAUSES, value);
|
|
3604
|
+
}
|
|
1440
3605
|
function decodeCealHostInvocationAuthenticationRequest(value) {
|
|
1441
3606
|
if (!isCealJsonRecord(value) || !exactKeys(value, ["schema_version", "client_nonce"]) || value.schema_version !== CEAL_HOST_INVOCATION_AUTHENTICATION_REQUEST_SCHEMA || typeof value.client_nonce !== "string" || !CEAL_HOST_CLIENT_NONCE_PATTERN.test(value.client_nonce)) {
|
|
1442
3607
|
throw new TypeError("The Host invocation authentication request is invalid.");
|
|
@@ -1450,19 +3615,46 @@ function decodeCealHostInvocationAuthenticationResult(value, now = /* @__PURE__
|
|
|
1450
3615
|
return Object.freeze({ schema_version: CEAL_HOST_INVOCATION_AUTHENTICATION_RESULT_SCHEMA, context_token: value.context_token, expires_at: value.expires_at });
|
|
1451
3616
|
}
|
|
1452
3617
|
function validFutureTimestamp(value, now) {
|
|
1453
|
-
const
|
|
1454
|
-
return Number.isFinite(
|
|
3618
|
+
const timestamp4 = Date.parse(value);
|
|
3619
|
+
return Number.isFinite(timestamp4) && new Date(timestamp4).toISOString() === value && timestamp4 > now.getTime();
|
|
1455
3620
|
}
|
|
1456
3621
|
function exactKeys(value, expected) {
|
|
1457
3622
|
const keys = Object.keys(value);
|
|
1458
3623
|
return keys.length === expected.length && expected.every((key) => Object.hasOwn(value, key));
|
|
1459
3624
|
}
|
|
1460
3625
|
|
|
3626
|
+
// packages/ceal-client-protocol/src/host-service-diagnostic.ts
|
|
3627
|
+
var CEAL_HOST_SERVICE_DIAGNOSTIC_SCHEMA = "ceal.host_service_diagnostic.v1";
|
|
3628
|
+
var CEAL_HOST_SERVICE_DIAGNOSTIC_PRODUCERS = vocabulary(["claude", "codex"]);
|
|
3629
|
+
var CEAL_HOST_SERVICE_DIAGNOSTIC_EVENTS = vocabulary([
|
|
3630
|
+
"hook_invoked",
|
|
3631
|
+
"registration_written",
|
|
3632
|
+
"hook_failed",
|
|
3633
|
+
"watcher_turn_observed",
|
|
3634
|
+
"current_prompt_registered",
|
|
3635
|
+
"current_prompt_registration_failed",
|
|
3636
|
+
"current_prompt_capacity_exhausted",
|
|
3637
|
+
"activation_recorded",
|
|
3638
|
+
"activation_failed",
|
|
3639
|
+
"watcher_scan_failed",
|
|
3640
|
+
"activation_wait_skipped",
|
|
3641
|
+
"activation_wait_engaged",
|
|
3642
|
+
"activation_wait_completed",
|
|
3643
|
+
"activation_wait_exhausted"
|
|
3644
|
+
]);
|
|
3645
|
+
var CEAL_HOST_SERVICE_DIAGNOSTIC_FAILURE_KINDS = vocabulary([
|
|
3646
|
+
"malformed_line",
|
|
3647
|
+
"other",
|
|
3648
|
+
"payload_rejected",
|
|
3649
|
+
"read_error",
|
|
3650
|
+
"size_budget",
|
|
3651
|
+
"symlink"
|
|
3652
|
+
]);
|
|
3653
|
+
|
|
1461
3654
|
// packages/ceal-client-protocol/src/client-result-materialization.ts
|
|
1462
3655
|
var CEAL_UNREAD_REASONS = vocabulary(["blocked", "unavailable", "too_large", "unsupported", "download_failed", "permission_denied"]);
|
|
1463
|
-
var
|
|
1464
|
-
var
|
|
1465
|
-
var FIELDS = /* @__PURE__ */ new Set([...REQUIRED_FIELDS2, "local_result_root", "continue_argv", "model_disclosure"]);
|
|
3656
|
+
var REQUIRED_FIELDS2 = Object.freeze(["schema_version", "operation_id", "path", "sha256"]);
|
|
3657
|
+
var FIELDS = /* @__PURE__ */ new Set([...REQUIRED_FIELDS2, "items_path", "row_count", "result_complete", "coverage", "local_result_root", "model_disclosure", "continue_argv", "how_to_read"]);
|
|
1466
3658
|
|
|
1467
3659
|
// packages/ceal-client-protocol/src/gateway-cache-origin-validation.ts
|
|
1468
3660
|
var CEAL_MAX_CACHE_ORIGIN_AGE_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
@@ -1492,14 +3684,6 @@ var CEAL_GATEWAY_ANNOUNCEMENT_POLICY_NON_CLAIMS = vocabulary([
|
|
|
1492
3684
|
"target_specific_scope_not_declared"
|
|
1493
3685
|
]);
|
|
1494
3686
|
|
|
1495
|
-
// packages/ceal-client-protocol/src/gateway-write-identity.ts
|
|
1496
|
-
var CEAL_GATEWAY_WRITE_IDENTITY_ROLES = Object.freeze(["replay_identity", "lookup_handle", "collision_evidence"]);
|
|
1497
|
-
var CEAL_GATEWAY_WRITE_IDENTITY_FIELDS = Object.freeze({
|
|
1498
|
-
replay_identity: "idempotency_claim_sha256",
|
|
1499
|
-
lookup_handle: "write_request_sha256",
|
|
1500
|
-
collision_evidence: "normalized_mutation_sha256"
|
|
1501
|
-
});
|
|
1502
|
-
|
|
1503
3687
|
// packages/ceal-client-protocol/src/gateway-scoped-identity-projection-validation.ts
|
|
1504
3688
|
var PROJECTION_REVISION_KEYS = Object.freeze(["graph_revision", "subject_key_revision", "projection_revision"]);
|
|
1505
3689
|
|
|
@@ -1512,6 +3696,18 @@ var CEAL_SUPPORTED_GATEWAY_PROTOCOL_RANGE = Object.freeze({
|
|
|
1512
3696
|
// packages/ceal-client-protocol/src/admin-projection-vocabulary.ts
|
|
1513
3697
|
var ADMIN_PROJECTION_STATES = vocabulary(["ready", "empty", "partial", "unknown"]);
|
|
1514
3698
|
var ADMIN_VIEW_KINDS = vocabulary(["request_detail", "resource_access_timeline", "weekly_usage"]);
|
|
3699
|
+
var ADMIN_RECORD_PROJECTION_KINDS = vocabulary([
|
|
3700
|
+
"request_list",
|
|
3701
|
+
"usage_series",
|
|
3702
|
+
"connector_health",
|
|
3703
|
+
"person_connections",
|
|
3704
|
+
"client_sessions",
|
|
3705
|
+
"knowledge_base",
|
|
3706
|
+
"change_history",
|
|
3707
|
+
"approval_queue",
|
|
3708
|
+
"access_group_list",
|
|
3709
|
+
"capability_catalogue"
|
|
3710
|
+
]);
|
|
1515
3711
|
var ADMIN_GAP_KINDS = vocabulary(["unknown", "unavailable", "partial"]);
|
|
1516
3712
|
var ADMIN_UNAVAILABLE_REASONS = vocabulary([
|
|
1517
3713
|
"not_recorded",
|
|
@@ -1535,7 +3731,11 @@ var ADMIN_SOURCE_OWNERS = vocabulary([
|
|
|
1535
3731
|
"person",
|
|
1536
3732
|
"resource",
|
|
1537
3733
|
"prompt",
|
|
1538
|
-
"usage"
|
|
3734
|
+
"usage",
|
|
3735
|
+
"connector",
|
|
3736
|
+
"session",
|
|
3737
|
+
"knowledge",
|
|
3738
|
+
"policy"
|
|
1539
3739
|
]);
|
|
1540
3740
|
var ADMIN_COMPLETENESS_STATES = vocabulary(["complete", "partial", "unknown"]);
|
|
1541
3741
|
var ADMIN_OPERATION_OUTCOMES = vocabulary(["completed", "failed", "denied", "cancelled", "unknown"]);
|
|
@@ -1813,6 +4013,9 @@ async function doctorCodexClient(options = {}) {
|
|
|
1813
4013
|
return { schema_version: CODEX_CLIENT_DOCTOR_SCHEMA_VERSION, ...await doctorClient(options, "Codex") };
|
|
1814
4014
|
}
|
|
1815
4015
|
|
|
4016
|
+
// host/invocation-authentication-command.ts
|
|
4017
|
+
import { performance } from "node:perf_hooks";
|
|
4018
|
+
|
|
1816
4019
|
// host/relay/src/producer-frame.ts
|
|
1817
4020
|
var HOST_PRODUCER_FRAME_SCHEMA = "ceal.host_producer_frame.v1";
|
|
1818
4021
|
var HOST_PRODUCER_MAX_JSON_BYTES = 262144;
|
|
@@ -1824,6 +4027,15 @@ var FRAME_KINDS = new Set(HOST_PRODUCER_FRAME_KINDS);
|
|
|
1824
4027
|
function isHostProducerFrameKind(value) {
|
|
1825
4028
|
return typeof value === "string" && FRAME_KINDS.has(value);
|
|
1826
4029
|
}
|
|
4030
|
+
var HOST_PRODUCER_FRAME_ERROR_CODES = [
|
|
4031
|
+
"invalid_frame_encoding",
|
|
4032
|
+
"invalid_frame_length",
|
|
4033
|
+
"frame_truncated",
|
|
4034
|
+
"unsupported_frame_schema",
|
|
4035
|
+
"invalid_frame_shape",
|
|
4036
|
+
"invalid_producer_identity",
|
|
4037
|
+
"frame_too_large"
|
|
4038
|
+
];
|
|
1827
4039
|
var HostProducerFrameError = class extends Error {
|
|
1828
4040
|
code;
|
|
1829
4041
|
constructor(code, message = code) {
|
|
@@ -1858,6 +4070,9 @@ function decodeHostProducerFrame(input) {
|
|
|
1858
4070
|
validateFrame(value);
|
|
1859
4071
|
return value;
|
|
1860
4072
|
}
|
|
4073
|
+
function isHostSafeRef(value) {
|
|
4074
|
+
return safeRef(value);
|
|
4075
|
+
}
|
|
1861
4076
|
function validateFrame(value) {
|
|
1862
4077
|
if (!record(value)) throw new HostProducerFrameError("invalid_frame_shape");
|
|
1863
4078
|
if (value.schema_version !== HOST_PRODUCER_FRAME_SCHEMA) throw new HostProducerFrameError("unsupported_frame_schema", `unsupported_frame_schema: ${refusalFact("schema_version", value.schema_version, HOST_PRODUCER_FRAME_SCHEMA)}`);
|
|
@@ -1945,6 +4160,15 @@ function exactOptional(value, required, optional) {
|
|
|
1945
4160
|
return required.every((key) => keys.includes(key)) && keys.every((key) => required.includes(key) || optional.includes(key));
|
|
1946
4161
|
}
|
|
1947
4162
|
|
|
4163
|
+
// host/relay/src/host-producer-core.ts
|
|
4164
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
4165
|
+
import { O_NOFOLLOW, O_RDONLY as O_RDONLY2 } from "node:constants";
|
|
4166
|
+
import { mkdir as mkdir2, open as open3, readFile as readFile2, rename as rename2, writeFile } from "node:fs/promises";
|
|
4167
|
+
import { join as join3 } from "node:path";
|
|
4168
|
+
|
|
4169
|
+
// host/relay/src/relay-ipc.ts
|
|
4170
|
+
import { createConnection, createServer } from "node:net";
|
|
4171
|
+
|
|
1948
4172
|
// host/relay/src/durable-atomic-replacement.ts
|
|
1949
4173
|
import { O_RDONLY } from "node:constants";
|
|
1950
4174
|
import { lstat, mkdir, open as open2, rename, unlink } from "node:fs/promises";
|
|
@@ -1962,20 +4186,24 @@ var DEFAULT_PORT = {
|
|
|
1962
4186
|
// host/relay/src/relay-request-binding-store.ts
|
|
1963
4187
|
var MAX_STATE_BYTES = 8 * 1024 * 1024;
|
|
1964
4188
|
|
|
1965
|
-
// host/relay/src/relay-quarantine-store.ts
|
|
1966
|
-
var RELAY_QUARANTINE_MAX_BYTES = 16 * 1024 * 1024;
|
|
1967
|
-
|
|
1968
|
-
// host/relay/src/relay-admission-store.ts
|
|
1969
|
-
var DEFAULT_LIMITS = { global_count: 8192, global_bytes: 64 * 1024 * 1024, producer_count: 4096, producer_bytes: 32 * 1024 * 1024 };
|
|
1970
|
-
var RETRY_SECONDS = [1, 2, 4, 8, 16, 32, 60];
|
|
1971
|
-
var MAX_RETRYABLE_ATTEMPTS = RETRY_SECONDS.length + 10;
|
|
1972
|
-
|
|
1973
|
-
// host/relay/src/relay-ipc.ts
|
|
1974
|
-
import { createConnection, createServer } from "node:net";
|
|
1975
|
-
|
|
1976
4189
|
// host/relay/src/current-prompt-custody.ts
|
|
1977
4190
|
var HOST_CURRENT_PROMPT_MAX_BYTES = 256 * 1024;
|
|
1978
4191
|
|
|
4192
|
+
// host/service-log.ts
|
|
4193
|
+
function writeHostServiceDiagnostic(producer_id, event, failure_kind, cause, sink) {
|
|
4194
|
+
const line = `${JSON.stringify({ schema_version: CEAL_HOST_SERVICE_DIAGNOSTIC_SCHEMA, producer_id, event, ...event === "watcher_scan_failed" && failure_kind !== void 0 ? { failure_kind } : {}, ...event === "watcher_scan_failed" && cause !== void 0 ? { cause } : {} })}
|
|
4195
|
+
`;
|
|
4196
|
+
try {
|
|
4197
|
+
(sink ?? defaultHostServiceDiagnosticSink)(line);
|
|
4198
|
+
} catch {
|
|
4199
|
+
}
|
|
4200
|
+
}
|
|
4201
|
+
function defaultHostServiceDiagnosticSink(line) {
|
|
4202
|
+
process.stderr.write(line);
|
|
4203
|
+
}
|
|
4204
|
+
var HOST_SERVICE_LOG_MAX_BYTES = 1024 * 1024;
|
|
4205
|
+
var HOST_SERVICE_LOG_TAIL_BYTES = 64 * 1024;
|
|
4206
|
+
|
|
1979
4207
|
// host/relay/src/relay-ipc.ts
|
|
1980
4208
|
var HOST_RELAY_REQUEST_BINDING_KEYS = Object.freeze([
|
|
1981
4209
|
"schema_version",
|
|
@@ -1996,6 +4224,7 @@ var HOST_RELAY_IPC_RESPONSE_SCHEMA = "ceal.host_relay_admission.v1";
|
|
|
1996
4224
|
var HOST_RELAY_INVOCATION_CONTEXT_QUERY_SCHEMA = "ceal.host_relay_invocation_context_query.v1";
|
|
1997
4225
|
var HOST_RELAY_INVOCATION_CONTEXT_RESULT_SCHEMA = "ceal.host_relay_invocation_context_result.v1";
|
|
1998
4226
|
var HOST_RELAY_CURRENT_PROMPT_REGISTER_SCHEMA = "ceal.host_relay_current_prompt_register.v1";
|
|
4227
|
+
var HOST_RELAY_CURRENT_PROMPT_RELEASE_SCHEMA = "ceal.host_relay_current_prompt_release.v1";
|
|
1999
4228
|
var HOST_RELAY_CURRENT_PROMPT_RESULT_SCHEMA = "ceal.host_relay_current_prompt_result.v1";
|
|
2000
4229
|
var HOST_RELAY_IPC_LENGTH_BYTES = Uint32Array.BYTES_PER_ELEMENT;
|
|
2001
4230
|
var HOST_RELAY_ADMISSION_RESPONSE_MAX_BYTES = 4096;
|
|
@@ -2008,6 +4237,8 @@ var HOST_RELAY_INVOCATION_MINT_REFUSAL_REASONS = vocabulary([
|
|
|
2008
4237
|
"gateway_unavailable",
|
|
2009
4238
|
"gateway_refused",
|
|
2010
4239
|
"gateway_response_invalid",
|
|
4240
|
+
"gateway_rate_limited",
|
|
4241
|
+
"producer_frame_invalid",
|
|
2011
4242
|
"deadline",
|
|
2012
4243
|
"cancelled",
|
|
2013
4244
|
"mint_failed",
|
|
@@ -2021,6 +4252,17 @@ var HOST_RELAY_INVOCATION_MINT_REFUSAL_REASONS = vocabulary([
|
|
|
2021
4252
|
"host_input_mismatch",
|
|
2022
4253
|
"host_prompt_mismatch"
|
|
2023
4254
|
]);
|
|
4255
|
+
var HOST_RELAY_DIRECT_WIRE_MINT_REASONS = vocabulary([
|
|
4256
|
+
"context_stale",
|
|
4257
|
+
"context_expired",
|
|
4258
|
+
"host_source_refused",
|
|
4259
|
+
"host_credential_refused",
|
|
4260
|
+
"gateway_unavailable",
|
|
4261
|
+
"gateway_rate_limited",
|
|
4262
|
+
"gateway_refused",
|
|
4263
|
+
"gateway_response_invalid",
|
|
4264
|
+
"producer_frame_invalid"
|
|
4265
|
+
]);
|
|
2024
4266
|
var HOST_RELAY_INVOCATION_MINT_OUTCOMES = vocabulary(["completed", "caller_cancelled", "deadline", "failed", "no_binding"]);
|
|
2025
4267
|
var HOST_RELAY_EXCHANGE_FAILURES = vocabulary([
|
|
2026
4268
|
"permission_denied",
|
|
@@ -2042,6 +4284,12 @@ var HostRelayIpcError = class extends Error {
|
|
|
2042
4284
|
this.failure = failure2;
|
|
2043
4285
|
}
|
|
2044
4286
|
};
|
|
4287
|
+
var HostRelayCurrentPromptCapacityRefusal = class extends Error {
|
|
4288
|
+
constructor() {
|
|
4289
|
+
super("current_prompt_capacity_exhausted");
|
|
4290
|
+
this.name = "HostRelayCurrentPromptCapacityRefusal";
|
|
4291
|
+
}
|
|
4292
|
+
};
|
|
2045
4293
|
function hostRelayExchangeFailure(error) {
|
|
2046
4294
|
return error instanceof HostRelayIpcError ? error.failure : void 0;
|
|
2047
4295
|
}
|
|
@@ -2090,8 +4338,14 @@ var HostRelayCurrentPromptPort = class {
|
|
|
2090
4338
|
async register(input) {
|
|
2091
4339
|
const request2 = { schema_version: HOST_RELAY_CURRENT_PROMPT_REGISTER_SCHEMA, ...input };
|
|
2092
4340
|
const response2 = await exchange(this.endpoint, encodeLengthPrefixed(request2), this.timeout_ms, decodeCurrentPromptResponseBuffer);
|
|
4341
|
+
if (response2.status === "capacity_exhausted") throw new HostRelayCurrentPromptCapacityRefusal();
|
|
2093
4342
|
if (response2.status !== "registered") throw new HostRelayIpcError("relay_unavailable", response2.status);
|
|
2094
4343
|
}
|
|
4344
|
+
async release(identity) {
|
|
4345
|
+
const request2 = { schema_version: HOST_RELAY_CURRENT_PROMPT_RELEASE_SCHEMA, ...identity };
|
|
4346
|
+
const response2 = await exchange(this.endpoint, encodeLengthPrefixed(request2), this.timeout_ms, decodeCurrentPromptResponseBuffer);
|
|
4347
|
+
if (response2.status !== "released") throw new HostRelayIpcError("relay_unavailable", response2.status, "response_invalid");
|
|
4348
|
+
}
|
|
2095
4349
|
};
|
|
2096
4350
|
function submitHostProducerFrame(endpoint, frame, timeoutMs = 5e3) {
|
|
2097
4351
|
return exchange(endpoint, encodeHostProducerFrame(frame), timeoutMs, decodeResponseBuffer);
|
|
@@ -2183,7 +4437,7 @@ function decodeInvocationContextResponseBuffer(buffer) {
|
|
|
2183
4437
|
function decodeCurrentPromptResponseBuffer(buffer) {
|
|
2184
4438
|
const value = decodeLengthPrefixedJson(buffer, HOST_RELAY_ADMISSION_RESPONSE_MAX_BYTES);
|
|
2185
4439
|
if (value === null) return null;
|
|
2186
|
-
if (!record2(value) || !exactKeys3(value, ["schema_version", "status"]) || value.schema_version !== HOST_RELAY_CURRENT_PROMPT_RESULT_SCHEMA || value.status !== "registered" && value.status !== "current_prompt_unavailable") throw new HostRelayIpcError("relay_unavailable");
|
|
4440
|
+
if (!record2(value) || !exactKeys3(value, ["schema_version", "status"]) || value.schema_version !== HOST_RELAY_CURRENT_PROMPT_RESULT_SCHEMA || value.status !== "registered" && value.status !== "capacity_exhausted" && value.status !== "current_prompt_unavailable" && value.status !== "released") throw new HostRelayIpcError("relay_unavailable", "Host Relay current-prompt response is invalid.", "response_invalid");
|
|
2187
4441
|
return { schema_version: HOST_RELAY_CURRENT_PROMPT_RESULT_SCHEMA, status: value.status };
|
|
2188
4442
|
}
|
|
2189
4443
|
function encodeInvocationContextQuery(query) {
|
|
@@ -2192,11 +4446,14 @@ function encodeInvocationContextQuery(query) {
|
|
|
2192
4446
|
return encodeLengthPrefixed(value);
|
|
2193
4447
|
}
|
|
2194
4448
|
function validInvocationContextQueryRequest(value) {
|
|
2195
|
-
return validQueryIdentity(value, HOST_RELAY_INVOCATION_CONTEXT_QUERY_SCHEMA) && exactKeys3(value, ["schema_version", "producer_id", "producer_installation_ref", "local_session_ref", "local_turn_ref", "client_nonce"]) && typeof value.client_nonce === "string" && CEAL_HOST_CLIENT_NONCE_PATTERN.test(value.client_nonce);
|
|
4449
|
+
return validQueryIdentity(value, HOST_RELAY_INVOCATION_CONTEXT_QUERY_SCHEMA) && exactKeys3(value, ["schema_version", "producer_id", "producer_installation_ref", "local_session_ref", "local_turn_ref", "client_nonce"], ["visible_output_max_bytes"]) && typeof value.client_nonce === "string" && CEAL_HOST_CLIENT_NONCE_PATTERN.test(value.client_nonce) && (value.visible_output_max_bytes === void 0 || validVisibleOutputBudget(value.visible_output_max_bytes));
|
|
2196
4450
|
}
|
|
2197
4451
|
function validQueryIdentity(value, schema) {
|
|
2198
4452
|
return record2(value) && value.schema_version === schema && (value.producer_id === "codex" || value.producer_id === "claude") && safeRef2(value.producer_installation_ref) && safeRef2(value.local_session_ref) && safeRef2(value.local_turn_ref);
|
|
2199
4453
|
}
|
|
4454
|
+
function validVisibleOutputBudget(value) {
|
|
4455
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value > 0 && value <= CEAL_CANONICAL_HTTP_MAX_RESPONSE_BYTES;
|
|
4456
|
+
}
|
|
2200
4457
|
function validInvocationContextResponse(value) {
|
|
2201
4458
|
if (!record2(value) || value.schema_version !== HOST_RELAY_INVOCATION_CONTEXT_RESULT_SCHEMA) return false;
|
|
2202
4459
|
if (value.status === "no_binding") return Object.keys(value).length === 2;
|
|
@@ -2228,8 +4485,9 @@ function encodeLengthPrefixed(value) {
|
|
|
2228
4485
|
body.copy(output, HOST_RELAY_IPC_LENGTH_BYTES);
|
|
2229
4486
|
return output;
|
|
2230
4487
|
}
|
|
2231
|
-
function exactKeys3(value,
|
|
2232
|
-
|
|
4488
|
+
function exactKeys3(value, required, optional = []) {
|
|
4489
|
+
const keys = Object.keys(value);
|
|
4490
|
+
return required.every((key) => Object.hasOwn(value, key)) && keys.every((key) => required.includes(key) || optional.includes(key));
|
|
2233
4491
|
}
|
|
2234
4492
|
function safeRef2(value) {
|
|
2235
4493
|
return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(value);
|
|
@@ -2238,24 +4496,385 @@ function errorCode2(error) {
|
|
|
2238
4496
|
return record2(error) && typeof error.code === "string" ? error.code : null;
|
|
2239
4497
|
}
|
|
2240
4498
|
|
|
4499
|
+
// host/relay/src/host-producer-core.ts
|
|
4500
|
+
var HOST_TRANSCRIPT_CURSOR_REASONS = vocabulary(["transcript_replaced", "transcript_truncated", "transcript_rewritten", "transcript_malformed"]);
|
|
4501
|
+
function isHostTranscriptCursorReason(value) {
|
|
4502
|
+
return typeof value === "string" && HOST_TRANSCRIPT_CURSOR_REASONS.some((reason) => reason === value);
|
|
4503
|
+
}
|
|
4504
|
+
var TRANSCRIPT_MISSING_REASON = "transcript_missing";
|
|
4505
|
+
var TRANSCRIPT_SCAN_READ_ERROR_ERRNOS = ["EBADF", "EACCES", "EIO", "EMFILE", "ENFILE", "ENOENT", "ENOTDIR", "EPERM"];
|
|
4506
|
+
function transcriptScanFailureKind(error, adapterFailureKind) {
|
|
4507
|
+
if (transcriptErrorCode(error) === "ELOOP") return "symlink";
|
|
4508
|
+
const adapter = adapterFailureKind(error);
|
|
4509
|
+
if (adapter !== void 0) return adapter;
|
|
4510
|
+
const code = transcriptErrorCode(error);
|
|
4511
|
+
if (code === "EFBIG") return "size_budget";
|
|
4512
|
+
if (code !== null && TRANSCRIPT_SCAN_READ_ERROR_ERRNOS.includes(code)) return "read_error";
|
|
4513
|
+
return "other";
|
|
4514
|
+
}
|
|
4515
|
+
async function registerHostCurrentPromptDiagnosed(register, diagnostic) {
|
|
4516
|
+
try {
|
|
4517
|
+
await register();
|
|
4518
|
+
diagnostic("current_prompt_registered");
|
|
4519
|
+
return true;
|
|
4520
|
+
} catch (error) {
|
|
4521
|
+
if (!(error instanceof HostRelayCurrentPromptCapacityRefusal)) diagnostic("current_prompt_registration_failed");
|
|
4522
|
+
throw error;
|
|
4523
|
+
}
|
|
4524
|
+
}
|
|
4525
|
+
function transcriptErrorCode(error) {
|
|
4526
|
+
return typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : null;
|
|
4527
|
+
}
|
|
4528
|
+
var HOST_TRANSCRIPT_READ_CHUNK_BYTES = 256 * 1024;
|
|
4529
|
+
async function readTranscriptCompleteChunk(handle, offset, size) {
|
|
4530
|
+
const available = Math.max(0, size - offset);
|
|
4531
|
+
if (available === 0) return "empty";
|
|
4532
|
+
const chunks = [];
|
|
4533
|
+
let position = offset;
|
|
4534
|
+
let total = 0;
|
|
4535
|
+
let lastNewline = -1;
|
|
4536
|
+
while (position < size) {
|
|
4537
|
+
const buffer = Buffer.alloc(Math.min(HOST_TRANSCRIPT_READ_CHUNK_BYTES, size - position));
|
|
4538
|
+
const read = await handle.read(buffer, 0, buffer.length, position);
|
|
4539
|
+
if (read.bytesRead === 0) break;
|
|
4540
|
+
const chunk = buffer.subarray(0, read.bytesRead);
|
|
4541
|
+
chunks.push(chunk);
|
|
4542
|
+
const newline = chunk.lastIndexOf(10);
|
|
4543
|
+
if (newline >= 0) lastNewline = total + newline;
|
|
4544
|
+
total += chunk.length;
|
|
4545
|
+
position += chunk.length;
|
|
4546
|
+
if (lastNewline >= 0) break;
|
|
4547
|
+
}
|
|
4548
|
+
if (lastNewline < 0) return "partial";
|
|
4549
|
+
return Buffer.concat(chunks, total).subarray(0, lastNewline + 1);
|
|
4550
|
+
}
|
|
4551
|
+
async function readTranscriptAnchor(handle, offset, anchorBytes) {
|
|
4552
|
+
const start = Math.max(0, offset - anchorBytes);
|
|
4553
|
+
const anchor = Buffer.alloc(offset - start);
|
|
4554
|
+
if (anchor.length > 0) await handle.read(anchor, 0, anchor.length, start);
|
|
4555
|
+
return { start, sha256: transcriptSha256(anchor) };
|
|
4556
|
+
}
|
|
4557
|
+
async function transcriptAnchorMatches(handle, cursor) {
|
|
4558
|
+
const buffer = Buffer.alloc(cursor.offset - cursor.anchor_start);
|
|
4559
|
+
if (buffer.length > 0) await handle.read(buffer, 0, buffer.length, cursor.anchor_start);
|
|
4560
|
+
return transcriptSha256(buffer) === cursor.anchor_sha256;
|
|
4561
|
+
}
|
|
4562
|
+
function transcriptCursorIdentityReason(cursor, transcriptPath, device, inode) {
|
|
4563
|
+
if (cursor.device !== device || cursor.inode !== inode || cursor.transcript_path !== transcriptPath) return "transcript_replaced";
|
|
4564
|
+
return null;
|
|
4565
|
+
}
|
|
4566
|
+
async function transcriptCursorBoundsReason(handle, cursor, size) {
|
|
4567
|
+
if (size < cursor.offset) return "transcript_truncated";
|
|
4568
|
+
if (cursor.offset > 0 && !await transcriptAnchorMatches(handle, cursor)) return "transcript_rewritten";
|
|
4569
|
+
return null;
|
|
4570
|
+
}
|
|
4571
|
+
function transcriptSha256(value) {
|
|
4572
|
+
return createHash3("sha256").update(value).digest("hex");
|
|
4573
|
+
}
|
|
4574
|
+
function transcriptObjectSha256(value) {
|
|
4575
|
+
return createHash3("sha256").update(JSON.stringify(value), "utf8").digest("hex");
|
|
4576
|
+
}
|
|
4577
|
+
function isTranscriptRecord(value) {
|
|
4578
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
4579
|
+
}
|
|
4580
|
+
function isMissingTranscriptError(error) {
|
|
4581
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
4582
|
+
}
|
|
4583
|
+
function transcriptTimestamp(now, fail) {
|
|
4584
|
+
const value = now();
|
|
4585
|
+
if (!Number.isFinite(value.getTime())) throw fail();
|
|
4586
|
+
return value.toISOString();
|
|
4587
|
+
}
|
|
4588
|
+
function transcriptExpiration(now, retentionMs, fail) {
|
|
4589
|
+
return new Date(Date.parse(transcriptTimestamp(now, fail)) + retentionMs).toISOString();
|
|
4590
|
+
}
|
|
4591
|
+
function createTranscriptWatcherBase(options, owner) {
|
|
4592
|
+
if (typeof options.outbox_dir !== "string" || options.outbox_dir.length === 0) throw owner.invalid_outbox();
|
|
4593
|
+
return {
|
|
4594
|
+
outboxRetentionMs: options.retention_ms ?? owner.default_retention_ms,
|
|
4595
|
+
now: options.now ?? (() => /* @__PURE__ */ new Date()),
|
|
4596
|
+
log: options.log ?? ((line) => {
|
|
4597
|
+
process.stderr.write(`${line}
|
|
4598
|
+
`);
|
|
4599
|
+
}),
|
|
4600
|
+
producerInstallationRef: options.producer_installation_ref
|
|
4601
|
+
};
|
|
4602
|
+
}
|
|
4603
|
+
async function scanTranscriptRegistrations(registrations, scanOne) {
|
|
4604
|
+
let records = 0;
|
|
4605
|
+
let enqueued = 0;
|
|
4606
|
+
let quarantined = 0;
|
|
4607
|
+
for (const registration of registrations) {
|
|
4608
|
+
const result = await scanOne(registration);
|
|
4609
|
+
records += result.records;
|
|
4610
|
+
enqueued += result.enqueued;
|
|
4611
|
+
if (result.quarantined) quarantined += 1;
|
|
4612
|
+
}
|
|
4613
|
+
return { registrations: registrations.length, records, enqueued, quarantined };
|
|
4614
|
+
}
|
|
4615
|
+
function formatRetiredTranscriptLog(producerLabel, transcriptPath) {
|
|
4616
|
+
return `${producerLabel} retired a transcript registration: transcript_path=${JSON.stringify(transcriptPath)}, reason=${TRANSCRIPT_MISSING_REASON}.`;
|
|
4617
|
+
}
|
|
4618
|
+
var HostTranscriptWatcher = class {
|
|
4619
|
+
outboxRetentionMs;
|
|
4620
|
+
now;
|
|
4621
|
+
log;
|
|
4622
|
+
producerInstallationRef;
|
|
4623
|
+
clockFailure;
|
|
4624
|
+
constructor(options, owner) {
|
|
4625
|
+
const base = createTranscriptWatcherBase(options, owner);
|
|
4626
|
+
this.outboxRetentionMs = base.outboxRetentionMs;
|
|
4627
|
+
this.now = base.now;
|
|
4628
|
+
this.log = base.log;
|
|
4629
|
+
this.producerInstallationRef = base.producerInstallationRef;
|
|
4630
|
+
this.clockFailure = owner.clock_failure;
|
|
4631
|
+
}
|
|
4632
|
+
async scanOnce() {
|
|
4633
|
+
return scanTranscriptRegistrations(await this.listRegistrations(), (registration) => this.scanRegistration(registration));
|
|
4634
|
+
}
|
|
4635
|
+
async scanRegistration(registration) {
|
|
4636
|
+
try {
|
|
4637
|
+
return await this.openTranscript(registration, (handle) => this.scanOpened(handle, registration), {
|
|
4638
|
+
missing: () => this.retireMissing(registration),
|
|
4639
|
+
failed: (handle, error) => this.scanFailed(handle, registration, error)
|
|
4640
|
+
});
|
|
4641
|
+
} catch (error) {
|
|
4642
|
+
if (error instanceof HostRelayCurrentPromptCapacityRefusal) return { records: 0, enqueued: 0, quarantined: false };
|
|
4643
|
+
throw error;
|
|
4644
|
+
}
|
|
4645
|
+
}
|
|
4646
|
+
async openTranscript(registration, scan, handlers) {
|
|
4647
|
+
let handle;
|
|
4648
|
+
try {
|
|
4649
|
+
handle = await open3(this.transcriptPathOf(registration), O_RDONLY2 | O_NOFOLLOW);
|
|
4650
|
+
return await scan(handle);
|
|
4651
|
+
} catch (error) {
|
|
4652
|
+
if (handle === void 0 && isMissingTranscriptError(error)) return handlers.missing();
|
|
4653
|
+
if (hostRelayExchangeFailure(error) !== void 0 || error instanceof HostRelayCurrentPromptCapacityRefusal) throw error;
|
|
4654
|
+
return handlers.failed(handle, error);
|
|
4655
|
+
} finally {
|
|
4656
|
+
await handle?.close();
|
|
4657
|
+
}
|
|
4658
|
+
}
|
|
4659
|
+
/**
|
|
4660
|
+
* A transcript the Host deleted never comes back, so retrying its
|
|
4661
|
+
* registration once per reconcile interval is a failure with no end.
|
|
4662
|
+
* Retire it at the scan that finds it missing and say so once. Only
|
|
4663
|
+
* ENOENT means gone; a permission or busy failure is about this moment,
|
|
4664
|
+
* not about the file, and keeps the registration for the next scan.
|
|
4665
|
+
*/
|
|
4666
|
+
async retireMissingTranscript(transcriptPath, producerLabel, retire) {
|
|
4667
|
+
await retire();
|
|
4668
|
+
this.log(formatRetiredTranscriptLog(producerLabel, transcriptPath));
|
|
4669
|
+
return { records: 0, enqueued: 0, quarantined: false };
|
|
4670
|
+
}
|
|
4671
|
+
stamp() {
|
|
4672
|
+
return transcriptTimestamp(this.now, this.clockFailure);
|
|
4673
|
+
}
|
|
4674
|
+
expire(retentionMs) {
|
|
4675
|
+
return transcriptExpiration(this.now, retentionMs, this.clockFailure);
|
|
4676
|
+
}
|
|
4677
|
+
sha(value) {
|
|
4678
|
+
return transcriptSha256(value);
|
|
4679
|
+
}
|
|
4680
|
+
objectSha(value) {
|
|
4681
|
+
return transcriptObjectSha256(value);
|
|
4682
|
+
}
|
|
4683
|
+
isRecord(value) {
|
|
4684
|
+
return isTranscriptRecord(value);
|
|
4685
|
+
}
|
|
4686
|
+
readChunk(handle, offset, size) {
|
|
4687
|
+
return readTranscriptCompleteChunk(handle, offset, size);
|
|
4688
|
+
}
|
|
4689
|
+
readAnchor(handle, offset, anchorBytes) {
|
|
4690
|
+
return readTranscriptAnchor(handle, offset, anchorBytes);
|
|
4691
|
+
}
|
|
4692
|
+
cursorIdentityReason(cursor, transcriptPath, device, inode) {
|
|
4693
|
+
return transcriptCursorIdentityReason(cursor, transcriptPath, device, inode);
|
|
4694
|
+
}
|
|
4695
|
+
cursorBoundsReason(handle, cursor, size) {
|
|
4696
|
+
return transcriptCursorBoundsReason(handle, cursor, size);
|
|
4697
|
+
}
|
|
4698
|
+
};
|
|
4699
|
+
var HOST_PRODUCER_STATE_IDENTITY = {
|
|
4700
|
+
codex: { file_name: "codex-producer-state.json", schema: "ceal.codex_producer_state.v1" },
|
|
4701
|
+
claude: { file_name: "claude-producer-state.json", schema: "ceal.claude_producer_state.v1" }
|
|
4702
|
+
};
|
|
4703
|
+
var HostProducerDrainCore = class {
|
|
4704
|
+
host;
|
|
4705
|
+
relay;
|
|
4706
|
+
statePath;
|
|
4707
|
+
stateSchema;
|
|
4708
|
+
installationRef;
|
|
4709
|
+
epoch;
|
|
4710
|
+
now;
|
|
4711
|
+
tail = Promise.resolve();
|
|
4712
|
+
constructor(host, runtime) {
|
|
4713
|
+
if (!isHostSafeRef(runtime.producer_installation_ref)) throw host.fail("configuration", `${host.producer_label} producer installation identity is invalid.`);
|
|
4714
|
+
const epoch = runtime.producer_epoch ?? 1;
|
|
4715
|
+
if (!Number.isSafeInteger(epoch) || epoch <= 0) throw host.fail("configuration", `${host.producer_label} producer epoch is invalid.`);
|
|
4716
|
+
this.host = host;
|
|
4717
|
+
this.relay = runtime.relay;
|
|
4718
|
+
this.statePath = join3(host.outbox_directory, HOST_PRODUCER_STATE_IDENTITY[host.producer_id].file_name);
|
|
4719
|
+
this.stateSchema = HOST_PRODUCER_STATE_IDENTITY[host.producer_id].schema;
|
|
4720
|
+
this.installationRef = runtime.producer_installation_ref;
|
|
4721
|
+
this.epoch = epoch;
|
|
4722
|
+
this.now = runtime.now ?? (() => /* @__PURE__ */ new Date());
|
|
4723
|
+
}
|
|
4724
|
+
drainOutbox() {
|
|
4725
|
+
const run = this.tail.then(() => this.drainLocked());
|
|
4726
|
+
this.tail = run.then(() => void 0, () => void 0);
|
|
4727
|
+
return run;
|
|
4728
|
+
}
|
|
4729
|
+
async drainLocked() {
|
|
4730
|
+
const read = await this.host.listEnvelopes();
|
|
4731
|
+
let admitted = 0;
|
|
4732
|
+
let expired = 0;
|
|
4733
|
+
let retained = 0;
|
|
4734
|
+
for (const envelope of read.entries) {
|
|
4735
|
+
const reserved = await this.hasReservation(this.host.submissionRefOf(envelope));
|
|
4736
|
+
if (!reserved && Date.parse(this.host.expiresAtOf(envelope)) <= this.now().getTime()) {
|
|
4737
|
+
await this.host.removeEnvelope(envelope);
|
|
4738
|
+
expired += 1;
|
|
4739
|
+
continue;
|
|
4740
|
+
}
|
|
4741
|
+
const frames = await this.reserve(envelope);
|
|
4742
|
+
let complete = true;
|
|
4743
|
+
for (const frame of frames) {
|
|
4744
|
+
const outcome = await this.relay.admit(frame);
|
|
4745
|
+
if (outcome.code !== "admitted" && outcome.code !== "already_admitted") {
|
|
4746
|
+
complete = false;
|
|
4747
|
+
break;
|
|
4748
|
+
}
|
|
4749
|
+
}
|
|
4750
|
+
if (!complete) {
|
|
4751
|
+
retained += 1;
|
|
4752
|
+
break;
|
|
4753
|
+
}
|
|
4754
|
+
await this.host.removeEnvelope(envelope);
|
|
4755
|
+
await this.release(this.host.submissionRefOf(envelope));
|
|
4756
|
+
admitted += 1;
|
|
4757
|
+
}
|
|
4758
|
+
return { admitted, retained: retained + Math.max(0, read.entries.length - admitted - expired - retained), expired, malformed: read.malformed };
|
|
4759
|
+
}
|
|
4760
|
+
async hasReservation(submissionRef) {
|
|
4761
|
+
return (await this.readState()).pending[submissionRef] !== void 0;
|
|
4762
|
+
}
|
|
4763
|
+
async reserve(envelope) {
|
|
4764
|
+
const state = await this.readState();
|
|
4765
|
+
const submissionRef = this.host.submissionRefOf(envelope);
|
|
4766
|
+
const existing = state.pending[submissionRef];
|
|
4767
|
+
if (existing !== void 0) return existing;
|
|
4768
|
+
const drafts = await this.host.mapEnvelope(envelope);
|
|
4769
|
+
const frames = drafts.map((draft, offset) => ({
|
|
4770
|
+
schema_version: "ceal.host_producer_frame.v1",
|
|
4771
|
+
producer_id: this.host.producer_id,
|
|
4772
|
+
producer_installation_ref: this.installationRef,
|
|
4773
|
+
producer_epoch: this.epoch,
|
|
4774
|
+
sequence: state.next_sequence + offset,
|
|
4775
|
+
frame_kind: draft.frame_kind,
|
|
4776
|
+
occurred_at: this.host.createdAtOf(envelope),
|
|
4777
|
+
payload: draft.payload
|
|
4778
|
+
}));
|
|
4779
|
+
await this.writeState({ ...state, next_sequence: state.next_sequence + frames.length, pending: { ...state.pending, [submissionRef]: frames } });
|
|
4780
|
+
return frames;
|
|
4781
|
+
}
|
|
4782
|
+
async release(submissionRef) {
|
|
4783
|
+
const state = await this.readState();
|
|
4784
|
+
if (state.pending[submissionRef] === void 0) return;
|
|
4785
|
+
const pending = { ...state.pending };
|
|
4786
|
+
delete pending[submissionRef];
|
|
4787
|
+
await this.writeState({ ...state, pending });
|
|
4788
|
+
}
|
|
4789
|
+
async readState() {
|
|
4790
|
+
try {
|
|
4791
|
+
const value = JSON.parse(await readFile2(this.statePath, "utf8"));
|
|
4792
|
+
return this.decodeState(value);
|
|
4793
|
+
} catch (error) {
|
|
4794
|
+
if (errorCode3(error) !== "ENOENT") throw error;
|
|
4795
|
+
return { schema_version: this.stateSchema, producer_installation_ref: this.installationRef, producer_epoch: this.epoch, next_sequence: 1, pending: {} };
|
|
4796
|
+
}
|
|
4797
|
+
}
|
|
4798
|
+
async writeState(state) {
|
|
4799
|
+
await mkdir2(this.host.outbox_directory, { recursive: true, mode: 448 });
|
|
4800
|
+
const temporary = `${this.statePath}.${process.pid}.new`;
|
|
4801
|
+
await writeFile(temporary, JSON.stringify(state), { mode: 384 });
|
|
4802
|
+
await rename2(temporary, this.statePath);
|
|
4803
|
+
}
|
|
4804
|
+
decodeState(value) {
|
|
4805
|
+
const label = this.host.producer_label;
|
|
4806
|
+
const fail = (code, message) => this.host.fail(code, message);
|
|
4807
|
+
if (!isDrainStateHeader(value, this.stateSchema, this.installationRef)) {
|
|
4808
|
+
throw fail("storage", `${label} producer state header is malformed or belongs to another installation (${refusalFacts([
|
|
4809
|
+
{ name: "schema_version", value: isTranscriptRecord(value) ? value.schema_version : void 0, expected: this.stateSchema },
|
|
4810
|
+
{ name: "producer_installation_ref", value: isTranscriptRecord(value) ? value.producer_installation_ref : void 0, expected: this.installationRef }
|
|
4811
|
+
])}).`);
|
|
4812
|
+
}
|
|
4813
|
+
if (Number(value.producer_epoch) > this.epoch) throw fail("storage", `${label} producer state epoch is ahead of this installation (${refusalFact("producer_epoch", value.producer_epoch, `at most ${this.epoch}`)}).`);
|
|
4814
|
+
const pending = {};
|
|
4815
|
+
const storedEpoch = Number(value.producer_epoch);
|
|
4816
|
+
for (const [submissionRef, frames] of Object.entries(value.pending)) {
|
|
4817
|
+
if (!isHostSafeRef(submissionRef) || !Array.isArray(frames) || frames.length === 0) throw fail("storage", `${label} producer pending reservation is malformed.`);
|
|
4818
|
+
pending[submissionRef] = frames.map((frame) => this.decodeStoredFrame(frame, storedEpoch));
|
|
4819
|
+
}
|
|
4820
|
+
return { schema_version: this.stateSchema, producer_installation_ref: this.installationRef, producer_epoch: this.epoch, next_sequence: Number(value.next_sequence), pending };
|
|
4821
|
+
}
|
|
4822
|
+
decodeStoredFrame(value, storedEpoch) {
|
|
4823
|
+
const label = this.host.producer_label;
|
|
4824
|
+
const json = Buffer.from(JSON.stringify(value), "utf8");
|
|
4825
|
+
const encoded = Buffer.allocUnsafe(json.length + 4);
|
|
4826
|
+
encoded.writeUInt32BE(json.length, 0);
|
|
4827
|
+
json.copy(encoded, 4);
|
|
4828
|
+
const frame = decodeHostProducerFrame(encoded);
|
|
4829
|
+
if (frame.producer_id !== this.host.producer_id || frame.producer_installation_ref !== this.installationRef || frame.producer_epoch > storedEpoch) throw this.host.fail("storage", `${label} producer pending frame identity is malformed (${refusalFacts([
|
|
4830
|
+
{ name: "producer_id", value: frame.producer_id, expected: this.host.producer_id },
|
|
4831
|
+
{ name: "producer_installation_ref", value: frame.producer_installation_ref, expected: this.installationRef },
|
|
4832
|
+
{ name: "producer_epoch", value: frame.producer_epoch, expected: `at most ${storedEpoch}` }
|
|
4833
|
+
])}).`);
|
|
4834
|
+
return frame;
|
|
4835
|
+
}
|
|
4836
|
+
};
|
|
4837
|
+
function isDrainStateHeader(value, schema, installationRef) {
|
|
4838
|
+
return isTranscriptRecord(value) && value.schema_version === schema && value.producer_installation_ref === installationRef && Number.isSafeInteger(value.producer_epoch) && Number(value.producer_epoch) > 0 && Number.isSafeInteger(value.next_sequence) && Number(value.next_sequence) > 0 && isTranscriptRecord(value.pending);
|
|
4839
|
+
}
|
|
4840
|
+
function errorCode3(error) {
|
|
4841
|
+
return typeof error === "object" && error !== null && "code" in error ? String(error.code) : null;
|
|
4842
|
+
}
|
|
4843
|
+
|
|
4844
|
+
// host/relay/src/relay-quarantine-store.ts
|
|
4845
|
+
var RELAY_QUARANTINE_MAX_BYTES = 16 * 1024 * 1024;
|
|
4846
|
+
var RELAY_QUARANTINE_FRAME_REASONS = ["frame_identity_conflict", "sequence_gap", "gateway_refused"];
|
|
4847
|
+
var RELAY_QUARANTINE_REASONS = [...RELAY_QUARANTINE_FRAME_REASONS, ...HOST_PRODUCER_FRAME_ERROR_CODES];
|
|
4848
|
+
|
|
4849
|
+
// host/relay/src/relay-admission-store.ts
|
|
4850
|
+
var DEFAULT_LIMITS = { global_count: 8192, global_bytes: 64 * 1024 * 1024, producer_count: 4096, producer_bytes: 32 * 1024 * 1024 };
|
|
4851
|
+
var RETRY_SECONDS = [1, 2, 4, 8, 16, 32, 60];
|
|
4852
|
+
var MAX_RETRYABLE_ATTEMPTS = RETRY_SECONDS.length + 10;
|
|
4853
|
+
|
|
2241
4854
|
// host/invocation-authentication-command.ts
|
|
2242
4855
|
var HOST_INVOCATION_AUTHENTICATION_COMMAND_PREFIX = ["authenticate", "--client-nonce"];
|
|
2243
|
-
var
|
|
2244
|
-
|
|
4856
|
+
var HOST_AUTHENTICATION_BUDGET_ENVIRONMENT = "CEAL_HOST_AUTHENTICATION_BUDGET_MS";
|
|
4857
|
+
var HOST_CONTEXT_ACTIVATION_WAIT_MAX_MS = 2e4;
|
|
4858
|
+
var CODEX_CONTEXT_ACTIVATION_WAIT_MAX_MS = HOST_CONTEXT_ACTIVATION_WAIT_MAX_MS;
|
|
4859
|
+
var HOST_AUTHENTICATION_COMPLETION_RESERVE_MS = 5e3;
|
|
4860
|
+
var INVOCATION_CONTEXT_POLL_INTERVAL_MS = 250;
|
|
4861
|
+
var REFUSAL_REASON_PATTERN = /^[a-z][a-z0-9_]{0,63}$/u;
|
|
4862
|
+
function installedHostInvocationAuthenticationCommandOptions(config, contextBudgetMs, maxContextWaitMs) {
|
|
2245
4863
|
const port = new HostRelayInvocationContextPort(config.relay_endpoint);
|
|
2246
4864
|
return {
|
|
2247
4865
|
host_source_ref: config.host_source_ref,
|
|
2248
4866
|
outbox_dir: config.outbox_dir,
|
|
2249
4867
|
producer_installation_ref: config.producer_installation_ref,
|
|
4868
|
+
context_activation_wait_ms: boundedContextActivationWait(contextBudgetMs, config.ipc_timeout_ms, maxContextWaitMs),
|
|
2250
4869
|
mint_invocation_context: (input) => port.mintInvocationContext({ ...input, producer_id: input.producer_id })
|
|
2251
4870
|
};
|
|
2252
4871
|
}
|
|
2253
|
-
async function runHostInvocationAuthenticationCommand(
|
|
4872
|
+
async function runHostInvocationAuthenticationCommand(descriptor2, args, options) {
|
|
2254
4873
|
let sink = options?.output_sink;
|
|
2255
4874
|
try {
|
|
2256
|
-
const resolved = await resolveOptions(
|
|
4875
|
+
const resolved = await resolveOptions(descriptor2, args, options);
|
|
2257
4876
|
sink = resolved.options.output_sink;
|
|
2258
|
-
writeResult(await authenticateHostInvocation(
|
|
4877
|
+
writeResult(await authenticateHostInvocation(descriptor2, resolved.input, resolved.options), sink);
|
|
2259
4878
|
return 0;
|
|
2260
4879
|
} catch (error) {
|
|
2261
4880
|
writeResult({ ok: false, code: "invocation_authentication_unavailable", reason: authenticationRefusalReason(error) }, sink);
|
|
@@ -2264,65 +4883,150 @@ async function runHostInvocationAuthenticationCommand(descriptor, args, options)
|
|
|
2264
4883
|
}
|
|
2265
4884
|
function authenticationRefusalReason(error) {
|
|
2266
4885
|
const message = error instanceof Error ? error.message : "";
|
|
2267
|
-
|
|
4886
|
+
if (!REFUSAL_REASON_PATTERN.test(message)) return "host_refusal_invalid";
|
|
4887
|
+
return isCealHostAuthenticationCause(message) ? message : "host_refusal_invalid";
|
|
2268
4888
|
}
|
|
2269
|
-
async function authenticateHostInvocation(
|
|
2270
|
-
if (input.length !== HOST_INVOCATION_AUTHENTICATION_COMMAND_PREFIX.length + 1 || input[0] !== HOST_INVOCATION_AUTHENTICATION_COMMAND_PREFIX[0] || input[1] !== HOST_INVOCATION_AUTHENTICATION_COMMAND_PREFIX[1]) throw new TypeError("
|
|
4889
|
+
async function authenticateHostInvocation(descriptor2, input, options) {
|
|
4890
|
+
if (input.length !== HOST_INVOCATION_AUTHENTICATION_COMMAND_PREFIX.length + 1 || input[0] !== HOST_INVOCATION_AUTHENTICATION_COMMAND_PREFIX[0] || input[1] !== HOST_INVOCATION_AUTHENTICATION_COMMAND_PREFIX[1]) throw new TypeError("invalid_arguments");
|
|
2271
4891
|
const request2 = decodeCealHostInvocationAuthenticationRequest({ schema_version: CEAL_HOST_INVOCATION_AUTHENTICATION_REQUEST_SCHEMA, client_nonce: input[2] });
|
|
2272
4892
|
const config = validateOptions(options);
|
|
2273
|
-
const now =
|
|
2274
|
-
const { store, current } = await currentInvocation(
|
|
2275
|
-
if (config.mint_invocation_context === void 0) throw new TypeError("
|
|
4893
|
+
const now = config.now ?? (() => /* @__PURE__ */ new Date());
|
|
4894
|
+
const { store, current } = await currentInvocation(descriptor2, config, now);
|
|
4895
|
+
if (config.mint_invocation_context === void 0) throw new TypeError("relay_failed");
|
|
2276
4896
|
const query = {
|
|
2277
|
-
producer_id:
|
|
4897
|
+
producer_id: descriptor2.producer_id,
|
|
2278
4898
|
producer_installation_ref: config.producer_installation_ref,
|
|
2279
4899
|
local_session_ref: current.identity.host_session_ref,
|
|
2280
4900
|
local_turn_ref: current.identity.host_turn_ref,
|
|
2281
|
-
client_nonce: request2.client_nonce
|
|
4901
|
+
client_nonce: request2.client_nonce,
|
|
4902
|
+
...await visibleOutputBudget(descriptor2)
|
|
2282
4903
|
};
|
|
2283
4904
|
const response2 = await mintedResult(config.mint_invocation_context, query);
|
|
2284
|
-
const
|
|
2285
|
-
|
|
2286
|
-
|
|
4905
|
+
const completedAt = now();
|
|
4906
|
+
const rechecked = await store.readInvocationContext(current.identity.host_source_ref, current.identity.host_session_ref, completedAt);
|
|
4907
|
+
if (rechecked === null || !sameTurn(current, rechecked)) throw new TypeError("context_replaced");
|
|
4908
|
+
return decodeCealHostInvocationAuthenticationResult(response2.result, completedAt);
|
|
4909
|
+
}
|
|
4910
|
+
async function visibleOutputBudget(descriptor2) {
|
|
4911
|
+
const bytes = await descriptor2.resolve_visible_output_max_bytes?.();
|
|
4912
|
+
return bytes === void 0 ? {} : { visible_output_max_bytes: bytes };
|
|
2287
4913
|
}
|
|
2288
4914
|
async function mintedResult(mint, query) {
|
|
2289
4915
|
let response2;
|
|
2290
4916
|
try {
|
|
2291
4917
|
response2 = await mint(query);
|
|
2292
4918
|
} catch (error) {
|
|
2293
|
-
throw new TypeError(
|
|
4919
|
+
throw new TypeError(exchangeFailureCause(hostRelayExchangeFailure(error) ?? "unavailable"));
|
|
2294
4920
|
}
|
|
2295
|
-
if (response2.status === "refused") throw new TypeError(
|
|
2296
|
-
if (response2.status !== "ready") throw new TypeError(
|
|
4921
|
+
if (response2.status === "refused") throw new TypeError(mintRefusalCause(response2.reason));
|
|
4922
|
+
if (response2.status !== "ready") throw new TypeError("no_binding");
|
|
2297
4923
|
return response2;
|
|
2298
4924
|
}
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
4925
|
+
function mintRefusalCause(reason) {
|
|
4926
|
+
if (isDirectMintRefusalCause(reason)) return reason;
|
|
4927
|
+
if (reason === "deadline" || reason === "cancelled") return "transient_retryable";
|
|
4928
|
+
if (reason === "mint_failed" || reason === "relay_failed") return reason;
|
|
4929
|
+
return isVocabularyWord(CEAL_HOST_MINT_REQUEST_CONTEXT_REFUSAL_REASONS, reason) ? "context_stale" : "host_refusal_invalid";
|
|
4930
|
+
}
|
|
4931
|
+
function isDirectMintRefusalCause(reason) {
|
|
4932
|
+
return isVocabularyWord(HOST_RELAY_DIRECT_WIRE_MINT_REASONS, reason);
|
|
4933
|
+
}
|
|
4934
|
+
function exchangeFailureCause(failure2) {
|
|
4935
|
+
if (failure2 === "permission_denied") return "relay_permission_denied";
|
|
4936
|
+
if (failure2 === "timed_out") return "transient_retryable";
|
|
4937
|
+
return "relay_unavailable";
|
|
4938
|
+
}
|
|
4939
|
+
async function currentInvocation(descriptor2, config, now) {
|
|
4940
|
+
const store = descriptor2.create_store(config.outbox_dir);
|
|
4941
|
+
const identity = resolveIdentity(descriptor2, config);
|
|
2302
4942
|
if (identity.status !== "ready") throw new TypeError(identity.status);
|
|
2303
|
-
const
|
|
2304
|
-
|
|
2305
|
-
|
|
4943
|
+
const waitBudgetMs = config.context_activation_wait_ms ?? 0;
|
|
4944
|
+
const monotonicNow = config.monotonic_now ?? (() => performance.now());
|
|
4945
|
+
const deadline = monotonicNow() + waitBudgetMs;
|
|
4946
|
+
let firstCheck = true;
|
|
4947
|
+
let waitEngaged = false;
|
|
4948
|
+
while (true) {
|
|
4949
|
+
if (!firstCheck && monotonicNow() >= deadline) {
|
|
4950
|
+
recordActivationWaitExhaustion(descriptor2.producer_id, waitEngaged, waitBudgetMs, config.diagnostic_sink);
|
|
4951
|
+
throw new TypeError("context_unavailable");
|
|
4952
|
+
}
|
|
4953
|
+
firstCheck = false;
|
|
4954
|
+
const observedAt = now();
|
|
4955
|
+
const current = await readLiveSessionContext(store, identity.identity.host_source_ref, identity.identity.host_session_ref, observedAt);
|
|
4956
|
+
if (current !== null) {
|
|
4957
|
+
recordActivationWaitCompletion(descriptor2.producer_id, waitEngaged, config.diagnostic_sink);
|
|
4958
|
+
return { store, current };
|
|
4959
|
+
}
|
|
4960
|
+
const remainingMs = deadline - monotonicNow();
|
|
4961
|
+
if (remainingMs <= 0) {
|
|
4962
|
+
recordActivationWaitExhaustion(descriptor2.producer_id, waitEngaged, waitBudgetMs, config.diagnostic_sink);
|
|
4963
|
+
throw new TypeError("context_unavailable");
|
|
4964
|
+
}
|
|
4965
|
+
recordActivationWaitEngagement(descriptor2.producer_id, waitEngaged, config.diagnostic_sink);
|
|
4966
|
+
waitEngaged = true;
|
|
4967
|
+
const intervalMs = Math.min(INVOCATION_CONTEXT_POLL_INTERVAL_MS, remainingMs);
|
|
4968
|
+
await (config.wait ?? waitForContextActivation)(intervalMs);
|
|
4969
|
+
}
|
|
4970
|
+
}
|
|
4971
|
+
function recordActivationWaitExhaustion(producer, engaged, budgetMs, sink) {
|
|
4972
|
+
if (engaged || budgetMs > 0) writeHostServiceDiagnostic(producer, "activation_wait_exhausted", void 0, void 0, sink);
|
|
4973
|
+
else writeHostServiceDiagnostic(producer, "activation_wait_skipped", void 0, void 0, sink);
|
|
4974
|
+
}
|
|
4975
|
+
function recordActivationWaitCompletion(producer, engaged, sink) {
|
|
4976
|
+
if (engaged) writeHostServiceDiagnostic(producer, "activation_wait_completed", void 0, void 0, sink);
|
|
4977
|
+
}
|
|
4978
|
+
function recordActivationWaitEngagement(producer, engaged, sink) {
|
|
4979
|
+
if (!engaged) writeHostServiceDiagnostic(producer, "activation_wait_engaged", void 0, void 0, sink);
|
|
4980
|
+
}
|
|
4981
|
+
async function readLiveSessionContext(store, hostSourceRef, hostSessionRef, now) {
|
|
4982
|
+
const current = await store.readInvocationContext(hostSourceRef, hostSessionRef, now);
|
|
4983
|
+
if (current !== null) {
|
|
4984
|
+
if (Date.parse(current.expires_at) <= now.getTime()) throw new TypeError("context_expired");
|
|
4985
|
+
return current;
|
|
4986
|
+
}
|
|
4987
|
+
const raw = await store.readRawInvocationContext?.(hostSourceRef, hostSessionRef);
|
|
4988
|
+
if (raw !== null && raw !== void 0 && Date.parse(raw.expires_at) <= now.getTime()) throw new TypeError("context_expired");
|
|
4989
|
+
return null;
|
|
2306
4990
|
}
|
|
2307
|
-
function resolveIdentity(
|
|
2308
|
-
const sessionId = options.session_id === null ? void 0 : options.session_id ?? process.env[
|
|
2309
|
-
if (isHostSessionId(sessionId)) return { status: "ready", identity: { host_source_ref: options.host_source_ref, host_session_ref:
|
|
2310
|
-
return { status: "
|
|
4991
|
+
function resolveIdentity(descriptor2, options) {
|
|
4992
|
+
const sessionId = options.session_id === null ? void 0 : options.session_id ?? process.env[descriptor2.session_id_env];
|
|
4993
|
+
if (isHostSessionId(sessionId)) return { status: "ready", identity: { host_source_ref: options.host_source_ref, host_session_ref: descriptor2.session_ref(options.host_source_ref, sessionId) } };
|
|
4994
|
+
return { status: "session_unavailable" };
|
|
2311
4995
|
}
|
|
2312
|
-
async function resolveOptions(
|
|
4996
|
+
async function resolveOptions(descriptor2, args, options) {
|
|
2313
4997
|
if (options !== void 0) return { input: [...args], options };
|
|
2314
|
-
const configPath =
|
|
4998
|
+
const configPath = descriptor2.parse_config_flag(args);
|
|
4999
|
+
const config = await descriptor2.read_producer_config(configPath);
|
|
2315
5000
|
return {
|
|
2316
|
-
input: args.filter((argument) => !argument.startsWith(`${
|
|
2317
|
-
options: installedHostInvocationAuthenticationCommandOptions(
|
|
5001
|
+
input: args.filter((argument) => !argument.startsWith(`${descriptor2.config_flag}=`)),
|
|
5002
|
+
options: installedHostInvocationAuthenticationCommandOptions(config, authenticationBudgetMsFromEnvironment(), descriptor2.context_activation_wait_max_ms)
|
|
2318
5003
|
};
|
|
2319
5004
|
}
|
|
5005
|
+
function authenticationBudgetMsFromEnvironment() {
|
|
5006
|
+
const value = process.env[HOST_AUTHENTICATION_BUDGET_ENVIRONMENT];
|
|
5007
|
+
if (value === void 0) return 0;
|
|
5008
|
+
if (!/^(?:0|[1-9][0-9]{0,8})$/u.test(value)) throw new TypeError("invalid_arguments");
|
|
5009
|
+
return Number(value);
|
|
5010
|
+
}
|
|
5011
|
+
function boundedContextActivationWait(contextBudgetMs, relayTimeoutMs, maxContextWaitMs) {
|
|
5012
|
+
if (maxContextWaitMs === void 0 || contextBudgetMs <= 0) return 0;
|
|
5013
|
+
const availableWaitMs = contextBudgetMs - relayTimeoutMs - HOST_AUTHENTICATION_COMPLETION_RESERVE_MS;
|
|
5014
|
+
return Math.max(0, Math.min(maxContextWaitMs, availableWaitMs));
|
|
5015
|
+
}
|
|
5016
|
+
function waitForContextActivation(milliseconds) {
|
|
5017
|
+
return new Promise((resolve) => {
|
|
5018
|
+
setTimeout(resolve, milliseconds);
|
|
5019
|
+
});
|
|
5020
|
+
}
|
|
2320
5021
|
function validateOptions(options) {
|
|
2321
|
-
if (typeof options.outbox_dir !== "string" || options.outbox_dir.length === 0 || typeof options.host_source_ref !== "string" || !SAFE_REF.test(options.host_source_ref) || typeof options.producer_installation_ref !== "string" || !SAFE_REF.test(options.producer_installation_ref) || !validOptionalSession(options.session_id)) {
|
|
2322
|
-
throw new TypeError("
|
|
5022
|
+
if (typeof options.outbox_dir !== "string" || options.outbox_dir.length === 0 || typeof options.host_source_ref !== "string" || !SAFE_REF.test(options.host_source_ref) || typeof options.producer_installation_ref !== "string" || !SAFE_REF.test(options.producer_installation_ref) || !validContextActivationWait(options.context_activation_wait_ms) || !validOptionalSession(options.session_id)) {
|
|
5023
|
+
throw new TypeError("options_invalid");
|
|
2323
5024
|
}
|
|
2324
5025
|
return options;
|
|
2325
5026
|
}
|
|
5027
|
+
function validContextActivationWait(value) {
|
|
5028
|
+
return value === void 0 || Number.isSafeInteger(value) && value >= 0 && value <= HOST_CONTEXT_ACTIVATION_WAIT_MAX_MS;
|
|
5029
|
+
}
|
|
2326
5030
|
function isHostSessionId(value) {
|
|
2327
5031
|
return typeof value === "string" && value.length > 0 && value.length <= 256 && !value.includes("\0");
|
|
2328
5032
|
}
|
|
@@ -2341,7 +5045,7 @@ function writeResult(value, sink) {
|
|
|
2341
5045
|
import { posix as posix3, win32 as win323 } from "node:path";
|
|
2342
5046
|
|
|
2343
5047
|
// host/runtime-source-paths.ts
|
|
2344
|
-
import { createHash as
|
|
5048
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
2345
5049
|
import { posix as posix2, win32 as win322 } from "node:path";
|
|
2346
5050
|
|
|
2347
5051
|
// host/absolute-path.ts
|
|
@@ -2363,7 +5067,7 @@ function hostRuntimeSourcePaths(stateRoot, sourceRef, platform = process.platfor
|
|
|
2363
5067
|
const sourcesRoot = path.join(stateRoot, "sources");
|
|
2364
5068
|
const sourceRoot = path.join(sourcesRoot, sourceId);
|
|
2365
5069
|
const runtimeRoot = path.join(stateRoot, "run");
|
|
2366
|
-
const endpoint = platform === "win32" ? `\\\\.\\pipe\\ceal-host-${
|
|
5070
|
+
const endpoint = platform === "win32" ? `\\\\.\\pipe\\ceal-host-${createHash4("sha256").update(`${stateRoot}\0${sourceRef}`).digest("hex").slice(0, 24)}` : path.join(runtimeRoot, `${sourceId}.sock`);
|
|
2367
5071
|
assertHostRuntimeIpcLength(endpoint, platform);
|
|
2368
5072
|
return { sourceId, sourcesRoot, sourceRoot, relayRoot: path.join(sourceRoot, "relay"), codexOutbox: path.join(sourceRoot, "producers", "codex", "outbox"), claudeOutbox: path.join(sourceRoot, "producers", "claude", "outbox"), endpoint, runtimeRoot };
|
|
2369
5073
|
}
|
|
@@ -2379,7 +5083,7 @@ function assertHostProducerSourcePaths(stateRoot, config, producer, platform = p
|
|
|
2379
5083
|
|
|
2380
5084
|
// host/producer-service.ts
|
|
2381
5085
|
import { constants } from "node:fs";
|
|
2382
|
-
import { lstat as lstat2, open as
|
|
5086
|
+
import { lstat as lstat2, open as open4 } from "node:fs/promises";
|
|
2383
5087
|
var SAFE_REF4 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
|
|
2384
5088
|
var HOST_PRODUCER_CONFIG_FLAG = "--ceal-host-config";
|
|
2385
5089
|
var HostProducerServiceError = class extends Error {
|
|
@@ -2400,22 +5104,22 @@ function hostProducerExtraPath(extras, key) {
|
|
|
2400
5104
|
function parseHostProducerConfigFlag(args, platform = process.platform) {
|
|
2401
5105
|
return parseProducerHostConfigFlag(args, HOST_PRODUCER_CONFIG_FLAG, platform, hostProducerError);
|
|
2402
5106
|
}
|
|
2403
|
-
async function readHostProducerConfig(
|
|
2404
|
-
const config = decodeHostProducerConfigText(
|
|
5107
|
+
async function readHostProducerConfig(descriptor2, configPath, platform = process.platform) {
|
|
5108
|
+
const config = decodeHostProducerConfigText(descriptor2, await readProducerConfigText(configPath, platform, hostProducerError), platform);
|
|
2405
5109
|
const path = platform === "win32" ? win323 : posix3;
|
|
2406
5110
|
const root = path.resolve(config.outbox_dir, "../../../../..");
|
|
2407
5111
|
try {
|
|
2408
|
-
assertHostProducerSourcePaths(root, config,
|
|
5112
|
+
assertHostProducerSourcePaths(root, config, descriptor2.producer_id, platform);
|
|
2409
5113
|
} catch (error) {
|
|
2410
5114
|
throw hostProducerError("invalid_config", error instanceof Error ? error.message : "Host producer source tuple is invalid.");
|
|
2411
5115
|
}
|
|
2412
5116
|
return config;
|
|
2413
5117
|
}
|
|
2414
|
-
function decodeHostProducerConfigText(
|
|
2415
|
-
const extraPaths =
|
|
2416
|
-
const decoded = decodeProducerConfigCore(text, { schema:
|
|
5118
|
+
function decodeHostProducerConfigText(descriptor2, text, platform = process.platform) {
|
|
5119
|
+
const extraPaths = descriptor2.extra_paths ?? [];
|
|
5120
|
+
const decoded = decodeProducerConfigCore(text, { schema: descriptor2.schema, keys: [...HOST_PRODUCER_CONFIG_KEYS, ...extraPaths], platform, extraPaths, error: hostProducerError });
|
|
2417
5121
|
const { extra_paths: extras, ...core } = decoded;
|
|
2418
|
-
return Object.freeze(
|
|
5122
|
+
return Object.freeze(descriptor2.config({ schema_version: descriptor2.schema, ...core }, extras));
|
|
2419
5123
|
}
|
|
2420
5124
|
function hostProducerError(code, message = code) {
|
|
2421
5125
|
return new HostProducerServiceError(code, message);
|
|
@@ -2490,7 +5194,7 @@ function validateConfigFile(value, platform, error) {
|
|
|
2490
5194
|
}
|
|
2491
5195
|
async function openConfigFile(configPath, flags, error) {
|
|
2492
5196
|
try {
|
|
2493
|
-
return await
|
|
5197
|
+
return await open4(configPath, flags);
|
|
2494
5198
|
} catch {
|
|
2495
5199
|
throw error("config_unavailable");
|
|
2496
5200
|
}
|
|
@@ -2551,7 +5255,7 @@ function boundedMilliseconds(value) {
|
|
|
2551
5255
|
}
|
|
2552
5256
|
|
|
2553
5257
|
// host/codex/src/codex-decoder.ts
|
|
2554
|
-
import { createHash as
|
|
5258
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
2555
5259
|
|
|
2556
5260
|
// host/codex/src/codex-types.ts
|
|
2557
5261
|
var CODEX_THREAD_ID_ENVIRONMENT = "CODEX_THREAD_ID";
|
|
@@ -2562,10 +5266,6 @@ var CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION = "ceal.codex_invocation_context.v1"
|
|
|
2562
5266
|
var CODEX_TRANSCRIPT_REGISTRATION_SCHEMA_VERSION = "ceal.codex_transcript_registration.v1";
|
|
2563
5267
|
var CODEX_TRANSCRIPT_CURSOR_SCHEMA_VERSION = "ceal.codex_transcript_cursor.v1";
|
|
2564
5268
|
var CODEX_DEFAULT_RETENTION_MS = 24 * 60 * 60 * 1e3;
|
|
2565
|
-
var CODEX_TRANSCRIPT_CURSOR_REASONS = ["transcript_replaced", "transcript_truncated", "transcript_rewritten", "transcript_malformed"];
|
|
2566
|
-
function isCodexTranscriptCursorReason(value) {
|
|
2567
|
-
return typeof value === "string" && CODEX_TRANSCRIPT_CURSOR_REASONS.some((reason) => reason === value);
|
|
2568
|
-
}
|
|
2569
5269
|
var CodexHostAdapterError = class extends Error {
|
|
2570
5270
|
name = "CodexHostAdapterError";
|
|
2571
5271
|
code;
|
|
@@ -2577,7 +5277,7 @@ var CodexHostAdapterError = class extends Error {
|
|
|
2577
5277
|
|
|
2578
5278
|
// host/codex/src/codex-decoder.ts
|
|
2579
5279
|
var SAFE_REF5 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
|
|
2580
|
-
var MAX_PAYLOAD_BYTES =
|
|
5280
|
+
var MAX_PAYLOAD_BYTES = 512 * 1024;
|
|
2581
5281
|
function observationRef(event, identity, value) {
|
|
2582
5282
|
return cealHostObservationRef("codex", shortDigest({ event, identity, value }));
|
|
2583
5283
|
}
|
|
@@ -2601,16 +5301,16 @@ function turnObservationValue(sessionId, turnRef, status) {
|
|
|
2601
5301
|
return { status, host_session_id_sha256: sha256(sessionId), host_turn_ref: turnRef };
|
|
2602
5302
|
}
|
|
2603
5303
|
function sha256(value) {
|
|
2604
|
-
return
|
|
5304
|
+
return createHash5("sha256").update(value, "utf8").digest("hex");
|
|
2605
5305
|
}
|
|
2606
5306
|
function shortDigest(value) {
|
|
2607
5307
|
return cealRequestSha256(value);
|
|
2608
5308
|
}
|
|
2609
5309
|
|
|
2610
5310
|
// host/codex/src/codex-outbox.ts
|
|
2611
|
-
import { O_NOFOLLOW, O_RDONLY as
|
|
2612
|
-
import { lstat as lstat3, mkdir as
|
|
2613
|
-
import { dirname, isAbsolute as isAbsolute2, join as
|
|
5311
|
+
import { O_NOFOLLOW as O_NOFOLLOW2, O_RDONLY as O_RDONLY3 } from "node:constants";
|
|
5312
|
+
import { lstat as lstat3, mkdir as mkdir3, open as open5, readdir, rename as rename3, unlink as unlink2 } from "node:fs/promises";
|
|
5313
|
+
import { dirname, isAbsolute as isAbsolute2, join as join4 } from "node:path";
|
|
2614
5314
|
|
|
2615
5315
|
// host/invocation-context.ts
|
|
2616
5316
|
var HOST_INVOCATION_IDENTITY_KEYS = ["host_session_ref", "host_turn_ref", "host_source_ref"];
|
|
@@ -2624,17 +5324,32 @@ function hasHostInvocationIdentityKeys(value) {
|
|
|
2624
5324
|
function hasHostInvocationContextKeys(value, optional = []) {
|
|
2625
5325
|
return requiredKeys(value, HOST_INVOCATION_CONTEXT_REQUIRED_KEYS, optional);
|
|
2626
5326
|
}
|
|
2627
|
-
function
|
|
5327
|
+
async function readLatestSessionProjection(file, hostSourceRef, hostSessionRef, readProjection) {
|
|
5328
|
+
const context = await readProjection(file);
|
|
5329
|
+
if (context === null || context.identity.host_source_ref !== hostSourceRef || context.identity.host_session_ref !== hostSessionRef) return null;
|
|
5330
|
+
return context;
|
|
5331
|
+
}
|
|
5332
|
+
function isLiveSessionProjection(context, now) {
|
|
5333
|
+
return context !== null && Date.parse(context.expires_at) > now.getTime();
|
|
5334
|
+
}
|
|
5335
|
+
function invocationContextFromTurn(identity, promptRef, expiresAt, descriptor2) {
|
|
2628
5336
|
const context = {
|
|
2629
|
-
schema_version:
|
|
5337
|
+
schema_version: descriptor2.schema_version,
|
|
2630
5338
|
identity,
|
|
2631
5339
|
prompt_ref: promptRef,
|
|
2632
5340
|
expires_at: expiresAt,
|
|
2633
|
-
...
|
|
5341
|
+
...descriptor2.turn_generation_ref === void 0 ? {} : { turn_generation_ref: descriptor2.turn_generation_ref },
|
|
5342
|
+
...descriptor2.working_directory === void 0 ? {} : { working_directory: descriptor2.working_directory }
|
|
2634
5343
|
};
|
|
2635
|
-
|
|
5344
|
+
descriptor2.validate(context);
|
|
2636
5345
|
return Object.freeze(context);
|
|
2637
5346
|
}
|
|
5347
|
+
function isHostInvocationTurnSelection(value) {
|
|
5348
|
+
return isRecord3(value) && Object.keys(value).length === 5 && value.schema_version === "ceal.host_invocation_turn_selection.v1" && ["host_source_ref", "host_session_ref", "prompt_ref", "turn_generation_ref"].every((key) => safeRef3(value[key]));
|
|
5349
|
+
}
|
|
5350
|
+
function invocationTurnSelectionMatches(context, selection) {
|
|
5351
|
+
return selection === null || context !== null && selection.host_source_ref === context.identity.host_source_ref && selection.host_session_ref === context.identity.host_session_ref && selection.prompt_ref === context.prompt_ref && selection.turn_generation_ref === context.turn_generation_ref;
|
|
5352
|
+
}
|
|
2638
5353
|
function exactKeys4(value, keys) {
|
|
2639
5354
|
const actual = Object.keys(value);
|
|
2640
5355
|
return actual.length === keys.length && keys.every((key) => Object.hasOwn(value, key)) && actual.every((key) => keys.includes(key));
|
|
@@ -2644,10 +5359,16 @@ function requiredKeys(value, required, optional) {
|
|
|
2644
5359
|
const allowed = /* @__PURE__ */ new Set([...required, ...optional]);
|
|
2645
5360
|
return actual.length >= required.length && actual.length <= allowed.size && required.every((key) => Object.hasOwn(value, key)) && actual.every((key) => allowed.has(key));
|
|
2646
5361
|
}
|
|
5362
|
+
function isRecord3(value) {
|
|
5363
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
5364
|
+
}
|
|
5365
|
+
function safeRef3(value) {
|
|
5366
|
+
return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(value);
|
|
5367
|
+
}
|
|
2647
5368
|
|
|
2648
5369
|
// host/codex/src/codex-invocation-context.ts
|
|
2649
|
-
function codexInvocationContextFromTurn(identity, promptRef, expiresAt) {
|
|
2650
|
-
return invocationContextFromTurn(identity, promptRef, expiresAt, { schema_version: CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION, validate: validateCodexHostInvocationContext });
|
|
5370
|
+
function codexInvocationContextFromTurn(identity, promptRef, expiresAt, turnGenerationRef) {
|
|
5371
|
+
return invocationContextFromTurn(identity, promptRef, expiresAt, { schema_version: CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION, validate: validateCodexHostInvocationContext, turn_generation_ref: turnGenerationRef });
|
|
2651
5372
|
}
|
|
2652
5373
|
function validateCodexHostInvocationContext(value) {
|
|
2653
5374
|
if (!isContextShape(value)) {
|
|
@@ -2657,28 +5378,29 @@ function validateCodexHostInvocationContext(value) {
|
|
|
2657
5378
|
validateContextReferences(value);
|
|
2658
5379
|
validateContextTimes(value);
|
|
2659
5380
|
}
|
|
2660
|
-
function invocationContextFromBinding(binding) {
|
|
5381
|
+
function invocationContextFromBinding(binding, turnGenerationRef) {
|
|
2661
5382
|
const context = {
|
|
2662
5383
|
schema_version: CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION,
|
|
2663
5384
|
identity: binding.identity,
|
|
2664
5385
|
prompt_ref: binding.prompt_ref,
|
|
2665
5386
|
request_ref: binding.request_ref,
|
|
2666
5387
|
bound_at: binding.bound_at,
|
|
2667
|
-
expires_at: binding.expires_at
|
|
5388
|
+
expires_at: binding.expires_at,
|
|
5389
|
+
...turnGenerationRef === void 0 ? {} : { turn_generation_ref: turnGenerationRef }
|
|
2668
5390
|
};
|
|
2669
5391
|
validateCodexHostInvocationContext(context);
|
|
2670
5392
|
return Object.freeze(context);
|
|
2671
5393
|
}
|
|
2672
5394
|
function validateIdentity2(value) {
|
|
2673
|
-
if (!
|
|
5395
|
+
if (!isRecord4(value) || !hasHostInvocationIdentityKeys(value) || ![value.host_session_ref, value.host_turn_ref, value.host_source_ref].every(safeRef4)) {
|
|
2674
5396
|
throw new CodexHostAdapterError("storage", "Codex Host invocation identity is malformed.");
|
|
2675
5397
|
}
|
|
2676
5398
|
}
|
|
2677
5399
|
function isContextShape(value) {
|
|
2678
|
-
return
|
|
5400
|
+
return isRecord4(value) && hasHostInvocationContextKeys(value, ["request_ref", "bound_at", "turn_generation_ref"]) && value.schema_version === CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION;
|
|
2679
5401
|
}
|
|
2680
5402
|
function validateContextReferences(value) {
|
|
2681
|
-
if (!
|
|
5403
|
+
if (!safeRef4(value.prompt_ref) || !optionalSafeRef(value.request_ref) || !optionalSafeRef(value.turn_generation_ref)) throw new CodexHostAdapterError("storage", "Codex Host invocation context is malformed.");
|
|
2682
5404
|
}
|
|
2683
5405
|
function validateContextTimes(value) {
|
|
2684
5406
|
const expiresAt = value.expires_at;
|
|
@@ -2687,18 +5409,18 @@ function validateContextTimes(value) {
|
|
|
2687
5409
|
if (typeof boundAt === "string" && Date.parse(boundAt) > Date.parse(expiresAt)) throw new CodexHostAdapterError("storage", `Codex Host invocation context has invalid binding time (${refusalFact("bound_at", boundAt, `at or before ${expiresAt}`)}).`);
|
|
2688
5410
|
}
|
|
2689
5411
|
function optionalSafeRef(value) {
|
|
2690
|
-
return value === void 0 ||
|
|
5412
|
+
return value === void 0 || safeRef4(value);
|
|
2691
5413
|
}
|
|
2692
5414
|
function optionalTimestamp(value) {
|
|
2693
5415
|
return value === void 0 || timestamp2(value);
|
|
2694
5416
|
}
|
|
2695
|
-
function
|
|
5417
|
+
function safeRef4(value) {
|
|
2696
5418
|
return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(value);
|
|
2697
5419
|
}
|
|
2698
5420
|
function timestamp2(value) {
|
|
2699
5421
|
return typeof value === "string" && value.length <= 64 && Number.isFinite(Date.parse(value));
|
|
2700
5422
|
}
|
|
2701
|
-
function
|
|
5423
|
+
function isRecord4(value) {
|
|
2702
5424
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2703
5425
|
}
|
|
2704
5426
|
|
|
@@ -2711,20 +5433,22 @@ var CodexOutboxStore = class {
|
|
|
2711
5433
|
bindingsDirectory;
|
|
2712
5434
|
sessionsDirectory;
|
|
2713
5435
|
activeContextsDirectory;
|
|
5436
|
+
turnSelectionsDirectory;
|
|
2714
5437
|
registrationsDirectory;
|
|
2715
5438
|
cursorsDirectory;
|
|
2716
5439
|
constructor(directory) {
|
|
2717
5440
|
if (typeof directory !== "string" || directory.length === 0) throw new CodexHostAdapterError("configuration", "Codex outbox directory is required.");
|
|
2718
5441
|
this.directory = directory;
|
|
2719
|
-
this.entriesDirectory =
|
|
2720
|
-
this.bindingsDirectory =
|
|
2721
|
-
this.sessionsDirectory =
|
|
2722
|
-
this.activeContextsDirectory =
|
|
2723
|
-
this.
|
|
2724
|
-
this.
|
|
5442
|
+
this.entriesDirectory = join4(directory, "entries");
|
|
5443
|
+
this.bindingsDirectory = join4(directory, "bindings");
|
|
5444
|
+
this.sessionsDirectory = join4(directory, "sessions");
|
|
5445
|
+
this.activeContextsDirectory = join4(directory, "active-contexts");
|
|
5446
|
+
this.turnSelectionsDirectory = join4(directory, "turn-selections");
|
|
5447
|
+
this.registrationsDirectory = join4(directory, "transcript-registrations");
|
|
5448
|
+
this.cursorsDirectory = join4(directory, "transcript-cursors");
|
|
2725
5449
|
}
|
|
2726
5450
|
async prepare() {
|
|
2727
|
-
for (const path of [this.directory, this.entriesDirectory, this.bindingsDirectory, this.sessionsDirectory, this.activeContextsDirectory, this.registrationsDirectory, this.cursorsDirectory]) {
|
|
5451
|
+
for (const path of [this.directory, this.entriesDirectory, this.bindingsDirectory, this.sessionsDirectory, this.activeContextsDirectory, this.turnSelectionsDirectory, this.registrationsDirectory, this.cursorsDirectory]) {
|
|
2728
5452
|
await ensurePrivateOwnerDirectory(path);
|
|
2729
5453
|
}
|
|
2730
5454
|
}
|
|
@@ -2740,7 +5464,7 @@ var CodexOutboxStore = class {
|
|
|
2740
5464
|
for (const name of await readdir(this.entriesDirectory)) {
|
|
2741
5465
|
if (!name.endsWith(".json")) continue;
|
|
2742
5466
|
try {
|
|
2743
|
-
const value = JSON.parse(await readPrivateFile(
|
|
5467
|
+
const value = JSON.parse(await readPrivateFile(join4(this.entriesDirectory, name)));
|
|
2744
5468
|
validateEnvelope(value);
|
|
2745
5469
|
entries.push(value);
|
|
2746
5470
|
} catch {
|
|
@@ -2768,8 +5492,8 @@ var CodexOutboxStore = class {
|
|
|
2768
5492
|
* prompt replaces this projection, so it cannot inherit the prior turn's
|
|
2769
5493
|
* Request by session alone.
|
|
2770
5494
|
*/
|
|
2771
|
-
async activateInvocationContext(identity, promptRef, expiresAt) {
|
|
2772
|
-
const context = codexInvocationContextFromTurn(identity, promptRef, expiresAt);
|
|
5495
|
+
async activateInvocationContext(identity, promptRef, expiresAt, turnGenerationRef) {
|
|
5496
|
+
const context = codexInvocationContextFromTurn(identity, promptRef, expiresAt, turnGenerationRef);
|
|
2773
5497
|
await this.prepare();
|
|
2774
5498
|
const path = this.activeContextPath(identity);
|
|
2775
5499
|
try {
|
|
@@ -2783,6 +5507,25 @@ var CodexOutboxStore = class {
|
|
|
2783
5507
|
throw error;
|
|
2784
5508
|
}
|
|
2785
5509
|
}
|
|
5510
|
+
async writeInvocationTurnSelection(selection) {
|
|
5511
|
+
if (!isHostInvocationTurnSelection(selection)) throw new CodexHostAdapterError("invalid_input", "Codex Host turn selection is invalid.");
|
|
5512
|
+
await this.prepare();
|
|
5513
|
+
await writeAtomicJson(this.turnSelectionPath(selection.host_source_ref, selection.host_session_ref), selection);
|
|
5514
|
+
}
|
|
5515
|
+
async readInvocationTurnSelection(hostSourceRef, hostSessionRef) {
|
|
5516
|
+
if (!SAFE_REF6.test(hostSourceRef) || !SAFE_REF6.test(hostSessionRef)) throw new CodexHostAdapterError("invalid_input", "Codex Host turn selection identity is invalid.");
|
|
5517
|
+
await this.prepare();
|
|
5518
|
+
return readOptionalJson(this.turnSelectionPath(hostSourceRef, hostSessionRef), validateTurnSelection);
|
|
5519
|
+
}
|
|
5520
|
+
async attachInvocationTurnGeneration(identity, promptRef, turnGenerationRef) {
|
|
5521
|
+
const selection = await this.readInvocationTurnSelection(identity.host_source_ref, identity.host_session_ref);
|
|
5522
|
+
if (selection === null || selection.prompt_ref !== promptRef || selection.turn_generation_ref !== turnGenerationRef) return false;
|
|
5523
|
+
const path = this.activeContextPath(identity);
|
|
5524
|
+
const active = await readOptionalJson(path, validateCodexHostInvocationContext);
|
|
5525
|
+
if (active === null || active.prompt_ref !== promptRef || !sameIdentity(active.identity, identity)) return false;
|
|
5526
|
+
await writeAtomicJson(path, { ...active, turn_generation_ref: turnGenerationRef });
|
|
5527
|
+
return true;
|
|
5528
|
+
}
|
|
2786
5529
|
/**
|
|
2787
5530
|
* Publish a Request reference only while the acknowledged binding is still
|
|
2788
5531
|
* the active turn. A delayed relay response therefore cannot overwrite a
|
|
@@ -2792,17 +5535,25 @@ var CodexOutboxStore = class {
|
|
|
2792
5535
|
validateBinding(binding);
|
|
2793
5536
|
const active = await this.readInvocationContext(binding.identity.host_source_ref, binding.identity.host_session_ref, now);
|
|
2794
5537
|
if (active === null || !sameIdentity(active.identity, binding.identity)) return false;
|
|
2795
|
-
await writeAtomicJson(this.activeContextPath(binding.identity), invocationContextFromBinding(binding));
|
|
5538
|
+
await writeAtomicJson(this.activeContextPath(binding.identity), invocationContextFromBinding(binding, active.turn_generation_ref));
|
|
2796
5539
|
return true;
|
|
2797
5540
|
}
|
|
2798
|
-
/** Return only the
|
|
5541
|
+
/** Return only the live session projection; never fall back to another turn. */
|
|
2799
5542
|
async readInvocationContext(hostSourceRef, hostSessionRef, now = /* @__PURE__ */ new Date()) {
|
|
2800
|
-
if (!SAFE_REF6.test(hostSourceRef) || !SAFE_REF6.test(hostSessionRef)) throw new CodexHostAdapterError("invalid_input", "Codex Host session identity is invalid.");
|
|
2801
5543
|
if (!(now instanceof Date) || !Number.isFinite(now.getTime())) throw new CodexHostAdapterError("invalid_input", "Codex Host context clock is invalid.");
|
|
5544
|
+
const context = await this.readRawInvocationContext(hostSourceRef, hostSessionRef);
|
|
5545
|
+
return isLiveSessionProjection(context, now) && invocationTurnSelectionMatches(context, await this.readInvocationTurnSelection(hostSourceRef, hostSessionRef)) ? context : null;
|
|
5546
|
+
}
|
|
5547
|
+
/**
|
|
5548
|
+
* The latest Codex session projection even when past expiry, so the
|
|
5549
|
+
* invocation authenticator can report an expired context distinctly from
|
|
5550
|
+
* a missing one. Every other caller keeps the fail-closed read above.
|
|
5551
|
+
*/
|
|
5552
|
+
async readRawInvocationContext(hostSourceRef, hostSessionRef) {
|
|
5553
|
+
if (!SAFE_REF6.test(hostSourceRef) || !SAFE_REF6.test(hostSessionRef)) throw new CodexHostAdapterError("invalid_input", "Codex Host session identity is invalid.");
|
|
2802
5554
|
await this.prepare();
|
|
2803
|
-
const context = await
|
|
2804
|
-
|
|
2805
|
-
return Date.parse(context.expires_at) > now.getTime() ? context : null;
|
|
5555
|
+
const context = await readLatestSessionProjection(this.activeContextPath({ host_source_ref: hostSourceRef, host_session_ref: hostSessionRef }), hostSourceRef, hostSessionRef, (file) => readOptionalJson(file, validateCodexHostInvocationContext));
|
|
5556
|
+
return invocationTurnSelectionMatches(context, await this.readInvocationTurnSelection(hostSourceRef, hostSessionRef)) ? context : null;
|
|
2806
5557
|
}
|
|
2807
5558
|
/** Clear the projection only if the caller still owns its exact active turn. */
|
|
2808
5559
|
async clearInvocationContext(identity, now = /* @__PURE__ */ new Date()) {
|
|
@@ -2861,7 +5612,7 @@ var CodexOutboxStore = class {
|
|
|
2861
5612
|
for (const name of await readdir(this.registrationsDirectory)) {
|
|
2862
5613
|
if (!name.endsWith(".json")) continue;
|
|
2863
5614
|
try {
|
|
2864
|
-
const value = JSON.parse(await readPrivateFile(
|
|
5615
|
+
const value = JSON.parse(await readPrivateFile(join4(this.registrationsDirectory, name)));
|
|
2865
5616
|
validateRegistration(value);
|
|
2866
5617
|
registrations.push(value);
|
|
2867
5618
|
} catch {
|
|
@@ -2903,22 +5654,25 @@ var CodexOutboxStore = class {
|
|
|
2903
5654
|
}
|
|
2904
5655
|
entryPath(submissionRef) {
|
|
2905
5656
|
if (!SAFE_REF6.test(submissionRef)) throw storageError("Codex submission identity is malformed.");
|
|
2906
|
-
return
|
|
5657
|
+
return join4(this.entriesDirectory, `${cealRequestSha256(submissionRef)}.json`);
|
|
2907
5658
|
}
|
|
2908
5659
|
bindingPath(identity) {
|
|
2909
|
-
return
|
|
5660
|
+
return join4(this.bindingsDirectory, `${identityKey(identity)}.json`);
|
|
2910
5661
|
}
|
|
2911
5662
|
sessionPath(sourceRef, sessionRef) {
|
|
2912
|
-
return
|
|
5663
|
+
return join4(this.sessionsDirectory, `${identityKey({ host_source_ref: sourceRef, host_session_ref: sessionRef, host_turn_ref: "session" })}.json`);
|
|
2913
5664
|
}
|
|
2914
5665
|
activeContextPath(identity) {
|
|
2915
|
-
return
|
|
5666
|
+
return join4(this.activeContextsDirectory, `${invocationContextKey(identity)}.json`);
|
|
5667
|
+
}
|
|
5668
|
+
turnSelectionPath(sourceRef, sessionRef) {
|
|
5669
|
+
return join4(this.turnSelectionsDirectory, `${invocationContextKey({ host_source_ref: sourceRef, host_session_ref: sessionRef })}.json`);
|
|
2916
5670
|
}
|
|
2917
5671
|
registrationPath(sourceRef, sessionRef) {
|
|
2918
|
-
return
|
|
5672
|
+
return join4(this.registrationsDirectory, `${sessionStateKey(sourceRef, sessionRef)}.json`);
|
|
2919
5673
|
}
|
|
2920
5674
|
cursorPath(sourceRef, sessionRef) {
|
|
2921
|
-
return
|
|
5675
|
+
return join4(this.cursorsDirectory, `${sessionStateKey(sourceRef, sessionRef)}.json`);
|
|
2922
5676
|
}
|
|
2923
5677
|
};
|
|
2924
5678
|
async function removeOwnerState(path, what) {
|
|
@@ -2956,7 +5710,7 @@ async function findBindingByAlias(directory, sourceRef, sessionRef, alias) {
|
|
|
2956
5710
|
}
|
|
2957
5711
|
async function readBindingCandidate(directory, name) {
|
|
2958
5712
|
try {
|
|
2959
|
-
const value = JSON.parse(await readPrivateFile(
|
|
5713
|
+
const value = JSON.parse(await readPrivateFile(join4(directory, name)));
|
|
2960
5714
|
validateBinding(value);
|
|
2961
5715
|
return value;
|
|
2962
5716
|
} catch {
|
|
@@ -2975,14 +5729,14 @@ async function writeAtomicJson(path, value) {
|
|
|
2975
5729
|
if (text === void 0) throw storageError("Codex owner state cannot be serialized.");
|
|
2976
5730
|
const temp = `${path}.${process.pid}.${Math.random().toString(16).slice(2)}.tmp`;
|
|
2977
5731
|
try {
|
|
2978
|
-
const handle = await
|
|
5732
|
+
const handle = await open5(temp, "wx", 384);
|
|
2979
5733
|
try {
|
|
2980
5734
|
await handle.writeFile(text, "utf8");
|
|
2981
5735
|
await handle.sync();
|
|
2982
5736
|
} finally {
|
|
2983
5737
|
await handle.close();
|
|
2984
5738
|
}
|
|
2985
|
-
await
|
|
5739
|
+
await rename3(temp, path);
|
|
2986
5740
|
await syncDirectory(dirname(path));
|
|
2987
5741
|
} catch (error) {
|
|
2988
5742
|
try {
|
|
@@ -2995,7 +5749,7 @@ async function writeAtomicJson(path, value) {
|
|
|
2995
5749
|
}
|
|
2996
5750
|
async function syncDirectory(path) {
|
|
2997
5751
|
try {
|
|
2998
|
-
const handle = await
|
|
5752
|
+
const handle = await open5(path, "r");
|
|
2999
5753
|
try {
|
|
3000
5754
|
await handle.sync();
|
|
3001
5755
|
} finally {
|
|
@@ -3020,7 +5774,7 @@ async function ensurePrivateOwnerDirectory(path) {
|
|
|
3020
5774
|
await lstat3(path);
|
|
3021
5775
|
} catch (error) {
|
|
3022
5776
|
if (!isNotFound(error)) throw storageError("Codex owner state directory is unavailable.");
|
|
3023
|
-
await
|
|
5777
|
+
await mkdir3(path, { recursive: true, mode: 448 });
|
|
3024
5778
|
}
|
|
3025
5779
|
const stats = await lstat3(path);
|
|
3026
5780
|
const uid = typeof process.geteuid === "function" ? process.geteuid() : stats.uid;
|
|
@@ -3031,7 +5785,7 @@ async function ensurePrivateOwnerDirectory(path) {
|
|
|
3031
5785
|
async function readPrivateFile(path) {
|
|
3032
5786
|
let handle;
|
|
3033
5787
|
try {
|
|
3034
|
-
handle = await
|
|
5788
|
+
handle = await open5(path, O_RDONLY3 | O_NOFOLLOW2);
|
|
3035
5789
|
const stats = await handle.stat();
|
|
3036
5790
|
const uid = typeof process.geteuid === "function" ? process.geteuid() : stats.uid;
|
|
3037
5791
|
if (!stats.isFile()) throw storageError(`Codex owner state path is not a regular file (${refusalFact("mode", `0o${stats.mode.toString(8)}`, "a regular-file mode (0o100xxx)")}).`);
|
|
@@ -3043,7 +5797,7 @@ async function readPrivateFile(path) {
|
|
|
3043
5797
|
}
|
|
3044
5798
|
}
|
|
3045
5799
|
function validateEnvelope(value) {
|
|
3046
|
-
if (!
|
|
5800
|
+
if (!isRecord5(value)) throw storageError("Codex outbox entry is malformed.");
|
|
3047
5801
|
if (!sameKeys(value, ["schema_version", "identity", "host_input_ref", "input_kind", "prompt_ref", "observations", "origin_input", "submission_ref", "created_at", "expires_at"], ["request_ref", "codex_turn_id"])) throw storageError(`Codex outbox entry key set is malformed (${refusalFact("keys", Object.keys(value), "exactly the outbox entry key set")}).`);
|
|
3048
5802
|
if (value.schema_version !== CODEX_OUTBOX_SCHEMA_VERSION) throw storageError(`Codex outbox entry is malformed (${refusalFact("schema_version", value.schema_version, `expected ${CODEX_OUTBOX_SCHEMA_VERSION}`)}).`);
|
|
3049
5803
|
validateIdentity3(value.identity);
|
|
@@ -3061,7 +5815,7 @@ function validateEnvelopeReferences(value) {
|
|
|
3061
5815
|
if (typeof value.origin_input !== "boolean") throw storageError("Codex outbox origin disposition is malformed.");
|
|
3062
5816
|
}
|
|
3063
5817
|
function validateRegistration(value) {
|
|
3064
|
-
if (!
|
|
5818
|
+
if (!isRecord5(value)) throw storageError("Codex transcript registration is malformed.");
|
|
3065
5819
|
if (!sameKeys(value, ["schema_version", "host_source_ref", "host_session_ref", "codex_session_id", "transcript_path", "registered_at", "expires_at"], ["cwd"])) throw storageError(`Codex transcript registration key set is malformed (${refusalFact("keys", Object.keys(value), "exactly the registration key set")}).`);
|
|
3066
5820
|
if (value.schema_version !== CODEX_TRANSCRIPT_REGISTRATION_SCHEMA_VERSION) throw storageError(`Codex transcript registration is malformed (${refusalFact("schema_version", value.schema_version, `expected ${CODEX_TRANSCRIPT_REGISTRATION_SCHEMA_VERSION}`)}).`);
|
|
3067
5821
|
validateRegistrationFields(value);
|
|
@@ -3077,12 +5831,12 @@ function validRegistrationCwd(value) {
|
|
|
3077
5831
|
return value === void 0 || typeof value === "string" && isAbsolute2(value) && value.length <= CODEX_TRANSCRIPT_PATH_MAX_CHARACTERS && !value.includes("\0");
|
|
3078
5832
|
}
|
|
3079
5833
|
function validateCursor(value) {
|
|
3080
|
-
if (!
|
|
5834
|
+
if (!isRecord5(value)) throw storageError("Codex transcript cursor is malformed.");
|
|
3081
5835
|
if (!sameKeys(value, ["schema_version", "host_source_ref", "host_session_ref", "transcript_path", "device", "inode", "offset", "last_ordinal", "anchor_start", "anchor_sha256", "header_validated", "status", "updated_at"], ["active_task", "reason"])) throw storageError(`Codex transcript cursor key set is malformed (${refusalFact("keys", Object.keys(value), "exactly the cursor key set")}).`);
|
|
3082
5836
|
if (value.schema_version !== CODEX_TRANSCRIPT_CURSOR_SCHEMA_VERSION) throw storageError(`Codex transcript cursor is malformed (${refusalFact("schema_version", value.schema_version, `expected ${CODEX_TRANSCRIPT_CURSOR_SCHEMA_VERSION}`)}).`);
|
|
3083
5837
|
if (!validCursorSource(value) || !validCursorPosition(value) || !validCursorStatus(value)) throw storageError("Codex transcript cursor fields are malformed.");
|
|
3084
5838
|
if (value.active_task !== void 0 && !validActiveTask(value.active_task)) throw storageError("Codex transcript task cursor is malformed.");
|
|
3085
|
-
if (value.reason !== void 0 && !
|
|
5839
|
+
if (value.reason !== void 0 && !isHostTranscriptCursorReason(value.reason)) throw storageError("Codex transcript cursor reason is malformed.");
|
|
3086
5840
|
}
|
|
3087
5841
|
function validCursorSource(value) {
|
|
3088
5842
|
return [value.host_source_ref, value.host_session_ref].every((candidate) => typeof candidate === "string" && SAFE_REF6.test(candidate)) && typeof value.transcript_path === "string" && value.transcript_path.length > 0 && typeof value.device === "string" && typeof value.inode === "string";
|
|
@@ -3094,7 +5848,7 @@ function validCursorStatus(value) {
|
|
|
3094
5848
|
return (value.status === "active" || value.status === "quarantined") && isTimestamp(value.updated_at);
|
|
3095
5849
|
}
|
|
3096
5850
|
function validActiveTask(value) {
|
|
3097
|
-
if (!
|
|
5851
|
+
if (!isRecord5(value) || !sameKeys(value, ["codex_turn_id", "host_turn_ref", "started_at"], ["origin_host_input_ref", "prompt_ref", "model", "token_usage", "last_total_usage", "token_usage_gap_reason"])) return false;
|
|
3098
5852
|
return validActiveTaskIdentity(value) && validActiveTaskReferences(value) && validActiveTaskUsage(value);
|
|
3099
5853
|
}
|
|
3100
5854
|
function validActiveTaskIdentity(value) {
|
|
@@ -3110,7 +5864,7 @@ function validActiveTaskUsage(value) {
|
|
|
3110
5864
|
return (value.token_usage === void 0 || validTokenUsage(value.token_usage)) && (value.last_total_usage === void 0 || validTokenUsage(value.last_total_usage)) && (value.token_usage_gap_reason === void 0 || value.token_usage_gap_reason === "token_count_shape_not_attributable");
|
|
3111
5865
|
}
|
|
3112
5866
|
function validTokenUsage(value) {
|
|
3113
|
-
if (!
|
|
5867
|
+
if (!isRecord5(value) || !sameKeys(value, ["input_tokens", "cached_input_tokens", "cache_write_input_tokens", "output_tokens", "reasoning_output_tokens", "total_tokens"])) return false;
|
|
3114
5868
|
if (![value.input_tokens, value.cached_input_tokens, value.cache_write_input_tokens, value.output_tokens, value.reasoning_output_tokens, value.total_tokens].every(nonNegativeInteger)) return false;
|
|
3115
5869
|
return value.total_tokens === Number(value.input_tokens) + Number(value.output_tokens) && Number(value.cached_input_tokens) + Number(value.cache_write_input_tokens) <= Number(value.input_tokens) && Number(value.reasoning_output_tokens) <= Number(value.output_tokens);
|
|
3116
5870
|
}
|
|
@@ -3130,7 +5884,7 @@ function validateEnvelopeTimestamps(value) {
|
|
|
3130
5884
|
if (!isTimestamp(value.expires_at)) throw storageError("Codex outbox timestamps are malformed.");
|
|
3131
5885
|
}
|
|
3132
5886
|
function validateBinding(value) {
|
|
3133
|
-
if (!
|
|
5887
|
+
if (!isRecord5(value)) throw storageError("Codex turn binding is malformed.");
|
|
3134
5888
|
if (!sameKeys(value, ["schema_version", "identity", "prompt_ref", "request_ref", "codex_turn_ids", "bound_at", "expires_at"])) throw storageError(`Codex turn binding key set is malformed (${refusalFact("keys", Object.keys(value), "exactly the turn binding key set")}).`);
|
|
3135
5889
|
if (value.schema_version !== CODEX_TURN_BINDING_SCHEMA_VERSION) throw storageError(`Codex turn binding is malformed (${refusalFact("schema_version", value.schema_version, `expected ${CODEX_TURN_BINDING_SCHEMA_VERSION}`)}).`);
|
|
3136
5890
|
validateIdentity3(value.identity);
|
|
@@ -3138,19 +5892,22 @@ function validateBinding(value) {
|
|
|
3138
5892
|
if (!isStringList(value.codex_turn_ids) || !isTimestamp(value.bound_at) || !isTimestamp(value.expires_at)) throw storageError("Codex turn binding fields are malformed.");
|
|
3139
5893
|
}
|
|
3140
5894
|
function validateSession(value) {
|
|
3141
|
-
if (!
|
|
5895
|
+
if (!isRecord5(value)) throw storageError("Codex session snapshot is malformed.");
|
|
3142
5896
|
if (!sameKeys(value, ["schema_version", "host_session_ref", "host_source_ref", "observed_at", "value", "expires_at"])) throw storageError(`Codex session snapshot key set is malformed (${refusalFact("keys", Object.keys(value), "exactly the session snapshot key set")}).`);
|
|
3143
5897
|
if (value.schema_version !== CODEX_SESSION_SCHEMA_VERSION) throw storageError(`Codex session snapshot is malformed (${refusalFact("schema_version", value.schema_version, `expected ${CODEX_SESSION_SCHEMA_VERSION}`)}).`);
|
|
3144
5898
|
if (!SAFE_REF6.test(String(value.host_session_ref)) || !SAFE_REF6.test(String(value.host_source_ref)) || !isTimestamp(value.observed_at) || !isTimestamp(value.expires_at) || !isJsonValue(value.value)) throw storageError("Codex session snapshot fields are malformed.");
|
|
3145
5899
|
}
|
|
5900
|
+
function validateTurnSelection(value) {
|
|
5901
|
+
if (!isHostInvocationTurnSelection(value)) throw storageError("Codex Host turn selection is malformed.");
|
|
5902
|
+
}
|
|
3146
5903
|
function validateIdentity3(value) {
|
|
3147
|
-
if (!
|
|
5904
|
+
if (!isRecord5(value) || !hasHostInvocationIdentityKeys(value) || ![value.host_session_ref, value.host_turn_ref, value.host_source_ref].every((candidate) => typeof candidate === "string" && SAFE_REF6.test(candidate))) throw storageError("Codex Host identity is malformed.");
|
|
3148
5905
|
}
|
|
3149
5906
|
function isJsonValue(value) {
|
|
3150
5907
|
if (value === null || typeof value === "string" || typeof value === "boolean") return true;
|
|
3151
5908
|
if (typeof value === "number") return Number.isFinite(value);
|
|
3152
5909
|
if (Array.isArray(value)) return value.every(isJsonValue);
|
|
3153
|
-
return
|
|
5910
|
+
return isRecord5(value) && Object.entries(value).every(([key, child]) => key.length > 0 && key.length <= 128 && isJsonValue(child));
|
|
3154
5911
|
}
|
|
3155
5912
|
function isStringList(value) {
|
|
3156
5913
|
return Array.isArray(value) && value.every((candidate) => typeof candidate === "string" && SAFE_REF6.test(candidate));
|
|
@@ -3163,104 +5920,50 @@ function sameKeys(value, required, optional = []) {
|
|
|
3163
5920
|
const keys = Object.keys(value);
|
|
3164
5921
|
return keys.length >= required.length && keys.length <= allowed.size && required.every((key) => Object.hasOwn(value, key)) && keys.every((key) => allowed.has(key));
|
|
3165
5922
|
}
|
|
3166
|
-
function
|
|
5923
|
+
function isRecord5(value) {
|
|
3167
5924
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3168
5925
|
}
|
|
3169
5926
|
function isNotFound(error) {
|
|
3170
|
-
return
|
|
5927
|
+
return isRecord5(error) && error.code === "ENOENT";
|
|
3171
5928
|
}
|
|
3172
5929
|
function storageError(message) {
|
|
3173
5930
|
return new CodexHostAdapterError("storage", message);
|
|
3174
5931
|
}
|
|
3175
5932
|
|
|
3176
5933
|
// host/codex/src/codex-producer.ts
|
|
3177
|
-
import { createHash as
|
|
3178
|
-
import { mkdir as mkdir3, readFile as readFile2, rename as rename3, writeFile } from "node:fs/promises";
|
|
3179
|
-
import { join as join4 } from "node:path";
|
|
3180
|
-
var STATE_SCHEMA = "ceal.codex_producer_state.v1";
|
|
5934
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
3181
5935
|
var SAFE_REF7 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
|
|
3182
5936
|
var CodexProducer = class {
|
|
5937
|
+
producer_id = "codex";
|
|
5938
|
+
producer_label = "Codex";
|
|
5939
|
+
outbox_directory;
|
|
3183
5940
|
store;
|
|
3184
|
-
|
|
3185
|
-
installationRef;
|
|
3186
|
-
epoch;
|
|
3187
|
-
relay;
|
|
3188
|
-
now;
|
|
3189
|
-
tail = Promise.resolve();
|
|
5941
|
+
core;
|
|
3190
5942
|
constructor(options) {
|
|
3191
|
-
if (!SAFE_REF7.test(options.producer_installation_ref)) throw new CodexHostAdapterError("configuration", "Codex producer installation identity is invalid.");
|
|
3192
|
-
const epoch = options.producer_epoch ?? 1;
|
|
3193
|
-
if (!Number.isSafeInteger(epoch) || epoch <= 0) throw new CodexHostAdapterError("configuration", "Codex producer epoch is invalid.");
|
|
3194
5943
|
this.store = new CodexOutboxStore(options.outbox_dir);
|
|
3195
|
-
this.
|
|
3196
|
-
this.
|
|
3197
|
-
this.epoch = epoch;
|
|
3198
|
-
this.relay = options.relay;
|
|
3199
|
-
this.now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
5944
|
+
this.outbox_directory = this.store.directory;
|
|
5945
|
+
this.core = new HostProducerDrainCore(this, options);
|
|
3200
5946
|
}
|
|
3201
5947
|
drainOutbox() {
|
|
3202
|
-
|
|
3203
|
-
this.tail = run.then(() => void 0, () => void 0);
|
|
3204
|
-
return run;
|
|
5948
|
+
return this.core.drainOutbox();
|
|
3205
5949
|
}
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
let admitted = 0;
|
|
3209
|
-
let expired = 0;
|
|
3210
|
-
let retained = 0;
|
|
3211
|
-
for (const envelope of read.entries) {
|
|
3212
|
-
const reserved = await this.hasReservation(envelope.submission_ref);
|
|
3213
|
-
if (!reserved && Date.parse(envelope.expires_at) <= this.now().getTime()) {
|
|
3214
|
-
await this.store.remove(envelope);
|
|
3215
|
-
expired += 1;
|
|
3216
|
-
continue;
|
|
3217
|
-
}
|
|
3218
|
-
const frames = await this.reserve(envelope);
|
|
3219
|
-
let complete = true;
|
|
3220
|
-
for (const frame of frames) {
|
|
3221
|
-
const outcome = await this.relay.admit(frame);
|
|
3222
|
-
if (outcome.code !== "admitted" && outcome.code !== "already_admitted") {
|
|
3223
|
-
complete = false;
|
|
3224
|
-
break;
|
|
3225
|
-
}
|
|
3226
|
-
}
|
|
3227
|
-
if (!complete) {
|
|
3228
|
-
retained += 1;
|
|
3229
|
-
break;
|
|
3230
|
-
}
|
|
3231
|
-
await this.store.remove(envelope);
|
|
3232
|
-
await this.release(envelope.submission_ref);
|
|
3233
|
-
admitted += 1;
|
|
3234
|
-
}
|
|
3235
|
-
return { admitted, retained: retained + Math.max(0, read.entries.length - admitted - expired - retained), expired, malformed: read.malformed };
|
|
5950
|
+
fail(code, message) {
|
|
5951
|
+
return new CodexHostAdapterError(code, message);
|
|
3236
5952
|
}
|
|
3237
|
-
|
|
3238
|
-
return
|
|
5953
|
+
listEnvelopes() {
|
|
5954
|
+
return this.store.list();
|
|
3239
5955
|
}
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
const existing = state.pending[envelope.submission_ref];
|
|
3243
|
-
if (existing !== void 0) return existing;
|
|
3244
|
-
const drafts = await this.mapEnvelope(envelope);
|
|
3245
|
-
const frames = drafts.map((draft, offset) => ({
|
|
3246
|
-
schema_version: "ceal.host_producer_frame.v1",
|
|
3247
|
-
producer_id: "codex",
|
|
3248
|
-
producer_installation_ref: this.installationRef,
|
|
3249
|
-
producer_epoch: this.epoch,
|
|
3250
|
-
sequence: state.next_sequence + offset,
|
|
3251
|
-
frame_kind: draft.frame_kind,
|
|
3252
|
-
occurred_at: envelope.created_at,
|
|
3253
|
-
payload: draft.payload
|
|
3254
|
-
}));
|
|
3255
|
-
await this.writeState({ ...state, next_sequence: state.next_sequence + frames.length, pending: { ...state.pending, [envelope.submission_ref]: frames } });
|
|
3256
|
-
return frames;
|
|
5956
|
+
removeEnvelope(envelope) {
|
|
5957
|
+
return this.store.remove(envelope);
|
|
3257
5958
|
}
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
5959
|
+
submissionRefOf(envelope) {
|
|
5960
|
+
return envelope.submission_ref;
|
|
5961
|
+
}
|
|
5962
|
+
expiresAtOf(envelope) {
|
|
5963
|
+
return envelope.expires_at;
|
|
5964
|
+
}
|
|
5965
|
+
createdAtOf(envelope) {
|
|
5966
|
+
return envelope.created_at;
|
|
3264
5967
|
}
|
|
3265
5968
|
async mapEnvelope(envelope) {
|
|
3266
5969
|
const prompt = observation(envelope, "prompt");
|
|
@@ -3276,7 +5979,7 @@ var CodexProducer = class {
|
|
|
3276
5979
|
const directoryIdentity = registration?.cwd ?? envelope.identity.host_session_ref;
|
|
3277
5980
|
drafts.push({ frame_kind: "session_started", payload: compact({
|
|
3278
5981
|
local_session_ref: envelope.identity.host_session_ref,
|
|
3279
|
-
working_directory_ref: `workspace:${
|
|
5982
|
+
working_directory_ref: `workspace:${createHash6("sha256").update(directoryIdentity, "utf8").digest("hex")}`,
|
|
3280
5983
|
model: recordText(session.value, "model"),
|
|
3281
5984
|
host_version: nestedText(session.value, "host_version"),
|
|
3282
5985
|
observations: [session]
|
|
@@ -3301,21 +6004,6 @@ var CodexProducer = class {
|
|
|
3301
6004
|
}) });
|
|
3302
6005
|
return drafts;
|
|
3303
6006
|
}
|
|
3304
|
-
async readState() {
|
|
3305
|
-
try {
|
|
3306
|
-
const value = JSON.parse(await readFile2(this.statePath, "utf8"));
|
|
3307
|
-
return decodeState(value, this.installationRef, this.epoch);
|
|
3308
|
-
} catch (error) {
|
|
3309
|
-
if (errorCode3(error) !== "ENOENT") throw error;
|
|
3310
|
-
return { schema_version: STATE_SCHEMA, producer_installation_ref: this.installationRef, producer_epoch: this.epoch, next_sequence: 1, pending: {} };
|
|
3311
|
-
}
|
|
3312
|
-
}
|
|
3313
|
-
async writeState(state) {
|
|
3314
|
-
await mkdir3(this.store.directory, { recursive: true, mode: 448 });
|
|
3315
|
-
const temporary = `${this.statePath}.${process.pid}.new`;
|
|
3316
|
-
await writeFile(temporary, JSON.stringify(state), { mode: 384 });
|
|
3317
|
-
await rename3(temporary, this.statePath);
|
|
3318
|
-
}
|
|
3319
6007
|
};
|
|
3320
6008
|
function mapTerminal(envelope) {
|
|
3321
6009
|
const timing = observation(envelope, "timing");
|
|
@@ -3343,7 +6031,7 @@ function compact(value) {
|
|
|
3343
6031
|
return Object.fromEntries(Object.entries(value).filter((entry) => entry[1] !== void 0));
|
|
3344
6032
|
}
|
|
3345
6033
|
function asRecord(value) {
|
|
3346
|
-
return
|
|
6034
|
+
return isRecord6(value) ? value : void 0;
|
|
3347
6035
|
}
|
|
3348
6036
|
function recordText(value, key) {
|
|
3349
6037
|
const record3 = asRecord(value);
|
|
@@ -3357,53 +6045,14 @@ function nonNegativeNumber(value) {
|
|
|
3357
6045
|
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
|
|
3358
6046
|
}
|
|
3359
6047
|
function safeReasonRef(value) {
|
|
3360
|
-
return SAFE_REF7.test(value) ? value : `reason:${
|
|
3361
|
-
}
|
|
3362
|
-
function errorCode3(error) {
|
|
3363
|
-
return typeof error === "object" && error !== null && "code" in error ? String(error.code) : null;
|
|
3364
|
-
}
|
|
3365
|
-
function decodeState(value, installationRef, epoch) {
|
|
3366
|
-
if (!validStateHeader(value, installationRef)) {
|
|
3367
|
-
throw new CodexHostAdapterError("storage", `Codex producer state header is malformed or belongs to another installation (${refusalFacts([
|
|
3368
|
-
{ name: "schema_version", value: isRecord5(value) ? value.schema_version : void 0, expected: STATE_SCHEMA },
|
|
3369
|
-
{ name: "producer_installation_ref", value: isRecord5(value) ? value.producer_installation_ref : void 0, expected: installationRef }
|
|
3370
|
-
])}).`);
|
|
3371
|
-
}
|
|
3372
|
-
if (Number(value.producer_epoch) > epoch) throw new CodexHostAdapterError("storage", `Codex producer state epoch is ahead of this installation (${refusalFact("producer_epoch", value.producer_epoch, `at most ${epoch}`)}).`);
|
|
3373
|
-
const pending = {};
|
|
3374
|
-
for (const [submissionRef, frames] of Object.entries(value.pending)) {
|
|
3375
|
-
if (!SAFE_REF7.test(submissionRef) || !Array.isArray(frames) || frames.length === 0) throw new CodexHostAdapterError("storage", "Codex producer pending reservation is malformed.");
|
|
3376
|
-
pending[submissionRef] = frames.map((frame) => decodeStoredFrame(frame, installationRef, Number(value.producer_epoch)));
|
|
3377
|
-
}
|
|
3378
|
-
return { schema_version: STATE_SCHEMA, producer_installation_ref: installationRef, producer_epoch: epoch, next_sequence: Number(value.next_sequence), pending };
|
|
3379
|
-
}
|
|
3380
|
-
function validStateHeader(value, installationRef) {
|
|
3381
|
-
return isRecord5(value) && value.schema_version === STATE_SCHEMA && value.producer_installation_ref === installationRef && Number.isSafeInteger(value.producer_epoch) && Number(value.producer_epoch) > 0 && Number.isSafeInteger(value.next_sequence) && Number(value.next_sequence) > 0 && isRecord5(value.pending);
|
|
3382
|
-
}
|
|
3383
|
-
function decodeStoredFrame(value, installationRef, epoch) {
|
|
3384
|
-
const json = Buffer.from(JSON.stringify(value), "utf8");
|
|
3385
|
-
const encoded = Buffer.allocUnsafe(json.length + 4);
|
|
3386
|
-
encoded.writeUInt32BE(json.length, 0);
|
|
3387
|
-
json.copy(encoded, 4);
|
|
3388
|
-
const frame = decodeHostProducerFrame(encoded);
|
|
3389
|
-
if (frame.producer_id !== "codex" || frame.producer_installation_ref !== installationRef || frame.producer_epoch > epoch) throw new CodexHostAdapterError("storage", `Codex producer pending frame identity is malformed (${refusalFacts([
|
|
3390
|
-
{ name: "producer_id", value: frame.producer_id, expected: "codex" },
|
|
3391
|
-
{ name: "producer_installation_ref", value: frame.producer_installation_ref, expected: installationRef },
|
|
3392
|
-
{ name: "producer_epoch", value: frame.producer_epoch, expected: `at most ${epoch}` }
|
|
3393
|
-
])}).`);
|
|
3394
|
-
return frame;
|
|
6048
|
+
return SAFE_REF7.test(value) ? value : `reason:${createHash6("sha256").update(value, "utf8").digest("hex")}`;
|
|
3395
6049
|
}
|
|
3396
|
-
function
|
|
6050
|
+
function isRecord6(value) {
|
|
3397
6051
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3398
6052
|
}
|
|
3399
6053
|
|
|
3400
|
-
// host/codex/src/codex-transcript-watcher.ts
|
|
3401
|
-
import { createHash as createHash7 } from "node:crypto";
|
|
3402
|
-
import { O_NOFOLLOW as O_NOFOLLOW2, O_RDONLY as O_RDONLY3 } from "node:constants";
|
|
3403
|
-
import { open as open5 } from "node:fs/promises";
|
|
3404
|
-
|
|
3405
6054
|
// host/codex/src/codex-transcript-baseline.ts
|
|
3406
|
-
import { createHash as
|
|
6055
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
3407
6056
|
|
|
3408
6057
|
// host/codex/src/codex-transcript-decoder.ts
|
|
3409
6058
|
var SAFE_REF8 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u;
|
|
@@ -3415,40 +6064,40 @@ function decodeCodexTranscriptLine(line) {
|
|
|
3415
6064
|
} catch {
|
|
3416
6065
|
reject("Codex transcript record is not valid JSON.");
|
|
3417
6066
|
}
|
|
3418
|
-
if (!
|
|
6067
|
+
if (!isRecord7(value)) reject("Codex transcript record envelope is malformed.");
|
|
3419
6068
|
const ordinal = safeOrdinal(value.ordinal);
|
|
3420
|
-
const
|
|
3421
|
-
if (!
|
|
3422
|
-
if (value.type === "session_meta") return decodeSessionMeta(value.payload, ordinal,
|
|
3423
|
-
if (value.type === "turn_context") return decodeTurnContext(value.payload, ordinal,
|
|
3424
|
-
if (value.type === "event_msg") return decodeEventMessage(value.payload, ordinal,
|
|
3425
|
-
if (value.type === "response_item") return decodeResponseItem(value.payload, ordinal,
|
|
3426
|
-
return { kind: "ignored", ordinal, timestamp:
|
|
3427
|
-
}
|
|
3428
|
-
function decodeTurnContext(payload, ordinal,
|
|
6069
|
+
const timestamp4 = safeTimestamp(value.timestamp);
|
|
6070
|
+
if (!isRecord7(value.payload) || typeof value.type !== "string") reject("Codex transcript record payload is malformed.");
|
|
6071
|
+
if (value.type === "session_meta") return decodeSessionMeta(value.payload, ordinal, timestamp4);
|
|
6072
|
+
if (value.type === "turn_context") return decodeTurnContext(value.payload, ordinal, timestamp4);
|
|
6073
|
+
if (value.type === "event_msg") return decodeEventMessage(value.payload, ordinal, timestamp4);
|
|
6074
|
+
if (value.type === "response_item") return decodeResponseItem(value.payload, ordinal, timestamp4);
|
|
6075
|
+
return { kind: "ignored", ordinal, timestamp: timestamp4 };
|
|
6076
|
+
}
|
|
6077
|
+
function decodeTurnContext(payload, ordinal, timestamp4) {
|
|
3429
6078
|
return {
|
|
3430
6079
|
kind: "turn_context",
|
|
3431
6080
|
ordinal,
|
|
3432
|
-
timestamp:
|
|
3433
|
-
turn_id:
|
|
6081
|
+
timestamp: timestamp4,
|
|
6082
|
+
turn_id: safeRef5(payload.turn_id, "Codex turn context identity is invalid."),
|
|
3434
6083
|
model: boundedNonEmptyText(payload.model, 256, "Codex turn context model is invalid.")
|
|
3435
6084
|
};
|
|
3436
6085
|
}
|
|
3437
|
-
function decodeSessionMeta(payload, ordinal,
|
|
3438
|
-
const sessionId =
|
|
6086
|
+
function decodeSessionMeta(payload, ordinal, timestamp4) {
|
|
6087
|
+
const sessionId = safeRef5(payload.id, "Codex transcript session identity is invalid.");
|
|
3439
6088
|
const cliVersion = boundedNonEmptyText(payload.cli_version, 64, "Codex transcript version is invalid.");
|
|
3440
|
-
return { kind: "session_meta", ordinal, timestamp:
|
|
6089
|
+
return { kind: "session_meta", ordinal, timestamp: timestamp4, session_id: sessionId, cli_version: cliVersion };
|
|
3441
6090
|
}
|
|
3442
|
-
function decodeEventMessage(payload, ordinal,
|
|
6091
|
+
function decodeEventMessage(payload, ordinal, timestamp4) {
|
|
3443
6092
|
if (payload.type === "task_started") {
|
|
3444
|
-
return { kind: "task_started", ordinal, timestamp:
|
|
6093
|
+
return { kind: "task_started", ordinal, timestamp: timestamp4, turn_id: safeRef5(payload.turn_id, "Codex task identity is invalid."), started_at: safeNumber(payload.started_at) };
|
|
3445
6094
|
}
|
|
3446
6095
|
if (payload.type === "task_complete") {
|
|
3447
6096
|
return {
|
|
3448
6097
|
kind: "task_complete",
|
|
3449
6098
|
ordinal,
|
|
3450
|
-
timestamp:
|
|
3451
|
-
turn_id:
|
|
6099
|
+
timestamp: timestamp4,
|
|
6100
|
+
turn_id: safeRef5(payload.turn_id, "Codex task identity is invalid."),
|
|
3452
6101
|
started_at: safeNumber(payload.started_at),
|
|
3453
6102
|
completed_at: safeNumber(payload.completed_at),
|
|
3454
6103
|
duration_ms: safeNumber(payload.duration_ms),
|
|
@@ -3459,20 +6108,20 @@ function decodeEventMessage(payload, ordinal, timestamp5) {
|
|
|
3459
6108
|
return {
|
|
3460
6109
|
kind: "turn_aborted",
|
|
3461
6110
|
ordinal,
|
|
3462
|
-
timestamp:
|
|
3463
|
-
turn_id:
|
|
6111
|
+
timestamp: timestamp4,
|
|
6112
|
+
turn_id: safeRef5(payload.turn_id, "Codex task identity is invalid."),
|
|
3464
6113
|
started_at: safeNumber(payload.started_at),
|
|
3465
6114
|
completed_at: safeNumber(payload.completed_at),
|
|
3466
6115
|
duration_ms: safeNumber(payload.duration_ms),
|
|
3467
6116
|
reason: boundedText(payload.reason, 256, "Codex task abort reason is invalid.")
|
|
3468
6117
|
};
|
|
3469
6118
|
}
|
|
3470
|
-
if (payload.type === "token_count") return decodeTokenCount(payload, ordinal,
|
|
3471
|
-
return { kind: "ignored", ordinal, timestamp:
|
|
6119
|
+
if (payload.type === "token_count") return decodeTokenCount(payload, ordinal, timestamp4);
|
|
6120
|
+
return { kind: "ignored", ordinal, timestamp: timestamp4 };
|
|
3472
6121
|
}
|
|
3473
|
-
function decodeTokenCount(payload, ordinal,
|
|
3474
|
-
if (payload.info === null) return { kind: "token_count", ordinal, timestamp:
|
|
3475
|
-
if (!
|
|
6122
|
+
function decodeTokenCount(payload, ordinal, timestamp4) {
|
|
6123
|
+
if (payload.info === null) return { kind: "token_count", ordinal, timestamp: timestamp4 };
|
|
6124
|
+
if (!isRecord7(payload.info)) return { kind: "token_count", ordinal, timestamp: timestamp4, usage_gap_reason: "token_count_shape_not_attributable" };
|
|
3476
6125
|
const lastUsage = optionalTokenUsage(payload.info.last_token_usage);
|
|
3477
6126
|
const totalUsage = optionalTokenUsage(payload.info.total_token_usage);
|
|
3478
6127
|
const gap = lastUsage.status === "invalid" || totalUsage.status === "invalid";
|
|
@@ -3480,7 +6129,7 @@ function decodeTokenCount(payload, ordinal, timestamp5) {
|
|
|
3480
6129
|
return {
|
|
3481
6130
|
kind: "token_count",
|
|
3482
6131
|
ordinal,
|
|
3483
|
-
timestamp:
|
|
6132
|
+
timestamp: timestamp4,
|
|
3484
6133
|
...lastUsage.status === "valid" ? { last_usage: lastUsage.value } : {},
|
|
3485
6134
|
...totalUsage.status === "valid" ? { total_usage: totalUsage.value } : {},
|
|
3486
6135
|
...usageGapReason === void 0 ? {} : { usage_gap_reason: usageGapReason }
|
|
@@ -3496,7 +6145,7 @@ function optionalTokenUsage(value) {
|
|
|
3496
6145
|
}
|
|
3497
6146
|
}
|
|
3498
6147
|
function decodeTokenUsage(value) {
|
|
3499
|
-
if (!
|
|
6148
|
+
if (!isRecord7(value)) reject("Codex token usage is malformed.");
|
|
3500
6149
|
const usage = {
|
|
3501
6150
|
input_tokens: safeTokenCount(value.input_tokens),
|
|
3502
6151
|
cached_input_tokens: safeTokenCount(value.cached_input_tokens),
|
|
@@ -3508,20 +6157,20 @@ function decodeTokenUsage(value) {
|
|
|
3508
6157
|
if (usage.total_tokens !== usage.input_tokens + usage.output_tokens || usage.cached_input_tokens + usage.cache_write_input_tokens > usage.input_tokens || usage.reasoning_output_tokens > usage.output_tokens) reject("Codex token usage buckets are inconsistent.");
|
|
3509
6158
|
return usage;
|
|
3510
6159
|
}
|
|
3511
|
-
function decodeResponseItem(payload, ordinal,
|
|
3512
|
-
if (payload.type !== "message" || payload.role !== "user") return { kind: "ignored", ordinal, timestamp:
|
|
6160
|
+
function decodeResponseItem(payload, ordinal, timestamp4) {
|
|
6161
|
+
if (payload.type !== "message" || payload.role !== "user") return { kind: "ignored", ordinal, timestamp: timestamp4 };
|
|
3513
6162
|
const metadata = userMessageMetadata(payload.internal_chat_message_metadata_passthrough);
|
|
3514
6163
|
const inputKind = inputKindFromContentItems(metadata.content_item_kinds);
|
|
3515
|
-
if (inputKind === void 0) return { kind: "ignored", ordinal, timestamp:
|
|
6164
|
+
if (inputKind === void 0) return { kind: "ignored", ordinal, timestamp: timestamp4 };
|
|
3516
6165
|
const prompt = userTextContent(payload.content);
|
|
3517
6166
|
return {
|
|
3518
6167
|
kind: "user_text",
|
|
3519
6168
|
ordinal,
|
|
3520
|
-
timestamp:
|
|
6169
|
+
timestamp: timestamp4,
|
|
3521
6170
|
prompt,
|
|
3522
6171
|
input_kind: inputKind,
|
|
3523
|
-
message_id:
|
|
3524
|
-
turn_id:
|
|
6172
|
+
message_id: safeRef5(payload.id, "Codex user message identity is invalid."),
|
|
6173
|
+
turn_id: safeRef5(metadata.turn_id, "Codex user message task identity is invalid.")
|
|
3525
6174
|
};
|
|
3526
6175
|
}
|
|
3527
6176
|
function inputKindFromContentItems(kinds) {
|
|
@@ -3530,13 +6179,13 @@ function inputKindFromContentItems(kinds) {
|
|
|
3530
6179
|
return kinds[0] === "goal.internal_context" ? "host_automatic" : void 0;
|
|
3531
6180
|
}
|
|
3532
6181
|
function userMessageMetadata(value) {
|
|
3533
|
-
if (!
|
|
6182
|
+
if (!isRecord7(value) || !Array.isArray(value.content_item_kinds)) reject("Codex user message provenance is malformed.");
|
|
3534
6183
|
return { ...value, content_item_kinds: value.content_item_kinds };
|
|
3535
6184
|
}
|
|
3536
6185
|
function userTextContent(value) {
|
|
3537
6186
|
if (!Array.isArray(value)) reject(`Codex user text content is malformed (${refusalFact("kind", typeof value, "array")}).`);
|
|
3538
6187
|
if (value.length !== 1) reject(`Codex user text content is malformed (${refusalFact("items", value.length, "exactly one")}).`);
|
|
3539
|
-
if (!
|
|
6188
|
+
if (!isRecord7(value[0]) || value[0].type !== "input_text") reject(`Codex user text content is malformed (${refusalFact("item_type", isRecord7(value[0]) ? value[0].type : typeof value[0], "input_text")}).`);
|
|
3540
6189
|
return boundedText(value[0].text, MAX_PROMPT_BYTES, "Codex user text is invalid.");
|
|
3541
6190
|
}
|
|
3542
6191
|
function safeOrdinal(value) {
|
|
@@ -3557,7 +6206,7 @@ function safeTimestamp(value) {
|
|
|
3557
6206
|
if (!Number.isFinite(Date.parse(value))) reject(`Codex transcript timestamp is invalid (${refusalFact("parsed_ms", Date.parse(value), "a finite epoch milliseconds value")}).`);
|
|
3558
6207
|
return value;
|
|
3559
6208
|
}
|
|
3560
|
-
function
|
|
6209
|
+
function safeRef5(value, message) {
|
|
3561
6210
|
if (typeof value !== "string" || !SAFE_REF8.test(value)) reject(message);
|
|
3562
6211
|
return value;
|
|
3563
6212
|
}
|
|
@@ -3572,7 +6221,7 @@ function boundedNonEmptyText(value, maximum, message) {
|
|
|
3572
6221
|
if (result.length === 0) reject(message);
|
|
3573
6222
|
return result;
|
|
3574
6223
|
}
|
|
3575
|
-
function
|
|
6224
|
+
function isRecord7(value) {
|
|
3576
6225
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3577
6226
|
}
|
|
3578
6227
|
function reject(message) {
|
|
@@ -3616,7 +6265,7 @@ function assertCodexTranscriptHeader(registration, record3) {
|
|
|
3616
6265
|
])}).`);
|
|
3617
6266
|
}
|
|
3618
6267
|
function digest(value) {
|
|
3619
|
-
return
|
|
6268
|
+
return createHash7("sha256").update(value).digest("hex");
|
|
3620
6269
|
}
|
|
3621
6270
|
function timestamp3(now) {
|
|
3622
6271
|
const value = now();
|
|
@@ -3632,78 +6281,53 @@ function codexSubmissionReference(hostInputRef, event, ordinal) {
|
|
|
3632
6281
|
}
|
|
3633
6282
|
|
|
3634
6283
|
// host/codex/src/codex-transcript-watcher.ts
|
|
3635
|
-
var
|
|
3636
|
-
var TRANSCRIPT_MISSING_REASON = "transcript_missing";
|
|
3637
|
-
var CodexTranscriptWatcher = class {
|
|
6284
|
+
var CodexTranscriptWatcher = class extends HostTranscriptWatcher {
|
|
3638
6285
|
store;
|
|
3639
|
-
outboxRetentionMs;
|
|
3640
|
-
now;
|
|
3641
|
-
log;
|
|
3642
|
-
producerInstallationRef;
|
|
3643
6286
|
registerCurrentPrompt;
|
|
6287
|
+
releaseCurrentPrompt;
|
|
6288
|
+
diagnostic;
|
|
3644
6289
|
constructor(options) {
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
this.log = options.log ?? ((line) => {
|
|
3650
|
-
process.stderr.write(`${line}
|
|
3651
|
-
`);
|
|
6290
|
+
super(options, {
|
|
6291
|
+
default_retention_ms: CODEX_DEFAULT_RETENTION_MS,
|
|
6292
|
+
invalid_outbox: () => new CodexHostAdapterError("configuration", "Codex transcript watcher outbox is invalid."),
|
|
6293
|
+
clock_failure: () => new CodexHostAdapterError("storage", "Codex watcher clock is invalid.")
|
|
3652
6294
|
});
|
|
3653
|
-
this.
|
|
6295
|
+
this.store = new CodexOutboxStore(options.outbox_dir);
|
|
3654
6296
|
this.registerCurrentPrompt = options.register_current_prompt;
|
|
6297
|
+
this.releaseCurrentPrompt = options.release_current_prompt;
|
|
6298
|
+
this.diagnostic = options.diagnostic ?? (() => void 0);
|
|
3655
6299
|
}
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
let records = 0;
|
|
3659
|
-
let enqueued = 0;
|
|
3660
|
-
let quarantined = 0;
|
|
3661
|
-
for (const registration of registrations) {
|
|
3662
|
-
const result = await this.scanRegistration(registration);
|
|
3663
|
-
records += result.records;
|
|
3664
|
-
enqueued += result.enqueued;
|
|
3665
|
-
if (result.quarantined) quarantined += 1;
|
|
3666
|
-
}
|
|
3667
|
-
return { registrations: registrations.length, records, enqueued, quarantined };
|
|
6300
|
+
transcriptPathOf(registration) {
|
|
6301
|
+
return registration.transcript_path;
|
|
3668
6302
|
}
|
|
3669
|
-
async
|
|
3670
|
-
|
|
3671
|
-
try {
|
|
3672
|
-
handle = await open5(registration.transcript_path, O_RDONLY3 | O_NOFOLLOW2);
|
|
3673
|
-
const { size, device, inode } = await ownedCodexTranscriptFile(handle);
|
|
3674
|
-
const preflight = await this.preflight(registration, handle, size, device, inode);
|
|
3675
|
-
if (preflight.cursor === null) return preflight.result;
|
|
3676
|
-
const complete = await readCompleteChunk(handle, preflight.cursor, size);
|
|
3677
|
-
if (complete === "empty" || complete === "partial") return { records: 0, enqueued: 0, quarantined: false };
|
|
3678
|
-
return await this.consumeCompleteChunk(registration, handle, preflight.cursor, complete, device, inode);
|
|
3679
|
-
} catch (error) {
|
|
3680
|
-
if (handle === void 0 && isMissingTranscript(error)) return await this.retireRegistration(registration);
|
|
3681
|
-
await this.quarantineFailure(registration, handle);
|
|
3682
|
-
return { records: 0, enqueued: 0, quarantined: true };
|
|
3683
|
-
} finally {
|
|
3684
|
-
await handle?.close();
|
|
3685
|
-
}
|
|
6303
|
+
async listRegistrations() {
|
|
6304
|
+
return this.store.listTranscriptRegistrations();
|
|
3686
6305
|
}
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
6306
|
+
async scanOpened(handle, registration) {
|
|
6307
|
+
const { size, device, inode } = await ownedCodexTranscriptFile(handle);
|
|
6308
|
+
const preflight = await this.preflight(registration, handle, size, device, inode);
|
|
6309
|
+
if (preflight.cursor === null) return preflight.result;
|
|
6310
|
+
const complete = await this.readChunk(handle, preflight.cursor.offset, size);
|
|
6311
|
+
if (complete === "empty" || complete === "partial") return { records: 0, enqueued: 0, quarantined: false };
|
|
6312
|
+
return await this.consumeCompleteChunk(registration, handle, preflight.cursor, complete, device, inode);
|
|
6313
|
+
}
|
|
6314
|
+
async scanFailed(handle, registration, error) {
|
|
6315
|
+
this.diagnostic("watcher_scan_failed", codexTranscriptScanFailureKind(error));
|
|
6316
|
+
await this.quarantineFailure(registration, handle);
|
|
6317
|
+
return { records: 0, enqueued: 0, quarantined: true };
|
|
6318
|
+
}
|
|
6319
|
+
async retireMissing(registration) {
|
|
6320
|
+
await this.releaseStoredPromptBestEffort(registration.host_session_ref, await this.store.readTranscriptCursor(registration).catch(() => null));
|
|
6321
|
+
return this.retireMissingTranscript(registration.transcript_path, "Codex", () => this.store.retireTranscriptRegistration(registration));
|
|
3701
6322
|
}
|
|
3702
6323
|
async preflight(registration, handle, size, device, inode) {
|
|
3703
6324
|
const existing = await this.store.readTranscriptCursor(registration);
|
|
3704
6325
|
let cursor = existing ?? codexTranscriptInitialCursor(registration, device, inode, this.now);
|
|
3705
|
-
if (cursor.status === "quarantined")
|
|
3706
|
-
|
|
6326
|
+
if (cursor.status === "quarantined") {
|
|
6327
|
+
if (cursor.reason !== "transcript_malformed") await this.releaseStoredPromptBestEffort(registration.host_session_ref, cursor);
|
|
6328
|
+
return { cursor: null, result: { records: 0, enqueued: 0, quarantined: true } };
|
|
6329
|
+
}
|
|
6330
|
+
const reason = this.cursorIdentityReason(cursor, registration.transcript_path, device, inode) ?? await this.cursorBoundsReason(handle, cursor, size);
|
|
3707
6331
|
if (reason === null) return { cursor, result: { records: 0, enqueued: 0, quarantined: false } };
|
|
3708
6332
|
await this.quarantine(registration, cursor, device, inode, reason);
|
|
3709
6333
|
return { cursor: null, result: { records: 0, enqueued: 0, quarantined: true } };
|
|
@@ -3729,39 +6353,53 @@ var CodexTranscriptWatcher = class {
|
|
|
3729
6353
|
async observeSessionMetadata(registration, record3) {
|
|
3730
6354
|
if (record3.kind !== "session_meta") return;
|
|
3731
6355
|
const session = await this.store.readSession(registration.host_source_ref, registration.host_session_ref);
|
|
3732
|
-
if (session !== null &&
|
|
6356
|
+
if (session !== null && this.isRecord(session.value)) await this.store.saveSession({ ...session, value: { ...session.value, host_version: record3.cli_version } });
|
|
3733
6357
|
}
|
|
3734
6358
|
async commitCursor(registration, handle, cursor, consumedBytes, device, inode, lastOrdinal, activeTask) {
|
|
3735
6359
|
const offset = cursor.offset + consumedBytes;
|
|
3736
|
-
const
|
|
3737
|
-
|
|
3738
|
-
if (anchor.length > 0) await handle.read(anchor, 0, anchor.length, anchorStart);
|
|
3739
|
-
await this.store.writeTranscriptCursor({ schema_version: "ceal.codex_transcript_cursor.v1", host_source_ref: registration.host_source_ref, host_session_ref: registration.host_session_ref, transcript_path: registration.transcript_path, device, inode, offset, last_ordinal: lastOrdinal, anchor_start: anchorStart, anchor_sha256: sha2562(anchor), header_validated: true, ...activeTask === void 0 ? {} : { active_task: activeTask }, status: "active", updated_at: timestamp4(this.now) });
|
|
6360
|
+
const anchor = await this.readAnchor(handle, offset, CODEX_TRANSCRIPT_ANCHOR_BYTES);
|
|
6361
|
+
await this.store.writeTranscriptCursor({ schema_version: "ceal.codex_transcript_cursor.v1", host_source_ref: registration.host_source_ref, host_session_ref: registration.host_session_ref, transcript_path: registration.transcript_path, device, inode, offset, last_ordinal: lastOrdinal, anchor_start: anchor.start, anchor_sha256: anchor.sha256, header_validated: true, ...activeTask === void 0 ? {} : { active_task: activeTask }, status: "active", updated_at: this.stamp() });
|
|
3740
6362
|
}
|
|
3741
6363
|
async quarantineFailure(registration, handle) {
|
|
3742
6364
|
if (handle === void 0) return;
|
|
3743
6365
|
const stats = await handle.stat().catch(() => null);
|
|
3744
6366
|
if (stats === null) return;
|
|
3745
6367
|
const existing = await this.store.readTranscriptCursor(registration).catch(() => null);
|
|
3746
|
-
|
|
6368
|
+
const quarantined = {
|
|
6369
|
+
...existing ?? codexTranscriptInitialCursor(registration, String(stats.dev), String(stats.ino), this.now),
|
|
6370
|
+
transcript_path: registration.transcript_path,
|
|
6371
|
+
device: String(stats.dev),
|
|
6372
|
+
inode: String(stats.ino),
|
|
6373
|
+
status: "quarantined",
|
|
6374
|
+
reason: "transcript_malformed",
|
|
6375
|
+
updated_at: this.stamp()
|
|
6376
|
+
};
|
|
6377
|
+
await this.store.writeTranscriptCursor(quarantined);
|
|
3747
6378
|
}
|
|
3748
6379
|
async processRecord(registration, activeTask, record3) {
|
|
3749
|
-
if (record3.kind === "task_started")
|
|
3750
|
-
return { activeTask: { codex_turn_id: record3.turn_id, host_turn_ref: hostTurnReference(registration.host_source_ref, registration.host_session_ref, record3.turn_id), started_at: record3.timestamp }, enqueued: 0 };
|
|
3751
|
-
}
|
|
6380
|
+
if (record3.kind === "task_started") return this.processTaskStarted(registration, activeTask, record3);
|
|
3752
6381
|
if (record3.kind === "turn_context") return { ...activeTask === void 0 ? {} : { activeTask: record3.turn_id === activeTask.codex_turn_id ? { ...activeTask, model: record3.model } : activeTask }, enqueued: 0 };
|
|
3753
6382
|
if (record3.kind === "token_count") return { ...activeTask === void 0 ? {} : { activeTask: accumulateTokenCount(activeTask, record3) }, enqueued: 0 };
|
|
3754
6383
|
if (record3.kind === "user_text") return this.processUserInput(registration, activeTask, record3);
|
|
3755
6384
|
if (record3.kind === "task_complete" || record3.kind === "turn_aborted") return this.processTerminal(registration, activeTask, record3);
|
|
3756
6385
|
return { ...activeTask === void 0 ? {} : { activeTask }, enqueued: 0 };
|
|
3757
6386
|
}
|
|
6387
|
+
async processTaskStarted(registration, activeTask, record3) {
|
|
6388
|
+
if (activeTask !== void 0 && activeTask.codex_turn_id !== record3.turn_id && activeTask.prompt_ref !== void 0) await this.releasePrompt(registration.host_session_ref, activeTask, activeTask.prompt_ref);
|
|
6389
|
+
return { activeTask: { codex_turn_id: record3.turn_id, host_turn_ref: hostTurnReference(registration.host_source_ref, registration.host_session_ref, record3.turn_id), started_at: record3.timestamp }, enqueued: 0 };
|
|
6390
|
+
}
|
|
3758
6391
|
async processUserInput(registration, activeTask, record3) {
|
|
3759
|
-
if (activeTask === void 0 || activeTask.codex_turn_id !== record3.turn_id)
|
|
6392
|
+
if (activeTask === void 0 || activeTask.codex_turn_id !== record3.turn_id) {
|
|
6393
|
+
const adopted = await this.adoptHookCorrelatedTurn(registration, activeTask, record3);
|
|
6394
|
+
if (adopted === void 0) return { ...activeTask === void 0 ? {} : { activeTask }, enqueued: 0 };
|
|
6395
|
+
activeTask = adopted;
|
|
6396
|
+
}
|
|
3760
6397
|
const hostInputRef = hostInputReference(registration.host_source_ref, registration.host_session_ref, record3.turn_id, record3.message_id, record3.ordinal, record3.prompt);
|
|
3761
6398
|
const origin = activeTask.origin_host_input_ref === void 0;
|
|
3762
6399
|
const promptValue = promptObservationValue(record3.prompt);
|
|
3763
6400
|
const currentPromptRef = hostProducerPromptRef(promptValue.body_sha256);
|
|
3764
6401
|
const promptRef = activeTask.prompt_ref ?? currentPromptRef;
|
|
6402
|
+
const steeredPromptRef = await this.steeredPromptRef(registration, activeTask, origin, currentPromptRef);
|
|
3765
6403
|
const identity = { host_source_ref: registration.host_source_ref, host_session_ref: registration.host_session_ref, host_turn_ref: activeTask.host_turn_ref };
|
|
3766
6404
|
const observations = [{
|
|
3767
6405
|
observation_ref: observationRef("transcript_user_text", hostInputRef, record3.prompt),
|
|
@@ -3785,16 +6423,90 @@ var CodexTranscriptWatcher = class {
|
|
|
3785
6423
|
origin_input: origin,
|
|
3786
6424
|
submission_ref: codexSubmissionReference(hostInputRef, "input", record3.ordinal),
|
|
3787
6425
|
created_at: record3.timestamp,
|
|
3788
|
-
expires_at:
|
|
6426
|
+
expires_at: this.expire(this.outboxRetentionMs)
|
|
6427
|
+
};
|
|
6428
|
+
const persisted = await this.persistUserInputTurn(registration, activeTask, record3, hostInputRef, origin, currentPromptRef, promptRef, identity, envelope);
|
|
6429
|
+
if (steeredPromptRef !== null) await this.activateTranscriptTurnContext(identity, steeredPromptRef, envelope.expires_at);
|
|
6430
|
+
return persisted;
|
|
6431
|
+
}
|
|
6432
|
+
/**
|
|
6433
|
+
* The steered prompt to re-activate under the running task, or null when
|
|
6434
|
+
* there is nothing to repair. A steered message joins the running turn
|
|
6435
|
+
* with new prompt bytes but no task_started. When the steer hook already
|
|
6436
|
+
* replaced the turn selection (a turn id the hook did not recognize as
|
|
6437
|
+
* the running one, or a hook that ran before any context was live), the
|
|
6438
|
+
* running task's context no longer matches and the next invocation would
|
|
6439
|
+
* wait for a boundary that never comes. When the hook kept the live
|
|
6440
|
+
* selection, the context still matches and this stays null.
|
|
6441
|
+
*/
|
|
6442
|
+
async steeredPromptRef(registration, activeTask, origin, currentPromptRef) {
|
|
6443
|
+
if (origin || activeTask.prompt_ref === void 0 || activeTask.prompt_ref === currentPromptRef) return null;
|
|
6444
|
+
const selection = await this.store.readInvocationTurnSelection(registration.host_source_ref, registration.host_session_ref).catch(() => null);
|
|
6445
|
+
return selection?.prompt_ref === currentPromptRef ? currentPromptRef : null;
|
|
6446
|
+
}
|
|
6447
|
+
/**
|
|
6448
|
+
* Adopt the live hooked turn when its transcript message arrives before
|
|
6449
|
+
* (or without) its task_started, as an interrupted turn's follow-up can.
|
|
6450
|
+
* The UserPromptSubmit hook names the exact hooked prompt, so only a
|
|
6451
|
+
* message carrying those bytes adopts; inherited history and other turns
|
|
6452
|
+
* stay ignored. A stale active task for another turn releases first, the
|
|
6453
|
+
* same as a task_started supersession.
|
|
6454
|
+
*/
|
|
6455
|
+
async adoptHookCorrelatedTurn(registration, activeTask, record3) {
|
|
6456
|
+
const currentPromptRef = hostProducerPromptRef(promptObservationValue(record3.prompt).body_sha256);
|
|
6457
|
+
const selection = await this.store.readInvocationTurnSelection(registration.host_source_ref, registration.host_session_ref);
|
|
6458
|
+
if (selection?.prompt_ref !== currentPromptRef) return void 0;
|
|
6459
|
+
if (activeTask !== void 0 && activeTask.codex_turn_id !== record3.turn_id && activeTask.prompt_ref !== void 0) {
|
|
6460
|
+
await this.releasePrompt(registration.host_session_ref, activeTask, activeTask.prompt_ref);
|
|
6461
|
+
}
|
|
6462
|
+
return {
|
|
6463
|
+
codex_turn_id: record3.turn_id,
|
|
6464
|
+
host_turn_ref: hostTurnReference(registration.host_source_ref, registration.host_session_ref, record3.turn_id),
|
|
6465
|
+
started_at: record3.timestamp
|
|
3789
6466
|
};
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
6467
|
+
}
|
|
6468
|
+
async persistUserInputTurn(registration, activeTask, record3, hostInputRef, origin, currentPromptRef, promptRef, identity, envelope) {
|
|
6469
|
+
const custodyRegistered = await this.registerPrompt(origin, registration, activeTask, currentPromptRef, record3.prompt, envelope.expires_at);
|
|
6470
|
+
if (custodyRegistered) this.diagnostic("watcher_turn_observed");
|
|
6471
|
+
try {
|
|
6472
|
+
await this.store.put(envelope);
|
|
6473
|
+
if (origin) await this.activateTranscriptTurnContext(identity, promptRef, envelope.expires_at);
|
|
6474
|
+
} catch (error) {
|
|
6475
|
+
if (custodyRegistered) await this.releasePrompt(registration.host_session_ref, activeTask, currentPromptRef).catch(() => void 0);
|
|
6476
|
+
throw error;
|
|
6477
|
+
}
|
|
3793
6478
|
return { activeTask: { ...activeTask, origin_host_input_ref: activeTask.origin_host_input_ref ?? hostInputRef, prompt_ref: activeTask.prompt_ref ?? currentPromptRef }, enqueued: 1 };
|
|
3794
6479
|
}
|
|
3795
6480
|
async registerPrompt(origin, registration, activeTask, promptRef, prompt, expiresAt) {
|
|
3796
|
-
if (!origin || this.producerInstallationRef === void 0 || this.registerCurrentPrompt === void 0) return;
|
|
3797
|
-
|
|
6481
|
+
if (!origin || this.producerInstallationRef === void 0 || this.registerCurrentPrompt === void 0) return false;
|
|
6482
|
+
const register = this.registerCurrentPrompt;
|
|
6483
|
+
const installationRef = this.producerInstallationRef;
|
|
6484
|
+
return registerHostCurrentPromptDiagnosed(
|
|
6485
|
+
() => register({ producer_id: "codex", producer_installation_ref: installationRef, local_session_ref: registration.host_session_ref, local_turn_ref: activeTask.host_turn_ref, prompt_ref: promptRef, current_prompt: prompt, context_expires_at: expiresAt }),
|
|
6486
|
+
(event) => this.diagnostic(event)
|
|
6487
|
+
);
|
|
6488
|
+
}
|
|
6489
|
+
async activateTranscriptTurnContext(identity, promptRef, expiresAt) {
|
|
6490
|
+
try {
|
|
6491
|
+
const selection = await this.store.readInvocationTurnSelection(identity.host_source_ref, identity.host_session_ref);
|
|
6492
|
+
const turnGenerationRef = selection?.prompt_ref === promptRef ? selection.turn_generation_ref : void 0;
|
|
6493
|
+
await this.store.activateInvocationContext(identity, promptRef, expiresAt, turnGenerationRef);
|
|
6494
|
+
this.diagnostic("activation_recorded");
|
|
6495
|
+
} catch (error) {
|
|
6496
|
+
this.diagnostic("activation_failed");
|
|
6497
|
+
throw error;
|
|
6498
|
+
}
|
|
6499
|
+
}
|
|
6500
|
+
async releasePrompt(sessionRef, activeTask, promptRef) {
|
|
6501
|
+
if (this.producerInstallationRef === void 0 || this.releaseCurrentPrompt === void 0) return;
|
|
6502
|
+
await this.releaseCurrentPrompt({ producer_id: "codex", producer_installation_ref: this.producerInstallationRef, local_session_ref: sessionRef, local_turn_ref: activeTask.host_turn_ref, prompt_ref: promptRef });
|
|
6503
|
+
}
|
|
6504
|
+
async releaseStoredPromptBestEffort(sessionRef, cursor) {
|
|
6505
|
+
await this.releaseActiveTaskBestEffort(sessionRef, cursor?.active_task);
|
|
6506
|
+
}
|
|
6507
|
+
async releaseActiveTaskBestEffort(sessionRef, activeTask) {
|
|
6508
|
+
if (activeTask?.prompt_ref === void 0) return;
|
|
6509
|
+
await this.releasePrompt(sessionRef, activeTask, activeTask.prompt_ref).catch(() => void 0);
|
|
3798
6510
|
}
|
|
3799
6511
|
async processTerminal(registration, activeTask, record3) {
|
|
3800
6512
|
if (activeTask === void 0 || activeTask.codex_turn_id !== record3.turn_id || activeTask.origin_host_input_ref === void 0 || activeTask.prompt_ref === void 0) return { ...activeTask === void 0 ? {} : { activeTask }, enqueued: 0 };
|
|
@@ -3812,16 +6524,26 @@ var CodexTranscriptWatcher = class {
|
|
|
3812
6524
|
origin_input: false,
|
|
3813
6525
|
submission_ref: codexSubmissionReference(activeTask.origin_host_input_ref, "terminal", record3.ordinal),
|
|
3814
6526
|
created_at: record3.timestamp,
|
|
3815
|
-
expires_at:
|
|
6527
|
+
expires_at: this.expire(this.outboxRetentionMs)
|
|
3816
6528
|
});
|
|
6529
|
+
await this.releasePrompt(registration.host_session_ref, activeTask, activeTask.prompt_ref);
|
|
3817
6530
|
await this.store.clearInvocationContext(identity, this.now());
|
|
3818
6531
|
return { enqueued: 1 };
|
|
3819
6532
|
}
|
|
3820
6533
|
async quarantine(registration, cursor, device, inode, reason) {
|
|
3821
|
-
|
|
6534
|
+
await this.releaseStoredPromptBestEffort(registration.host_session_ref, cursor);
|
|
6535
|
+
const quarantined = { ...cursor, transcript_path: registration.transcript_path, device, inode, status: "quarantined", reason, updated_at: this.stamp() };
|
|
3822
6536
|
await this.store.writeTranscriptCursor(quarantined);
|
|
3823
6537
|
}
|
|
3824
6538
|
};
|
|
6539
|
+
function codexTranscriptScanFailureKind(error) {
|
|
6540
|
+
return transcriptScanFailureKind(error, (candidate) => {
|
|
6541
|
+
if (!(candidate instanceof CodexHostAdapterError)) return void 0;
|
|
6542
|
+
if (candidate.code === "payload_rejected") return "payload_rejected";
|
|
6543
|
+
if (candidate.code === "storage") return "read_error";
|
|
6544
|
+
return void 0;
|
|
6545
|
+
});
|
|
6546
|
+
}
|
|
3825
6547
|
function accumulateTokenCount(activeTask, record3) {
|
|
3826
6548
|
if (record3.usage_gap_reason !== void 0) return { ...activeTask, token_usage_gap_reason: record3.usage_gap_reason };
|
|
3827
6549
|
const last = record3.last_usage;
|
|
@@ -3855,19 +6577,18 @@ function terminalCostValue() {
|
|
|
3855
6577
|
return notRecorded("provider_cost_not_observed");
|
|
3856
6578
|
}
|
|
3857
6579
|
function notRecorded(reason) {
|
|
3858
|
-
return
|
|
6580
|
+
return hostObservationNotRecorded(reason);
|
|
3859
6581
|
}
|
|
3860
6582
|
function tokenObservationValue(usage) {
|
|
3861
6583
|
return {
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
source: "codex_transcript.event_msg.token_count.info.last_token_usage",
|
|
6584
|
+
...createHostTokenObservationValue({
|
|
6585
|
+
input: usage.input_tokens,
|
|
6586
|
+
output: usage.output_tokens,
|
|
6587
|
+
total: usage.total_tokens,
|
|
6588
|
+
cached_input: usage.cached_input_tokens,
|
|
6589
|
+
cache_write_input: usage.cache_write_input_tokens,
|
|
6590
|
+
reasoning_output: usage.reasoning_output_tokens
|
|
6591
|
+
}, "codex_transcript.event_msg.token_count.info.last_token_usage"),
|
|
3871
6592
|
attribution: "sequential_active_task",
|
|
3872
6593
|
total_usage_role: "dedup_and_reset_detection_only"
|
|
3873
6594
|
};
|
|
@@ -3901,65 +6622,24 @@ function looksLikeStaleRegression(current, previous, last) {
|
|
|
3901
6622
|
if (previous.total_tokens <= 0 || current.total_tokens <= 0 || last.total_tokens <= 0) return false;
|
|
3902
6623
|
return current.total_tokens * 100 >= previous.total_tokens * 98 || current.total_tokens + last.total_tokens * 2 >= previous.total_tokens;
|
|
3903
6624
|
}
|
|
3904
|
-
function isMissingTranscript(error) {
|
|
3905
|
-
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
3906
|
-
}
|
|
3907
|
-
async function cursorFailureReason(registration, handle, cursor, size, device, inode) {
|
|
3908
|
-
if (cursor.device !== device || cursor.inode !== inode || cursor.transcript_path !== registration.transcript_path) return "transcript_replaced";
|
|
3909
|
-
if (size < cursor.offset) return "transcript_truncated";
|
|
3910
|
-
if (cursor.offset > 0 && !await anchorMatches(handle, cursor)) return "transcript_rewritten";
|
|
3911
|
-
return null;
|
|
3912
|
-
}
|
|
3913
|
-
async function readCompleteChunk(handle, cursor, size) {
|
|
3914
|
-
const available = Math.max(0, size - cursor.offset);
|
|
3915
|
-
if (available === 0) return "empty";
|
|
3916
|
-
const chunks = [];
|
|
3917
|
-
let position = cursor.offset;
|
|
3918
|
-
let total = 0;
|
|
3919
|
-
let lastNewline = -1;
|
|
3920
|
-
while (position < size) {
|
|
3921
|
-
const buffer = Buffer.alloc(Math.min(READ_CHUNK_BYTES, size - position));
|
|
3922
|
-
const read = await handle.read(buffer, 0, buffer.length, position);
|
|
3923
|
-
if (read.bytesRead === 0) break;
|
|
3924
|
-
const chunk = buffer.subarray(0, read.bytesRead);
|
|
3925
|
-
chunks.push(chunk);
|
|
3926
|
-
const newline = chunk.lastIndexOf(10);
|
|
3927
|
-
if (newline >= 0) lastNewline = total + newline;
|
|
3928
|
-
total += chunk.length;
|
|
3929
|
-
position += chunk.length;
|
|
3930
|
-
if (lastNewline >= 0) break;
|
|
3931
|
-
}
|
|
3932
|
-
if (lastNewline < 0) return "partial";
|
|
3933
|
-
return Buffer.concat(chunks, total).subarray(0, lastNewline + 1);
|
|
3934
|
-
}
|
|
3935
6625
|
function assertRecordSequence(registration, cursor, records, lastOrdinal, record3) {
|
|
3936
6626
|
if ((cursor.header_validated || records > 0) && record3.ordinal <= lastOrdinal) throw new CodexHostAdapterError("payload_rejected", `Codex transcript ordinal is not monotonic (${refusalFact("ordinal", record3.ordinal, `greater than ${lastOrdinal}`)}).`);
|
|
3937
6627
|
if (!cursor.header_validated && records === 0) assertCodexTranscriptHeader(registration, record3);
|
|
3938
6628
|
}
|
|
3939
|
-
async function anchorMatches(handle, cursor) {
|
|
3940
|
-
const buffer = Buffer.alloc(cursor.offset - cursor.anchor_start);
|
|
3941
|
-
if (buffer.length > 0) await handle.read(buffer, 0, buffer.length, cursor.anchor_start);
|
|
3942
|
-
return sha2562(buffer) === cursor.anchor_sha256;
|
|
3943
|
-
}
|
|
3944
|
-
function sha2562(value) {
|
|
3945
|
-
return createHash7("sha256").update(value).digest("hex");
|
|
3946
|
-
}
|
|
3947
|
-
function isRecord7(value) {
|
|
3948
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3949
|
-
}
|
|
3950
|
-
function timestamp4(now) {
|
|
3951
|
-
const value = now();
|
|
3952
|
-
if (!Number.isFinite(value.getTime())) throw new CodexHostAdapterError("storage", "Codex watcher clock is invalid.");
|
|
3953
|
-
return value.toISOString();
|
|
3954
|
-
}
|
|
3955
|
-
function expiration(now, retentionMs) {
|
|
3956
|
-
return new Date(Date.parse(timestamp4(now)) + retentionMs).toISOString();
|
|
3957
|
-
}
|
|
3958
6629
|
|
|
3959
6630
|
// host/codex/src/codex-producer-runtime.ts
|
|
3960
6631
|
async function drainCodexProducerOnce(options) {
|
|
3961
6632
|
const promptPort = new HostRelayCurrentPromptPort(options.relay_endpoint, options.timeout_ms);
|
|
3962
|
-
const scan = await new CodexTranscriptWatcher({
|
|
6633
|
+
const scan = await new CodexTranscriptWatcher({
|
|
6634
|
+
outbox_dir: options.outbox_dir,
|
|
6635
|
+
producer_installation_ref: options.producer_installation_ref,
|
|
6636
|
+
register_current_prompt: (input) => promptPort.register(input),
|
|
6637
|
+
release_current_prompt: (identity) => promptPort.release(identity),
|
|
6638
|
+
diagnostic: (event, failure_kind) => writeHostServiceDiagnostic("codex", event, failure_kind)
|
|
6639
|
+
}).scanOnce().catch((error) => {
|
|
6640
|
+
writeHostServiceDiagnostic("codex", "watcher_scan_failed", codexTranscriptScanFailureKind(error));
|
|
6641
|
+
throw error;
|
|
6642
|
+
});
|
|
3963
6643
|
const producer = new CodexProducer({ outbox_dir: options.outbox_dir, producer_installation_ref: options.producer_installation_ref, relay: new HostRelayIpcAdmissionPort(options.relay_endpoint, options.timeout_ms), ...options.producer_epoch === void 0 ? {} : { producer_epoch: options.producer_epoch }, ...options.now === void 0 ? {} : { now: options.now } });
|
|
3964
6644
|
return { scanned: scan.enqueued, ...await producer.drainOutbox() };
|
|
3965
6645
|
}
|
|
@@ -3982,15 +6662,52 @@ var CODEX_PRODUCER_DESCRIPTOR = {
|
|
|
3982
6662
|
drain: drainCodexProducerOnce
|
|
3983
6663
|
};
|
|
3984
6664
|
|
|
6665
|
+
// host/codex/src/codex-visible-output-budget.ts
|
|
6666
|
+
import { readFile as readFile3 } from "node:fs/promises";
|
|
6667
|
+
import { homedir } from "node:os";
|
|
6668
|
+
import { join as join5 } from "node:path";
|
|
6669
|
+
var import_toml = __toESM(require_toml(), 1);
|
|
6670
|
+
var CODEX_DEFAULT_TOOL_OUTPUT_TOKEN_LIMIT = 5e3;
|
|
6671
|
+
var CODEX_UTF8_BYTES_PER_OUTPUT_TOKEN = 4;
|
|
6672
|
+
async function resolveCodexVisibleOutputMaxBytes(environment = process.env) {
|
|
6673
|
+
const codexHome = environment.CODEX_HOME || join5(homedir(), ".codex");
|
|
6674
|
+
let source;
|
|
6675
|
+
try {
|
|
6676
|
+
source = await readFile3(join5(codexHome, "config.toml"), "utf8");
|
|
6677
|
+
} catch (error) {
|
|
6678
|
+
return isNotFound2(error) ? codexBytes(CODEX_DEFAULT_TOOL_OUTPUT_TOKEN_LIMIT) : void 0;
|
|
6679
|
+
}
|
|
6680
|
+
try {
|
|
6681
|
+
const parsed = import_toml.default.parse(source);
|
|
6682
|
+
if (!isRecord8(parsed)) return void 0;
|
|
6683
|
+
const configured = parsed.tool_output_token_limit;
|
|
6684
|
+
if (configured === void 0) return codexBytes(CODEX_DEFAULT_TOOL_OUTPUT_TOKEN_LIMIT);
|
|
6685
|
+
return typeof configured === "number" && Number.isSafeInteger(configured) && configured > 0 ? codexBytes(configured) : void 0;
|
|
6686
|
+
} catch {
|
|
6687
|
+
return void 0;
|
|
6688
|
+
}
|
|
6689
|
+
}
|
|
6690
|
+
function codexBytes(tokens) {
|
|
6691
|
+
return Math.min(tokens * CODEX_UTF8_BYTES_PER_OUTPUT_TOKEN, CEAL_CANONICAL_HTTP_MAX_RESPONSE_BYTES);
|
|
6692
|
+
}
|
|
6693
|
+
function isRecord8(value) {
|
|
6694
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
6695
|
+
}
|
|
6696
|
+
function isNotFound2(error) {
|
|
6697
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
6698
|
+
}
|
|
6699
|
+
|
|
3985
6700
|
// host/codex/src/codex-invocation-authentication-command.ts
|
|
3986
6701
|
var CODEX_INVOCATION_AUTHENTICATION_DESCRIPTOR = {
|
|
3987
6702
|
producer_id: "codex",
|
|
6703
|
+
context_activation_wait_max_ms: CODEX_CONTEXT_ACTIVATION_WAIT_MAX_MS,
|
|
3988
6704
|
create_store: (directory) => new CodexOutboxStore(directory),
|
|
3989
6705
|
session_id_env: CODEX_THREAD_ID_ENVIRONMENT,
|
|
3990
6706
|
session_ref: hostSessionReference,
|
|
3991
6707
|
config_flag: HOST_PRODUCER_CONFIG_FLAG,
|
|
3992
6708
|
parse_config_flag: parseHostProducerConfigFlag,
|
|
3993
|
-
read_producer_config: (configPath) => readHostProducerConfig(CODEX_PRODUCER_DESCRIPTOR, configPath)
|
|
6709
|
+
read_producer_config: (configPath) => readHostProducerConfig(CODEX_PRODUCER_DESCRIPTOR, configPath),
|
|
6710
|
+
resolve_visible_output_max_bytes: () => resolveCodexVisibleOutputMaxBytes()
|
|
3994
6711
|
};
|
|
3995
6712
|
function runCodexInvocationAuthenticationCommand(args, options) {
|
|
3996
6713
|
return runHostInvocationAuthenticationCommand(CODEX_INVOCATION_AUTHENTICATION_DESCRIPTOR, args, options);
|