@oharness/server 0.9.3 → 0.11.0

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.
Files changed (93) hide show
  1. package/dist/analytics.d.ts +32 -29
  2. package/dist/analytics.js +225 -278
  3. package/dist/analytics.js.map +1 -1
  4. package/dist/i18n.js +500 -64
  5. package/dist/i18n.js.map +1 -1
  6. package/dist/icons.js +1 -0
  7. package/dist/icons.js.map +1 -1
  8. package/dist/main.js +4 -0
  9. package/dist/main.js.map +1 -1
  10. package/dist/model-order.js +1 -0
  11. package/dist/model-order.js.map +1 -1
  12. package/dist/page/client/account.js +570 -27
  13. package/dist/page/client/account.js.map +1 -1
  14. package/dist/page/client/base.js +55 -12
  15. package/dist/page/client/base.js.map +1 -1
  16. package/dist/page/client/browser.js +1 -1
  17. package/dist/page/client/composer.js +802 -59
  18. package/dist/page/client/composer.js.map +1 -1
  19. package/dist/page/client/computer.d.ts +27 -0
  20. package/dist/page/client/computer.js +358 -0
  21. package/dist/page/client/computer.js.map +1 -0
  22. package/dist/page/client/dialogs.js +168 -6
  23. package/dist/page/client/dialogs.js.map +1 -1
  24. package/dist/page/client/events.js +119 -9
  25. package/dist/page/client/events.js.map +1 -1
  26. package/dist/page/client/files.js +86 -1
  27. package/dist/page/client/files.js.map +1 -1
  28. package/dist/page/client/index.js +8 -0
  29. package/dist/page/client/index.js.map +1 -1
  30. package/dist/page/client/panels.js +14 -10
  31. package/dist/page/client/panels.js.map +1 -1
  32. package/dist/page/client/ripple.d.ts +13 -0
  33. package/dist/page/client/ripple.js +247 -0
  34. package/dist/page/client/ripple.js.map +1 -0
  35. package/dist/page/client/routines.js +432 -45
  36. package/dist/page/client/routines.js.map +1 -1
  37. package/dist/page/client/shell.js +386 -104
  38. package/dist/page/client/shell.js.map +1 -1
  39. package/dist/page/client/state.js +278 -19
  40. package/dist/page/client/state.js.map +1 -1
  41. package/dist/page/client/tasks.d.ts +8 -0
  42. package/dist/page/client/tasks.js +293 -0
  43. package/dist/page/client/tasks.js.map +1 -0
  44. package/dist/page/client/terminal.js +34 -7
  45. package/dist/page/client/terminal.js.map +1 -1
  46. package/dist/page/client/theme.d.ts +17 -0
  47. package/dist/page/client/theme.js +365 -0
  48. package/dist/page/client/theme.js.map +1 -0
  49. package/dist/page/client/transcript.js +196 -8
  50. package/dist/page/client/transcript.js.map +1 -1
  51. package/dist/page/client/usage.js +1 -11
  52. package/dist/page/client/usage.js.map +1 -1
  53. package/dist/page/style.js +745 -76
  54. package/dist/page/style.js.map +1 -1
  55. package/dist/page.js +94 -16
  56. package/dist/page.js.map +1 -1
  57. package/dist/prefs.d.ts +31 -0
  58. package/dist/prefs.js +13 -1
  59. package/dist/prefs.js.map +1 -1
  60. package/dist/remote-crypto.d.ts +78 -0
  61. package/dist/remote-crypto.js +216 -0
  62. package/dist/remote-crypto.js.map +1 -0
  63. package/dist/remote.d.ts +103 -0
  64. package/dist/remote.js +498 -0
  65. package/dist/remote.js.map +1 -0
  66. package/dist/server.d.ts +70 -0
  67. package/dist/server.js +1738 -73
  68. package/dist/server.js.map +1 -1
  69. package/dist/starters.d.ts +92 -0
  70. package/dist/starters.js +213 -0
  71. package/dist/starters.js.map +1 -0
  72. package/dist/suggest.d.ts +42 -0
  73. package/dist/suggest.js +215 -0
  74. package/dist/suggest.js.map +1 -0
  75. package/dist/terminal.d.ts +28 -2
  76. package/dist/terminal.js +45 -3
  77. package/dist/terminal.js.map +1 -1
  78. package/dist/theme-assets.d.ts +39 -0
  79. package/dist/theme-assets.js +109 -0
  80. package/dist/theme-assets.js.map +1 -0
  81. package/dist/theme-store.d.ts +50 -0
  82. package/dist/theme-store.js +124 -0
  83. package/dist/theme-store.js.map +1 -0
  84. package/dist/theme-tools.d.ts +25 -0
  85. package/dist/theme-tools.js +243 -0
  86. package/dist/theme-tools.js.map +1 -0
  87. package/dist/turn-shots.d.ts +43 -0
  88. package/dist/turn-shots.js +80 -0
  89. package/dist/turn-shots.js.map +1 -0
  90. package/dist/user-theme.d.ts +143 -0
  91. package/dist/user-theme.js +510 -0
  92. package/dist/user-theme.js.map +1 -0
  93. package/package.json +2 -2
