@tiagojct/subsub 0.20.0 → 0.22.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/CHANGELOG.md +21 -0
- package/README.md +8 -1
- package/dist/chrome.js +171 -0
- package/dist/cli.js +10 -0
- package/dist/config.js +2 -0
- package/dist/dialogs.js +81 -0
- package/dist/files.js +66 -0
- package/dist/look.js +36 -17
- package/dist/rpc.js +185 -0
- package/dist/screens.js +425 -0
- package/dist/skin.js +37 -0
- package/dist/subsub.js +198 -31
- package/dist/tui-view.js +228 -0
- package/dist/tui.js +651 -0
- package/dist/web.js +16 -216
- package/dist/words.js +26 -0
- package/package.json +1 -1
- package/scripts/make-themes.mjs +112 -0
- package/scripts/plate.json +35 -0
- package/src/chrome.ts +208 -0
- package/src/cli.ts +9 -0
- package/src/config.ts +4 -0
- package/src/dialogs.ts +107 -0
- package/src/files.ts +66 -0
- package/src/look.ts +45 -18
- package/src/rpc.ts +198 -0
- package/src/screens.ts +530 -0
- package/src/skin.ts +65 -0
- package/src/subsub.ts +214 -36
- package/src/tui-view.ts +270 -0
- package/src/tui.ts +710 -0
- package/src/web.ts +14 -209
- package/src/words.ts +40 -0
- package/themes/subsub-glauca-dark-256.json +80 -0
- package/themes/subsub-glauca-dark.json +73 -77
- package/themes/subsub-glauca-light-256.json +80 -0
- package/themes/subsub-glauca-light.json +73 -77
- package/themes/subsub-try-works-dark-256.json +80 -0
- package/themes/subsub-try-works-dark.json +73 -77
- package/themes/subsub-try-works-light-256.json +80 -0
- package/themes/subsub-try-works-light.json +73 -77
- package/scripts/make-themes.py +0 -116
package/src/web.ts
CHANGED
|
@@ -14,20 +14,15 @@
|
|
|
14
14
|
* stops by itself, so a shortcut can start it without a terminal.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import { spawn, type ChildProcess } from "node:child_process";
|
|
18
17
|
import { randomBytes, timingSafeEqual } from "node:crypto";
|
|
19
18
|
import { createReadStream, existsSync, mkdirSync, readdirSync, readFileSync, renameSync, statSync, writeFileSync, appendFileSync } from "node:fs";
|
|
20
19
|
import { createServer, type IncomingMessage, type Server, type ServerResponse } from "node:http";
|
|
21
20
|
import { homedir } from "node:os";
|
|
22
21
|
import { basename, dirname, extname, join, normalize, relative, resolve, sep } from "node:path";
|
|
23
|
-
import { StringDecoder } from "node:string_decoder";
|
|
24
22
|
import { agentDirFor, chooseCwd, PACKAGE_DIR, packageVersion } from "./cli.ts";
|
|
25
|
-
import { configPath,
|
|
23
|
+
import { configPath, loadConfig, RECOMMENDED_MODELS, readConfigFile, saveConfig, type SubsubConfig, uiLanguage, withStarbuck } from "./config.ts";
|
|
26
24
|
import { TESTED_MODELS } from "./init.ts";
|
|
27
25
|
import { KEY_PROVIDERS, saveApiKey } from "./keys.ts";
|
|
28
|
-
import { NOTE_DIRS, obsidianRoot, SETTINGS_DIR } from "./layout.ts";
|
|
29
|
-
import { field, frontMatter } from "./notes.ts";
|
|
30
|
-
import { realish, within } from "./paths.ts";
|
|
31
26
|
|
|
32
27
|
// ---------------------------------------------------------------- options
|
|
33
28
|
|
|
@@ -63,130 +58,15 @@ export { uiLanguage } from "./config.ts";
|
|
|
63
58
|
|
|
64
59
|
export { KEY_PROVIDERS, saveApiKey } from "./keys.ts";
|
|
65
60
|
|
|
66
|
-
// ----------------------------------------------------------------
|
|
67
|
-
|
|
68
|
-
type Listener = (ev: any) => void;
|
|
69
|
-
|
|
70
|
-
/** pi as a child process in RPC mode. Strict JSONL: records end at LF only. */
|
|
71
|
-
export class Agent {
|
|
72
|
-
proc?: ChildProcess;
|
|
73
|
-
private decoder = new StringDecoder("utf8");
|
|
74
|
-
private buf = "";
|
|
75
|
-
private n = 0;
|
|
76
|
-
private pending = new Map<string, { resolve: (v: any) => void; reject: (e: Error) => void; timer: NodeJS.Timeout }>();
|
|
77
|
-
private listeners = new Set<Listener>();
|
|
78
|
-
stderr = "";
|
|
79
|
-
onExit?: (code: number | null) => void;
|
|
80
|
-
|
|
81
|
-
private readonly command: string;
|
|
82
|
-
private readonly args: string[];
|
|
83
|
-
private readonly cwd: string;
|
|
84
|
-
private readonly env: NodeJS.ProcessEnv;
|
|
85
|
-
|
|
86
|
-
constructor(command: string, args: string[], cwd: string, env: NodeJS.ProcessEnv) {
|
|
87
|
-
this.command = command;
|
|
88
|
-
this.args = args;
|
|
89
|
-
this.cwd = cwd;
|
|
90
|
-
this.env = env;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
start(extra: string[] = []): void {
|
|
94
|
-
this.buf = "";
|
|
95
|
-
this.decoder = new StringDecoder("utf8");
|
|
96
|
-
const proc = spawn(this.command, [...this.args, ...extra], { cwd: this.cwd, env: this.env, stdio: ["pipe", "pipe", "pipe"], windowsHide: true });
|
|
97
|
-
this.proc = proc;
|
|
98
|
-
proc.stdout!.on("data", (chunk: Buffer) => this.feed(this.decoder.write(chunk)));
|
|
99
|
-
proc.stderr!.on("data", (d: Buffer) => {
|
|
100
|
-
this.stderr = (this.stderr + d.toString()).slice(-20_000);
|
|
101
|
-
});
|
|
102
|
-
proc.once("exit", (code) => {
|
|
103
|
-
if (this.proc !== proc) return;
|
|
104
|
-
this.proc = undefined;
|
|
105
|
-
for (const p of this.pending.values()) {
|
|
106
|
-
clearTimeout(p.timer);
|
|
107
|
-
p.reject(new Error(`pi stopped (code ${code}). ${this.stderr.slice(-500)}`));
|
|
108
|
-
}
|
|
109
|
-
this.pending.clear();
|
|
110
|
-
this.onExit?.(code);
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
private feed(text: string): void {
|
|
115
|
-
this.buf += text;
|
|
116
|
-
let i: number;
|
|
117
|
-
while ((i = this.buf.indexOf("\n")) >= 0) {
|
|
118
|
-
const line = this.buf.slice(0, i).replace(/\r$/, "");
|
|
119
|
-
this.buf = this.buf.slice(i + 1);
|
|
120
|
-
if (!line.trim()) continue;
|
|
121
|
-
let rec: any;
|
|
122
|
-
try {
|
|
123
|
-
rec = JSON.parse(line);
|
|
124
|
-
} catch {
|
|
125
|
-
continue;
|
|
126
|
-
}
|
|
127
|
-
if (rec.type === "response" && typeof rec.id === "string" && this.pending.has(rec.id)) {
|
|
128
|
-
const p = this.pending.get(rec.id)!;
|
|
129
|
-
this.pending.delete(rec.id);
|
|
130
|
-
clearTimeout(p.timer);
|
|
131
|
-
if (rec.success === false) p.reject(new Error(rec.error ?? `${rec.command} failed`));
|
|
132
|
-
else p.resolve(rec.data);
|
|
133
|
-
continue;
|
|
134
|
-
}
|
|
135
|
-
for (const l of this.listeners) l(rec);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
61
|
+
// ---------------------------------------------------------------- files (shared with the terminal screens)
|
|
138
62
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
return () => this.listeners.delete(l);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
write(rec: unknown): void {
|
|
145
|
-
const stdin = this.proc?.stdin;
|
|
146
|
-
if (!stdin || !stdin.writable) throw new Error("pi is not running");
|
|
147
|
-
stdin.write(`${JSON.stringify(rec)}\n`);
|
|
148
|
-
}
|
|
63
|
+
import { allowedFile, listNotes, openExternal, openFile, OPENABLE, wikilinkTarget } from "./files.ts";
|
|
64
|
+
export { allowedFile, listNotes, openExternal, OPENABLE, wikilinkTarget };
|
|
149
65
|
|
|
150
|
-
|
|
151
|
-
const id = `w${++this.n}`;
|
|
152
|
-
return new Promise<T>((resolvePromise, reject) => {
|
|
153
|
-
const timer = setTimeout(() => {
|
|
154
|
-
this.pending.delete(id);
|
|
155
|
-
reject(new Error(`pi did not answer ${String(cmd.type)} in time`));
|
|
156
|
-
}, timeoutMs);
|
|
157
|
-
this.pending.set(id, { resolve: resolvePromise, reject, timer });
|
|
158
|
-
try {
|
|
159
|
-
this.write({ ...cmd, id });
|
|
160
|
-
} catch (err) {
|
|
161
|
-
clearTimeout(timer);
|
|
162
|
-
this.pending.delete(id);
|
|
163
|
-
reject(err as Error);
|
|
164
|
-
}
|
|
165
|
-
});
|
|
166
|
-
}
|
|
66
|
+
// ---------------------------------------------------------------- pi in RPC mode (src/rpc.ts)
|
|
167
67
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
if (!proc) return;
|
|
171
|
-
this.proc = undefined;
|
|
172
|
-
for (const p of this.pending.values()) {
|
|
173
|
-
clearTimeout(p.timer);
|
|
174
|
-
p.reject(new Error("pi was stopped"));
|
|
175
|
-
}
|
|
176
|
-
this.pending.clear();
|
|
177
|
-
await new Promise<void>((done) => {
|
|
178
|
-
const t = setTimeout(() => {
|
|
179
|
-
proc.kill("SIGKILL");
|
|
180
|
-
done();
|
|
181
|
-
}, 3000);
|
|
182
|
-
proc.once("exit", () => {
|
|
183
|
-
clearTimeout(t);
|
|
184
|
-
done();
|
|
185
|
-
});
|
|
186
|
-
proc.kill();
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
}
|
|
68
|
+
import { Agent, findLibrary, isDialog, Side, withHints } from "./rpc.ts";
|
|
69
|
+
export { Agent };
|
|
190
70
|
|
|
191
71
|
// ---------------------------------------------------------------- helpers
|
|
192
72
|
|
|
@@ -206,43 +86,6 @@ const NOTE_TYPES = new Set([".md", ".markdown"]);
|
|
|
206
86
|
/** Images that a note shows (a figure cut out of a PDF, for example). */
|
|
207
87
|
const IMAGE_TYPES: Record<string, string> = { ".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".gif": "image/gif", ".webp": "image/webp" };
|
|
208
88
|
|
|
209
|
-
/** Files that the Open button may hand to the system (never programs or scripts). */
|
|
210
|
-
export const OPENABLE = new Set([".md", ".markdown", ".txt", ".pdf", ".bib", ".csv", ".qmd"]);
|
|
211
|
-
|
|
212
|
-
/** A file inside the working folder or the Sub-Sub folder, judged by its real path, so a link cannot point outside. */
|
|
213
|
-
export function allowedFile(raw: string, cwd: string, vault?: string): string | undefined {
|
|
214
|
-
// expand() resolves against the process folder: use it for "~" only.
|
|
215
|
-
const target = resolve(cwd, raw.startsWith("~") ? expand(raw) : raw);
|
|
216
|
-
const real = realish(target);
|
|
217
|
-
const inside = within(real, realish(cwd)) || Boolean(vault && within(real, realish(vault)));
|
|
218
|
-
return inside && existsSync(target) && statSync(target).isFile() ? target : undefined;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
/** The note a [[wikilink]] names: the first <folder>/<name>.md in the Sub-Sub folder, as Obsidian would find it. */
|
|
222
|
-
export function wikilinkTarget(name: string, root: string): string | undefined {
|
|
223
|
-
const file = name.endsWith(".md") ? name : `${name}.md`;
|
|
224
|
-
return ["", ...NOTE_DIRS, SETTINGS_DIR].map((d) => join(root, d, file)).find((f) => existsSync(f));
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/** The notes in the Sub-Sub folders, newest first (dot folders such as Research/.plans left out). */
|
|
228
|
-
export function listNotes(root: string, max = 300): Array<{ path: string; rel: string; modified: number }> {
|
|
229
|
-
const out: Array<{ path: string; rel: string; modified: number }> = [];
|
|
230
|
-
for (const d of [...NOTE_DIRS, SETTINGS_DIR]) {
|
|
231
|
-
let names: string[] = [];
|
|
232
|
-
try {
|
|
233
|
-
names = readdirSync(join(root, d), { recursive: true }) as string[];
|
|
234
|
-
} catch {
|
|
235
|
-
continue;
|
|
236
|
-
}
|
|
237
|
-
for (const n of names) {
|
|
238
|
-
if (!n.endsWith(".md") || n.split(/[\\/]/).some((x) => x.startsWith("."))) continue;
|
|
239
|
-
const path = join(root, d, n);
|
|
240
|
-
out.push({ path, rel: join(d, n), modified: statSync(path).mtimeMs });
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
return out.sort((a, b) => b.modified - a.modified).slice(0, max);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
89
|
const CSP = [
|
|
247
90
|
"default-src 'none'",
|
|
248
91
|
"script-src 'self'",
|
|
@@ -255,14 +98,6 @@ const CSP = [
|
|
|
255
98
|
"frame-ancestors 'none'",
|
|
256
99
|
].join("; ");
|
|
257
100
|
|
|
258
|
-
function readText(path: string): string {
|
|
259
|
-
try {
|
|
260
|
-
return readFileSync(path, "utf8");
|
|
261
|
-
} catch {
|
|
262
|
-
return "";
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
101
|
function same(a: string, b: string): boolean {
|
|
267
102
|
const x = Buffer.from(a);
|
|
268
103
|
const y = Buffer.from(b);
|
|
@@ -310,18 +145,6 @@ function alive(pid: number): boolean {
|
|
|
310
145
|
}
|
|
311
146
|
}
|
|
312
147
|
|
|
313
|
-
/** Open a URL or a file with the system's default program. */
|
|
314
|
-
export function openExternal(target: string): void {
|
|
315
|
-
const opts = { detached: true, stdio: "ignore" as const, windowsHide: true };
|
|
316
|
-
let child: ChildProcess;
|
|
317
|
-
if (process.platform === "darwin") child = spawn("open", [target], opts);
|
|
318
|
-
// rundll32 hands the target to the default program without cmd.exe parsing it.
|
|
319
|
-
else if (process.platform === "win32") child = spawn("rundll32", ["url.dll,FileProtocolHandler", target], opts);
|
|
320
|
-
else child = spawn("xdg-open", [target], opts);
|
|
321
|
-
child.on("error", () => {});
|
|
322
|
-
child.unref();
|
|
323
|
-
}
|
|
324
|
-
|
|
325
148
|
// ---------------------------------------------------------------- server
|
|
326
149
|
|
|
327
150
|
interface RunningFile {
|
|
@@ -363,7 +186,7 @@ export async function startWeb(opts: WebOptions, env: NodeJS.ProcessEnv = proces
|
|
|
363
186
|
const clients = new Set<ServerResponse>();
|
|
364
187
|
const dialogs = new Map<string, any>();
|
|
365
188
|
let subsubState: unknown = null;
|
|
366
|
-
|
|
189
|
+
const side = new Side();
|
|
367
190
|
let busy = false;
|
|
368
191
|
let lastSeen = Date.now();
|
|
369
192
|
let restarting = false;
|
|
@@ -388,22 +211,12 @@ export async function startWeb(opts: WebOptions, env: NodeJS.ProcessEnv = proces
|
|
|
388
211
|
|
|
389
212
|
agent.on((ev) => {
|
|
390
213
|
if (ev.type === "extension_ui_request") {
|
|
391
|
-
if (
|
|
214
|
+
if (isDialog(ev)) {
|
|
392
215
|
dialogs.set(ev.id, ev);
|
|
393
216
|
broadcast(ev);
|
|
394
|
-
} else if (
|
|
395
|
-
|
|
396
|
-
subsubState = ev.statusText ? JSON.parse(ev.statusText) : null;
|
|
397
|
-
} catch {
|
|
398
|
-
subsubState = null;
|
|
399
|
-
}
|
|
217
|
+
} else if (side.take(ev) === "state") {
|
|
218
|
+
subsubState = side.state;
|
|
400
219
|
broadcast({ type: "subsub_state", state: subsubState });
|
|
401
|
-
} else if (ev.method === "setStatus" && ev.statusKey === "subsub.find") {
|
|
402
|
-
try {
|
|
403
|
-
lastFind = ev.statusText ? JSON.parse(ev.statusText) : null;
|
|
404
|
-
} catch {
|
|
405
|
-
lastFind = null;
|
|
406
|
-
}
|
|
407
220
|
} else if (ev.method === "notify") {
|
|
408
221
|
broadcast(ev);
|
|
409
222
|
}
|
|
@@ -445,13 +258,7 @@ export async function startWeb(opts: WebOptions, env: NodeJS.ProcessEnv = proces
|
|
|
445
258
|
out.session = await agent.request({ type: "get_state" });
|
|
446
259
|
lastSession = (out.session as { sessionFile?: string }).sessionFile ?? lastSession;
|
|
447
260
|
out.messages = ((await agent.request({ type: "get_messages" })) as { messages: unknown[] }).messages;
|
|
448
|
-
|
|
449
|
-
// RPC has no argument hints: read them from the prompt files.
|
|
450
|
-
out.commands = commands.map((c) => {
|
|
451
|
-
const front = c.source === "prompt" && c.sourceInfo?.path ? frontMatter(readText(c.sourceInfo.path)) : undefined;
|
|
452
|
-
const hint = front && field(front, "argument-hint");
|
|
453
|
-
return hint ? { ...c, hint } : c;
|
|
454
|
-
});
|
|
261
|
+
out.commands = withHints(((await agent.request({ type: "get_commands" })) as { commands: Array<Record<string, any>> }).commands);
|
|
455
262
|
} catch (err) {
|
|
456
263
|
out.error = (err as Error).message;
|
|
457
264
|
}
|
|
@@ -702,8 +509,7 @@ export async function startWeb(opts: WebOptions, env: NodeJS.ProcessEnv = proces
|
|
|
702
509
|
case "GET /api/library": {
|
|
703
510
|
const q = (url.searchParams.get("q") ?? "").replace(/\s+/g, " ").trim().slice(0, 200);
|
|
704
511
|
if (!q) return send(res, 200, { q, items: [] });
|
|
705
|
-
|
|
706
|
-
return send(res, 200, lastFind?.q === q ? lastFind : { q, items: [] });
|
|
512
|
+
return send(res, 200, await findLibrary(agent, side, q));
|
|
707
513
|
}
|
|
708
514
|
case "POST /api/session/name": {
|
|
709
515
|
const body = await readJson(req);
|
|
@@ -739,8 +545,7 @@ export async function startWeb(opts: WebOptions, env: NodeJS.ProcessEnv = proces
|
|
|
739
545
|
if (!target) return send(res, 404, { error: "not found in the Sub-Sub folder" });
|
|
740
546
|
// Documents only: a file that the model wrote must never be run.
|
|
741
547
|
if (!OPENABLE.has(extname(target).toLowerCase())) return send(res, 403, { error: "Sub-Sub opens only notes and documents (.md, .txt, .pdf, .bib, .csv, .qmd)." });
|
|
742
|
-
|
|
743
|
-
else openExternal(target);
|
|
548
|
+
openFile(target, vault);
|
|
744
549
|
return send(res, 200, { ok: true });
|
|
745
550
|
}
|
|
746
551
|
case "POST /api/quit":
|
package/src/words.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The plain words of the web view (actions, suggestions, names of tools, in English and Portuguese), for the terminal screens.
|
|
3
|
+
* web/i18n.js is a browser module with no imports; it is loaded here as it is, so the two views never differ.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import { pathToFileURL } from "node:url";
|
|
8
|
+
import { PACKAGE_DIR } from "./cli.ts";
|
|
9
|
+
|
|
10
|
+
export interface Action {
|
|
11
|
+
cmd: string;
|
|
12
|
+
en: string;
|
|
13
|
+
pt: string;
|
|
14
|
+
/** Send the command at once instead of filling the box. */
|
|
15
|
+
send?: boolean;
|
|
16
|
+
/** The command takes a library item. */
|
|
17
|
+
item?: boolean;
|
|
18
|
+
/** Needs an add-on, for example "starbuck". */
|
|
19
|
+
needs?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface Words {
|
|
23
|
+
ACTIONS: { research: Action[]; library: Action[] };
|
|
24
|
+
SUGGESTIONS: Record<"researcher" | "librarian", Array<{ en: string; pt: string }>>;
|
|
25
|
+
TOOLS: { en: Record<string, string>; pt: Record<string, string> };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let words: Promise<Words> | undefined;
|
|
29
|
+
|
|
30
|
+
/** A dynamic import: a static one would pull a file outside src/ into the TypeScript build. */
|
|
31
|
+
export function loadWords(): Promise<Words> {
|
|
32
|
+
words ??= import(pathToFileURL(join(PACKAGE_DIR, "web", "i18n.js")).href) as Promise<Words>;
|
|
33
|
+
return words;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** What a tool is called while it runs ("zotero_find_items" is "search the library"); unknown tools keep their name. */
|
|
37
|
+
export function toolWord(w: Words, lang: "en" | "pt", name: string): string {
|
|
38
|
+
const short = name.replace(/^(zotero|scholar)_/, "");
|
|
39
|
+
return w.TOOLS[lang][short] ?? w.TOOLS.en[short] ?? name;
|
|
40
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://raw.githubusercontent.com/earendil-works/pi/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
|
|
3
|
+
"name": "subsub-glauca-dark-256",
|
|
4
|
+
"vars": {
|
|
5
|
+
"ink": 254,
|
|
6
|
+
"muted": 145,
|
|
7
|
+
"faint": 246,
|
|
8
|
+
"prussian": 110,
|
|
9
|
+
"madder": 173,
|
|
10
|
+
"sap": 144,
|
|
11
|
+
"gamboge": 179,
|
|
12
|
+
"mark": 242,
|
|
13
|
+
"rule": 236,
|
|
14
|
+
"accent": 110,
|
|
15
|
+
"wash": 236
|
|
16
|
+
},
|
|
17
|
+
"colors": {
|
|
18
|
+
"text": "ink",
|
|
19
|
+
"userMessageText": "ink",
|
|
20
|
+
"customMessageText": "ink",
|
|
21
|
+
"toolTitle": "ink",
|
|
22
|
+
"mdHeading": "ink",
|
|
23
|
+
"mdCode": "ink",
|
|
24
|
+
"mdCodeBlock": "ink",
|
|
25
|
+
"error": "ink",
|
|
26
|
+
"muted": "muted",
|
|
27
|
+
"toolOutput": "muted",
|
|
28
|
+
"mdQuote": "muted",
|
|
29
|
+
"toolDiffContext": "muted",
|
|
30
|
+
"thinkingText": "muted",
|
|
31
|
+
"toolDiffRemoved": "muted",
|
|
32
|
+
"dim": "faint",
|
|
33
|
+
"mdLinkUrl": "faint",
|
|
34
|
+
"syntaxComment": "faint",
|
|
35
|
+
"border": "mark",
|
|
36
|
+
"mdQuoteBorder": "mark",
|
|
37
|
+
"mdListBullet": "mark",
|
|
38
|
+
"borderMuted": "rule",
|
|
39
|
+
"mdHr": "rule",
|
|
40
|
+
"mdCodeBlockBorder": "rule",
|
|
41
|
+
"scrollbarTrack": "rule",
|
|
42
|
+
"thinkingOff": "rule",
|
|
43
|
+
"scrollbarThumb": "faint",
|
|
44
|
+
"accent": "accent",
|
|
45
|
+
"borderAccent": "accent",
|
|
46
|
+
"bashMode": "accent",
|
|
47
|
+
"customMessageLabel": "accent",
|
|
48
|
+
"thinkingXhigh": "accent",
|
|
49
|
+
"thinkingMax": "accent",
|
|
50
|
+
"mdLink": "prussian",
|
|
51
|
+
"thinkingHigh": "prussian",
|
|
52
|
+
"success": "sap",
|
|
53
|
+
"toolDiffAdded": "sap",
|
|
54
|
+
"warning": "gamboge",
|
|
55
|
+
"selectedBg": "wash",
|
|
56
|
+
"searchMatchBg": "",
|
|
57
|
+
"searchMatchText": "ink",
|
|
58
|
+
"userMessageBg": "",
|
|
59
|
+
"toolSuccessBg": "",
|
|
60
|
+
"customMessageBg": "",
|
|
61
|
+
"toolErrorBg": "",
|
|
62
|
+
"toolPendingBg": "",
|
|
63
|
+
"syntaxKeyword": "prussian",
|
|
64
|
+
"syntaxNumber": "prussian",
|
|
65
|
+
"syntaxFunction": "ink",
|
|
66
|
+
"syntaxVariable": "ink",
|
|
67
|
+
"syntaxType": "ink",
|
|
68
|
+
"syntaxString": "muted",
|
|
69
|
+
"syntaxOperator": "muted",
|
|
70
|
+
"syntaxPunctuation": "faint",
|
|
71
|
+
"thinkingMinimal": "faint",
|
|
72
|
+
"thinkingLow": "mark",
|
|
73
|
+
"thinkingMedium": "muted"
|
|
74
|
+
},
|
|
75
|
+
"export": {
|
|
76
|
+
"pageBg": "#12171c",
|
|
77
|
+
"cardBg": "#192128",
|
|
78
|
+
"infoBg": "#0d1115"
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -2,90 +2,86 @@
|
|
|
2
2
|
"$schema": "https://raw.githubusercontent.com/earendil-works/pi/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
|
|
3
3
|
"name": "subsub-glauca-dark",
|
|
4
4
|
"vars": {
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"muted": "#
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"dim": "#5d6a6d",
|
|
24
|
-
"select": "#263e48",
|
|
25
|
-
"okBg": "#1b2920",
|
|
26
|
-
"errBg": "#331c19"
|
|
5
|
+
"sheet": "#12171c",
|
|
6
|
+
"sunk": "#0d1115",
|
|
7
|
+
"field": "#192128",
|
|
8
|
+
"ink": "#dce1de",
|
|
9
|
+
"muted": "#a6b0b3",
|
|
10
|
+
"faint": "#8d989d",
|
|
11
|
+
"rule": "#2c363f",
|
|
12
|
+
"mark": "#66727c",
|
|
13
|
+
"prussian": "#86b4da",
|
|
14
|
+
"prussianWash": "#1e3042",
|
|
15
|
+
"madder": "#e6866d",
|
|
16
|
+
"madderWash": "#3d2620",
|
|
17
|
+
"sap": "#a3c078",
|
|
18
|
+
"sapWash": "#253220",
|
|
19
|
+
"gamboge": "#e2b45a",
|
|
20
|
+
"gambogeWash": "#3a3019",
|
|
21
|
+
"accent": "#86b4da",
|
|
22
|
+
"wash": "#1e3042"
|
|
27
23
|
},
|
|
28
24
|
"colors": {
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
25
|
+
"text": "ink",
|
|
26
|
+
"userMessageText": "ink",
|
|
27
|
+
"customMessageText": "ink",
|
|
28
|
+
"toolTitle": "ink",
|
|
29
|
+
"mdHeading": "ink",
|
|
30
|
+
"mdCode": "ink",
|
|
31
|
+
"mdCodeBlock": "ink",
|
|
32
|
+
"error": "ink",
|
|
36
33
|
"muted": "muted",
|
|
37
|
-
"dim": "dim",
|
|
38
|
-
"text": "text",
|
|
39
|
-
"thinkingText": "muted",
|
|
40
|
-
"selectedBg": "select",
|
|
41
|
-
"scrollbarTrack": "line",
|
|
42
|
-
"scrollbarThumb": "muted",
|
|
43
|
-
"searchMatchBg": "select",
|
|
44
|
-
"searchMatchText": "text",
|
|
45
|
-
"userMessageBg": "raised",
|
|
46
|
-
"userMessageText": "text",
|
|
47
|
-
"customMessageBg": "surface",
|
|
48
|
-
"customMessageText": "text",
|
|
49
|
-
"customMessageLabel": "tonePale",
|
|
50
|
-
"toolPendingBg": "surface",
|
|
51
|
-
"toolSuccessBg": "okBg",
|
|
52
|
-
"toolErrorBg": "errBg",
|
|
53
|
-
"toolTitle": "text",
|
|
54
34
|
"toolOutput": "muted",
|
|
55
|
-
"mdHeading": "tonePale",
|
|
56
|
-
"mdLink": "link",
|
|
57
|
-
"mdLinkUrl": "dim",
|
|
58
|
-
"mdCode": "green",
|
|
59
|
-
"mdCodeBlock": "text",
|
|
60
|
-
"mdCodeBlockBorder": "line",
|
|
61
35
|
"mdQuote": "muted",
|
|
62
|
-
"mdQuoteBorder": "toneBright",
|
|
63
|
-
"mdHr": "line",
|
|
64
|
-
"mdListBullet": "toneBright",
|
|
65
|
-
"toolDiffAdded": "green",
|
|
66
|
-
"toolDiffRemoved": "red",
|
|
67
36
|
"toolDiffContext": "muted",
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
"
|
|
78
|
-
"
|
|
79
|
-
"
|
|
80
|
-
"
|
|
81
|
-
"
|
|
82
|
-
"
|
|
83
|
-
"
|
|
84
|
-
"bashMode": "
|
|
37
|
+
"thinkingText": "muted",
|
|
38
|
+
"toolDiffRemoved": "muted",
|
|
39
|
+
"dim": "faint",
|
|
40
|
+
"mdLinkUrl": "faint",
|
|
41
|
+
"syntaxComment": "faint",
|
|
42
|
+
"border": "mark",
|
|
43
|
+
"mdQuoteBorder": "mark",
|
|
44
|
+
"mdListBullet": "mark",
|
|
45
|
+
"borderMuted": "rule",
|
|
46
|
+
"mdHr": "rule",
|
|
47
|
+
"mdCodeBlockBorder": "rule",
|
|
48
|
+
"scrollbarTrack": "rule",
|
|
49
|
+
"thinkingOff": "rule",
|
|
50
|
+
"scrollbarThumb": "faint",
|
|
51
|
+
"accent": "accent",
|
|
52
|
+
"borderAccent": "accent",
|
|
53
|
+
"bashMode": "accent",
|
|
54
|
+
"customMessageLabel": "accent",
|
|
55
|
+
"thinkingXhigh": "accent",
|
|
56
|
+
"thinkingMax": "accent",
|
|
57
|
+
"mdLink": "prussian",
|
|
58
|
+
"thinkingHigh": "prussian",
|
|
59
|
+
"success": "sap",
|
|
60
|
+
"toolDiffAdded": "sap",
|
|
61
|
+
"warning": "gamboge",
|
|
62
|
+
"selectedBg": "wash",
|
|
63
|
+
"searchMatchBg": "gambogeWash",
|
|
64
|
+
"searchMatchText": "ink",
|
|
65
|
+
"userMessageBg": "field",
|
|
66
|
+
"toolSuccessBg": "field",
|
|
67
|
+
"customMessageBg": "sunk",
|
|
68
|
+
"toolErrorBg": "sunk",
|
|
69
|
+
"toolPendingBg": "gambogeWash",
|
|
70
|
+
"syntaxKeyword": "prussian",
|
|
71
|
+
"syntaxNumber": "prussian",
|
|
72
|
+
"syntaxFunction": "ink",
|
|
73
|
+
"syntaxVariable": "ink",
|
|
74
|
+
"syntaxType": "ink",
|
|
75
|
+
"syntaxString": "muted",
|
|
76
|
+
"syntaxOperator": "muted",
|
|
77
|
+
"syntaxPunctuation": "faint",
|
|
78
|
+
"thinkingMinimal": "faint",
|
|
79
|
+
"thinkingLow": "mark",
|
|
80
|
+
"thinkingMedium": "muted"
|
|
85
81
|
},
|
|
86
82
|
"export": {
|
|
87
|
-
"pageBg": "#
|
|
88
|
-
"cardBg": "#
|
|
89
|
-
"infoBg": "#
|
|
83
|
+
"pageBg": "#12171c",
|
|
84
|
+
"cardBg": "#192128",
|
|
85
|
+
"infoBg": "#0d1115"
|
|
90
86
|
}
|
|
91
87
|
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://raw.githubusercontent.com/earendil-works/pi/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
|
|
3
|
+
"name": "subsub-glauca-light-256",
|
|
4
|
+
"vars": {
|
|
5
|
+
"ink": 234,
|
|
6
|
+
"muted": 239,
|
|
7
|
+
"faint": 241,
|
|
8
|
+
"prussian": 24,
|
|
9
|
+
"madder": 94,
|
|
10
|
+
"sap": 58,
|
|
11
|
+
"gamboge": 94,
|
|
12
|
+
"mark": 102,
|
|
13
|
+
"rule": 251,
|
|
14
|
+
"accent": 24,
|
|
15
|
+
"wash": 254
|
|
16
|
+
},
|
|
17
|
+
"colors": {
|
|
18
|
+
"text": "ink",
|
|
19
|
+
"userMessageText": "ink",
|
|
20
|
+
"customMessageText": "ink",
|
|
21
|
+
"toolTitle": "ink",
|
|
22
|
+
"mdHeading": "ink",
|
|
23
|
+
"mdCode": "ink",
|
|
24
|
+
"mdCodeBlock": "ink",
|
|
25
|
+
"error": "ink",
|
|
26
|
+
"muted": "muted",
|
|
27
|
+
"toolOutput": "muted",
|
|
28
|
+
"mdQuote": "muted",
|
|
29
|
+
"toolDiffContext": "muted",
|
|
30
|
+
"thinkingText": "muted",
|
|
31
|
+
"toolDiffRemoved": "muted",
|
|
32
|
+
"dim": "faint",
|
|
33
|
+
"mdLinkUrl": "faint",
|
|
34
|
+
"syntaxComment": "faint",
|
|
35
|
+
"border": "mark",
|
|
36
|
+
"mdQuoteBorder": "mark",
|
|
37
|
+
"mdListBullet": "mark",
|
|
38
|
+
"borderMuted": "rule",
|
|
39
|
+
"mdHr": "rule",
|
|
40
|
+
"mdCodeBlockBorder": "rule",
|
|
41
|
+
"scrollbarTrack": "rule",
|
|
42
|
+
"thinkingOff": "rule",
|
|
43
|
+
"scrollbarThumb": "faint",
|
|
44
|
+
"accent": "accent",
|
|
45
|
+
"borderAccent": "accent",
|
|
46
|
+
"bashMode": "accent",
|
|
47
|
+
"customMessageLabel": "accent",
|
|
48
|
+
"thinkingXhigh": "accent",
|
|
49
|
+
"thinkingMax": "accent",
|
|
50
|
+
"mdLink": "prussian",
|
|
51
|
+
"thinkingHigh": "prussian",
|
|
52
|
+
"success": "sap",
|
|
53
|
+
"toolDiffAdded": "sap",
|
|
54
|
+
"warning": "gamboge",
|
|
55
|
+
"selectedBg": "wash",
|
|
56
|
+
"searchMatchBg": "",
|
|
57
|
+
"searchMatchText": "ink",
|
|
58
|
+
"userMessageBg": "",
|
|
59
|
+
"toolSuccessBg": "",
|
|
60
|
+
"customMessageBg": "",
|
|
61
|
+
"toolErrorBg": "",
|
|
62
|
+
"toolPendingBg": "",
|
|
63
|
+
"syntaxKeyword": "prussian",
|
|
64
|
+
"syntaxNumber": "prussian",
|
|
65
|
+
"syntaxFunction": "ink",
|
|
66
|
+
"syntaxVariable": "ink",
|
|
67
|
+
"syntaxType": "ink",
|
|
68
|
+
"syntaxString": "muted",
|
|
69
|
+
"syntaxOperator": "muted",
|
|
70
|
+
"syntaxPunctuation": "faint",
|
|
71
|
+
"thinkingMinimal": "faint",
|
|
72
|
+
"thinkingLow": "mark",
|
|
73
|
+
"thinkingMedium": "muted"
|
|
74
|
+
},
|
|
75
|
+
"export": {
|
|
76
|
+
"pageBg": "#e9ece6",
|
|
77
|
+
"cardBg": "#f4f5f1",
|
|
78
|
+
"infoBg": "#dfe3dc"
|
|
79
|
+
}
|
|
80
|
+
}
|