feat(ai): patch Architect prompt with full Spec Kit PRD template rules

This commit is contained in:
2026-05-19 19:49:05 -07:00
parent 329eb4eb67
commit f48cde3890

View File

@@ -109,91 +109,92 @@ export default function PlanPageV2() {
// The business case / 1-page summary
// ──────────────────────────────────────────────────
function ObjectiveView({ plan, projectId, onChange }: { plan: Plan, projectId: string, onChange: (p: Plan) => void }) {
const [editing, setEditing] = useState(!plan.vision);
const [draft, setDraft] = useState(plan.vision ?? "");
const [saving, setSaving] = useState(false);
const [generating, setGenerating] = useState(false);
useEffect(() => {
if (plan.vision !== draft) {
setDraft(plan.vision ?? "");
}
}, [plan.vision]);
const save = async () => {
const save = async (text: string) => {
setSaving(true);
try {
const r = await fetch(`/api/projects/${projectId}/plan`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ kind: "vision", text: draft }),
body: JSON.stringify({ kind: "vision", text }),
});
const d = await r.json();
if (d.plan) onChange(d.plan);
setEditing(false);
} finally {
setSaving(false);
}
};
const handleGenerate = async () => {
if (!draft.trim()) {
alert("Please write an objective first before generating the PRD.");
return;
}
if (!confirm("This will overwrite the PRD and Execution Plan based on this objective. Continue?")) return;
setGenerating(true);
try {
await fetch(`/api/projects/${projectId}/plan`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ kind: "vision", text: draft }),
});
const r = await fetch(`/api/projects/${projectId}/plan/generate`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ objective: draft }),
});
const d = await r.json();
if (d.plan) onChange(d.plan);
alert("Blueprint generated successfully! Check the PRD and Delegate tabs.");
} finally {
setGenerating(false);
}
};
return (
<div className="panel-container">
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 16 }}>
<div>
</div>
<div style={{ display: "flex", gap: 12 }}>
<div style={{ display: "flex", justifyContent: "flex-end", marginBottom: 16 }}>
<div style={{ display: "flex", alignItems: "center", gap: 12 }}>
{saving && <span style={{ fontSize: "0.75rem", color: INK.faint }}>Saving...</span>}
<button
onClick={async () => {
if (!confirm("This will overwrite the PRD and Execution Plan based on the current objective. Continue?")) return;
setSaving(true);
try {
const r = await fetch(`/api/projects/${projectId}/plan/generate`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ objective: draft }),
});
const d = await r.json();
if (d.plan) onChange(d.plan);
} finally {
setSaving(false);
setEditing(false);
}
}}
disabled={saving || !draft.trim()}
onClick={handleGenerate}
disabled={generating || !draft.trim()}
className="btn-primary"
style={{ fontWeight: 600, fontSize: "0.85rem", padding: "6px 16px", borderRadius: 6 }}
style={{ padding: "8px 16px", borderRadius: 8, fontWeight: 600 }}
>
{saving ? <><Loader2 size={12} className="animate-spin" /> Generating...</> : "Generate Complete PRD"}
{generating ? (
<><Loader2 size={14} className="animate-spin" /> Generating Blueprint...</>
) : (
"Generate Complete PRD"
)}
</button>
{!editing && (
<button onClick={() => setEditing(true)} className="btn-ghost">
<Pencil size={12} /> Edit
</button>
)}
</div>
</div>
{editing ? (
<div style={{ border: `1px solid ${INK.border}`, borderRadius: 8, overflow: "hidden" }}>
<textarea
value={draft}
onChange={(e) => setDraft(e.target.value)}
style={{
width: "100%", minHeight: 400, padding: 20, fontSize: "0.95rem", lineHeight: 1.6,
border: "none", outline: "none", resize: "vertical", fontFamily: "var(--font-sans)",
}}
placeholder="Describe the business objective..."
/>
<div style={{ display: "flex", justifyContent: "flex-end", gap: 8, padding: "12px 20px", background: INK.bgHover, borderTop: `1px solid ${INK.border}` }}>
<button onClick={() => setEditing(false)} className="btn-ghost">Cancel</button>
<button onClick={save} disabled={saving} className="btn-primary">
{saving ? "Saving..." : "Save Objective"}
</button>
</div>
</div>
) : (
<div className="markdown-prose" style={{ background: "#fff", border: `1px solid ${INK.border}`, padding: 32, borderRadius: 8, minHeight: 200 }}>
{plan.vision ? (
<ReactMarkdown>{plan.vision}</ReactMarkdown>
) : (
<div style={{ color: INK.faint, fontStyle: "italic" }}>No objective defined yet. Switch to Architect mode and brainstorm with the AI.</div>
)}
</div>
)}
<div style={{ border: `1px solid ${INK.border}`, borderRadius: 8, overflow: "hidden", background: "#fff", boxShadow: "0 1px 3px rgba(0,0,0,0.02)" }}>
<textarea
value={draft}
onChange={(e) => setDraft(e.target.value)}
onBlur={() => save(draft)}
style={{
width: "100%", minHeight: 400, padding: 24, fontSize: "0.95rem", lineHeight: 1.6,
border: "none", outline: "none", resize: "vertical", fontFamily: "var(--font-sans)",
color: INK.main
}}
placeholder="Describe the business objective..."
/>
</div>
</div>
);
}