@oharness/server 0.5.0 → 0.5.1
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/i18n.js +473 -10
- package/dist/i18n.js.map +1 -1
- package/dist/main.js +5 -2
- package/dist/main.js.map +1 -1
- package/dist/markdown.js +512 -61
- package/dist/markdown.js.map +1 -1
- package/dist/page.js +2599 -373
- package/dist/page.js.map +1 -1
- package/dist/prefs.d.ts +7 -0
- package/dist/prefs.js +3 -0
- package/dist/prefs.js.map +1 -1
- package/dist/server.d.ts +14 -1
- package/dist/server.js +264 -42
- package/dist/server.js.map +1 -1
- package/dist/theme.d.ts +18 -0
- package/dist/theme.js +96 -0
- package/dist/theme.js.map +1 -0
- package/package.json +2 -2
package/dist/page.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page.js","sourceRoot":"","sources":["../src/page.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAClE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE7C;;;;;;;;;;;;;;GAcG;AAEH,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAs7DvB,CAAC;AAEF,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAu2Q5B,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,OAAO,GAAG;;;;;yCAKyB,CAAC;AAE1C,MAAM,CAAC,MAAM,IAAI,GAAG;;;;;;;4CAOwB,kBAAkB,CAAC,OAAO,CAAC;SAC9D,KAAK;EACZ,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA8RK,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;qBACvB,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;EAC1C,aAAa;EACb,UAAU;EACV,gBAAgB;;;QAGV,CAAC"}
|
|
1
|
+
{"version":3,"file":"page.js","sourceRoot":"","sources":["../src/page.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAClE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC;;;;;;;;;;;;;;GAcG;AAEH,0EAA0E;AAC1E,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAA;EACtB,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAysEV,CAAC;AAEF,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4vU5B,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,OAAO,GAAG;;;;;yCAKyB,CAAC;AAE1C,MAAM,CAAC,MAAM,IAAI,GAAG;;;;;;;4CAOwB,kBAAkB,CAAC,OAAO,CAAC;SAC9D,KAAK;EACZ,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAqSK,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;qBACvB,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;EAC1C,aAAa;EACb,UAAU;EACV,gBAAgB;;;QAGV,CAAC"}
|
package/dist/prefs.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { EffortChoice } from "@oharness/engine/providers/types.ts";
|
|
1
2
|
/**
|
|
2
3
|
* What the frontend remembers between runs.
|
|
3
4
|
*
|
|
@@ -12,6 +13,12 @@
|
|
|
12
13
|
export interface Prefs {
|
|
13
14
|
/** Canonical id of the model last chosen in the picker. */
|
|
14
15
|
model?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Reasoning effort last chosen in the picker, carried to new sessions the
|
|
18
|
+
* same way the model is. Kept as picked, not as clamped: the next session
|
|
19
|
+
* may be on a model that has the tier this one lacked.
|
|
20
|
+
*/
|
|
21
|
+
effort?: EffortChoice;
|
|
15
22
|
/**
|
|
16
23
|
* Directory of the project last opened by hand.
|
|
17
24
|
*
|
package/dist/prefs.js
CHANGED
|
@@ -2,6 +2,7 @@ import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { userPath } from "@oharness/engine/paths.ts";
|
|
4
4
|
import { parseJson } from "@oharness/engine/util/json.ts";
|
|
5
|
+
import { isEffortChoice } from "@oharness/engine/providers/types.ts";
|
|
5
6
|
/** The lists that are arrays of strings, checked the same way on read. */
|
|
6
7
|
const STRING_LISTS = ["pinnedSessions", "pinnedProjects", "projectOrder"];
|
|
7
8
|
const FILE = () => userPath("prefs.json");
|
|
@@ -19,6 +20,8 @@ export async function readPrefs() {
|
|
|
19
20
|
const prefs = {};
|
|
20
21
|
if (typeof parsed.value.model === "string" && parsed.value.model)
|
|
21
22
|
prefs.model = parsed.value.model;
|
|
23
|
+
if (isEffortChoice(parsed.value.effort))
|
|
24
|
+
prefs.effort = parsed.value.effort;
|
|
22
25
|
if (typeof parsed.value.project === "string" && parsed.value.project) {
|
|
23
26
|
prefs.project = parsed.value.project;
|
|
24
27
|
}
|
package/dist/prefs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prefs.js","sourceRoot":"","sources":["../src/prefs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"prefs.js","sourceRoot":"","sources":["../src/prefs.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { Agent } from "@oharness/engine/agent/agent.ts";
|
|
|
2
2
|
import type { Session } from "@oharness/engine/agent/session.ts";
|
|
3
3
|
import { Harness } from "@oharness/engine/harness.ts";
|
|
4
4
|
import type { PermissionRequest } from "@oharness/engine/agent/permissions.ts";
|
|
5
|
+
import type { QuestionRequest, QuestionResult } from "@oharness/engine/tools/questions.ts";
|
|
5
6
|
import type { SettingsScope } from "@oharness/engine/agent/settings.ts";
|
|
6
7
|
/**
|
|
7
8
|
* A browser frontend for the same agent the terminal drives.
|
|
@@ -31,16 +32,28 @@ export interface WebServerOptions {
|
|
|
31
32
|
* have to pay for.
|
|
32
33
|
*/
|
|
33
34
|
openProject?: (cwd: string) => Promise<Harness>;
|
|
35
|
+
/**
|
|
36
|
+
* Told when a turn starts waiting on a person — once, not again on a replay.
|
|
37
|
+
* The desktop shell uses it to notify while its window is in the background;
|
|
38
|
+
* a turn waiting unseen for an hour is the failure it exists to prevent.
|
|
39
|
+
*/
|
|
40
|
+
onInteraction?: (interaction: {
|
|
41
|
+
kind: "permission" | "question";
|
|
42
|
+
session?: string;
|
|
43
|
+
title: string;
|
|
44
|
+
}) => void;
|
|
34
45
|
}
|
|
35
46
|
export interface WebServer {
|
|
36
47
|
readonly url: string;
|
|
37
48
|
readonly token: string;
|
|
38
49
|
close(): Promise<void>;
|
|
39
50
|
/** Answers the prompt the engine is waiting on, used by the HTTP layer. */
|
|
40
|
-
readonly permissionPrompt: (request: PermissionRequest) => Promise<{
|
|
51
|
+
readonly permissionPrompt: (request: PermissionRequest, signal?: AbortSignal) => Promise<{
|
|
41
52
|
allow: boolean;
|
|
42
53
|
remember?: boolean | "session" | SettingsScope;
|
|
43
54
|
}>;
|
|
55
|
+
/** Answers `ask_user` from the page, the same way. */
|
|
56
|
+
readonly questionPrompt: (request: QuestionRequest, signal: AbortSignal) => Promise<QuestionResult>;
|
|
44
57
|
}
|
|
45
58
|
export declare function startWebServer(opts: WebServerOptions): Promise<WebServer>;
|
|
46
59
|
/** One thing the composer's + menu attached to a message. */
|
package/dist/server.js
CHANGED
|
@@ -8,9 +8,11 @@ import { updateUserMcpConfig } from "@oharness/engine/config-files.ts";
|
|
|
8
8
|
import { connectorConfig, officialConnectors } from "@oharness/engine/mcp/registry.ts";
|
|
9
9
|
import { missingSecrets } from "@oharness/engine/mcp/secrets.ts";
|
|
10
10
|
import { connectorIcon, providerSites, siteIcon } from "./icons.js";
|
|
11
|
+
import { checkAnswer } from "@oharness/engine/tools/questions.ts";
|
|
11
12
|
import { PERMISSION_MODES } from "@oharness/engine/agent/permissions.ts";
|
|
13
|
+
import { canDisableThinking, effectiveEffort, isEffortChoice, thinkingFor, } from "@oharness/engine/providers/types.ts";
|
|
12
14
|
import { isReadable } from "@oharness/engine/agent/workspace.ts";
|
|
13
|
-
import {
|
|
15
|
+
import { visibleText } from "@oharness/engine/core/types.ts";
|
|
14
16
|
import { errorMessage } from "@oharness/engine/core/errors.ts";
|
|
15
17
|
import { officialBaseUrl, officialTeam } from "@oharness/engine/auth/providers/official.ts";
|
|
16
18
|
import { updateUserConfig } from "@oharness/engine/config.ts";
|
|
@@ -34,6 +36,13 @@ import { accountTeams, publishArtifact, unpublishArtifact } from "@oharness/engi
|
|
|
34
36
|
* stops short says so rather than reading as the whole history.
|
|
35
37
|
*/
|
|
36
38
|
const USAGE_SESSION_SCAN = 200;
|
|
39
|
+
/**
|
|
40
|
+
* How many trail entries one read of every session may return.
|
|
41
|
+
*
|
|
42
|
+
* Generous, because the page filters and pages through what it is given and a
|
|
43
|
+
* cap that bites in the middle of a normal week would make the filter lie.
|
|
44
|
+
*/
|
|
45
|
+
const AUDIT_ENTRY_CAP = 5000;
|
|
37
46
|
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
38
47
|
/**
|
|
39
48
|
* The windows the usage page offers.
|
|
@@ -48,6 +57,55 @@ const USAGE_RANGES = {
|
|
|
48
57
|
"90d": { id: "90d", days: 90 },
|
|
49
58
|
all: { id: "all", days: 0 },
|
|
50
59
|
};
|
|
60
|
+
/**
|
|
61
|
+
* The longest window that may be asked for by hand.
|
|
62
|
+
*
|
|
63
|
+
* The same year the site's picker allows, so a range chosen there and typed
|
|
64
|
+
* here mean the same thing. Past it the daily buckets are hairs and the walk
|
|
65
|
+
* is every session on disk for a curve that says nothing the presets do not.
|
|
66
|
+
*/
|
|
67
|
+
const MAX_CUSTOM_DAYS = 366;
|
|
68
|
+
const DAY_KEY = /^\d{4}-\d{2}-\d{2}$/;
|
|
69
|
+
/**
|
|
70
|
+
* The window the usage page is asking about: a preset, or two days picked on
|
|
71
|
+
* a calendar.
|
|
72
|
+
*
|
|
73
|
+
* UTC days, because that is what the picker hands over and what the buckets
|
|
74
|
+
* below are floored to — a window whose edges were local midnight and whose
|
|
75
|
+
* columns were UTC would put a day's spend in the column beside its own.
|
|
76
|
+
*
|
|
77
|
+
* `until` is exclusive and never in the future; a range picked backwards is
|
|
78
|
+
* read forwards, and one longer than the cap keeps its last day. Nothing here
|
|
79
|
+
* refuses: a page that answers "bad range" for two days somebody just clicked
|
|
80
|
+
* is a page arguing with its own calendar.
|
|
81
|
+
*/
|
|
82
|
+
function usageWindow(range, from, to) {
|
|
83
|
+
const now = Date.now();
|
|
84
|
+
const midnight = Math.floor(now / DAY_MS) * DAY_MS;
|
|
85
|
+
if (range === "custom" && from && to && DAY_KEY.test(from) && DAY_KEY.test(to)) {
|
|
86
|
+
let first = Date.parse(`${from}T00:00:00Z`);
|
|
87
|
+
let last = Date.parse(`${to}T00:00:00Z`);
|
|
88
|
+
if (Number.isFinite(first) && Number.isFinite(last)) {
|
|
89
|
+
if (first > last)
|
|
90
|
+
[first, last] = [last, first];
|
|
91
|
+
last = Math.min(last, midnight);
|
|
92
|
+
first = Math.min(first, last);
|
|
93
|
+
first = Math.max(first, last - (MAX_CUSTOM_DAYS - 1) * DAY_MS);
|
|
94
|
+
const key = (ms) => new Date(ms).toISOString().slice(0, 10);
|
|
95
|
+
return {
|
|
96
|
+
id: "custom",
|
|
97
|
+
since: first,
|
|
98
|
+
// Inclusive of the last day, so a range ending today still counts what
|
|
99
|
+
// was spent in the hour this page was opened.
|
|
100
|
+
until: Math.min(last + DAY_MS, now),
|
|
101
|
+
from: key(first),
|
|
102
|
+
to: key(last),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const preset = USAGE_RANGES[range ?? ""] ?? USAGE_RANGES["30d"];
|
|
107
|
+
return { id: preset.id, since: preset.days ? now - preset.days * DAY_MS : 0, until: now };
|
|
108
|
+
}
|
|
51
109
|
/**
|
|
52
110
|
* What was spent over time, per model.
|
|
53
111
|
*
|
|
@@ -63,15 +121,16 @@ const USAGE_RANGES = {
|
|
|
63
121
|
* alternative is reading every transcript to place each turn, which is a lot
|
|
64
122
|
* of disk for a curve nobody reads to four decimal places.
|
|
65
123
|
*/
|
|
66
|
-
function usageSeries(rows, since) {
|
|
67
|
-
const
|
|
68
|
-
const span = Math.max(now - since, DAY_MS);
|
|
124
|
+
function usageSeries(rows, since, until = Date.now()) {
|
|
125
|
+
const span = Math.max(until - since, DAY_MS);
|
|
69
126
|
const step = span > 60 * DAY_MS ? "week" : "day";
|
|
70
127
|
const width = step === "week" ? 7 * DAY_MS : DAY_MS;
|
|
71
128
|
// Anchored to the end rather than to midnight of the first day: the last
|
|
72
|
-
// bucket should be the one
|
|
73
|
-
// sliver that reads as a collapse in spending.
|
|
74
|
-
|
|
129
|
+
// bucket should be the one the window ends in, so the newest column is never
|
|
130
|
+
// a sliver that reads as a collapse in spending. A window that ends on a
|
|
131
|
+
// bucket boundary keeps that bucket rather than opening an empty one after
|
|
132
|
+
// it, which is what a picked range ending yesterday would otherwise draw.
|
|
133
|
+
const end = Math.floor((until - 1) / width) * width + width;
|
|
75
134
|
const count = Math.min(Math.ceil((end - since) / width), 400);
|
|
76
135
|
const from = end - count * width;
|
|
77
136
|
const buckets = Array.from({ length: count }, (_, i) => ({
|
|
@@ -168,7 +227,7 @@ export async function startWebServer(opts) {
|
|
|
168
227
|
* choice changes, so re-reading it per session would only add a disk hit to
|
|
169
228
|
* answer a question this already knows.
|
|
170
229
|
*/
|
|
171
|
-
let preferredModel =
|
|
230
|
+
let { model: preferredModel, effort: preferredEffort } = await readPrefs();
|
|
172
231
|
/**
|
|
173
232
|
* A new session on a harness, honouring that preference.
|
|
174
233
|
*
|
|
@@ -178,7 +237,10 @@ export async function startWebServer(opts) {
|
|
|
178
237
|
*/
|
|
179
238
|
const freshSession = (harness) => {
|
|
180
239
|
const known = preferredModel && harness.listModels().some((model) => model.id === preferredModel);
|
|
181
|
-
return harness.createSession(
|
|
240
|
+
return harness.createSession({
|
|
241
|
+
...(known ? { model: preferredModel } : {}),
|
|
242
|
+
...(preferredEffort ? { effort: preferredEffort } : {}),
|
|
243
|
+
});
|
|
182
244
|
};
|
|
183
245
|
/**
|
|
184
246
|
* Files staged for the next prompt.
|
|
@@ -267,13 +329,74 @@ export async function startWebServer(opts) {
|
|
|
267
329
|
}));
|
|
268
330
|
}
|
|
269
331
|
watchConnections(opts.harness);
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
332
|
+
/**
|
|
333
|
+
* Take a waiting interaction off every screen.
|
|
334
|
+
*
|
|
335
|
+
* Broadcast on answer as well as on interrupt: a second window showing the
|
|
336
|
+
* same card must not stay answerable after the first one answered it.
|
|
337
|
+
*/
|
|
338
|
+
const retire = (entry) => {
|
|
339
|
+
if (pending.get(entry.id) !== entry)
|
|
340
|
+
return false;
|
|
341
|
+
pending.delete(entry.id);
|
|
342
|
+
broadcast({ type: "interaction_closed", id: entry.id, ...(entry.session ? { session: entry.session } : {}) });
|
|
343
|
+
return true;
|
|
344
|
+
};
|
|
345
|
+
/** The event a waiting interaction is drawn from, for a live broadcast and a replay alike. */
|
|
346
|
+
const announce = (entry) => entry.kind === "permission"
|
|
347
|
+
? { type: "permission_request", id: entry.id, request: entry.request, ...(entry.session ? { session: entry.session } : {}) }
|
|
348
|
+
: { type: "question_request", id: entry.id, request: entry.request, session: entry.session };
|
|
349
|
+
const notify = (entry) => {
|
|
350
|
+
try {
|
|
351
|
+
opts.onInteraction?.({
|
|
352
|
+
kind: entry.kind,
|
|
353
|
+
...(entry.session ? { session: entry.session } : {}),
|
|
354
|
+
title: entry.kind === "permission" ? entry.request.title : (entry.request.questions[0]?.question ?? ""),
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
catch {
|
|
358
|
+
// A notifier that throws must not take the prompt down with it.
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
// No timeout on either of these, on purpose. A prompt that auto-denies after
|
|
362
|
+
// a while would silently fail long-running work while the user is away; a
|
|
363
|
+
// prompt that auto-allows would be worse. It waits — until it is answered,
|
|
364
|
+
// or the turn waiting on it is interrupted.
|
|
365
|
+
const permissionPrompt = (request, signal) => new Promise((resolve) => {
|
|
366
|
+
const entry = {
|
|
367
|
+
kind: "permission",
|
|
368
|
+
id: randomUUID(),
|
|
369
|
+
...(request.sessionId ? { session: request.sessionId } : {}),
|
|
370
|
+
request,
|
|
371
|
+
settle: (reply) => {
|
|
372
|
+
if (retire(entry))
|
|
373
|
+
resolve(reply);
|
|
374
|
+
},
|
|
375
|
+
};
|
|
376
|
+
if (signal?.aborted)
|
|
377
|
+
return resolve({ allow: false });
|
|
378
|
+
pending.set(entry.id, entry);
|
|
379
|
+
signal?.addEventListener("abort", () => entry.settle({ allow: false }), { once: true });
|
|
380
|
+
broadcast(announce(entry));
|
|
381
|
+
notify(entry);
|
|
382
|
+
});
|
|
383
|
+
const questionPrompt = (request, signal) => new Promise((resolve) => {
|
|
384
|
+
const entry = {
|
|
385
|
+
kind: "question",
|
|
386
|
+
id: randomUUID(),
|
|
387
|
+
session: request.sessionId,
|
|
388
|
+
request,
|
|
389
|
+
settle: (result) => {
|
|
390
|
+
if (retire(entry))
|
|
391
|
+
resolve(result);
|
|
392
|
+
},
|
|
393
|
+
};
|
|
394
|
+
if (signal.aborted)
|
|
395
|
+
return resolve({ outcome: "aborted" });
|
|
396
|
+
pending.set(entry.id, entry);
|
|
397
|
+
signal.addEventListener("abort", () => entry.settle({ outcome: "aborted" }), { once: true });
|
|
398
|
+
broadcast(announce(entry));
|
|
399
|
+
notify(entry);
|
|
277
400
|
});
|
|
278
401
|
const server = createServer((req, res) => {
|
|
279
402
|
void handle(req, res).catch((err) => {
|
|
@@ -320,12 +443,12 @@ export async function startWebServer(opts) {
|
|
|
320
443
|
const runner = runnerFor(url.searchParams.get("session"));
|
|
321
444
|
const page = runner?.harness.extensions.page(url.searchParams.get("id") ?? "");
|
|
322
445
|
if (!page)
|
|
323
|
-
return send(res, 404, { error: "
|
|
446
|
+
return send(res, 404, { error: "This plugin page is not enabled." });
|
|
324
447
|
try {
|
|
325
448
|
return send(res, 200, await page.read());
|
|
326
449
|
}
|
|
327
450
|
catch {
|
|
328
|
-
return send(res, 400, { error: "
|
|
451
|
+
return send(res, 400, { error: "The plugin page could not be read. Check its local files." });
|
|
329
452
|
}
|
|
330
453
|
}
|
|
331
454
|
case "POST /plugin-page": {
|
|
@@ -334,12 +457,18 @@ export async function startWebServer(opts) {
|
|
|
334
457
|
const runner = runnerFor(body.session);
|
|
335
458
|
const page = runner?.harness.extensions.page(typeof body.page === "string" ? body.page : "");
|
|
336
459
|
if (!page || !body.input || typeof body.input !== "object" || Array.isArray(body.input))
|
|
337
|
-
return send(res, 400, { error: "
|
|
460
|
+
return send(res, 400, { error: "Invalid plugin page action." });
|
|
338
461
|
try {
|
|
339
462
|
return send(res, 200, await page.act(body.input));
|
|
340
463
|
}
|
|
341
464
|
catch (error) {
|
|
342
|
-
|
|
465
|
+
// A code and its values travel with the message, so the page can say it in its own language.
|
|
466
|
+
const detail = (error && typeof error === "object" ? error : {});
|
|
467
|
+
return send(res, 400, {
|
|
468
|
+
error: errorMessage(error),
|
|
469
|
+
...(typeof detail.code === "string" ? { code: detail.code } : {}),
|
|
470
|
+
...(detail.params && typeof detail.params === "object" ? { params: detail.params } : {}),
|
|
471
|
+
});
|
|
343
472
|
}
|
|
344
473
|
}
|
|
345
474
|
case "POST /cloud-connection": {
|
|
@@ -1382,18 +1511,50 @@ export async function startWebServer(opts) {
|
|
|
1382
1511
|
return void res.end(body);
|
|
1383
1512
|
}
|
|
1384
1513
|
/**
|
|
1385
|
-
*
|
|
1514
|
+
* The permission trail — one session's, or every session's.
|
|
1515
|
+
*
|
|
1516
|
+
* A session by default, because that is where it is written and how the
|
|
1517
|
+
* Settings row reads it: beside the conversation it describes, with no
|
|
1518
|
+
* id to know before opening.
|
|
1386
1519
|
*
|
|
1387
|
-
*
|
|
1388
|
-
*
|
|
1389
|
-
*
|
|
1520
|
+
* `session=all` is what the page asks for. The question an audit trail
|
|
1521
|
+
* is opened for — when was this ever allowed, and who said yes — is
|
|
1522
|
+
* rarely one a single session answers, and leaving it to be answered by
|
|
1523
|
+
* downloading the export and reading JSON lines by hand is not an answer
|
|
1524
|
+
* a page can hand somebody.
|
|
1525
|
+
*
|
|
1526
|
+
* Newest session first and capped, because the walk is a file read per
|
|
1527
|
+
* session. `/audit/export` already pays that cost, but it pays it for a
|
|
1528
|
+
* download somebody asked for by name; a panel that repaints has to stop
|
|
1529
|
+
* somewhere, and `more` says out loud that it did.
|
|
1390
1530
|
*/
|
|
1391
1531
|
case "GET /audit": {
|
|
1392
|
-
const
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1532
|
+
const asked = url.searchParams.get("session") ?? current.session.id;
|
|
1533
|
+
if (asked !== "all") {
|
|
1534
|
+
return send(res, 200, {
|
|
1535
|
+
session: asked,
|
|
1536
|
+
entries: await current.harness.decisions(asked),
|
|
1537
|
+
});
|
|
1538
|
+
}
|
|
1539
|
+
const metas = (await current.harness.listSessions(Number.MAX_SAFE_INTEGER))
|
|
1540
|
+
.sort((a, b) => b.updatedAt - a.updatedAt);
|
|
1541
|
+
const entries = [];
|
|
1542
|
+
let scanned = 0;
|
|
1543
|
+
let more = false;
|
|
1544
|
+
for (const meta of metas) {
|
|
1545
|
+
if (entries.length >= AUDIT_ENTRY_CAP) {
|
|
1546
|
+
more = true;
|
|
1547
|
+
break;
|
|
1548
|
+
}
|
|
1549
|
+
scanned += 1;
|
|
1550
|
+
// The session id on every line, the same way the export writes it:
|
|
1551
|
+
// once the scope is more than one session, a row that cannot say
|
|
1552
|
+
// which one it came from is a row nobody can follow up on.
|
|
1553
|
+
for (const entry of await current.harness.decisions(meta.id)) {
|
|
1554
|
+
entries.push({ ...entry, session: meta.id });
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
return send(res, 200, { session: "all", entries, sessions: scanned, more });
|
|
1397
1558
|
}
|
|
1398
1559
|
// The key lives behind this rather than in the HTML: a build that has one
|
|
1399
1560
|
// still hands it to nobody until they have opted in.
|
|
@@ -1454,8 +1615,8 @@ export async function startWebServer(opts) {
|
|
|
1454
1615
|
// totals, the models, the sessions and the curve — is that window and
|
|
1455
1616
|
// nothing else, because a figure that answers a different question
|
|
1456
1617
|
// from the chart under it is worse than no figure.
|
|
1457
|
-
const
|
|
1458
|
-
const since
|
|
1618
|
+
const window = usageWindow(url.searchParams.get("range"), url.searchParams.get("from"), url.searchParams.get("to"));
|
|
1619
|
+
const { since, until } = window;
|
|
1459
1620
|
const stored = await current.harness.listSessions(USAGE_SESSION_SCAN);
|
|
1460
1621
|
const rows = new Map();
|
|
1461
1622
|
for (const meta of stored) {
|
|
@@ -1489,7 +1650,7 @@ export async function startWebServer(opts) {
|
|
|
1489
1650
|
// They are still counted in `scanned`, which is what says how far back
|
|
1490
1651
|
// the numbers above them reach.
|
|
1491
1652
|
const list = [...rows.values()]
|
|
1492
|
-
.filter((row) => row.updatedAt >= since)
|
|
1653
|
+
.filter((row) => row.updatedAt >= since && row.updatedAt < until)
|
|
1493
1654
|
.filter((row) => row.costUsd > 0 || row.input || row.output || row.cacheRead || row.cacheWrite)
|
|
1494
1655
|
.sort((a, b) => b.updatedAt - a.updatedAt);
|
|
1495
1656
|
const zero = { costUsd: 0, input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
|
|
@@ -1514,8 +1675,14 @@ export async function startWebServer(opts) {
|
|
|
1514
1675
|
byModel.set(row.model, add(bucket, row));
|
|
1515
1676
|
}
|
|
1516
1677
|
return send(res, 200, {
|
|
1517
|
-
range:
|
|
1518
|
-
|
|
1678
|
+
range: window.id,
|
|
1679
|
+
// Echoed back so the picker opens on the window being shown rather
|
|
1680
|
+
// than on what was typed: the two differ whenever a range was
|
|
1681
|
+
// clamped, and a calendar that disagrees with the figures beside it
|
|
1682
|
+
// is the one thing it must not do.
|
|
1683
|
+
from: window.from,
|
|
1684
|
+
to: window.to,
|
|
1685
|
+
series: usageSeries(list, since || (list.length ? list[list.length - 1].updatedAt : Date.now()), until),
|
|
1519
1686
|
totals: { ...totals, sessions: list.length },
|
|
1520
1687
|
// Sorted by what was spent, not by name: the row worth seeing first
|
|
1521
1688
|
// is the expensive one.
|
|
@@ -1880,6 +2047,23 @@ export async function startWebServer(opts) {
|
|
|
1880
2047
|
return send(res, 400, { error: errorMessage(err) });
|
|
1881
2048
|
}
|
|
1882
2049
|
}
|
|
2050
|
+
case "POST /effort": {
|
|
2051
|
+
const body = await readJson(req);
|
|
2052
|
+
const runner = runnerFor(body.session);
|
|
2053
|
+
if (!runner)
|
|
2054
|
+
return send(res, 404, { error: "no such session" });
|
|
2055
|
+
if (!isEffortChoice(body.effort)) {
|
|
2056
|
+
return send(res, 400, { error: `unknown effort: ${String(body.effort)}` });
|
|
2057
|
+
}
|
|
2058
|
+
// Not refused while a turn runs, unlike a model switch: the request in
|
|
2059
|
+
// flight already carries its effort, and the next one reads this.
|
|
2060
|
+
runner.session.effort = body.effort;
|
|
2061
|
+
preferredEffort = body.effort;
|
|
2062
|
+
void writePrefs({ effort: preferredEffort });
|
|
2063
|
+
void runner.session.persist().catch(() => { });
|
|
2064
|
+
broadcast({ type: "state", session: runner.session.id, state: state(runner) });
|
|
2065
|
+
return send(res, 200, state(runner));
|
|
2066
|
+
}
|
|
1883
2067
|
case "POST /mode": {
|
|
1884
2068
|
const body = await readJson(req);
|
|
1885
2069
|
const runner = runnerFor(body.session);
|
|
@@ -2071,10 +2255,9 @@ export async function startWebServer(opts) {
|
|
|
2071
2255
|
case "POST /permission": {
|
|
2072
2256
|
const body = await readJson(req);
|
|
2073
2257
|
const entry = typeof body.id === "string" ? pending.get(body.id) : undefined;
|
|
2074
|
-
if (!entry)
|
|
2258
|
+
if (!entry || entry.kind !== "permission")
|
|
2075
2259
|
return send(res, 404, { error: "no such pending request" });
|
|
2076
|
-
|
|
2077
|
-
entry.resolve({
|
|
2260
|
+
entry.settle({
|
|
2078
2261
|
allow: body.allow === true,
|
|
2079
2262
|
...(typeof body.remember === "string"
|
|
2080
2263
|
? { remember: body.remember }
|
|
@@ -2082,6 +2265,19 @@ export async function startWebServer(opts) {
|
|
|
2082
2265
|
});
|
|
2083
2266
|
return send(res, 200, { ok: true });
|
|
2084
2267
|
}
|
|
2268
|
+
case "POST /question": {
|
|
2269
|
+
const body = await readJson(req);
|
|
2270
|
+
const entry = typeof body.id === "string" ? pending.get(body.id) : undefined;
|
|
2271
|
+
if (!entry || entry.kind !== "question")
|
|
2272
|
+
return send(res, 404, { error: "no such pending question" });
|
|
2273
|
+
// Checked here rather than trusted: the page is one client of this
|
|
2274
|
+
// route, and a label the model never offered must not reach it as one.
|
|
2275
|
+
const checked = checkAnswer(entry.request.questions, body.answer);
|
|
2276
|
+
if (!checked.ok)
|
|
2277
|
+
return send(res, 400, { error: checked.error });
|
|
2278
|
+
entry.settle(checked.result);
|
|
2279
|
+
return send(res, 200, { ok: true });
|
|
2280
|
+
}
|
|
2085
2281
|
case "POST /interrupt":
|
|
2086
2282
|
{
|
|
2087
2283
|
const body = await readJson(req);
|
|
@@ -2289,6 +2485,13 @@ export async function startWebServer(opts) {
|
|
|
2289
2485
|
model: model.id,
|
|
2290
2486
|
provider: model.provider,
|
|
2291
2487
|
mode: sess.permissions.getMode(),
|
|
2488
|
+
// What the next request will carry, not what was picked: a pick the
|
|
2489
|
+
// model lacks shows as the tier it is clamped to, and a model that
|
|
2490
|
+
// cannot stop thinking never shows "off". Absent when the model has no
|
|
2491
|
+
// tiers at all, which is the page's cue to hide the control.
|
|
2492
|
+
effort: effectiveEffort(model, thinkingFor(runner.harness.config.thinking, sess.effort)),
|
|
2493
|
+
effortLevels: model.effortLevels,
|
|
2494
|
+
effortOff: model.effortLevels.length > 0 && canDisableThinking(model),
|
|
2292
2495
|
costUsd: sess.costUsd,
|
|
2293
2496
|
// Beside the cost, because the line under the composer says three things
|
|
2294
2497
|
// about one turn: what it cost, how many tokens that took, and how much
|
|
@@ -2315,7 +2518,7 @@ export async function startWebServer(opts) {
|
|
|
2315
2518
|
index++;
|
|
2316
2519
|
const tools = message.content.filter((block) => block.type === "tool_call");
|
|
2317
2520
|
const results = message.content.filter((block) => block.type === "tool_result");
|
|
2318
|
-
const text =
|
|
2521
|
+
const text = visibleText(message).trim();
|
|
2319
2522
|
// The bytes stay where they are; what travels is where to find them.
|
|
2320
2523
|
// Without this a reloaded conversation showed "[image: shot.png]" where
|
|
2321
2524
|
// the screenshot had been — the model still saw it, the person did not.
|
|
@@ -2388,7 +2591,8 @@ export async function startWebServer(opts) {
|
|
|
2388
2591
|
? opts.openProject(project.path)
|
|
2389
2592
|
: Harness.create({
|
|
2390
2593
|
cwd: project.path,
|
|
2391
|
-
permissionPrompt: (request) => permissionPrompt(request),
|
|
2594
|
+
permissionPrompt: (request, signal) => permissionPrompt(request, signal),
|
|
2595
|
+
questionPrompt: (request, signal) => questionPrompt(request, signal),
|
|
2392
2596
|
}));
|
|
2393
2597
|
harnesses.set(project.path, harness);
|
|
2394
2598
|
watchConnections(harness);
|
|
@@ -2500,6 +2704,12 @@ export async function startWebServer(opts) {
|
|
|
2500
2704
|
const input = staged.length ? buildMessage(text, staged) : text;
|
|
2501
2705
|
try {
|
|
2502
2706
|
for await (const event of runner.agent.run(input, { signal: controller.signal })) {
|
|
2707
|
+
// The agent's own question_request is not forwarded: the page draws
|
|
2708
|
+
// the card from questionPrompt's announce, which carries the id the
|
|
2709
|
+
// answer is posted back to. Forwarding both drew the card twice, and
|
|
2710
|
+
// the copy without that id could only ever 404.
|
|
2711
|
+
if (event.type === "question_request")
|
|
2712
|
+
continue;
|
|
2503
2713
|
broadcast({ ...event, session: id });
|
|
2504
2714
|
}
|
|
2505
2715
|
}
|
|
@@ -2551,6 +2761,14 @@ export async function startWebServer(opts) {
|
|
|
2551
2761
|
res.write(`data: ${JSON.stringify({ type: "connection_card", session: card.session, card })}\n\n`);
|
|
2552
2762
|
}
|
|
2553
2763
|
}
|
|
2764
|
+
// Whatever is still waiting on a person, again. A page that reloads while
|
|
2765
|
+
// a turn waits on it would otherwise never see the card, and the turn
|
|
2766
|
+
// would wait on nobody for as long as the process lives.
|
|
2767
|
+
for (const entry of pending.values())
|
|
2768
|
+
res.write(`data: ${JSON.stringify(announce(entry))}\n\n`);
|
|
2769
|
+
// And the full list, so a page that missed an interaction_closed while
|
|
2770
|
+
// disconnected can drop the cards that are no longer waiting.
|
|
2771
|
+
res.write(`data: ${JSON.stringify({ type: "pending_interactions", ids: [...pending.keys()] })}\n\n`);
|
|
2554
2772
|
// A heartbeat keeps intermediaries from closing an idle stream while the
|
|
2555
2773
|
// model is thinking.
|
|
2556
2774
|
const beat = setInterval(() => res.write(": ping\n\n"), 15_000);
|
|
@@ -2718,6 +2936,7 @@ export async function startWebServer(opts) {
|
|
|
2718
2936
|
url: `http://${host}:${port}/?token=${token}`,
|
|
2719
2937
|
token,
|
|
2720
2938
|
permissionPrompt,
|
|
2939
|
+
questionPrompt,
|
|
2721
2940
|
async close() {
|
|
2722
2941
|
for (const unsubscribe of connectionSubscriptions)
|
|
2723
2942
|
unsubscribe();
|
|
@@ -2728,9 +2947,12 @@ export async function startWebServer(opts) {
|
|
|
2728
2947
|
clients.clear();
|
|
2729
2948
|
// Any prompt still waiting has to be answered, or the agent's turn hangs
|
|
2730
2949
|
// forever holding the process open. Shutting down denies.
|
|
2731
|
-
for (const entry of pending.values())
|
|
2732
|
-
entry.
|
|
2733
|
-
|
|
2950
|
+
for (const entry of [...pending.values()]) {
|
|
2951
|
+
if (entry.kind === "permission")
|
|
2952
|
+
entry.settle({ allow: false });
|
|
2953
|
+
else
|
|
2954
|
+
entry.settle({ outcome: "unavailable" });
|
|
2955
|
+
}
|
|
2734
2956
|
for (const runner of runners.values())
|
|
2735
2957
|
runner.running?.abort();
|
|
2736
2958
|
await new Promise((resolve) => server.close(() => resolve()));
|