@oharness/server 0.9.2 → 0.10.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/i18n.js +356 -62
- package/dist/i18n.js.map +1 -1
- package/dist/main.js +4 -0
- package/dist/main.js.map +1 -1
- package/dist/page/client/account.js +430 -23
- package/dist/page/client/account.js.map +1 -1
- package/dist/page/client/base.js +20 -1
- package/dist/page/client/base.js.map +1 -1
- package/dist/page/client/composer.js +709 -58
- 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 +93 -6
- package/dist/page/client/dialogs.js.map +1 -1
- package/dist/page/client/events.js +94 -7
- 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 +4 -0
- package/dist/page/client/index.js.map +1 -1
- package/dist/page/client/panels.js +12 -6
- package/dist/page/client/panels.js.map +1 -1
- package/dist/page/client/routines.js +296 -41
- package/dist/page/client/routines.js.map +1 -1
- package/dist/page/client/shell.js +229 -51
- package/dist/page/client/shell.js.map +1 -1
- package/dist/page/client/state.js +273 -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/transcript.js +174 -6
- 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 +706 -104
- package/dist/page/style.js.map +1 -1
- package/dist/page.js +161 -54
- package/dist/page.js.map +1 -1
- package/dist/prefs.d.ts +14 -0
- package/dist/prefs.js +8 -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 +1291 -49
- 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/theme.js +5 -0
- package/dist/theme.js.map +1 -1
- package/dist/turn-shots.d.ts +27 -0
- package/dist/turn-shots.js +71 -0
- package/dist/turn-shots.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { MemoryEntry } from "@oharness/engine/agent/memory.ts";
|
|
2
|
+
import type { Harness } from "@oharness/engine/harness.ts";
|
|
3
|
+
/**
|
|
4
|
+
* The offers under "What should I work on?".
|
|
5
|
+
*
|
|
6
|
+
* A project the agent has never worked in gets the same rotating set, and
|
|
7
|
+
* they are about the user's day rather than the directory: an empty folder has
|
|
8
|
+
* no code to profile and no README to fix, and guessing at one teaches a new
|
|
9
|
+
* person that this is a code tool and nothing else.
|
|
10
|
+
*
|
|
11
|
+
* Once there is history, the offers are written from it: what the recent
|
|
12
|
+
* conversations in this project were about, plus the project's notes when it
|
|
13
|
+
* has any. Conversations come first because nearly every project has them —
|
|
14
|
+
* notes mostly go to the user's own memory, not the project's, so a starter
|
|
15
|
+
* that waited for project notes was one most people never saw. Only titles and
|
|
16
|
+
* the opening request of each are read, never the whole transcript, and both
|
|
17
|
+
* pass through the same secret redaction memory uses.
|
|
18
|
+
*/
|
|
19
|
+
export interface Starter {
|
|
20
|
+
/** What fits on the chip. */
|
|
21
|
+
label: string;
|
|
22
|
+
/** The sentence the chip sends. */
|
|
23
|
+
prompt: string;
|
|
24
|
+
}
|
|
25
|
+
/** `pending`: a set is being written for this project, and will be pushed when it lands. */
|
|
26
|
+
export type StarterReply = {
|
|
27
|
+
kind: "fixed";
|
|
28
|
+
pending?: boolean;
|
|
29
|
+
} | {
|
|
30
|
+
kind: "written";
|
|
31
|
+
starters: Starter[];
|
|
32
|
+
};
|
|
33
|
+
/** One recent conversation, as the prompt sees it. */
|
|
34
|
+
export interface SessionDigest {
|
|
35
|
+
id: string;
|
|
36
|
+
title?: string;
|
|
37
|
+
/** What the user asked first, cut short and redacted. */
|
|
38
|
+
ask?: string;
|
|
39
|
+
updatedAt: number;
|
|
40
|
+
}
|
|
41
|
+
/** What the starters are written from. */
|
|
42
|
+
export interface ProjectContext {
|
|
43
|
+
sessions: SessionDigest[];
|
|
44
|
+
notes: MemoryEntry[];
|
|
45
|
+
}
|
|
46
|
+
/** Ids under "starter.<id>" in i18n: the rotating offers for a project with no memory. */
|
|
47
|
+
export declare const FIXED_STARTERS: readonly ["trip", "email", "research", "savings", "japanTrip"];
|
|
48
|
+
export declare const STARTERS_PROMPT = "You suggest what a user could ask an AI agent to do next in one of their projects. You are given what they have recently asked the agent in this project, and the agent's notes about it when there are any.\n\nWrite exactly three suggestions. Each one:\n- is grounded in what the user has actually been doing here \u2014 a thread they started and did not finish, a natural next step after something they did, a recurring chore \u2014 never invented;\n- is specific: name the file, app, document, topic or decision it is about;\n- differs in kind from the other two (for example: continue or fix something, check or measure something, write or plan something);\n- has a \"label\": an imperative phrase under 60 characters that fits on a button;\n- has a \"prompt\": one to three sentences the agent receives, saying what to do and what to hand back.\n\nDo not simply repeat a request the user already made; offer the step after it. Skip anything that looks finished. Never include secrets, keys or personal data.\nReply with only a JSON array: [{\"label\": \"...\", \"prompt\": \"...\"}, ...]";
|
|
49
|
+
/** Recent conversations as the prompt shows them: newest first, each short. */
|
|
50
|
+
export declare function sessionsText(sessions: readonly SessionDigest[]): string;
|
|
51
|
+
/** The notes as the prompt shows them: newest first, each cut short, the whole bounded. */
|
|
52
|
+
export declare function notesText(notes: readonly MemoryEntry[], budget?: number): string;
|
|
53
|
+
export declare function startersRequest(context: ProjectContext, locale: string): string;
|
|
54
|
+
/** How long one generation may take before the fixed three are shown instead. */
|
|
55
|
+
export declare const STARTERS_TIMEOUT_MS = 45000;
|
|
56
|
+
/**
|
|
57
|
+
* The project's recent conversations, digested.
|
|
58
|
+
*
|
|
59
|
+
* The open, empty one on screen is not history, and routine runs are the
|
|
60
|
+
* scheduler talking, not the user. Reading a transcript is the costly part,
|
|
61
|
+
* so only the dozen most recent are opened, and only their first user turn.
|
|
62
|
+
*/
|
|
63
|
+
export declare function recentSessions(harness: Harness, cwd: string): Promise<SessionDigest[]>;
|
|
64
|
+
/** Three usable starters out of a model reply, or nothing. */
|
|
65
|
+
export declare function parseStarters(reply: string): Starter[] | undefined;
|
|
66
|
+
/**
|
|
67
|
+
* What a set of starters was written from, in which language.
|
|
68
|
+
*
|
|
69
|
+
* A new conversation, a renamed one, or a note edited or added is a project
|
|
70
|
+
* that has moved on, so the offers are rewritten. A turn inside an existing
|
|
71
|
+
* conversation is not: keying on its last activity would pay for a new set
|
|
72
|
+
* every time a message is sent. A restart with the same history pays nothing.
|
|
73
|
+
*/
|
|
74
|
+
export declare function startersKey(context: ProjectContext, locale: string): string;
|
|
75
|
+
/**
|
|
76
|
+
* The starters for one project, as the page asks for them.
|
|
77
|
+
*
|
|
78
|
+
* Never waits on a model. With a set already written for this history it is
|
|
79
|
+
* returned; otherwise the answer is the fixed three at once, marked pending,
|
|
80
|
+
* and a set is written in the background — `onReady` is told when it lands,
|
|
81
|
+
* so the page can swap it in, and the next ask reads it from disk. Writing
|
|
82
|
+
* one takes a flash model twenty-odd seconds, which no new conversation
|
|
83
|
+
* should sit through.
|
|
84
|
+
*
|
|
85
|
+
* One generation per project and history at a time: the page asks on boot and
|
|
86
|
+
* on every project switch, and two tabs landing together must not pay twice.
|
|
87
|
+
*/
|
|
88
|
+
export type StartersFor = ((harness: Harness, cwd: string, locale: string, model?: string) => Promise<StarterReply>) & {
|
|
89
|
+
/** Every generation still running has settled. For tests and shutdown. */
|
|
90
|
+
idle(): Promise<void>;
|
|
91
|
+
};
|
|
92
|
+
export declare function createStarters(onReady?: (cwd: string, locale: string, starters: Starter[]) => void): StartersFor;
|
package/dist/starters.js
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { userPath } from "@oharness/engine/paths.ts";
|
|
5
|
+
import { parseJson } from "@oharness/engine/util/json.ts";
|
|
6
|
+
import { redactSecrets } from "@oharness/engine/agent/memory-redact.ts";
|
|
7
|
+
import { visibleText } from "@oharness/engine/core/types.ts";
|
|
8
|
+
/** Ids under "starter.<id>" in i18n: the rotating offers for a project with no memory. */
|
|
9
|
+
export const FIXED_STARTERS = ["trip", "email", "research", "savings", "japanTrip"];
|
|
10
|
+
const LANGUAGES = { en: "English", zh: "Simplified Chinese" };
|
|
11
|
+
export const STARTERS_PROMPT = `You suggest what a user could ask an AI agent to do next in one of their projects. You are given what they have recently asked the agent in this project, and the agent's notes about it when there are any.
|
|
12
|
+
|
|
13
|
+
Write exactly three suggestions. Each one:
|
|
14
|
+
- is grounded in what the user has actually been doing here — a thread they started and did not finish, a natural next step after something they did, a recurring chore — never invented;
|
|
15
|
+
- is specific: name the file, app, document, topic or decision it is about;
|
|
16
|
+
- differs in kind from the other two (for example: continue or fix something, check or measure something, write or plan something);
|
|
17
|
+
- has a "label": an imperative phrase under 60 characters that fits on a button;
|
|
18
|
+
- has a "prompt": one to three sentences the agent receives, saying what to do and what to hand back.
|
|
19
|
+
|
|
20
|
+
Do not simply repeat a request the user already made; offer the step after it. Skip anything that looks finished. Never include secrets, keys or personal data.
|
|
21
|
+
Reply with only a JSON array: [{"label": "...", "prompt": "..."}, ...]`;
|
|
22
|
+
/** Recent conversations as the prompt shows them: newest first, each short. */
|
|
23
|
+
export function sessionsText(sessions) {
|
|
24
|
+
return [...sessions]
|
|
25
|
+
.sort((a, b) => b.updatedAt - a.updatedAt)
|
|
26
|
+
.map((session) => {
|
|
27
|
+
const lines = [`<session updated="${new Date(session.updatedAt).toISOString().slice(0, 10)}">`];
|
|
28
|
+
if (session.title)
|
|
29
|
+
lines.push(`title: ${session.title}`);
|
|
30
|
+
if (session.ask)
|
|
31
|
+
lines.push(`first request: ${session.ask}`);
|
|
32
|
+
lines.push("</session>");
|
|
33
|
+
return lines.join("\n");
|
|
34
|
+
})
|
|
35
|
+
.join("\n\n");
|
|
36
|
+
}
|
|
37
|
+
/** The notes as the prompt shows them: newest first, each cut short, the whole bounded. */
|
|
38
|
+
export function notesText(notes, budget = 12_000) {
|
|
39
|
+
const sorted = [...notes].sort((a, b) => (b.updatedAt ?? b.createdAt) - (a.updatedAt ?? a.createdAt));
|
|
40
|
+
const out = [];
|
|
41
|
+
let used = 0;
|
|
42
|
+
for (const note of sorted) {
|
|
43
|
+
const body = note.body.length > 600 ? note.body.slice(0, 600) + "…" : note.body;
|
|
44
|
+
const block = `<note id="${note.id}"${note.type ? ` type="${note.type}"` : ""}>\n${note.summary}\n\n${body}\n</note>`;
|
|
45
|
+
if (used + block.length > budget)
|
|
46
|
+
break;
|
|
47
|
+
out.push(block);
|
|
48
|
+
used += block.length;
|
|
49
|
+
}
|
|
50
|
+
return out.join("\n\n");
|
|
51
|
+
}
|
|
52
|
+
export function startersRequest(context, locale) {
|
|
53
|
+
const language = LANGUAGES[locale] ?? LANGUAGES.en;
|
|
54
|
+
const parts = [];
|
|
55
|
+
if (context.sessions.length)
|
|
56
|
+
parts.push(`Recent conversations in this project:\n${sessionsText(context.sessions)}`);
|
|
57
|
+
if (context.notes.length)
|
|
58
|
+
parts.push(`Project notes:\n${notesText(context.notes)}`);
|
|
59
|
+
return `${parts.join("\n\n")}\n\nWrite the three suggestions in ${language}, as a JSON array.`;
|
|
60
|
+
}
|
|
61
|
+
/** How long one generation may take before the fixed three are shown instead. */
|
|
62
|
+
export const STARTERS_TIMEOUT_MS = 45_000;
|
|
63
|
+
function isTimeout(error) {
|
|
64
|
+
const name = error?.name;
|
|
65
|
+
return name === "TimeoutError" || name === "AbortError" || /abort|timed? ?out/i.test(String(error));
|
|
66
|
+
}
|
|
67
|
+
/** How many recent conversations are read, and how much of each. */
|
|
68
|
+
const SESSION_LIMIT = 12;
|
|
69
|
+
const ASK_LENGTH = 200;
|
|
70
|
+
/**
|
|
71
|
+
* The project's recent conversations, digested.
|
|
72
|
+
*
|
|
73
|
+
* The open, empty one on screen is not history, and routine runs are the
|
|
74
|
+
* scheduler talking, not the user. Reading a transcript is the costly part,
|
|
75
|
+
* so only the dozen most recent are opened, and only their first user turn.
|
|
76
|
+
*/
|
|
77
|
+
export async function recentSessions(harness, cwd) {
|
|
78
|
+
const metas = (await harness.listSessions(500).catch(() => []))
|
|
79
|
+
.filter((meta) => meta.cwd === cwd && !meta.routine && meta.turns > 0)
|
|
80
|
+
.slice(0, SESSION_LIMIT);
|
|
81
|
+
return Promise.all(metas.map(async (meta) => {
|
|
82
|
+
let ask;
|
|
83
|
+
try {
|
|
84
|
+
const first = (await harness.store.recordsOf(meta.id)).find((record) => record.message.role === "user");
|
|
85
|
+
const text = first ? visibleText(first.message).replace(/\s+/g, " ").trim() : "";
|
|
86
|
+
if (text)
|
|
87
|
+
ask = redactSecrets(text.length > ASK_LENGTH ? text.slice(0, ASK_LENGTH) + "…" : text).text;
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// A transcript that will not read still has its title.
|
|
91
|
+
}
|
|
92
|
+
const title = meta.title ? redactSecrets(meta.title).text : undefined;
|
|
93
|
+
return { id: meta.id, updatedAt: meta.updatedAt, ...(title ? { title } : {}), ...(ask ? { ask } : {}) };
|
|
94
|
+
}));
|
|
95
|
+
}
|
|
96
|
+
/** Three usable starters out of a model reply, or nothing. */
|
|
97
|
+
export function parseStarters(reply) {
|
|
98
|
+
const start = reply.indexOf("[");
|
|
99
|
+
const end = reply.lastIndexOf("]");
|
|
100
|
+
if (start < 0 || end <= start)
|
|
101
|
+
return undefined;
|
|
102
|
+
const parsed = parseJson(reply.slice(start, end + 1));
|
|
103
|
+
if (!parsed.ok || !Array.isArray(parsed.value))
|
|
104
|
+
return undefined;
|
|
105
|
+
const starters = [];
|
|
106
|
+
for (const item of parsed.value) {
|
|
107
|
+
if (!item || typeof item !== "object")
|
|
108
|
+
continue;
|
|
109
|
+
const { label, prompt } = item;
|
|
110
|
+
if (typeof label !== "string" || typeof prompt !== "string")
|
|
111
|
+
continue;
|
|
112
|
+
const cleanLabel = label.replace(/\s+/g, " ").trim();
|
|
113
|
+
const cleanPrompt = prompt.trim();
|
|
114
|
+
if (!cleanLabel || !cleanPrompt || cleanLabel.length > 120 || cleanPrompt.length > 1_200)
|
|
115
|
+
continue;
|
|
116
|
+
starters.push({ label: cleanLabel, prompt: cleanPrompt });
|
|
117
|
+
if (starters.length === 3)
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
return starters.length === 3 ? starters : undefined;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* What a set of starters was written from, in which language.
|
|
124
|
+
*
|
|
125
|
+
* A new conversation, a renamed one, or a note edited or added is a project
|
|
126
|
+
* that has moved on, so the offers are rewritten. A turn inside an existing
|
|
127
|
+
* conversation is not: keying on its last activity would pay for a new set
|
|
128
|
+
* every time a message is sent. A restart with the same history pays nothing.
|
|
129
|
+
*/
|
|
130
|
+
export function startersKey(context, locale) {
|
|
131
|
+
const notes = context.notes
|
|
132
|
+
.map((note) => [note.id, note.updatedAt ?? note.createdAt, note.summary.length, note.body.length])
|
|
133
|
+
.sort((a, b) => String(a[0]).localeCompare(String(b[0])));
|
|
134
|
+
const sessions = context.sessions
|
|
135
|
+
.map((session) => [session.id, session.title ?? ""])
|
|
136
|
+
.sort((a, b) => String(a[0]).localeCompare(String(b[0])));
|
|
137
|
+
return createHash("sha256").update(JSON.stringify([locale, notes, sessions])).digest("hex");
|
|
138
|
+
}
|
|
139
|
+
const cacheFile = (cwd) => userPath("starters", createHash("sha256").update(cwd).digest("hex").slice(0, 24) + ".json");
|
|
140
|
+
async function readCached(cwd, key) {
|
|
141
|
+
try {
|
|
142
|
+
const parsed = parseJson(await readFile(cacheFile(cwd), "utf8"));
|
|
143
|
+
if (!parsed.ok || parsed.value?.key !== key || !Array.isArray(parsed.value.starters))
|
|
144
|
+
return undefined;
|
|
145
|
+
return parseStarters(JSON.stringify(parsed.value.starters));
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
return undefined;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
async function writeCached(cwd, key, starters) {
|
|
152
|
+
const file = cacheFile(cwd);
|
|
153
|
+
await mkdir(path.dirname(file), { recursive: true });
|
|
154
|
+
await writeFile(file, JSON.stringify({ key, starters }), "utf8");
|
|
155
|
+
}
|
|
156
|
+
export function createStarters(onReady) {
|
|
157
|
+
const pending = new Map();
|
|
158
|
+
const failed = new Set();
|
|
159
|
+
const get = async (harness, cwd, locale, model) => {
|
|
160
|
+
const [notes, sessions] = await Promise.all([
|
|
161
|
+
harness.memory ? harness.memory.load().catch(() => []) : Promise.resolve([]),
|
|
162
|
+
recentSessions(harness, cwd),
|
|
163
|
+
]);
|
|
164
|
+
if (!notes.length && !sessions.length)
|
|
165
|
+
return { kind: "fixed" };
|
|
166
|
+
const context = { notes, sessions };
|
|
167
|
+
const key = startersKey(context, locale);
|
|
168
|
+
const slot = cwd + "\0" + key;
|
|
169
|
+
if (failed.has(slot))
|
|
170
|
+
return { kind: "fixed" };
|
|
171
|
+
const cached = await readCached(cwd, key);
|
|
172
|
+
if (cached)
|
|
173
|
+
return { kind: "written", starters: cached };
|
|
174
|
+
if (!pending.has(slot)) {
|
|
175
|
+
const job = (async () => {
|
|
176
|
+
try {
|
|
177
|
+
// Generous: a flash model answering from a dozen conversations takes
|
|
178
|
+
// twenty-odd seconds, and nothing is waiting on it.
|
|
179
|
+
const reply = await harness.generateText(STARTERS_PROMPT, startersRequest(context, locale), AbortSignal.timeout(STARTERS_TIMEOUT_MS), 1_500, model);
|
|
180
|
+
const starters = parseStarters(reply);
|
|
181
|
+
if (!starters) {
|
|
182
|
+
harness.logger.warn("starters: the model's reply held no three usable starters", { reply: reply.slice(0, 500) });
|
|
183
|
+
failed.add(slot);
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
await writeCached(cwd, key, starters).catch(() => { });
|
|
187
|
+
onReady?.(cwd, locale, starters);
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
harness.logger.warn("starters: could not write them", { error: String(error) });
|
|
191
|
+
// No model configured, offline, or too slow this time: the fixed
|
|
192
|
+
// three stay. A timeout is tried again on the next ask — a slow
|
|
193
|
+
// moment is not a model that cannot do this; anything else waits
|
|
194
|
+
// for the history to change.
|
|
195
|
+
if (!isTimeout(error))
|
|
196
|
+
failed.add(slot);
|
|
197
|
+
}
|
|
198
|
+
finally {
|
|
199
|
+
pending.delete(slot);
|
|
200
|
+
}
|
|
201
|
+
})();
|
|
202
|
+
pending.set(slot, job);
|
|
203
|
+
}
|
|
204
|
+
return { kind: "fixed", pending: true };
|
|
205
|
+
};
|
|
206
|
+
return Object.assign(get, {
|
|
207
|
+
idle: async () => {
|
|
208
|
+
while (pending.size)
|
|
209
|
+
await Promise.all([...pending.values()]);
|
|
210
|
+
},
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
//# sourceMappingURL=starters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"starters.js","sourceRoot":"","sources":["../src/starters.ts"],"names":[],"mappings":"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"}
|
package/dist/theme.js
CHANGED
|
@@ -14,6 +14,10 @@
|
|
|
14
14
|
export const LIGHT = {
|
|
15
15
|
bg: "#fff",
|
|
16
16
|
panel: "#f7f7f8",
|
|
17
|
+
// The window's frame: the top bar and the rail, one L around the panel and
|
|
18
|
+
// the page. A third surface, set back behind both, so the frame reads as
|
|
19
|
+
// the window rather than as more page or more panel.
|
|
20
|
+
frame: "#ececee",
|
|
17
21
|
fg: "#1a1a1a",
|
|
18
22
|
dim: "#6b7280",
|
|
19
23
|
line: "#00000010",
|
|
@@ -57,6 +61,7 @@ export const LIGHT = {
|
|
|
57
61
|
export const DARK = {
|
|
58
62
|
bg: "#0e1013",
|
|
59
63
|
panel: "#15171c",
|
|
64
|
+
frame: "#08090b",
|
|
60
65
|
fg: "#e6e6e6",
|
|
61
66
|
dim: "#8b93a1",
|
|
62
67
|
line: "#ffffff14",
|
package/dist/theme.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme.js","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,MAAM,CAAC,MAAM,KAAK,GAAY;IAC5B,EAAE,EAAE,MAAM;IACV,KAAK,EAAE,SAAS;IAChB,EAAE,EAAE,SAAS;IACb,GAAG,EAAE,SAAS;IACd,IAAI,EAAE,WAAW;IACjB,MAAM,EAAE,SAAS;IACjB,uEAAuE;IACvE,+EAA+E;IAC/E,8EAA8E;IAC9E,8EAA8E;IAC9E,8EAA8E;IAC9E,KAAK,EAAE,SAAS;IAChB,YAAY,EAAE,WAAW;IACzB,uEAAuE;IACvE,4EAA4E;IAC5E,yEAAyE;IACzE,WAAW,EAAE,SAAS;IACtB,aAAa,EAAE,SAAS;IACxB,EAAE,EAAE,SAAS;IACb,IAAI,EAAE,SAAS;IACf,GAAG,EAAE,SAAS;IACd,GAAG,EAAE,SAAS;IACd,QAAQ,EAAE,SAAS;IACnB,GAAG,EAAE,SAAS;IACd,QAAQ,EAAE,SAAS;IACnB,KAAK,EAAE,WAAW;IAClB,GAAG,EAAE,WAAW;IAChB,KAAK,EAAE,SAAS;IAChB,IAAI,EAAE,WAAW;IACjB,KAAK,EAAE,WAAW;IAClB,aAAa,EAAE,WAAW;IAC1B,KAAK,EAAE,WAAW;IAClB,wEAAwE;IACxE,4EAA4E;IAC5E,2EAA2E;IAC3E,mEAAmE;IACnE,cAAc,EAAE,0CAA0C;IAC1D,EAAE,EAAE,SAAS;IACb,GAAG,EAAE,SAAS;IACd,GAAG,EAAE,SAAS;IACd,GAAG,EAAE,SAAS;CACf,CAAC;AAEF,MAAM,CAAC,MAAM,IAAI,GAAY;IAC3B,EAAE,EAAE,SAAS;IACb,KAAK,EAAE,SAAS;IAChB,EAAE,EAAE,SAAS;IACb,GAAG,EAAE,SAAS;IACd,IAAI,EAAE,WAAW;IACjB,MAAM,EAAE,SAAS;IACjB,KAAK,EAAE,SAAS;IAChB,YAAY,EAAE,WAAW;IACzB,WAAW,EAAE,SAAS;IACtB,aAAa,EAAE,SAAS;IACxB,EAAE,EAAE,SAAS;IACb,IAAI,EAAE,SAAS;IACf,GAAG,EAAE,SAAS;IACd,GAAG,EAAE,SAAS;IACd,QAAQ,EAAE,SAAS;IACnB,GAAG,EAAE,SAAS;IACd,QAAQ,EAAE,SAAS;IACnB,KAAK,EAAE,WAAW;IAClB,GAAG,EAAE,WAAW;IAChB,KAAK,EAAE,SAAS;IAChB,IAAI,EAAE,WAAW;IACjB,KAAK,EAAE,WAAW;IAClB,aAAa,EAAE,WAAW;IAC1B,KAAK,EAAE,WAAW;IAClB,cAAc,EAAE,0CAA0C;IAC1D,EAAE,EAAE,SAAS;IACb,GAAG,EAAE,SAAS;IACd,GAAG,EAAE,SAAS;IACd,GAAG,EAAE,SAAS;CACf,CAAC;AAEF,MAAM,IAAI,GAAG,CAAC,OAAgB,EAAE,EAAE,CAChC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC;KACpB,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,IAAI,IAAI,KAAK,GAAG,CAAC;KAC7C,IAAI,CAAC,GAAG,CAAC,CAAC;AAEf,4EAA4E;AAC5E,8DAA8D;AAC9D,MAAM,CAAC,MAAM,SAAS,GACpB,6BAA6B,IAAI,CAAC,KAAK,CAAC,KAAK;IAC7C,yFAAyF,IAAI,CAAC,IAAI,CAAC,MAAM;IACzG,+CAA+C,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC"}
|
|
1
|
+
{"version":3,"file":"theme.js","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,MAAM,CAAC,MAAM,KAAK,GAAY;IAC5B,EAAE,EAAE,MAAM;IACV,KAAK,EAAE,SAAS;IAChB,2EAA2E;IAC3E,yEAAyE;IACzE,qDAAqD;IACrD,KAAK,EAAE,SAAS;IAChB,EAAE,EAAE,SAAS;IACb,GAAG,EAAE,SAAS;IACd,IAAI,EAAE,WAAW;IACjB,MAAM,EAAE,SAAS;IACjB,uEAAuE;IACvE,+EAA+E;IAC/E,8EAA8E;IAC9E,8EAA8E;IAC9E,8EAA8E;IAC9E,KAAK,EAAE,SAAS;IAChB,YAAY,EAAE,WAAW;IACzB,uEAAuE;IACvE,4EAA4E;IAC5E,yEAAyE;IACzE,WAAW,EAAE,SAAS;IACtB,aAAa,EAAE,SAAS;IACxB,EAAE,EAAE,SAAS;IACb,IAAI,EAAE,SAAS;IACf,GAAG,EAAE,SAAS;IACd,GAAG,EAAE,SAAS;IACd,QAAQ,EAAE,SAAS;IACnB,GAAG,EAAE,SAAS;IACd,QAAQ,EAAE,SAAS;IACnB,KAAK,EAAE,WAAW;IAClB,GAAG,EAAE,WAAW;IAChB,KAAK,EAAE,SAAS;IAChB,IAAI,EAAE,WAAW;IACjB,KAAK,EAAE,WAAW;IAClB,aAAa,EAAE,WAAW;IAC1B,KAAK,EAAE,WAAW;IAClB,wEAAwE;IACxE,4EAA4E;IAC5E,2EAA2E;IAC3E,mEAAmE;IACnE,cAAc,EAAE,0CAA0C;IAC1D,EAAE,EAAE,SAAS;IACb,GAAG,EAAE,SAAS;IACd,GAAG,EAAE,SAAS;IACd,GAAG,EAAE,SAAS;CACf,CAAC;AAEF,MAAM,CAAC,MAAM,IAAI,GAAY;IAC3B,EAAE,EAAE,SAAS;IACb,KAAK,EAAE,SAAS;IAChB,KAAK,EAAE,SAAS;IAChB,EAAE,EAAE,SAAS;IACb,GAAG,EAAE,SAAS;IACd,IAAI,EAAE,WAAW;IACjB,MAAM,EAAE,SAAS;IACjB,KAAK,EAAE,SAAS;IAChB,YAAY,EAAE,WAAW;IACzB,WAAW,EAAE,SAAS;IACtB,aAAa,EAAE,SAAS;IACxB,EAAE,EAAE,SAAS;IACb,IAAI,EAAE,SAAS;IACf,GAAG,EAAE,SAAS;IACd,GAAG,EAAE,SAAS;IACd,QAAQ,EAAE,SAAS;IACnB,GAAG,EAAE,SAAS;IACd,QAAQ,EAAE,SAAS;IACnB,KAAK,EAAE,WAAW;IAClB,GAAG,EAAE,WAAW;IAChB,KAAK,EAAE,SAAS;IAChB,IAAI,EAAE,WAAW;IACjB,KAAK,EAAE,WAAW;IAClB,aAAa,EAAE,WAAW;IAC1B,KAAK,EAAE,WAAW;IAClB,cAAc,EAAE,0CAA0C;IAC1D,EAAE,EAAE,SAAS;IACb,GAAG,EAAE,SAAS;IACd,GAAG,EAAE,SAAS;IACd,GAAG,EAAE,SAAS;CACf,CAAC;AAEF,MAAM,IAAI,GAAG,CAAC,OAAgB,EAAE,EAAE,CAChC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC;KACpB,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,IAAI,IAAI,KAAK,GAAG,CAAC;KAC7C,IAAI,CAAC,GAAG,CAAC,CAAC;AAEf,4EAA4E;AAC5E,8DAA8D;AAC9D,MAAM,CAAC,MAAM,SAAS,GACpB,6BAA6B,IAAI,CAAC,KAAK,CAAC,KAAK;IAC7C,yFAAyF,IAAI,CAAC,IAAI,CAAC,MAAM;IACzG,+CAA+C,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ComputerSnapshotEvent } from "@oharness/engine/computer/session.ts";
|
|
2
|
+
/**
|
|
3
|
+
* The windows a Computer use turn left behind, as the person saw them.
|
|
4
|
+
*
|
|
5
|
+
* The agent works from the accessibility tree and screenshots only when that
|
|
6
|
+
* tree is not enough, so a turn in Bear or Finder usually ends with no picture
|
|
7
|
+
* in the transcript at all. When one ends, the host captures each window it
|
|
8
|
+
* worked in and the picture is kept here — beside the session, not in it: the
|
|
9
|
+
* transcript is what the model reads, and these are for the person reading it
|
|
10
|
+
* back.
|
|
11
|
+
*
|
|
12
|
+
* One directory per session: the JPEGs, and an index.jsonl of where in the
|
|
13
|
+
* conversation each belongs (`at`, the message count when its turn ended).
|
|
14
|
+
*/
|
|
15
|
+
export interface TurnShot {
|
|
16
|
+
at: number;
|
|
17
|
+
app: string;
|
|
18
|
+
title?: string;
|
|
19
|
+
file: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function saveTurnShots(session: string, at: number, shots: ComputerSnapshotEvent["shots"]): Promise<TurnShot[]>;
|
|
22
|
+
/** Synchronous: the transcript is flattened synchronously, and this file is a few lines. */
|
|
23
|
+
export declare function listTurnShots(session: string): TurnShot[];
|
|
24
|
+
/** The bytes of one picture, or nothing for a name that is not one of ours. */
|
|
25
|
+
export declare function turnShotPath(session: string, file: string): string | undefined;
|
|
26
|
+
export declare function removeTurnShots(session: string): Promise<void>;
|
|
27
|
+
export declare function turnShotSrc(session: string, file: string): string;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { appendFile, mkdir, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { userPath } from "@oharness/engine/paths.ts";
|
|
5
|
+
function dir(session) {
|
|
6
|
+
// Session ids are the store's own (date_hex), but the id also arrives on a
|
|
7
|
+
// URL: anything that could climb out of the directory is refused.
|
|
8
|
+
if (!/^[\w-]+$/.test(session))
|
|
9
|
+
throw new Error("bad session id");
|
|
10
|
+
return userPath("computer-shots", session);
|
|
11
|
+
}
|
|
12
|
+
export async function saveTurnShots(session, at, shots) {
|
|
13
|
+
const root = dir(session);
|
|
14
|
+
await mkdir(root, { recursive: true });
|
|
15
|
+
const saved = [];
|
|
16
|
+
const stamp = Date.now();
|
|
17
|
+
for (const [index, shot] of shots.entries()) {
|
|
18
|
+
const file = `${at}-${stamp}-${index}.jpg`;
|
|
19
|
+
await writeFile(path.join(root, file), Buffer.from(shot.data, "base64"));
|
|
20
|
+
saved.push({ at, app: shot.app, ...(shot.title ? { title: shot.title } : {}), file });
|
|
21
|
+
}
|
|
22
|
+
await appendFile(path.join(root, "index.jsonl"), saved.map((one) => JSON.stringify(one) + "\n").join(""));
|
|
23
|
+
return saved;
|
|
24
|
+
}
|
|
25
|
+
/** Synchronous: the transcript is flattened synchronously, and this file is a few lines. */
|
|
26
|
+
export function listTurnShots(session) {
|
|
27
|
+
let file;
|
|
28
|
+
try {
|
|
29
|
+
file = path.join(dir(session), "index.jsonl");
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
if (!existsSync(file))
|
|
35
|
+
return [];
|
|
36
|
+
const shots = [];
|
|
37
|
+
for (const line of readFileSync(file, "utf8").split("\n")) {
|
|
38
|
+
if (!line.trim())
|
|
39
|
+
continue;
|
|
40
|
+
try {
|
|
41
|
+
shots.push(JSON.parse(line));
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// A torn last line from a crash loses one picture, not the rest.
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return shots;
|
|
48
|
+
}
|
|
49
|
+
/** The bytes of one picture, or nothing for a name that is not one of ours. */
|
|
50
|
+
export function turnShotPath(session, file) {
|
|
51
|
+
if (!/^[\w.-]+\.jpg$/.test(file))
|
|
52
|
+
return undefined;
|
|
53
|
+
try {
|
|
54
|
+
return path.join(dir(session), file);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export async function removeTurnShots(session) {
|
|
61
|
+
try {
|
|
62
|
+
await rm(dir(session), { recursive: true, force: true });
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
// Nothing to remove, or an id that could never have had any.
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
export function turnShotSrc(session, file) {
|
|
69
|
+
return `/turn-shot?session=${encodeURIComponent(session)}&file=${encodeURIComponent(file)}`;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=turn-shots.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"turn-shots.js","sourceRoot":"","sources":["../src/turn-shots.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oharness/server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "The browser frontend's server. Deployable on its own, without a terminal attached.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"build": "rm -rf dist && tsc -p tsconfig.build.json"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@oharness/engine": "0.
|
|
48
|
+
"@oharness/engine": "0.10.0",
|
|
49
49
|
"@xterm/addon-fit": "^0.11.0",
|
|
50
50
|
"@xterm/xterm": "^6.0.0"
|
|
51
51
|
},
|