@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/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":"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"}
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 { messageText } from "@oharness/engine/core/types.ts";
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 now = Date.now();
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 happening now, so the newest column is never a
73
- // sliver that reads as a collapse in spending.
74
- const end = Math.floor(now / width) * width + width;
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 = (await readPrefs()).model;
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(known ? { model: preferredModel } : {});
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
- const permissionPrompt = (request) => new Promise((resolve) => {
271
- const id = randomUUID();
272
- pending.set(id, { id, request, resolve });
273
- broadcast({ type: "permission_request", id, request });
274
- // No timeout here on purpose. A prompt that auto-denies after a while
275
- // would silently fail long-running work while the user is away; a prompt
276
- // that auto-allows would be worse. It waits.
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
- return send(res, 400, { error: errorMessage(error) });
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
- * One session's permission trail.
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
- * Scoped to a session because that is where it is written and how it is
1388
- * meant to be read — beside the conversation it describes. Defaults to
1389
- * the focused one so the panel does not have to know an id to open.
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 id = url.searchParams.get("session") ?? current.session.id;
1393
- return send(res, 200, {
1394
- session: id,
1395
- entries: await current.harness.decisions(id),
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 range = USAGE_RANGES[url.searchParams.get("range") ?? ""] ?? USAGE_RANGES["30d"];
1458
- const since = range.days ? Date.now() - range.days * DAY_MS : 0;
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: range.id,
1518
- series: usageSeries(list, since || (list.length ? list[list.length - 1].updatedAt : Date.now())),
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
- pending.delete(entry.id);
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 = messageText(message).trim();
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.resolve({ allow: false });
2733
- pending.clear();
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()));