@corca-org/ceal-host-linux-arm64 1.0.18 → 1.0.19
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 +1924 -522
- package/libexec/ceal-host/claude-invocation-authentication.mjs +1806 -330
- package/libexec/ceal-host/claude-producer.mjs +1773 -412
- package/libexec/ceal-host/codex-hook.mjs +1427 -1013
- package/libexec/ceal-host/codex-invocation-authentication.mjs +3071 -515
- package/libexec/ceal-host/codex-producer.mjs +815 -439
- package/libexec/ceal-host/control.mjs +2266 -1095
- package/libexec/ceal-host/relay.mjs +468 -103
- 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"]);
|
|
@@ -973,6 +3032,7 @@ var CEAL_ACTIVITY_TIMESTAMP_BASES = vocabulary([
|
|
|
973
3032
|
"resource_modified"
|
|
974
3033
|
]);
|
|
975
3034
|
var CEAL_ACTIVITY_CONNECTOR_KINDS = vocabulary(["slack", "github", "google-calendar", "google-drive", "notion"]);
|
|
3035
|
+
var CEAL_ACTIVITY_UNSUPPORTED_EVENT_KIND_CODE = "unsupported_event_kind";
|
|
976
3036
|
var CEAL_ACTIVITY_GAP_CODES = vocabulary([
|
|
977
3037
|
"provider_page_budget",
|
|
978
3038
|
"call_deadline",
|
|
@@ -980,7 +3040,7 @@ var CEAL_ACTIVITY_GAP_CODES = vocabulary([
|
|
|
980
3040
|
"provider_cursor_unavailable",
|
|
981
3041
|
"malformed_provider_page",
|
|
982
3042
|
"visibility_incomplete",
|
|
983
|
-
|
|
3043
|
+
CEAL_ACTIVITY_UNSUPPORTED_EVENT_KIND_CODE,
|
|
984
3044
|
"direct_messages_excluded"
|
|
985
3045
|
]);
|
|
986
3046
|
var CEAL_ACTIVITY_EVENT_KINDS = vocabulary([
|
|
@@ -1045,6 +3105,8 @@ var RESOURCE_ROW_KEY_RULES = Object.freeze({
|
|
|
1045
3105
|
modified_at: { required: false, timestamp: true },
|
|
1046
3106
|
modified_at_local: { required: false, timestamp: true },
|
|
1047
3107
|
viewed_by_me_at: { required: false, timestamp: true },
|
|
3108
|
+
own_ceal_write: { required: false, timestamp: false },
|
|
3109
|
+
owned_by_me: { required: false, timestamp: false },
|
|
1048
3110
|
visibility: { required: false, timestamp: false },
|
|
1049
3111
|
start: { required: false, timestamp: false },
|
|
1050
3112
|
end: { required: false, timestamp: false },
|
|
@@ -1078,6 +3140,15 @@ function cealExcludedTargetCoverageJsonSchema() {
|
|
|
1078
3140
|
};
|
|
1079
3141
|
}
|
|
1080
3142
|
|
|
3143
|
+
// packages/ceal-client-protocol/src/gateway-write-identity.ts
|
|
3144
|
+
var CEAL_GATEWAY_WRITE_IDENTITY_ROLES = Object.freeze(["replay_identity", "lookup_handle", "collision_evidence"]);
|
|
3145
|
+
var CEAL_GATEWAY_WRITE_REQUEST_REF_PATTERN = /^gateway-write-request:[a-f0-9]{8}-(?:[a-f0-9]{4}-){3}[a-f0-9]{12}$/u;
|
|
3146
|
+
var CEAL_GATEWAY_WRITE_IDENTITY_FIELDS = Object.freeze({
|
|
3147
|
+
replay_identity: "idempotency_claim_sha256",
|
|
3148
|
+
lookup_handle: "write_request_sha256",
|
|
3149
|
+
collision_evidence: "normalized_mutation_sha256"
|
|
3150
|
+
});
|
|
3151
|
+
|
|
1081
3152
|
// packages/ceal-client-protocol/src/write-safety-finding.ts
|
|
1082
3153
|
var CEAL_WRITE_SAFETY_FINDING_STATUSES = vocabulary(["warning", "unchecked"]);
|
|
1083
3154
|
var CEAL_WRITE_SAFETY_AUDIENCES = vocabulary(["workspace", "person", "members", "unknown"]);
|
|
@@ -1105,7 +3176,11 @@ var CEAL_REFRESH_FAILURE_CODES = vocabulary([
|
|
|
1105
3176
|
"refresh_revoked",
|
|
1106
3177
|
"authority_replaced",
|
|
1107
3178
|
"refresh_recovery_unavailable",
|
|
1108
|
-
"refresh_recovery_expired"
|
|
3179
|
+
"refresh_recovery_expired",
|
|
3180
|
+
// The serving gate answers this while the Gateway is still starting and the
|
|
3181
|
+
// refresh was never attempted; the same attempt stays retryable. It is never
|
|
3182
|
+
// stored by the session owner, only answered at the serving edge.
|
|
3183
|
+
"gateway_starting"
|
|
1109
3184
|
]);
|
|
1110
3185
|
|
|
1111
3186
|
// packages/ceal-client-protocol/src/request-validation-primitives.ts
|
|
@@ -1138,7 +3213,7 @@ var CANCELLATION_STATES = vocabulary(["requested", "cancelled"]);
|
|
|
1138
3213
|
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
3214
|
var CEAL_REQUEST_JSON_SCHEMA = {
|
|
1140
3215
|
type: "object",
|
|
1141
|
-
maxProperties:
|
|
3216
|
+
maxProperties: 11,
|
|
1142
3217
|
additionalProperties: false,
|
|
1143
3218
|
properties: {
|
|
1144
3219
|
schema_version: { type: "string", const: CEAL_REQUEST_SCHEMA_VERSION, maxLength: 32 },
|
|
@@ -1162,7 +3237,8 @@ var CEAL_REQUEST_JSON_SCHEMA = {
|
|
|
1162
3237
|
host_turn_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
|
|
1163
3238
|
host_input_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
|
|
1164
3239
|
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." }
|
|
3240
|
+
requester_timezone: { type: "string", minLength: 1, maxLength: 128, description: "IANA timezone observed for the requester on this Request." },
|
|
3241
|
+
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
3242
|
},
|
|
1167
3243
|
required: CEAL_REQUEST_KEYS
|
|
1168
3244
|
};
|
|
@@ -1221,6 +3297,7 @@ var REQUEST_EXECUTION_PREPARE_REFUSAL_PROPERTIES = {
|
|
|
1221
3297
|
retryable: { type: "boolean" },
|
|
1222
3298
|
source: { type: "string", enum: ["provider", "gateway"] },
|
|
1223
3299
|
retry_after_ms: { type: "integer", minimum: 0, maximum: CEAL_RETRY_AFTER_MAX_MS },
|
|
3300
|
+
write_request_ref: { type: "string", pattern: CEAL_GATEWAY_WRITE_REQUEST_REF_PATTERN.source, maxLength: 128 },
|
|
1224
3301
|
excluded_targets: cealExcludedTargetCoverageJsonSchema(),
|
|
1225
3302
|
repaired_input: {},
|
|
1226
3303
|
unrepaired_pointers: { type: "array", maxItems: 128, items: { type: "string", minLength: 1, maxLength: 256 } },
|
|
@@ -1285,6 +3362,43 @@ function cealHostObservationRef(producer, digest2) {
|
|
|
1285
3362
|
if (!HOST_OBSERVATION_PRODUCER.test(producer) || !HOST_OBSERVATION_DIGEST.test(digest2)) invalid("Ceal Host observation reference parts are invalid.");
|
|
1286
3363
|
return `${CEAL_HOST_OBSERVATION_REF_PREFIX}${producer}-${digest2}`;
|
|
1287
3364
|
}
|
|
3365
|
+
var HOST_TOKEN_OBSERVATION_BREAKDOWN_KEYS = vocabulary(["cached_input", "cache_write_input", "reasoning_output"]);
|
|
3366
|
+
function createHostTokenObservationValue(counts, source) {
|
|
3367
|
+
const core = validTokenCore(counts);
|
|
3368
|
+
if (typeof source !== "string" || source.length === 0 || source.length > 256) invalid("Ceal Host token observation source is invalid.");
|
|
3369
|
+
const value = { status: "available", unit: "tokens", input: core.input, output: core.output, total: core.total, source };
|
|
3370
|
+
for (const breakdown of validTokenBreakdowns(counts)) value[breakdown.key] = breakdown.tokens;
|
|
3371
|
+
assertHostObservationValue(value, "token");
|
|
3372
|
+
return value;
|
|
3373
|
+
}
|
|
3374
|
+
function validTokenCore(counts) {
|
|
3375
|
+
if (!isOperationRecord(counts) || !safeCount(counts.input) || !safeCount(counts.output) || !safeCount(counts.total)) invalid("Ceal Host token observation counts are invalid.");
|
|
3376
|
+
if (counts.total !== counts.input + counts.output) invalid("Ceal Host token observation counts are invalid.");
|
|
3377
|
+
return { input: counts.input, output: counts.output, total: counts.total };
|
|
3378
|
+
}
|
|
3379
|
+
function validTokenBreakdowns(counts) {
|
|
3380
|
+
const breakdowns = [
|
|
3381
|
+
{ key: "cached_input", tokens: counts.cached_input },
|
|
3382
|
+
{ key: "cache_write_input", tokens: counts.cache_write_input },
|
|
3383
|
+
{ key: "reasoning_output", tokens: counts.reasoning_output }
|
|
3384
|
+
];
|
|
3385
|
+
const stated = breakdowns.filter((breakdown) => breakdown.tokens !== void 0).map((breakdown) => ({ key: breakdown.key, tokens: Number(breakdown.tokens) }));
|
|
3386
|
+
for (const breakdown of stated) {
|
|
3387
|
+
if (!safeCount(breakdown.tokens)) invalid("Ceal Host token observation counts are invalid.");
|
|
3388
|
+
}
|
|
3389
|
+
const cached = counts.cached_input ?? 0;
|
|
3390
|
+
const created = counts.cache_write_input ?? 0;
|
|
3391
|
+
const reasoning = counts.reasoning_output ?? 0;
|
|
3392
|
+
if (cached + created > counts.input || reasoning > counts.output) invalid("Ceal Host token observation counts are invalid.");
|
|
3393
|
+
return stated;
|
|
3394
|
+
}
|
|
3395
|
+
function hostObservationNotRecorded(reason) {
|
|
3396
|
+
if (typeof reason !== "string" || reason.length === 0 || reason.length > 256) invalid("Ceal Host observation gap reason is invalid.");
|
|
3397
|
+
return { status: "not_recorded", reason };
|
|
3398
|
+
}
|
|
3399
|
+
function safeCount(value) {
|
|
3400
|
+
return Number.isSafeInteger(value) && Number(value) >= 0;
|
|
3401
|
+
}
|
|
1288
3402
|
function validateCealHostObservationDraft(value) {
|
|
1289
3403
|
const record3 = operationRecord(value, "Ceal Host observation draft is invalid.");
|
|
1290
3404
|
requirePrefixedRef(record3.observation_ref, CEAL_HOST_OBSERVATION_REF_PREFIX, "Ceal Host observation reference is invalid.");
|
|
@@ -1437,6 +3551,55 @@ var CEAL_HOST_MINT_REQUEST_CONTEXT_REFUSAL_REASONS = vocabulary([
|
|
|
1437
3551
|
"host_input_mismatch",
|
|
1438
3552
|
"host_prompt_mismatch"
|
|
1439
3553
|
]);
|
|
3554
|
+
var CEAL_HOST_AUTHENTICATION_CAUSES = vocabulary([
|
|
3555
|
+
"invalid_arguments",
|
|
3556
|
+
"options_invalid",
|
|
3557
|
+
"session_unavailable",
|
|
3558
|
+
"context_unavailable",
|
|
3559
|
+
"context_replaced",
|
|
3560
|
+
"no_binding",
|
|
3561
|
+
"context_stale",
|
|
3562
|
+
"context_expired",
|
|
3563
|
+
"host_source_refused",
|
|
3564
|
+
"host_credential_refused",
|
|
3565
|
+
"gateway_unavailable",
|
|
3566
|
+
"gateway_rate_limited",
|
|
3567
|
+
"gateway_refused",
|
|
3568
|
+
"gateway_response_invalid",
|
|
3569
|
+
"producer_frame_invalid",
|
|
3570
|
+
"relay_permission_denied",
|
|
3571
|
+
"relay_unavailable",
|
|
3572
|
+
"transient_retryable",
|
|
3573
|
+
"mint_failed",
|
|
3574
|
+
"relay_failed",
|
|
3575
|
+
"host_refusal_invalid"
|
|
3576
|
+
]);
|
|
3577
|
+
var CEAL_HOST_AUTHENTICATION_POLICY = Object.freeze({
|
|
3578
|
+
invalid_arguments: Object.freeze({ classification: "host_arguments_invalid", next_action: "answer_with_gap" }),
|
|
3579
|
+
options_invalid: Object.freeze({ classification: "host_configuration_invalid", next_action: "answer_with_gap" }),
|
|
3580
|
+
session_unavailable: Object.freeze({ classification: "host_session_unavailable", next_action: "answer_with_gap" }),
|
|
3581
|
+
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; run `ceal-host install` to repair the Host hook registration, then retry this command on a fresh Host turn" }),
|
|
3582
|
+
context_replaced: Object.freeze({ classification: "host_invocation_context_stale", next_action: "refresh_host_invocation_context" }),
|
|
3583
|
+
no_binding: Object.freeze({ classification: "host_binding_unavailable", next_action: "refresh_host_invocation_context" }),
|
|
3584
|
+
context_stale: Object.freeze({ classification: "host_invocation_context_stale", next_action: "refresh_host_invocation_context" }),
|
|
3585
|
+
context_expired: Object.freeze({ classification: "host_invocation_context_expired", next_action: "refresh_host_invocation_context" }),
|
|
3586
|
+
host_source_refused: Object.freeze({ classification: "host_source_refused", next_action: "answer_with_gap" }),
|
|
3587
|
+
host_credential_refused: Object.freeze({ classification: "host_registration_credential_refused", next_action: "ask_admin" }),
|
|
3588
|
+
gateway_unavailable: Object.freeze({ classification: "host_mint_gateway_unavailable", next_action: "ask_admin" }),
|
|
3589
|
+
gateway_rate_limited: Object.freeze({ classification: "host_mint_gateway_rate_limited", next_action: "answer_with_gap" }),
|
|
3590
|
+
gateway_refused: Object.freeze({ classification: "host_mint_gateway_refused", next_action: "answer_with_gap" }),
|
|
3591
|
+
gateway_response_invalid: Object.freeze({ classification: "host_mint_gateway_response_invalid", next_action: "answer_with_gap" }),
|
|
3592
|
+
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" }),
|
|
3593
|
+
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" }),
|
|
3594
|
+
relay_unavailable: Object.freeze({ classification: "host_relay_unavailable", next_action: "answer_with_gap" }),
|
|
3595
|
+
transient_retryable: Object.freeze({ classification: "host_mint_transient_retryable", next_action: "retry" }),
|
|
3596
|
+
mint_failed: Object.freeze({ classification: "host_mint_failed", next_action: "answer_with_gap" }),
|
|
3597
|
+
relay_failed: Object.freeze({ classification: "host_relay_failed", next_action: "answer_with_gap" }),
|
|
3598
|
+
host_refusal_invalid: Object.freeze({ classification: "host_refusal_invalid", next_action: "answer_with_gap" })
|
|
3599
|
+
});
|
|
3600
|
+
function isCealHostAuthenticationCause(value) {
|
|
3601
|
+
return isVocabularyWord(CEAL_HOST_AUTHENTICATION_CAUSES, value);
|
|
3602
|
+
}
|
|
1440
3603
|
function decodeCealHostInvocationAuthenticationRequest(value) {
|
|
1441
3604
|
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
3605
|
throw new TypeError("The Host invocation authentication request is invalid.");
|
|
@@ -1450,19 +3613,45 @@ function decodeCealHostInvocationAuthenticationResult(value, now = /* @__PURE__
|
|
|
1450
3613
|
return Object.freeze({ schema_version: CEAL_HOST_INVOCATION_AUTHENTICATION_RESULT_SCHEMA, context_token: value.context_token, expires_at: value.expires_at });
|
|
1451
3614
|
}
|
|
1452
3615
|
function validFutureTimestamp(value, now) {
|
|
1453
|
-
const
|
|
1454
|
-
return Number.isFinite(
|
|
3616
|
+
const timestamp4 = Date.parse(value);
|
|
3617
|
+
return Number.isFinite(timestamp4) && new Date(timestamp4).toISOString() === value && timestamp4 > now.getTime();
|
|
1455
3618
|
}
|
|
1456
3619
|
function exactKeys(value, expected) {
|
|
1457
3620
|
const keys = Object.keys(value);
|
|
1458
3621
|
return keys.length === expected.length && expected.every((key) => Object.hasOwn(value, key));
|
|
1459
3622
|
}
|
|
1460
3623
|
|
|
3624
|
+
// packages/ceal-client-protocol/src/host-service-diagnostic.ts
|
|
3625
|
+
var CEAL_HOST_SERVICE_DIAGNOSTIC_SCHEMA = "ceal.host_service_diagnostic.v1";
|
|
3626
|
+
var CEAL_HOST_SERVICE_DIAGNOSTIC_PRODUCERS = vocabulary(["claude", "codex"]);
|
|
3627
|
+
var CEAL_HOST_SERVICE_DIAGNOSTIC_EVENTS = vocabulary([
|
|
3628
|
+
"hook_invoked",
|
|
3629
|
+
"registration_written",
|
|
3630
|
+
"hook_failed",
|
|
3631
|
+
"watcher_turn_observed",
|
|
3632
|
+
"current_prompt_registered",
|
|
3633
|
+
"current_prompt_registration_failed",
|
|
3634
|
+
"activation_recorded",
|
|
3635
|
+
"activation_failed",
|
|
3636
|
+
"watcher_scan_failed",
|
|
3637
|
+
"activation_wait_skipped",
|
|
3638
|
+
"activation_wait_engaged",
|
|
3639
|
+
"activation_wait_completed",
|
|
3640
|
+
"activation_wait_exhausted"
|
|
3641
|
+
]);
|
|
3642
|
+
var CEAL_HOST_SERVICE_DIAGNOSTIC_FAILURE_KINDS = vocabulary([
|
|
3643
|
+
"malformed_line",
|
|
3644
|
+
"other",
|
|
3645
|
+
"payload_rejected",
|
|
3646
|
+
"read_error",
|
|
3647
|
+
"size_budget",
|
|
3648
|
+
"symlink"
|
|
3649
|
+
]);
|
|
3650
|
+
|
|
1461
3651
|
// packages/ceal-client-protocol/src/client-result-materialization.ts
|
|
1462
3652
|
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"]);
|
|
3653
|
+
var REQUIRED_FIELDS2 = Object.freeze(["schema_version", "operation_id", "path", "sha256"]);
|
|
3654
|
+
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
3655
|
|
|
1467
3656
|
// packages/ceal-client-protocol/src/gateway-cache-origin-validation.ts
|
|
1468
3657
|
var CEAL_MAX_CACHE_ORIGIN_AGE_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
@@ -1492,14 +3681,6 @@ var CEAL_GATEWAY_ANNOUNCEMENT_POLICY_NON_CLAIMS = vocabulary([
|
|
|
1492
3681
|
"target_specific_scope_not_declared"
|
|
1493
3682
|
]);
|
|
1494
3683
|
|
|
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
3684
|
// packages/ceal-client-protocol/src/gateway-scoped-identity-projection-validation.ts
|
|
1504
3685
|
var PROJECTION_REVISION_KEYS = Object.freeze(["graph_revision", "subject_key_revision", "projection_revision"]);
|
|
1505
3686
|
|
|
@@ -1512,6 +3693,18 @@ var CEAL_SUPPORTED_GATEWAY_PROTOCOL_RANGE = Object.freeze({
|
|
|
1512
3693
|
// packages/ceal-client-protocol/src/admin-projection-vocabulary.ts
|
|
1513
3694
|
var ADMIN_PROJECTION_STATES = vocabulary(["ready", "empty", "partial", "unknown"]);
|
|
1514
3695
|
var ADMIN_VIEW_KINDS = vocabulary(["request_detail", "resource_access_timeline", "weekly_usage"]);
|
|
3696
|
+
var ADMIN_RECORD_PROJECTION_KINDS = vocabulary([
|
|
3697
|
+
"request_list",
|
|
3698
|
+
"usage_series",
|
|
3699
|
+
"connector_health",
|
|
3700
|
+
"person_connections",
|
|
3701
|
+
"client_sessions",
|
|
3702
|
+
"knowledge_base",
|
|
3703
|
+
"change_history",
|
|
3704
|
+
"approval_queue",
|
|
3705
|
+
"access_group_list",
|
|
3706
|
+
"capability_catalogue"
|
|
3707
|
+
]);
|
|
1515
3708
|
var ADMIN_GAP_KINDS = vocabulary(["unknown", "unavailable", "partial"]);
|
|
1516
3709
|
var ADMIN_UNAVAILABLE_REASONS = vocabulary([
|
|
1517
3710
|
"not_recorded",
|
|
@@ -1535,7 +3728,11 @@ var ADMIN_SOURCE_OWNERS = vocabulary([
|
|
|
1535
3728
|
"person",
|
|
1536
3729
|
"resource",
|
|
1537
3730
|
"prompt",
|
|
1538
|
-
"usage"
|
|
3731
|
+
"usage",
|
|
3732
|
+
"connector",
|
|
3733
|
+
"session",
|
|
3734
|
+
"knowledge",
|
|
3735
|
+
"policy"
|
|
1539
3736
|
]);
|
|
1540
3737
|
var ADMIN_COMPLETENESS_STATES = vocabulary(["complete", "partial", "unknown"]);
|
|
1541
3738
|
var ADMIN_OPERATION_OUTCOMES = vocabulary(["completed", "failed", "denied", "cancelled", "unknown"]);
|
|
@@ -1813,6 +4010,9 @@ async function doctorCodexClient(options = {}) {
|
|
|
1813
4010
|
return { schema_version: CODEX_CLIENT_DOCTOR_SCHEMA_VERSION, ...await doctorClient(options, "Codex") };
|
|
1814
4011
|
}
|
|
1815
4012
|
|
|
4013
|
+
// host/invocation-authentication-command.ts
|
|
4014
|
+
import { performance } from "node:perf_hooks";
|
|
4015
|
+
|
|
1816
4016
|
// host/relay/src/producer-frame.ts
|
|
1817
4017
|
var HOST_PRODUCER_FRAME_SCHEMA = "ceal.host_producer_frame.v1";
|
|
1818
4018
|
var HOST_PRODUCER_MAX_JSON_BYTES = 262144;
|
|
@@ -1824,6 +4024,15 @@ var FRAME_KINDS = new Set(HOST_PRODUCER_FRAME_KINDS);
|
|
|
1824
4024
|
function isHostProducerFrameKind(value) {
|
|
1825
4025
|
return typeof value === "string" && FRAME_KINDS.has(value);
|
|
1826
4026
|
}
|
|
4027
|
+
var HOST_PRODUCER_FRAME_ERROR_CODES = [
|
|
4028
|
+
"invalid_frame_encoding",
|
|
4029
|
+
"invalid_frame_length",
|
|
4030
|
+
"frame_truncated",
|
|
4031
|
+
"unsupported_frame_schema",
|
|
4032
|
+
"invalid_frame_shape",
|
|
4033
|
+
"invalid_producer_identity",
|
|
4034
|
+
"frame_too_large"
|
|
4035
|
+
];
|
|
1827
4036
|
var HostProducerFrameError = class extends Error {
|
|
1828
4037
|
code;
|
|
1829
4038
|
constructor(code, message = code) {
|
|
@@ -1858,6 +4067,9 @@ function decodeHostProducerFrame(input) {
|
|
|
1858
4067
|
validateFrame(value);
|
|
1859
4068
|
return value;
|
|
1860
4069
|
}
|
|
4070
|
+
function isHostSafeRef(value) {
|
|
4071
|
+
return safeRef(value);
|
|
4072
|
+
}
|
|
1861
4073
|
function validateFrame(value) {
|
|
1862
4074
|
if (!record(value)) throw new HostProducerFrameError("invalid_frame_shape");
|
|
1863
4075
|
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 +4157,15 @@ function exactOptional(value, required, optional) {
|
|
|
1945
4157
|
return required.every((key) => keys.includes(key)) && keys.every((key) => required.includes(key) || optional.includes(key));
|
|
1946
4158
|
}
|
|
1947
4159
|
|
|
4160
|
+
// host/relay/src/host-producer-core.ts
|
|
4161
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
4162
|
+
import { O_NOFOLLOW, O_RDONLY as O_RDONLY2 } from "node:constants";
|
|
4163
|
+
import { mkdir as mkdir2, open as open3, readFile as readFile2, rename as rename2, writeFile } from "node:fs/promises";
|
|
4164
|
+
import { join as join3 } from "node:path";
|
|
4165
|
+
|
|
4166
|
+
// host/relay/src/relay-ipc.ts
|
|
4167
|
+
import { createConnection, createServer } from "node:net";
|
|
4168
|
+
|
|
1948
4169
|
// host/relay/src/durable-atomic-replacement.ts
|
|
1949
4170
|
import { O_RDONLY } from "node:constants";
|
|
1950
4171
|
import { lstat, mkdir, open as open2, rename, unlink } from "node:fs/promises";
|
|
@@ -1962,17 +4183,6 @@ var DEFAULT_PORT = {
|
|
|
1962
4183
|
// host/relay/src/relay-request-binding-store.ts
|
|
1963
4184
|
var MAX_STATE_BYTES = 8 * 1024 * 1024;
|
|
1964
4185
|
|
|
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
4186
|
// host/relay/src/current-prompt-custody.ts
|
|
1977
4187
|
var HOST_CURRENT_PROMPT_MAX_BYTES = 256 * 1024;
|
|
1978
4188
|
|
|
@@ -2008,6 +4218,8 @@ var HOST_RELAY_INVOCATION_MINT_REFUSAL_REASONS = vocabulary([
|
|
|
2008
4218
|
"gateway_unavailable",
|
|
2009
4219
|
"gateway_refused",
|
|
2010
4220
|
"gateway_response_invalid",
|
|
4221
|
+
"gateway_rate_limited",
|
|
4222
|
+
"producer_frame_invalid",
|
|
2011
4223
|
"deadline",
|
|
2012
4224
|
"cancelled",
|
|
2013
4225
|
"mint_failed",
|
|
@@ -2021,6 +4233,17 @@ var HOST_RELAY_INVOCATION_MINT_REFUSAL_REASONS = vocabulary([
|
|
|
2021
4233
|
"host_input_mismatch",
|
|
2022
4234
|
"host_prompt_mismatch"
|
|
2023
4235
|
]);
|
|
4236
|
+
var HOST_RELAY_DIRECT_WIRE_MINT_REASONS = vocabulary([
|
|
4237
|
+
"context_stale",
|
|
4238
|
+
"context_expired",
|
|
4239
|
+
"host_source_refused",
|
|
4240
|
+
"host_credential_refused",
|
|
4241
|
+
"gateway_unavailable",
|
|
4242
|
+
"gateway_rate_limited",
|
|
4243
|
+
"gateway_refused",
|
|
4244
|
+
"gateway_response_invalid",
|
|
4245
|
+
"producer_frame_invalid"
|
|
4246
|
+
]);
|
|
2024
4247
|
var HOST_RELAY_INVOCATION_MINT_OUTCOMES = vocabulary(["completed", "caller_cancelled", "deadline", "failed", "no_binding"]);
|
|
2025
4248
|
var HOST_RELAY_EXCHANGE_FAILURES = vocabulary([
|
|
2026
4249
|
"permission_denied",
|
|
@@ -2192,11 +4415,14 @@ function encodeInvocationContextQuery(query) {
|
|
|
2192
4415
|
return encodeLengthPrefixed(value);
|
|
2193
4416
|
}
|
|
2194
4417
|
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);
|
|
4418
|
+
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
4419
|
}
|
|
2197
4420
|
function validQueryIdentity(value, schema) {
|
|
2198
4421
|
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
4422
|
}
|
|
4423
|
+
function validVisibleOutputBudget(value) {
|
|
4424
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value > 0 && value <= CEAL_CANONICAL_HTTP_MAX_RESPONSE_BYTES;
|
|
4425
|
+
}
|
|
2200
4426
|
function validInvocationContextResponse(value) {
|
|
2201
4427
|
if (!record2(value) || value.schema_version !== HOST_RELAY_INVOCATION_CONTEXT_RESULT_SCHEMA) return false;
|
|
2202
4428
|
if (value.status === "no_binding") return Object.keys(value).length === 2;
|
|
@@ -2209,53 +4435,398 @@ function validInvocationContextResponse(value) {
|
|
|
2209
4435
|
return false;
|
|
2210
4436
|
}
|
|
2211
4437
|
}
|
|
2212
|
-
function decodeLengthPrefixedJson(input, maximum) {
|
|
2213
|
-
if (input.length < HOST_RELAY_IPC_LENGTH_BYTES) return null;
|
|
2214
|
-
const length = input.readUInt32BE(0);
|
|
2215
|
-
if (length === 0 || length > maximum) throw new HostRelayIpcError("relay_unavailable", `Host Relay IPC message length is invalid: ${refusalFact("declared_bytes", length, `between 1 and ${maximum}`)}.`);
|
|
2216
|
-
if (input.length < length + HOST_RELAY_IPC_LENGTH_BYTES) return null;
|
|
2217
|
-
if (input.length !== length + HOST_RELAY_IPC_LENGTH_BYTES) throw new HostRelayIpcError("relay_unavailable", `Host Relay IPC message has trailing bytes: ${refusalFacts([{ name: "declared_bytes", value: length, expected: `the received message length minus ${HOST_RELAY_IPC_LENGTH_BYTES}` }, { name: "received_bytes", value: input.byteLength, expected: `exactly ${length + HOST_RELAY_IPC_LENGTH_BYTES}` }])}.`);
|
|
4438
|
+
function decodeLengthPrefixedJson(input, maximum) {
|
|
4439
|
+
if (input.length < HOST_RELAY_IPC_LENGTH_BYTES) return null;
|
|
4440
|
+
const length = input.readUInt32BE(0);
|
|
4441
|
+
if (length === 0 || length > maximum) throw new HostRelayIpcError("relay_unavailable", `Host Relay IPC message length is invalid: ${refusalFact("declared_bytes", length, `between 1 and ${maximum}`)}.`);
|
|
4442
|
+
if (input.length < length + HOST_RELAY_IPC_LENGTH_BYTES) return null;
|
|
4443
|
+
if (input.length !== length + HOST_RELAY_IPC_LENGTH_BYTES) throw new HostRelayIpcError("relay_unavailable", `Host Relay IPC message has trailing bytes: ${refusalFacts([{ name: "declared_bytes", value: length, expected: `the received message length minus ${HOST_RELAY_IPC_LENGTH_BYTES}` }, { name: "received_bytes", value: input.byteLength, expected: `exactly ${length + HOST_RELAY_IPC_LENGTH_BYTES}` }])}.`);
|
|
4444
|
+
try {
|
|
4445
|
+
return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(input.subarray(HOST_RELAY_IPC_LENGTH_BYTES)));
|
|
4446
|
+
} catch {
|
|
4447
|
+
throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC message is invalid.");
|
|
4448
|
+
}
|
|
4449
|
+
}
|
|
4450
|
+
function encodeLengthPrefixed(value) {
|
|
4451
|
+
const body = Buffer.from(JSON.stringify(value), "utf8");
|
|
4452
|
+
const output = Buffer.allocUnsafe(body.length + HOST_RELAY_IPC_LENGTH_BYTES);
|
|
4453
|
+
output.writeUInt32BE(body.length, 0);
|
|
4454
|
+
body.copy(output, HOST_RELAY_IPC_LENGTH_BYTES);
|
|
4455
|
+
return output;
|
|
4456
|
+
}
|
|
4457
|
+
function exactKeys3(value, required, optional = []) {
|
|
4458
|
+
const keys = Object.keys(value);
|
|
4459
|
+
return required.every((key) => Object.hasOwn(value, key)) && keys.every((key) => required.includes(key) || optional.includes(key));
|
|
4460
|
+
}
|
|
4461
|
+
function safeRef2(value) {
|
|
4462
|
+
return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(value);
|
|
4463
|
+
}
|
|
4464
|
+
function errorCode2(error) {
|
|
4465
|
+
return record2(error) && typeof error.code === "string" ? error.code : null;
|
|
4466
|
+
}
|
|
4467
|
+
|
|
4468
|
+
// host/relay/src/host-producer-core.ts
|
|
4469
|
+
var HOST_TRANSCRIPT_CURSOR_REASONS = vocabulary(["transcript_replaced", "transcript_truncated", "transcript_rewritten", "transcript_malformed"]);
|
|
4470
|
+
function isHostTranscriptCursorReason(value) {
|
|
4471
|
+
return typeof value === "string" && HOST_TRANSCRIPT_CURSOR_REASONS.some((reason) => reason === value);
|
|
4472
|
+
}
|
|
4473
|
+
var TRANSCRIPT_MISSING_REASON = "transcript_missing";
|
|
4474
|
+
var HOST_TRANSCRIPT_READ_CHUNK_BYTES = 256 * 1024;
|
|
4475
|
+
async function readTranscriptCompleteChunk(handle, offset, size) {
|
|
4476
|
+
const available = Math.max(0, size - offset);
|
|
4477
|
+
if (available === 0) return "empty";
|
|
4478
|
+
const chunks = [];
|
|
4479
|
+
let position = offset;
|
|
4480
|
+
let total = 0;
|
|
4481
|
+
let lastNewline = -1;
|
|
4482
|
+
while (position < size) {
|
|
4483
|
+
const buffer = Buffer.alloc(Math.min(HOST_TRANSCRIPT_READ_CHUNK_BYTES, size - position));
|
|
4484
|
+
const read = await handle.read(buffer, 0, buffer.length, position);
|
|
4485
|
+
if (read.bytesRead === 0) break;
|
|
4486
|
+
const chunk = buffer.subarray(0, read.bytesRead);
|
|
4487
|
+
chunks.push(chunk);
|
|
4488
|
+
const newline = chunk.lastIndexOf(10);
|
|
4489
|
+
if (newline >= 0) lastNewline = total + newline;
|
|
4490
|
+
total += chunk.length;
|
|
4491
|
+
position += chunk.length;
|
|
4492
|
+
if (lastNewline >= 0) break;
|
|
4493
|
+
}
|
|
4494
|
+
if (lastNewline < 0) return "partial";
|
|
4495
|
+
return Buffer.concat(chunks, total).subarray(0, lastNewline + 1);
|
|
4496
|
+
}
|
|
4497
|
+
async function readTranscriptAnchor(handle, offset, anchorBytes) {
|
|
4498
|
+
const start = Math.max(0, offset - anchorBytes);
|
|
4499
|
+
const anchor = Buffer.alloc(offset - start);
|
|
4500
|
+
if (anchor.length > 0) await handle.read(anchor, 0, anchor.length, start);
|
|
4501
|
+
return { start, sha256: transcriptSha256(anchor) };
|
|
4502
|
+
}
|
|
4503
|
+
async function transcriptAnchorMatches(handle, cursor) {
|
|
4504
|
+
const buffer = Buffer.alloc(cursor.offset - cursor.anchor_start);
|
|
4505
|
+
if (buffer.length > 0) await handle.read(buffer, 0, buffer.length, cursor.anchor_start);
|
|
4506
|
+
return transcriptSha256(buffer) === cursor.anchor_sha256;
|
|
4507
|
+
}
|
|
4508
|
+
function transcriptCursorIdentityReason(cursor, transcriptPath, device, inode) {
|
|
4509
|
+
if (cursor.device !== device || cursor.inode !== inode || cursor.transcript_path !== transcriptPath) return "transcript_replaced";
|
|
4510
|
+
return null;
|
|
4511
|
+
}
|
|
4512
|
+
async function transcriptCursorBoundsReason(handle, cursor, size) {
|
|
4513
|
+
if (size < cursor.offset) return "transcript_truncated";
|
|
4514
|
+
if (cursor.offset > 0 && !await transcriptAnchorMatches(handle, cursor)) return "transcript_rewritten";
|
|
4515
|
+
return null;
|
|
4516
|
+
}
|
|
4517
|
+
function transcriptSha256(value) {
|
|
4518
|
+
return createHash3("sha256").update(value).digest("hex");
|
|
4519
|
+
}
|
|
4520
|
+
function transcriptObjectSha256(value) {
|
|
4521
|
+
return createHash3("sha256").update(JSON.stringify(value), "utf8").digest("hex");
|
|
4522
|
+
}
|
|
4523
|
+
function isTranscriptRecord(value) {
|
|
4524
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
4525
|
+
}
|
|
4526
|
+
function isMissingTranscriptError(error) {
|
|
4527
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
4528
|
+
}
|
|
4529
|
+
function transcriptTimestamp(now, fail) {
|
|
4530
|
+
const value = now();
|
|
4531
|
+
if (!Number.isFinite(value.getTime())) throw fail();
|
|
4532
|
+
return value.toISOString();
|
|
4533
|
+
}
|
|
4534
|
+
function transcriptExpiration(now, retentionMs, fail) {
|
|
4535
|
+
return new Date(Date.parse(transcriptTimestamp(now, fail)) + retentionMs).toISOString();
|
|
4536
|
+
}
|
|
4537
|
+
function createTranscriptWatcherBase(options, owner) {
|
|
4538
|
+
if (typeof options.outbox_dir !== "string" || options.outbox_dir.length === 0) throw owner.invalid_outbox();
|
|
4539
|
+
return {
|
|
4540
|
+
outboxRetentionMs: options.retention_ms ?? owner.default_retention_ms,
|
|
4541
|
+
now: options.now ?? (() => /* @__PURE__ */ new Date()),
|
|
4542
|
+
log: options.log ?? ((line) => {
|
|
4543
|
+
process.stderr.write(`${line}
|
|
4544
|
+
`);
|
|
4545
|
+
}),
|
|
4546
|
+
producerInstallationRef: options.producer_installation_ref
|
|
4547
|
+
};
|
|
4548
|
+
}
|
|
4549
|
+
async function scanTranscriptRegistrations(registrations, scanOne) {
|
|
4550
|
+
let records = 0;
|
|
4551
|
+
let enqueued = 0;
|
|
4552
|
+
let quarantined = 0;
|
|
4553
|
+
for (const registration of registrations) {
|
|
4554
|
+
const result = await scanOne(registration);
|
|
4555
|
+
records += result.records;
|
|
4556
|
+
enqueued += result.enqueued;
|
|
4557
|
+
if (result.quarantined) quarantined += 1;
|
|
4558
|
+
}
|
|
4559
|
+
return { registrations: registrations.length, records, enqueued, quarantined };
|
|
4560
|
+
}
|
|
4561
|
+
function formatRetiredTranscriptLog(producerLabel, transcriptPath) {
|
|
4562
|
+
return `${producerLabel} retired a transcript registration: transcript_path=${JSON.stringify(transcriptPath)}, reason=${TRANSCRIPT_MISSING_REASON}.`;
|
|
4563
|
+
}
|
|
4564
|
+
var HostTranscriptWatcher = class {
|
|
4565
|
+
outboxRetentionMs;
|
|
4566
|
+
now;
|
|
4567
|
+
log;
|
|
4568
|
+
producerInstallationRef;
|
|
4569
|
+
clockFailure;
|
|
4570
|
+
constructor(options, owner) {
|
|
4571
|
+
const base = createTranscriptWatcherBase(options, owner);
|
|
4572
|
+
this.outboxRetentionMs = base.outboxRetentionMs;
|
|
4573
|
+
this.now = base.now;
|
|
4574
|
+
this.log = base.log;
|
|
4575
|
+
this.producerInstallationRef = base.producerInstallationRef;
|
|
4576
|
+
this.clockFailure = owner.clock_failure;
|
|
4577
|
+
}
|
|
4578
|
+
async scanOnce() {
|
|
4579
|
+
return scanTranscriptRegistrations(await this.listRegistrations(), (registration) => this.scanRegistration(registration));
|
|
4580
|
+
}
|
|
4581
|
+
async scanRegistration(registration) {
|
|
4582
|
+
return this.openTranscript(registration, (handle) => this.scanOpened(handle, registration), {
|
|
4583
|
+
missing: () => this.retireMissing(registration),
|
|
4584
|
+
failed: (handle, error) => this.scanFailed(handle, registration, error)
|
|
4585
|
+
});
|
|
4586
|
+
}
|
|
4587
|
+
async openTranscript(registration, scan, handlers) {
|
|
4588
|
+
let handle;
|
|
4589
|
+
try {
|
|
4590
|
+
handle = await open3(this.transcriptPathOf(registration), O_RDONLY2 | O_NOFOLLOW);
|
|
4591
|
+
return await scan(handle);
|
|
4592
|
+
} catch (error) {
|
|
4593
|
+
if (handle === void 0 && isMissingTranscriptError(error)) return handlers.missing();
|
|
4594
|
+
if (hostRelayExchangeFailure(error) !== void 0) throw error;
|
|
4595
|
+
return handlers.failed(handle, error);
|
|
4596
|
+
} finally {
|
|
4597
|
+
await handle?.close();
|
|
4598
|
+
}
|
|
4599
|
+
}
|
|
4600
|
+
/**
|
|
4601
|
+
* A transcript the Host deleted never comes back, so retrying its
|
|
4602
|
+
* registration once per reconcile interval is a failure with no end.
|
|
4603
|
+
* Retire it at the scan that finds it missing and say so once. Only
|
|
4604
|
+
* ENOENT means gone; a permission or busy failure is about this moment,
|
|
4605
|
+
* not about the file, and keeps the registration for the next scan.
|
|
4606
|
+
*/
|
|
4607
|
+
async retireMissingTranscript(transcriptPath, producerLabel, retire) {
|
|
4608
|
+
await retire();
|
|
4609
|
+
this.log(formatRetiredTranscriptLog(producerLabel, transcriptPath));
|
|
4610
|
+
return { records: 0, enqueued: 0, quarantined: false };
|
|
4611
|
+
}
|
|
4612
|
+
stamp() {
|
|
4613
|
+
return transcriptTimestamp(this.now, this.clockFailure);
|
|
4614
|
+
}
|
|
4615
|
+
expire(retentionMs) {
|
|
4616
|
+
return transcriptExpiration(this.now, retentionMs, this.clockFailure);
|
|
4617
|
+
}
|
|
4618
|
+
sha(value) {
|
|
4619
|
+
return transcriptSha256(value);
|
|
4620
|
+
}
|
|
4621
|
+
objectSha(value) {
|
|
4622
|
+
return transcriptObjectSha256(value);
|
|
4623
|
+
}
|
|
4624
|
+
isRecord(value) {
|
|
4625
|
+
return isTranscriptRecord(value);
|
|
4626
|
+
}
|
|
4627
|
+
readChunk(handle, offset, size) {
|
|
4628
|
+
return readTranscriptCompleteChunk(handle, offset, size);
|
|
4629
|
+
}
|
|
4630
|
+
readAnchor(handle, offset, anchorBytes) {
|
|
4631
|
+
return readTranscriptAnchor(handle, offset, anchorBytes);
|
|
4632
|
+
}
|
|
4633
|
+
cursorIdentityReason(cursor, transcriptPath, device, inode) {
|
|
4634
|
+
return transcriptCursorIdentityReason(cursor, transcriptPath, device, inode);
|
|
4635
|
+
}
|
|
4636
|
+
cursorBoundsReason(handle, cursor, size) {
|
|
4637
|
+
return transcriptCursorBoundsReason(handle, cursor, size);
|
|
4638
|
+
}
|
|
4639
|
+
};
|
|
4640
|
+
var HOST_PRODUCER_STATE_IDENTITY = {
|
|
4641
|
+
codex: { file_name: "codex-producer-state.json", schema: "ceal.codex_producer_state.v1" },
|
|
4642
|
+
claude: { file_name: "claude-producer-state.json", schema: "ceal.claude_producer_state.v1" }
|
|
4643
|
+
};
|
|
4644
|
+
var HostProducerDrainCore = class {
|
|
4645
|
+
host;
|
|
4646
|
+
relay;
|
|
4647
|
+
statePath;
|
|
4648
|
+
stateSchema;
|
|
4649
|
+
installationRef;
|
|
4650
|
+
epoch;
|
|
4651
|
+
now;
|
|
4652
|
+
tail = Promise.resolve();
|
|
4653
|
+
constructor(host, runtime) {
|
|
4654
|
+
if (!isHostSafeRef(runtime.producer_installation_ref)) throw host.fail("configuration", `${host.producer_label} producer installation identity is invalid.`);
|
|
4655
|
+
const epoch = runtime.producer_epoch ?? 1;
|
|
4656
|
+
if (!Number.isSafeInteger(epoch) || epoch <= 0) throw host.fail("configuration", `${host.producer_label} producer epoch is invalid.`);
|
|
4657
|
+
this.host = host;
|
|
4658
|
+
this.relay = runtime.relay;
|
|
4659
|
+
this.statePath = join3(host.outbox_directory, HOST_PRODUCER_STATE_IDENTITY[host.producer_id].file_name);
|
|
4660
|
+
this.stateSchema = HOST_PRODUCER_STATE_IDENTITY[host.producer_id].schema;
|
|
4661
|
+
this.installationRef = runtime.producer_installation_ref;
|
|
4662
|
+
this.epoch = epoch;
|
|
4663
|
+
this.now = runtime.now ?? (() => /* @__PURE__ */ new Date());
|
|
4664
|
+
}
|
|
4665
|
+
drainOutbox() {
|
|
4666
|
+
const run = this.tail.then(() => this.drainLocked());
|
|
4667
|
+
this.tail = run.then(() => void 0, () => void 0);
|
|
4668
|
+
return run;
|
|
4669
|
+
}
|
|
4670
|
+
async drainLocked() {
|
|
4671
|
+
const read = await this.host.listEnvelopes();
|
|
4672
|
+
let admitted = 0;
|
|
4673
|
+
let expired = 0;
|
|
4674
|
+
let retained = 0;
|
|
4675
|
+
for (const envelope of read.entries) {
|
|
4676
|
+
const reserved = await this.hasReservation(this.host.submissionRefOf(envelope));
|
|
4677
|
+
if (!reserved && Date.parse(this.host.expiresAtOf(envelope)) <= this.now().getTime()) {
|
|
4678
|
+
await this.host.removeEnvelope(envelope);
|
|
4679
|
+
expired += 1;
|
|
4680
|
+
continue;
|
|
4681
|
+
}
|
|
4682
|
+
const frames = await this.reserve(envelope);
|
|
4683
|
+
let complete = true;
|
|
4684
|
+
for (const frame of frames) {
|
|
4685
|
+
const outcome = await this.relay.admit(frame);
|
|
4686
|
+
if (outcome.code !== "admitted" && outcome.code !== "already_admitted") {
|
|
4687
|
+
complete = false;
|
|
4688
|
+
break;
|
|
4689
|
+
}
|
|
4690
|
+
}
|
|
4691
|
+
if (!complete) {
|
|
4692
|
+
retained += 1;
|
|
4693
|
+
break;
|
|
4694
|
+
}
|
|
4695
|
+
await this.host.removeEnvelope(envelope);
|
|
4696
|
+
await this.release(this.host.submissionRefOf(envelope));
|
|
4697
|
+
admitted += 1;
|
|
4698
|
+
}
|
|
4699
|
+
return { admitted, retained: retained + Math.max(0, read.entries.length - admitted - expired - retained), expired, malformed: read.malformed };
|
|
4700
|
+
}
|
|
4701
|
+
async hasReservation(submissionRef) {
|
|
4702
|
+
return (await this.readState()).pending[submissionRef] !== void 0;
|
|
4703
|
+
}
|
|
4704
|
+
async reserve(envelope) {
|
|
4705
|
+
const state = await this.readState();
|
|
4706
|
+
const submissionRef = this.host.submissionRefOf(envelope);
|
|
4707
|
+
const existing = state.pending[submissionRef];
|
|
4708
|
+
if (existing !== void 0) return existing;
|
|
4709
|
+
const drafts = await this.host.mapEnvelope(envelope);
|
|
4710
|
+
const frames = drafts.map((draft, offset) => ({
|
|
4711
|
+
schema_version: "ceal.host_producer_frame.v1",
|
|
4712
|
+
producer_id: this.host.producer_id,
|
|
4713
|
+
producer_installation_ref: this.installationRef,
|
|
4714
|
+
producer_epoch: this.epoch,
|
|
4715
|
+
sequence: state.next_sequence + offset,
|
|
4716
|
+
frame_kind: draft.frame_kind,
|
|
4717
|
+
occurred_at: this.host.createdAtOf(envelope),
|
|
4718
|
+
payload: draft.payload
|
|
4719
|
+
}));
|
|
4720
|
+
await this.writeState({ ...state, next_sequence: state.next_sequence + frames.length, pending: { ...state.pending, [submissionRef]: frames } });
|
|
4721
|
+
return frames;
|
|
4722
|
+
}
|
|
4723
|
+
async release(submissionRef) {
|
|
4724
|
+
const state = await this.readState();
|
|
4725
|
+
if (state.pending[submissionRef] === void 0) return;
|
|
4726
|
+
const pending = { ...state.pending };
|
|
4727
|
+
delete pending[submissionRef];
|
|
4728
|
+
await this.writeState({ ...state, pending });
|
|
4729
|
+
}
|
|
4730
|
+
async readState() {
|
|
4731
|
+
try {
|
|
4732
|
+
const value = JSON.parse(await readFile2(this.statePath, "utf8"));
|
|
4733
|
+
return this.decodeState(value);
|
|
4734
|
+
} catch (error) {
|
|
4735
|
+
if (errorCode3(error) !== "ENOENT") throw error;
|
|
4736
|
+
return { schema_version: this.stateSchema, producer_installation_ref: this.installationRef, producer_epoch: this.epoch, next_sequence: 1, pending: {} };
|
|
4737
|
+
}
|
|
4738
|
+
}
|
|
4739
|
+
async writeState(state) {
|
|
4740
|
+
await mkdir2(this.host.outbox_directory, { recursive: true, mode: 448 });
|
|
4741
|
+
const temporary = `${this.statePath}.${process.pid}.new`;
|
|
4742
|
+
await writeFile(temporary, JSON.stringify(state), { mode: 384 });
|
|
4743
|
+
await rename2(temporary, this.statePath);
|
|
4744
|
+
}
|
|
4745
|
+
decodeState(value) {
|
|
4746
|
+
const label = this.host.producer_label;
|
|
4747
|
+
const fail = (code, message) => this.host.fail(code, message);
|
|
4748
|
+
if (!isDrainStateHeader(value, this.stateSchema, this.installationRef)) {
|
|
4749
|
+
throw fail("storage", `${label} producer state header is malformed or belongs to another installation (${refusalFacts([
|
|
4750
|
+
{ name: "schema_version", value: isTranscriptRecord(value) ? value.schema_version : void 0, expected: this.stateSchema },
|
|
4751
|
+
{ name: "producer_installation_ref", value: isTranscriptRecord(value) ? value.producer_installation_ref : void 0, expected: this.installationRef }
|
|
4752
|
+
])}).`);
|
|
4753
|
+
}
|
|
4754
|
+
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}`)}).`);
|
|
4755
|
+
const pending = {};
|
|
4756
|
+
const storedEpoch = Number(value.producer_epoch);
|
|
4757
|
+
for (const [submissionRef, frames] of Object.entries(value.pending)) {
|
|
4758
|
+
if (!isHostSafeRef(submissionRef) || !Array.isArray(frames) || frames.length === 0) throw fail("storage", `${label} producer pending reservation is malformed.`);
|
|
4759
|
+
pending[submissionRef] = frames.map((frame) => this.decodeStoredFrame(frame, storedEpoch));
|
|
4760
|
+
}
|
|
4761
|
+
return { schema_version: this.stateSchema, producer_installation_ref: this.installationRef, producer_epoch: this.epoch, next_sequence: Number(value.next_sequence), pending };
|
|
4762
|
+
}
|
|
4763
|
+
decodeStoredFrame(value, storedEpoch) {
|
|
4764
|
+
const label = this.host.producer_label;
|
|
4765
|
+
const json = Buffer.from(JSON.stringify(value), "utf8");
|
|
4766
|
+
const encoded = Buffer.allocUnsafe(json.length + 4);
|
|
4767
|
+
encoded.writeUInt32BE(json.length, 0);
|
|
4768
|
+
json.copy(encoded, 4);
|
|
4769
|
+
const frame = decodeHostProducerFrame(encoded);
|
|
4770
|
+
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([
|
|
4771
|
+
{ name: "producer_id", value: frame.producer_id, expected: this.host.producer_id },
|
|
4772
|
+
{ name: "producer_installation_ref", value: frame.producer_installation_ref, expected: this.installationRef },
|
|
4773
|
+
{ name: "producer_epoch", value: frame.producer_epoch, expected: `at most ${storedEpoch}` }
|
|
4774
|
+
])}).`);
|
|
4775
|
+
return frame;
|
|
4776
|
+
}
|
|
4777
|
+
};
|
|
4778
|
+
function isDrainStateHeader(value, schema, installationRef) {
|
|
4779
|
+
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);
|
|
4780
|
+
}
|
|
4781
|
+
function errorCode3(error) {
|
|
4782
|
+
return typeof error === "object" && error !== null && "code" in error ? String(error.code) : null;
|
|
4783
|
+
}
|
|
4784
|
+
|
|
4785
|
+
// host/relay/src/relay-quarantine-store.ts
|
|
4786
|
+
var RELAY_QUARANTINE_MAX_BYTES = 16 * 1024 * 1024;
|
|
4787
|
+
var RELAY_QUARANTINE_FRAME_REASONS = ["frame_identity_conflict", "sequence_gap", "gateway_refused"];
|
|
4788
|
+
var RELAY_QUARANTINE_REASONS = [...RELAY_QUARANTINE_FRAME_REASONS, ...HOST_PRODUCER_FRAME_ERROR_CODES];
|
|
4789
|
+
|
|
4790
|
+
// host/relay/src/relay-admission-store.ts
|
|
4791
|
+
var DEFAULT_LIMITS = { global_count: 8192, global_bytes: 64 * 1024 * 1024, producer_count: 4096, producer_bytes: 32 * 1024 * 1024 };
|
|
4792
|
+
var RETRY_SECONDS = [1, 2, 4, 8, 16, 32, 60];
|
|
4793
|
+
var MAX_RETRYABLE_ATTEMPTS = RETRY_SECONDS.length + 10;
|
|
4794
|
+
|
|
4795
|
+
// host/service-log.ts
|
|
4796
|
+
function writeHostServiceDiagnostic(producer_id, event, failure_kind) {
|
|
2218
4797
|
try {
|
|
2219
|
-
|
|
4798
|
+
process.stderr.write(`${JSON.stringify({ schema_version: CEAL_HOST_SERVICE_DIAGNOSTIC_SCHEMA, producer_id, event, ...event === "watcher_scan_failed" && failure_kind !== void 0 ? { failure_kind } : {} })}
|
|
4799
|
+
`);
|
|
2220
4800
|
} catch {
|
|
2221
|
-
throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC message is invalid.");
|
|
2222
4801
|
}
|
|
2223
4802
|
}
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
const output = Buffer.allocUnsafe(body.length + HOST_RELAY_IPC_LENGTH_BYTES);
|
|
2227
|
-
output.writeUInt32BE(body.length, 0);
|
|
2228
|
-
body.copy(output, HOST_RELAY_IPC_LENGTH_BYTES);
|
|
2229
|
-
return output;
|
|
2230
|
-
}
|
|
2231
|
-
function exactKeys3(value, keys) {
|
|
2232
|
-
return Object.keys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
|
|
2233
|
-
}
|
|
2234
|
-
function safeRef2(value) {
|
|
2235
|
-
return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(value);
|
|
2236
|
-
}
|
|
2237
|
-
function errorCode2(error) {
|
|
2238
|
-
return record2(error) && typeof error.code === "string" ? error.code : null;
|
|
2239
|
-
}
|
|
4803
|
+
var HOST_SERVICE_LOG_MAX_BYTES = 1024 * 1024;
|
|
4804
|
+
var HOST_SERVICE_LOG_TAIL_BYTES = 64 * 1024;
|
|
2240
4805
|
|
|
2241
4806
|
// host/invocation-authentication-command.ts
|
|
2242
4807
|
var HOST_INVOCATION_AUTHENTICATION_COMMAND_PREFIX = ["authenticate", "--client-nonce"];
|
|
2243
|
-
var
|
|
2244
|
-
|
|
4808
|
+
var HOST_AUTHENTICATION_BUDGET_ENVIRONMENT = "CEAL_HOST_AUTHENTICATION_BUDGET_MS";
|
|
4809
|
+
var HOST_CONTEXT_ACTIVATION_WAIT_MAX_MS = 2e4;
|
|
4810
|
+
var CODEX_CONTEXT_ACTIVATION_WAIT_MAX_MS = HOST_CONTEXT_ACTIVATION_WAIT_MAX_MS;
|
|
4811
|
+
var HOST_AUTHENTICATION_COMPLETION_RESERVE_MS = 5e3;
|
|
4812
|
+
var INVOCATION_CONTEXT_POLL_INTERVAL_MS = 250;
|
|
4813
|
+
var REFUSAL_REASON_PATTERN = /^[a-z][a-z0-9_]{0,63}$/u;
|
|
4814
|
+
function installedHostInvocationAuthenticationCommandOptions(config, contextBudgetMs, maxContextWaitMs) {
|
|
2245
4815
|
const port = new HostRelayInvocationContextPort(config.relay_endpoint);
|
|
2246
4816
|
return {
|
|
2247
4817
|
host_source_ref: config.host_source_ref,
|
|
2248
4818
|
outbox_dir: config.outbox_dir,
|
|
2249
4819
|
producer_installation_ref: config.producer_installation_ref,
|
|
4820
|
+
context_activation_wait_ms: boundedContextActivationWait(contextBudgetMs, config.ipc_timeout_ms, maxContextWaitMs),
|
|
2250
4821
|
mint_invocation_context: (input) => port.mintInvocationContext({ ...input, producer_id: input.producer_id })
|
|
2251
4822
|
};
|
|
2252
4823
|
}
|
|
2253
|
-
async function runHostInvocationAuthenticationCommand(
|
|
4824
|
+
async function runHostInvocationAuthenticationCommand(descriptor2, args, options) {
|
|
2254
4825
|
let sink = options?.output_sink;
|
|
2255
4826
|
try {
|
|
2256
|
-
const resolved = await resolveOptions(
|
|
4827
|
+
const resolved = await resolveOptions(descriptor2, args, options);
|
|
2257
4828
|
sink = resolved.options.output_sink;
|
|
2258
|
-
writeResult(await authenticateHostInvocation(
|
|
4829
|
+
writeResult(await authenticateHostInvocation(descriptor2, resolved.input, resolved.options), sink);
|
|
2259
4830
|
return 0;
|
|
2260
4831
|
} catch (error) {
|
|
2261
4832
|
writeResult({ ok: false, code: "invocation_authentication_unavailable", reason: authenticationRefusalReason(error) }, sink);
|
|
@@ -2264,65 +4835,150 @@ async function runHostInvocationAuthenticationCommand(descriptor, args, options)
|
|
|
2264
4835
|
}
|
|
2265
4836
|
function authenticationRefusalReason(error) {
|
|
2266
4837
|
const message = error instanceof Error ? error.message : "";
|
|
2267
|
-
|
|
4838
|
+
if (!REFUSAL_REASON_PATTERN.test(message)) return "host_refusal_invalid";
|
|
4839
|
+
return isCealHostAuthenticationCause(message) ? message : "host_refusal_invalid";
|
|
2268
4840
|
}
|
|
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("
|
|
4841
|
+
async function authenticateHostInvocation(descriptor2, input, options) {
|
|
4842
|
+
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
4843
|
const request2 = decodeCealHostInvocationAuthenticationRequest({ schema_version: CEAL_HOST_INVOCATION_AUTHENTICATION_REQUEST_SCHEMA, client_nonce: input[2] });
|
|
2272
4844
|
const config = validateOptions(options);
|
|
2273
|
-
const now =
|
|
2274
|
-
const { store, current } = await currentInvocation(
|
|
2275
|
-
if (config.mint_invocation_context === void 0) throw new TypeError("
|
|
4845
|
+
const now = config.now ?? (() => /* @__PURE__ */ new Date());
|
|
4846
|
+
const { store, current } = await currentInvocation(descriptor2, config, now);
|
|
4847
|
+
if (config.mint_invocation_context === void 0) throw new TypeError("relay_failed");
|
|
2276
4848
|
const query = {
|
|
2277
|
-
producer_id:
|
|
4849
|
+
producer_id: descriptor2.producer_id,
|
|
2278
4850
|
producer_installation_ref: config.producer_installation_ref,
|
|
2279
4851
|
local_session_ref: current.identity.host_session_ref,
|
|
2280
4852
|
local_turn_ref: current.identity.host_turn_ref,
|
|
2281
|
-
client_nonce: request2.client_nonce
|
|
4853
|
+
client_nonce: request2.client_nonce,
|
|
4854
|
+
...await visibleOutputBudget(descriptor2)
|
|
2282
4855
|
};
|
|
2283
4856
|
const response2 = await mintedResult(config.mint_invocation_context, query);
|
|
2284
|
-
const
|
|
2285
|
-
|
|
2286
|
-
|
|
4857
|
+
const completedAt = now();
|
|
4858
|
+
const rechecked = await store.readInvocationContext(current.identity.host_source_ref, current.identity.host_session_ref, completedAt);
|
|
4859
|
+
if (rechecked === null || !sameTurn(current, rechecked)) throw new TypeError("context_replaced");
|
|
4860
|
+
return decodeCealHostInvocationAuthenticationResult(response2.result, completedAt);
|
|
4861
|
+
}
|
|
4862
|
+
async function visibleOutputBudget(descriptor2) {
|
|
4863
|
+
const bytes = await descriptor2.resolve_visible_output_max_bytes?.();
|
|
4864
|
+
return bytes === void 0 ? {} : { visible_output_max_bytes: bytes };
|
|
2287
4865
|
}
|
|
2288
4866
|
async function mintedResult(mint, query) {
|
|
2289
4867
|
let response2;
|
|
2290
4868
|
try {
|
|
2291
4869
|
response2 = await mint(query);
|
|
2292
4870
|
} catch (error) {
|
|
2293
|
-
throw new TypeError(
|
|
4871
|
+
throw new TypeError(exchangeFailureCause(hostRelayExchangeFailure(error) ?? "unavailable"));
|
|
2294
4872
|
}
|
|
2295
|
-
if (response2.status === "refused") throw new TypeError(
|
|
2296
|
-
if (response2.status !== "ready") throw new TypeError(
|
|
4873
|
+
if (response2.status === "refused") throw new TypeError(mintRefusalCause(response2.reason));
|
|
4874
|
+
if (response2.status !== "ready") throw new TypeError("no_binding");
|
|
2297
4875
|
return response2;
|
|
2298
4876
|
}
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
4877
|
+
function mintRefusalCause(reason) {
|
|
4878
|
+
if (isDirectMintRefusalCause(reason)) return reason;
|
|
4879
|
+
if (reason === "deadline" || reason === "cancelled") return "transient_retryable";
|
|
4880
|
+
if (reason === "mint_failed" || reason === "relay_failed") return reason;
|
|
4881
|
+
return isVocabularyWord(CEAL_HOST_MINT_REQUEST_CONTEXT_REFUSAL_REASONS, reason) ? "context_stale" : "host_refusal_invalid";
|
|
4882
|
+
}
|
|
4883
|
+
function isDirectMintRefusalCause(reason) {
|
|
4884
|
+
return isVocabularyWord(HOST_RELAY_DIRECT_WIRE_MINT_REASONS, reason);
|
|
4885
|
+
}
|
|
4886
|
+
function exchangeFailureCause(failure2) {
|
|
4887
|
+
if (failure2 === "permission_denied") return "relay_permission_denied";
|
|
4888
|
+
if (failure2 === "timed_out") return "transient_retryable";
|
|
4889
|
+
return "relay_unavailable";
|
|
4890
|
+
}
|
|
4891
|
+
async function currentInvocation(descriptor2, config, now) {
|
|
4892
|
+
const store = descriptor2.create_store(config.outbox_dir);
|
|
4893
|
+
const identity = resolveIdentity(descriptor2, config);
|
|
2302
4894
|
if (identity.status !== "ready") throw new TypeError(identity.status);
|
|
2303
|
-
const
|
|
2304
|
-
|
|
2305
|
-
|
|
4895
|
+
const waitBudgetMs = config.context_activation_wait_ms ?? 0;
|
|
4896
|
+
const monotonicNow = config.monotonic_now ?? (() => performance.now());
|
|
4897
|
+
const deadline = monotonicNow() + waitBudgetMs;
|
|
4898
|
+
let firstCheck = true;
|
|
4899
|
+
let waitEngaged = false;
|
|
4900
|
+
while (true) {
|
|
4901
|
+
if (!firstCheck && monotonicNow() >= deadline) {
|
|
4902
|
+
recordActivationWaitExhaustion(descriptor2.producer_id, waitEngaged, waitBudgetMs);
|
|
4903
|
+
throw new TypeError("context_unavailable");
|
|
4904
|
+
}
|
|
4905
|
+
firstCheck = false;
|
|
4906
|
+
const observedAt = now();
|
|
4907
|
+
const current = await readLiveSessionContext(store, identity.identity.host_source_ref, identity.identity.host_session_ref, observedAt);
|
|
4908
|
+
if (current !== null) {
|
|
4909
|
+
recordActivationWaitCompletion(descriptor2.producer_id, waitEngaged);
|
|
4910
|
+
return { store, current };
|
|
4911
|
+
}
|
|
4912
|
+
const remainingMs = deadline - monotonicNow();
|
|
4913
|
+
if (remainingMs <= 0) {
|
|
4914
|
+
recordActivationWaitExhaustion(descriptor2.producer_id, waitEngaged, waitBudgetMs);
|
|
4915
|
+
throw new TypeError("context_unavailable");
|
|
4916
|
+
}
|
|
4917
|
+
recordActivationWaitEngagement(descriptor2.producer_id, waitEngaged);
|
|
4918
|
+
waitEngaged = true;
|
|
4919
|
+
const intervalMs = Math.min(INVOCATION_CONTEXT_POLL_INTERVAL_MS, remainingMs);
|
|
4920
|
+
await (config.wait ?? waitForContextActivation)(intervalMs);
|
|
4921
|
+
}
|
|
4922
|
+
}
|
|
4923
|
+
function recordActivationWaitExhaustion(producer, engaged, budgetMs) {
|
|
4924
|
+
if (engaged || budgetMs > 0) writeHostServiceDiagnostic(producer, "activation_wait_exhausted");
|
|
4925
|
+
else writeHostServiceDiagnostic(producer, "activation_wait_skipped");
|
|
4926
|
+
}
|
|
4927
|
+
function recordActivationWaitCompletion(producer, engaged) {
|
|
4928
|
+
if (engaged) writeHostServiceDiagnostic(producer, "activation_wait_completed");
|
|
4929
|
+
}
|
|
4930
|
+
function recordActivationWaitEngagement(producer, engaged) {
|
|
4931
|
+
if (!engaged) writeHostServiceDiagnostic(producer, "activation_wait_engaged");
|
|
4932
|
+
}
|
|
4933
|
+
async function readLiveSessionContext(store, hostSourceRef, hostSessionRef, now) {
|
|
4934
|
+
const current = await store.readInvocationContext(hostSourceRef, hostSessionRef, now);
|
|
4935
|
+
if (current !== null) {
|
|
4936
|
+
if (Date.parse(current.expires_at) <= now.getTime()) throw new TypeError("context_expired");
|
|
4937
|
+
return current;
|
|
4938
|
+
}
|
|
4939
|
+
const raw = await store.readRawInvocationContext?.(hostSourceRef, hostSessionRef);
|
|
4940
|
+
if (raw !== null && raw !== void 0 && Date.parse(raw.expires_at) <= now.getTime()) throw new TypeError("context_expired");
|
|
4941
|
+
return null;
|
|
2306
4942
|
}
|
|
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: "
|
|
4943
|
+
function resolveIdentity(descriptor2, options) {
|
|
4944
|
+
const sessionId = options.session_id === null ? void 0 : options.session_id ?? process.env[descriptor2.session_id_env];
|
|
4945
|
+
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) } };
|
|
4946
|
+
return { status: "session_unavailable" };
|
|
2311
4947
|
}
|
|
2312
|
-
async function resolveOptions(
|
|
4948
|
+
async function resolveOptions(descriptor2, args, options) {
|
|
2313
4949
|
if (options !== void 0) return { input: [...args], options };
|
|
2314
|
-
const configPath =
|
|
4950
|
+
const configPath = descriptor2.parse_config_flag(args);
|
|
4951
|
+
const config = await descriptor2.read_producer_config(configPath);
|
|
2315
4952
|
return {
|
|
2316
|
-
input: args.filter((argument) => !argument.startsWith(`${
|
|
2317
|
-
options: installedHostInvocationAuthenticationCommandOptions(
|
|
4953
|
+
input: args.filter((argument) => !argument.startsWith(`${descriptor2.config_flag}=`)),
|
|
4954
|
+
options: installedHostInvocationAuthenticationCommandOptions(config, authenticationBudgetMsFromEnvironment(), descriptor2.context_activation_wait_max_ms)
|
|
2318
4955
|
};
|
|
2319
4956
|
}
|
|
4957
|
+
function authenticationBudgetMsFromEnvironment() {
|
|
4958
|
+
const value = process.env[HOST_AUTHENTICATION_BUDGET_ENVIRONMENT];
|
|
4959
|
+
if (value === void 0) return 0;
|
|
4960
|
+
if (!/^(?:0|[1-9][0-9]{0,8})$/u.test(value)) throw new TypeError("invalid_arguments");
|
|
4961
|
+
return Number(value);
|
|
4962
|
+
}
|
|
4963
|
+
function boundedContextActivationWait(contextBudgetMs, relayTimeoutMs, maxContextWaitMs) {
|
|
4964
|
+
if (maxContextWaitMs === void 0 || contextBudgetMs <= 0) return 0;
|
|
4965
|
+
const availableWaitMs = contextBudgetMs - relayTimeoutMs - HOST_AUTHENTICATION_COMPLETION_RESERVE_MS;
|
|
4966
|
+
return Math.max(0, Math.min(maxContextWaitMs, availableWaitMs));
|
|
4967
|
+
}
|
|
4968
|
+
function waitForContextActivation(milliseconds) {
|
|
4969
|
+
return new Promise((resolve) => {
|
|
4970
|
+
setTimeout(resolve, milliseconds);
|
|
4971
|
+
});
|
|
4972
|
+
}
|
|
2320
4973
|
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("
|
|
4974
|
+
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)) {
|
|
4975
|
+
throw new TypeError("options_invalid");
|
|
2323
4976
|
}
|
|
2324
4977
|
return options;
|
|
2325
4978
|
}
|
|
4979
|
+
function validContextActivationWait(value) {
|
|
4980
|
+
return value === void 0 || Number.isSafeInteger(value) && value >= 0 && value <= HOST_CONTEXT_ACTIVATION_WAIT_MAX_MS;
|
|
4981
|
+
}
|
|
2326
4982
|
function isHostSessionId(value) {
|
|
2327
4983
|
return typeof value === "string" && value.length > 0 && value.length <= 256 && !value.includes("\0");
|
|
2328
4984
|
}
|
|
@@ -2341,7 +4997,7 @@ function writeResult(value, sink) {
|
|
|
2341
4997
|
import { posix as posix3, win32 as win323 } from "node:path";
|
|
2342
4998
|
|
|
2343
4999
|
// host/runtime-source-paths.ts
|
|
2344
|
-
import { createHash as
|
|
5000
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
2345
5001
|
import { posix as posix2, win32 as win322 } from "node:path";
|
|
2346
5002
|
|
|
2347
5003
|
// host/absolute-path.ts
|
|
@@ -2363,7 +5019,7 @@ function hostRuntimeSourcePaths(stateRoot, sourceRef, platform = process.platfor
|
|
|
2363
5019
|
const sourcesRoot = path.join(stateRoot, "sources");
|
|
2364
5020
|
const sourceRoot = path.join(sourcesRoot, sourceId);
|
|
2365
5021
|
const runtimeRoot = path.join(stateRoot, "run");
|
|
2366
|
-
const endpoint = platform === "win32" ? `\\\\.\\pipe\\ceal-host-${
|
|
5022
|
+
const endpoint = platform === "win32" ? `\\\\.\\pipe\\ceal-host-${createHash4("sha256").update(`${stateRoot}\0${sourceRef}`).digest("hex").slice(0, 24)}` : path.join(runtimeRoot, `${sourceId}.sock`);
|
|
2367
5023
|
assertHostRuntimeIpcLength(endpoint, platform);
|
|
2368
5024
|
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
5025
|
}
|
|
@@ -2379,7 +5035,7 @@ function assertHostProducerSourcePaths(stateRoot, config, producer, platform = p
|
|
|
2379
5035
|
|
|
2380
5036
|
// host/producer-service.ts
|
|
2381
5037
|
import { constants } from "node:fs";
|
|
2382
|
-
import { lstat as lstat2, open as
|
|
5038
|
+
import { lstat as lstat2, open as open4 } from "node:fs/promises";
|
|
2383
5039
|
var SAFE_REF4 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
|
|
2384
5040
|
var HOST_PRODUCER_CONFIG_FLAG = "--ceal-host-config";
|
|
2385
5041
|
var HostProducerServiceError = class extends Error {
|
|
@@ -2400,22 +5056,22 @@ function hostProducerExtraPath(extras, key) {
|
|
|
2400
5056
|
function parseHostProducerConfigFlag(args, platform = process.platform) {
|
|
2401
5057
|
return parseProducerHostConfigFlag(args, HOST_PRODUCER_CONFIG_FLAG, platform, hostProducerError);
|
|
2402
5058
|
}
|
|
2403
|
-
async function readHostProducerConfig(
|
|
2404
|
-
const config = decodeHostProducerConfigText(
|
|
5059
|
+
async function readHostProducerConfig(descriptor2, configPath, platform = process.platform) {
|
|
5060
|
+
const config = decodeHostProducerConfigText(descriptor2, await readProducerConfigText(configPath, platform, hostProducerError), platform);
|
|
2405
5061
|
const path = platform === "win32" ? win323 : posix3;
|
|
2406
5062
|
const root = path.resolve(config.outbox_dir, "../../../../..");
|
|
2407
5063
|
try {
|
|
2408
|
-
assertHostProducerSourcePaths(root, config,
|
|
5064
|
+
assertHostProducerSourcePaths(root, config, descriptor2.producer_id, platform);
|
|
2409
5065
|
} catch (error) {
|
|
2410
5066
|
throw hostProducerError("invalid_config", error instanceof Error ? error.message : "Host producer source tuple is invalid.");
|
|
2411
5067
|
}
|
|
2412
5068
|
return config;
|
|
2413
5069
|
}
|
|
2414
|
-
function decodeHostProducerConfigText(
|
|
2415
|
-
const extraPaths =
|
|
2416
|
-
const decoded = decodeProducerConfigCore(text, { schema:
|
|
5070
|
+
function decodeHostProducerConfigText(descriptor2, text, platform = process.platform) {
|
|
5071
|
+
const extraPaths = descriptor2.extra_paths ?? [];
|
|
5072
|
+
const decoded = decodeProducerConfigCore(text, { schema: descriptor2.schema, keys: [...HOST_PRODUCER_CONFIG_KEYS, ...extraPaths], platform, extraPaths, error: hostProducerError });
|
|
2417
5073
|
const { extra_paths: extras, ...core } = decoded;
|
|
2418
|
-
return Object.freeze(
|
|
5074
|
+
return Object.freeze(descriptor2.config({ schema_version: descriptor2.schema, ...core }, extras));
|
|
2419
5075
|
}
|
|
2420
5076
|
function hostProducerError(code, message = code) {
|
|
2421
5077
|
return new HostProducerServiceError(code, message);
|
|
@@ -2490,7 +5146,7 @@ function validateConfigFile(value, platform, error) {
|
|
|
2490
5146
|
}
|
|
2491
5147
|
async function openConfigFile(configPath, flags, error) {
|
|
2492
5148
|
try {
|
|
2493
|
-
return await
|
|
5149
|
+
return await open4(configPath, flags);
|
|
2494
5150
|
} catch {
|
|
2495
5151
|
throw error("config_unavailable");
|
|
2496
5152
|
}
|
|
@@ -2551,7 +5207,7 @@ function boundedMilliseconds(value) {
|
|
|
2551
5207
|
}
|
|
2552
5208
|
|
|
2553
5209
|
// host/codex/src/codex-decoder.ts
|
|
2554
|
-
import { createHash as
|
|
5210
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
2555
5211
|
|
|
2556
5212
|
// host/codex/src/codex-types.ts
|
|
2557
5213
|
var CODEX_THREAD_ID_ENVIRONMENT = "CODEX_THREAD_ID";
|
|
@@ -2562,10 +5218,6 @@ var CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION = "ceal.codex_invocation_context.v1"
|
|
|
2562
5218
|
var CODEX_TRANSCRIPT_REGISTRATION_SCHEMA_VERSION = "ceal.codex_transcript_registration.v1";
|
|
2563
5219
|
var CODEX_TRANSCRIPT_CURSOR_SCHEMA_VERSION = "ceal.codex_transcript_cursor.v1";
|
|
2564
5220
|
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
5221
|
var CodexHostAdapterError = class extends Error {
|
|
2570
5222
|
name = "CodexHostAdapterError";
|
|
2571
5223
|
code;
|
|
@@ -2577,7 +5229,7 @@ var CodexHostAdapterError = class extends Error {
|
|
|
2577
5229
|
|
|
2578
5230
|
// host/codex/src/codex-decoder.ts
|
|
2579
5231
|
var SAFE_REF5 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
|
|
2580
|
-
var MAX_PAYLOAD_BYTES =
|
|
5232
|
+
var MAX_PAYLOAD_BYTES = 512 * 1024;
|
|
2581
5233
|
function observationRef(event, identity, value) {
|
|
2582
5234
|
return cealHostObservationRef("codex", shortDigest({ event, identity, value }));
|
|
2583
5235
|
}
|
|
@@ -2601,16 +5253,16 @@ function turnObservationValue(sessionId, turnRef, status) {
|
|
|
2601
5253
|
return { status, host_session_id_sha256: sha256(sessionId), host_turn_ref: turnRef };
|
|
2602
5254
|
}
|
|
2603
5255
|
function sha256(value) {
|
|
2604
|
-
return
|
|
5256
|
+
return createHash5("sha256").update(value, "utf8").digest("hex");
|
|
2605
5257
|
}
|
|
2606
5258
|
function shortDigest(value) {
|
|
2607
5259
|
return cealRequestSha256(value);
|
|
2608
5260
|
}
|
|
2609
5261
|
|
|
2610
5262
|
// 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
|
|
5263
|
+
import { O_NOFOLLOW as O_NOFOLLOW2, O_RDONLY as O_RDONLY3 } from "node:constants";
|
|
5264
|
+
import { lstat as lstat3, mkdir as mkdir3, open as open5, readdir, rename as rename3, unlink as unlink2 } from "node:fs/promises";
|
|
5265
|
+
import { dirname, isAbsolute as isAbsolute2, join as join4 } from "node:path";
|
|
2614
5266
|
|
|
2615
5267
|
// host/invocation-context.ts
|
|
2616
5268
|
var HOST_INVOCATION_IDENTITY_KEYS = ["host_session_ref", "host_turn_ref", "host_source_ref"];
|
|
@@ -2624,17 +5276,32 @@ function hasHostInvocationIdentityKeys(value) {
|
|
|
2624
5276
|
function hasHostInvocationContextKeys(value, optional = []) {
|
|
2625
5277
|
return requiredKeys(value, HOST_INVOCATION_CONTEXT_REQUIRED_KEYS, optional);
|
|
2626
5278
|
}
|
|
2627
|
-
function
|
|
5279
|
+
async function readLatestSessionProjection(file, hostSourceRef, hostSessionRef, readProjection) {
|
|
5280
|
+
const context = await readProjection(file);
|
|
5281
|
+
if (context === null || context.identity.host_source_ref !== hostSourceRef || context.identity.host_session_ref !== hostSessionRef) return null;
|
|
5282
|
+
return context;
|
|
5283
|
+
}
|
|
5284
|
+
function isLiveSessionProjection(context, now) {
|
|
5285
|
+
return context !== null && Date.parse(context.expires_at) > now.getTime();
|
|
5286
|
+
}
|
|
5287
|
+
function invocationContextFromTurn(identity, promptRef, expiresAt, descriptor2) {
|
|
2628
5288
|
const context = {
|
|
2629
|
-
schema_version:
|
|
5289
|
+
schema_version: descriptor2.schema_version,
|
|
2630
5290
|
identity,
|
|
2631
5291
|
prompt_ref: promptRef,
|
|
2632
5292
|
expires_at: expiresAt,
|
|
2633
|
-
...
|
|
5293
|
+
...descriptor2.turn_generation_ref === void 0 ? {} : { turn_generation_ref: descriptor2.turn_generation_ref },
|
|
5294
|
+
...descriptor2.working_directory === void 0 ? {} : { working_directory: descriptor2.working_directory }
|
|
2634
5295
|
};
|
|
2635
|
-
|
|
5296
|
+
descriptor2.validate(context);
|
|
2636
5297
|
return Object.freeze(context);
|
|
2637
5298
|
}
|
|
5299
|
+
function isHostInvocationTurnSelection(value) {
|
|
5300
|
+
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]));
|
|
5301
|
+
}
|
|
5302
|
+
function invocationTurnSelectionMatches(context, selection) {
|
|
5303
|
+
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;
|
|
5304
|
+
}
|
|
2638
5305
|
function exactKeys4(value, keys) {
|
|
2639
5306
|
const actual = Object.keys(value);
|
|
2640
5307
|
return actual.length === keys.length && keys.every((key) => Object.hasOwn(value, key)) && actual.every((key) => keys.includes(key));
|
|
@@ -2644,10 +5311,16 @@ function requiredKeys(value, required, optional) {
|
|
|
2644
5311
|
const allowed = /* @__PURE__ */ new Set([...required, ...optional]);
|
|
2645
5312
|
return actual.length >= required.length && actual.length <= allowed.size && required.every((key) => Object.hasOwn(value, key)) && actual.every((key) => allowed.has(key));
|
|
2646
5313
|
}
|
|
5314
|
+
function isRecord3(value) {
|
|
5315
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
5316
|
+
}
|
|
5317
|
+
function safeRef3(value) {
|
|
5318
|
+
return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(value);
|
|
5319
|
+
}
|
|
2647
5320
|
|
|
2648
5321
|
// 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 });
|
|
5322
|
+
function codexInvocationContextFromTurn(identity, promptRef, expiresAt, turnGenerationRef) {
|
|
5323
|
+
return invocationContextFromTurn(identity, promptRef, expiresAt, { schema_version: CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION, validate: validateCodexHostInvocationContext, turn_generation_ref: turnGenerationRef });
|
|
2651
5324
|
}
|
|
2652
5325
|
function validateCodexHostInvocationContext(value) {
|
|
2653
5326
|
if (!isContextShape(value)) {
|
|
@@ -2657,28 +5330,29 @@ function validateCodexHostInvocationContext(value) {
|
|
|
2657
5330
|
validateContextReferences(value);
|
|
2658
5331
|
validateContextTimes(value);
|
|
2659
5332
|
}
|
|
2660
|
-
function invocationContextFromBinding(binding) {
|
|
5333
|
+
function invocationContextFromBinding(binding, turnGenerationRef) {
|
|
2661
5334
|
const context = {
|
|
2662
5335
|
schema_version: CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION,
|
|
2663
5336
|
identity: binding.identity,
|
|
2664
5337
|
prompt_ref: binding.prompt_ref,
|
|
2665
5338
|
request_ref: binding.request_ref,
|
|
2666
5339
|
bound_at: binding.bound_at,
|
|
2667
|
-
expires_at: binding.expires_at
|
|
5340
|
+
expires_at: binding.expires_at,
|
|
5341
|
+
...turnGenerationRef === void 0 ? {} : { turn_generation_ref: turnGenerationRef }
|
|
2668
5342
|
};
|
|
2669
5343
|
validateCodexHostInvocationContext(context);
|
|
2670
5344
|
return Object.freeze(context);
|
|
2671
5345
|
}
|
|
2672
5346
|
function validateIdentity2(value) {
|
|
2673
|
-
if (!
|
|
5347
|
+
if (!isRecord4(value) || !hasHostInvocationIdentityKeys(value) || ![value.host_session_ref, value.host_turn_ref, value.host_source_ref].every(safeRef4)) {
|
|
2674
5348
|
throw new CodexHostAdapterError("storage", "Codex Host invocation identity is malformed.");
|
|
2675
5349
|
}
|
|
2676
5350
|
}
|
|
2677
5351
|
function isContextShape(value) {
|
|
2678
|
-
return
|
|
5352
|
+
return isRecord4(value) && hasHostInvocationContextKeys(value, ["request_ref", "bound_at", "turn_generation_ref"]) && value.schema_version === CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION;
|
|
2679
5353
|
}
|
|
2680
5354
|
function validateContextReferences(value) {
|
|
2681
|
-
if (!
|
|
5355
|
+
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
5356
|
}
|
|
2683
5357
|
function validateContextTimes(value) {
|
|
2684
5358
|
const expiresAt = value.expires_at;
|
|
@@ -2687,18 +5361,18 @@ function validateContextTimes(value) {
|
|
|
2687
5361
|
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
5362
|
}
|
|
2689
5363
|
function optionalSafeRef(value) {
|
|
2690
|
-
return value === void 0 ||
|
|
5364
|
+
return value === void 0 || safeRef4(value);
|
|
2691
5365
|
}
|
|
2692
5366
|
function optionalTimestamp(value) {
|
|
2693
5367
|
return value === void 0 || timestamp2(value);
|
|
2694
5368
|
}
|
|
2695
|
-
function
|
|
5369
|
+
function safeRef4(value) {
|
|
2696
5370
|
return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(value);
|
|
2697
5371
|
}
|
|
2698
5372
|
function timestamp2(value) {
|
|
2699
5373
|
return typeof value === "string" && value.length <= 64 && Number.isFinite(Date.parse(value));
|
|
2700
5374
|
}
|
|
2701
|
-
function
|
|
5375
|
+
function isRecord4(value) {
|
|
2702
5376
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2703
5377
|
}
|
|
2704
5378
|
|
|
@@ -2711,20 +5385,22 @@ var CodexOutboxStore = class {
|
|
|
2711
5385
|
bindingsDirectory;
|
|
2712
5386
|
sessionsDirectory;
|
|
2713
5387
|
activeContextsDirectory;
|
|
5388
|
+
turnSelectionsDirectory;
|
|
2714
5389
|
registrationsDirectory;
|
|
2715
5390
|
cursorsDirectory;
|
|
2716
5391
|
constructor(directory) {
|
|
2717
5392
|
if (typeof directory !== "string" || directory.length === 0) throw new CodexHostAdapterError("configuration", "Codex outbox directory is required.");
|
|
2718
5393
|
this.directory = directory;
|
|
2719
|
-
this.entriesDirectory =
|
|
2720
|
-
this.bindingsDirectory =
|
|
2721
|
-
this.sessionsDirectory =
|
|
2722
|
-
this.activeContextsDirectory =
|
|
2723
|
-
this.
|
|
2724
|
-
this.
|
|
5394
|
+
this.entriesDirectory = join4(directory, "entries");
|
|
5395
|
+
this.bindingsDirectory = join4(directory, "bindings");
|
|
5396
|
+
this.sessionsDirectory = join4(directory, "sessions");
|
|
5397
|
+
this.activeContextsDirectory = join4(directory, "active-contexts");
|
|
5398
|
+
this.turnSelectionsDirectory = join4(directory, "turn-selections");
|
|
5399
|
+
this.registrationsDirectory = join4(directory, "transcript-registrations");
|
|
5400
|
+
this.cursorsDirectory = join4(directory, "transcript-cursors");
|
|
2725
5401
|
}
|
|
2726
5402
|
async prepare() {
|
|
2727
|
-
for (const path of [this.directory, this.entriesDirectory, this.bindingsDirectory, this.sessionsDirectory, this.activeContextsDirectory, this.registrationsDirectory, this.cursorsDirectory]) {
|
|
5403
|
+
for (const path of [this.directory, this.entriesDirectory, this.bindingsDirectory, this.sessionsDirectory, this.activeContextsDirectory, this.turnSelectionsDirectory, this.registrationsDirectory, this.cursorsDirectory]) {
|
|
2728
5404
|
await ensurePrivateOwnerDirectory(path);
|
|
2729
5405
|
}
|
|
2730
5406
|
}
|
|
@@ -2740,7 +5416,7 @@ var CodexOutboxStore = class {
|
|
|
2740
5416
|
for (const name of await readdir(this.entriesDirectory)) {
|
|
2741
5417
|
if (!name.endsWith(".json")) continue;
|
|
2742
5418
|
try {
|
|
2743
|
-
const value = JSON.parse(await readPrivateFile(
|
|
5419
|
+
const value = JSON.parse(await readPrivateFile(join4(this.entriesDirectory, name)));
|
|
2744
5420
|
validateEnvelope(value);
|
|
2745
5421
|
entries.push(value);
|
|
2746
5422
|
} catch {
|
|
@@ -2768,8 +5444,8 @@ var CodexOutboxStore = class {
|
|
|
2768
5444
|
* prompt replaces this projection, so it cannot inherit the prior turn's
|
|
2769
5445
|
* Request by session alone.
|
|
2770
5446
|
*/
|
|
2771
|
-
async activateInvocationContext(identity, promptRef, expiresAt) {
|
|
2772
|
-
const context = codexInvocationContextFromTurn(identity, promptRef, expiresAt);
|
|
5447
|
+
async activateInvocationContext(identity, promptRef, expiresAt, turnGenerationRef) {
|
|
5448
|
+
const context = codexInvocationContextFromTurn(identity, promptRef, expiresAt, turnGenerationRef);
|
|
2773
5449
|
await this.prepare();
|
|
2774
5450
|
const path = this.activeContextPath(identity);
|
|
2775
5451
|
try {
|
|
@@ -2783,6 +5459,25 @@ var CodexOutboxStore = class {
|
|
|
2783
5459
|
throw error;
|
|
2784
5460
|
}
|
|
2785
5461
|
}
|
|
5462
|
+
async writeInvocationTurnSelection(selection) {
|
|
5463
|
+
if (!isHostInvocationTurnSelection(selection)) throw new CodexHostAdapterError("invalid_input", "Codex Host turn selection is invalid.");
|
|
5464
|
+
await this.prepare();
|
|
5465
|
+
await writeAtomicJson(this.turnSelectionPath(selection.host_source_ref, selection.host_session_ref), selection);
|
|
5466
|
+
}
|
|
5467
|
+
async readInvocationTurnSelection(hostSourceRef, hostSessionRef) {
|
|
5468
|
+
if (!SAFE_REF6.test(hostSourceRef) || !SAFE_REF6.test(hostSessionRef)) throw new CodexHostAdapterError("invalid_input", "Codex Host turn selection identity is invalid.");
|
|
5469
|
+
await this.prepare();
|
|
5470
|
+
return readOptionalJson(this.turnSelectionPath(hostSourceRef, hostSessionRef), validateTurnSelection);
|
|
5471
|
+
}
|
|
5472
|
+
async attachInvocationTurnGeneration(identity, promptRef, turnGenerationRef) {
|
|
5473
|
+
const selection = await this.readInvocationTurnSelection(identity.host_source_ref, identity.host_session_ref);
|
|
5474
|
+
if (selection === null || selection.prompt_ref !== promptRef || selection.turn_generation_ref !== turnGenerationRef) return false;
|
|
5475
|
+
const path = this.activeContextPath(identity);
|
|
5476
|
+
const active = await readOptionalJson(path, validateCodexHostInvocationContext);
|
|
5477
|
+
if (active === null || active.prompt_ref !== promptRef || !sameIdentity(active.identity, identity)) return false;
|
|
5478
|
+
await writeAtomicJson(path, { ...active, turn_generation_ref: turnGenerationRef });
|
|
5479
|
+
return true;
|
|
5480
|
+
}
|
|
2786
5481
|
/**
|
|
2787
5482
|
* Publish a Request reference only while the acknowledged binding is still
|
|
2788
5483
|
* the active turn. A delayed relay response therefore cannot overwrite a
|
|
@@ -2792,17 +5487,25 @@ var CodexOutboxStore = class {
|
|
|
2792
5487
|
validateBinding(binding);
|
|
2793
5488
|
const active = await this.readInvocationContext(binding.identity.host_source_ref, binding.identity.host_session_ref, now);
|
|
2794
5489
|
if (active === null || !sameIdentity(active.identity, binding.identity)) return false;
|
|
2795
|
-
await writeAtomicJson(this.activeContextPath(binding.identity), invocationContextFromBinding(binding));
|
|
5490
|
+
await writeAtomicJson(this.activeContextPath(binding.identity), invocationContextFromBinding(binding, active.turn_generation_ref));
|
|
2796
5491
|
return true;
|
|
2797
5492
|
}
|
|
2798
|
-
/** Return only the
|
|
5493
|
+
/** Return only the live session projection; never fall back to another turn. */
|
|
2799
5494
|
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
5495
|
if (!(now instanceof Date) || !Number.isFinite(now.getTime())) throw new CodexHostAdapterError("invalid_input", "Codex Host context clock is invalid.");
|
|
5496
|
+
const context = await this.readRawInvocationContext(hostSourceRef, hostSessionRef);
|
|
5497
|
+
return isLiveSessionProjection(context, now) && invocationTurnSelectionMatches(context, await this.readInvocationTurnSelection(hostSourceRef, hostSessionRef)) ? context : null;
|
|
5498
|
+
}
|
|
5499
|
+
/**
|
|
5500
|
+
* The latest Codex session projection even when past expiry, so the
|
|
5501
|
+
* invocation authenticator can report an expired context distinctly from
|
|
5502
|
+
* a missing one. Every other caller keeps the fail-closed read above.
|
|
5503
|
+
*/
|
|
5504
|
+
async readRawInvocationContext(hostSourceRef, hostSessionRef) {
|
|
5505
|
+
if (!SAFE_REF6.test(hostSourceRef) || !SAFE_REF6.test(hostSessionRef)) throw new CodexHostAdapterError("invalid_input", "Codex Host session identity is invalid.");
|
|
2802
5506
|
await this.prepare();
|
|
2803
|
-
const context = await
|
|
2804
|
-
|
|
2805
|
-
return Date.parse(context.expires_at) > now.getTime() ? context : null;
|
|
5507
|
+
const context = await readLatestSessionProjection(this.activeContextPath({ host_source_ref: hostSourceRef, host_session_ref: hostSessionRef }), hostSourceRef, hostSessionRef, (file) => readOptionalJson(file, validateCodexHostInvocationContext));
|
|
5508
|
+
return invocationTurnSelectionMatches(context, await this.readInvocationTurnSelection(hostSourceRef, hostSessionRef)) ? context : null;
|
|
2806
5509
|
}
|
|
2807
5510
|
/** Clear the projection only if the caller still owns its exact active turn. */
|
|
2808
5511
|
async clearInvocationContext(identity, now = /* @__PURE__ */ new Date()) {
|
|
@@ -2861,7 +5564,7 @@ var CodexOutboxStore = class {
|
|
|
2861
5564
|
for (const name of await readdir(this.registrationsDirectory)) {
|
|
2862
5565
|
if (!name.endsWith(".json")) continue;
|
|
2863
5566
|
try {
|
|
2864
|
-
const value = JSON.parse(await readPrivateFile(
|
|
5567
|
+
const value = JSON.parse(await readPrivateFile(join4(this.registrationsDirectory, name)));
|
|
2865
5568
|
validateRegistration(value);
|
|
2866
5569
|
registrations.push(value);
|
|
2867
5570
|
} catch {
|
|
@@ -2903,22 +5606,25 @@ var CodexOutboxStore = class {
|
|
|
2903
5606
|
}
|
|
2904
5607
|
entryPath(submissionRef) {
|
|
2905
5608
|
if (!SAFE_REF6.test(submissionRef)) throw storageError("Codex submission identity is malformed.");
|
|
2906
|
-
return
|
|
5609
|
+
return join4(this.entriesDirectory, `${cealRequestSha256(submissionRef)}.json`);
|
|
2907
5610
|
}
|
|
2908
5611
|
bindingPath(identity) {
|
|
2909
|
-
return
|
|
5612
|
+
return join4(this.bindingsDirectory, `${identityKey(identity)}.json`);
|
|
2910
5613
|
}
|
|
2911
5614
|
sessionPath(sourceRef, sessionRef) {
|
|
2912
|
-
return
|
|
5615
|
+
return join4(this.sessionsDirectory, `${identityKey({ host_source_ref: sourceRef, host_session_ref: sessionRef, host_turn_ref: "session" })}.json`);
|
|
2913
5616
|
}
|
|
2914
5617
|
activeContextPath(identity) {
|
|
2915
|
-
return
|
|
5618
|
+
return join4(this.activeContextsDirectory, `${invocationContextKey(identity)}.json`);
|
|
5619
|
+
}
|
|
5620
|
+
turnSelectionPath(sourceRef, sessionRef) {
|
|
5621
|
+
return join4(this.turnSelectionsDirectory, `${invocationContextKey({ host_source_ref: sourceRef, host_session_ref: sessionRef })}.json`);
|
|
2916
5622
|
}
|
|
2917
5623
|
registrationPath(sourceRef, sessionRef) {
|
|
2918
|
-
return
|
|
5624
|
+
return join4(this.registrationsDirectory, `${sessionStateKey(sourceRef, sessionRef)}.json`);
|
|
2919
5625
|
}
|
|
2920
5626
|
cursorPath(sourceRef, sessionRef) {
|
|
2921
|
-
return
|
|
5627
|
+
return join4(this.cursorsDirectory, `${sessionStateKey(sourceRef, sessionRef)}.json`);
|
|
2922
5628
|
}
|
|
2923
5629
|
};
|
|
2924
5630
|
async function removeOwnerState(path, what) {
|
|
@@ -2956,7 +5662,7 @@ async function findBindingByAlias(directory, sourceRef, sessionRef, alias) {
|
|
|
2956
5662
|
}
|
|
2957
5663
|
async function readBindingCandidate(directory, name) {
|
|
2958
5664
|
try {
|
|
2959
|
-
const value = JSON.parse(await readPrivateFile(
|
|
5665
|
+
const value = JSON.parse(await readPrivateFile(join4(directory, name)));
|
|
2960
5666
|
validateBinding(value);
|
|
2961
5667
|
return value;
|
|
2962
5668
|
} catch {
|
|
@@ -2975,14 +5681,14 @@ async function writeAtomicJson(path, value) {
|
|
|
2975
5681
|
if (text === void 0) throw storageError("Codex owner state cannot be serialized.");
|
|
2976
5682
|
const temp = `${path}.${process.pid}.${Math.random().toString(16).slice(2)}.tmp`;
|
|
2977
5683
|
try {
|
|
2978
|
-
const handle = await
|
|
5684
|
+
const handle = await open5(temp, "wx", 384);
|
|
2979
5685
|
try {
|
|
2980
5686
|
await handle.writeFile(text, "utf8");
|
|
2981
5687
|
await handle.sync();
|
|
2982
5688
|
} finally {
|
|
2983
5689
|
await handle.close();
|
|
2984
5690
|
}
|
|
2985
|
-
await
|
|
5691
|
+
await rename3(temp, path);
|
|
2986
5692
|
await syncDirectory(dirname(path));
|
|
2987
5693
|
} catch (error) {
|
|
2988
5694
|
try {
|
|
@@ -2995,7 +5701,7 @@ async function writeAtomicJson(path, value) {
|
|
|
2995
5701
|
}
|
|
2996
5702
|
async function syncDirectory(path) {
|
|
2997
5703
|
try {
|
|
2998
|
-
const handle = await
|
|
5704
|
+
const handle = await open5(path, "r");
|
|
2999
5705
|
try {
|
|
3000
5706
|
await handle.sync();
|
|
3001
5707
|
} finally {
|
|
@@ -3020,7 +5726,7 @@ async function ensurePrivateOwnerDirectory(path) {
|
|
|
3020
5726
|
await lstat3(path);
|
|
3021
5727
|
} catch (error) {
|
|
3022
5728
|
if (!isNotFound(error)) throw storageError("Codex owner state directory is unavailable.");
|
|
3023
|
-
await
|
|
5729
|
+
await mkdir3(path, { recursive: true, mode: 448 });
|
|
3024
5730
|
}
|
|
3025
5731
|
const stats = await lstat3(path);
|
|
3026
5732
|
const uid = typeof process.geteuid === "function" ? process.geteuid() : stats.uid;
|
|
@@ -3031,7 +5737,7 @@ async function ensurePrivateOwnerDirectory(path) {
|
|
|
3031
5737
|
async function readPrivateFile(path) {
|
|
3032
5738
|
let handle;
|
|
3033
5739
|
try {
|
|
3034
|
-
handle = await
|
|
5740
|
+
handle = await open5(path, O_RDONLY3 | O_NOFOLLOW2);
|
|
3035
5741
|
const stats = await handle.stat();
|
|
3036
5742
|
const uid = typeof process.geteuid === "function" ? process.geteuid() : stats.uid;
|
|
3037
5743
|
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 +5749,7 @@ async function readPrivateFile(path) {
|
|
|
3043
5749
|
}
|
|
3044
5750
|
}
|
|
3045
5751
|
function validateEnvelope(value) {
|
|
3046
|
-
if (!
|
|
5752
|
+
if (!isRecord5(value)) throw storageError("Codex outbox entry is malformed.");
|
|
3047
5753
|
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
5754
|
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
5755
|
validateIdentity3(value.identity);
|
|
@@ -3061,7 +5767,7 @@ function validateEnvelopeReferences(value) {
|
|
|
3061
5767
|
if (typeof value.origin_input !== "boolean") throw storageError("Codex outbox origin disposition is malformed.");
|
|
3062
5768
|
}
|
|
3063
5769
|
function validateRegistration(value) {
|
|
3064
|
-
if (!
|
|
5770
|
+
if (!isRecord5(value)) throw storageError("Codex transcript registration is malformed.");
|
|
3065
5771
|
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
5772
|
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
5773
|
validateRegistrationFields(value);
|
|
@@ -3077,12 +5783,12 @@ function validRegistrationCwd(value) {
|
|
|
3077
5783
|
return value === void 0 || typeof value === "string" && isAbsolute2(value) && value.length <= CODEX_TRANSCRIPT_PATH_MAX_CHARACTERS && !value.includes("\0");
|
|
3078
5784
|
}
|
|
3079
5785
|
function validateCursor(value) {
|
|
3080
|
-
if (!
|
|
5786
|
+
if (!isRecord5(value)) throw storageError("Codex transcript cursor is malformed.");
|
|
3081
5787
|
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
5788
|
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
5789
|
if (!validCursorSource(value) || !validCursorPosition(value) || !validCursorStatus(value)) throw storageError("Codex transcript cursor fields are malformed.");
|
|
3084
5790
|
if (value.active_task !== void 0 && !validActiveTask(value.active_task)) throw storageError("Codex transcript task cursor is malformed.");
|
|
3085
|
-
if (value.reason !== void 0 && !
|
|
5791
|
+
if (value.reason !== void 0 && !isHostTranscriptCursorReason(value.reason)) throw storageError("Codex transcript cursor reason is malformed.");
|
|
3086
5792
|
}
|
|
3087
5793
|
function validCursorSource(value) {
|
|
3088
5794
|
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 +5800,7 @@ function validCursorStatus(value) {
|
|
|
3094
5800
|
return (value.status === "active" || value.status === "quarantined") && isTimestamp(value.updated_at);
|
|
3095
5801
|
}
|
|
3096
5802
|
function validActiveTask(value) {
|
|
3097
|
-
if (!
|
|
5803
|
+
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
5804
|
return validActiveTaskIdentity(value) && validActiveTaskReferences(value) && validActiveTaskUsage(value);
|
|
3099
5805
|
}
|
|
3100
5806
|
function validActiveTaskIdentity(value) {
|
|
@@ -3110,7 +5816,7 @@ function validActiveTaskUsage(value) {
|
|
|
3110
5816
|
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
5817
|
}
|
|
3112
5818
|
function validTokenUsage(value) {
|
|
3113
|
-
if (!
|
|
5819
|
+
if (!isRecord5(value) || !sameKeys(value, ["input_tokens", "cached_input_tokens", "cache_write_input_tokens", "output_tokens", "reasoning_output_tokens", "total_tokens"])) return false;
|
|
3114
5820
|
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
5821
|
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
5822
|
}
|
|
@@ -3130,7 +5836,7 @@ function validateEnvelopeTimestamps(value) {
|
|
|
3130
5836
|
if (!isTimestamp(value.expires_at)) throw storageError("Codex outbox timestamps are malformed.");
|
|
3131
5837
|
}
|
|
3132
5838
|
function validateBinding(value) {
|
|
3133
|
-
if (!
|
|
5839
|
+
if (!isRecord5(value)) throw storageError("Codex turn binding is malformed.");
|
|
3134
5840
|
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
5841
|
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
5842
|
validateIdentity3(value.identity);
|
|
@@ -3138,19 +5844,22 @@ function validateBinding(value) {
|
|
|
3138
5844
|
if (!isStringList(value.codex_turn_ids) || !isTimestamp(value.bound_at) || !isTimestamp(value.expires_at)) throw storageError("Codex turn binding fields are malformed.");
|
|
3139
5845
|
}
|
|
3140
5846
|
function validateSession(value) {
|
|
3141
|
-
if (!
|
|
5847
|
+
if (!isRecord5(value)) throw storageError("Codex session snapshot is malformed.");
|
|
3142
5848
|
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
5849
|
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
5850
|
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
5851
|
}
|
|
5852
|
+
function validateTurnSelection(value) {
|
|
5853
|
+
if (!isHostInvocationTurnSelection(value)) throw storageError("Codex Host turn selection is malformed.");
|
|
5854
|
+
}
|
|
3146
5855
|
function validateIdentity3(value) {
|
|
3147
|
-
if (!
|
|
5856
|
+
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
5857
|
}
|
|
3149
5858
|
function isJsonValue(value) {
|
|
3150
5859
|
if (value === null || typeof value === "string" || typeof value === "boolean") return true;
|
|
3151
5860
|
if (typeof value === "number") return Number.isFinite(value);
|
|
3152
5861
|
if (Array.isArray(value)) return value.every(isJsonValue);
|
|
3153
|
-
return
|
|
5862
|
+
return isRecord5(value) && Object.entries(value).every(([key, child]) => key.length > 0 && key.length <= 128 && isJsonValue(child));
|
|
3154
5863
|
}
|
|
3155
5864
|
function isStringList(value) {
|
|
3156
5865
|
return Array.isArray(value) && value.every((candidate) => typeof candidate === "string" && SAFE_REF6.test(candidate));
|
|
@@ -3163,104 +5872,50 @@ function sameKeys(value, required, optional = []) {
|
|
|
3163
5872
|
const keys = Object.keys(value);
|
|
3164
5873
|
return keys.length >= required.length && keys.length <= allowed.size && required.every((key) => Object.hasOwn(value, key)) && keys.every((key) => allowed.has(key));
|
|
3165
5874
|
}
|
|
3166
|
-
function
|
|
5875
|
+
function isRecord5(value) {
|
|
3167
5876
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3168
5877
|
}
|
|
3169
5878
|
function isNotFound(error) {
|
|
3170
|
-
return
|
|
5879
|
+
return isRecord5(error) && error.code === "ENOENT";
|
|
3171
5880
|
}
|
|
3172
5881
|
function storageError(message) {
|
|
3173
5882
|
return new CodexHostAdapterError("storage", message);
|
|
3174
5883
|
}
|
|
3175
5884
|
|
|
3176
5885
|
// 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";
|
|
5886
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
3181
5887
|
var SAFE_REF7 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
|
|
3182
5888
|
var CodexProducer = class {
|
|
5889
|
+
producer_id = "codex";
|
|
5890
|
+
producer_label = "Codex";
|
|
5891
|
+
outbox_directory;
|
|
3183
5892
|
store;
|
|
3184
|
-
|
|
3185
|
-
installationRef;
|
|
3186
|
-
epoch;
|
|
3187
|
-
relay;
|
|
3188
|
-
now;
|
|
3189
|
-
tail = Promise.resolve();
|
|
5893
|
+
core;
|
|
3190
5894
|
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
5895
|
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());
|
|
5896
|
+
this.outbox_directory = this.store.directory;
|
|
5897
|
+
this.core = new HostProducerDrainCore(this, options);
|
|
3200
5898
|
}
|
|
3201
5899
|
drainOutbox() {
|
|
3202
|
-
|
|
3203
|
-
this.tail = run.then(() => void 0, () => void 0);
|
|
3204
|
-
return run;
|
|
5900
|
+
return this.core.drainOutbox();
|
|
3205
5901
|
}
|
|
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 };
|
|
5902
|
+
fail(code, message) {
|
|
5903
|
+
return new CodexHostAdapterError(code, message);
|
|
3236
5904
|
}
|
|
3237
|
-
|
|
3238
|
-
return
|
|
5905
|
+
listEnvelopes() {
|
|
5906
|
+
return this.store.list();
|
|
3239
5907
|
}
|
|
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;
|
|
5908
|
+
removeEnvelope(envelope) {
|
|
5909
|
+
return this.store.remove(envelope);
|
|
3257
5910
|
}
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
5911
|
+
submissionRefOf(envelope) {
|
|
5912
|
+
return envelope.submission_ref;
|
|
5913
|
+
}
|
|
5914
|
+
expiresAtOf(envelope) {
|
|
5915
|
+
return envelope.expires_at;
|
|
5916
|
+
}
|
|
5917
|
+
createdAtOf(envelope) {
|
|
5918
|
+
return envelope.created_at;
|
|
3264
5919
|
}
|
|
3265
5920
|
async mapEnvelope(envelope) {
|
|
3266
5921
|
const prompt = observation(envelope, "prompt");
|
|
@@ -3276,7 +5931,7 @@ var CodexProducer = class {
|
|
|
3276
5931
|
const directoryIdentity = registration?.cwd ?? envelope.identity.host_session_ref;
|
|
3277
5932
|
drafts.push({ frame_kind: "session_started", payload: compact({
|
|
3278
5933
|
local_session_ref: envelope.identity.host_session_ref,
|
|
3279
|
-
working_directory_ref: `workspace:${
|
|
5934
|
+
working_directory_ref: `workspace:${createHash6("sha256").update(directoryIdentity, "utf8").digest("hex")}`,
|
|
3280
5935
|
model: recordText(session.value, "model"),
|
|
3281
5936
|
host_version: nestedText(session.value, "host_version"),
|
|
3282
5937
|
observations: [session]
|
|
@@ -3301,21 +5956,6 @@ var CodexProducer = class {
|
|
|
3301
5956
|
}) });
|
|
3302
5957
|
return drafts;
|
|
3303
5958
|
}
|
|
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
5959
|
};
|
|
3320
5960
|
function mapTerminal(envelope) {
|
|
3321
5961
|
const timing = observation(envelope, "timing");
|
|
@@ -3343,7 +5983,7 @@ function compact(value) {
|
|
|
3343
5983
|
return Object.fromEntries(Object.entries(value).filter((entry) => entry[1] !== void 0));
|
|
3344
5984
|
}
|
|
3345
5985
|
function asRecord(value) {
|
|
3346
|
-
return
|
|
5986
|
+
return isRecord6(value) ? value : void 0;
|
|
3347
5987
|
}
|
|
3348
5988
|
function recordText(value, key) {
|
|
3349
5989
|
const record3 = asRecord(value);
|
|
@@ -3357,53 +5997,14 @@ function nonNegativeNumber(value) {
|
|
|
3357
5997
|
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
|
|
3358
5998
|
}
|
|
3359
5999
|
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;
|
|
6000
|
+
return SAFE_REF7.test(value) ? value : `reason:${createHash6("sha256").update(value, "utf8").digest("hex")}`;
|
|
3395
6001
|
}
|
|
3396
|
-
function
|
|
6002
|
+
function isRecord6(value) {
|
|
3397
6003
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3398
6004
|
}
|
|
3399
6005
|
|
|
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
6006
|
// host/codex/src/codex-transcript-baseline.ts
|
|
3406
|
-
import { createHash as
|
|
6007
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
3407
6008
|
|
|
3408
6009
|
// host/codex/src/codex-transcript-decoder.ts
|
|
3409
6010
|
var SAFE_REF8 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u;
|
|
@@ -3415,40 +6016,40 @@ function decodeCodexTranscriptLine(line) {
|
|
|
3415
6016
|
} catch {
|
|
3416
6017
|
reject("Codex transcript record is not valid JSON.");
|
|
3417
6018
|
}
|
|
3418
|
-
if (!
|
|
6019
|
+
if (!isRecord7(value)) reject("Codex transcript record envelope is malformed.");
|
|
3419
6020
|
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,
|
|
6021
|
+
const timestamp4 = safeTimestamp(value.timestamp);
|
|
6022
|
+
if (!isRecord7(value.payload) || typeof value.type !== "string") reject("Codex transcript record payload is malformed.");
|
|
6023
|
+
if (value.type === "session_meta") return decodeSessionMeta(value.payload, ordinal, timestamp4);
|
|
6024
|
+
if (value.type === "turn_context") return decodeTurnContext(value.payload, ordinal, timestamp4);
|
|
6025
|
+
if (value.type === "event_msg") return decodeEventMessage(value.payload, ordinal, timestamp4);
|
|
6026
|
+
if (value.type === "response_item") return decodeResponseItem(value.payload, ordinal, timestamp4);
|
|
6027
|
+
return { kind: "ignored", ordinal, timestamp: timestamp4 };
|
|
6028
|
+
}
|
|
6029
|
+
function decodeTurnContext(payload, ordinal, timestamp4) {
|
|
3429
6030
|
return {
|
|
3430
6031
|
kind: "turn_context",
|
|
3431
6032
|
ordinal,
|
|
3432
|
-
timestamp:
|
|
3433
|
-
turn_id:
|
|
6033
|
+
timestamp: timestamp4,
|
|
6034
|
+
turn_id: safeRef5(payload.turn_id, "Codex turn context identity is invalid."),
|
|
3434
6035
|
model: boundedNonEmptyText(payload.model, 256, "Codex turn context model is invalid.")
|
|
3435
6036
|
};
|
|
3436
6037
|
}
|
|
3437
|
-
function decodeSessionMeta(payload, ordinal,
|
|
3438
|
-
const sessionId =
|
|
6038
|
+
function decodeSessionMeta(payload, ordinal, timestamp4) {
|
|
6039
|
+
const sessionId = safeRef5(payload.id, "Codex transcript session identity is invalid.");
|
|
3439
6040
|
const cliVersion = boundedNonEmptyText(payload.cli_version, 64, "Codex transcript version is invalid.");
|
|
3440
|
-
return { kind: "session_meta", ordinal, timestamp:
|
|
6041
|
+
return { kind: "session_meta", ordinal, timestamp: timestamp4, session_id: sessionId, cli_version: cliVersion };
|
|
3441
6042
|
}
|
|
3442
|
-
function decodeEventMessage(payload, ordinal,
|
|
6043
|
+
function decodeEventMessage(payload, ordinal, timestamp4) {
|
|
3443
6044
|
if (payload.type === "task_started") {
|
|
3444
|
-
return { kind: "task_started", ordinal, timestamp:
|
|
6045
|
+
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
6046
|
}
|
|
3446
6047
|
if (payload.type === "task_complete") {
|
|
3447
6048
|
return {
|
|
3448
6049
|
kind: "task_complete",
|
|
3449
6050
|
ordinal,
|
|
3450
|
-
timestamp:
|
|
3451
|
-
turn_id:
|
|
6051
|
+
timestamp: timestamp4,
|
|
6052
|
+
turn_id: safeRef5(payload.turn_id, "Codex task identity is invalid."),
|
|
3452
6053
|
started_at: safeNumber(payload.started_at),
|
|
3453
6054
|
completed_at: safeNumber(payload.completed_at),
|
|
3454
6055
|
duration_ms: safeNumber(payload.duration_ms),
|
|
@@ -3459,20 +6060,20 @@ function decodeEventMessage(payload, ordinal, timestamp5) {
|
|
|
3459
6060
|
return {
|
|
3460
6061
|
kind: "turn_aborted",
|
|
3461
6062
|
ordinal,
|
|
3462
|
-
timestamp:
|
|
3463
|
-
turn_id:
|
|
6063
|
+
timestamp: timestamp4,
|
|
6064
|
+
turn_id: safeRef5(payload.turn_id, "Codex task identity is invalid."),
|
|
3464
6065
|
started_at: safeNumber(payload.started_at),
|
|
3465
6066
|
completed_at: safeNumber(payload.completed_at),
|
|
3466
6067
|
duration_ms: safeNumber(payload.duration_ms),
|
|
3467
6068
|
reason: boundedText(payload.reason, 256, "Codex task abort reason is invalid.")
|
|
3468
6069
|
};
|
|
3469
6070
|
}
|
|
3470
|
-
if (payload.type === "token_count") return decodeTokenCount(payload, ordinal,
|
|
3471
|
-
return { kind: "ignored", ordinal, timestamp:
|
|
6071
|
+
if (payload.type === "token_count") return decodeTokenCount(payload, ordinal, timestamp4);
|
|
6072
|
+
return { kind: "ignored", ordinal, timestamp: timestamp4 };
|
|
3472
6073
|
}
|
|
3473
|
-
function decodeTokenCount(payload, ordinal,
|
|
3474
|
-
if (payload.info === null) return { kind: "token_count", ordinal, timestamp:
|
|
3475
|
-
if (!
|
|
6074
|
+
function decodeTokenCount(payload, ordinal, timestamp4) {
|
|
6075
|
+
if (payload.info === null) return { kind: "token_count", ordinal, timestamp: timestamp4 };
|
|
6076
|
+
if (!isRecord7(payload.info)) return { kind: "token_count", ordinal, timestamp: timestamp4, usage_gap_reason: "token_count_shape_not_attributable" };
|
|
3476
6077
|
const lastUsage = optionalTokenUsage(payload.info.last_token_usage);
|
|
3477
6078
|
const totalUsage = optionalTokenUsage(payload.info.total_token_usage);
|
|
3478
6079
|
const gap = lastUsage.status === "invalid" || totalUsage.status === "invalid";
|
|
@@ -3480,7 +6081,7 @@ function decodeTokenCount(payload, ordinal, timestamp5) {
|
|
|
3480
6081
|
return {
|
|
3481
6082
|
kind: "token_count",
|
|
3482
6083
|
ordinal,
|
|
3483
|
-
timestamp:
|
|
6084
|
+
timestamp: timestamp4,
|
|
3484
6085
|
...lastUsage.status === "valid" ? { last_usage: lastUsage.value } : {},
|
|
3485
6086
|
...totalUsage.status === "valid" ? { total_usage: totalUsage.value } : {},
|
|
3486
6087
|
...usageGapReason === void 0 ? {} : { usage_gap_reason: usageGapReason }
|
|
@@ -3496,7 +6097,7 @@ function optionalTokenUsage(value) {
|
|
|
3496
6097
|
}
|
|
3497
6098
|
}
|
|
3498
6099
|
function decodeTokenUsage(value) {
|
|
3499
|
-
if (!
|
|
6100
|
+
if (!isRecord7(value)) reject("Codex token usage is malformed.");
|
|
3500
6101
|
const usage = {
|
|
3501
6102
|
input_tokens: safeTokenCount(value.input_tokens),
|
|
3502
6103
|
cached_input_tokens: safeTokenCount(value.cached_input_tokens),
|
|
@@ -3508,20 +6109,20 @@ function decodeTokenUsage(value) {
|
|
|
3508
6109
|
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
6110
|
return usage;
|
|
3510
6111
|
}
|
|
3511
|
-
function decodeResponseItem(payload, ordinal,
|
|
3512
|
-
if (payload.type !== "message" || payload.role !== "user") return { kind: "ignored", ordinal, timestamp:
|
|
6112
|
+
function decodeResponseItem(payload, ordinal, timestamp4) {
|
|
6113
|
+
if (payload.type !== "message" || payload.role !== "user") return { kind: "ignored", ordinal, timestamp: timestamp4 };
|
|
3513
6114
|
const metadata = userMessageMetadata(payload.internal_chat_message_metadata_passthrough);
|
|
3514
6115
|
const inputKind = inputKindFromContentItems(metadata.content_item_kinds);
|
|
3515
|
-
if (inputKind === void 0) return { kind: "ignored", ordinal, timestamp:
|
|
6116
|
+
if (inputKind === void 0) return { kind: "ignored", ordinal, timestamp: timestamp4 };
|
|
3516
6117
|
const prompt = userTextContent(payload.content);
|
|
3517
6118
|
return {
|
|
3518
6119
|
kind: "user_text",
|
|
3519
6120
|
ordinal,
|
|
3520
|
-
timestamp:
|
|
6121
|
+
timestamp: timestamp4,
|
|
3521
6122
|
prompt,
|
|
3522
6123
|
input_kind: inputKind,
|
|
3523
|
-
message_id:
|
|
3524
|
-
turn_id:
|
|
6124
|
+
message_id: safeRef5(payload.id, "Codex user message identity is invalid."),
|
|
6125
|
+
turn_id: safeRef5(metadata.turn_id, "Codex user message task identity is invalid.")
|
|
3525
6126
|
};
|
|
3526
6127
|
}
|
|
3527
6128
|
function inputKindFromContentItems(kinds) {
|
|
@@ -3530,13 +6131,13 @@ function inputKindFromContentItems(kinds) {
|
|
|
3530
6131
|
return kinds[0] === "goal.internal_context" ? "host_automatic" : void 0;
|
|
3531
6132
|
}
|
|
3532
6133
|
function userMessageMetadata(value) {
|
|
3533
|
-
if (!
|
|
6134
|
+
if (!isRecord7(value) || !Array.isArray(value.content_item_kinds)) reject("Codex user message provenance is malformed.");
|
|
3534
6135
|
return { ...value, content_item_kinds: value.content_item_kinds };
|
|
3535
6136
|
}
|
|
3536
6137
|
function userTextContent(value) {
|
|
3537
6138
|
if (!Array.isArray(value)) reject(`Codex user text content is malformed (${refusalFact("kind", typeof value, "array")}).`);
|
|
3538
6139
|
if (value.length !== 1) reject(`Codex user text content is malformed (${refusalFact("items", value.length, "exactly one")}).`);
|
|
3539
|
-
if (!
|
|
6140
|
+
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
6141
|
return boundedText(value[0].text, MAX_PROMPT_BYTES, "Codex user text is invalid.");
|
|
3541
6142
|
}
|
|
3542
6143
|
function safeOrdinal(value) {
|
|
@@ -3557,7 +6158,7 @@ function safeTimestamp(value) {
|
|
|
3557
6158
|
if (!Number.isFinite(Date.parse(value))) reject(`Codex transcript timestamp is invalid (${refusalFact("parsed_ms", Date.parse(value), "a finite epoch milliseconds value")}).`);
|
|
3558
6159
|
return value;
|
|
3559
6160
|
}
|
|
3560
|
-
function
|
|
6161
|
+
function safeRef5(value, message) {
|
|
3561
6162
|
if (typeof value !== "string" || !SAFE_REF8.test(value)) reject(message);
|
|
3562
6163
|
return value;
|
|
3563
6164
|
}
|
|
@@ -3572,7 +6173,7 @@ function boundedNonEmptyText(value, maximum, message) {
|
|
|
3572
6173
|
if (result.length === 0) reject(message);
|
|
3573
6174
|
return result;
|
|
3574
6175
|
}
|
|
3575
|
-
function
|
|
6176
|
+
function isRecord7(value) {
|
|
3576
6177
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3577
6178
|
}
|
|
3578
6179
|
function reject(message) {
|
|
@@ -3616,7 +6217,7 @@ function assertCodexTranscriptHeader(registration, record3) {
|
|
|
3616
6217
|
])}).`);
|
|
3617
6218
|
}
|
|
3618
6219
|
function digest(value) {
|
|
3619
|
-
return
|
|
6220
|
+
return createHash7("sha256").update(value).digest("hex");
|
|
3620
6221
|
}
|
|
3621
6222
|
function timestamp3(now) {
|
|
3622
6223
|
const value = now();
|
|
@@ -3632,78 +6233,44 @@ function codexSubmissionReference(hostInputRef, event, ordinal) {
|
|
|
3632
6233
|
}
|
|
3633
6234
|
|
|
3634
6235
|
// host/codex/src/codex-transcript-watcher.ts
|
|
3635
|
-
var
|
|
3636
|
-
var TRANSCRIPT_MISSING_REASON = "transcript_missing";
|
|
3637
|
-
var CodexTranscriptWatcher = class {
|
|
6236
|
+
var CodexTranscriptWatcher = class extends HostTranscriptWatcher {
|
|
3638
6237
|
store;
|
|
3639
|
-
outboxRetentionMs;
|
|
3640
|
-
now;
|
|
3641
|
-
log;
|
|
3642
|
-
producerInstallationRef;
|
|
3643
6238
|
registerCurrentPrompt;
|
|
3644
6239
|
constructor(options) {
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
this.log = options.log ?? ((line) => {
|
|
3650
|
-
process.stderr.write(`${line}
|
|
3651
|
-
`);
|
|
6240
|
+
super(options, {
|
|
6241
|
+
default_retention_ms: CODEX_DEFAULT_RETENTION_MS,
|
|
6242
|
+
invalid_outbox: () => new CodexHostAdapterError("configuration", "Codex transcript watcher outbox is invalid."),
|
|
6243
|
+
clock_failure: () => new CodexHostAdapterError("storage", "Codex watcher clock is invalid.")
|
|
3652
6244
|
});
|
|
3653
|
-
this.
|
|
6245
|
+
this.store = new CodexOutboxStore(options.outbox_dir);
|
|
3654
6246
|
this.registerCurrentPrompt = options.register_current_prompt;
|
|
3655
6247
|
}
|
|
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 };
|
|
6248
|
+
transcriptPathOf(registration) {
|
|
6249
|
+
return registration.transcript_path;
|
|
3668
6250
|
}
|
|
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
|
-
}
|
|
6251
|
+
async listRegistrations() {
|
|
6252
|
+
return this.store.listTranscriptRegistrations();
|
|
3686
6253
|
}
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
return
|
|
6254
|
+
async scanOpened(handle, registration) {
|
|
6255
|
+
const { size, device, inode } = await ownedCodexTranscriptFile(handle);
|
|
6256
|
+
const preflight = await this.preflight(registration, handle, size, device, inode);
|
|
6257
|
+
if (preflight.cursor === null) return preflight.result;
|
|
6258
|
+
const complete = await this.readChunk(handle, preflight.cursor.offset, size);
|
|
6259
|
+
if (complete === "empty" || complete === "partial") return { records: 0, enqueued: 0, quarantined: false };
|
|
6260
|
+
return await this.consumeCompleteChunk(registration, handle, preflight.cursor, complete, device, inode);
|
|
6261
|
+
}
|
|
6262
|
+
async scanFailed(handle, registration, _error) {
|
|
6263
|
+
await this.quarantineFailure(registration, handle);
|
|
6264
|
+
return { records: 0, enqueued: 0, quarantined: true };
|
|
6265
|
+
}
|
|
6266
|
+
async retireMissing(registration) {
|
|
6267
|
+
return this.retireMissingTranscript(registration.transcript_path, "Codex", () => this.store.retireTranscriptRegistration(registration));
|
|
3701
6268
|
}
|
|
3702
6269
|
async preflight(registration, handle, size, device, inode) {
|
|
3703
6270
|
const existing = await this.store.readTranscriptCursor(registration);
|
|
3704
6271
|
let cursor = existing ?? codexTranscriptInitialCursor(registration, device, inode, this.now);
|
|
3705
6272
|
if (cursor.status === "quarantined") return { cursor: null, result: { records: 0, enqueued: 0, quarantined: true } };
|
|
3706
|
-
const reason =
|
|
6273
|
+
const reason = this.cursorIdentityReason(cursor, registration.transcript_path, device, inode) ?? await this.cursorBoundsReason(handle, cursor, size);
|
|
3707
6274
|
if (reason === null) return { cursor, result: { records: 0, enqueued: 0, quarantined: false } };
|
|
3708
6275
|
await this.quarantine(registration, cursor, device, inode, reason);
|
|
3709
6276
|
return { cursor: null, result: { records: 0, enqueued: 0, quarantined: true } };
|
|
@@ -3729,14 +6296,12 @@ var CodexTranscriptWatcher = class {
|
|
|
3729
6296
|
async observeSessionMetadata(registration, record3) {
|
|
3730
6297
|
if (record3.kind !== "session_meta") return;
|
|
3731
6298
|
const session = await this.store.readSession(registration.host_source_ref, registration.host_session_ref);
|
|
3732
|
-
if (session !== null &&
|
|
6299
|
+
if (session !== null && this.isRecord(session.value)) await this.store.saveSession({ ...session, value: { ...session.value, host_version: record3.cli_version } });
|
|
3733
6300
|
}
|
|
3734
6301
|
async commitCursor(registration, handle, cursor, consumedBytes, device, inode, lastOrdinal, activeTask) {
|
|
3735
6302
|
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) });
|
|
6303
|
+
const anchor = await this.readAnchor(handle, offset, CODEX_TRANSCRIPT_ANCHOR_BYTES);
|
|
6304
|
+
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
6305
|
}
|
|
3741
6306
|
async quarantineFailure(registration, handle) {
|
|
3742
6307
|
if (handle === void 0) return;
|
|
@@ -3785,11 +6350,11 @@ var CodexTranscriptWatcher = class {
|
|
|
3785
6350
|
origin_input: origin,
|
|
3786
6351
|
submission_ref: codexSubmissionReference(hostInputRef, "input", record3.ordinal),
|
|
3787
6352
|
created_at: record3.timestamp,
|
|
3788
|
-
expires_at:
|
|
6353
|
+
expires_at: this.expire(this.outboxRetentionMs)
|
|
3789
6354
|
};
|
|
3790
6355
|
await this.registerPrompt(origin, registration, activeTask, currentPromptRef, record3.prompt, envelope.expires_at);
|
|
3791
6356
|
await this.store.put(envelope);
|
|
3792
|
-
if (origin) await this.store
|
|
6357
|
+
if (origin) await activateTranscriptTurnContext(this.store, identity, promptRef, envelope.expires_at);
|
|
3793
6358
|
return { activeTask: { ...activeTask, origin_host_input_ref: activeTask.origin_host_input_ref ?? hostInputRef, prompt_ref: activeTask.prompt_ref ?? currentPromptRef }, enqueued: 1 };
|
|
3794
6359
|
}
|
|
3795
6360
|
async registerPrompt(origin, registration, activeTask, promptRef, prompt, expiresAt) {
|
|
@@ -3812,16 +6377,21 @@ var CodexTranscriptWatcher = class {
|
|
|
3812
6377
|
origin_input: false,
|
|
3813
6378
|
submission_ref: codexSubmissionReference(activeTask.origin_host_input_ref, "terminal", record3.ordinal),
|
|
3814
6379
|
created_at: record3.timestamp,
|
|
3815
|
-
expires_at:
|
|
6380
|
+
expires_at: this.expire(this.outboxRetentionMs)
|
|
3816
6381
|
});
|
|
3817
6382
|
await this.store.clearInvocationContext(identity, this.now());
|
|
3818
6383
|
return { enqueued: 1 };
|
|
3819
6384
|
}
|
|
3820
6385
|
async quarantine(registration, cursor, device, inode, reason) {
|
|
3821
|
-
const quarantined = { ...cursor, transcript_path: registration.transcript_path, device, inode, status: "quarantined", reason, updated_at:
|
|
6386
|
+
const quarantined = { ...cursor, transcript_path: registration.transcript_path, device, inode, status: "quarantined", reason, updated_at: this.stamp() };
|
|
3822
6387
|
await this.store.writeTranscriptCursor(quarantined);
|
|
3823
6388
|
}
|
|
3824
6389
|
};
|
|
6390
|
+
async function activateTranscriptTurnContext(store, identity, promptRef, expiresAt) {
|
|
6391
|
+
const selection = await store.readInvocationTurnSelection(identity.host_source_ref, identity.host_session_ref);
|
|
6392
|
+
const turnGenerationRef = selection?.prompt_ref === promptRef ? selection.turn_generation_ref : void 0;
|
|
6393
|
+
await store.activateInvocationContext(identity, promptRef, expiresAt, turnGenerationRef);
|
|
6394
|
+
}
|
|
3825
6395
|
function accumulateTokenCount(activeTask, record3) {
|
|
3826
6396
|
if (record3.usage_gap_reason !== void 0) return { ...activeTask, token_usage_gap_reason: record3.usage_gap_reason };
|
|
3827
6397
|
const last = record3.last_usage;
|
|
@@ -3855,19 +6425,18 @@ function terminalCostValue() {
|
|
|
3855
6425
|
return notRecorded("provider_cost_not_observed");
|
|
3856
6426
|
}
|
|
3857
6427
|
function notRecorded(reason) {
|
|
3858
|
-
return
|
|
6428
|
+
return hostObservationNotRecorded(reason);
|
|
3859
6429
|
}
|
|
3860
6430
|
function tokenObservationValue(usage) {
|
|
3861
6431
|
return {
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
source: "codex_transcript.event_msg.token_count.info.last_token_usage",
|
|
6432
|
+
...createHostTokenObservationValue({
|
|
6433
|
+
input: usage.input_tokens,
|
|
6434
|
+
output: usage.output_tokens,
|
|
6435
|
+
total: usage.total_tokens,
|
|
6436
|
+
cached_input: usage.cached_input_tokens,
|
|
6437
|
+
cache_write_input: usage.cache_write_input_tokens,
|
|
6438
|
+
reasoning_output: usage.reasoning_output_tokens
|
|
6439
|
+
}, "codex_transcript.event_msg.token_count.info.last_token_usage"),
|
|
3871
6440
|
attribution: "sequential_active_task",
|
|
3872
6441
|
total_usage_role: "dedup_and_reset_detection_only"
|
|
3873
6442
|
};
|
|
@@ -3901,60 +6470,10 @@ function looksLikeStaleRegression(current, previous, last) {
|
|
|
3901
6470
|
if (previous.total_tokens <= 0 || current.total_tokens <= 0 || last.total_tokens <= 0) return false;
|
|
3902
6471
|
return current.total_tokens * 100 >= previous.total_tokens * 98 || current.total_tokens + last.total_tokens * 2 >= previous.total_tokens;
|
|
3903
6472
|
}
|
|
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
6473
|
function assertRecordSequence(registration, cursor, records, lastOrdinal, record3) {
|
|
3936
6474
|
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
6475
|
if (!cursor.header_validated && records === 0) assertCodexTranscriptHeader(registration, record3);
|
|
3938
6476
|
}
|
|
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
6477
|
|
|
3959
6478
|
// host/codex/src/codex-producer-runtime.ts
|
|
3960
6479
|
async function drainCodexProducerOnce(options) {
|
|
@@ -3982,15 +6501,52 @@ var CODEX_PRODUCER_DESCRIPTOR = {
|
|
|
3982
6501
|
drain: drainCodexProducerOnce
|
|
3983
6502
|
};
|
|
3984
6503
|
|
|
6504
|
+
// host/codex/src/codex-visible-output-budget.ts
|
|
6505
|
+
import { readFile as readFile3 } from "node:fs/promises";
|
|
6506
|
+
import { homedir } from "node:os";
|
|
6507
|
+
import { join as join5 } from "node:path";
|
|
6508
|
+
var import_toml = __toESM(require_toml(), 1);
|
|
6509
|
+
var CODEX_DEFAULT_TOOL_OUTPUT_TOKEN_LIMIT = 5e3;
|
|
6510
|
+
var CODEX_UTF8_BYTES_PER_OUTPUT_TOKEN = 4;
|
|
6511
|
+
async function resolveCodexVisibleOutputMaxBytes(environment = process.env) {
|
|
6512
|
+
const codexHome = environment.CODEX_HOME || join5(homedir(), ".codex");
|
|
6513
|
+
let source;
|
|
6514
|
+
try {
|
|
6515
|
+
source = await readFile3(join5(codexHome, "config.toml"), "utf8");
|
|
6516
|
+
} catch (error) {
|
|
6517
|
+
return isNotFound2(error) ? codexBytes(CODEX_DEFAULT_TOOL_OUTPUT_TOKEN_LIMIT) : void 0;
|
|
6518
|
+
}
|
|
6519
|
+
try {
|
|
6520
|
+
const parsed = import_toml.default.parse(source);
|
|
6521
|
+
if (!isRecord8(parsed)) return void 0;
|
|
6522
|
+
const configured = parsed.tool_output_token_limit;
|
|
6523
|
+
if (configured === void 0) return codexBytes(CODEX_DEFAULT_TOOL_OUTPUT_TOKEN_LIMIT);
|
|
6524
|
+
return typeof configured === "number" && Number.isSafeInteger(configured) && configured > 0 ? codexBytes(configured) : void 0;
|
|
6525
|
+
} catch {
|
|
6526
|
+
return void 0;
|
|
6527
|
+
}
|
|
6528
|
+
}
|
|
6529
|
+
function codexBytes(tokens) {
|
|
6530
|
+
return Math.min(tokens * CODEX_UTF8_BYTES_PER_OUTPUT_TOKEN, CEAL_CANONICAL_HTTP_MAX_RESPONSE_BYTES);
|
|
6531
|
+
}
|
|
6532
|
+
function isRecord8(value) {
|
|
6533
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
6534
|
+
}
|
|
6535
|
+
function isNotFound2(error) {
|
|
6536
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
6537
|
+
}
|
|
6538
|
+
|
|
3985
6539
|
// host/codex/src/codex-invocation-authentication-command.ts
|
|
3986
6540
|
var CODEX_INVOCATION_AUTHENTICATION_DESCRIPTOR = {
|
|
3987
6541
|
producer_id: "codex",
|
|
6542
|
+
context_activation_wait_max_ms: CODEX_CONTEXT_ACTIVATION_WAIT_MAX_MS,
|
|
3988
6543
|
create_store: (directory) => new CodexOutboxStore(directory),
|
|
3989
6544
|
session_id_env: CODEX_THREAD_ID_ENVIRONMENT,
|
|
3990
6545
|
session_ref: hostSessionReference,
|
|
3991
6546
|
config_flag: HOST_PRODUCER_CONFIG_FLAG,
|
|
3992
6547
|
parse_config_flag: parseHostProducerConfigFlag,
|
|
3993
|
-
read_producer_config: (configPath) => readHostProducerConfig(CODEX_PRODUCER_DESCRIPTOR, configPath)
|
|
6548
|
+
read_producer_config: (configPath) => readHostProducerConfig(CODEX_PRODUCER_DESCRIPTOR, configPath),
|
|
6549
|
+
resolve_visible_output_max_bytes: () => resolveCodexVisibleOutputMaxBytes()
|
|
3994
6550
|
};
|
|
3995
6551
|
function runCodexInvocationAuthenticationCommand(args, options) {
|
|
3996
6552
|
return runHostInvocationAuthenticationCommand(CODEX_INVOCATION_AUTHENTICATION_DESCRIPTOR, args, options);
|