@geohar/unbien-cli 0.1.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/README.md +72 -0
- package/dist/client.d.ts +89 -0
- package/dist/client.js +210 -0
- package/dist/client.js.map +1 -0
- package/dist/commands.d.ts +59 -0
- package/dist/commands.js +273 -0
- package/dist/commands.js.map +1 -0
- package/dist/connect.d.ts +2 -0
- package/dist/connect.js +475 -0
- package/dist/connect.js.map +1 -0
- package/dist/identity.d.ts +2 -0
- package/dist/identity.js +30 -0
- package/dist/identity.js.map +1 -0
- package/dist/invite.d.ts +10 -0
- package/dist/invite.js +28 -0
- package/dist/invite.js.map +1 -0
- package/dist/main.d.ts +3 -0
- package/dist/main.js +20 -0
- package/dist/main.js.map +1 -0
- package/dist/panels.d.ts +40 -0
- package/dist/panels.js +155 -0
- package/dist/panels.js.map +1 -0
- package/dist/picker.d.ts +6 -0
- package/dist/picker.js +95 -0
- package/dist/picker.js.map +1 -0
- package/dist/plan.d.ts +30 -0
- package/dist/plan.js +132 -0
- package/dist/plan.js.map +1 -0
- package/dist/reduce.d.ts +45 -0
- package/dist/reduce.js +123 -0
- package/dist/reduce.js.map +1 -0
- package/dist/render.d.ts +13 -0
- package/dist/render.js +91 -0
- package/dist/render.js.map +1 -0
- package/dist/replay.d.ts +2 -0
- package/dist/replay.js +57 -0
- package/dist/replay.js.map +1 -0
- package/dist/settings.d.ts +27 -0
- package/dist/settings.js +31 -0
- package/dist/settings.js.map +1 -0
- package/dist/store.d.ts +13 -0
- package/dist/store.js +20 -0
- package/dist/store.js.map +1 -0
- package/dist/theme.d.ts +7 -0
- package/dist/theme.js +110 -0
- package/dist/theme.js.map +1 -0
- package/dist/tui.d.ts +78 -0
- package/dist/tui.js +265 -0
- package/dist/tui.js.map +1 -0
- package/package.json +58 -0
package/dist/render.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Draws transcript items with pi's OWN interactive components, so a remote
|
|
3
|
+
* session looks identical to a local one. Built-in tool definitions are
|
|
4
|
+
* constructed for their renderers only — `execute` is never called, so nothing
|
|
5
|
+
* here touches the filesystem.
|
|
6
|
+
*/
|
|
7
|
+
import { AssistantMessageComponent, UserMessageComponent, ToolExecutionComponent, createBashToolDefinition, createEditToolDefinition, createFindToolDefinition, createGrepToolDefinition, createLsToolDefinition, createReadToolDefinition, createWriteToolDefinition, getMarkdownTheme, } from "@earendil-works/pi-coding-agent";
|
|
8
|
+
// SAFETY: these components touch exactly one TUI member — `requestRender` — to
|
|
9
|
+
// schedule a repaint. A one-shot render has nothing to schedule, so the stub is
|
|
10
|
+
// complete for this use; a component reaching further would throw loudly here
|
|
11
|
+
// rather than silently mis-render.
|
|
12
|
+
const offlineTui = { requestRender: () => { } };
|
|
13
|
+
function builtinRenderers(cwd) {
|
|
14
|
+
return new Map([
|
|
15
|
+
["bash", createBashToolDefinition(cwd)],
|
|
16
|
+
["edit", createEditToolDefinition(cwd)],
|
|
17
|
+
["find", createFindToolDefinition(cwd)],
|
|
18
|
+
["grep", createGrepToolDefinition(cwd)],
|
|
19
|
+
["ls", createLsToolDefinition(cwd)],
|
|
20
|
+
["read", createReadToolDefinition(cwd)],
|
|
21
|
+
["write", createWriteToolDefinition(cwd)],
|
|
22
|
+
]);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Draw an in-flight assistant turn with the SAME component that draws the
|
|
26
|
+
* settled one, so the text doesn't visibly reflow when the message lands — it
|
|
27
|
+
* is simply replaced by its finished self.
|
|
28
|
+
*/
|
|
29
|
+
/**
|
|
30
|
+
* In-flight reasoning, drawn as a thinking block by the same component that
|
|
31
|
+
* renders it once settled.
|
|
32
|
+
*/
|
|
33
|
+
export function renderThinking(text, width) {
|
|
34
|
+
if (!text)
|
|
35
|
+
return [];
|
|
36
|
+
const component = new AssistantMessageComponent(undefined, false, getMarkdownTheme());
|
|
37
|
+
// A thinking block carries its prose in `thinking`, not `text`.
|
|
38
|
+
component.updateContent({
|
|
39
|
+
role: "assistant",
|
|
40
|
+
content: [{ type: "thinking", thinking: text }],
|
|
41
|
+
}, true);
|
|
42
|
+
return component.render(width);
|
|
43
|
+
}
|
|
44
|
+
export function renderStreaming(text, width) {
|
|
45
|
+
if (!text)
|
|
46
|
+
return [];
|
|
47
|
+
const component = new AssistantMessageComponent({ role: "assistant", content: [{ type: "text", text }] }, false, getMarkdownTheme());
|
|
48
|
+
component.updateContent({ role: "assistant", content: [{ type: "text", text }] }, true);
|
|
49
|
+
return component.render(width);
|
|
50
|
+
}
|
|
51
|
+
export function renderTranscript(items, width, cwd, hideThinking = false) {
|
|
52
|
+
const markdownTheme = getMarkdownTheme();
|
|
53
|
+
const renderers = builtinRenderers(cwd);
|
|
54
|
+
const lines = [];
|
|
55
|
+
for (const item of items) {
|
|
56
|
+
if (item.kind === "notice") {
|
|
57
|
+
lines.push(` ${item.text}`, "");
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (item.kind === "message") {
|
|
61
|
+
const { message } = item;
|
|
62
|
+
if (message.role === "user") {
|
|
63
|
+
const text = message.content
|
|
64
|
+
.filter((b) => b.type === "text")
|
|
65
|
+
.map((b) => b.text ?? "")
|
|
66
|
+
.join("\n");
|
|
67
|
+
lines.push(...new UserMessageComponent(text, markdownTheme).render(width), "");
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
const component = new AssistantMessageComponent(
|
|
71
|
+
// The wire message IS pi's own serialization of an AssistantMessage.
|
|
72
|
+
message, hideThinking, markdownTheme);
|
|
73
|
+
lines.push(...component.render(width), "");
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
const card = new ToolExecutionComponent(item.toolName, item.toolCallId, item.args, {}, renderers.get(item.toolName.toLowerCase()), offlineTui, cwd);
|
|
77
|
+
card.setArgsComplete();
|
|
78
|
+
card.markExecutionStarted();
|
|
79
|
+
if (item.result) {
|
|
80
|
+
card.updateResult({
|
|
81
|
+
content: item.result.content,
|
|
82
|
+
details: item.result.details,
|
|
83
|
+
isError: item.result.isError,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
card.setExpanded(true);
|
|
87
|
+
lines.push(...card.render(width), "");
|
|
88
|
+
}
|
|
89
|
+
return lines;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"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"}
|
package/dist/replay.d.ts
ADDED
package/dist/replay.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Replays a captured rpc-envelope fixture through the reducer and pi's
|
|
4
|
+
* components — the look-and-feel prototype, with no transport and no session.
|
|
5
|
+
*/
|
|
6
|
+
import { readFileSync } from "node:fs";
|
|
7
|
+
import { reduce, toEnvelope } from "./reduce.js";
|
|
8
|
+
import { renderTranscript } from "./render.js";
|
|
9
|
+
import { applyTheme, availableThemes } from "./theme.js";
|
|
10
|
+
function parseArgs(argv) {
|
|
11
|
+
const positional = [];
|
|
12
|
+
let theme;
|
|
13
|
+
let width;
|
|
14
|
+
let cwd;
|
|
15
|
+
for (let i = 0; i < argv.length; i++) {
|
|
16
|
+
if (argv[i] === "--theme")
|
|
17
|
+
theme = argv[++i];
|
|
18
|
+
else if (argv[i] === "--width")
|
|
19
|
+
width = Number(argv[++i]);
|
|
20
|
+
else if (argv[i] === "--cwd")
|
|
21
|
+
cwd = argv[++i];
|
|
22
|
+
else
|
|
23
|
+
positional.push(argv[i]);
|
|
24
|
+
}
|
|
25
|
+
return { file: positional[0], theme, width, cwd };
|
|
26
|
+
}
|
|
27
|
+
const { file, theme, width, cwd } = parseArgs(process.argv.slice(2));
|
|
28
|
+
// Listing themes must not require a fixture.
|
|
29
|
+
if (theme === "list") {
|
|
30
|
+
console.log((await availableThemes()).join("\n"));
|
|
31
|
+
process.exit(0);
|
|
32
|
+
}
|
|
33
|
+
if (!file) {
|
|
34
|
+
console.error("usage: unbien replay <fixture.jsonl> [--theme <name>|list] [--width <cols>] [--cwd <path>]");
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
await applyTheme(theme);
|
|
38
|
+
const envelopes = [];
|
|
39
|
+
for (const line of readFileSync(file, "utf8").split("\n")) {
|
|
40
|
+
if (!line.trim())
|
|
41
|
+
continue;
|
|
42
|
+
let parsed;
|
|
43
|
+
try {
|
|
44
|
+
parsed = JSON.parse(line);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const env = toEnvelope(parsed);
|
|
50
|
+
if (env)
|
|
51
|
+
envelopes.push(env);
|
|
52
|
+
}
|
|
53
|
+
const cols = width ?? process.stdout.columns ?? 100;
|
|
54
|
+
// Tool cards resolve paths against the SESSION's cwd, which is remote and has
|
|
55
|
+
// no relation to wherever this client happens to be running.
|
|
56
|
+
console.log(renderTranscript(reduce(envelopes), cols, cwd ?? process.cwd()).join("\n"));
|
|
57
|
+
//# sourceMappingURL=replay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replay.js","sourceRoot":"","sources":["../src/replay.ts"],"names":[],"mappings":";AACA;;;GAGG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAwB,MAAM,aAAa,CAAA;AACtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAExD,SAAS,SAAS,CAAC,IAAuB;IACxC,MAAM,UAAU,GAAa,EAAE,CAAA;IAC/B,IAAI,KAAyB,CAAA;IAC7B,IAAI,KAAyB,CAAA;IAC7B,IAAI,GAAuB,CAAA;IAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,SAAS;YAAE,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;aACvC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,SAAS;YAAE,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;aACpD,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,OAAO;YAAE,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;;YACxC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAE,CAAC,CAAA;IAChC,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,CAAA;AACnD,CAAC;AAED,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;AAEpE,6CAA6C;AAC7C,IAAI,KAAK,KAAK,MAAM,EAAE,CAAC;IACrB,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,eAAe,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;IACjD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC;AAED,IAAI,CAAC,IAAI,EAAE,CAAC;IACV,OAAO,CAAC,KAAK,CACX,4FAA4F,CAC7F,CAAA;IACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC;AAED,MAAM,UAAU,CAAC,KAAK,CAAC,CAAA;AAEvB,MAAM,SAAS,GAAsB,EAAE,CAAA;AACvC,KAAK,MAAM,IAAI,IAAI,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;IAC1D,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;QAAE,SAAQ;IAC1B,IAAI,MAAe,CAAA;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,SAAQ;IACV,CAAC;IACD,MAAM,GAAG,GAAG,UAAU,CAAC,MAAM,CAAC,CAAA;IAC9B,IAAI,GAAG;QAAE,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAC9B,CAAC;AAED,MAAM,IAAI,GAAG,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,OAAO,IAAI,GAAG,CAAA;AACnD,8EAA8E;AAC9E,6DAA6D;AAC7D,OAAO,CAAC,GAAG,CACT,gBAAgB,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAC3E,CAAA"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The CLI's own settings, kept separate from pi's: these are client display
|
|
3
|
+
* preferences and have no meaning to the host session.
|
|
4
|
+
*/
|
|
5
|
+
/** pi-plan's widget states: hidden, a one-line summary, or the full panel. */
|
|
6
|
+
export type PanelMode = "hidden" | "collapsed" | "expanded";
|
|
7
|
+
export interface CliSettings {
|
|
8
|
+
/** Theme name; falls back to pi's configured theme when unset. */
|
|
9
|
+
theme?: string;
|
|
10
|
+
/** Render reasoning deltas live, not just in the settled message. */
|
|
11
|
+
streamThinking: boolean;
|
|
12
|
+
/** Show the settled message's thinking block at all. */
|
|
13
|
+
showThinking: boolean;
|
|
14
|
+
/** Persistent plan widget above the composer. */
|
|
15
|
+
planMode: PanelMode;
|
|
16
|
+
/** Persistent subagents widget above the composer. */
|
|
17
|
+
subagentsMode: PanelMode;
|
|
18
|
+
/** Include finished plan items (pi-plan's `filter done`). */
|
|
19
|
+
planShowDone: boolean;
|
|
20
|
+
/** Include non-plan kinds — design/note context (pi-plan's `filter context`). */
|
|
21
|
+
planShowContext: boolean;
|
|
22
|
+
/** Row cap before the panel trails off with "…N more". */
|
|
23
|
+
planMaxRows: number;
|
|
24
|
+
}
|
|
25
|
+
export declare function settingsPath(): string;
|
|
26
|
+
export declare function loadSettings(path?: string): CliSettings;
|
|
27
|
+
export declare function saveSettings(settings: CliSettings, path?: string): void;
|
package/dist/settings.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
const DEFAULTS = {
|
|
5
|
+
streamThinking: false,
|
|
6
|
+
showThinking: true,
|
|
7
|
+
planMode: "hidden",
|
|
8
|
+
subagentsMode: "hidden",
|
|
9
|
+
// pi-plan's own defaults: a plan should show what's actionable, not history.
|
|
10
|
+
planShowDone: false,
|
|
11
|
+
planShowContext: false,
|
|
12
|
+
planMaxRows: 18,
|
|
13
|
+
};
|
|
14
|
+
const SETTINGS_PATH = join(homedir(), ".config", "unbien-cli", "settings.json");
|
|
15
|
+
export function settingsPath() {
|
|
16
|
+
return SETTINGS_PATH;
|
|
17
|
+
}
|
|
18
|
+
export function loadSettings(path = SETTINGS_PATH) {
|
|
19
|
+
try {
|
|
20
|
+
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
21
|
+
return { ...DEFAULTS, ...parsed };
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return { ...DEFAULTS };
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function saveSettings(settings, path = SETTINGS_PATH) {
|
|
28
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
29
|
+
writeFileSync(path, `${JSON.stringify(settings, null, 2)}\n`);
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=settings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings.js","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAChE,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AA4BzC,MAAM,QAAQ,GAAgB;IAC5B,cAAc,EAAE,KAAK;IACrB,YAAY,EAAE,IAAI;IAClB,QAAQ,EAAE,QAAQ;IAClB,aAAa,EAAE,QAAQ;IACvB,6EAA6E;IAC7E,YAAY,EAAE,KAAK;IACnB,eAAe,EAAE,KAAK;IACtB,WAAW,EAAE,EAAE;CAChB,CAAA;AAED,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,YAAY,EAAE,eAAe,CAAC,CAAA;AAE/E,MAAM,UAAU,YAAY;IAC1B,OAAO,aAAa,CAAA;AACtB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAI,GAAG,aAAa;IAC/C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CACvB,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CACH,CAAA;QACzB,OAAO,EAAE,GAAG,QAAQ,EAAE,GAAG,MAAM,EAAE,CAAA;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,GAAG,QAAQ,EAAE,CAAA;IACxB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,QAAqB,EACrB,IAAI,GAAG,aAAa;IAEpB,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC7C,aAAa,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAA;AAC/D,CAAC"}
|
package/dist/store.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pi machines this client has paired with. Pairing is machine-level, so one
|
|
3
|
+
* successful pair reaches every session that pi hosts — the invite's room is
|
|
4
|
+
* just where the token was issued, not a limit on what we can attach to.
|
|
5
|
+
*/
|
|
6
|
+
export interface PairedPeer {
|
|
7
|
+
epk: string;
|
|
8
|
+
relayUrl: string;
|
|
9
|
+
name?: string;
|
|
10
|
+
pairedAt: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function loadPeers(path?: string): PairedPeer[];
|
|
13
|
+
export declare function rememberPeer(peer: PairedPeer, path?: string): void;
|
package/dist/store.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
const STORE_PATH = join(homedir(), ".local", "state", "un-bien", "proxy-peers.json");
|
|
5
|
+
export function loadPeers(path = STORE_PATH) {
|
|
6
|
+
try {
|
|
7
|
+
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
8
|
+
return parsed.peers ?? [];
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return [];
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export function rememberPeer(peer, path = STORE_PATH) {
|
|
15
|
+
const peers = loadPeers(path).filter((p) => p.epk !== peer.epk);
|
|
16
|
+
peers.push(peer);
|
|
17
|
+
mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
|
|
18
|
+
writeFileSync(path, JSON.stringify({ peers }, null, 2), { mode: 0o600 });
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAChE,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAczC,MAAM,UAAU,GAAG,IAAI,CACrB,OAAO,EAAE,EACT,QAAQ,EACR,OAAO,EACP,SAAS,EACT,kBAAkB,CACnB,CAAA;AAED,MAAM,UAAU,SAAS,CAAC,IAAI,GAAG,UAAU;IACzC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAEnD,CAAA;QACD,OAAO,MAAM,CAAC,KAAK,IAAI,EAAE,CAAA;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAA;IACX,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAgB,EAAE,IAAI,GAAG,UAAU;IAC9D,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,CAAC,GAAG,CAAC,CAAA;IAC/D,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAChB,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;IAC1D,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;AAC1E,CAAC"}
|
package/dist/theme.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function availableThemes(): Promise<string[]>;
|
|
2
|
+
/**
|
|
3
|
+
* Explicit flag wins, then the theme configured in pi's settings, then pi's own
|
|
4
|
+
* terminal-background default. Returns the theme actually applied, which may
|
|
5
|
+
* differ from the request when a name cannot be resolved.
|
|
6
|
+
*/
|
|
7
|
+
export declare function applyTheme(requested?: string): Promise<string>;
|
package/dist/theme.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { existsSync, readdirSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { DefaultResourceLoader, SettingsManager, getAgentDir, initTheme, } from "@earendil-works/pi-coding-agent";
|
|
4
|
+
const BUILTIN = ["dark", "light"];
|
|
5
|
+
/** pi's active theme is shared through this key so separate module copies agree. */
|
|
6
|
+
const THEME_KEY = Symbol.for("@earendil-works/pi-coding-agent:theme");
|
|
7
|
+
function customThemesDir() {
|
|
8
|
+
return join(getAgentDir(), "themes");
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Themes can be contributed by pi PACKAGES, declared as a `pi.themes` array in
|
|
12
|
+
* the package manifest (e.g. `@wierdbytes/pi-tokyo-night`). Resolving those by
|
|
13
|
+
* hand would mean reimplementing pi's rules, so ask pi's own resource loader —
|
|
14
|
+
* with every other resource disabled, so no extension code is loaded or run.
|
|
15
|
+
*/
|
|
16
|
+
async function contributedThemes() {
|
|
17
|
+
const agentDir = getAgentDir();
|
|
18
|
+
const loader = new DefaultResourceLoader({
|
|
19
|
+
cwd: process.cwd(),
|
|
20
|
+
agentDir,
|
|
21
|
+
settingsManager: SettingsManager.create(process.cwd(), agentDir),
|
|
22
|
+
noExtensions: true,
|
|
23
|
+
noSkills: true,
|
|
24
|
+
noPromptTemplates: true,
|
|
25
|
+
noContextFiles: true,
|
|
26
|
+
});
|
|
27
|
+
await loader.reload();
|
|
28
|
+
const found = new Map();
|
|
29
|
+
for (const theme of loader.getThemes().themes) {
|
|
30
|
+
if (theme.name && !found.has(theme.name))
|
|
31
|
+
found.set(theme.name, theme);
|
|
32
|
+
}
|
|
33
|
+
return found;
|
|
34
|
+
}
|
|
35
|
+
export async function availableThemes() {
|
|
36
|
+
const names = new Set(BUILTIN);
|
|
37
|
+
const dir = customThemesDir();
|
|
38
|
+
if (existsSync(dir)) {
|
|
39
|
+
for (const file of readdirSync(dir)) {
|
|
40
|
+
if (file.endsWith(".json"))
|
|
41
|
+
names.add(file.slice(0, -".json".length));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
for (const name of (await contributedThemes()).keys())
|
|
46
|
+
names.add(name);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// Package themes are a bonus; never block startup on resolving them.
|
|
50
|
+
}
|
|
51
|
+
return [...names].sort((a, b) => a.localeCompare(b));
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* pi's `theme` setting may be a single name or an auto pair `"<light>/<dark>"`.
|
|
55
|
+
* pi resolves the pair by querying the terminal's real background; that
|
|
56
|
+
* detector isn't exported, so fall back to the COLORFGBG hint.
|
|
57
|
+
*/
|
|
58
|
+
function configuredTheme() {
|
|
59
|
+
let setting;
|
|
60
|
+
try {
|
|
61
|
+
setting = SettingsManager.create(process.cwd()).getThemeSetting();
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
if (!setting)
|
|
67
|
+
return undefined;
|
|
68
|
+
const slash = setting.indexOf("/");
|
|
69
|
+
if (slash === -1)
|
|
70
|
+
return setting;
|
|
71
|
+
const light = setting.slice(0, slash).trim();
|
|
72
|
+
const dark = setting.slice(slash + 1).trim();
|
|
73
|
+
if (!light || !dark)
|
|
74
|
+
return undefined;
|
|
75
|
+
const bg = process.env["COLORFGBG"]?.split(";").pop();
|
|
76
|
+
return bg !== undefined && Number(bg) >= 9 ? light : dark;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Explicit flag wins, then the theme configured in pi's settings, then pi's own
|
|
80
|
+
* terminal-background default. Returns the theme actually applied, which may
|
|
81
|
+
* differ from the request when a name cannot be resolved.
|
|
82
|
+
*/
|
|
83
|
+
export async function applyTheme(requested) {
|
|
84
|
+
const name = requested ?? configuredTheme();
|
|
85
|
+
if (!name) {
|
|
86
|
+
initTheme(undefined, false);
|
|
87
|
+
return "auto";
|
|
88
|
+
}
|
|
89
|
+
// Anything pi can resolve on its own goes through the public API.
|
|
90
|
+
if (BUILTIN.includes(name) ||
|
|
91
|
+
existsSync(join(customThemesDir(), `${name}.json`))) {
|
|
92
|
+
initTheme(name, false);
|
|
93
|
+
return name;
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
const contributed = (await contributedThemes()).get(name);
|
|
97
|
+
if (contributed) {
|
|
98
|
+
;
|
|
99
|
+
globalThis[THEME_KEY] = contributed;
|
|
100
|
+
return name;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
// Fall through to the built-in fallback below.
|
|
105
|
+
}
|
|
106
|
+
// initTheme falls back to dark silently; be explicit that we did not comply.
|
|
107
|
+
initTheme(name, false);
|
|
108
|
+
return `dark (could not resolve "${name}")`;
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=theme.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.js","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AACjD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,WAAW,EACX,SAAS,GAEV,MAAM,iCAAiC,CAAA;AAExC,MAAM,OAAO,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAEjC,oFAAoF;AACpF,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,uCAAuC,CAAC,CAAA;AAErE,SAAS,eAAe;IACtB,OAAO,IAAI,CAAC,WAAW,EAAE,EAAE,QAAQ,CAAC,CAAA;AACtC,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,iBAAiB;IAC9B,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAA;IAC9B,MAAM,MAAM,GAAG,IAAI,qBAAqB,CAAC;QACvC,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;QAClB,QAAQ;QACR,eAAe,EAAE,eAAe,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,CAAC;QAChE,YAAY,EAAE,IAAI;QAClB,QAAQ,EAAE,IAAI;QACd,iBAAiB,EAAE,IAAI;QACvB,cAAc,EAAE,IAAI;KACrB,CAAC,CAAA;IACF,MAAM,MAAM,CAAC,MAAM,EAAE,CAAA;IACrB,MAAM,KAAK,GAAG,IAAI,GAAG,EAAiB,CAAA;IACtC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC,MAAM,EAAE,CAAC;QAC9C,IAAI,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IACxE,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAA;IAC9B,MAAM,GAAG,GAAG,eAAe,EAAE,CAAA;IAC7B,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACpB,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;YACpC,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAA;QACvE,CAAC;IACH,CAAC;IACD,IAAI,CAAC;QACH,KAAK,MAAM,IAAI,IAAI,CAAC,MAAM,iBAAiB,EAAE,CAAC,CAAC,IAAI,EAAE;YAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IACxE,CAAC;IAAC,MAAM,CAAC;QACP,qEAAqE;IACvE,CAAC;IACD,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAA;AACtD,CAAC;AAED;;;;GAIG;AACH,SAAS,eAAe;IACtB,IAAI,OAA2B,CAAA;IAC/B,IAAI,CAAC;QACH,OAAO,GAAG,eAAe,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,eAAe,EAAE,CAAA;IACnE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,IAAI,CAAC,OAAO;QAAE,OAAO,SAAS,CAAA;IAE9B,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IAClC,IAAI,KAAK,KAAK,CAAC,CAAC;QAAE,OAAO,OAAO,CAAA;IAChC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,CAAA;IAC5C,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IAC5C,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAA;IACrC,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAA;IACrD,OAAO,EAAE,KAAK,SAAS,IAAI,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAA;AAC3D,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,SAAkB;IACjD,MAAM,IAAI,GAAG,SAAS,IAAI,eAAe,EAAE,CAAA;IAC3C,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,SAAS,CAAC,SAAS,EAAE,KAAK,CAAC,CAAA;QAC3B,OAAO,MAAM,CAAA;IACf,CAAC;IAED,kEAAkE;IAClE,IACE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;QACtB,UAAU,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,GAAG,IAAI,OAAO,CAAC,CAAC,EACnD,CAAC;QACD,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;QACtB,OAAO,IAAI,CAAA;IACb,CAAC;IAED,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,CAAC,MAAM,iBAAiB,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QACzD,IAAI,WAAW,EAAE,CAAC;YAChB,CAAC;YAAC,UAAsC,CAAC,SAAS,CAAC,GAAG,WAAW,CAAA;YACjE,OAAO,IAAI,CAAA;QACb,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,+CAA+C;IACjD,CAAC;IAED,6EAA6E;IAC7E,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IACtB,OAAO,4BAA4B,IAAI,IAAI,CAAA;AAC7C,CAAC"}
|
package/dist/tui.d.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { TuiMainScreen, type SelectItem } from "@earendil-works/pi-tui";
|
|
2
|
+
export interface ShellStatus {
|
|
3
|
+
session: string;
|
|
4
|
+
cwd: string;
|
|
5
|
+
model?: string;
|
|
6
|
+
working?: boolean;
|
|
7
|
+
/** What the agent is doing right now, e.g. a running tool's name. */
|
|
8
|
+
activity?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare class Shell {
|
|
11
|
+
private readonly onQuit;
|
|
12
|
+
readonly tui: TuiMainScreen;
|
|
13
|
+
private readonly editor;
|
|
14
|
+
private readonly footer;
|
|
15
|
+
private readonly working;
|
|
16
|
+
private isWorking;
|
|
17
|
+
private quitting;
|
|
18
|
+
/** In-flight assistant turn, shown above the editor until it settles. */
|
|
19
|
+
private readonly live;
|
|
20
|
+
private readonly transcript;
|
|
21
|
+
/** Persistent panel widgets, pinned above the composer like pi's own. */
|
|
22
|
+
private readonly widgets;
|
|
23
|
+
/**
|
|
24
|
+
* Command output (/tree, /plan, …) lives BELOW the transcript: `draw()`
|
|
25
|
+
* replaces the transcript wholesale on every frame, which would otherwise
|
|
26
|
+
* erase anything a command had printed.
|
|
27
|
+
*/
|
|
28
|
+
private readonly notes;
|
|
29
|
+
private status;
|
|
30
|
+
/** A modal chooser owns input while open, so the editor must not also see it. */
|
|
31
|
+
private overlay;
|
|
32
|
+
constructor(status: ShellStatus, onSubmit: (text: string) => void, onQuit?: () => void);
|
|
33
|
+
start(): void;
|
|
34
|
+
/**
|
|
35
|
+
* Terminal reset is pi's job, not ours: `tui.stop()` → `ProcessTerminal.stop()`
|
|
36
|
+
* disables bracketed paste and the Kitty keyboard protocol, drops its stdin
|
|
37
|
+
* handlers, and restores raw mode to what it WAS — pausing stdin first, which
|
|
38
|
+
* its own comment marks as the fix for a Ctrl-D race that can close the parent
|
|
39
|
+
* shell over SSH. Doing any of that by hand here re-broke that ordering.
|
|
40
|
+
*
|
|
41
|
+
* We add only what pi can't know about: our socket, and a watchdog so a throw
|
|
42
|
+
* in teardown can't leave the process stranded.
|
|
43
|
+
*/
|
|
44
|
+
quit(): void;
|
|
45
|
+
/**
|
|
46
|
+
* The in-flight turn is REWRITTEN on every delta, so it can't be appended to
|
|
47
|
+
* the transcript. It renders in its own region and is cleared the moment the
|
|
48
|
+
* settled message takes its place — same component, so no visible reflow.
|
|
49
|
+
*/
|
|
50
|
+
setLive(lines: readonly string[]): void;
|
|
51
|
+
stop(): void;
|
|
52
|
+
setStatus(patch: Partial<ShellStatus>): void;
|
|
53
|
+
/**
|
|
54
|
+
* Transcript must live INSIDE the TUI: a full repaint emits `\x1b[3J`, which
|
|
55
|
+
* clears the scrollback buffer, so anything written straight to stdout is
|
|
56
|
+
* erased the moment the shell next redraws.
|
|
57
|
+
*/
|
|
58
|
+
print(lines: readonly string[]): void;
|
|
59
|
+
/** Drop command output (it is scratch, not conversation). */
|
|
60
|
+
clearNotes(): void;
|
|
61
|
+
/** Replace the pinned panel widgets (plan / subagents). */
|
|
62
|
+
setWidgets(lines: readonly string[]): void;
|
|
63
|
+
/** Replace the whole transcript (history replay re-reduces from scratch). */
|
|
64
|
+
setTranscript(lines: readonly string[]): void;
|
|
65
|
+
/**
|
|
66
|
+
* A chooser whose rows carry ACTIONS: a single keypress both picks the row
|
|
67
|
+
* and says what to do with it. Filtering is off here on purpose — the letter
|
|
68
|
+
* keys are the shortcuts, and a filter would swallow them.
|
|
69
|
+
*/
|
|
70
|
+
chooseAction(title: string, items: SelectItem[], hint: string, keys: readonly string[]): Promise<{
|
|
71
|
+
item: SelectItem;
|
|
72
|
+
action: string;
|
|
73
|
+
} | null>;
|
|
74
|
+
/** A highlighted chooser layered over the editor; resolves to the pick. */
|
|
75
|
+
choose(title: string, items: SelectItem[]): Promise<SelectItem | null>;
|
|
76
|
+
get hasOverlay(): boolean;
|
|
77
|
+
private renderFooter;
|
|
78
|
+
}
|