@oharness/server 0.10.0 → 0.12.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 +242 -12
- package/dist/i18n.js.map +1 -1
- package/dist/icons.d.ts +3 -0
- package/dist/icons.js +69 -3
- package/dist/icons.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 +140 -4
- package/dist/page/client/account.js.map +1 -1
- package/dist/page/client/base.js +42 -16
- package/dist/page/client/base.js.map +1 -1
- package/dist/page/client/browser.js +1 -1
- package/dist/page/client/composer.js +641 -47
- package/dist/page/client/composer.js.map +1 -1
- package/dist/page/client/dialogs.js +75 -0
- package/dist/page/client/dialogs.js.map +1 -1
- package/dist/page/client/events.js +25 -2
- package/dist/page/client/events.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 +4 -4
- 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 +173 -41
- package/dist/page/client/routines.js.map +1 -1
- package/dist/page/client/shell.js +200 -54
- package/dist/page/client/shell.js.map +1 -1
- package/dist/page/client/state.js +7 -2
- package/dist/page/client/state.js.map +1 -1
- 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 +63 -7
- package/dist/page/client/transcript.js.map +1 -1
- package/dist/page/style.js +273 -22
- package/dist/page/style.js.map +1 -1
- package/dist/page.js +5 -5
- package/dist/page.js.map +1 -1
- package/dist/prefs.d.ts +17 -0
- package/dist/prefs.js +5 -0
- package/dist/prefs.js.map +1 -1
- package/dist/server.js +710 -45
- package/dist/server.js.map +1 -1
- 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 +35 -2
- package/dist/terminal.js +60 -4
- 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/tool-icons.d.ts +12 -0
- package/dist/tool-icons.js +16 -0
- package/dist/tool-icons.js.map +1 -0
- package/dist/turn-shots.d.ts +18 -2
- package/dist/turn-shots.js +10 -1
- package/dist/turn-shots.js.map +1 -1
- 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
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { ThemeInput } from "./user-theme.ts";
|
|
2
|
+
/**
|
|
3
|
+
* The theme in use, the ones used before it, and the way back.
|
|
4
|
+
*
|
|
5
|
+
* One file in the user directory, beside prefs.json: a theme is a preference
|
|
6
|
+
* about how the app looks, not a property of a project. Stored as the input the
|
|
7
|
+
* model gave rather than as CSS, and resolved again on every load, so a stored
|
|
8
|
+
* theme always goes through today's validation and can never smuggle in
|
|
9
|
+
* anything the current rules would refuse.
|
|
10
|
+
*
|
|
11
|
+
* A file that cannot be read or does not validate is treated as no theme. The
|
|
12
|
+
* file itself is left where it is, for whoever wants to see what was in it:
|
|
13
|
+
* the one thing a broken theme must never do is stop the app from starting.
|
|
14
|
+
*/
|
|
15
|
+
export interface StoredTheme {
|
|
16
|
+
id: string;
|
|
17
|
+
name: string;
|
|
18
|
+
appliedAt: number;
|
|
19
|
+
input: ThemeInput;
|
|
20
|
+
}
|
|
21
|
+
export interface ThemeState {
|
|
22
|
+
active: {
|
|
23
|
+
id: string;
|
|
24
|
+
name: string;
|
|
25
|
+
} | null;
|
|
26
|
+
css: string;
|
|
27
|
+
canUndo: boolean;
|
|
28
|
+
history: Array<{
|
|
29
|
+
id: string;
|
|
30
|
+
name: string;
|
|
31
|
+
appliedAt: number;
|
|
32
|
+
active: boolean;
|
|
33
|
+
}>;
|
|
34
|
+
}
|
|
35
|
+
export declare class ThemeStore {
|
|
36
|
+
private file;
|
|
37
|
+
private resolved;
|
|
38
|
+
static load(): Promise<ThemeStore>;
|
|
39
|
+
state(): ThemeState;
|
|
40
|
+
/** The active theme as given, for the model to start a revision from. */
|
|
41
|
+
activeInput(): ThemeInput | undefined;
|
|
42
|
+
apply(input: ThemeInput): Promise<ThemeState>;
|
|
43
|
+
applyHistory(id: string): Promise<ThemeState | undefined>;
|
|
44
|
+
reset(): Promise<ThemeState>;
|
|
45
|
+
undo(): Promise<ThemeState>;
|
|
46
|
+
private moveTo;
|
|
47
|
+
private activeEntry;
|
|
48
|
+
private resolveActive;
|
|
49
|
+
private save;
|
|
50
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { randomUUID } 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 { renameWithRetry } from "@oharness/engine/util/fs.ts";
|
|
7
|
+
import { pruneAssets } from "./theme-assets.js";
|
|
8
|
+
import { resolveTheme, themeAssets, themeCss } from "./user-theme.js";
|
|
9
|
+
const MAX_HISTORY = 10;
|
|
10
|
+
const MAX_UNDO = 20;
|
|
11
|
+
const FILE = () => userPath("theme.json");
|
|
12
|
+
export class ThemeStore {
|
|
13
|
+
file = { version: 1, active: null, history: [], undo: [] };
|
|
14
|
+
resolved;
|
|
15
|
+
static async load() {
|
|
16
|
+
const store = new ThemeStore();
|
|
17
|
+
try {
|
|
18
|
+
const parsed = parseJson(await readFile(FILE(), "utf8"));
|
|
19
|
+
if (parsed.ok)
|
|
20
|
+
store.file = clean(parsed.value);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
// No file yet, or one that cannot be read: the built-in theme.
|
|
24
|
+
}
|
|
25
|
+
store.resolveActive();
|
|
26
|
+
// Images no theme in the history uses any more. In the background: a slow
|
|
27
|
+
// disk must not hold up the page.
|
|
28
|
+
void pruneAssets(store.file.history.flatMap((h) => themeAssets(h.input)));
|
|
29
|
+
return store;
|
|
30
|
+
}
|
|
31
|
+
state() {
|
|
32
|
+
const entry = this.activeEntry();
|
|
33
|
+
return {
|
|
34
|
+
active: entry && this.resolved ? { id: entry.id, name: entry.name } : null,
|
|
35
|
+
css: this.resolved ? themeCss(this.resolved) : "",
|
|
36
|
+
canUndo: this.file.undo.length > 0,
|
|
37
|
+
history: this.file.history.map((h) => ({ id: h.id, name: h.name, appliedAt: h.appliedAt, active: h.id === this.file.active })),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/** The active theme as given, for the model to start a revision from. */
|
|
41
|
+
activeInput() {
|
|
42
|
+
return this.resolved ? this.activeEntry()?.input : undefined;
|
|
43
|
+
}
|
|
44
|
+
async apply(input) {
|
|
45
|
+
const entry = { id: randomUUID(), name: input.name, appliedAt: Date.now(), input };
|
|
46
|
+
this.file.history = [entry, ...this.file.history].slice(0, MAX_HISTORY);
|
|
47
|
+
return this.moveTo(entry.id);
|
|
48
|
+
}
|
|
49
|
+
async applyHistory(id) {
|
|
50
|
+
if (!this.file.history.some((h) => h.id === id))
|
|
51
|
+
return undefined;
|
|
52
|
+
return this.moveTo(id);
|
|
53
|
+
}
|
|
54
|
+
async reset() {
|
|
55
|
+
return this.moveTo(null);
|
|
56
|
+
}
|
|
57
|
+
async undo() {
|
|
58
|
+
const previous = this.file.undo.pop();
|
|
59
|
+
if (previous === undefined)
|
|
60
|
+
return this.state();
|
|
61
|
+
// An entry pushed out of history since cannot be gone back to; the
|
|
62
|
+
// built-in theme always can.
|
|
63
|
+
this.file.active = previous && this.file.history.some((h) => h.id === previous) ? previous : null;
|
|
64
|
+
this.resolveActive();
|
|
65
|
+
await this.save();
|
|
66
|
+
return this.state();
|
|
67
|
+
}
|
|
68
|
+
async moveTo(id) {
|
|
69
|
+
if (id === this.file.active)
|
|
70
|
+
return this.state();
|
|
71
|
+
this.file.undo = [...this.file.undo, this.file.active].slice(-MAX_UNDO);
|
|
72
|
+
this.file.active = id;
|
|
73
|
+
this.resolveActive();
|
|
74
|
+
await this.save();
|
|
75
|
+
return this.state();
|
|
76
|
+
}
|
|
77
|
+
activeEntry() {
|
|
78
|
+
return this.file.history.find((h) => h.id === this.file.active);
|
|
79
|
+
}
|
|
80
|
+
resolveActive() {
|
|
81
|
+
const entry = this.activeEntry();
|
|
82
|
+
const result = entry ? resolveTheme(entry.input) : undefined;
|
|
83
|
+
this.resolved = result?.ok ? result.theme : undefined;
|
|
84
|
+
}
|
|
85
|
+
async save() {
|
|
86
|
+
const file = FILE();
|
|
87
|
+
await mkdir(path.dirname(file), { recursive: true });
|
|
88
|
+
tempSeq += 1;
|
|
89
|
+
const temp = `${file}.${process.pid}.${tempSeq}.tmp`;
|
|
90
|
+
await writeFile(temp, `${JSON.stringify(this.file, null, 2)}\n`, "utf8");
|
|
91
|
+
await renameWithRetry(temp, file);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
let tempSeq = 0;
|
|
95
|
+
/** Only the shape this module wrote; anything else is dropped, not trusted. */
|
|
96
|
+
function clean(raw) {
|
|
97
|
+
const out = { version: 1, active: null, history: [], undo: [] };
|
|
98
|
+
if (typeof raw !== "object" || raw === null)
|
|
99
|
+
return out;
|
|
100
|
+
const body = raw;
|
|
101
|
+
if (Array.isArray(body["history"])) {
|
|
102
|
+
for (const item of body["history"]) {
|
|
103
|
+
if (typeof item !== "object" || item === null)
|
|
104
|
+
continue;
|
|
105
|
+
const h = item;
|
|
106
|
+
if (typeof h["id"] !== "string" || typeof h["input"] !== "object" || h["input"] === null)
|
|
107
|
+
continue;
|
|
108
|
+
out.history.push({
|
|
109
|
+
id: h["id"],
|
|
110
|
+
name: typeof h["name"] === "string" ? h["name"] : "Custom",
|
|
111
|
+
appliedAt: typeof h["appliedAt"] === "number" ? h["appliedAt"] : 0,
|
|
112
|
+
input: h["input"],
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const ids = new Set(out.history.map((h) => h.id));
|
|
117
|
+
if (typeof body["active"] === "string" && ids.has(body["active"]))
|
|
118
|
+
out.active = body["active"];
|
|
119
|
+
if (Array.isArray(body["undo"])) {
|
|
120
|
+
out.undo = body["undo"].filter((v) => v === null || (typeof v === "string" && ids.has(v))).slice(-MAX_UNDO);
|
|
121
|
+
}
|
|
122
|
+
return out;
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=theme-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme-store.js","sourceRoot":"","sources":["../src/theme-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Tool } from "@oharness/engine/tools/types.ts";
|
|
2
|
+
import type { ResolvedTheme, ThemeInput } from "./user-theme.ts";
|
|
3
|
+
/**
|
|
4
|
+
* The agent's side of theming: learn what can change, and propose a theme.
|
|
5
|
+
*
|
|
6
|
+
* Proposing is all it can do. `set_theme` makes a preview card in the
|
|
7
|
+
* conversation and returns; the theme is applied only when the person clicks
|
|
8
|
+
* Apply on it. That is why the tool is read-only and needs no approval: the
|
|
9
|
+
* card is the approval, and it comes with the result in front of them rather
|
|
10
|
+
* than a description of it.
|
|
11
|
+
*
|
|
12
|
+
* Registered by the web server only. A terminal has no page to theme.
|
|
13
|
+
*/
|
|
14
|
+
export declare const GET_THEME_SCHEMA_TOOL = "get_theme_schema";
|
|
15
|
+
export declare const SET_THEME_TOOL = "set_theme";
|
|
16
|
+
export declare const RESET_THEME_TOOL = "reset_theme";
|
|
17
|
+
export interface ThemeToolHost {
|
|
18
|
+
/** The theme in use as it was given, or undefined for the built-in one. */
|
|
19
|
+
activeInput(): ThemeInput | undefined;
|
|
20
|
+
/** Put a preview card in front of the person; returns its id. */
|
|
21
|
+
propose(sessionId: string, theme: ResolvedTheme): string;
|
|
22
|
+
/** Go back to the built-in theme; returns the name of the one it replaced. */
|
|
23
|
+
reset(): Promise<string | undefined>;
|
|
24
|
+
}
|
|
25
|
+
export declare function createThemeTools(host: ThemeToolHost): Tool[];
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { toolError, toolText } from "@oharness/engine/tools/types.ts";
|
|
3
|
+
import { DARK, LIGHT } from "./theme.js";
|
|
4
|
+
import { assetExists, importAsset } from "./theme-assets.js";
|
|
5
|
+
import { ASSET_ID, IMAGE_SLOTS, SEEDS, TOKENS, describeReport, resolveTheme } from "./user-theme.js";
|
|
6
|
+
/**
|
|
7
|
+
* The agent's side of theming: learn what can change, and propose a theme.
|
|
8
|
+
*
|
|
9
|
+
* Proposing is all it can do. `set_theme` makes a preview card in the
|
|
10
|
+
* conversation and returns; the theme is applied only when the person clicks
|
|
11
|
+
* Apply on it. That is why the tool is read-only and needs no approval: the
|
|
12
|
+
* card is the approval, and it comes with the result in front of them rather
|
|
13
|
+
* than a description of it.
|
|
14
|
+
*
|
|
15
|
+
* Registered by the web server only. A terminal has no page to theme.
|
|
16
|
+
*/
|
|
17
|
+
export const GET_THEME_SCHEMA_TOOL = "get_theme_schema";
|
|
18
|
+
export const SET_THEME_TOOL = "set_theme";
|
|
19
|
+
export const RESET_THEME_TOOL = "reset_theme";
|
|
20
|
+
const paletteSchema = {
|
|
21
|
+
type: "object",
|
|
22
|
+
description: "Token → hex colour (#rrggbb, or #rrggbbaa for translucent non-seed tokens).",
|
|
23
|
+
additionalProperties: { type: "string" },
|
|
24
|
+
};
|
|
25
|
+
const imageRef = {
|
|
26
|
+
type: "string",
|
|
27
|
+
description: "Path to a PNG, JPEG or WebP file in the workspace (for example one you just generated), or an asset id already used by the current theme.",
|
|
28
|
+
};
|
|
29
|
+
const imagesSchema = {
|
|
30
|
+
type: "object",
|
|
31
|
+
description: "Optional images, by slot. Call get_theme_schema for what each slot is and its options.",
|
|
32
|
+
properties: {
|
|
33
|
+
conversation: {
|
|
34
|
+
type: "object",
|
|
35
|
+
properties: {
|
|
36
|
+
image: imageRef,
|
|
37
|
+
fit: { type: "string", enum: ["cover", "contain", "tile"] },
|
|
38
|
+
anchor: { type: "string", enum: ["top-left", "top", "top-right", "left", "center", "right", "bottom-left", "bottom", "bottom-right"] },
|
|
39
|
+
scrim: { type: "number", minimum: 0.5, maximum: 0.95 },
|
|
40
|
+
blend: { type: "string", enum: ["normal", "multiply", "screen", "luminosity", "soft-light"] },
|
|
41
|
+
dark: { type: "object", properties: { image: imageRef, scrim: { type: "number", minimum: 0.5, maximum: 0.95 } } },
|
|
42
|
+
},
|
|
43
|
+
required: ["image"],
|
|
44
|
+
},
|
|
45
|
+
empty: {
|
|
46
|
+
type: "object",
|
|
47
|
+
properties: { image: imageRef, size: { type: "string", enum: ["small", "medium", "large"] }, align: { type: "string", enum: ["left", "center"] } },
|
|
48
|
+
required: ["image"],
|
|
49
|
+
},
|
|
50
|
+
avatar: {
|
|
51
|
+
type: "object",
|
|
52
|
+
properties: { image: imageRef, shape: { type: "string", enum: ["circle", "rounded", "square"] } },
|
|
53
|
+
required: ["image"],
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
additionalProperties: false,
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Turn every `image` the model named into a stored asset, in place, as
|
|
60
|
+
* `asset`. A file outside what the agent may read is refused by the same
|
|
61
|
+
* policy that guards its other tools; a file that is not a still image is
|
|
62
|
+
* refused by its bytes. Either way the slot is dropped and the reason is
|
|
63
|
+
* reported, and the rest of the theme still goes through.
|
|
64
|
+
*/
|
|
65
|
+
async function importImages(input, ctx) {
|
|
66
|
+
const problems = [];
|
|
67
|
+
if (typeof input !== "object" || input === null)
|
|
68
|
+
return { input, problems };
|
|
69
|
+
const copy = structuredClone(input);
|
|
70
|
+
const images = copy["images"];
|
|
71
|
+
if (typeof images !== "object" || images === null)
|
|
72
|
+
return { input: copy, problems };
|
|
73
|
+
const toAsset = async (where, slot) => {
|
|
74
|
+
// `asset` too: get_theme_schema shows the theme in use as stored, where
|
|
75
|
+
// an image is an asset id under that name, and a model revising it copies
|
|
76
|
+
// what it was shown.
|
|
77
|
+
const ref = slot["image"] ?? slot["asset"];
|
|
78
|
+
delete slot["image"];
|
|
79
|
+
delete slot["asset"];
|
|
80
|
+
if (typeof ref !== "string" || !ref.trim()) {
|
|
81
|
+
problems.push(`images.${where}: no image given`);
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
if (ASSET_ID.test(ref)) {
|
|
85
|
+
if (await assetExists(ref)) {
|
|
86
|
+
slot["asset"] = ref;
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
problems.push(`images.${where}: no stored asset ${ref}`);
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
let file;
|
|
93
|
+
try {
|
|
94
|
+
file = ctx.host?.resolvePath ? ctx.host.resolvePath(ref, "read") : path.resolve(ctx.cwd, ref);
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
problems.push(`images.${where}: ${err instanceof Error ? err.message : String(err)}`);
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
const imported = await importAsset(file);
|
|
101
|
+
if (!imported.ok) {
|
|
102
|
+
problems.push(`images.${where}: ${imported.error}`);
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
slot["asset"] = imported.id;
|
|
106
|
+
return true;
|
|
107
|
+
};
|
|
108
|
+
for (const [name, value] of Object.entries(images)) {
|
|
109
|
+
if (typeof value !== "object" || value === null)
|
|
110
|
+
continue;
|
|
111
|
+
const slot = value;
|
|
112
|
+
if (!(await toAsset(name, slot))) {
|
|
113
|
+
delete images[name];
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
const dark = slot["dark"];
|
|
117
|
+
if (typeof dark === "object" && dark !== null && "image" in dark) {
|
|
118
|
+
if (!(await toAsset(`${name}.dark`, dark)))
|
|
119
|
+
delete dark["asset"];
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return { input: copy, problems };
|
|
123
|
+
}
|
|
124
|
+
export function createThemeTools(host) {
|
|
125
|
+
const schemaTool = {
|
|
126
|
+
name: GET_THEME_SCHEMA_TOOL,
|
|
127
|
+
description: "Describe what the app's colour theme can change: the tokens, what each colours, the rules a theme must follow, and the theme in use now. Call this before set_theme.",
|
|
128
|
+
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
129
|
+
readOnly: true,
|
|
130
|
+
source: "builtin",
|
|
131
|
+
renderTitle: () => "Theme schema",
|
|
132
|
+
async execute() {
|
|
133
|
+
return toolText(schemaText(host.activeInput()));
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
const setTool = {
|
|
137
|
+
name: SET_THEME_TOOL,
|
|
138
|
+
description: [
|
|
139
|
+
"Propose a theme for this app's interface: colours, and optionally images in fixed slots (conversation background, empty-session art, assistant avatar). It is shown to the user as a preview card and is NOT applied until they click Apply.",
|
|
140
|
+
"Give the four seeds (bg, fg, accent, brand) for each side you change; everything else is derived from them. Override any other token only when the user asked for something specific.",
|
|
141
|
+
"Colours are hex only. Text colours that fail contrast are adjusted, and the result says what moved.",
|
|
142
|
+
"For an image, generate or find a PNG, JPEG or WebP file first and pass its path. Pick seed colours that suit the image.",
|
|
143
|
+
"Use only for the app's own look. Call get_theme_schema first.",
|
|
144
|
+
].join(" "),
|
|
145
|
+
inputSchema: {
|
|
146
|
+
type: "object",
|
|
147
|
+
properties: {
|
|
148
|
+
name: { type: "string", description: "A short name for the theme, e.g. \"Ember\"." },
|
|
149
|
+
mode: {
|
|
150
|
+
type: "string",
|
|
151
|
+
enum: ["both", "light", "dark"],
|
|
152
|
+
description: "both (default): follows the system and the light/dark switch. light or dark: always that side.",
|
|
153
|
+
},
|
|
154
|
+
light: paletteSchema,
|
|
155
|
+
dark: paletteSchema,
|
|
156
|
+
images: imagesSchema,
|
|
157
|
+
},
|
|
158
|
+
required: ["name"],
|
|
159
|
+
additionalProperties: false,
|
|
160
|
+
},
|
|
161
|
+
// Changes nothing by itself: see the header.
|
|
162
|
+
readOnly: true,
|
|
163
|
+
concurrencySafe: false,
|
|
164
|
+
source: "builtin",
|
|
165
|
+
renderTitle: (input) => {
|
|
166
|
+
const name = typeof input === "object" && input && typeof input.name === "string"
|
|
167
|
+
? input.name
|
|
168
|
+
: "";
|
|
169
|
+
return name ? `Theme(${name})` : "Theme";
|
|
170
|
+
},
|
|
171
|
+
async execute(input, ctx) {
|
|
172
|
+
const imported = await importImages(input, ctx);
|
|
173
|
+
const result = resolveTheme(imported.input);
|
|
174
|
+
if (!result.ok) {
|
|
175
|
+
const why = [result.error, ...imported.problems].join("; ");
|
|
176
|
+
return toolError(`The theme was not accepted: ${why}. Call get_theme_schema for the format.`);
|
|
177
|
+
}
|
|
178
|
+
result.theme.report.dropped.unshift(...imported.problems);
|
|
179
|
+
const id = host.propose(ctx.sessionId, result.theme);
|
|
180
|
+
return toolText([
|
|
181
|
+
`A preview card for "${result.theme.input.name}" now follows your reply in the conversation. It is not applied: the user previews, applies or discards it from that card. Do not say the theme has changed, and do not say where on screen the card is.`,
|
|
182
|
+
describeReport(result.theme.report),
|
|
183
|
+
].join("\n\n"), { themePreview: id });
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
/*
|
|
187
|
+
* The one theme tool that changes something by itself, and the reason it
|
|
188
|
+
* may: going back to the built-in look cannot make the app unreadable, and
|
|
189
|
+
* it is one click to undo from the account menu. Asking for approval to
|
|
190
|
+
* undo a theme the person wants gone would only stand in their way.
|
|
191
|
+
*/
|
|
192
|
+
const resetTool = {
|
|
193
|
+
name: RESET_THEME_TOOL,
|
|
194
|
+
description: "Put the app back on its built-in theme, removing any custom colours and images. Use when the user asks to reset, restore the default look, or remove a custom theme. It takes effect at once and can be undone from the account menu.",
|
|
195
|
+
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
196
|
+
readOnly: true,
|
|
197
|
+
concurrencySafe: false,
|
|
198
|
+
source: "builtin",
|
|
199
|
+
renderTitle: () => "Reset theme",
|
|
200
|
+
async execute() {
|
|
201
|
+
const was = await host.reset();
|
|
202
|
+
return toolText(was
|
|
203
|
+
? `The built-in theme is back; "${was}" is no longer applied. The user can undo this from the account menu.`
|
|
204
|
+
: "The built-in theme was already in use; nothing changed.");
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
return [schemaTool, setTool, resetTool];
|
|
208
|
+
}
|
|
209
|
+
function schemaText(active) {
|
|
210
|
+
const tokens = Object.entries(TOKENS)
|
|
211
|
+
.map(([token, meaning]) => `- ${token}: ${meaning} Built-in: light ${LIGHT[token]}, dark ${DARK[token]}.`)
|
|
212
|
+
.join("\n");
|
|
213
|
+
return [
|
|
214
|
+
"The interface is coloured by a set of tokens with a light and a dark value each. A theme sets some of them; set_theme derives the rest.",
|
|
215
|
+
"",
|
|
216
|
+
`Seeds: ${SEEDS.join(", ")}. Give all four for each side you change. panel, frame, dim, line, hover, sel, field, track, focus, ring, brand-tint and brand-ink are derived from them; the status and syntax colours keep their built-in values unless set.`,
|
|
217
|
+
"",
|
|
218
|
+
"Rules:",
|
|
219
|
+
"- Values are hex colours. Seeds must be opaque.",
|
|
220
|
+
"- light describes the light side and dark the dark side. mode \"both\" keeps the system and the user's light/dark switch working; a side you leave out keeps the built-in palette.",
|
|
221
|
+
"- Text pairs are held to contrast (4.5:1 for text, 3:1 for marks) and moved if they fail; prefer colours that already pass.",
|
|
222
|
+
"- Colours and the image slots below are all that can change: not layout, size, fonts or which elements show.",
|
|
223
|
+
"",
|
|
224
|
+
"Tokens:",
|
|
225
|
+
tokens,
|
|
226
|
+
"",
|
|
227
|
+
"Image slots (optional, under \"images\"; each takes an \"image\": a workspace path to a PNG, JPEG or WebP, or an asset id from the current theme):",
|
|
228
|
+
...Object.entries(IMAGE_SLOTS).map(([slot, about]) => `- ${slot}: ${about}`),
|
|
229
|
+
"Images are copied into the theme when proposed; SVG, GIF and animated images are refused. The page decides where each slot is drawn and keeps text over the conversation background readable.",
|
|
230
|
+
"",
|
|
231
|
+
active ? `Theme in use now:\n${JSON.stringify(active, null, 2)}` : "Theme in use now: the built-in one.",
|
|
232
|
+
"",
|
|
233
|
+
"Example:",
|
|
234
|
+
JSON.stringify({
|
|
235
|
+
name: "Ember",
|
|
236
|
+
mode: "both",
|
|
237
|
+
light: { bg: "#fffaf5", fg: "#1c1410", accent: "#3a1d0e", brand: "#c25300" },
|
|
238
|
+
dark: { bg: "#120c09", fg: "#f3e9e1", accent: "#f3e9e1", brand: "#ff8a3d" },
|
|
239
|
+
images: { conversation: { image: "./ember-wall.png", fit: "cover", scrim: 0.82 }, avatar: { image: "./ember-avatar.png" } },
|
|
240
|
+
}),
|
|
241
|
+
].join("\n");
|
|
242
|
+
}
|
|
243
|
+
//# sourceMappingURL=theme-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme-tools.js","sourceRoot":"","sources":["../src/theme-tools.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAGrG;;;;;;;;;;GAUG;AAEH,MAAM,CAAC,MAAM,qBAAqB,GAAG,kBAAkB,CAAC;AACxD,MAAM,CAAC,MAAM,cAAc,GAAG,WAAW,CAAC;AAC1C,MAAM,CAAC,MAAM,gBAAgB,GAAG,aAAa,CAAC;AAW9C,MAAM,aAAa,GAAG;IACpB,IAAI,EAAE,QAAQ;IACd,WAAW,EAAE,6EAA6E;IAC1F,oBAAoB,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;CAChC,CAAC;AAEX,MAAM,QAAQ,GAAG;IACf,IAAI,EAAE,QAAQ;IACd,WAAW,EAAE,2IAA2I;CAChJ,CAAC;AAEX,MAAM,YAAY,GAAG;IACnB,IAAI,EAAE,QAAQ;IACd,WAAW,EAAE,wFAAwF;IACrG,UAAU,EAAE;QACV,YAAY,EAAE;YACZ,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,KAAK,EAAE,QAAQ;gBACf,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE;gBAC3D,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,UAAU,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,cAAc,CAAC,EAAE;gBACtI,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE;gBACtD,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,YAAY,CAAC,EAAE;gBAC7F,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE;aAClH;YACD,QAAQ,EAAE,CAAC,OAAO,CAAC;SACpB;QACD,KAAK,EAAE;YACL,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,EAAE;YAClJ,QAAQ,EAAE,CAAC,OAAO,CAAC;SACpB;QACD,MAAM,EAAE;YACN,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,EAAE;YACjG,QAAQ,EAAE,CAAC,OAAO,CAAC;SACpB;KACF;IACD,oBAAoB,EAAE,KAAK;CACnB,CAAC;AAEX;;;;;;GAMG;AACH,KAAK,UAAU,YAAY,CAAC,KAAc,EAAE,GAAgB;IAC1D,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;IAC5E,MAAM,IAAI,GAAG,eAAe,CAAC,KAAK,CAA4B,CAAC;IAC/D,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC9B,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IAEpF,MAAM,OAAO,GAAG,KAAK,EAAE,KAAa,EAAE,IAA6B,EAAoB,EAAE;QACvF,wEAAwE;QACxE,0EAA0E;QAC1E,qBAAqB;QACrB,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC;QAC3C,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC;QACrB,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;YAC3C,QAAQ,CAAC,IAAI,CAAC,UAAU,KAAK,kBAAkB,CAAC,CAAC;YACjD,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACvB,IAAI,MAAM,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC3B,IAAI,CAAC,OAAO,CAAC,GAAG,GAAG,CAAC;gBACpB,OAAO,IAAI,CAAC;YACd,CAAC;YACD,QAAQ,CAAC,IAAI,CAAC,UAAU,KAAK,qBAAqB,GAAG,EAAE,CAAC,CAAC;YACzD,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,IAAY,CAAC;QACjB,IAAI,CAAC;YACH,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAChG,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,QAAQ,CAAC,IAAI,CAAC,UAAU,KAAK,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACtF,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,CAAC;QACzC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,QAAQ,CAAC,IAAI,CAAC,UAAU,KAAK,KAAK,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;YACpD,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC;QAC5B,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;IAEF,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAiC,CAAC,EAAE,CAAC;QAC9E,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;YAAE,SAAS;QAC1D,MAAM,IAAI,GAAG,KAAgC,CAAC;QAC9C,IAAI,CAAC,CAAC,MAAM,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC;YACjC,OAAQ,MAAkC,CAAC,IAAI,CAAC,CAAC;YACjD,SAAS;QACX,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;QAC1B,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;YACjE,IAAI,CAAC,CAAC,MAAM,OAAO,CAAC,GAAG,IAAI,OAAO,EAAE,IAA+B,CAAC,CAAC;gBAAE,OAAQ,IAAgC,CAAC,OAAO,CAAC,CAAC;QAC3H,CAAC;IACH,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAmB;IAClD,MAAM,UAAU,GAAS;QACvB,IAAI,EAAE,qBAAqB;QAC3B,WAAW,EACT,sKAAsK;QACxK,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE,oBAAoB,EAAE,KAAK,EAAE;QAC5E,QAAQ,EAAE,IAAI;QACd,MAAM,EAAE,SAAS;QACjB,WAAW,EAAE,GAAG,EAAE,CAAC,cAAc;QACjC,KAAK,CAAC,OAAO;YACX,OAAO,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QAClD,CAAC;KACF,CAAC;IAEF,MAAM,OAAO,GAAS;QACpB,IAAI,EAAE,cAAc;QACpB,WAAW,EAAE;YACX,8OAA8O;YAC9O,uLAAuL;YACvL,qGAAqG;YACrG,yHAAyH;YACzH,+DAA+D;SAChE,CAAC,IAAI,CAAC,GAAG,CAAC;QACX,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,6CAA6C,EAAE;gBACpF,IAAI,EAAE;oBACJ,IAAI,EAAE,QAAQ;oBACd,IAAI,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC;oBAC/B,WAAW,EAAE,gGAAgG;iBAC9G;gBACD,KAAK,EAAE,aAAa;gBACpB,IAAI,EAAE,aAAa;gBACnB,MAAM,EAAE,YAAY;aACrB;YACD,QAAQ,EAAE,CAAC,MAAM,CAAC;YAClB,oBAAoB,EAAE,KAAK;SAC5B;QACD,6CAA6C;QAC7C,QAAQ,EAAE,IAAI;QACd,eAAe,EAAE,KAAK;QACtB,MAAM,EAAE,SAAS;QACjB,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE;YACrB,MAAM,IAAI,GAAG,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,IAAI,OAAQ,KAA4B,CAAC,IAAI,KAAK,QAAQ;gBACvG,CAAC,CAAE,KAA0B,CAAC,IAAI;gBAClC,CAAC,CAAC,EAAE,CAAC;YACP,OAAO,IAAI,CAAC,CAAC,CAAC,SAAS,IAAI,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC;QAC3C,CAAC;QACD,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG;YACtB,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YAChD,MAAM,MAAM,GAAG,YAAY,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;YAC5C,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;gBACf,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC5D,OAAO,SAAS,CAAC,+BAA+B,GAAG,yCAAyC,CAAC,CAAC;YAChG,CAAC;YACD,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;YAC1D,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;YACrD,OAAO,QAAQ,CACb;gBACE,uBAAuB,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,0MAA0M;gBACxP,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;aACpC,CAAC,IAAI,CAAC,MAAM,CAAC,EACd,EAAE,YAAY,EAAE,EAAE,EAAE,CACrB,CAAC;QACJ,CAAC;KACF,CAAC;IAEF;;;;;OAKG;IACH,MAAM,SAAS,GAAS;QACtB,IAAI,EAAE,gBAAgB;QACtB,WAAW,EACT,uOAAuO;QACzO,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE,oBAAoB,EAAE,KAAK,EAAE;QAC5E,QAAQ,EAAE,IAAI;QACd,eAAe,EAAE,KAAK;QACtB,MAAM,EAAE,SAAS;QACjB,WAAW,EAAE,GAAG,EAAE,CAAC,aAAa;QAChC,KAAK,CAAC,OAAO;YACX,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;YAC/B,OAAO,QAAQ,CACb,GAAG;gBACD,CAAC,CAAC,gCAAgC,GAAG,uEAAuE;gBAC5G,CAAC,CAAC,yDAAyD,CAC9D,CAAC;QACJ,CAAC;KACF,CAAC;IAEF,OAAO,CAAC,UAAU,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;AAC1C,CAAC;AAED,SAAS,UAAU,CAAC,MAA8B;IAChD,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;SAClC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,KAAK,KAAK,KAAK,OAAO,oBAAoB,KAAK,CAAC,KAAK,CAAC,UAAU,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;SACzG,IAAI,CAAC,IAAI,CAAC,CAAC;IACd,OAAO;QACL,yIAAyI;QACzI,EAAE;QACF,UAAU,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,gOAAgO;QAC1P,EAAE;QACF,QAAQ;QACR,iDAAiD;QACjD,oLAAoL;QACpL,6HAA6H;QAC7H,8GAA8G;QAC9G,EAAE;QACF,SAAS;QACT,MAAM;QACN,EAAE;QACF,oJAAoJ;QACpJ,GAAG,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,IAAI,KAAK,KAAK,EAAE,CAAC;QAC5E,+LAA+L;QAC/L,EAAE;QACF,MAAM,CAAC,CAAC,CAAC,sBAAsB,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,qCAAqC;QACxG,EAAE;QACF,UAAU;QACV,IAAI,CAAC,SAAS,CAAC;YACb,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,MAAM;YACZ,KAAK,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE;YAC5E,IAAI,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE;YAC3E,MAAM,EAAE,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,kBAAkB,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,oBAAoB,EAAE,EAAE;SAC5H,CAAC;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code's and Codex's app icons, for the rows that bring in what those
|
|
3
|
+
* two tools already have.
|
|
4
|
+
*
|
|
5
|
+
* Their own marks rather than their companies': a row that says "Import from
|
|
6
|
+
* Claude Code" next to Anthropic's logo is naming one thing and showing
|
|
7
|
+
* another. Taken from the apps themselves — Claude's from Claude.app, and for
|
|
8
|
+
* Codex the ChatGPT mark from ChatGPT.app — cropped to the tile and scaled
|
|
9
|
+
* to 64px, which covers the 16px menu glyph at four times. Inline, because
|
|
10
|
+
* the build copies TypeScript and nothing beside it.
|
|
11
|
+
*/
|
|
12
|
+
export declare const TOOL_ICONS: Record<string, string>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code's and Codex's app icons, for the rows that bring in what those
|
|
3
|
+
* two tools already have.
|
|
4
|
+
*
|
|
5
|
+
* Their own marks rather than their companies': a row that says "Import from
|
|
6
|
+
* Claude Code" next to Anthropic's logo is naming one thing and showing
|
|
7
|
+
* another. Taken from the apps themselves — Claude's from Claude.app, and for
|
|
8
|
+
* Codex the ChatGPT mark from ChatGPT.app — cropped to the tile and scaled
|
|
9
|
+
* to 64px, which covers the 16px menu glyph at four times. Inline, because
|
|
10
|
+
* the build copies TypeScript and nothing beside it.
|
|
11
|
+
*/
|
|
12
|
+
export const TOOL_ICONS = {
|
|
13
|
+
claude: "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",
|
|
14
|
+
codex: "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",
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=tool-icons.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-icons.js","sourceRoot":"","sources":["../src/tool-icons.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,UAAU,GAA2B;IAChD,MAAM,EAAE,k+WAAk+W;IAC1+W,KAAK,EAAE,84UAA84U;CACt5U,CAAC"}
|
package/dist/turn-shots.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { ComputerSnapshotEvent } from "@oharness/engine/computer/session.ts";
|
|
2
1
|
/**
|
|
3
2
|
* The windows a Computer use turn left behind, as the person saw them.
|
|
4
3
|
*
|
|
@@ -14,11 +13,28 @@ import type { ComputerSnapshotEvent } from "@oharness/engine/computer/session.ts
|
|
|
14
13
|
*/
|
|
15
14
|
export interface TurnShot {
|
|
16
15
|
at: number;
|
|
16
|
+
/** The app the window belongs to; for a browser tab, the site's host. */
|
|
17
17
|
app: string;
|
|
18
18
|
title?: string;
|
|
19
|
+
/** Absent for a Computer use window. */
|
|
20
|
+
kind?: "browser";
|
|
19
21
|
file: string;
|
|
20
22
|
}
|
|
21
|
-
|
|
23
|
+
/** One picture to keep: base64 JPEG and what it shows. */
|
|
24
|
+
export interface TurnShotInput {
|
|
25
|
+
app: string;
|
|
26
|
+
title?: string;
|
|
27
|
+
kind?: "browser";
|
|
28
|
+
data: string;
|
|
29
|
+
}
|
|
30
|
+
/** A kept picture as the page draws it. */
|
|
31
|
+
export declare function turnShotView(session: string, shot: TurnShot): {
|
|
32
|
+
app: string;
|
|
33
|
+
title?: string;
|
|
34
|
+
kind?: "browser";
|
|
35
|
+
src: string;
|
|
36
|
+
};
|
|
37
|
+
export declare function saveTurnShots(session: string, at: number, shots: readonly TurnShotInput[]): Promise<TurnShot[]>;
|
|
22
38
|
/** Synchronous: the transcript is flattened synchronously, and this file is a few lines. */
|
|
23
39
|
export declare function listTurnShots(session: string): TurnShot[];
|
|
24
40
|
/** The bytes of one picture, or nothing for a name that is not one of ours. */
|
package/dist/turn-shots.js
CHANGED
|
@@ -2,6 +2,15 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
2
2
|
import { appendFile, mkdir, rm, writeFile } from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { userPath } from "@oharness/engine/paths.ts";
|
|
5
|
+
/** A kept picture as the page draws it. */
|
|
6
|
+
export function turnShotView(session, shot) {
|
|
7
|
+
return {
|
|
8
|
+
app: shot.app,
|
|
9
|
+
...(shot.title ? { title: shot.title } : {}),
|
|
10
|
+
...(shot.kind ? { kind: shot.kind } : {}),
|
|
11
|
+
src: turnShotSrc(session, shot.file),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
5
14
|
function dir(session) {
|
|
6
15
|
// Session ids are the store's own (date_hex), but the id also arrives on a
|
|
7
16
|
// URL: anything that could climb out of the directory is refused.
|
|
@@ -17,7 +26,7 @@ export async function saveTurnShots(session, at, shots) {
|
|
|
17
26
|
for (const [index, shot] of shots.entries()) {
|
|
18
27
|
const file = `${at}-${stamp}-${index}.jpg`;
|
|
19
28
|
await writeFile(path.join(root, file), Buffer.from(shot.data, "base64"));
|
|
20
|
-
saved.push({ at, app: shot.app, ...(shot.title ? { title: shot.title } : {}), file });
|
|
29
|
+
saved.push({ at, app: shot.app, ...(shot.title ? { title: shot.title } : {}), ...(shot.kind ? { kind: shot.kind } : {}), file });
|
|
21
30
|
}
|
|
22
31
|
await appendFile(path.join(root, "index.jsonl"), saved.map((one) => JSON.stringify(one) + "\n").join(""));
|
|
23
32
|
return saved;
|
package/dist/turn-shots.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"turn-shots.js","sourceRoot":"","sources":["../src/turn-shots.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"turn-shots.js","sourceRoot":"","sources":["../src/turn-shots.ts"],"names":[],"mappings":"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"}
|