@joeyshi12/casper 0.7.3 → 0.8.1
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 +12 -1
- package/dist/agents/prompt.md +46 -0
- package/dist/mcp.js +412 -0
- package/dist/server.js +546 -37
- package/dist/web/assets/{abnfDiagram-N423BO3Z-5RMwP9tv.js → abnfDiagram-N423BO3Z-J5DaDTt8.js} +1 -1
- package/dist/web/assets/{arc-DEuUsPX5.js → arc-CXWeATz6.js} +1 -1
- package/dist/web/assets/{architectureDiagram-T3A2C74G-k4h0zktw.js → architectureDiagram-T3A2C74G-ecXfY9My.js} +1 -1
- package/dist/web/assets/{blockDiagram-VBNYF7ZC-qTl9ZS2k.js → blockDiagram-VBNYF7ZC-D5ClKOWV.js} +1 -1
- package/dist/web/assets/{c4Diagram-5PPSVZJV-R6o_zt-Q.js → c4Diagram-5PPSVZJV-BxW2-O4j.js} +1 -1
- package/dist/web/assets/channel-BXz-ycSk.js +1 -0
- package/dist/web/assets/{chunk-2GRJ4B5K-CrJyVfhF.js → chunk-2GRJ4B5K-BBWhz2x0.js} +1 -1
- package/dist/web/assets/{chunk-2Q5K7J3B-BvGurkBq.js → chunk-2Q5K7J3B-CfD68qFQ.js} +1 -1
- package/dist/web/assets/{chunk-5RXB4S5H-DuE267ol.js → chunk-5RXB4S5H-DaznI8_V.js} +1 -1
- package/dist/web/assets/{chunk-5VM5RSS4-DAVY20oh.js → chunk-5VM5RSS4-BYxWXCvw.js} +1 -1
- package/dist/web/assets/{chunk-6Q2QTUOP-DvkSg8Wl.js → chunk-6Q2QTUOP-C8zmDMoc.js} +1 -1
- package/dist/web/assets/{chunk-GF5L2VYU-B8KQ7FAJ.js → chunk-GF5L2VYU-BXGR_P0f.js} +1 -1
- package/dist/web/assets/{chunk-JWPE2WC7-D2J6xFCq.js → chunk-JWPE2WC7-DsHbIvH7.js} +1 -1
- package/dist/web/assets/{chunk-KBJHAD2P-BfgGkRN_.js → chunk-KBJHAD2P-B8G6QD3I.js} +1 -1
- package/dist/web/assets/{chunk-RYQCIY6F-C0uby4vT.js → chunk-RYQCIY6F-B1rujkgY.js} +1 -1
- package/dist/web/assets/{chunk-XXDRQBXY-BAZLB2J1.js → chunk-XXDRQBXY-hjvfwopv.js} +1 -1
- package/dist/web/assets/classDiagram-JCYQIIEL-CRBj8GMD.js +1 -0
- package/dist/web/assets/classDiagram-v2-OCEON4UE-CRBj8GMD.js +1 -0
- package/dist/web/assets/{cose-bilkent-JH36ORCC-8FFjV-r2.js → cose-bilkent-JH36ORCC-D4S1nlYR.js} +1 -1
- package/dist/web/assets/{cynefin-VYW2F7L2-CDT1GZi_.js → cynefin-VYW2F7L2-DtN8m_GE.js} +1 -1
- package/dist/web/assets/{cynefinDiagram-MW4NZA55-DMs5fXGJ.js → cynefinDiagram-MW4NZA55-Dkk-H0Nw.js} +1 -1
- package/dist/web/assets/{dagre-VZM6K2ZE-BUgnrG7T.js → dagre-VZM6K2ZE-BSkCOa-Z.js} +1 -1
- package/dist/web/assets/{diagram-7IWD3JNH-DUJeTMJj.js → diagram-7IWD3JNH-Bses1wzI.js} +1 -1
- package/dist/web/assets/{diagram-B4RE2ZJO-BsVTn5rU.js → diagram-B4RE2ZJO-BW7sntb1.js} +1 -1
- package/dist/web/assets/{diagram-LBJQPF4R--uxNHPeF.js → diagram-LBJQPF4R-DHzgX2HL.js} +1 -1
- package/dist/web/assets/{diagram-Q27KOJAE-GYAROo1s.js → diagram-Q27KOJAE-mcXdgoK9.js} +1 -1
- package/dist/web/assets/{diagram-UB23O5K3-CpJvxU_K.js → diagram-UB23O5K3-BO5P9LAa.js} +1 -1
- package/dist/web/assets/{ebnfDiagram-BXEA7PRR-l3iEqoSP.js → ebnfDiagram-BXEA7PRR-F0zOfsYe.js} +1 -1
- package/dist/web/assets/{erDiagram-JOGREHBK-BoFHrs3B.js → erDiagram-JOGREHBK-aOYH_ZnE.js} +1 -1
- package/dist/web/assets/{flowDiagram-UKHOOZJN-CXMq4-uD.js → flowDiagram-UKHOOZJN-DmtkMJ60.js} +1 -1
- package/dist/web/assets/{ganttDiagram-PKOTCBZU-YMv8lvSL.js → ganttDiagram-PKOTCBZU-BFy8QpeS.js} +1 -1
- package/dist/web/assets/{gitGraphDiagram-DS77QQ5N-BgrfufCE.js → gitGraphDiagram-DS77QQ5N-CjbCeQfE.js} +1 -1
- package/dist/web/assets/{index-IBYN7wml.js → index-Bbzvwn2R.js} +207 -53
- package/dist/web/assets/{index-D7QnyK89.css → index-POlrwDS0.css} +1 -1
- package/dist/web/assets/{infoDiagram-6WML65LV-DMpqFKuC.js → infoDiagram-6WML65LV-CGFvyGjJ.js} +1 -1
- package/dist/web/assets/{ishikawaDiagram-WSZJBQD7-BKdkzZXu.js → ishikawaDiagram-WSZJBQD7-BbVf1sRd.js} +1 -1
- package/dist/web/assets/{journeyDiagram-NVQOT4AX-NPjJ9Fq8.js → journeyDiagram-NVQOT4AX-BNevDB-1.js} +1 -1
- package/dist/web/assets/{kanban-definition-27J2QSJJ-MSVfDvXb.js → kanban-definition-27J2QSJJ-BdmYFEey.js} +1 -1
- package/dist/web/assets/{linear-Bugxdj26.js → linear-DJt4yr3f.js} +1 -1
- package/dist/web/assets/{mermaid.core-BrC5_l7I.js → mermaid.core-D-YupbG3.js} +5 -5
- package/dist/web/assets/{mindmap-definition-FAOFIHXS-yB60YQKy.js → mindmap-definition-FAOFIHXS-toscoNiP.js} +1 -1
- package/dist/web/assets/{pegDiagram-VL7TDLO6-BfdGiZwB.js → pegDiagram-VL7TDLO6-42qysB7S.js} +1 -1
- package/dist/web/assets/{pieDiagram-7S7Q4E2Y-BuJwU-QQ.js → pieDiagram-7S7Q4E2Y-DeC8rSjm.js} +1 -1
- package/dist/web/assets/{quadrantDiagram-CIZ2JOQS-DvYy4rS6.js → quadrantDiagram-CIZ2JOQS-BsmBMVxR.js} +1 -1
- package/dist/web/assets/{railroadDiagram-AXF67PYL-D0Slzbqv.js → railroadDiagram-AXF67PYL-CUEYoy5N.js} +1 -1
- package/dist/web/assets/{requirementDiagram-LRYGKXZP-O1O4JCzu.js → requirementDiagram-LRYGKXZP-QOIVNSdo.js} +1 -1
- package/dist/web/assets/{sankeyDiagram-W5VNT64P-WTewsL_K.js → sankeyDiagram-W5VNT64P-BTvBZ4O6.js} +1 -1
- package/dist/web/assets/{sequenceDiagram-SI44F4Z6-BUoBi4kR.js → sequenceDiagram-SI44F4Z6-PgaCw-bZ.js} +1 -1
- package/dist/web/assets/{sizeCapture-X5ZJPWSS-BV9d3RVn.js → sizeCapture-X5ZJPWSS-xVBXwmWY.js} +1 -1
- package/dist/web/assets/{stateDiagram-OKZ733FA-BqdAeMq4.js → stateDiagram-OKZ733FA-BWvlFx8p.js} +1 -1
- package/dist/web/assets/stateDiagram-v2-UEYNNEHI-CWroHbLn.js +1 -0
- package/dist/web/assets/{swimlanes-SLNWSIFB-Dn0Z0yF4.js → swimlanes-SLNWSIFB-B6SREfpi.js} +2 -2
- package/dist/web/assets/swimlanesDiagram-ULZ7WXOC-B7_kKLQV.js +8 -0
- package/dist/web/assets/{timeline-definition-Z64GVDOM-RXIqWmas.js → timeline-definition-Z64GVDOM-pOrViFO-.js} +1 -1
- package/dist/web/assets/{vennDiagram-T6HMQDX7-Djv2Kody.js → vennDiagram-T6HMQDX7-DXbf3Z8V.js} +1 -1
- package/dist/web/assets/{wardleyDiagram-T6FBY63Y-k8z1iXMI.js → wardleyDiagram-T6FBY63Y-BulJVCrV.js} +1 -1
- package/dist/web/assets/{xychartDiagram-ELKLHX3M-DBRaiGnz.js → xychartDiagram-ELKLHX3M-MI1zCRjW.js} +1 -1
- package/dist/web/index.html +2 -2
- package/dist/web/sw.js +1 -1
- package/package.json +1 -1
- package/dist/agents/casper.json +0 -16
- package/dist/web/assets/channel-BQC-40u0.js +0 -1
- package/dist/web/assets/classDiagram-JCYQIIEL-9L45zm4i.js +0 -1
- package/dist/web/assets/classDiagram-v2-OCEON4UE-9L45zm4i.js +0 -1
- package/dist/web/assets/stateDiagram-v2-UEYNNEHI-DQeB4eKD.js +0 -1
- package/dist/web/assets/swimlanesDiagram-ULZ7WXOC-Dl6pHbTK.js +0 -8
package/dist/server.js
CHANGED
|
@@ -74,26 +74,62 @@ var init_settings = __esm({
|
|
|
74
74
|
// server/src/cli/agentFile.ts
|
|
75
75
|
var agentFile_exports = {};
|
|
76
76
|
__export(agentFile_exports, {
|
|
77
|
+
agentConfig: () => agentConfig,
|
|
78
|
+
agentPrompt: () => agentPrompt,
|
|
77
79
|
installAgentFile: () => installAgentFile
|
|
78
80
|
});
|
|
79
81
|
import crypto2 from "node:crypto";
|
|
80
82
|
import fs3 from "node:fs";
|
|
81
83
|
import path4 from "node:path";
|
|
82
84
|
import url from "node:url";
|
|
83
|
-
function
|
|
85
|
+
function agentPrompt() {
|
|
84
86
|
const here = path4.dirname(url.fileURLToPath(import.meta.url));
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
87
|
+
const candidates = [
|
|
88
|
+
path4.resolve(here, "agents/prompt.md"),
|
|
89
|
+
// bundled: beside server.js
|
|
90
|
+
path4.resolve(here, "../../../assets/agents/prompt.md")
|
|
91
|
+
// from source
|
|
92
|
+
];
|
|
93
|
+
const found = candidates.find((c) => fs3.existsSync(c));
|
|
94
|
+
return found ? fs3.readFileSync(found, "utf8").trimEnd() : null;
|
|
95
|
+
}
|
|
96
|
+
function mcpServerPath() {
|
|
97
|
+
const here = path4.dirname(url.fileURLToPath(import.meta.url));
|
|
98
|
+
const candidates = [
|
|
99
|
+
path4.resolve(here, "mcp.js"),
|
|
100
|
+
// bundled: beside server.js
|
|
101
|
+
path4.resolve(here, "../../dist/mcp.js")
|
|
102
|
+
// from source, if built
|
|
103
|
+
];
|
|
104
|
+
return candidates.find((c) => fs3.existsSync(c)) ?? null;
|
|
105
|
+
}
|
|
106
|
+
function agentConfig(prompt, mcp) {
|
|
107
|
+
return {
|
|
108
|
+
name: "casper",
|
|
109
|
+
description: "Casper \u2014 a coding agent for developing from the chat web interface.",
|
|
110
|
+
prompt,
|
|
111
|
+
mcpServers: {
|
|
112
|
+
casper: mcp ? { command: process.execPath, args: [mcp], env: {}, timeout: 1e4 } : { command: "casper", args: ["mcp"], env: {}, timeout: 1e4 }
|
|
113
|
+
},
|
|
114
|
+
tools: ["*"],
|
|
115
|
+
toolAliases: {},
|
|
116
|
+
allowedTools: [],
|
|
117
|
+
resources: [],
|
|
118
|
+
hooks: {},
|
|
119
|
+
toolsSettings: {},
|
|
120
|
+
includeMcpJson: true,
|
|
121
|
+
model: null
|
|
122
|
+
};
|
|
88
123
|
}
|
|
89
|
-
function sha256(
|
|
90
|
-
return crypto2.createHash("sha256").update(
|
|
124
|
+
function sha256(text2) {
|
|
125
|
+
return crypto2.createHash("sha256").update(text2).digest("hex");
|
|
91
126
|
}
|
|
92
127
|
function installAgentFile(home2, dataDir) {
|
|
93
|
-
const src = sourceFile();
|
|
94
128
|
const target = path4.join(home2, ".kiro", "agents", "casper.json");
|
|
95
|
-
|
|
96
|
-
|
|
129
|
+
const prompt = agentPrompt();
|
|
130
|
+
if (prompt === null) return { action: "no-source", target };
|
|
131
|
+
const desired = `${JSON.stringify(agentConfig(prompt, mcpServerPath()), null, 2)}
|
|
132
|
+
`;
|
|
97
133
|
const stampFile = path4.join(dataDir, "agent-stamp");
|
|
98
134
|
const stamp = fs3.existsSync(stampFile) ? fs3.readFileSync(stampFile, "utf8").trim() : "";
|
|
99
135
|
const write = () => {
|
|
@@ -611,20 +647,20 @@ var init_acp = __esm({
|
|
|
611
647
|
});
|
|
612
648
|
|
|
613
649
|
// shared/dist/attachments.js
|
|
614
|
-
function attachmentPaths(
|
|
615
|
-
const line =
|
|
650
|
+
function attachmentPaths(text2) {
|
|
651
|
+
const line = text2.split("\n").find((l) => l.startsWith(ATTACHMENTS_PREFIX));
|
|
616
652
|
if (!line)
|
|
617
653
|
return [];
|
|
618
654
|
return line.slice(ATTACHMENTS_PREFIX.length).split(", ").map((s) => s.trim()).filter(Boolean);
|
|
619
655
|
}
|
|
620
|
-
function imageAttachmentPaths(
|
|
621
|
-
return attachmentPaths(
|
|
656
|
+
function imageAttachmentPaths(text2) {
|
|
657
|
+
return attachmentPaths(text2).filter((p) => {
|
|
622
658
|
const lower = p.toLowerCase();
|
|
623
659
|
return IMAGE_EXTS.some((ext) => lower.endsWith(ext));
|
|
624
660
|
});
|
|
625
661
|
}
|
|
626
|
-
function stripAttachmentsLine(
|
|
627
|
-
return
|
|
662
|
+
function stripAttachmentsLine(text2) {
|
|
663
|
+
return text2.split("\n").filter((l) => !l.startsWith(ATTACHMENTS_PREFIX)).join("\n").trim();
|
|
628
664
|
}
|
|
629
665
|
var ATTACHMENTS_PREFIX, IMAGE_EXTS;
|
|
630
666
|
var init_attachments = __esm({
|
|
@@ -1304,17 +1340,17 @@ async function hydrateTranscript(sessionId) {
|
|
|
1304
1340
|
const pushMsg = (msg) => items.push({ type: "message", message: msg });
|
|
1305
1341
|
if (entry.kind === "Prompt") {
|
|
1306
1342
|
const raw2 = textOf("text");
|
|
1307
|
-
const
|
|
1343
|
+
const text2 = stripAttachmentsLine(raw2);
|
|
1308
1344
|
const imagePaths = imageAttachmentPaths(raw2);
|
|
1309
|
-
if (
|
|
1310
|
-
pushMsg({ id: `u-${baseId}`, role: "user", text, timestamp: ts, imagePaths });
|
|
1345
|
+
if (text2.trim() || imagePaths.length)
|
|
1346
|
+
pushMsg({ id: `u-${baseId}`, role: "user", text: text2, timestamp: ts, imagePaths });
|
|
1311
1347
|
} else if (entry.kind === "AssistantMessage") {
|
|
1312
1348
|
const thinking = textOf("thinking");
|
|
1313
1349
|
if (thinking.trim())
|
|
1314
1350
|
pushMsg({ id: `t-${baseId}`, role: "thinking", text: thinking, timestamp: ts });
|
|
1315
|
-
const
|
|
1316
|
-
if (
|
|
1317
|
-
pushMsg({ id: `a-${baseId}`, role: "assistant", text, timestamp: ts });
|
|
1351
|
+
const text2 = textOf("text");
|
|
1352
|
+
if (text2.trim())
|
|
1353
|
+
pushMsg({ id: `a-${baseId}`, role: "assistant", text: text2, timestamp: ts });
|
|
1318
1354
|
for (const c of content) {
|
|
1319
1355
|
const d = toolUseData(c);
|
|
1320
1356
|
if (!d) continue;
|
|
@@ -2107,8 +2143,8 @@ async function listAgents() {
|
|
|
2107
2143
|
cwd: config.defaultCwd,
|
|
2108
2144
|
maxBuffer: 2 * 1024 * 1024
|
|
2109
2145
|
});
|
|
2110
|
-
const
|
|
2111
|
-
for (const rawLine of
|
|
2146
|
+
const text2 = (stderr || "") + "\n" + (stdout || "");
|
|
2147
|
+
for (const rawLine of text2.split("\n")) {
|
|
2112
2148
|
const line = rawLine.replace(ANSI, "");
|
|
2113
2149
|
const m = /^\s{0,2}(\*\s)?([A-Za-z0-9_-]+)\s{2,}(Global|Workspace|Local)\b/.exec(
|
|
2114
2150
|
line
|
|
@@ -3271,7 +3307,8 @@ var init_server = __esm({
|
|
|
3271
3307
|
// server/src/cli/doctor.ts
|
|
3272
3308
|
var doctor_exports = {};
|
|
3273
3309
|
__export(doctor_exports, {
|
|
3274
|
-
doctor: () => doctor
|
|
3310
|
+
doctor: () => doctor,
|
|
3311
|
+
mcpWiring: () => mcpWiring
|
|
3275
3312
|
});
|
|
3276
3313
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
3277
3314
|
import fs14 from "node:fs";
|
|
@@ -3289,6 +3326,28 @@ function which(bin) {
|
|
|
3289
3326
|
}
|
|
3290
3327
|
return void 0;
|
|
3291
3328
|
}
|
|
3329
|
+
function mcpWiring(agentJson, resolve) {
|
|
3330
|
+
let servers;
|
|
3331
|
+
try {
|
|
3332
|
+
servers = JSON.parse(agentJson).mcpServers;
|
|
3333
|
+
} catch {
|
|
3334
|
+
return { ok: false, detail: "the agent file is not valid JSON" };
|
|
3335
|
+
}
|
|
3336
|
+
const server = servers?.casper;
|
|
3337
|
+
if (!server) {
|
|
3338
|
+
return { ok: false, detail: "not declared in the agent file, so widgets are unavailable" };
|
|
3339
|
+
}
|
|
3340
|
+
const command = typeof server.command === "string" ? server.command : "";
|
|
3341
|
+
const args = Array.isArray(server.args) ? server.args.filter((a) => typeof a === "string") : [];
|
|
3342
|
+
if (!resolve(command)) {
|
|
3343
|
+
return { ok: false, detail: `${command || "(no command)"} not found - widgets are unavailable` };
|
|
3344
|
+
}
|
|
3345
|
+
const script = args.find((a) => a.endsWith(".js"));
|
|
3346
|
+
if (script && !fs14.existsSync(script)) {
|
|
3347
|
+
return { ok: false, detail: `${script} is gone - delete the agent file and restart to rewrite it` };
|
|
3348
|
+
}
|
|
3349
|
+
return { ok: true, detail: script ?? `${command} ${args.join(" ")}` };
|
|
3350
|
+
}
|
|
3292
3351
|
function checks() {
|
|
3293
3352
|
const out = [];
|
|
3294
3353
|
out.push({
|
|
@@ -3357,11 +3416,16 @@ function checks() {
|
|
|
3357
3416
|
}
|
|
3358
3417
|
);
|
|
3359
3418
|
const agent = path15.join(config.kiroSessionsDir, "..", "..", "agents", "casper.json");
|
|
3419
|
+
const hasAgent = fs14.existsSync(agent);
|
|
3360
3420
|
out.push({
|
|
3361
|
-
ok:
|
|
3421
|
+
ok: hasAgent,
|
|
3362
3422
|
name: "casper agent",
|
|
3363
|
-
detail:
|
|
3423
|
+
detail: hasAgent ? agent : `${agent} missing - it is installed on first run`
|
|
3364
3424
|
});
|
|
3425
|
+
if (hasAgent) {
|
|
3426
|
+
const wiring = mcpWiring(fs14.readFileSync(agent, "utf8"), which);
|
|
3427
|
+
out.push({ ok: wiring.ok, name: "casper mcp", detail: wiring.detail });
|
|
3428
|
+
}
|
|
3365
3429
|
return out;
|
|
3366
3430
|
}
|
|
3367
3431
|
function doctor() {
|
|
@@ -3388,6 +3452,445 @@ var init_doctor = __esm({
|
|
|
3388
3452
|
}
|
|
3389
3453
|
});
|
|
3390
3454
|
|
|
3455
|
+
// server/src/mcp/guidelines.ts
|
|
3456
|
+
function getGuidelines(modules) {
|
|
3457
|
+
const parts = [CORE];
|
|
3458
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3459
|
+
for (const mod of modules) {
|
|
3460
|
+
const sections = MODULE_SECTIONS[mod];
|
|
3461
|
+
if (!sections) continue;
|
|
3462
|
+
for (const section of sections) {
|
|
3463
|
+
if (seen.has(section)) continue;
|
|
3464
|
+
seen.add(section);
|
|
3465
|
+
parts.push(section);
|
|
3466
|
+
}
|
|
3467
|
+
}
|
|
3468
|
+
return parts.join("\n\n");
|
|
3469
|
+
}
|
|
3470
|
+
var MODULES, CORE, COLOR, UI, CHARTS, SVG, DIAGRAMS, ART, MODULE_SECTIONS;
|
|
3471
|
+
var init_guidelines = __esm({
|
|
3472
|
+
"server/src/mcp/guidelines.ts"() {
|
|
3473
|
+
"use strict";
|
|
3474
|
+
MODULES = ["interactive", "chart", "diagram", "art"];
|
|
3475
|
+
CORE = `# Widgets
|
|
3476
|
+
|
|
3477
|
+
A widget is a self-contained HTML fragment rendered inline in the conversation. No
|
|
3478
|
+
doctype, html, head or body tag - just content. It is not a file and not a
|
|
3479
|
+
deliverable; it is part of what you are saying. Reach for one when a picture
|
|
3480
|
+
answers better than a paragraph.
|
|
3481
|
+
|
|
3482
|
+
## Structure, in this order
|
|
3483
|
+
|
|
3484
|
+
1. A short \`<style>\` block.
|
|
3485
|
+
2. The content markup.
|
|
3486
|
+
3. A single \`<script>\` at the end.
|
|
3487
|
+
|
|
3488
|
+
Order matters. Content renders as it arrives, and scripts run only once the message
|
|
3489
|
+
is complete, so a widget whose script sits at the top looks inert until the end.
|
|
3490
|
+
|
|
3491
|
+
## Hard rules
|
|
3492
|
+
|
|
3493
|
+
- No gradients, drop shadows or blur. They flash while content is patched in.
|
|
3494
|
+
- No HTML comments. They cost tokens and buy nothing.
|
|
3495
|
+
- Two font weights only: 400 and 500. Never 600 or 700.
|
|
3496
|
+
- Sentence case for every label, heading and button. Never Title Case, never ALL CAPS.
|
|
3497
|
+
- Never hardcode a colour that has a variable below.
|
|
3498
|
+
- Size text in px, 11 to 15 for body and labels, up to 18 for a single heading.
|
|
3499
|
+
- Keep the whole widget under 600px tall unless the content genuinely needs more.
|
|
3500
|
+
|
|
3501
|
+
## The sandbox
|
|
3502
|
+
|
|
3503
|
+
The frame has an opaque origin. localStorage, sessionStorage, cookies and requests
|
|
3504
|
+
to Casper all throw or fail. Hold state in a variable for the life of the page.
|
|
3505
|
+
|
|
3506
|
+
Libraries load from these hosts only: cdnjs.cloudflare.com, cdn.jsdelivr.net,
|
|
3507
|
+
unpkg.com, esm.sh. Anything else is refused by the content security policy, as is
|
|
3508
|
+
eval and new Function, so pick libraries that don't rely on them.
|
|
3509
|
+
|
|
3510
|
+
## Theme
|
|
3511
|
+
|
|
3512
|
+
The background is transparent and the app's own variables are set. Use them:
|
|
3513
|
+
|
|
3514
|
+
--color-text-primary, --color-text-secondary
|
|
3515
|
+
--color-background-primary, --color-background-secondary
|
|
3516
|
+
--color-border
|
|
3517
|
+
--color-accent, --color-accent-alt
|
|
3518
|
+
--color-teal, --color-green, --color-yellow, --color-orange, --color-red
|
|
3519
|
+
--font-body, --font-mono
|
|
3520
|
+
|
|
3521
|
+
Read them in script with getComputedStyle(document.documentElement).getPropertyValue.
|
|
3522
|
+
|
|
3523
|
+
## Talking back
|
|
3524
|
+
|
|
3525
|
+
casper.sendPrompt(text) sends a message as if the user typed it, indistinguishable
|
|
3526
|
+
in the transcript from one they wrote. Most widgets need no button at all. Add one
|
|
3527
|
+
only when the obvious next step is a question they would otherwise type out by hand,
|
|
3528
|
+
and never as decoration or to invite engagement. One at most.`;
|
|
3529
|
+
COLOR = `## Colour
|
|
3530
|
+
|
|
3531
|
+
Six accents are available: --color-accent (purple), --color-accent-alt (pink),
|
|
3532
|
+
--color-teal, --color-green, --color-yellow, --color-orange, --color-red.
|
|
3533
|
+
|
|
3534
|
+
Colour encodes meaning, never sequence. If two series differ only by being
|
|
3535
|
+
different series, use one accent at two opacities rather than two hues. Two or
|
|
3536
|
+
three hues per widget is the ceiling.
|
|
3537
|
+
|
|
3538
|
+
Semantics people already expect: green for success or growth, red for error or
|
|
3539
|
+
loss, orange for warning or pending, teal for neutral information, purple for the
|
|
3540
|
+
primary subject.
|
|
3541
|
+
|
|
3542
|
+
For text on a filled background, use --color-background-primary as the text colour
|
|
3543
|
+
rather than black. For a tint, use the accent at 12 to 20 percent opacity with the
|
|
3544
|
+
accent itself as the border.`;
|
|
3545
|
+
UI = `## Components
|
|
3546
|
+
|
|
3547
|
+
Card: background --color-background-secondary, 1px --color-border, radius 10px,
|
|
3548
|
+
padding 12px 14px. No shadow.
|
|
3549
|
+
|
|
3550
|
+
Metric: label 11px --color-text-secondary above a 20px 500-weight value. Group
|
|
3551
|
+
metrics in a grid with 12px gaps, never a table.
|
|
3552
|
+
|
|
3553
|
+
Button: 12px text, background --color-background-secondary, 1px --color-border,
|
|
3554
|
+
radius 6px, padding 5px 10px. On hover, move the border to --color-accent. Never
|
|
3555
|
+
paint a button in an accent colour unless it is the single primary action.
|
|
3556
|
+
|
|
3557
|
+
Input and range: set accent-color to var(--color-accent) and let the browser style
|
|
3558
|
+
the rest.
|
|
3559
|
+
|
|
3560
|
+
Table: only for genuinely tabular data. 1px --color-border between rows, no
|
|
3561
|
+
vertical rules, 12px text, numbers right-aligned in --font-mono.
|
|
3562
|
+
|
|
3563
|
+
Rows of key and value: a flex row with the label in --color-text-secondary and the
|
|
3564
|
+
value in --font-mono, separated by a border-bottom on all but the last.`;
|
|
3565
|
+
CHARTS = `## Charts
|
|
3566
|
+
|
|
3567
|
+
Chart.js from cdn.jsdelivr.net is the default choice. Load it with a script tag
|
|
3568
|
+
before your own script; it will have finished loading by the time your script runs,
|
|
3569
|
+
so there's no need to poll for it.
|
|
3570
|
+
|
|
3571
|
+
Wrap every canvas in a div with position relative and an explicit height, and set
|
|
3572
|
+
maintainAspectRatio to false. Without both, the canvas grows without bound.
|
|
3573
|
+
|
|
3574
|
+
Turn the built-in legend off (plugins.legend.display false) and write the legend as
|
|
3575
|
+
HTML if it's needed - the built-in one ignores the theme.
|
|
3576
|
+
|
|
3577
|
+
Grid lines in --color-border at low opacity, ticks in --color-text-secondary, 11px.
|
|
3578
|
+
Datasets take an accent colour with borderWidth 2 and no point markers unless
|
|
3579
|
+
individual readings matter.
|
|
3580
|
+
|
|
3581
|
+
Format numbers so the sign leads: -$5M, never $-5M. Abbreviate above four digits
|
|
3582
|
+
(12.4k, 3.1M). Percentages get one decimal at most.
|
|
3583
|
+
|
|
3584
|
+
Pick the form from the question: trend over time is a line, comparison across
|
|
3585
|
+
categories is a horizontal bar when labels are words, composition is a stacked bar
|
|
3586
|
+
rather than a pie unless there are three slices or fewer.`;
|
|
3587
|
+
SVG = `## SVG
|
|
3588
|
+
|
|
3589
|
+
Set viewBox and leave width and height off, so the drawing scales to the frame.
|
|
3590
|
+
Compute the viewBox from the content bounds and add 8 units of padding on every
|
|
3591
|
+
side; anything drawn outside is invisible and reviewers will not see the mistake.
|
|
3592
|
+
|
|
3593
|
+
Text width is the usual cause of overflow. At font-size 12 with the body font,
|
|
3594
|
+
budget 6.2px per character for lowercase and 7.4px for uppercase, then size boxes
|
|
3595
|
+
from the longest label rather than by eye.
|
|
3596
|
+
|
|
3597
|
+
Connector paths need fill="none" explicitly. SVG fills paths black by default, so a
|
|
3598
|
+
curve without it renders as a filled blob.
|
|
3599
|
+
|
|
3600
|
+
Define arrowheads once in defs with a marker whose fill is context-stroke, so the
|
|
3601
|
+
head inherits the line colour instead of needing one marker per colour.
|
|
3602
|
+
|
|
3603
|
+
Stroke widths: 1.5 for connectors, 2 for emphasis, 1 for gridlines. Never below 1.`;
|
|
3604
|
+
DIAGRAMS = `## Diagrams
|
|
3605
|
+
|
|
3606
|
+
Two mistakes account for most bad diagrams. First, arrows that cross boxes they
|
|
3607
|
+
have nothing to do with: trace every arrow's straight path and if it passes through
|
|
3608
|
+
a box, route it around or move the box. Second, boxes sized by guess rather than by
|
|
3609
|
+
the longest label they contain.
|
|
3610
|
+
|
|
3611
|
+
Route on the verb, not the noun. "How does a request flow" wants a sequence, "what
|
|
3612
|
+
are the parts" wants a structural diagram, "why is it slow" wants an annotated
|
|
3613
|
+
before and after.
|
|
3614
|
+
|
|
3615
|
+
Budgets: at most four boxes across one tier, at most five words in a label, at most
|
|
3616
|
+
three tiers deep. Beyond that, split into two diagrams or drop detail.
|
|
3617
|
+
|
|
3618
|
+
Label every arrow that isn't obvious, in 10px --color-text-secondary. An unlabelled
|
|
3619
|
+
arrow asserts a relationship without saying which.
|
|
3620
|
+
|
|
3621
|
+
Lay out left to right for flow and top to bottom for hierarchy, and keep a single
|
|
3622
|
+
consistent gap between tiers.`;
|
|
3623
|
+
ART = `## Illustration
|
|
3624
|
+
|
|
3625
|
+
Build from geometry: circles, rounded rectangles, and paths with two or three
|
|
3626
|
+
control points. Detail beyond that reads as noise at conversation size.
|
|
3627
|
+
|
|
3628
|
+
Use flat fills from the palette with no more than three colours plus a background.
|
|
3629
|
+
Depth comes from overlap and size, never from gradients or shadows.
|
|
3630
|
+
|
|
3631
|
+
Animate with CSS on transform and opacity only, 0.3s or slower, and only where the
|
|
3632
|
+
motion carries meaning. Anything faster or busier is a distraction in a chat.
|
|
3633
|
+
|
|
3634
|
+
For anything representational, prefer a diagram with labels. An unlabelled drawing
|
|
3635
|
+
of a concept is decoration.`;
|
|
3636
|
+
MODULE_SECTIONS = {
|
|
3637
|
+
interactive: [UI, COLOR],
|
|
3638
|
+
chart: [UI, COLOR, CHARTS],
|
|
3639
|
+
diagram: [COLOR, SVG, DIAGRAMS],
|
|
3640
|
+
art: [COLOR, SVG, ART]
|
|
3641
|
+
};
|
|
3642
|
+
}
|
|
3643
|
+
});
|
|
3644
|
+
|
|
3645
|
+
// server/src/mcp/choice.ts
|
|
3646
|
+
function validateChoice(data) {
|
|
3647
|
+
if (typeof data !== "object" || data === null || Array.isArray(data)) {
|
|
3648
|
+
return "arguments must be an object.";
|
|
3649
|
+
}
|
|
3650
|
+
const d = data;
|
|
3651
|
+
if (typeof d.question !== "string" || !d.question.trim()) {
|
|
3652
|
+
return "question is required: what you are asking the user to decide.";
|
|
3653
|
+
}
|
|
3654
|
+
if (!Array.isArray(d.options) || d.options.length < 2) {
|
|
3655
|
+
return "at least two options are needed.";
|
|
3656
|
+
}
|
|
3657
|
+
if (d.options.length > MAX_OPTIONS) {
|
|
3658
|
+
return `at most ${MAX_OPTIONS} options; ${d.options.length} is too many to tap through.`;
|
|
3659
|
+
}
|
|
3660
|
+
for (const [i, raw] of d.options.entries()) {
|
|
3661
|
+
if (typeof raw !== "object" || raw === null) return `options[${i}] must be an object.`;
|
|
3662
|
+
const o = raw;
|
|
3663
|
+
if (typeof o.label !== "string" || !o.label.trim()) {
|
|
3664
|
+
return `options[${i}].label is required and must be a short phrase.`;
|
|
3665
|
+
}
|
|
3666
|
+
if (o.prompt !== void 0 && typeof o.prompt !== "string") {
|
|
3667
|
+
return `options[${i}].prompt must be a string when given.`;
|
|
3668
|
+
}
|
|
3669
|
+
if (o.detail !== void 0 && typeof o.detail !== "string") {
|
|
3670
|
+
return `options[${i}].detail must be a string when given.`;
|
|
3671
|
+
}
|
|
3672
|
+
}
|
|
3673
|
+
return null;
|
|
3674
|
+
}
|
|
3675
|
+
var MAX_OPTIONS;
|
|
3676
|
+
var init_choice = __esm({
|
|
3677
|
+
"server/src/mcp/choice.ts"() {
|
|
3678
|
+
"use strict";
|
|
3679
|
+
MAX_OPTIONS = 6;
|
|
3680
|
+
}
|
|
3681
|
+
});
|
|
3682
|
+
|
|
3683
|
+
// server/src/mcp/protocol.ts
|
|
3684
|
+
function ok(id, result) {
|
|
3685
|
+
return { jsonrpc: "2.0", id, result };
|
|
3686
|
+
}
|
|
3687
|
+
function text(body, isError = false) {
|
|
3688
|
+
return { content: [{ type: "text", text: body }], isError };
|
|
3689
|
+
}
|
|
3690
|
+
function callError(id, message) {
|
|
3691
|
+
return ok(id, text(message, true));
|
|
3692
|
+
}
|
|
3693
|
+
function asStringArray(value) {
|
|
3694
|
+
return Array.isArray(value) ? value.filter((v) => typeof v === "string") : [];
|
|
3695
|
+
}
|
|
3696
|
+
function handleReadMe(id, args) {
|
|
3697
|
+
const modules = asStringArray(args.modules);
|
|
3698
|
+
const known = modules.filter((m) => MODULES.includes(m));
|
|
3699
|
+
if (known.length === 0) {
|
|
3700
|
+
return callError(id, `Name at least one module: ${MODULES.join(", ")}.`);
|
|
3701
|
+
}
|
|
3702
|
+
return ok(id, text(getGuidelines(known)));
|
|
3703
|
+
}
|
|
3704
|
+
function handleShowWidget(id, args) {
|
|
3705
|
+
if (args.i_have_seen_read_me !== true) {
|
|
3706
|
+
return callError(id, "Call read_me first, then set i_have_seen_read_me to true.");
|
|
3707
|
+
}
|
|
3708
|
+
const title = typeof args.title === "string" ? args.title.trim() : "";
|
|
3709
|
+
if (!title) return callError(id, "title is required: a short snake_case identifier.");
|
|
3710
|
+
const code = typeof args.widget_code === "string" ? args.widget_code : "";
|
|
3711
|
+
if (!code.trim()) return callError(id, "widget_code is required.");
|
|
3712
|
+
if (code.length > MAX_WIDGET_CHARS) {
|
|
3713
|
+
return callError(
|
|
3714
|
+
id,
|
|
3715
|
+
`widget_code is ${Math.round(code.length / 1024)} KB, over the ${MAX_WIDGET_CHARS / 1024} KB limit. Simplify it.`
|
|
3716
|
+
);
|
|
3717
|
+
}
|
|
3718
|
+
if (/<(!doctype|html|head|body)\b/i.test(code)) {
|
|
3719
|
+
return callError(id, "Pass a fragment, not a document: drop the doctype, html and body tags.");
|
|
3720
|
+
}
|
|
3721
|
+
return ok(id, text(`Widget "${title}" is on screen. Don't repeat its content in prose.`));
|
|
3722
|
+
}
|
|
3723
|
+
function handleChoice(id, args) {
|
|
3724
|
+
const problem = validateChoice(args);
|
|
3725
|
+
if (problem) return callError(id, problem);
|
|
3726
|
+
return ok(id, text("Options are on screen. Wait for the user to pick one."));
|
|
3727
|
+
}
|
|
3728
|
+
function handleMessage(req, version) {
|
|
3729
|
+
const id = req.id ?? null;
|
|
3730
|
+
const method = req.method ?? "";
|
|
3731
|
+
const params = req.params ?? {};
|
|
3732
|
+
if (method.startsWith("notifications/")) return null;
|
|
3733
|
+
switch (method) {
|
|
3734
|
+
case "initialize": {
|
|
3735
|
+
const asked = typeof params.protocolVersion === "string" ? params.protocolVersion : null;
|
|
3736
|
+
return ok(id, {
|
|
3737
|
+
protocolVersion: asked ?? DEFAULT_PROTOCOL_VERSION,
|
|
3738
|
+
capabilities: { tools: { listChanged: false } },
|
|
3739
|
+
serverInfo: { name: SERVER_NAME, version }
|
|
3740
|
+
});
|
|
3741
|
+
}
|
|
3742
|
+
case "ping":
|
|
3743
|
+
return ok(id, {});
|
|
3744
|
+
case "tools/list":
|
|
3745
|
+
return ok(id, { tools: TOOLS });
|
|
3746
|
+
case "tools/call": {
|
|
3747
|
+
const name = typeof params.name === "string" ? params.name : "";
|
|
3748
|
+
const args = params.arguments ?? {};
|
|
3749
|
+
if (name === "read_me") return handleReadMe(id, args);
|
|
3750
|
+
if (name === "show_widget") return handleShowWidget(id, args);
|
|
3751
|
+
if (name === "show_choice") return handleChoice(id, args);
|
|
3752
|
+
return { jsonrpc: "2.0", id, error: { code: -32602, message: `Unknown tool: ${name}` } };
|
|
3753
|
+
}
|
|
3754
|
+
default:
|
|
3755
|
+
if (id === null) return null;
|
|
3756
|
+
return { jsonrpc: "2.0", id, error: { code: -32601, message: `Unknown method: ${method}` } };
|
|
3757
|
+
}
|
|
3758
|
+
}
|
|
3759
|
+
var DEFAULT_PROTOCOL_VERSION, SERVER_NAME, MAX_WIDGET_CHARS, TOOLS;
|
|
3760
|
+
var init_protocol = __esm({
|
|
3761
|
+
"server/src/mcp/protocol.ts"() {
|
|
3762
|
+
"use strict";
|
|
3763
|
+
init_guidelines();
|
|
3764
|
+
init_choice();
|
|
3765
|
+
DEFAULT_PROTOCOL_VERSION = "2025-06-18";
|
|
3766
|
+
SERVER_NAME = "casper-generative-ui";
|
|
3767
|
+
MAX_WIDGET_CHARS = 256 * 1024;
|
|
3768
|
+
TOOLS = [
|
|
3769
|
+
{
|
|
3770
|
+
name: "read_me",
|
|
3771
|
+
title: "Widget design guidelines",
|
|
3772
|
+
description: "Read the widget design guidelines. Call this once, before your first show_widget call, with the modules relevant to what you are about to build. Do not mention this call to the user.",
|
|
3773
|
+
inputSchema: {
|
|
3774
|
+
type: "object",
|
|
3775
|
+
properties: {
|
|
3776
|
+
modules: {
|
|
3777
|
+
type: "array",
|
|
3778
|
+
items: { type: "string", enum: [...MODULES] },
|
|
3779
|
+
minItems: 1,
|
|
3780
|
+
description: "interactive for controls, sketches and simulations, chart for data, diagram for structure and flow, art for illustration."
|
|
3781
|
+
}
|
|
3782
|
+
},
|
|
3783
|
+
required: ["modules"]
|
|
3784
|
+
}
|
|
3785
|
+
},
|
|
3786
|
+
{
|
|
3787
|
+
name: "show_widget",
|
|
3788
|
+
title: "Show widget",
|
|
3789
|
+
description: "Render an interactive widget inline in the conversation. Pass an HTML fragment: no doctype, html or body tag. Style first, then content, then a single script last. Use this instead of describing something visual in prose.",
|
|
3790
|
+
inputSchema: {
|
|
3791
|
+
type: "object",
|
|
3792
|
+
properties: {
|
|
3793
|
+
i_have_seen_read_me: {
|
|
3794
|
+
type: "boolean",
|
|
3795
|
+
description: "True only if you have already called read_me in this conversation."
|
|
3796
|
+
},
|
|
3797
|
+
title: {
|
|
3798
|
+
type: "string",
|
|
3799
|
+
description: "Short snake_case identifier, e.g. compound_interest."
|
|
3800
|
+
},
|
|
3801
|
+
widget_code: {
|
|
3802
|
+
type: "string",
|
|
3803
|
+
description: "The HTML fragment to render."
|
|
3804
|
+
}
|
|
3805
|
+
},
|
|
3806
|
+
required: ["i_have_seen_read_me", "title", "widget_code"]
|
|
3807
|
+
}
|
|
3808
|
+
},
|
|
3809
|
+
{
|
|
3810
|
+
name: "show_choice",
|
|
3811
|
+
title: "Ask the user to choose",
|
|
3812
|
+
description: "Ask the user to pick from a few options, which they tap instead of typing. Use it wherever you would otherwise end a message asking which of several ways to proceed.",
|
|
3813
|
+
inputSchema: {
|
|
3814
|
+
type: "object",
|
|
3815
|
+
properties: {
|
|
3816
|
+
question: { type: "string", description: "What they are deciding." },
|
|
3817
|
+
options: {
|
|
3818
|
+
type: "array",
|
|
3819
|
+
minItems: 2,
|
|
3820
|
+
maxItems: MAX_OPTIONS,
|
|
3821
|
+
items: {
|
|
3822
|
+
type: "object",
|
|
3823
|
+
properties: {
|
|
3824
|
+
label: { type: "string", description: "Short, tappable phrase." },
|
|
3825
|
+
detail: { type: "string", description: "One line of context." },
|
|
3826
|
+
prompt: {
|
|
3827
|
+
type: "string",
|
|
3828
|
+
description: "Message sent when tapped. Defaults to the label."
|
|
3829
|
+
}
|
|
3830
|
+
},
|
|
3831
|
+
required: ["label"]
|
|
3832
|
+
}
|
|
3833
|
+
}
|
|
3834
|
+
},
|
|
3835
|
+
required: ["question", "options"]
|
|
3836
|
+
}
|
|
3837
|
+
}
|
|
3838
|
+
];
|
|
3839
|
+
}
|
|
3840
|
+
});
|
|
3841
|
+
|
|
3842
|
+
// server/src/mcp/server.ts
|
|
3843
|
+
var server_exports2 = {};
|
|
3844
|
+
__export(server_exports2, {
|
|
3845
|
+
runMcpServer: () => runMcpServer
|
|
3846
|
+
});
|
|
3847
|
+
import { createInterface } from "node:readline";
|
|
3848
|
+
function runMcpServer() {
|
|
3849
|
+
const rl = createInterface({ input: process.stdin });
|
|
3850
|
+
rl.on("line", (line) => {
|
|
3851
|
+
const trimmed = line.trim();
|
|
3852
|
+
if (!trimmed) return;
|
|
3853
|
+
let req;
|
|
3854
|
+
try {
|
|
3855
|
+
req = JSON.parse(trimmed);
|
|
3856
|
+
} catch {
|
|
3857
|
+
process.stdout.write(
|
|
3858
|
+
JSON.stringify({
|
|
3859
|
+
jsonrpc: "2.0",
|
|
3860
|
+
id: null,
|
|
3861
|
+
error: { code: -32700, message: "Parse error" }
|
|
3862
|
+
}) + "\n"
|
|
3863
|
+
);
|
|
3864
|
+
return;
|
|
3865
|
+
}
|
|
3866
|
+
try {
|
|
3867
|
+
const res = handleMessage(req, VERSION);
|
|
3868
|
+
if (res) process.stdout.write(JSON.stringify(res) + "\n");
|
|
3869
|
+
} catch (err) {
|
|
3870
|
+
process.stderr.write(`casper-mcp: ${err.message}
|
|
3871
|
+
`);
|
|
3872
|
+
if (req.id !== void 0 && req.id !== null) {
|
|
3873
|
+
process.stdout.write(
|
|
3874
|
+
JSON.stringify({
|
|
3875
|
+
jsonrpc: "2.0",
|
|
3876
|
+
id: req.id,
|
|
3877
|
+
error: { code: -32603, message: "Internal error" }
|
|
3878
|
+
}) + "\n"
|
|
3879
|
+
);
|
|
3880
|
+
}
|
|
3881
|
+
}
|
|
3882
|
+
});
|
|
3883
|
+
rl.on("close", () => process.exit(0));
|
|
3884
|
+
}
|
|
3885
|
+
var VERSION;
|
|
3886
|
+
var init_server2 = __esm({
|
|
3887
|
+
"server/src/mcp/server.ts"() {
|
|
3888
|
+
"use strict";
|
|
3889
|
+
init_protocol();
|
|
3890
|
+
VERSION = true ? "0.8.1" : "dev";
|
|
3891
|
+
}
|
|
3892
|
+
});
|
|
3893
|
+
|
|
3391
3894
|
// server/src/cli/program.ts
|
|
3392
3895
|
import fs15 from "node:fs";
|
|
3393
3896
|
import os4 from "node:os";
|
|
@@ -6523,9 +7026,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
6523
7026
|
helpWidth: context.helpWidth,
|
|
6524
7027
|
outputHasColors: context.hasColors
|
|
6525
7028
|
});
|
|
6526
|
-
const
|
|
6527
|
-
if (context.hasColors) return
|
|
6528
|
-
return this._outputConfiguration.stripColor(
|
|
7029
|
+
const text2 = helper.formatHelp(this, helper);
|
|
7030
|
+
if (context.hasColors) return text2;
|
|
7031
|
+
return this._outputConfiguration.stripColor(text2);
|
|
6529
7032
|
}
|
|
6530
7033
|
/**
|
|
6531
7034
|
* @typedef HelpContext
|
|
@@ -6685,7 +7188,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
6685
7188
|
* @param {(string | Function)} text - string to add, or a function returning a string
|
|
6686
7189
|
* @return {Command} `this` command for chaining
|
|
6687
7190
|
*/
|
|
6688
|
-
addHelpText(position,
|
|
7191
|
+
addHelpText(position, text2) {
|
|
6689
7192
|
const allowedValues = ["beforeAll", "before", "after", "afterAll"];
|
|
6690
7193
|
if (!allowedValues.includes(position)) {
|
|
6691
7194
|
throw new Error(`Unexpected value for position to addHelpText.
|
|
@@ -6694,10 +7197,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
6694
7197
|
const helpEvent = `${position}Help`;
|
|
6695
7198
|
this.on(helpEvent, (context) => {
|
|
6696
7199
|
let helpStr;
|
|
6697
|
-
if (typeof
|
|
6698
|
-
helpStr =
|
|
7200
|
+
if (typeof text2 === "function") {
|
|
7201
|
+
helpStr = text2({ error: context.error, command: context.command });
|
|
6699
7202
|
} else {
|
|
6700
|
-
helpStr =
|
|
7203
|
+
helpStr = text2;
|
|
6701
7204
|
}
|
|
6702
7205
|
if (helpStr) {
|
|
6703
7206
|
context.write(`${helpStr}
|
|
@@ -6764,7 +7267,7 @@ var program = new Command();
|
|
|
6764
7267
|
// server/src/cli/program.ts
|
|
6765
7268
|
init_paths();
|
|
6766
7269
|
init_settings();
|
|
6767
|
-
var
|
|
7270
|
+
var VERSION2 = true ? "0.8.1" : "dev";
|
|
6768
7271
|
async function bootstrap() {
|
|
6769
7272
|
const file = configFilePath();
|
|
6770
7273
|
const settings = readSettings(file);
|
|
@@ -6782,8 +7285,11 @@ async function bootstrap() {
|
|
|
6782
7285
|
process.stdout.write(`casper agent ${agent.action}: ${agent.target}
|
|
6783
7286
|
`);
|
|
6784
7287
|
} else if (agent.action === "kept-yours") {
|
|
6785
|
-
process.stdout.write(
|
|
6786
|
-
`
|
|
7288
|
+
process.stdout.write(
|
|
7289
|
+
`keeping your edited agent file at ${agent.target}
|
|
7290
|
+
Prompt and tool updates are being skipped. Delete it to take them.
|
|
7291
|
+
`
|
|
7292
|
+
);
|
|
6787
7293
|
}
|
|
6788
7294
|
}
|
|
6789
7295
|
function printToken() {
|
|
@@ -6825,7 +7331,7 @@ async function resetToken(value) {
|
|
|
6825
7331
|
}
|
|
6826
7332
|
function buildProgram() {
|
|
6827
7333
|
const program2 = new Command();
|
|
6828
|
-
program2.name("casper").description("Web client for kiro-cli over the Agent Client Protocol").version(
|
|
7334
|
+
program2.name("casper").description("Web client for kiro-cli over the Agent Client Protocol").version(VERSION2, "-v, --version").showHelpAfterError().allowUnknownOption(false).allowExcessArguments(false).addHelpText("after", `
|
|
6829
7335
|
Settings live in ${configFilePath()}.
|
|
6830
7336
|
Update with: npm install -g @joeyshi12/casper`);
|
|
6831
7337
|
program2.command("start").description("run the server in the foreground").allowUnknownOption(false).allowExcessArguments(false).action(async () => {
|
|
@@ -6840,6 +7346,9 @@ Update with: npm install -g @joeyshi12/casper`);
|
|
|
6840
7346
|
program2.command("doctor").description("check kiro-cli, settings, data directory and web app").allowUnknownOption(false).allowExcessArguments(false).action(async () => {
|
|
6841
7347
|
process.exitCode = (await Promise.resolve().then(() => (init_doctor(), doctor_exports))).doctor();
|
|
6842
7348
|
});
|
|
7349
|
+
program2.command("mcp").description("run the generative-UI MCP server on stdio (kiro spawns this itself)").allowUnknownOption(false).allowExcessArguments(false).action(async () => {
|
|
7350
|
+
(await Promise.resolve().then(() => (init_server2(), server_exports2))).runMcpServer();
|
|
7351
|
+
});
|
|
6843
7352
|
const service = program2.command("service").description("manage the systemd user service");
|
|
6844
7353
|
const svcCommand = (name, describe, run) => service.command(name).description(describe).allowUnknownOption(false).allowExcessArguments(false).action(async () => {
|
|
6845
7354
|
process.exitCode = run(await Promise.resolve().then(() => (init_service(), service_exports)));
|