diff --git a/scripts/build-docs-site.mjs b/scripts/build-docs-site.mjs
index 9672b84..face219 100644
--- a/scripts/build-docs-site.mjs
+++ b/scripts/build-docs-site.mjs
@@ -19,7 +19,7 @@ const cname = readCname();
const siteBase = cname ? `https://${cname}` : "";
const productName = "acpx";
-const productTagline = "Talk to coding agents from the command line";
+const productTagline = "Talk to agents from the command line";
const productDescription =
"Headless CLI client for the Agent Client Protocol — persistent multi-turn sessions, queue-aware prompts, structured output, and multi-step flows for Codex, Claude, Pi, OpenClaw, and any ACP-capable agent.";
const installCommand = "npm install -g acpx";
@@ -33,6 +33,51 @@ const sections = [
["Reference", ["CLI.md", "exit-codes.md", "VISION.md"]],
];
+const HIGHLIGHT_ALIASES = {
+ sh: "bash",
+ shell: "bash",
+ zsh: "bash",
+ console: "bash",
+ js: "ts",
+ javascript: "ts",
+ typescript: "ts",
+ jsonc: "json",
+};
+
+const HIGHLIGHT_RULES = {
+ bash: [
+ [/#[^\n]*/g, "com"],
+ [/'(?:[^'\\]|\\.)*'/g, "str"],
+ [/"(?:[^"\\]|\\.)*"/g, "str"],
+ [/`[^`]*`/g, "str"],
+ [/\$\{[^}]+\}|\$\w+/g, "var"],
+ [/\B-{1,2}[A-Za-z][\w-]*/g, "flag"],
+ [/\b\d+\b/g, "num"],
+ [/[|&;<>]+/g, "op"],
+ ],
+ json: [
+ [/"(?:[^"\\]|\\.)*"(?=\s*:)/g, "prop"],
+ [/"(?:[^"\\]|\\.)*"/g, "str"],
+ [/-?\b\d+(?:\.\d+)?(?:[eE][+-]?\d+)?\b/g, "num"],
+ [/\b(?:true|false|null)\b/g, "lit"],
+ [/[{}[\],:]/g, "op"],
+ ],
+ ts: [
+ [/\/\/[^\n]*/g, "com"],
+ [/\/\*[\s\S]*?\*\//g, "com"],
+ [/'(?:[^'\\]|\\.)*'/g, "str"],
+ [/"(?:[^"\\]|\\.)*"/g, "str"],
+ [/`(?:[^`\\]|\\.)*`/g, "str"],
+ [
+ /\b(?:const|let|var|function|return|import|export|from|default|async|await|if|else|for|while|switch|case|break|continue|new|class|interface|type|extends|implements|public|private|protected|readonly|as|in|of|typeof|instanceof|this|void|never)\b/g,
+ "kw",
+ ],
+ [/\b(?:true|false|null|undefined)\b/g, "lit"],
+ [/-?\b\d+(?:\.\d+)?(?:[eE][+-]?\d+)?\b/g, "num"],
+ [/\b[A-Z][A-Za-z0-9_]*\b/g, "typ"],
+ ],
+};
+
// Internal architecture notes and stray dev docs are not part of the user-facing site.
// They remain in the repo and are reachable from GitHub.
const buildExcludes = [
@@ -261,7 +306,7 @@ function markdownToHtml(markdown, currentRel) {
flushBlockquote();
if (fence) {
html.push(
- `
${escapeHtml(fence.lines.join("\n"))}
`,
+ `${highlight(fence.lines.join("\n"), fence.lang)}
`,
);
fence = null;
} else {
@@ -463,7 +508,7 @@ function homeHero(page) {
];
return `
Agent Client Protocol · Headless CLI
- Talk to coding agents from the command line
+ Talk to agents from the command line
${escapeHtml(description)}
Quickstart
@@ -656,6 +701,37 @@ function escapeAttr(value) {
return escapeHtml(value);
}
+function highlight(code, lang) {
+ const resolved = HIGHLIGHT_ALIASES[lang] || lang;
+ const rules = HIGHLIGHT_RULES[resolved];
+ if (!rules) {
+ return escapeHtml(code);
+ }
+ let out = "";
+ let i = 0;
+ while (i < code.length) {
+ let bestKind = null;
+ let bestText = null;
+ for (const [re, kind] of rules) {
+ re.lastIndex = i;
+ const m = re.exec(code);
+ if (m && m.index === i) {
+ bestKind = kind;
+ bestText = m[0];
+ break;
+ }
+ }
+ if (bestText !== null) {
+ out += `
${escapeHtml(bestText)}`;
+ i += bestText.length;
+ } else {
+ out += escapeHtml(code[i]);
+ i += 1;
+ }
+ }
+ return out;
+}
+
function validateLinks(outputDir) {
const failures = [];
const placeholderHrefs = /^(url|path|file|dir|name)$/i;
diff --git a/scripts/docs-site-assets.mjs b/scripts/docs-site-assets.mjs
index eb4e94c..f3ee146 100644
--- a/scripts/docs-site-assets.mjs
+++ b/scripts/docs-site-assets.mjs
@@ -56,9 +56,13 @@ a:hover{text-decoration:underline;text-underline-offset:.2em}
.sidebar-head{display:flex;align-items:center;gap:10px;margin-bottom:24px}
.brand{display:flex;align-items:center;gap:11px;color:var(--ink);text-decoration:none;flex:1;min-width:0}
.brand:hover{text-decoration:none}
-.brand .mark{flex:0 0 30px;width:30px;height:30px;border-radius:8px;background:var(--ink);position:relative;overflow:hidden;display:grid;place-items:center;color:#7dd3fc;font:700 14px/1 "JetBrains Mono","SF Mono",ui-monospace,monospace;letter-spacing:0}
-.brand .mark::before{content:"";position:absolute;inset:0;background:linear-gradient(135deg,rgba(14,165,233,.35),transparent 55%,rgba(168,85,247,.35));pointer-events:none}
-.brand .mark span{position:relative;z-index:1}
+.brand .mark{flex:0 0 34px;width:34px;height:34px;border-radius:9px;background:var(--ink);position:relative;overflow:hidden;display:grid;place-items:center;box-shadow:0 1px 0 rgba(255,255,255,.05) inset,0 8px 24px -10px rgba(14,165,233,.45)}
+.brand .mark::before{content:"";position:absolute;inset:0;background:radial-gradient(120% 120% at 0% 0%,rgba(14,165,233,.55),transparent 55%),radial-gradient(120% 120% at 100% 100%,rgba(168,85,247,.55),transparent 55%);pointer-events:none}
+.brand .mark::after{content:"";position:absolute;inset:1px;border-radius:8px;border:1px solid rgba(255,255,255,.08);pointer-events:none}
+.brand .mark svg{position:relative;z-index:1;width:20px;height:20px;display:block}
+.brand .mark .cursor{transform-origin:center;animation:acpx-blink 1.2s steps(2,jump-none) infinite}
+@keyframes acpx-blink{0%,49%{opacity:1}50%,100%{opacity:.25}}
+@media (prefers-reduced-motion: reduce){.brand .mark .cursor{animation:none}}
.brand strong{display:block;font-size:1.05rem;line-height:1.1;font-weight:600;letter-spacing:0;color:var(--ink)}
.brand small{display:block;color:var(--muted);font-size:.74rem;margin-top:3px;font-weight:400}
.theme-toggle{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;width:34px;height:34px;border-radius:8px;border:1px solid var(--line);background:var(--paper);color:var(--muted);cursor:pointer;padding:0;transition:border-color .15s,color .15s,background-color .15s,transform .12s}
@@ -130,6 +134,16 @@ body:not(.home) .doc>h1:first-child{display:none}
.doc pre::-webkit-scrollbar{height:8px;width:8px}
.doc pre::-webkit-scrollbar-thumb{background:#334155;border-radius:8px}
.doc pre code{display:block;background:transparent;border:0;color:inherit;padding:0;font-size:1em;white-space:pre}
+.doc pre .hl-com{color:#7a8597;font-style:italic}
+.doc pre .hl-str{color:#86efac}
+.doc pre .hl-num{color:#fbbf24}
+.doc pre .hl-kw{color:#c4b5fd;font-weight:500}
+.doc pre .hl-lit{color:#f0abfc}
+.doc pre .hl-flag{color:#7dd3fc}
+.doc pre .hl-var{color:#fca5a5}
+.doc pre .hl-prop{color:#7dd3fc}
+.doc pre .hl-op{color:#94a3b8}
+.doc pre .hl-typ{color:#fde68a}
.doc pre .copy{position:absolute;top:8px;right:8px;background:rgba(255,255,255,.06);color:var(--code-fg);border:1px solid rgba(255,255,255,.16);border-radius:6px;padding:3px 9px;font:500 .7rem/1 "Inter",sans-serif;cursor:pointer;opacity:0;transition:opacity .15s,background .15s,border-color .15s}
.doc pre:hover .copy,.doc pre .copy:focus{opacity:1}
.doc pre .copy:hover{background:rgba(255,255,255,.12)}
@@ -259,20 +273,24 @@ export function themeToggleHtml() {
}
export function brandMarkHtml() {
- return `
>_`;
+ return `
`;
}
export function faviconSvg() {
return `
`;
}