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