Skip to content

Commit 0ec317d

Browse files
committed
📝 docs: DeepWiki-backed Ask AI modal, Iconify icon system, and nav chrome overhaul
- Add ask-ai.js + deepwiki-backend.js: tabbed Search + Ask AI modal relaying questions to DeepWiki via the official MCP SDK - Replace all inline SVGs in index.md with <iconify-icon> elements (Lucide + Simple Icons); add icon-inject.js for runtime web component loading - Add header.html, search.html, toc.html overrides; restyle sidebar, TOC, and bottom nav chrome - Add speculation_rules.html: native prefetch on all internal hrefs, prerender on prev/next nav buttons - Fix console log rendering for imported CC sessions: map Agent/Read tool calls to spawn_submit/agent_result/file_read cards; correct unified diff hunk headers
1 parent 75d3086 commit 0ec317d

26 files changed

Lines changed: 2416 additions & 264 deletions

.devin/wiki.json

Lines changed: 235 additions & 116 deletions
Large diffs are not rendered by default.

apps/mewbo_console/src/utils/diff.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,12 @@ function deriveName(path: string): string {
1313
*/
1414
export function extractUnifiedDiffs(text: string): DiffFile[] {
1515
if (!text) return [];
16-
const parsed = parse(text);
16+
let parsed: ReturnType<typeof parse>;
17+
try {
18+
parsed = parse(text);
19+
} catch {
20+
return [];
21+
}
1722
return parsed.map((f) => ({
1823
name: deriveName(f.newName || f.oldName),
1924
path: f.newName || f.oldName,
@@ -45,7 +50,12 @@ function reconstructRawDiff(
4550
*/
4651
export function parseDiffHunks(text: string): ParsedDiffFile[] {
4752
if (!text) return [];
48-
const parsed = parse(text);
53+
let parsed: ReturnType<typeof parse>;
54+
try {
55+
parsed = parse(text);
56+
} catch {
57+
return [];
58+
}
4959
return parsed.map((f) => ({
5060
name: deriveName(f.newName || f.oldName),
5161
path: f.newName || f.oldName,

apps/mewbo_console/src/utils/logs.ts

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,61 @@ export function buildLogs(events: EventRecord[]): LogEntry[] {
228228
} catch { /* not JSON, fall through to shell */ }
229229
}
230230

231+
// Agent tool calls from imported sessions → spawn_submit (task) + agent_result (output)
232+
if (toolId === "Agent") {
233+
const inp = (payload.tool_input as Record<string, unknown>) || {};
234+
const description = typeof inp.description === "string" ? inp.description : "";
235+
const prompt = typeof inp.prompt === "string" ? inp.prompt : description;
236+
const subagentType = typeof inp.subagent_type === "string" ? inp.subagent_type : undefined;
237+
const agentModel = typeof inp.model === "string" ? inp.model : undefined;
238+
const resultText = typeof result === "string" ? result : "";
239+
logs.push({
240+
id: `spawn-submit-${idx++}`,
241+
type: "spawn_submit",
242+
content: "",
243+
timestamp: event.ts,
244+
spawnTask: prompt,
245+
spawnAgentType: subagentType,
246+
spawnModel: agentModel,
247+
spawnChildId: "",
248+
spawnAllowedTools: [],
249+
spawnDeniedTools: [],
250+
spawnExtras: [],
251+
spawnMessage: "",
252+
});
253+
if (resultText) {
254+
logs.push({
255+
id: `agent-result-${idx++}`,
256+
type: "agent_result",
257+
content: "",
258+
timestamp: event.ts,
259+
agentResultStatus: success ? "completed" : "failed",
260+
stepsUsed: 0,
261+
summary: truncate(resultText, 300),
262+
});
263+
}
264+
continue;
265+
}
266+
267+
// Read tool calls from imported sessions → file_read card
268+
if (toolId === "Read") {
269+
const inp = (payload.tool_input as Record<string, unknown>) || {};
270+
const filePath = typeof inp.file_path === "string" ? inp.file_path : "";
271+
if (filePath) {
272+
logs.push({
273+
id: `file-read-${idx++}`,
274+
type: "file_read",
275+
content: "",
276+
timestamp: event.ts,
277+
fileReadPath: filePath,
278+
fileReadText: typeof result === "string" ? result : "",
279+
agentId: eventAgentId,
280+
model: eventModel,
281+
});
282+
continue;
283+
}
284+
}
285+
231286
// steer_agent → render as a chat line ("<root → agent-xxxxxx>").
232287
// The result is always a short string ("Message sent.", "Agent xxx
233288
// cancelled.", or "ERROR: ..."), so no JSON parse needed.
@@ -315,12 +370,16 @@ export function buildLogs(events: EventRecord[]): LogEntry[] {
315370
const filePath = typeof inp?.file_path === "string" ? inp.file_path : "";
316371
if (filePath) {
317372
const oldStr = typeof inp?.old_string === "string" ? inp.old_string : "";
318-
const newStr = typeof inp?.new_string === "string" ? inp.new_string : "";
373+
const newStr = typeof inp?.new_string === "string" ? inp.new_string :
374+
(typeof inp?.content === "string" ? inp.content : "");
319375
let diffText = "";
320376
if (oldStr || newStr) {
321-
const oldLines = oldStr ? oldStr.split("\n").map((l: string) => `-${l}`).join("\n") : "";
322-
const newLines = newStr ? newStr.split("\n").map((l: string) => `+${l}`).join("\n") : "";
323-
diffText = `--- ${filePath}\n+++ ${filePath}\n@@ edit @@\n${[oldLines, newLines].filter(Boolean).join("\n")}`;
377+
const oldSplit = oldStr ? oldStr.split("\n") : [];
378+
const newSplit = newStr ? newStr.split("\n") : [];
379+
const oldLines = oldSplit.map((l: string) => `-${l}`).join("\n");
380+
const newLines = newSplit.map((l: string) => `+${l}`).join("\n");
381+
const hunkHeader = `@@ -1,${oldSplit.length} +1,${newSplit.length} @@`;
382+
diffText = `--- ${filePath}\n+++ ${filePath}\n${hunkHeader}\n${[oldLines, newLines].filter(Boolean).join("\n")}`;
324383
}
325384
const errorMsg = typeof payload.error === "string" ? payload.error : "";
326385
logs.push({

cloudflare/worker.js

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/**
2+
* Cloudflare Worker for docs.mewbo.com
3+
*
4+
* Deploy: CF Dashboard → Workers & Pages → Create Worker → paste this file
5+
* Route: docs.mewbo.com/* (zone route, orange-cloud proxy must be ON)
6+
*
7+
* Handles:
8+
* - /.well-known/api-catalog (RFC 9727, application/linkset+json)
9+
* - /.well-known/mcp/server-card.json (SEP-1649)
10+
* - /.well-known/agent-skills/index.json (Agent Skills Discovery v0.2.0)
11+
* - All other requests (pass-through + RFC 8288 Link headers)
12+
*/
13+
14+
const SITE = "https://docs.mewbo.com";
15+
const API = "https://api.mewbo.com"; // TODO: update if API base differs
16+
17+
// RFC 8288 Link headers injected on every HTML response
18+
const LINK_HEADERS = [
19+
`</.well-known/api-catalog>; rel="api-catalog"`,
20+
`</reference/>; rel="service-doc"`,
21+
`</.well-known/mcp/server-card.json>; rel="https://modelcontextprotocol.io/ns/server-card"`,
22+
];
23+
24+
// Static well-known responses (inline — avoids GitHub Pages MIME-type issues)
25+
const WELL_KNOWN = {
26+
"/.well-known/api-catalog": {
27+
type: "application/linkset+json",
28+
body: JSON.stringify({
29+
linkset: [
30+
{
31+
anchor: API + "/",
32+
"service-doc": [{ href: SITE + "/reference/" }],
33+
"service-desc": [{ href: API + "/swagger.json" }], // TODO: adjust OpenAPI spec URL
34+
status: [{ href: API + "/healthz" }], // TODO: adjust health endpoint
35+
},
36+
],
37+
}),
38+
},
39+
40+
"/.well-known/mcp/server-card.json": {
41+
type: "application/json",
42+
// TODO: fill in once Mewbo exposes a public MCP server endpoint.
43+
// Remove this entry entirely if Mewbo is MCP-client-only.
44+
body: JSON.stringify({
45+
serverInfo: { name: "Mewbo", version: "1.0.0" },
46+
transport: { type: "streamable-http", url: API + "/mcp" },
47+
capabilities: { tools: {}, resources: {}, prompts: {} },
48+
}),
49+
},
50+
51+
"/.well-known/agent-skills/index.json": {
52+
type: "application/json",
53+
// TODO: add entries as Mewbo publishes agent skills
54+
body: JSON.stringify({
55+
$schema: "https://agentskills.io/schema/v0.2.0/index.json",
56+
skills: [],
57+
}),
58+
},
59+
};
60+
61+
export default {
62+
async fetch(request) {
63+
const url = new URL(request.url);
64+
const entry = WELL_KNOWN[url.pathname];
65+
66+
// Serve well-known files directly with correct MIME types
67+
if (entry) {
68+
return new Response(entry.body, {
69+
headers: {
70+
"Content-Type": entry.type,
71+
"Cache-Control": "public, max-age=3600",
72+
"Access-Control-Allow-Origin": "*",
73+
},
74+
});
75+
}
76+
77+
// Pass through to GitHub Pages origin, appending Link headers
78+
const response = await fetch(request);
79+
const headers = new Headers(response.headers);
80+
81+
// Only inject Link headers on HTML responses (skip assets)
82+
const ct = headers.get("Content-Type") || "";
83+
if (ct.includes("text/html")) {
84+
for (const link of LINK_HEADERS) {
85+
headers.append("Link", link);
86+
}
87+
}
88+
89+
return new Response(response.body, {
90+
status: response.status,
91+
statusText: response.statusText,
92+
headers,
93+
});
94+
},
95+
};

0 commit comments

Comments
 (0)