feat: add one-click feature handoff flow

This commit is contained in:
OpenClaw Bot
2026-05-07 16:13:51 +02:00
parent aa4d79535c
commit 6f7fcd43a5
3 changed files with 45 additions and 3 deletions
+1
View File
@@ -33,6 +33,7 @@ BuildPulse v0.1 includes:
- Pulse Log screen - Pulse Log screen
- Export screen - Export screen
- AI session prompt export for coding-agent handoff - AI session prompt export for coding-agent handoff
- One-click handoff prep from a selected feature
- Appwrite-backed persistence on the Unraid server - Appwrite-backed persistence on the Unraid server
- Local cache fallback for resilience during backend hiccups - Local cache fallback for resilience during backend hiccups
- Pulse-shaped event records - Pulse-shaped event records
+13
View File
@@ -192,6 +192,19 @@ Expected:
- Contains recent pulses. - Contains recent pulses.
- Is useful as an AI coder handoff. - Is useful as an AI coder handoff.
### Test 5.5: Prepare AI handoff from selected feature
Steps:
1. Open Feature Plan.
2. Select a feature.
3. Click `Prepare AI Handoff`.
4. Confirm Export view opens with the selected feature loaded into `AI_SESSION_PROMPT.md`.
Expected:
- Export view opens immediately.
- Prompt focus feature matches the selected feature.
- Prompt includes current goal, acceptance criteria, parking-lot guardrails, and recent relevant pulses.
## Manual Test Group 6 — Mobile Usability ## Manual Test Group 6 — Mobile Usability
### Test 6.1: Phone layout ### Test 6.1: Phone layout
+28
View File
@@ -279,6 +279,15 @@ function App() {
})) }))
} }
const openFeatureHandoff = (featureId: string) => {
setPromptFeatureId(featureId)
setPromptTarget('OpenClaw')
setActiveTab('export')
const feature = appState.features.find((entry) => entry.id === featureId)
setStatusMessage(feature ? `Prepared AI handoff for “${feature.title}”.` : 'Prepared AI handoff prompt.')
}
const beginParkingEdit = (item: ParkingLotItem) => { const beginParkingEdit = (item: ParkingLotItem) => {
setSelectedParkingId(item.id) setSelectedParkingId(item.id)
setParkingDraft({ setParkingDraft({
@@ -601,6 +610,20 @@ function App() {
</div> </div>
</div> </div>
{selectedFeature && (
<section className="card quick-actions">
<div>
<strong>{selectedFeature.title}</strong>
<p>Selected and ready. Shape it here, then kick a clean brief to your agent.</p>
</div>
<div className="button-inline-row">
<button type="button" onClick={() => openFeatureHandoff(selectedFeature.id)}>
Prepare AI Handoff
</button>
</div>
</section>
)}
<div className="board-grid"> <div className="board-grid">
{FEATURE_COLUMNS.map((column) => ( {FEATURE_COLUMNS.map((column) => (
<article key={column} className="column card"> <article key={column} className="column card">
@@ -708,9 +731,14 @@ function App() {
<button type="button" onClick={saveFeature}>{selectedFeature ? 'Save Changes' : 'Add Feature'}</button> <button type="button" onClick={saveFeature}>{selectedFeature ? 'Save Changes' : 'Add Feature'}</button>
<button type="button" className="ghost" onClick={resetFeatureDraft}>Clear</button> <button type="button" className="ghost" onClick={resetFeatureDraft}>Clear</button>
{selectedFeature && ( {selectedFeature && (
<>
<button type="button" className="ghost" onClick={() => openFeatureHandoff(selectedFeature.id)}>
Prepare AI Handoff
</button>
<button type="button" className="danger" onClick={() => deleteFeature(selectedFeature.id)}> <button type="button" className="danger" onClick={() => deleteFeature(selectedFeature.id)}>
Delete Feature Delete Feature
</button> </button>
</>
)} )}
</div> </div>
</section> </section>