@@ -0,0 +1,293 @@
1
+ /**
2
+ * Background tasks: their rows over the composer, and the sheet one opens
3
+ * into — what the subagent was told, what it did, what it said — with a way
4
+ * to stop it or tell it something.
5
+ *
6
+ * One part of the client script; see ./index.ts for how the parts join.
7
+ */
8
+ export const TASKS = String.raw `
9
+ // --- background tasks -----------------------------------------------------
10
+
11
+ const TASK_LIVE = new Set(["queued", "running"]);
12
+ /** How many task rows sit over the composer; the sheet lists every one. */
13
+ const TASK_ROWS = 4;
14
+ /** The task the sheet shows, while it is open. */
15
+ let taskOpen = null;
16
+ let taskSheet = null;
17
+ /** Bumped per paint, so a slow answer never draws over a newer one. */
18
+ let taskPaintSeq = 0;
19
+
20
+ /**
21
+ * Running ones first, then the newest. Ended tasks stay listed, quieter, so
22
+ * what they said is a click away and they can still be sent a follow-up.
23
+ */
24
+ function sortedTasks(tasks) {
25
+ return (tasks || []).slice().sort((a, b) =>
26
+ (Number(TASK_LIVE.has(b.status)) - Number(TASK_LIVE.has(a.status))) || (b.queuedAt - a.queuedAt));
27
+ }
28
+
29
+ /** The rows over the composer, drawn by renderQueued with the queue. */
30
+ function appendTaskRows(container, here) {
31
+ // Put-away tasks leave the list; the transcript's card and the sheet's
32
+ // chips still reach them.
33
+ const tasks = sortedTasks(here && here.tasks).filter((task) => !task.dismissed);
34
+ for (const task of tasks.slice(0, TASK_ROWS)) {
35
+ const row = el("div", "q task task-" + task.status);
36
+ row.appendChild(el("span", "tag", t("tasks.status." + task.status)));
37
+ const name = el("span", "n", task.description + (task.activity ? " · " + task.activity : ""));
38
+ row.appendChild(name);
39
+ const open = el("button", "go", t("tasks.open"));
40
+ open.type = "button";
41
+ open.addEventListener("click", () => openTask(activeId, task.id));
42
+ row.appendChild(open);
43
+ // One × in the same place, saying what it does: running, it stops the
44
+ // task; ended, it only takes the row away.
45
+ const live = TASK_LIVE.has(task.status);
46
+ const close = el("button", "x", "×");
47
+ close.type = "button";
48
+ close.title = t(live ? "tasks.stop" : "tasks.dismiss");
49
+ close.setAttribute("aria-label", close.title);
50
+ close.addEventListener("click", () => void (live ? stopTask(activeId, task.id) : dismissTask(activeId, task.id)));
51
+ row.appendChild(close);
52
+ name.addEventListener("click", () => openTask(activeId, task.id));
53
+ container.appendChild(row);
54
+ }
55
+ if (tasks.length > TASK_ROWS) {
56
+ const more = el("button", "q task-more", t("tasks.more", { n: tasks.length - TASK_ROWS }));
57
+ more.type = "button";
58
+ more.addEventListener("click", () => openTask(activeId, tasks[TASK_ROWS].id));
59
+ container.appendChild(more);
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Background results read into the conversation, as the transcript shows them:
65
+ * one line per task saying how it ended, each a way into its sheet. Where it
66
+ * sits is where the model read them.
67
+ */
68
+ function taskCard(tasks) {
69
+ const card = el("div", "task-card");
70
+ card.appendChild(el("div", "task-card-head", t("tasks.cardTitle")));
71
+ for (const task of tasks) {
72
+ const row = el("div", "task-card-row task-" + task.status);
73
+ row.appendChild(el("span", "tag", t("tasks.status." + task.status)));
74
+ row.appendChild(el("span", "n", task.description));
75
+ const open = el("button", "go", t("tasks.open"));
76
+ open.type = "button";
77
+ // The conversation this card is in, which need not be the one on screen.
78
+ const session = P.id;
79
+ open.addEventListener("click", () => openTask(session, task.id));
80
+ row.appendChild(open);
81
+ card.appendChild(row);
82
+ }
83
+ // In the transcript's column, so it lines up with the messages around it.
84
+ const row = el("div", "column task-card-row-wrap");
85
+ row.appendChild(card);
86
+ P.node.appendChild(row);
87
+ follow();
88
+ }
89
+
90
+ /** A conversation's tasks changed: redraw what shows them. */
91
+ function tasksChanged(session, tasks) {
92
+ pane(session).tasks = tasks || [];
93
+ if (session === activeId) renderQueued();
94
+ if (taskOpen && taskOpen.session === session) void paintTask();
95
+ }
96
+
97
+ function openTask(session, id) {
98
+ taskOpen = { session, id, stick: true };
99
+ ensureTaskSheet();
100
+ taskSheet.hidden = false;
101
+ void paintTask();
102
+ taskSheet.querySelector(".task-input").focus();
103
+ }
104
+
105
+ function closeTask() {
106
+ taskOpen = null;
107
+ if (taskSheet) taskSheet.hidden = true;
108
+ }
109
+
110
+ async function dismissTask(session, id) {
111
+ const body = await api("/task", { session, id, action: "dismiss" });
112
+ if (body.error) addNotice(body.error, "notice err");
113
+ }
114
+
115
+ async function stopTask(session, id) {
116
+ const body = await api("/task", { session, id, action: "stop" });
117
+ if (body.error) addNotice(body.error, "notice err");
118
+ }
119
+
120
+ function ensureTaskSheet() {
121
+ if (taskSheet) return;
122
+ taskSheet = el("div");
123
+ taskSheet.id = "task-sheet";
124
+ taskSheet.hidden = true;
125
+ taskSheet.setAttribute("role", "dialog");
126
+ taskSheet.setAttribute("aria-label", t("tasks.title"));
127
+
128
+ const head = el("div", "task-head");
129
+ const titles = el("div", "task-titles");
130
+ titles.appendChild(el("div", "task-title"));
131
+ titles.appendChild(el("div", "task-meta"));
132
+ head.appendChild(titles);
133
+ const stop = el("button", "task-stop", t("tasks.stop"));
134
+ stop.type = "button";
135
+ stop.addEventListener("click", () => { if (taskOpen) void stopTask(taskOpen.session, taskOpen.id); });
136
+ head.appendChild(stop);
137
+ const close = el("button", "task-close", "×");
138
+ close.type = "button";
139
+ close.title = t("tasks.close");
140
+ close.setAttribute("aria-label", t("tasks.close"));
141
+ close.addEventListener("click", closeTask);
142
+ head.appendChild(close);
143
+ taskSheet.appendChild(head);
144
+
145
+ taskSheet.appendChild(el("div", "task-chips"));
146
+ const log = el("div", "task-log");
147
+ // Follow new lines only while the reader is at the bottom; scrolling up to
148
+ // read something earlier must not be undone by the next tool.
149
+ log.addEventListener("scroll", () => {
150
+ if (taskOpen) taskOpen.stick = log.scrollHeight - log.scrollTop - log.clientHeight < 40;
151
+ });
152
+ taskSheet.appendChild(log);
153
+
154
+ // The box is the field and its send button together, as in the composer.
155
+ const form = el("form", "task-form");
156
+ const box = el("div", "task-box");
157
+ const input = el("textarea", "task-input");
158
+ input.rows = 2;
159
+ input.setAttribute("aria-label", t("tasks.messageLabel"));
160
+ const send = el("button", "primary task-send");
161
+ send.type = "submit";
162
+ send.title = t("tasks.send");
163
+ send.setAttribute("aria-label", t("tasks.send"));
164
+ send.appendChild(svgIcon("send"));
165
+ box.appendChild(input);
166
+ box.appendChild(send);
167
+ form.appendChild(box);
168
+ form.addEventListener("submit", (e) => {
169
+ e.preventDefault();
170
+ void sendTask(input);
171
+ });
172
+ input.addEventListener("keydown", (e) => {
173
+ if (e.key === "Enter" && !e.shiftKey && !e.isComposing) {
174
+ e.preventDefault();
175
+ void sendTask(input);
176
+ }
177
+ });
178
+ taskSheet.appendChild(form);
179
+
180
+ taskSheet.addEventListener("keydown", (e) => {
181
+ if (e.key === "Escape") closeTask();
182
+ });
183
+ document.body.appendChild(taskSheet);
184
+ }
185
+
186
+ async function sendTask(input) {
187
+ const text = input.value.trim();
188
+ if (!text || !taskOpen) return;
189
+ const { session, id } = taskOpen;
190
+ input.disabled = true;
191
+ const body = await api("/task", { session, id, action: "message", text });
192
+ input.disabled = false;
193
+ if (body.error) {
194
+ taskSheet.querySelector(".task-log").appendChild(el("div", "task-error", body.error));
195
+ return;
196
+ }
197
+ input.value = "";
198
+ input.focus();
199
+ if (taskOpen) taskOpen.stick = true;
200
+ void paintTask();
201
+ }
202
+
203
+ function taskElapsed(task) {
204
+ if (!task.startedAt) return "";
205
+ const seconds = Math.max(0, Math.round(((task.endedAt || Date.now()) - task.startedAt) / 1000));
206
+ return seconds < 60 ? seconds + "s" : Math.floor(seconds / 60) + "m" + (seconds % 60) + "s";
207
+ }
208
+
209
+ async function paintTask() {
210
+ if (!taskOpen || !taskSheet) return;
211
+ const { session, id } = taskOpen;
212
+ const seq = ++taskPaintSeq;
213
+ const body = await getJson("/task?session=" + encodeURIComponent(session) + "&id=" + encodeURIComponent(id));
214
+ if (!taskOpen || taskOpen.id !== id || taskOpen.session !== session || seq !== taskPaintSeq) return;
215
+ const log = taskSheet.querySelector(".task-log");
216
+ // Tool rows the reader opened stay open across a redraw: a running task
217
+ // redraws on every step, and an expanded result snapping shut is unreadable.
218
+ // Only for the task already on screen: another task's rows are other rows.
219
+ const opened = new Set();
220
+ if (taskSheet.dataset.painted === id) {
221
+ log.querySelectorAll(".task-tool").forEach((node, index) => { if (node.open) opened.add(index); });
222
+ }
223
+ taskSheet.dataset.painted = id;
224
+ if (body.error) {
225
+ log.replaceChildren(el("div", "task-error", body.error));
226
+ return;
227
+ }
228
+ const task = body.task;
229
+
230
+ taskSheet.querySelector(".task-title").textContent = task.description;
231
+ const meta = [t("tasks.status." + task.status), task.agentType, t("tasks.turns", { n: task.turns }), taskElapsed(task)];
232
+ if (task.activity) meta.push(task.activity);
233
+ taskSheet.querySelector(".task-meta").textContent = meta.filter(Boolean).join(" · ");
234
+ taskSheet.querySelector(".task-stop").hidden = !TASK_LIVE.has(task.status);
235
+
236
+ // Every task of this conversation, so a sheet opened on one reaches the rest.
237
+ // One row that scrolls sideways: rebuilt on every change, so it keeps
238
+ // where it was scrolled to, and brings the open task's chip into view.
239
+ const chips = taskSheet.querySelector(".task-chips");
240
+ const scrolled = chips.scrollLeft;
241
+ chips.replaceChildren();
242
+ const all = sortedTasks(pane(session).tasks);
243
+ chips.hidden = all.length < 2;
244
+ let current = null;
245
+ for (const other of all) {
246
+ const chip = el("button", "task-chip task-" + other.status + (other.id === id ? " on" : ""), other.description);
247
+ chip.type = "button";
248
+ chip.addEventListener("click", () => openTask(session, other.id));
249
+ chips.appendChild(chip);
250
+ if (other.id === id) current = chip;
251
+ }
252
+ chips.scrollLeft = scrolled;
253
+ if (current && (current.offsetLeft < chips.scrollLeft || current.offsetLeft + current.offsetWidth > chips.scrollLeft + chips.clientWidth)) {
254
+ chips.scrollLeft = current.offsetLeft - 16;
255
+ }
256
+
257
+ log.replaceChildren();
258
+ for (const entry of body.transcript || []) {
259
+ if (entry.role === "tool") {
260
+ const tool = el("details", "task-tool" + (entry.isError ? " err" : ""));
261
+ const summary = el("summary");
262
+ summary.appendChild(el("span", "task-tool-name", entry.name));
263
+ summary.appendChild(el("span", "task-tool-input", entry.text));
264
+ tool.appendChild(summary);
265
+ if (entry.result) tool.appendChild(el("pre", "task-tool-result", entry.result));
266
+ if (opened.has(log.querySelectorAll(".task-tool").length)) tool.open = true;
267
+ log.appendChild(tool);
268
+ } else if (entry.role === "assistant") {
269
+ const msg = el("div", "task-msg assistant");
270
+ msg.appendChild(renderMarkdown(entry.text));
271
+ log.appendChild(msg);
272
+ } else {
273
+ log.appendChild(el("div", "task-msg user", entry.text));
274
+ }
275
+ }
276
+ if (!log.childElementCount) log.appendChild(el("div", "task-empty", t("tasks.empty")));
277
+ if (task.worktree) log.appendChild(el("div", "task-note", task.worktree));
278
+ if (task.error) log.appendChild(el("div", "task-error", task.error));
279
+ if (TASK_LIVE.has(task.status)) {
280
+ const working = el("div", "task-working");
281
+ working.appendChild(el("span", "spinner"));
282
+ log.appendChild(working);
283
+ }
284
+ if (taskOpen.stick) log.scrollTop = log.scrollHeight;
285
+
286
+ const input = taskSheet.querySelector(".task-input");
287
+ const stopped = task.status === "cancelled";
288
+ input.disabled = stopped;
289
+ taskSheet.querySelector(".task-send").disabled = stopped;
290
+ input.placeholder = t(stopped ? "tasks.placeholder.stopped" : TASK_LIVE.has(task.status) ? "tasks.placeholder.running" : "tasks.placeholder.ended");
291
+ }
292
+ `;
293
+ //# sourceMappingURL=tasks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tasks.js","sourceRoot":"","sources":["../../../src/page/client/tasks.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4R9B,CAAC"}
@@ -84,7 +84,7 @@ function terminalActive() {
84
84
  * Asked again for the project already on show it hides, which is what the
85
85
  * tab's button wants; force keeps it open, for the menus.
86
86
  */
87
- async function openTerminalIn(cwd, force) {
87
+ async function openTerminalIn(cwd, force, opts) {
88
88
  if (!cwd) return;
89
89
  if (terminalShownFor(cwd) && !force) return hideTerminal();
90
90
  track("panel_opened", { panel: "terminal" });
@@ -115,12 +115,28 @@ async function openTerminalIn(cwd, force) {
115
115
  const entry = terminalCreate(lib, cwd);
116
116
  void terminalAttach(entry, found, true);
117
117
  }
118
- if (!group.tabs.length) await terminalNew(cwd);
119
- else group.active = group.tabs[group.tabs.length - 1];
120
- } else if (!group.tabs.length) {
118
+ if (!group.tabs.length && !(opts && opts.bare)) await terminalNew(cwd);
119
+ else if (group.tabs.length) group.active = group.tabs[group.tabs.length - 1];
120
+ } else if (!group.tabs.length && !(opts && opts.bare)) {
121
121
  await terminalNew(cwd);
122
122
  }
123
- if (terminalCwd === cwd) terminalSelect(group.active);
123
+ if (terminalCwd === cwd && group.active) terminalSelect(group.active);
124
+ }
125
+
126
+ /**
127
+ * Hand the project to Claude Code: a new terminal tab running the user's own
128
+ * claude, signed in however they signed it in. OHarness starts it and stays
129
+ * out of the way — no login of ours, no token read — which is what keeps a
130
+ * Claude plan usable from here at all.
131
+ */
132
+ async function openClaudeCode(cwd, resume) {
133
+ if (!cwd) return;
134
+ track("panel_opened", { panel: "claude-code" });
135
+ // bare: the panel without the plain shell it would otherwise start, since
136
+ // the tab being opened is the one that was asked for.
137
+ await openTerminalIn(cwd, true, { bare: true });
138
+ // resume: a session an @claude reply ran in, opened in Claude Code itself.
139
+ if (terminalCwd === cwd) await terminalNew(cwd, "claude", resume);
124
140
  }
125
141
 
126
142
  function hideTerminal() {
@@ -135,9 +151,13 @@ function terminalFollow(cwd) {
135
151
  }
136
152
 
137
153
  /** Another shell in the project on show, as a new tab in front. */
138
- async function terminalNew(cwd) {
154
+ async function terminalNew(cwd, run, resume) {
139
155
  const lib = await loadTerminalLib();
140
156
  const entry = terminalCreate(lib, cwd);
157
+ // Only the first shell runs it: a tab restarted by typing after an exit is
158
+ // an ordinary shell, not a second Claude Code the user did not ask for.
159
+ if (run) entry.run = run;
160
+ if (run && resume) entry.resume = resume;
141
161
  terminalGroup(cwd).active = entry;
142
162
  terminalSelect(entry);
143
163
  await terminalStart(entry);
@@ -266,8 +286,15 @@ async function terminalStart(entry) {
266
286
  entry.id = null;
267
287
  if (replace) entry.term.reset();
268
288
  terminalFit(entry);
289
+ const run = entry.run;
290
+ const resume = entry.resume;
291
+ entry.run = undefined;
292
+ entry.resume = undefined;
269
293
  const body = await api("/term/open", {
270
- cwd: entry.cwd, cols: entry.term.cols, rows: entry.term.rows, ...(replace ? { replace } : {}),
294
+ cwd: entry.cwd, cols: entry.term.cols, rows: entry.term.rows,
295
+ ...(replace ? { replace } : {}),
296
+ ...(run ? { run } : {}),
297
+ ...(resume ? { resume } : {}),
271
298
  });
272
299
  entry.starting = false;
273
300
  if (!body || body.error) {
@@ -1 +1 @@
1
- {"version":3,"file":"terminal.js","sourceRoot":"","sources":["../../../src/page/client/terminal.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmVjC,CAAC"}
1
+ {"version":3,"file":"terminal.js","sourceRoot":"","sources":["../../../src/page/client/terminal.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8WjC,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Themes the agent proposes, and the one in use.
3
+ *
4
+ * A proposal arrives as a card in the conversation that asked for it. Nothing
5
+ * changes until the person acts on the card: Preview tries it on this page
6
+ * only, Apply makes it the theme everywhere, Discard drops it. The applied
7
+ * theme is printed into the page by the server and replaced here when another
8
+ * window changes it.
9
+ *
10
+ * Safe mode is the way out of a theme that made the page unreadable, so it is
11
+ * the one thing here that needs no theme, no card and no conversation: the
12
+ * page loaded with ?theme=default, or the shortcut below, and custom colours
13
+ * are off in this window until it is pressed again.
14
+ *
15
+ * One part of the client script; see ./index.ts for how the parts join.
16
+ */
17
+ export declare const THEME: string;