feat(v0.6): show CLAUDE.md on the project detail page + /init generate/update button

The detail page now reads <repo>/CLAUDE.md and shows it in a scrollable
monospace box, with one smart button: "↻ Update" when it exists / " Generate"
when it doesn't. The button opens an interactive Claude session in the repo
running /init (claude "/init") so you review what it writes — reuses the project
launcher, no new backend orchestration, stays a byte-shuttle.

- ProjectDetail += hasClaudeMd / claudeMd; buildProjectDetail reads CLAUDE.md
  (truncated 64KB, best-effort, in the existing Promise.all)
- renderProjectDetail: CLAUDE.md section (content box or empty state) + button
- style.css: .proj-section-row / .proj-claudemd-btn / .proj-claudemd

Tests +5 (458): backend read present/absent; frontend content+Update,
empty+Generate, button opens `claude "/init"`. Verified: tsc clean, full suite
green, build OK, curl returns the content, in-browser shows the box + button.
This commit is contained in:
Yaojia Wang
2026-06-30 14:51:42 +02:00
parent 67b0a43b39
commit 88b960bac5
7 changed files with 143 additions and 1 deletions

View File

@@ -464,6 +464,33 @@ export function renderProjectDetail(
root.append(list)
}
// CLAUDE.md — view + a smart Generate/Update button that runs /init interactively.
const cmHead = el('div', 'proj-section-row')
cmHead.append(el('div', 'proj-section-title', 'CLAUDE.md'))
const cmBtn = el('button', 'proj-claudemd-btn', detail.hasClaudeMd ? '↻ Update' : '✨ Generate')
cmBtn.title = detail.hasClaudeMd
? 'Open a Claude session running /init to refresh CLAUDE.md'
: 'Open a Claude session running /init to create CLAUDE.md'
// Launch claude with /init as the initial prompt, in this repo (interactive,
// so you review what it writes). Reuses the project launcher.
cmBtn.addEventListener('click', () => hooks.onOpenProject(detail.path, detail.name, 'claude "/init"\r'))
cmHead.append(cmBtn)
root.append(cmHead)
if (detail.hasClaudeMd && detail.claudeMd !== undefined) {
const pre = el('pre', 'proj-claudemd')
pre.textContent = detail.claudeMd
root.append(pre)
} else {
root.append(
el(
'div',
'proj-empty',
'No CLAUDE.md yet — generate one to give Claude project-specific instructions.',
),
)
}
// Launchers
root.append(el('div', 'proj-section-title', 'Start'))
root.append(makeLauncherRow(detail, hooks))