@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.
- package/dist/analytics.d.ts +32 -29
- package/dist/analytics.js +225 -278
- package/dist/analytics.js.map +1 -1
- package/dist/i18n.js +500 -64
- package/dist/i18n.js.map +1 -1
- package/dist/icons.js +1 -0
- package/dist/icons.js.map +1 -1
- package/dist/main.js +4 -0
- package/dist/main.js.map +1 -1
- package/dist/model-order.js +1 -0
- package/dist/model-order.js.map +1 -1
- package/dist/page/client/account.js +570 -27
- package/dist/page/client/account.js.map +1 -1
- package/dist/page/client/base.js +55 -12
- package/dist/page/client/base.js.map +1 -1
- package/dist/page/client/browser.js +1 -1
- package/dist/page/client/composer.js +802 -59
- package/dist/page/client/composer.js.map +1 -1
- package/dist/page/client/computer.d.ts +27 -0
- package/dist/page/client/computer.js +358 -0
- package/dist/page/client/computer.js.map +1 -0
- package/dist/page/client/dialogs.js +168 -6
- package/dist/page/client/dialogs.js.map +1 -1
- package/dist/page/client/events.js +119 -9
- package/dist/page/client/events.js.map +1 -1
- package/dist/page/client/files.js +86 -1
- package/dist/page/client/files.js.map +1 -1
- package/dist/page/client/index.js +8 -0
- package/dist/page/client/index.js.map +1 -1
- package/dist/page/client/panels.js +14 -10
- package/dist/page/client/panels.js.map +1 -1
- package/dist/page/client/ripple.d.ts +13 -0
- package/dist/page/client/ripple.js +247 -0
- package/dist/page/client/ripple.js.map +1 -0
- package/dist/page/client/routines.js +432 -45
- package/dist/page/client/routines.js.map +1 -1
- package/dist/page/client/shell.js +386 -104
- package/dist/page/client/shell.js.map +1 -1
- package/dist/page/client/state.js +278 -19
- package/dist/page/client/state.js.map +1 -1
- package/dist/page/client/tasks.d.ts +8 -0
- package/dist/page/client/tasks.js +293 -0
- package/dist/page/client/tasks.js.map +1 -0
- package/dist/page/client/terminal.js +34 -7
- package/dist/page/client/terminal.js.map +1 -1
- package/dist/page/client/theme.d.ts +17 -0
- package/dist/page/client/theme.js +365 -0
- package/dist/page/client/theme.js.map +1 -0
- package/dist/page/client/transcript.js +196 -8
- package/dist/page/client/transcript.js.map +1 -1
- package/dist/page/client/usage.js +1 -11
- package/dist/page/client/usage.js.map +1 -1
- package/dist/page/style.js +745 -76
- package/dist/page/style.js.map +1 -1
- package/dist/page.js +94 -16
- package/dist/page.js.map +1 -1
- package/dist/prefs.d.ts +31 -0
- package/dist/prefs.js +13 -1
- package/dist/prefs.js.map +1 -1
- package/dist/remote-crypto.d.ts +78 -0
- package/dist/remote-crypto.js +216 -0
- package/dist/remote-crypto.js.map +1 -0
- package/dist/remote.d.ts +103 -0
- package/dist/remote.js +498 -0
- package/dist/remote.js.map +1 -0
- package/dist/server.d.ts +70 -0
- package/dist/server.js +1738 -73
- package/dist/server.js.map +1 -1
- package/dist/starters.d.ts +92 -0
- package/dist/starters.js +213 -0
- package/dist/starters.js.map +1 -0
- package/dist/suggest.d.ts +42 -0
- package/dist/suggest.js +215 -0
- package/dist/suggest.js.map +1 -0
- package/dist/terminal.d.ts +28 -2
- package/dist/terminal.js +45 -3
- package/dist/terminal.js.map +1 -1
- package/dist/theme-assets.d.ts +39 -0
- package/dist/theme-assets.js +109 -0
- package/dist/theme-assets.js.map +1 -0
- package/dist/theme-store.d.ts +50 -0
- package/dist/theme-store.js +124 -0
- package/dist/theme-store.js.map +1 -0
- package/dist/theme-tools.d.ts +25 -0
- package/dist/theme-tools.js +243 -0
- package/dist/theme-tools.js.map +1 -0
- package/dist/turn-shots.d.ts +43 -0
- package/dist/turn-shots.js +80 -0
- package/dist/turn-shots.js.map +1 -0
- package/dist/user-theme.d.ts +143 -0
- package/dist/user-theme.js +510 -0
- package/dist/user-theme.js.map +1 -0
- package/package.json +2 -2
|
@@ -7,6 +7,51 @@
|
|
|
7
7
|
export const EVENTS = String.raw `
|
|
8
8
|
// --- events ---------------------------------------------------------------
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Streamed text, revealed at a steady pace rather than as it arrives.
|
|
12
|
+
*
|
|
13
|
+
* Models send text in pieces of very different sizes: measured through the
|
|
14
|
+
* official plan, GPT-5.6 Sol came as ~5 characters a piece, many to the same
|
|
15
|
+
* millisecond, and Claude Opus 5.5 as four pieces of ~260 characters some
|
|
16
|
+
* 280ms apart. Drawn as received, a reply lurched a sentence at a time. Each
|
|
17
|
+
* frame now shows a share of what is still waiting — a tenth of it, at least
|
|
18
|
+
* two characters — so a large piece unrolls over a few hundred milliseconds
|
|
19
|
+
* and a trickle is shown as it comes. Nothing is held back for long: the
|
|
20
|
+
* backlog is never more than a fraction of a second behind.
|
|
21
|
+
*
|
|
22
|
+
* A stream the pane has finished with (P.streaming cleared) still runs to the
|
|
23
|
+
* end of its text here; it only ever shows what it was sent.
|
|
24
|
+
*/
|
|
25
|
+
const streamsRevealing = new Set();
|
|
26
|
+
let streamFrame = 0;
|
|
27
|
+
|
|
28
|
+
function revealStream(stream) {
|
|
29
|
+
streamsRevealing.add(stream);
|
|
30
|
+
if (!streamFrame) streamFrame = requestAnimationFrame(revealStreams);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function revealStreams() {
|
|
34
|
+
streamFrame = 0;
|
|
35
|
+
for (const stream of streamsRevealing) {
|
|
36
|
+
const waiting = stream.text.length - stream.shown;
|
|
37
|
+
if (waiting <= 0) {
|
|
38
|
+
streamsRevealing.delete(stream);
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
let next = Math.min(stream.text.length, stream.shown + Math.max(2, Math.ceil(waiting / 10)));
|
|
42
|
+
// Never between the halves of a surrogate pair: an emoji cut in two draws
|
|
43
|
+
// as a box for a frame.
|
|
44
|
+
const code = stream.text.charCodeAt(next - 1);
|
|
45
|
+
if (code >= 0xd800 && code <= 0xdbff && next < stream.text.length) next++;
|
|
46
|
+
stream.shown = next;
|
|
47
|
+
// The whole block again: markdown is not incremental, and a half fence
|
|
48
|
+
// rendered as literal text then rewritten looks worse than this.
|
|
49
|
+
stream.node.replaceChildren(renderMarkdown(stream.text.slice(0, next)));
|
|
50
|
+
}
|
|
51
|
+
follow();
|
|
52
|
+
if (streamsRevealing.size) streamFrame = requestAnimationFrame(revealStreams);
|
|
53
|
+
}
|
|
54
|
+
|
|
10
55
|
const events = new EventSource(q("/events"));
|
|
11
56
|
events.onerror = () => { ctxText.textContent = "offline"; };
|
|
12
57
|
events.onmessage = (message) => {
|
|
@@ -29,6 +74,8 @@ events.onmessage = (message) => {
|
|
|
29
74
|
// been written yet, so there is nothing at /attachment to ask for.
|
|
30
75
|
const sent = sentPreviews.get(event.session) || [];
|
|
31
76
|
sentPreviews.delete(event.session);
|
|
77
|
+
P.suggestion = null;
|
|
78
|
+
if (event.session === activeId) paintSuggestion();
|
|
32
79
|
addUser(event.text || "", sent);
|
|
33
80
|
startWorking(t("work.thinking"));
|
|
34
81
|
const unshown = (event.attachments || []).filter(
|
|
@@ -44,15 +91,27 @@ events.onmessage = (message) => {
|
|
|
44
91
|
break;
|
|
45
92
|
}
|
|
46
93
|
|
|
94
|
+
// Background tasks ended and their results were just read in. When that
|
|
95
|
+
// is what started the turn — nobody typed anything — this is also the
|
|
96
|
+
// only sign the conversation is working again.
|
|
97
|
+
// A background task started, moved on or ended.
|
|
98
|
+
case "tasks": tasksChanged(event.session, event.tasks); break;
|
|
99
|
+
case "task_notification":
|
|
100
|
+
P.turn = null;
|
|
101
|
+
taskCard(event.tasks || []);
|
|
102
|
+
if (!P.busy) {
|
|
103
|
+
startWorking(t("work.thinking"));
|
|
104
|
+
setBusy(true);
|
|
105
|
+
}
|
|
106
|
+
break;
|
|
107
|
+
|
|
47
108
|
case "text_delta":
|
|
48
109
|
sealThinking();
|
|
49
110
|
stopWorking();
|
|
50
|
-
if (!P.streaming) { P.streaming = { text: "", node: el("div") }; assistantTurn().appendChild(P.streaming.node); }
|
|
111
|
+
if (!P.streaming) { P.streaming = { text: "", shown: 0, node: el("div") }; assistantTurn().appendChild(P.streaming.node); }
|
|
51
112
|
P.streaming.text += event.text;
|
|
52
|
-
//
|
|
53
|
-
|
|
54
|
-
P.streaming.node.replaceChildren(renderMarkdown(P.streaming.text));
|
|
55
|
-
follow();
|
|
113
|
+
// Not drawn here: revealed at a steady pace by revealStreams.
|
|
114
|
+
revealStream(P.streaming);
|
|
56
115
|
break;
|
|
57
116
|
|
|
58
117
|
case "thinking_delta": {
|
|
@@ -87,7 +146,21 @@ events.onmessage = (message) => {
|
|
|
87
146
|
renderQueued();
|
|
88
147
|
break;
|
|
89
148
|
|
|
90
|
-
case "assistant_message":
|
|
149
|
+
case "assistant_message": {
|
|
150
|
+
P.streaming = null;
|
|
151
|
+
const meta = event.message && event.message.meta;
|
|
152
|
+
if (meta && typeof meta.agent === "string") {
|
|
153
|
+
const session = meta.acpSession || {};
|
|
154
|
+
agentReply(P.turn, { name: meta.agent, session: session.id, cwd: session.cwd });
|
|
155
|
+
}
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
// After the turn ended: under its last reply, not a new turn of its own.
|
|
159
|
+
case "turn_shots": {
|
|
160
|
+
const replies = P.node.querySelectorAll(":scope > .turn.assistant");
|
|
161
|
+
turnShots(replies[replies.length - 1], event.shots);
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
91
164
|
case "turn_start": dropPendingTools(); break;
|
|
92
165
|
// A session named from its first prompt, or renamed: the tab and the
|
|
93
166
|
// sidebar row both carry the name.
|
|
@@ -162,7 +235,14 @@ events.onmessage = (message) => {
|
|
|
162
235
|
}
|
|
163
236
|
|
|
164
237
|
case "permission_request": showAsk(event); break;
|
|
238
|
+
case "remote_pair_request": showPairing(event); break;
|
|
239
|
+
case "remote_pair_closed": closePairing(event.id); break;
|
|
165
240
|
case "question_request": questionCard(event); break;
|
|
241
|
+
// A theme proposed by set_theme, and what became of it; then the theme in
|
|
242
|
+
// use, from this window or another.
|
|
243
|
+
case "theme_preview": themePreviewCard(event.preview); break;
|
|
244
|
+
case "theme_preview_closed": closeThemePreview(event.id, event.outcome); break;
|
|
245
|
+
case "theme": setThemeState(event.state); break;
|
|
166
246
|
case "question_result": settleQuestion(event); break;
|
|
167
247
|
// Sent once per (re)connect, after the replay: a card this page still
|
|
168
248
|
// shows as open but the server no longer holds closed while we were away.
|
|
@@ -177,7 +257,10 @@ events.onmessage = (message) => {
|
|
|
177
257
|
closeQuestion(event.id);
|
|
178
258
|
break;
|
|
179
259
|
case "permission_result":
|
|
180
|
-
|
|
260
|
+
// Plan mode holding a step back is the mode working, not something
|
|
261
|
+
// going wrong: said plainly, and not in the colour of an error.
|
|
262
|
+
if (!event.allowed && event.plan) addNotice(t("plan.held"), "notice");
|
|
263
|
+
else if (!event.allowed) addNotice("denied: " + (event.reason || ""), "err");
|
|
181
264
|
else if (event.remembered) addNotice("remembered: " + event.remembered);
|
|
182
265
|
break;
|
|
183
266
|
|
|
@@ -200,6 +283,18 @@ events.onmessage = (message) => {
|
|
|
200
283
|
void loadSessions();
|
|
201
284
|
if (shownPanel === "nav-routines") void showRoutines();
|
|
202
285
|
break;
|
|
286
|
+
// A worktree came or went: which session directories nest under which
|
|
287
|
+
// project is part of the project list.
|
|
288
|
+
case "projects":
|
|
289
|
+
void loadProjects();
|
|
290
|
+
break;
|
|
291
|
+
// A routine run started or ended, here or from the clock.
|
|
292
|
+
case "routines":
|
|
293
|
+
if (shownPanel === "nav-routines") void showRoutines();
|
|
294
|
+
break;
|
|
295
|
+
case "routine_activity":
|
|
296
|
+
if (shownPanel === "nav-routines") paintRoutineActivity(event);
|
|
297
|
+
break;
|
|
203
298
|
case "error":
|
|
204
299
|
P.streaming = null;
|
|
205
300
|
// A 402 is not an error to print, it is a screen to open. What the
|
|
@@ -242,13 +337,28 @@ events.onmessage = (message) => {
|
|
|
242
337
|
}
|
|
243
338
|
case "idle":
|
|
244
339
|
applyState(event.state);
|
|
245
|
-
|
|
340
|
+
// The bar above the transcript is the tab on screen's; a turn ending in
|
|
341
|
+
// a background tab (a worktree session, a second conversation) must not
|
|
342
|
+
// put its files there.
|
|
343
|
+
if (!event.session || event.session === activeId) renderChanges(event.changes);
|
|
246
344
|
void loadSessions();
|
|
247
345
|
break;
|
|
248
346
|
case "state": applyState(event.state); break;
|
|
347
|
+
case "suggestion":
|
|
348
|
+
P.suggestion = event.text;
|
|
349
|
+
if (event.session === activeId) paintSuggestion();
|
|
350
|
+
break;
|
|
351
|
+
case "suggestions":
|
|
352
|
+
if (!event.enabled) for (const entry of panes.values()) entry.suggestion = null;
|
|
353
|
+
paintSuggestion();
|
|
354
|
+
break;
|
|
355
|
+
// What a conversation is doing on the computer, for the live view.
|
|
356
|
+
case "computer": computerEvent(event.session, event.event); break;
|
|
357
|
+
// The project's starters, written in the background after the fixed three.
|
|
358
|
+
case "starters": startersArrived(event); break;
|
|
249
359
|
case "connectors_changed":
|
|
250
360
|
if (authorizing === event.connector) authorizing = null;
|
|
251
|
-
offer = { connectors: event.connectors, plugins: event.plugins || [], skills: event.skills || [] };
|
|
361
|
+
offer = { connectors: event.connectors, plugins: event.plugins || [], skills: event.skills || [], agents: event.agents || offer.agents || [] };
|
|
252
362
|
// The failure already said what went wrong; this only announces the
|
|
253
363
|
// half that is worth celebrating.
|
|
254
364
|
if (event.authorized) addNotice(t("market.authorized", { name: event.connector }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../../src/page/client/events.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAA
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../../src/page/client/events.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsY/B,CAAC"}
|
|
@@ -15,6 +15,7 @@ const explorer = document.getElementById("explorer");
|
|
|
15
15
|
const explorerTitle = document.getElementById("explorer-title");
|
|
16
16
|
const explorerTree = document.getElementById("explorer-tree");
|
|
17
17
|
const explorerView = document.getElementById("explorer-view");
|
|
18
|
+
const explorerQuery = document.getElementById("explorer-q");
|
|
18
19
|
|
|
19
20
|
/** The project folder on show, absolute; null while the pane has never opened. */
|
|
20
21
|
let explorerCwd = null;
|
|
@@ -65,6 +66,8 @@ async function openExplorer(cwd, force) {
|
|
|
65
66
|
explorerChildren = new Map();
|
|
66
67
|
explorerSelected = null;
|
|
67
68
|
explorerSource = false;
|
|
69
|
+
explorerQuery.value = "";
|
|
70
|
+
explorerHits = null;
|
|
68
71
|
}
|
|
69
72
|
explorerTitle.textContent = projectName(cwd);
|
|
70
73
|
explorerTitle.title = cwd;
|
|
@@ -96,6 +99,7 @@ async function explorerLoad() {
|
|
|
96
99
|
else explorerChildren.set(dir, body.entries || []);
|
|
97
100
|
});
|
|
98
101
|
paintExplorerTree();
|
|
102
|
+
if (explorerQuery.value.trim()) void explorerSearch();
|
|
99
103
|
if (explorerSelected) await explorerShow(explorerSelected);
|
|
100
104
|
else explorerView.replaceChildren(el("p", "muted explorer-hint", t("files.pick")));
|
|
101
105
|
}
|
|
@@ -125,6 +129,7 @@ async function explorerToggleDir(dir) {
|
|
|
125
129
|
}
|
|
126
130
|
|
|
127
131
|
function paintExplorerTree() {
|
|
132
|
+
if (explorerHits) return paintExplorerHits();
|
|
128
133
|
const scroll = explorerTree.scrollTop;
|
|
129
134
|
explorerTree.replaceChildren();
|
|
130
135
|
const root = explorerChildren.get("") || [];
|
|
@@ -285,6 +290,86 @@ function tabProjectButtons(id, cwd) {
|
|
|
285
290
|
return [files, term];
|
|
286
291
|
}
|
|
287
292
|
|
|
293
|
+
// --- searching the tree ------------------------------------------------------
|
|
294
|
+
// A name typed here is looked for through the whole project, not only the
|
|
295
|
+
// folders unfolded; while there is one, the matches stand in for the tree and
|
|
296
|
+
// clearing it brings the tree back exactly as it was.
|
|
297
|
+
|
|
298
|
+
/** The matches on show, or null while the tree is. */
|
|
299
|
+
let explorerHits = null;
|
|
300
|
+
let explorerSearchTimer = 0;
|
|
301
|
+
let explorerSearchSeq = 0;
|
|
302
|
+
|
|
303
|
+
async function explorerSearch() {
|
|
304
|
+
const query = explorerQuery.value.trim();
|
|
305
|
+
const seq = ++explorerSearchSeq;
|
|
306
|
+
if (!query) {
|
|
307
|
+
explorerHits = null;
|
|
308
|
+
return paintExplorerTree();
|
|
309
|
+
}
|
|
310
|
+
const cwd = explorerCwd;
|
|
311
|
+
const body = await getJson("/files/search?cwd=" + encodeURIComponent(cwd) + "&q=" + encodeURIComponent(query));
|
|
312
|
+
if (seq !== explorerSearchSeq || cwd !== explorerCwd) return;
|
|
313
|
+
explorerHits = body.error ? [] : (body.entries || []);
|
|
314
|
+
explorerTree.scrollTop = 0;
|
|
315
|
+
paintExplorerTree();
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function paintExplorerHits() {
|
|
319
|
+
explorerTree.replaceChildren();
|
|
320
|
+
if (!explorerHits.length) return void explorerTree.appendChild(el("p", "muted explorer-hint", t("files.noMatch")));
|
|
321
|
+
for (const entry of explorerHits) {
|
|
322
|
+
const row = el("button", "explorer-row" + (entry.path === explorerSelected ? " on" : ""));
|
|
323
|
+
row.type = "button";
|
|
324
|
+
row.setAttribute("role", "treeitem");
|
|
325
|
+
row.title = entry.path;
|
|
326
|
+
row.appendChild(svgIcon(entry.dir ? "folder" : "file"));
|
|
327
|
+
row.appendChild(el("span", "explorer-name", entry.name));
|
|
328
|
+
const parent = entry.path.slice(0, Math.max(0, entry.path.length - entry.name.length - 1));
|
|
329
|
+
if (parent) row.appendChild(el("span", "explorer-dir", parent));
|
|
330
|
+
row.addEventListener("click", () => void (entry.dir ? explorerReveal(entry.path) : explorerShow(entry.path)));
|
|
331
|
+
explorerTree.appendChild(row);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/** A folder picked from the matches: back to the tree, unfolded down to it. */
|
|
336
|
+
async function explorerReveal(dir) {
|
|
337
|
+
const parts = dir.split("/");
|
|
338
|
+
const dirs = explorerDirs();
|
|
339
|
+
for (let i = 1; i <= parts.length; i++) {
|
|
340
|
+
const at = parts.slice(0, i).join("/");
|
|
341
|
+
dirs.add(at);
|
|
342
|
+
if (!explorerChildren.has(at)) {
|
|
343
|
+
const body = await explorerFetch(at);
|
|
344
|
+
if (body.error) { dirs.delete(at); break; }
|
|
345
|
+
explorerChildren.set(at, body.entries || []);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
explorerQuery.value = "";
|
|
349
|
+
explorerHits = null;
|
|
350
|
+
explorerSearchSeq++;
|
|
351
|
+
paintExplorerTree();
|
|
352
|
+
const row = [...explorerTree.children].find((node) => node.title === dir);
|
|
353
|
+
if (row) row.scrollIntoView({ block: "nearest" });
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
explorerQuery.addEventListener("input", () => {
|
|
357
|
+
clearTimeout(explorerSearchTimer);
|
|
358
|
+
explorerSearchTimer = setTimeout(() => void explorerSearch(), 120);
|
|
359
|
+
});
|
|
360
|
+
explorerQuery.addEventListener("keydown", (event) => {
|
|
361
|
+
if (event.key === "Escape" && explorerQuery.value) {
|
|
362
|
+
event.preventDefault();
|
|
363
|
+
event.stopPropagation();
|
|
364
|
+
explorerQuery.value = "";
|
|
365
|
+
void explorerSearch();
|
|
366
|
+
} else if (event.key === "Enter" && explorerHits && explorerHits.length) {
|
|
367
|
+
event.preventDefault();
|
|
368
|
+
const first = explorerHits[0];
|
|
369
|
+
void (first.dir ? explorerReveal(first.path) : explorerShow(first.path));
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
|
|
288
373
|
document.getElementById("explorer-close").addEventListener("click", closeExplorer);
|
|
289
374
|
document.getElementById("explorer-refresh").addEventListener("click", () => void explorerLoad());
|
|
290
375
|
document.getElementById("explorer-terminal").addEventListener("click", () => void openTerminalIn(explorerCwd, true));
|
|
@@ -398,7 +483,7 @@ let explorerTreeDragged;
|
|
|
398
483
|
dragHandle(explorerSplit, {
|
|
399
484
|
get axis() { return isPhone() ? "y" : "x"; },
|
|
400
485
|
start: () => {
|
|
401
|
-
const rect =
|
|
486
|
+
const rect = document.getElementById("explorer-side").getBoundingClientRect();
|
|
402
487
|
return isPhone() ? rect.height : rect.width;
|
|
403
488
|
},
|
|
404
489
|
move: (dx, dy, start) => { explorerTreeDragged = explorerSetTree(start + (isPhone() ? dy : dx)); },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"files.js","sourceRoot":"","sources":["../../../src/page/client/files.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAA
|
|
1
|
+
{"version":3,"file":"files.js","sourceRoot":"","sources":["../../../src/page/client/files.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAye9B,CAAC"}
|
|
@@ -5,15 +5,19 @@ import { STATE } from "./state.js";
|
|
|
5
5
|
import { EVENTS } from "./events.js";
|
|
6
6
|
import { DIALOGS } from "./dialogs.js";
|
|
7
7
|
import { COMPOSER } from "./composer.js";
|
|
8
|
+
import { TASKS } from "./tasks.js";
|
|
8
9
|
import { ARTIFACTS } from "./artifacts.js";
|
|
9
10
|
import { ACCOUNT } from "./account.js";
|
|
10
11
|
import { ROUTINES } from "./routines.js";
|
|
11
12
|
import { USAGE } from "./usage.js";
|
|
12
13
|
import { PANELS } from "./panels.js";
|
|
13
14
|
import { BROWSER } from "./browser.js";
|
|
15
|
+
import { COMPUTER } from "./computer.js";
|
|
14
16
|
import { FILES } from "./files.js";
|
|
15
17
|
import { TERMINAL } from "./terminal.js";
|
|
16
18
|
import { SHELL } from "./shell.js";
|
|
19
|
+
import { RIPPLE } from "./ripple.js";
|
|
20
|
+
import { THEME } from "./theme.js";
|
|
17
21
|
/**
|
|
18
22
|
* The client script, assembled.
|
|
19
23
|
*
|
|
@@ -37,6 +41,7 @@ export const APP_SCRIPT = [
|
|
|
37
41
|
EVENTS,
|
|
38
42
|
DIALOGS,
|
|
39
43
|
COMPOSER,
|
|
44
|
+
TASKS,
|
|
40
45
|
ARTIFACTS,
|
|
41
46
|
ACCOUNT,
|
|
42
47
|
ROUTINES,
|
|
@@ -45,6 +50,9 @@ export const APP_SCRIPT = [
|
|
|
45
50
|
FILES,
|
|
46
51
|
TERMINAL,
|
|
47
52
|
BROWSER,
|
|
53
|
+
COMPUTER,
|
|
48
54
|
SHELL,
|
|
55
|
+
RIPPLE,
|
|
56
|
+
THEME,
|
|
49
57
|
].join("") + "\n";
|
|
50
58
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/page/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,UAAU,GACrB;IACA,IAAI;IACJ,OAAO;IACP,UAAU;IACV,KAAK;IACL,MAAM;IACN,OAAO;IACP,QAAQ;IACR,SAAS;IACT,OAAO;IACP,QAAQ;IACR,KAAK;IACL,MAAM;IACN,KAAK;IACL,QAAQ;IACR,OAAO;IACP,KAAK;CACJ,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/page/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,UAAU,GACrB;IACA,IAAI;IACJ,OAAO;IACP,UAAU;IACV,KAAK;IACL,MAAM;IACN,OAAO;IACP,QAAQ;IACR,KAAK;IACL,SAAS;IACT,OAAO;IACP,QAAQ;IACR,KAAK;IACL,MAAM;IACN,KAAK;IACL,QAAQ;IACR,OAAO;IACP,QAAQ;IACR,KAAK;IACL,MAAM;IACN,KAAK;CACJ,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC"}
|
|
@@ -168,7 +168,7 @@ async function refreshRoutineCount() {
|
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
/** Sidebar entries that open a view of their own rather than a conversation. */
|
|
171
|
-
const PANEL_NAV = new Set(["nav-artifacts", "nav-sessions", "nav-models", "nav-routines", "nav-settings"]);
|
|
171
|
+
const PANEL_NAV = new Set(["nav-artifacts", "nav-sessions", "nav-usage", "nav-models", "nav-routines", "nav-settings"]);
|
|
172
172
|
const pluginPages = new Map();
|
|
173
173
|
async function refreshPluginPages() {
|
|
174
174
|
const session = activeId;
|
|
@@ -384,7 +384,7 @@ async function showMemoryPage(id) {
|
|
|
384
384
|
form.appendChild(mergeActions);
|
|
385
385
|
form.onsubmit = async (event) => {
|
|
386
386
|
event.preventDefault();
|
|
387
|
-
if (!
|
|
387
|
+
if (!(await askConfirm({ body: t("memory.mergeConfirm"), ok: t("memory.mergeApply") }))) return;
|
|
388
388
|
apply.disabled = true;
|
|
389
389
|
await act({ action: "merge", note: { summary: summary.value.trim(), body: body.value.trim(), tags: tags.value.split(/[,,\s]+/).filter(Boolean), type: proposal.draft.type || "" } });
|
|
390
390
|
apply.disabled = false;
|
|
@@ -563,9 +563,9 @@ async function showMemoryPage(id) {
|
|
|
563
563
|
row.appendChild(line);
|
|
564
564
|
}
|
|
565
565
|
const remove = el("button", "ghost", t("memory.delete")); remove.type = "button";
|
|
566
|
-
remove.onclick = () => {
|
|
566
|
+
remove.onclick = async () => {
|
|
567
567
|
const linked = links.in.length ? t("memory.confirmDeleteLinked", { count: links.in.length }) : "";
|
|
568
|
-
if (
|
|
568
|
+
if (await askConfirm({ body: linked + t("memory.confirmDelete"), ok: t("memory.delete"), danger: true })) void act({ action: "delete", scope: note.scope, id: note.id, expectedHash: note.hash });
|
|
569
569
|
};
|
|
570
570
|
row.appendChild(editor(note, remove));
|
|
571
571
|
list.appendChild(row);
|
|
@@ -588,7 +588,7 @@ async function showMemoryPage(id) {
|
|
|
588
588
|
text.appendChild(el("div", "muted small", [new Date(backup.backedUpAt).toLocaleString(LOCALE), backup.reason ? t("memory.backupReason." + backup.reason) : "", scopeLabel, backup.id].filter(Boolean).join(" · ")));
|
|
589
589
|
row.appendChild(text);
|
|
590
590
|
const restore = el("button", "ghost", t("memory.restore")); restore.type = "button";
|
|
591
|
-
restore.onclick = () => { if (
|
|
591
|
+
restore.onclick = async () => { if (await askConfirm({ body: t("memory.confirmRestore"), ok: t("memory.restore") })) void act({ action: "restore", file: backup.file }); };
|
|
592
592
|
row.appendChild(restore);
|
|
593
593
|
backups.appendChild(row);
|
|
594
594
|
}
|
|
@@ -599,12 +599,12 @@ async function showMemoryPage(id) {
|
|
|
599
599
|
* Panels reached from a row inside another panel rather than from the sidebar.
|
|
600
600
|
*
|
|
601
601
|
* A full page, drawn where Models and Routines are drawn, but without a
|
|
602
|
-
* permanent destination in the sidebar
|
|
603
|
-
*
|
|
604
|
-
*
|
|
605
|
-
*
|
|
602
|
+
* permanent destination in the sidebar. It keeps the row it came from lit, so
|
|
603
|
+
* the sidebar still says where in the app this is. Usage is the exception that
|
|
604
|
+
* has a row of its own on the rail as well as Settings', and lights that one
|
|
605
|
+
* whichever way it was reached.
|
|
606
606
|
*/
|
|
607
|
-
const SUB_PANELS = { usage: "nav-
|
|
607
|
+
const SUB_PANELS = { usage: "nav-usage", audit: "nav-settings", permissions: "nav-settings" };
|
|
608
608
|
|
|
609
609
|
/** Which panel the panel view is currently showing, sub-panels included. */
|
|
610
610
|
let shownPanel = null;
|
|
@@ -652,6 +652,10 @@ document.getElementById("nav-sessions").addEventListener("click", () => {
|
|
|
652
652
|
setNav("nav-sessions");
|
|
653
653
|
void showUsageSessions();
|
|
654
654
|
});
|
|
655
|
+
document.getElementById("nav-usage").addEventListener("click", () => {
|
|
656
|
+
setNav("usage");
|
|
657
|
+
void showUsage();
|
|
658
|
+
});
|
|
655
659
|
document.getElementById("nav-routines").addEventListener("click", () => {
|
|
656
660
|
setNav("nav-routines");
|
|
657
661
|
void showRoutines();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"panels.js","sourceRoot":"","sources":["../../../src/page/client/panels.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAA
|
|
1
|
+
{"version":3,"file":"panels.js","sourceRoot":"","sources":["../../../src/page/client/panels.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqpB/B,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The field behind a new session: a grid of dots a click sends a shockwave
|
|
3
|
+
* through.
|
|
4
|
+
*
|
|
5
|
+
* Only while the empty state is on screen. The canvas sits under everything
|
|
6
|
+
* in #main and takes no pointer, so it can never eat a click meant for the
|
|
7
|
+
* composer or a starter; it only hears them go by. Nothing animates at rest —
|
|
8
|
+
* a frame is drawn when a wave is travelling or the pointer moves, and the
|
|
9
|
+
* loop stops once the last wave has died out, so an idle new tab costs nothing.
|
|
10
|
+
*
|
|
11
|
+
* One part of the client script; see ./index.ts for how the parts join.
|
|
12
|
+
*/
|
|
13
|
+
export declare const RIPPLE: string;
|