@chalky/chalky 0.0.0-stage → 0.1.3
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/LICENSE +21 -0
- package/README.md +46 -2
- package/app/SYSTEM.md +30 -0
- package/app/extensions/appdata/README.md +10 -0
- package/app/extensions/appdata/guide.md +4 -0
- package/app/extensions/appdata/index.ts +47 -0
- package/app/extensions/doodle/README.md +15 -0
- package/app/extensions/doodle/browser.js +388 -0
- package/app/extensions/doodle/guide.md +6 -0
- package/app/extensions/doodle/index.ts +54 -0
- package/app/extensions/files/browser.js +96 -0
- package/app/extensions/files/guide.md +7 -0
- package/app/extensions/files/index.ts +73 -0
- package/app/extensions/frames/README.md +37 -0
- package/app/extensions/frames/browser.js +163 -0
- package/app/extensions/frames/guide.md +7 -0
- package/app/extensions/frames/index.ts +76 -0
- package/app/extensions/mcp/browser.js +64 -0
- package/app/extensions/mcp/guide.md +5 -0
- package/app/extensions/mcp/index.ts +64 -0
- package/app/extensions/model/index.ts +20 -0
- package/app/extensions/page/index.ts +96 -0
- package/app/extensions/page/page.html +615 -0
- package/app/extensions/point/README.md +22 -0
- package/app/extensions/point/browser.js +245 -0
- package/app/extensions/point/guide.md +6 -0
- package/app/extensions/point/index.ts +97 -0
- package/app/extensions/prompt/index.ts +19 -0
- package/app/extensions/reload/index.ts +21 -0
- package/app/extensions/screen/browser.js +76 -0
- package/app/extensions/screen/index.ts +80 -0
- package/app/extensions/steps/index.ts +17 -0
- package/app/extensions/swarm/README.md +47 -0
- package/app/extensions/swarm/guide.md +11 -0
- package/app/extensions/swarm/index.ts +304 -0
- package/app/extensions/ui/README.md +69 -0
- package/app/extensions/ui/agents.js +45 -0
- package/app/extensions/ui/browser.js +363 -0
- package/app/extensions/ui/components/App.js +28 -0
- package/app/extensions/ui/components/Button.js +28 -0
- package/app/extensions/ui/components/Card.js +23 -0
- package/app/extensions/ui/components/Column.js +17 -0
- package/app/extensions/ui/components/Markdown.js +37 -0
- package/app/extensions/ui/components/Row.js +17 -0
- package/app/extensions/ui/components/Table.js +31 -0
- package/app/extensions/ui/components/Text.js +19 -0
- package/app/extensions/ui/components/TextField.js +30 -0
- package/app/extensions/ui/guide.md +7 -0
- package/app/extensions/ui/index.ts +271 -0
- package/app/extensions/ui/skills/agent-apps/SKILL.md +91 -0
- package/app/extensions/ui/skills/ui-check/SKILL.md +71 -0
- package/app/extensions/ui/skills/ui-check/scripts/check.mjs +306 -0
- package/app/extensions/ui/skills/ui-design/SKILL.md +123 -0
- package/app/extensions/ui/voice.js +114 -0
- package/app/extensions/ui_history/browser.js +97 -0
- package/app/extensions/ui_history/index.ts +109 -0
- package/app/extensions/versions/browser.js +58 -0
- package/app/extensions/versions/index.ts +168 -0
- package/app/extensions/viewer/README.md +12 -0
- package/app/extensions/viewer/browser.js +322 -0
- package/app/extensions/viewer/guide.md +5 -0
- package/app/extensions/viewer/index.ts +209 -0
- package/app/mcp.json +3 -0
- package/app/skills/plugin-map/SKILL.md +49 -0
- package/app/skills/write-skill/SKILL.md +57 -0
- package/app/ui/apps/.keep +0 -0
- package/bin/chalky.mjs +11 -0
- package/node_modules/xlsx/CHANGELOG.md +361 -0
- package/node_modules/xlsx/LICENSE +201 -0
- package/node_modules/xlsx/README.md +41 -0
- package/node_modules/xlsx/bin/xlsx.njs +310 -0
- package/node_modules/xlsx/bower.json +22 -0
- package/node_modules/xlsx/dist/LICENSE +201 -0
- package/node_modules/xlsx/dist/cpexcel.d.ts +39 -0
- package/node_modules/xlsx/dist/cpexcel.full.mjs +1502 -0
- package/node_modules/xlsx/dist/cpexcel.js +1506 -0
- package/node_modules/xlsx/dist/shim.min.js +2 -0
- package/node_modules/xlsx/dist/xlsx.core.min.js +18 -0
- package/node_modules/xlsx/dist/xlsx.core.min.map +1 -0
- package/node_modules/xlsx/dist/xlsx.extendscript.js +28259 -0
- package/node_modules/xlsx/dist/xlsx.full.min.js +24 -0
- package/node_modules/xlsx/dist/xlsx.full.min.map +1 -0
- package/node_modules/xlsx/dist/xlsx.mini.min.js +10 -0
- package/node_modules/xlsx/dist/xlsx.mini.min.map +1 -0
- package/node_modules/xlsx/dist/xlsx.zahl.js +4 -0
- package/node_modules/xlsx/dist/xlsx.zahl.mjs +2 -0
- package/node_modules/xlsx/dist/zahl.d.ts +4 -0
- package/node_modules/xlsx/package.json +183 -0
- package/node_modules/xlsx/types/index.d.ts +1065 -0
- package/node_modules/xlsx/types/tsconfig.json +15 -0
- package/node_modules/xlsx/xlsx.js +28103 -0
- package/node_modules/xlsx/xlsx.mjs +28228 -0
- package/node_modules/xlsx/xlsxworker.js +14 -0
- package/package.json +42 -4
- package/server.ts +275 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// The page the user sees (Python: chat_ui.py), as an extension like the others: agents can change it, and the
|
|
2
|
+
// versions extension keeps and rolls back its history.
|
|
3
|
+
// GET / page.html, read fresh on every load (edits show on reload)
|
|
4
|
+
// GET /page/scripts the browser parts the page imports: one per extension folder with a browser.js
|
|
5
|
+
// GET /extensions/<name>/browser.js that file (only browser.js: an extension's other files aren't served)
|
|
6
|
+
// An extension's browser.js is its part of the page: its default export gets the page's API (see page.html's header).
|
|
7
|
+
// Found by looking in each folder, as pi finds index.ts, so an extension has nothing to register.
|
|
8
|
+
// The conversation on the page: pi's messages in the page's format (OpenAI chat, as the Python harness stored them).
|
|
9
|
+
// event "message" {agent, role, content, ...} as an agent's pi session ends each message (host.eventHandlers)
|
|
10
|
+
// events "run_start", "run_end", "compacted" an agent's run started, ended (settled), its context was compacted
|
|
11
|
+
// on opening, a page gets every agent's record, in time order (host.connectHandlers): all its session files
|
|
12
|
+
// (compaction keeps the original entries, so the page still shows everything)
|
|
13
|
+
// "joined" (an agent's first system message) and reply_to (who a turn's answer goes to: the host's "chalky.turn"
|
|
14
|
+
// entry just before the user message that starts it) are read from the session, so nothing is kept here.
|
|
15
|
+
import fs from "node:fs";
|
|
16
|
+
import path from "node:path";
|
|
17
|
+
import { SessionManager, type ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
18
|
+
|
|
19
|
+
const host = (globalThis as any).chalky;
|
|
20
|
+
const EXTENSIONS = path.dirname(import.meta.dirname);
|
|
21
|
+
const browserFile = (name: string) => path.join(EXTENSIONS, name, "browser.js");
|
|
22
|
+
|
|
23
|
+
export default function (_pi: ExtensionAPI) {
|
|
24
|
+
host.routes.set("/", (_req: any, res: any) =>
|
|
25
|
+
res.writeHead(200, { "content-type": "text/html", "cache-control": "no-cache" }).end(fs.readFileSync(path.join(import.meta.dirname, "page.html"))));
|
|
26
|
+
host.routes.set("/page/scripts", (_req: any, res: any) => {
|
|
27
|
+
const names = fs.readdirSync(EXTENSIONS).filter((n) => fs.existsSync(browserFile(n))).sort();
|
|
28
|
+
res.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify(names.map((n) => `/extensions/${n}/browser.js`)));
|
|
29
|
+
});
|
|
30
|
+
host.routes.set("/extensions/", (req: any, res: any) => {
|
|
31
|
+
const [, , name, file] = new URL(req.url, "http://x").pathname.split("/");
|
|
32
|
+
if (file !== "browser.js" || !/^[\w-]+$/.test(name ?? "") || !fs.existsSync(browserFile(name))) return res.writeHead(404).end();
|
|
33
|
+
res.writeHead(200, { "content-type": "text/javascript", "cache-control": "no-cache" }).end(fs.readFileSync(browserFile(name)));
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const text = (content: any) => typeof content === "string" ? content
|
|
38
|
+
: content.filter((p: any) => p.type === "text").map((p: any) => p.text).join("");
|
|
39
|
+
|
|
40
|
+
// pi message -> the page's message. first: the agent's first system message, shown as "<agent> joined".
|
|
41
|
+
// replyTo: on the message that starts a turn, who its answer goes to (not on items slipped into a running turn).
|
|
42
|
+
function toPage(m: any, first = false, replyTo?: string) {
|
|
43
|
+
const ts = (m.timestamp ?? Date.now()) / 1000;
|
|
44
|
+
if (m.role === "system") return first ? { role: "system", content: "", ts } : null;
|
|
45
|
+
if (m.role === "user" || (m.role === "custom" && m.customType === "inbox")) { // inbox: swarm items filed without a turn
|
|
46
|
+
return { role: "user", content: text(m.content), ...(replyTo && { reply_to: replyTo }), ts };
|
|
47
|
+
}
|
|
48
|
+
if (m.role === "assistant") {
|
|
49
|
+
const calls = m.content.filter((p: any) => p.type === "toolCall")
|
|
50
|
+
.map((p: any) => ({ id: p.id, type: "function", function: { name: p.name, arguments: JSON.stringify(p.arguments) } }));
|
|
51
|
+
const reasoning = m.content.filter((p: any) => p.type === "thinking").map((p: any) => p.thinking).join("\n");
|
|
52
|
+
return { role: "assistant", content: text(m.content), ...(reasoning && { reasoning }), ...(calls.length && { tool_calls: calls }),
|
|
53
|
+
...(m.errorMessage && { content: `error: ${m.errorMessage}` }), ts };
|
|
54
|
+
}
|
|
55
|
+
if (m.role === "toolResult")
|
|
56
|
+
return { role: "tool", tool_call_id: m.toolCallId, content: (m.isError ? "error: " : "") + text(m.content), ts };
|
|
57
|
+
return null; // pi's own kinds (custom, compaction summary, ...): not shown
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Every message of an agent, from all its session files (older rounds first), in the page's format
|
|
61
|
+
function record(name: string) {
|
|
62
|
+
const sm = host.agents.get(name).session.sessionManager, current = sm.getSessionFile(), dir = path.dirname(current);
|
|
63
|
+
return fs.readdirSync(dir).filter((f) => f.endsWith(".jsonl")).sort().flatMap((f) => {
|
|
64
|
+
const p = path.join(dir, f);
|
|
65
|
+
const entries = p === current ? sm.getEntries() : SessionManager.open(p, dir).getEntries();
|
|
66
|
+
let joined = false, replyTo: string | undefined;
|
|
67
|
+
return entries.flatMap((e: any) => {
|
|
68
|
+
if (e.type === "custom" && e.customType === "chalky.turn") replyTo = e.data.reply_to;
|
|
69
|
+
const msg = e.type === "message" ? e.message : e.type === "custom_message" ? { ...e, role: "custom", timestamp: Date.parse(e.timestamp) } : null;
|
|
70
|
+
if (!msg) return [];
|
|
71
|
+
const m = toPage(msg, !joined && msg.role === "system", msg.role === "user" ? replyTo : undefined);
|
|
72
|
+
if (msg.role === "system") joined = true;
|
|
73
|
+
if (msg.role === "user") replyTo = undefined;
|
|
74
|
+
return m ? [{ agent: name, ...m }] : [];
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// pi saves a message after its message_end, so the session holds what came before it
|
|
80
|
+
host.eventHandlers.set("page", (name: string, ev: any) => {
|
|
81
|
+
if (ev.type === "message_end") {
|
|
82
|
+
const entries = host.agents.get(name)?.session.sessionManager.getEntries() ?? [];
|
|
83
|
+
const first = ev.message.role === "system" && !entries.some((e: any) => e.type === "message" && e.message.role === "system");
|
|
84
|
+
const last = entries.findLast((e: any) => !(e.type === "message" && e.message.role === "system")); // pi may put a prompt update between
|
|
85
|
+
const replyTo = ev.message.role === "user" && last?.type === "custom" && last.customType === "chalky.turn" ? last.data.reply_to : undefined;
|
|
86
|
+
const m = toPage(ev.message, first, replyTo);
|
|
87
|
+
if (m) host.broadcast("message", { agent: name, ...m });
|
|
88
|
+
} else if (ev.type === "agent_start") host.broadcast("run_start", { agent: name });
|
|
89
|
+
else if (ev.type === "agent_settled") host.broadcast("run_end", { agent: name });
|
|
90
|
+
else if (ev.type === "compaction_end" && ev.result)
|
|
91
|
+
host.broadcast("compacted", { agent: name, tokens_before: ev.result.tokensBefore, tokens_after: ev.result.estimatedTokensAfter ?? "?" });
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
host.connectHandlers.set("page", (send: (type: string, data: object) => void) => {
|
|
95
|
+
for (const m of [...host.agents.keys()].flatMap(record).sort((x: any, y: any) => x.ts - y.ts)) send("message", m);
|
|
96
|
+
});
|