@orkestrel/terminal 0.0.1 → 0.0.2
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/dist/src/core/index.cjs +572 -58
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +424 -7
- package/dist/src/core/index.d.ts +424 -7
- package/dist/src/core/index.js +563 -60
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +12 -11
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +12 -12
- package/dist/src/server/index.d.ts +12 -12
- package/dist/src/server/index.js +12 -11
- package/dist/src/server/index.js.map +1 -1
- package/package.json +7 -6
package/dist/src/core/index.cjs
CHANGED
|
@@ -3,6 +3,7 @@ let _orkestrel_contract = require("@orkestrel/contract");
|
|
|
3
3
|
let _orkestrel_console = require("@orkestrel/console");
|
|
4
4
|
let _orkestrel_emitter = require("@orkestrel/emitter");
|
|
5
5
|
let _orkestrel_sse = require("@orkestrel/sse");
|
|
6
|
+
let _orkestrel_database = require("@orkestrel/database");
|
|
6
7
|
//#region src/core/constants.ts
|
|
7
8
|
/** Carriage return (`\r`, U+000D) — Enter on most terminals. */
|
|
8
9
|
var RETURN = String.fromCharCode(13);
|
|
@@ -1034,8 +1035,10 @@ var isPendingPrompt = (0, _orkestrel_contract.recordOf)({
|
|
|
1034
1035
|
message: _orkestrel_contract.isString,
|
|
1035
1036
|
options: _orkestrel_contract.isRecord,
|
|
1036
1037
|
status: isPendingPromptStatus,
|
|
1037
|
-
time: _orkestrel_contract.isNumber
|
|
1038
|
-
|
|
1038
|
+
time: _orkestrel_contract.isNumber,
|
|
1039
|
+
from: _orkestrel_contract.isString,
|
|
1040
|
+
to: _orkestrel_contract.isString
|
|
1041
|
+
}, ["from", "to"]);
|
|
1039
1042
|
/**
|
|
1040
1043
|
* Rebuild a wire-decoded `validate` payload into a {@link ValidationRules} bag — the inverse of
|
|
1041
1044
|
* {@link serializeValidationRules}. Keeps only the primitive rule values (`boolean` / `number` /
|
|
@@ -1233,6 +1236,37 @@ function isInsecureRemote(url) {
|
|
|
1233
1236
|
const hostname = host.startsWith("[") ? host.slice(0, host.indexOf("]") + 1) : host.split(":")[0] ?? "";
|
|
1234
1237
|
return hostname !== "localhost" && hostname !== "127.0.0.1" && hostname !== "[::1]";
|
|
1235
1238
|
}
|
|
1239
|
+
/** Serialize a parked {@link PendingPrompt} into a {@link WireEvent} — event `'pending'`, `data` the JSON-stringified prompt, `id` the prompt's own id (an SSE bridge sets its frame `id:` from this). */
|
|
1240
|
+
function serializePending(prompt) {
|
|
1241
|
+
return {
|
|
1242
|
+
event: "pending",
|
|
1243
|
+
data: JSON.stringify(prompt),
|
|
1244
|
+
id: prompt.id
|
|
1245
|
+
};
|
|
1246
|
+
}
|
|
1247
|
+
/** Serialize a parked prompt's expiry into a {@link WireEvent} — event `'expire'`, `data` the JSON-stringified `{ id }` payload. */
|
|
1248
|
+
function serializeExpire(id) {
|
|
1249
|
+
return {
|
|
1250
|
+
event: "expire",
|
|
1251
|
+
data: JSON.stringify({ id })
|
|
1252
|
+
};
|
|
1253
|
+
}
|
|
1254
|
+
/** The {@link WireEvent} a broker/manager sends when it is going away — event `'shutdown'`, no payload. */
|
|
1255
|
+
function serializeShutdown() {
|
|
1256
|
+
return {
|
|
1257
|
+
event: "shutdown",
|
|
1258
|
+
data: ""
|
|
1259
|
+
};
|
|
1260
|
+
}
|
|
1261
|
+
/** Narrow an unknown wire payload to an answer POST body — a non-empty `id` string plus a `value` key (of any shape) present. */
|
|
1262
|
+
function isAnswerPayload(value) {
|
|
1263
|
+
return (0, _orkestrel_contract.isRecord)(value) && (0, _orkestrel_contract.isNonEmptyString)(value.id) && "value" in value;
|
|
1264
|
+
}
|
|
1265
|
+
/** Narrow an unknown value to a {@link TerminalSnapshot} — a non-empty `id` plus an optional numeric `timeout`. */
|
|
1266
|
+
var isTerminalSnapshot = (0, _orkestrel_contract.recordOf)({
|
|
1267
|
+
id: _orkestrel_contract.isNonEmptyString,
|
|
1268
|
+
timeout: _orkestrel_contract.isNumber
|
|
1269
|
+
}, ["timeout"]);
|
|
1236
1270
|
//#endregion
|
|
1237
1271
|
//#region src/core/Prompt.ts
|
|
1238
1272
|
/**
|
|
@@ -1272,12 +1306,14 @@ function isInsecureRemote(url) {
|
|
|
1272
1306
|
var Prompt = class {
|
|
1273
1307
|
#timeout;
|
|
1274
1308
|
#timer;
|
|
1309
|
+
#cap;
|
|
1275
1310
|
#parked = /* @__PURE__ */ new Map();
|
|
1276
1311
|
#emitter;
|
|
1277
1312
|
#destroyed = false;
|
|
1278
1313
|
constructor(options) {
|
|
1279
1314
|
this.#timeout = options?.timeout ?? 3e5;
|
|
1280
1315
|
this.#timer = options?.timer ?? defaultTimer;
|
|
1316
|
+
this.#cap = options?.cap;
|
|
1281
1317
|
this.#emitter = new _orkestrel_emitter.Emitter({
|
|
1282
1318
|
on: options?.on,
|
|
1283
1319
|
error: options?.error
|
|
@@ -1297,43 +1333,44 @@ var Prompt = class {
|
|
|
1297
1333
|
}
|
|
1298
1334
|
answer(id, value) {
|
|
1299
1335
|
const parked = this.#parked.get(id);
|
|
1300
|
-
if (parked === void 0) return
|
|
1336
|
+
if (parked === void 0) return {
|
|
1337
|
+
success: false,
|
|
1338
|
+
error: "unknown"
|
|
1339
|
+
};
|
|
1301
1340
|
const accepted = parked.respond(value);
|
|
1302
|
-
if (accepted === void 0) return
|
|
1341
|
+
if (accepted === void 0) return {
|
|
1342
|
+
success: false,
|
|
1343
|
+
error: "rejected"
|
|
1344
|
+
};
|
|
1303
1345
|
parked.cancel();
|
|
1304
1346
|
this.#emitter.emit("answer", id, accepted);
|
|
1305
1347
|
this.#parked.delete(id);
|
|
1306
|
-
return
|
|
1348
|
+
return {
|
|
1349
|
+
success: true,
|
|
1350
|
+
value: accepted
|
|
1351
|
+
};
|
|
1352
|
+
}
|
|
1353
|
+
park(request) {
|
|
1354
|
+
const gate = this.#gate(request.form, request.options);
|
|
1355
|
+
return this.#park(request.form, request.options.message, request.options, gate, request.from, request.to);
|
|
1307
1356
|
}
|
|
1308
1357
|
input(options) {
|
|
1309
|
-
|
|
1310
|
-
return this.#park("input", options.message, options, (value) => (0, _orkestrel_contract.isString)(value) && validator(value) === true ? value : void 0);
|
|
1358
|
+
return this.#park("input", options.message, options, this.#gate("input", options)).value;
|
|
1311
1359
|
}
|
|
1312
1360
|
password(options) {
|
|
1313
|
-
|
|
1314
|
-
return this.#park("password", options.message, options, (value) => (0, _orkestrel_contract.isString)(value) && validator(value) === true ? value : void 0);
|
|
1361
|
+
return this.#park("password", options.message, options, this.#gate("password", options)).value;
|
|
1315
1362
|
}
|
|
1316
1363
|
confirm(options) {
|
|
1317
|
-
return this.#park("confirm", options.message, options, (
|
|
1364
|
+
return this.#park("confirm", options.message, options, this.#gate("confirm", options)).value;
|
|
1318
1365
|
}
|
|
1319
1366
|
select(options) {
|
|
1320
|
-
|
|
1321
|
-
return this.#park("select", options.message, options, (value) => (0, _orkestrel_contract.isString)(value) && values.has(value) ? value : void 0);
|
|
1367
|
+
return this.#park("select", options.message, options, this.#gate("select", options)).value;
|
|
1322
1368
|
}
|
|
1323
1369
|
checkbox(options) {
|
|
1324
|
-
|
|
1325
|
-
const { min, max } = options;
|
|
1326
|
-
return this.#park("checkbox", options.message, options, (value) => {
|
|
1327
|
-
if (!(0, _orkestrel_contract.isArray)(value) || !value.every(_orkestrel_contract.isString)) return void 0;
|
|
1328
|
-
if (!value.every((item) => values.has(item))) return void 0;
|
|
1329
|
-
if (min !== void 0 && value.length < min) return void 0;
|
|
1330
|
-
if (max !== void 0 && value.length > max) return void 0;
|
|
1331
|
-
return value;
|
|
1332
|
-
});
|
|
1370
|
+
return this.#park("checkbox", options.message, options, this.#gate("checkbox", options)).value;
|
|
1333
1371
|
}
|
|
1334
1372
|
editor(options) {
|
|
1335
|
-
|
|
1336
|
-
return this.#park("editor", options.message, options, (value) => (0, _orkestrel_contract.isString)(value) && validator(value) === true ? value : void 0);
|
|
1373
|
+
return this.#park("editor", options.message, options, this.#gate("editor", options)).value;
|
|
1337
1374
|
}
|
|
1338
1375
|
destroy() {
|
|
1339
1376
|
if (this.#destroyed) return;
|
|
@@ -1342,8 +1379,15 @@ var Prompt = class {
|
|
|
1342
1379
|
this.#parked.clear();
|
|
1343
1380
|
this.#emitter.destroy();
|
|
1344
1381
|
}
|
|
1345
|
-
#park(form, message, options, gate) {
|
|
1346
|
-
if (this.#destroyed) return
|
|
1382
|
+
#park(form, message, options, gate, from, to) {
|
|
1383
|
+
if (this.#destroyed) return {
|
|
1384
|
+
id: crypto.randomUUID(),
|
|
1385
|
+
value: Promise.reject(new TerminalError("EXPIRE", "broker destroyed"))
|
|
1386
|
+
};
|
|
1387
|
+
if (this.#cap !== void 0 && this.#parked.size >= this.#cap) return {
|
|
1388
|
+
id: crypto.randomUUID(),
|
|
1389
|
+
value: Promise.reject(new TerminalError("LIMIT", `parked-prompt cap (${this.#cap}) reached`, { cap: this.#cap }))
|
|
1390
|
+
};
|
|
1347
1391
|
const id = crypto.randomUUID();
|
|
1348
1392
|
const prompt = {
|
|
1349
1393
|
id,
|
|
@@ -1351,35 +1395,83 @@ var Prompt = class {
|
|
|
1351
1395
|
message,
|
|
1352
1396
|
options: serializePromptOptions(options),
|
|
1353
1397
|
status: "pending",
|
|
1354
|
-
time: Date.now()
|
|
1398
|
+
time: Date.now(),
|
|
1399
|
+
...from !== void 0 ? { from } : {},
|
|
1400
|
+
...to !== void 0 ? { to } : {}
|
|
1355
1401
|
};
|
|
1356
|
-
return
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
const
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
...current
|
|
1366
|
-
|
|
1367
|
-
|
|
1402
|
+
return {
|
|
1403
|
+
id,
|
|
1404
|
+
value: new Promise((resolve, reject) => {
|
|
1405
|
+
const cancel = this.#timer(() => this.#expire(id), this.#timeout);
|
|
1406
|
+
const respond = (answer) => {
|
|
1407
|
+
const accepted = gate(answer);
|
|
1408
|
+
if (accepted === void 0) return void 0;
|
|
1409
|
+
const current = this.#parked.get(id);
|
|
1410
|
+
if (current !== void 0) this.#parked.set(id, {
|
|
1411
|
+
...current,
|
|
1412
|
+
prompt: {
|
|
1413
|
+
...current.prompt,
|
|
1414
|
+
status: "answered"
|
|
1415
|
+
}
|
|
1416
|
+
});
|
|
1417
|
+
resolve(accepted);
|
|
1418
|
+
return accepted;
|
|
1419
|
+
};
|
|
1420
|
+
const expire = () => {
|
|
1421
|
+
reject(new TerminalError("EXPIRE", `prompt ${id} expired`, { id }));
|
|
1422
|
+
};
|
|
1423
|
+
this.#parked.set(id, {
|
|
1424
|
+
prompt,
|
|
1425
|
+
respond,
|
|
1426
|
+
expire,
|
|
1427
|
+
cancel
|
|
1368
1428
|
});
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1429
|
+
this.#emitter.emit("pending", prompt);
|
|
1430
|
+
})
|
|
1431
|
+
};
|
|
1432
|
+
}
|
|
1433
|
+
#gate(form, options) {
|
|
1434
|
+
switch (form) {
|
|
1435
|
+
case "input":
|
|
1436
|
+
case "password":
|
|
1437
|
+
case "editor": {
|
|
1438
|
+
if (!this.#isTextOptions(form, options)) return () => void 0;
|
|
1439
|
+
const validator = resolveValidation(options.validate);
|
|
1440
|
+
return (value) => (0, _orkestrel_contract.isString)(value) && validator(value) === true ? value : void 0;
|
|
1441
|
+
}
|
|
1442
|
+
case "confirm":
|
|
1443
|
+
if (!this.#isConfirmOptions(form, options)) return () => void 0;
|
|
1444
|
+
return (value) => (0, _orkestrel_contract.isBoolean)(value) ? value : void 0;
|
|
1445
|
+
case "select": {
|
|
1446
|
+
if (!this.#isSelectOptions(form, options)) return () => void 0;
|
|
1447
|
+
const values = new Set(options.choices.map(normalizeChoice).map((choice) => choice.value));
|
|
1448
|
+
return (value) => (0, _orkestrel_contract.isString)(value) && values.has(value) ? value : void 0;
|
|
1449
|
+
}
|
|
1450
|
+
case "checkbox": {
|
|
1451
|
+
if (!this.#isCheckboxOptions(form, options)) return () => void 0;
|
|
1452
|
+
const values = new Set(options.choices.map(normalizeCheckboxChoice).map((choice) => choice.value));
|
|
1453
|
+
const { min, max } = options;
|
|
1454
|
+
return (value) => {
|
|
1455
|
+
if (!(0, _orkestrel_contract.isArray)(value) || !value.every(_orkestrel_contract.isString)) return void 0;
|
|
1456
|
+
if (!value.every((item) => values.has(item))) return void 0;
|
|
1457
|
+
if (min !== void 0 && value.length < min) return void 0;
|
|
1458
|
+
if (max !== void 0 && value.length > max) return void 0;
|
|
1459
|
+
return value;
|
|
1460
|
+
};
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
#isTextOptions(form, _options) {
|
|
1465
|
+
return form === "input" || form === "password" || form === "editor";
|
|
1466
|
+
}
|
|
1467
|
+
#isConfirmOptions(form, _options) {
|
|
1468
|
+
return form === "confirm";
|
|
1469
|
+
}
|
|
1470
|
+
#isSelectOptions(form, _options) {
|
|
1471
|
+
return form === "select";
|
|
1472
|
+
}
|
|
1473
|
+
#isCheckboxOptions(form, _options) {
|
|
1474
|
+
return form === "checkbox";
|
|
1383
1475
|
}
|
|
1384
1476
|
#expire(id) {
|
|
1385
1477
|
const parked = this.#parked.get(id);
|
|
@@ -1416,8 +1508,10 @@ var Prompt = class {
|
|
|
1416
1508
|
* never an `as`), dispatched to `terminal`, and its resolved value POSTed back to `url`.
|
|
1417
1509
|
* Dispatch is strictly SERIAL: the read loop drives the terminal for ONE prompt at a time and
|
|
1418
1510
|
* only reads/dispatches the next event after the current prompt fully settles (its answer
|
|
1419
|
-
* POSTed). A prompt id redelivered
|
|
1420
|
-
*
|
|
1511
|
+
* POSTed). A prompt id redelivered (e.g. after a reconnect) WHILE its prior dispatch is still
|
|
1512
|
+
* in flight is skipped (a `#seen` set tracks in-flight ids); once that dispatch settles (or the
|
|
1513
|
+
* broker sends `expire` for the id) the id is dropped from `#seen`, so a later redelivery of the
|
|
1514
|
+
* SAME id after completion is dispatched again — the client does not dedupe across completion.
|
|
1421
1515
|
* - **Server signals.** An `expire` event (the broker dropped a parked prompt) emits `expire`; a
|
|
1422
1516
|
* `shutdown` event calls {@link disconnect} (not {@link destroy}) — the client stops streaming
|
|
1423
1517
|
* without auto-reconnect but stays reusable; a later {@link connect} recovers it.
|
|
@@ -1451,6 +1545,7 @@ var PromptClient = class {
|
|
|
1451
1545
|
#connected = false;
|
|
1452
1546
|
#destroyed = false;
|
|
1453
1547
|
#warnedInsecureToken = false;
|
|
1548
|
+
#seen = /* @__PURE__ */ new Set();
|
|
1454
1549
|
constructor(options) {
|
|
1455
1550
|
this.url = options.url;
|
|
1456
1551
|
this.#terminal = options.terminal;
|
|
@@ -1501,6 +1596,7 @@ var PromptClient = class {
|
|
|
1501
1596
|
if (this.#destroyed) return;
|
|
1502
1597
|
this.#destroyed = true;
|
|
1503
1598
|
this.disconnect();
|
|
1599
|
+
this.#seen.clear();
|
|
1504
1600
|
this.#emitter.destroy();
|
|
1505
1601
|
}
|
|
1506
1602
|
async #stream() {
|
|
@@ -1536,22 +1632,28 @@ var PromptClient = class {
|
|
|
1536
1632
|
async #handle(event) {
|
|
1537
1633
|
if (event.event === SSE_EVENTS.pending) {
|
|
1538
1634
|
const parsed = parseWireJSON(event.data);
|
|
1539
|
-
if (isPendingPrompt(parsed)) await this.#dispatch(parsed.id, parsed);
|
|
1635
|
+
if (isPendingPrompt(parsed) && !this.#seen.has(parsed.id)) await this.#dispatch(parsed.id, parsed);
|
|
1540
1636
|
return;
|
|
1541
1637
|
}
|
|
1542
1638
|
if (event.event === SSE_EVENTS.expire) {
|
|
1543
1639
|
const parsed = parseWireJSON(event.data);
|
|
1544
|
-
if ((0, _orkestrel_contract.isRecord)(parsed) && (0, _orkestrel_contract.isString)(parsed.id))
|
|
1640
|
+
if ((0, _orkestrel_contract.isRecord)(parsed) && (0, _orkestrel_contract.isString)(parsed.id)) {
|
|
1641
|
+
this.#seen.delete(parsed.id);
|
|
1642
|
+
this.#emitter.emit("expire", parsed.id);
|
|
1643
|
+
}
|
|
1545
1644
|
return;
|
|
1546
1645
|
}
|
|
1547
1646
|
if (event.event === SSE_EVENTS.shutdown) this.disconnect();
|
|
1548
1647
|
}
|
|
1549
1648
|
async #dispatch(id, pending) {
|
|
1649
|
+
this.#seen.add(id);
|
|
1550
1650
|
try {
|
|
1551
1651
|
const value = await dispatchPendingPrompt(this.#terminal, pending);
|
|
1552
1652
|
await this.#post(id, value);
|
|
1553
1653
|
} catch (error) {
|
|
1554
1654
|
this.#emitter.emit("error", error);
|
|
1655
|
+
} finally {
|
|
1656
|
+
this.#seen.delete(id);
|
|
1555
1657
|
}
|
|
1556
1658
|
}
|
|
1557
1659
|
async #post(id, value) {
|
|
@@ -1570,8 +1672,11 @@ var PromptClient = class {
|
|
|
1570
1672
|
this.#emitter.emit("disconnect");
|
|
1571
1673
|
}
|
|
1572
1674
|
#headers(base) {
|
|
1573
|
-
if (this.#token !== void 0)
|
|
1574
|
-
|
|
1675
|
+
if (this.#token !== void 0) return {
|
|
1676
|
+
...base,
|
|
1677
|
+
[HEADER_TOKEN]: this.#token
|
|
1678
|
+
};
|
|
1679
|
+
return { ...base };
|
|
1575
1680
|
}
|
|
1576
1681
|
#wait(ms) {
|
|
1577
1682
|
return new Promise((resolve) => {
|
|
@@ -1588,6 +1693,345 @@ var PromptClient = class {
|
|
|
1588
1693
|
}
|
|
1589
1694
|
};
|
|
1590
1695
|
//#endregion
|
|
1696
|
+
//#region src/core/TerminalManager.ts
|
|
1697
|
+
/**
|
|
1698
|
+
* The multi-endpoint terminal MANAGER — a registry of named {@link PromptInterface} brokers (one
|
|
1699
|
+
* per endpoint), so several parties can `ask` prompts of each other by NAME with a `from` → `to`
|
|
1700
|
+
* attribution edge on every parked prompt, and a transitive DEADLOCK check across all in-flight
|
|
1701
|
+
* asks.
|
|
1702
|
+
*
|
|
1703
|
+
* @remarks
|
|
1704
|
+
* - **Registry.** `add(name, options?)` mints (or, if `name` is already mounted, returns the
|
|
1705
|
+
* EXISTING broker UNCHANGED — idempotent, never clobbers a live/parked endpoint). Every mounted
|
|
1706
|
+
* broker's `pending` / `answer` / `expire` events are re-emitted on the manager, attributed by
|
|
1707
|
+
* `name`.
|
|
1708
|
+
* - **`ask`.** The target must already be mounted via {@link add} — `ask` never auto-adds it;
|
|
1709
|
+
* rejects `TARGET` for an unknown `to` (listing the known names). Rejects `DEADLOCK` when parking
|
|
1710
|
+
* `from → to` would close a cycle over the CURRENT in-flight edge set (walked transitively);
|
|
1711
|
+
* otherwise parks through the target's broker and resolves with the ORIGINAL ticket Promise (edge
|
|
1712
|
+
* cleanup is attached via `.then`, never altering the value/rejection the caller observes).
|
|
1713
|
+
* - **Durable open / save.** `open(name)` restores an EMPTY broker from the `store` (parked
|
|
1714
|
+
* Promises are process-bound and never resurrected); `save(name)` persists the endpoint's
|
|
1715
|
+
* configured `timeout`.
|
|
1716
|
+
* - **Removal.** `remove` drops one endpoint or a batch (§9.2, array overload FIRST), destroying
|
|
1717
|
+
* each broker (which expires every prompt still parked on it). `clear` drops all; `destroy` is
|
|
1718
|
+
* idempotent.
|
|
1719
|
+
*
|
|
1720
|
+
* @example
|
|
1721
|
+
* ```ts
|
|
1722
|
+
* const manager = new TerminalManager()
|
|
1723
|
+
* manager.add('agent')
|
|
1724
|
+
* const name = manager.ask('user', 'agent', 'input', { message: 'Your name' })
|
|
1725
|
+
* manager.answer('agent', manager.pending('agent')[0].id, 'Ada')
|
|
1726
|
+
* await name // 'Ada'
|
|
1727
|
+
* ```
|
|
1728
|
+
*/
|
|
1729
|
+
var TerminalManager = class {
|
|
1730
|
+
#terminals = /* @__PURE__ */ new Map();
|
|
1731
|
+
#config = /* @__PURE__ */ new Map();
|
|
1732
|
+
#listeners = /* @__PURE__ */ new Map();
|
|
1733
|
+
#edges = /* @__PURE__ */ new Map();
|
|
1734
|
+
#store;
|
|
1735
|
+
#timeout;
|
|
1736
|
+
#timer;
|
|
1737
|
+
#cap;
|
|
1738
|
+
#emitter;
|
|
1739
|
+
#destroyed = false;
|
|
1740
|
+
constructor(options) {
|
|
1741
|
+
this.#store = options?.store;
|
|
1742
|
+
this.#timeout = options?.timeout;
|
|
1743
|
+
this.#timer = options?.timer;
|
|
1744
|
+
this.#cap = options?.cap;
|
|
1745
|
+
this.#emitter = new _orkestrel_emitter.Emitter({
|
|
1746
|
+
on: options?.on,
|
|
1747
|
+
error: options?.error
|
|
1748
|
+
});
|
|
1749
|
+
}
|
|
1750
|
+
get emitter() {
|
|
1751
|
+
return this.#emitter;
|
|
1752
|
+
}
|
|
1753
|
+
get count() {
|
|
1754
|
+
return this.#terminals.size;
|
|
1755
|
+
}
|
|
1756
|
+
terminal(name) {
|
|
1757
|
+
return this.#terminals.get(name);
|
|
1758
|
+
}
|
|
1759
|
+
terminals() {
|
|
1760
|
+
return [...this.#terminals.keys()];
|
|
1761
|
+
}
|
|
1762
|
+
add(name, options) {
|
|
1763
|
+
if (this.#destroyed) throw new TerminalError("DESTROYED", "manager destroyed");
|
|
1764
|
+
const existing = this.#terminals.get(name);
|
|
1765
|
+
if (existing !== void 0) return existing;
|
|
1766
|
+
const timeout = options?.timeout ?? this.#timeout;
|
|
1767
|
+
const timer = options?.timer ?? this.#timer;
|
|
1768
|
+
const cap = options?.cap ?? this.#cap;
|
|
1769
|
+
const broker = createPrompt({
|
|
1770
|
+
...timeout !== void 0 ? { timeout } : {},
|
|
1771
|
+
...timer !== void 0 ? { timer } : {},
|
|
1772
|
+
...cap !== void 0 ? { cap } : {}
|
|
1773
|
+
});
|
|
1774
|
+
const listeners = {
|
|
1775
|
+
pending: (prompt) => this.#emitter.emit("pending", prompt),
|
|
1776
|
+
answer: (id, value) => this.#emitter.emit("answer", name, id, value),
|
|
1777
|
+
expire: (id) => this.#emitter.emit("expire", name, id)
|
|
1778
|
+
};
|
|
1779
|
+
broker.emitter.on("pending", listeners.pending);
|
|
1780
|
+
broker.emitter.on("answer", listeners.answer);
|
|
1781
|
+
broker.emitter.on("expire", listeners.expire);
|
|
1782
|
+
this.#terminals.set(name, broker);
|
|
1783
|
+
this.#config.set(name, options ?? {});
|
|
1784
|
+
this.#listeners.set(name, listeners);
|
|
1785
|
+
return broker;
|
|
1786
|
+
}
|
|
1787
|
+
ask(from, to, form, options) {
|
|
1788
|
+
const broker = this.#terminals.get(to);
|
|
1789
|
+
if (broker === void 0) {
|
|
1790
|
+
const known = this.terminals();
|
|
1791
|
+
return Promise.reject(new TerminalError("TARGET", `unknown terminal '${to}' (known: ${known.length > 0 ? known.join(", ") : "none"})`, {
|
|
1792
|
+
to,
|
|
1793
|
+
known
|
|
1794
|
+
}));
|
|
1795
|
+
}
|
|
1796
|
+
const cycle = this.#findCycle(from, to);
|
|
1797
|
+
if (cycle !== void 0) return Promise.reject(new TerminalError("DEADLOCK", `ask ${from} -> ${to} would deadlock: ${cycle.join(" -> ")}`, {
|
|
1798
|
+
from,
|
|
1799
|
+
to,
|
|
1800
|
+
path: cycle
|
|
1801
|
+
}));
|
|
1802
|
+
const ticket = broker.park({
|
|
1803
|
+
form,
|
|
1804
|
+
options,
|
|
1805
|
+
from,
|
|
1806
|
+
to
|
|
1807
|
+
});
|
|
1808
|
+
if (broker.pending(ticket.id) !== void 0) {
|
|
1809
|
+
this.#edges.set(ticket.id, {
|
|
1810
|
+
from,
|
|
1811
|
+
to
|
|
1812
|
+
});
|
|
1813
|
+
const clear = () => {
|
|
1814
|
+
this.#edges.delete(ticket.id);
|
|
1815
|
+
};
|
|
1816
|
+
ticket.value.then(clear, clear);
|
|
1817
|
+
}
|
|
1818
|
+
return ticket.value;
|
|
1819
|
+
}
|
|
1820
|
+
pending(to) {
|
|
1821
|
+
if (to !== void 0) {
|
|
1822
|
+
const broker = this.#terminals.get(to);
|
|
1823
|
+
return broker === void 0 ? [] : broker.pending();
|
|
1824
|
+
}
|
|
1825
|
+
const result = [];
|
|
1826
|
+
for (const broker of this.#terminals.values()) result.push(...broker.pending());
|
|
1827
|
+
return result;
|
|
1828
|
+
}
|
|
1829
|
+
answer(to, id, value) {
|
|
1830
|
+
const broker = this.#terminals.get(to);
|
|
1831
|
+
if (broker === void 0) return {
|
|
1832
|
+
success: false,
|
|
1833
|
+
error: "terminal"
|
|
1834
|
+
};
|
|
1835
|
+
return broker.answer(id, value);
|
|
1836
|
+
}
|
|
1837
|
+
async open(name) {
|
|
1838
|
+
if (this.#destroyed) throw new TerminalError("DESTROYED", "manager destroyed");
|
|
1839
|
+
const existing = this.#terminals.get(name);
|
|
1840
|
+
if (existing !== void 0) return existing;
|
|
1841
|
+
if (this.#store === void 0) return void 0;
|
|
1842
|
+
const snapshot = await this.#store.get(name);
|
|
1843
|
+
if (this.#destroyed) throw new TerminalError("DESTROYED", "manager destroyed");
|
|
1844
|
+
if (snapshot === void 0) return void 0;
|
|
1845
|
+
return this.add(name, snapshot.timeout !== void 0 ? { timeout: snapshot.timeout } : {});
|
|
1846
|
+
}
|
|
1847
|
+
async save(name) {
|
|
1848
|
+
const broker = this.#terminals.get(name);
|
|
1849
|
+
if (this.#store === void 0 || broker === void 0) return false;
|
|
1850
|
+
const config = this.#config.get(name);
|
|
1851
|
+
const snapshot = {
|
|
1852
|
+
id: name,
|
|
1853
|
+
...config?.timeout !== void 0 ? { timeout: config.timeout } : {}
|
|
1854
|
+
};
|
|
1855
|
+
await this.#store.set(snapshot);
|
|
1856
|
+
return true;
|
|
1857
|
+
}
|
|
1858
|
+
remove(names) {
|
|
1859
|
+
if ((0, _orkestrel_contract.isArray)(names)) {
|
|
1860
|
+
let removed = false;
|
|
1861
|
+
for (const name of names) if (this.#removeOne(name)) removed = true;
|
|
1862
|
+
return removed;
|
|
1863
|
+
}
|
|
1864
|
+
return this.#removeOne(names);
|
|
1865
|
+
}
|
|
1866
|
+
clear() {
|
|
1867
|
+
for (const name of [...this.#terminals.keys()]) this.#removeOne(name);
|
|
1868
|
+
}
|
|
1869
|
+
destroy() {
|
|
1870
|
+
if (this.#destroyed) return;
|
|
1871
|
+
this.#destroyed = true;
|
|
1872
|
+
this.clear();
|
|
1873
|
+
this.#emitter.destroy();
|
|
1874
|
+
}
|
|
1875
|
+
#removeOne(name) {
|
|
1876
|
+
const broker = this.#terminals.get(name);
|
|
1877
|
+
if (broker === void 0) return false;
|
|
1878
|
+
broker.destroy();
|
|
1879
|
+
const listeners = this.#listeners.get(name);
|
|
1880
|
+
if (listeners !== void 0) {
|
|
1881
|
+
broker.emitter.off("pending", listeners.pending);
|
|
1882
|
+
broker.emitter.off("answer", listeners.answer);
|
|
1883
|
+
broker.emitter.off("expire", listeners.expire);
|
|
1884
|
+
}
|
|
1885
|
+
this.#terminals.delete(name);
|
|
1886
|
+
this.#config.delete(name);
|
|
1887
|
+
this.#listeners.delete(name);
|
|
1888
|
+
return true;
|
|
1889
|
+
}
|
|
1890
|
+
#findCycle(from, to) {
|
|
1891
|
+
if (from === to) return [from, to];
|
|
1892
|
+
const visited = /* @__PURE__ */ new Set([to]);
|
|
1893
|
+
const queue = [[to]];
|
|
1894
|
+
while (queue.length > 0) {
|
|
1895
|
+
const path = queue.shift();
|
|
1896
|
+
if (path === void 0) break;
|
|
1897
|
+
const last = path[path.length - 1];
|
|
1898
|
+
if (last === void 0) continue;
|
|
1899
|
+
for (const edge of this.#edges.values()) {
|
|
1900
|
+
if (edge.from !== last) continue;
|
|
1901
|
+
if (edge.to === from) return [
|
|
1902
|
+
from,
|
|
1903
|
+
...path,
|
|
1904
|
+
from
|
|
1905
|
+
];
|
|
1906
|
+
if (visited.has(edge.to)) continue;
|
|
1907
|
+
visited.add(edge.to);
|
|
1908
|
+
queue.push([...path, edge.to]);
|
|
1909
|
+
}
|
|
1910
|
+
}
|
|
1911
|
+
}
|
|
1912
|
+
};
|
|
1913
|
+
//#endregion
|
|
1914
|
+
//#region src/core/MemoryTerminalStore.ts
|
|
1915
|
+
/**
|
|
1916
|
+
* The in-memory {@link TerminalStoreInterface} — a process-lifetime `Map` of
|
|
1917
|
+
* {@link TerminalSnapshot}s keyed by endpoint id, the DEFAULT store
|
|
1918
|
+
* {@link import('./factories.js').createMemoryTerminalStore} builds. The EXACT twin of
|
|
1919
|
+
* {@link import('./DatabaseTerminalStore.js').DatabaseTerminalStore}.
|
|
1920
|
+
*
|
|
1921
|
+
* @remarks
|
|
1922
|
+
* A plain `Map<string, TerminalSnapshot>` (AGENTS §21 — the snapshot is already pure, self-contained
|
|
1923
|
+
* CONFIG-only JSON, so no encoding is needed for the memory tier). There is NO idle-TTL and NO
|
|
1924
|
+
* eviction: a persisted config lives until an explicit `delete`. A durable backend (JSON / SQLite /
|
|
1925
|
+
* IndexedDB) swaps in through the SAME interface without touching the manager — its
|
|
1926
|
+
* driver-pluggable twin is {@link import('./DatabaseTerminalStore.js').DatabaseTerminalStore} (the
|
|
1927
|
+
* snapshot as one opaque JSON column).
|
|
1928
|
+
*
|
|
1929
|
+
* - **`get` resolves the persisted snapshot for an id**, or `undefined` if none is stored.
|
|
1930
|
+
* - **`set` inserts / replaces under the snapshot's OWN `id`** (no separate id param).
|
|
1931
|
+
* - **`delete` drops a snapshot by id**; an absent id is a no-op (no throw).
|
|
1932
|
+
*
|
|
1933
|
+
* The public surface is EXACTLY `get` / `set` / `delete` — no extra members (the §22 method
|
|
1934
|
+
* bijection with {@link TerminalStoreInterface}). Hydration is a caller concern: `open` always
|
|
1935
|
+
* restores an EMPTY broker — parked Promises are process-bound and never resurrected.
|
|
1936
|
+
*
|
|
1937
|
+
* @example
|
|
1938
|
+
* ```ts
|
|
1939
|
+
* import { createMemoryTerminalStore } from '@src/core'
|
|
1940
|
+
*
|
|
1941
|
+
* const store = createMemoryTerminalStore()
|
|
1942
|
+
* await store.set({ id: 'shell', timeout: 5000 }) // persist a config
|
|
1943
|
+
* const snapshot = await store.get('shell')
|
|
1944
|
+
* await store.delete('shell') // drop it
|
|
1945
|
+
* ```
|
|
1946
|
+
*/
|
|
1947
|
+
var MemoryTerminalStore = class {
|
|
1948
|
+
#snapshots = /* @__PURE__ */ new Map();
|
|
1949
|
+
get(id) {
|
|
1950
|
+
return Promise.resolve(this.#snapshots.get(id));
|
|
1951
|
+
}
|
|
1952
|
+
set(snapshot) {
|
|
1953
|
+
this.#snapshots.set(snapshot.id, snapshot);
|
|
1954
|
+
return Promise.resolve();
|
|
1955
|
+
}
|
|
1956
|
+
delete(id) {
|
|
1957
|
+
this.#snapshots.delete(id);
|
|
1958
|
+
return Promise.resolve();
|
|
1959
|
+
}
|
|
1960
|
+
};
|
|
1961
|
+
//#endregion
|
|
1962
|
+
//#region src/core/DatabaseTerminalStore.ts
|
|
1963
|
+
/**
|
|
1964
|
+
* A {@link TerminalStoreInterface} backed by one table of the `databases` layer — an endpoint's
|
|
1965
|
+
* durable CONFIG state IS a row, so persistence reduces to keyed point-access (`get` / `set` /
|
|
1966
|
+
* `delete`) over a {@link TableInterface}, the driver-pluggable twin of the plain-`Map`
|
|
1967
|
+
* {@link import('./MemoryTerminalStore.js').MemoryTerminalStore}.
|
|
1968
|
+
*
|
|
1969
|
+
* @remarks
|
|
1970
|
+
* The store is driver-agnostic: it holds a single {@link TableInterface} whose backend (memory,
|
|
1971
|
+
* JSON, SQLite, IndexedDB) is chosen by whoever builds it (the factories), so a JSON / SQLite /
|
|
1972
|
+
* IndexedDB backend swaps in WITHOUT touching the manager — the same seam as
|
|
1973
|
+
* {@link import('./MemoryTerminalStore.js').MemoryTerminalStore}. The driver defaults to memory
|
|
1974
|
+
* ({@link import('./factories.js').createDatabaseTerminalStore} passes `createMemoryDriver()`), so
|
|
1975
|
+
* it ALSO works in memory out of the box; you opt into the durable plumbing by passing a JSON /
|
|
1976
|
+
* SQLite / IndexedDB driver.
|
|
1977
|
+
*
|
|
1978
|
+
* The {@link TerminalSnapshot} is stored as ONE OPAQUE JSON COLUMN — the table is a row of
|
|
1979
|
+
* `{ id; snapshot }` ({@link TerminalSnapshotRow}). The snapshot is already a COMPLETE,
|
|
1980
|
+
* self-contained, pure-JSON CONFIG payload (no live broker state), so storing it whole is lossless
|
|
1981
|
+
* AND keeps the row type flat (`snapshot` reads back as `unknown`).
|
|
1982
|
+
*
|
|
1983
|
+
* - **`set(snapshot)` upserts under the snapshot's OWN `id`** (no separate id param) — it writes
|
|
1984
|
+
* the row `{ id: snapshot.id, snapshot }`.
|
|
1985
|
+
* - **`get(id)` resolves the stored snapshot for an id**, narrowing the opaque JSON column back to
|
|
1986
|
+
* a {@link TerminalSnapshot} ({@link import('./helpers.js').isTerminalSnapshot} — the AGENTS §14
|
|
1987
|
+
* boundary narrow for an untrusted storage read), or `undefined` if none is stored.
|
|
1988
|
+
* - **`delete(id)` drops a snapshot by id**; an absent id is a no-op (no throw).
|
|
1989
|
+
*
|
|
1990
|
+
* There is NO idle-TTL / eviction — a persisted config lives until an explicit `delete`. The public
|
|
1991
|
+
* surface is EXACTLY `get` / `set` / `delete` — no extra members (the §22 method bijection with
|
|
1992
|
+
* {@link TerminalStoreInterface}). Hydration stays a caller concern: `open` always restores an EMPTY
|
|
1993
|
+
* broker — parked Promises are process-bound and never resurrected.
|
|
1994
|
+
*
|
|
1995
|
+
* @example
|
|
1996
|
+
* ```ts
|
|
1997
|
+
* import { createDatabaseTerminalStore, createMemoryDriver } from '@src/core'
|
|
1998
|
+
*
|
|
1999
|
+
* const store = createDatabaseTerminalStore(createMemoryDriver()) // a durable driver swaps in here
|
|
2000
|
+
* await store.set({ id: 'shell', timeout: 5000 }) // persist the config (one JSON column)
|
|
2001
|
+
* const snapshot = await store.get('shell')
|
|
2002
|
+
* await store.delete('shell') // drop it
|
|
2003
|
+
* ```
|
|
2004
|
+
*/
|
|
2005
|
+
var DatabaseTerminalStore = class {
|
|
2006
|
+
#table;
|
|
2007
|
+
/**
|
|
2008
|
+
* Wrap a table as a terminal store.
|
|
2009
|
+
*
|
|
2010
|
+
* @param table - The {@link TableInterface} holding the snapshots — its row is the
|
|
2011
|
+
* {@link TerminalSnapshotRow} `{ id; snapshot }` shape (the snapshot one opaque JSON column)
|
|
2012
|
+
*/
|
|
2013
|
+
constructor(table) {
|
|
2014
|
+
this.#table = table;
|
|
2015
|
+
}
|
|
2016
|
+
/** Resolve the persisted snapshot for `id`, narrowing the opaque JSON column back to a `TerminalSnapshot`. */
|
|
2017
|
+
async get(id) {
|
|
2018
|
+
const row = await this.#table.get(id);
|
|
2019
|
+
if (row === void 0) return void 0;
|
|
2020
|
+
return isTerminalSnapshot(row.snapshot) ? row.snapshot : void 0;
|
|
2021
|
+
}
|
|
2022
|
+
/** Insert or replace under the snapshot's OWN `id` (no separate id param) — the row is `{ id, snapshot }`. */
|
|
2023
|
+
async set(snapshot) {
|
|
2024
|
+
await this.#table.set({
|
|
2025
|
+
id: snapshot.id,
|
|
2026
|
+
snapshot
|
|
2027
|
+
});
|
|
2028
|
+
}
|
|
2029
|
+
/** Drop a snapshot by id; an absent id is a no-op (no throw). */
|
|
2030
|
+
async delete(id) {
|
|
2031
|
+
await this.#table.remove(id);
|
|
2032
|
+
}
|
|
2033
|
+
};
|
|
2034
|
+
//#endregion
|
|
1591
2035
|
//#region src/core/factories.ts
|
|
1592
2036
|
/**
|
|
1593
2037
|
* Create the headless prompt {@link PromptInterface} BROKER — it parks each prompt call as a
|
|
@@ -1646,6 +2090,65 @@ function createPrompt(options) {
|
|
|
1646
2090
|
function createPromptClient(options) {
|
|
1647
2091
|
return new PromptClient(options);
|
|
1648
2092
|
}
|
|
2093
|
+
/**
|
|
2094
|
+
* Create the multi-endpoint {@link TerminalManagerInterface} — a named registry of
|
|
2095
|
+
* {@link PromptInterface} brokers so several parties can `ask` prompts of each other by name,
|
|
2096
|
+
* with a transitive DEADLOCK check across every in-flight ask.
|
|
2097
|
+
*
|
|
2098
|
+
* @param options - See {@link TerminalManagerOptions}
|
|
2099
|
+
* @returns A {@link TerminalManagerInterface}
|
|
2100
|
+
*
|
|
2101
|
+
* @example
|
|
2102
|
+
* ```ts
|
|
2103
|
+
* import { createTerminalManager } from '@src/core'
|
|
2104
|
+
*
|
|
2105
|
+
* const manager = createTerminalManager()
|
|
2106
|
+
* manager.add('agent')
|
|
2107
|
+
* ```
|
|
2108
|
+
*/
|
|
2109
|
+
function createTerminalManager(options) {
|
|
2110
|
+
return new TerminalManager(options);
|
|
2111
|
+
}
|
|
2112
|
+
/**
|
|
2113
|
+
* Create the in-memory {@link TerminalStoreInterface} — a process-lifetime `Map` of endpoint
|
|
2114
|
+
* config snapshots, the default store backing a {@link TerminalManagerInterface}'s `open` / `save`.
|
|
2115
|
+
*
|
|
2116
|
+
* @returns A {@link TerminalStoreInterface}
|
|
2117
|
+
*
|
|
2118
|
+
* @example
|
|
2119
|
+
* ```ts
|
|
2120
|
+
* import { createMemoryTerminalStore } from '@src/core'
|
|
2121
|
+
*
|
|
2122
|
+
* const store = createMemoryTerminalStore()
|
|
2123
|
+
* ```
|
|
2124
|
+
*/
|
|
2125
|
+
function createMemoryTerminalStore() {
|
|
2126
|
+
return new MemoryTerminalStore();
|
|
2127
|
+
}
|
|
2128
|
+
/**
|
|
2129
|
+
* Create a {@link TerminalStoreInterface} backed by one table of the `databases` layer — the
|
|
2130
|
+
* driver-pluggable twin of {@link createMemoryTerminalStore}, storing each endpoint's config
|
|
2131
|
+
* snapshot as one opaque JSON column.
|
|
2132
|
+
*
|
|
2133
|
+
* @param driver - The {@link DriverInterface} backing the table (default an in-memory driver)
|
|
2134
|
+
* @returns A {@link TerminalStoreInterface}
|
|
2135
|
+
*
|
|
2136
|
+
* @example
|
|
2137
|
+
* ```ts
|
|
2138
|
+
* import { createDatabaseTerminalStore } from '@src/core'
|
|
2139
|
+
*
|
|
2140
|
+
* const store = createDatabaseTerminalStore() // in-memory by default
|
|
2141
|
+
* ```
|
|
2142
|
+
*/
|
|
2143
|
+
function createDatabaseTerminalStore(driver = (0, _orkestrel_database.createMemoryDriver)()) {
|
|
2144
|
+
return new DatabaseTerminalStore((0, _orkestrel_database.createDatabase)({
|
|
2145
|
+
driver,
|
|
2146
|
+
tables: { terminals: {
|
|
2147
|
+
id: (0, _orkestrel_contract.stringShape)(),
|
|
2148
|
+
snapshot: (0, _orkestrel_contract.rawShape)({})
|
|
2149
|
+
} }
|
|
2150
|
+
}).table("terminals"));
|
|
2151
|
+
}
|
|
1649
2152
|
//#endregion
|
|
1650
2153
|
exports.ACCEPT_EVENT_STREAM = ACCEPT_EVENT_STREAM;
|
|
1651
2154
|
exports.ALPHANUMERIC_PATTERN = ALPHANUMERIC_PATTERN;
|
|
@@ -1660,12 +2163,14 @@ exports.DEFAULT_MASK = DEFAULT_MASK;
|
|
|
1660
2163
|
exports.DEFAULT_PROMPT_TIMEOUT_MS = DEFAULT_PROMPT_TIMEOUT_MS;
|
|
1661
2164
|
exports.DEFAULT_RECONNECT_DELAY_MS = DEFAULT_RECONNECT_DELAY_MS;
|
|
1662
2165
|
exports.DELETE = DELETE;
|
|
2166
|
+
exports.DatabaseTerminalStore = DatabaseTerminalStore;
|
|
1663
2167
|
exports.EMAIL_PATTERN = EMAIL_PATTERN;
|
|
1664
2168
|
exports.ESCAPE = ESCAPE;
|
|
1665
2169
|
exports.HEADER_TOKEN = HEADER_TOKEN;
|
|
1666
2170
|
exports.INTEGER_PATTERN = INTEGER_PATTERN;
|
|
1667
2171
|
exports.KEY_CSI = KEY_CSI;
|
|
1668
2172
|
exports.KEY_SS3 = KEY_SS3;
|
|
2173
|
+
exports.MemoryTerminalStore = MemoryTerminalStore;
|
|
1669
2174
|
exports.NEWLINE = NEWLINE;
|
|
1670
2175
|
exports.NUMERIC_PATTERN = NUMERIC_PATTERN;
|
|
1671
2176
|
exports.PROMPT_ICONS = PROMPT_ICONS;
|
|
@@ -1679,6 +2184,7 @@ exports.SSE_BUFFER_LIMIT = SSE_BUFFER_LIMIT;
|
|
|
1679
2184
|
exports.SSE_EVENTS = SSE_EVENTS;
|
|
1680
2185
|
exports.TAB = TAB;
|
|
1681
2186
|
exports.TerminalError = TerminalError;
|
|
2187
|
+
exports.TerminalManager = TerminalManager;
|
|
1682
2188
|
exports.URL_PATTERN = URL_PATTERN;
|
|
1683
2189
|
exports.appendRule = appendRule;
|
|
1684
2190
|
exports.buildRuleValidator = buildRuleValidator;
|
|
@@ -1689,12 +2195,15 @@ exports.confirmReduce = confirmReduce;
|
|
|
1689
2195
|
exports.confirmView = confirmView;
|
|
1690
2196
|
exports.createCheckboxState = createCheckboxState;
|
|
1691
2197
|
exports.createConfirmState = createConfirmState;
|
|
2198
|
+
exports.createDatabaseTerminalStore = createDatabaseTerminalStore;
|
|
1692
2199
|
exports.createEditorState = createEditorState;
|
|
1693
2200
|
exports.createInputState = createInputState;
|
|
2201
|
+
exports.createMemoryTerminalStore = createMemoryTerminalStore;
|
|
1694
2202
|
exports.createPasswordState = createPasswordState;
|
|
1695
2203
|
exports.createPrompt = createPrompt;
|
|
1696
2204
|
exports.createPromptClient = createPromptClient;
|
|
1697
2205
|
exports.createSelectState = createSelectState;
|
|
2206
|
+
exports.createTerminalManager = createTerminalManager;
|
|
1698
2207
|
exports.defaultTimer = defaultTimer;
|
|
1699
2208
|
exports.dispatchPendingPrompt = dispatchPendingPrompt;
|
|
1700
2209
|
exports.editLine = editLine;
|
|
@@ -1707,6 +2216,7 @@ exports.globalFetch = globalFetch;
|
|
|
1707
2216
|
exports.inputReduce = inputReduce;
|
|
1708
2217
|
exports.inputView = inputView;
|
|
1709
2218
|
exports.isAbortError = isAbortError;
|
|
2219
|
+
exports.isAnswerPayload = isAnswerPayload;
|
|
1710
2220
|
exports.isCheckboxChoice = isCheckboxChoice;
|
|
1711
2221
|
exports.isInsecureRemote = isInsecureRemote;
|
|
1712
2222
|
exports.isPendingPrompt = isPendingPrompt;
|
|
@@ -1715,6 +2225,7 @@ exports.isPrintable = isPrintable;
|
|
|
1715
2225
|
exports.isPromptChoice = isPromptChoice;
|
|
1716
2226
|
exports.isPromptType = isPromptType;
|
|
1717
2227
|
exports.isTerminalError = isTerminalError;
|
|
2228
|
+
exports.isTerminalSnapshot = isTerminalSnapshot;
|
|
1718
2229
|
exports.normalizeCheckboxChoice = normalizeCheckboxChoice;
|
|
1719
2230
|
exports.normalizeChoice = normalizeChoice;
|
|
1720
2231
|
exports.parseKey = parseKey;
|
|
@@ -1731,7 +2242,10 @@ exports.sanitizeChoiceLabels = sanitizeChoiceLabels;
|
|
|
1731
2242
|
exports.selectReduce = selectReduce;
|
|
1732
2243
|
exports.selectView = selectView;
|
|
1733
2244
|
exports.serializeChoices = serializeChoices;
|
|
2245
|
+
exports.serializeExpire = serializeExpire;
|
|
2246
|
+
exports.serializePending = serializePending;
|
|
1734
2247
|
exports.serializePromptOptions = serializePromptOptions;
|
|
2248
|
+
exports.serializeShutdown = serializeShutdown;
|
|
1735
2249
|
exports.serializeValidationRules = serializeValidationRules;
|
|
1736
2250
|
exports.submitHeader = submitHeader;
|
|
1737
2251
|
exports.toggleIndex = toggleIndex;
|