Sets up the Socrata project repo with: docs/ — strategy and design documents - idea.md: full product vision - implementation-plan.md: Phase 0 + Phase 1 MVP plan - phase-0-validation.md: 2-week validation experiment strategy - phase-0-plan.md: concrete Phase 0 build plan - phase-0-results.md: Phase 0 gate outcome — GO for MVP - sysml-modeling.md: metamodel + SE discipline + validation rules - socrates.md: agent character, surfaces, modes, prompts, lifecycle - sync.md: bidirectional text↔diagram sync engineering - design-source/: HTML/CSS/JS handoff bundle from Claude Design phase-0/ — validated harness (CLI, no UI, no DB) - LM Studio (local OpenAI-compatible) generation + detection + judge - PlantUML rendering for SysML model visualization - 10-seed corpus (8 working + 2 holdouts) - 5 corpus runs with iteration history in reports/ - Final gate: 10/10 pass, mean 4.32/5, holdouts validated Phase 1 MVP scope and milestones documented in implementation-plan.md.
100 lines
3.4 KiB
JavaScript
100 lines
3.4 KiB
JavaScript
// TextCanvas — narrative editor surface with markup chips, headings, prose.
|
|
// Renders chips per markupStyle: "pill" | "underline" | "bracket" | "color".
|
|
|
|
const CHIP_TYPE_LABEL = {
|
|
block: "block",
|
|
property: "property",
|
|
association: "assoc",
|
|
requirement: "req",
|
|
};
|
|
|
|
function Chip({ kind, id, label, markupStyle, onHover, onClick, focused }) {
|
|
const cls = `chip chip-${kind} chip-style-${markupStyle}${focused ? " chip-focus" : ""}`;
|
|
const handlers = {
|
|
onMouseEnter: () => onHover && onHover(id),
|
|
onMouseLeave: () => onHover && onHover(null),
|
|
onClick: () => onClick && onClick(id, kind),
|
|
};
|
|
if (markupStyle === "bracket") {
|
|
return (
|
|
<span className={cls} {...handlers}>
|
|
<span className="chip-bracket">[</span>
|
|
<span className="chip-kind">{CHIP_TYPE_LABEL[kind]}:</span>
|
|
<span className="chip-label">{label}</span>
|
|
<span className="chip-bracket">]</span>
|
|
</span>
|
|
);
|
|
}
|
|
if (markupStyle === "underline") {
|
|
return (
|
|
<span className={cls} {...handlers}>
|
|
<span className="chip-glyph">{kindGlyph(kind)}</span>
|
|
<span className="chip-label">{label}</span>
|
|
</span>
|
|
);
|
|
}
|
|
// pill (default) and color both render as filled chips, color uses kind color, pill is muted.
|
|
return (
|
|
<span className={cls} {...handlers}>
|
|
<span className="chip-glyph">{kindGlyph(kind)}</span>
|
|
<span className="chip-label">{label}</span>
|
|
</span>
|
|
);
|
|
}
|
|
|
|
function kindGlyph(kind) {
|
|
switch (kind) {
|
|
case "block": return "▢";
|
|
case "property": return "·";
|
|
case "association": return "→";
|
|
case "requirement": return "§";
|
|
default: return "·";
|
|
}
|
|
}
|
|
|
|
function TextCanvas({ data, density, markupStyle, focusBlockId, setFocusBlockId, gutter }) {
|
|
const padY = density === "compact" ? 10 : 18;
|
|
return (
|
|
<div className="text-canvas" style={{ padding: `${padY}px ${density === "compact" ? 22 : 36}px` }}>
|
|
{gutter}
|
|
{data.narrative.map((node, i) => {
|
|
if (node.type === "h1") return <h1 key={i} className="t-h1">{node.text}</h1>;
|
|
if (node.type === "h2") return <h2 key={i} className="t-h2">{node.text}</h2>;
|
|
if (node.type === "p") {
|
|
return (
|
|
<p key={i} className="t-p">
|
|
{node.children.map((c, j) => {
|
|
if (c.t === "text") return <span key={j}>{c.v}</span>;
|
|
if (c.t === "chip") return (
|
|
<Chip key={j} kind={c.kind} id={c.id} label={c.label}
|
|
markupStyle={markupStyle}
|
|
focused={focusBlockId === c.id}
|
|
onHover={setFocusBlockId}
|
|
onClick={(id) => setFocusBlockId(id)}
|
|
/>
|
|
);
|
|
return null;
|
|
})}
|
|
</p>
|
|
);
|
|
}
|
|
return null;
|
|
})}
|
|
|
|
{/* a Socrates inline annotation (margin note) */}
|
|
<div className="margin-note">
|
|
<span className="margin-note-glyph">Σ</span>
|
|
<span>
|
|
<span className="margin-note-who">Socrates · margin</span>
|
|
<span className="margin-note-text">
|
|
"Refuses to produce solutions" is a strong constraint. Have you decided what counts as a "solution" vs. a "scaffold"? This boundary will determine whether the refusal policy is enforceable.
|
|
</span>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
window.TextCanvas = TextCanvas;
|
|
window.Chip = Chip;
|