feat: add focused handoff shortcuts

This commit is contained in:
OpenClaw Bot
2026-05-11 12:14:19 +02:00
parent 8218a3417e
commit 204e5ee64a
4 changed files with 83 additions and 14 deletions
+36 -7
View File
@@ -1203,15 +1203,31 @@ function App() {
}
}
const copySessionPrompt = async () => {
const copyFocusedHandoff = async (featureId?: string, target = promptTarget) => {
const resolvedFeatureId = featureId ?? selectedFeature?.id ?? (promptFeatureId || groupedFeatures.now[0]?.id)
const prompt = createAgentSessionPrompt(appState, {
featureId: resolvedFeatureId || undefined,
target,
})
try {
await navigator.clipboard.writeText(sessionPrompt)
setStatusMessage('AI session prompt copied to clipboard.')
await navigator.clipboard.writeText(prompt)
if (resolvedFeatureId) {
setPromptFeatureId(resolvedFeatureId)
}
setPromptTarget(target)
const feature = resolvedFeatureId ? appState.features.find((entry) => entry.id === resolvedFeatureId) : null
setStatusMessage(feature ? `Focused AI handoff for “${feature.title}” copied.` : 'Focused AI handoff copied.')
} catch {
setStatusMessage('Clipboard copy failed. Browser said no.')
}
}
const copySessionPrompt = async () => {
await copyFocusedHandoff(promptFeatureId || undefined, promptTarget)
}
const handleImport = async (event: ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0]
if (!file) return
@@ -1307,7 +1323,7 @@ function App() {
tab: 'export' as TabKey,
operatorNote: 'Use this when another agent or coding session needs clean context without archaeology.',
evidence: ['JSON export preserves full app state.', 'JSONL export carries pulse history.', 'Markdown package includes agent-facing project, feature, parking, pulse, and context files.'],
next: 'Add a “copy focused handoff” button directly on each capability detail.',
next: 'Add target-specific prompt presets so OpenClaw, Codex, and Claude get sharper default briefs.',
},
{
title: 'Appwrite Sync',
@@ -1339,7 +1355,7 @@ function App() {
<div className="app-shell">
<header className="mobile-shell-header card">
<div>
<p className="eyebrow">BuildPulse v0.3.0</p>
<p className="eyebrow">BuildPulse v0.3.1</p>
<h1>{appState.project.name}</h1>
<p className="hero-goal compact-goal">
<strong>Current goal:</strong> {appState.project.current_goal || 'Classify new ideas before they become work.'}
@@ -1667,6 +1683,9 @@ function App() {
<button type="button" className="ghost small" onClick={() => openFeatureHandoff(selectedFeature.id)}>
Prepare AI Handoff
</button>
<button type="button" className="ghost small" onClick={() => void copyFocusedHandoff(selectedFeature.id, 'OpenClaw')}>
Copy AI Handoff
</button>
</div>
</div>
</div>
@@ -1939,7 +1958,7 @@ function App() {
<section className="card functionality-hero">
<div>
<p className="eyebrow">Secondary status</p>
<h3>{appState.project.name} is now a local-first v0.3 cockpit with Appwrite sync and release-planning structure.</h3>
<h3>{appState.project.name} is now a local-first v0.3 cockpit with Appwrite sync, release-planning structure, and faster handoff prep.</h3>
<p>
The planning loop works from browser storage first, then syncs to Appwrite for the deployed Unraid runtime. If sync degrades, the cockpit should still stay usable locally.
</p>
@@ -2029,7 +2048,17 @@ function App() {
<h3>{selectedStatusCard.title}</h3>
<p>{selectedStatusCard.operatorNote}</p>
</div>
<span className={`pill functionality-${selectedStatusCard.status}`}>{selectedStatusCard.status}</span>
<div className="button-inline-row">
{selectedStatusCard.title === 'AI Handoff + Export' && (
<button type="button" className="ghost small" onClick={() => void copyFocusedHandoff(undefined, 'OpenClaw')}>
Copy Focused Handoff
</button>
)}
<button type="button" className="ghost small" onClick={() => setActiveTab(selectedStatusCard.tab)}>
{selectedStatusCard.action}
</button>
<span className={`pill functionality-${selectedStatusCard.status}`}>{selectedStatusCard.status}</span>
</div>
</div>
<div className="functionality-detail-grid">
<article>
+43 -6
View File
@@ -10,7 +10,7 @@ export const createSeedState = (): AppState => ({
one_line_pitch: 'A calm planning cockpit for AI-assisted product building.',
description:
'BuildPulse helps capture features, park distracting ideas, log progress as Pulse events, and export clean context for AI coding agents.',
current_goal: 'Ship v0.3 with Phases, Releases, and clear release-readiness signals.',
current_goal: 'Sharpen v0.4 handoff workflows so coding agents get the right context fast.',
notes: 'First dogfood project: BuildPulse manages BuildPulse.',
created_at: seedDate,
updated_at: seedDate,
@@ -40,9 +40,9 @@ export const createSeedState = (): AppState => ({
id: 'phase_structured_release_planning',
title: 'Phase 3: Structured Release Planning',
goal: 'Make releases concrete: what is required, what is forbidden, and how close the build is to ready.',
status: 'active',
status: 'done',
order: 3,
notes: 'This is the v0.3 step.',
notes: 'v0.3 shipped with phases, releases, and readiness signals.',
created_at: seedDate,
updated_at: seedDate,
},
@@ -50,9 +50,9 @@ export const createSeedState = (): AppState => ({
id: 'phase_session_handoff',
title: 'Phase 4: Session Handoff',
goal: 'Give agents cleaner, more targeted context packages for implementation sessions.',
status: 'upcoming',
status: 'active',
order: 4,
notes: 'Planned v0.4 direction.',
notes: 'Current v0.4 step: faster, more focused handoff workflows for coding sessions.',
created_at: seedDate,
updated_at: seedDate,
},
@@ -118,13 +118,50 @@ export const createSeedState = (): AppState => ({
'Local/cloud model router',
'Session prompt generator',
],
status: 'shipped',
notes: 'Shipped. Release planning structure is live; still no live integrations.',
created_at: seedDate,
updated_at: seedDate,
},
{
id: 'release_v040_focused_handoffs',
phase_id: 'phase_session_handoff',
name: 'v0.4 — Focused Session Handoffs',
goal: 'Cut the friction between choosing a feature and giving a coding agent a sharp, minimal brief.',
definition_of_done: [
'Feature detail includes a one-click copy handoff action.',
'Status detail can copy a focused handoff without detouring through export archaeology.',
'Prompt generation still respects release, phase, parking-lot, and recent-pulse guardrails.',
],
required_feature_ids: ['export_screen', 'feature_focused_handoff_shortcuts'],
optional_feature_ids: ['pulse_log_screen'],
forbidden_feature_titles: ['Live OpenClaw/Hermes Agent Status', 'WebSocket agent telemetry', 'GitHub / Gitea sync'],
status: 'in_progress',
notes: 'Keep this on planning structure only. No live integrations yet.',
notes: 'First concrete v0.4 slice before deeper prompt presets or session templates.',
created_at: seedDate,
updated_at: seedDate,
},
],
features: [
{
id: 'feature_focused_handoff_shortcuts',
title: 'Focused handoff shortcuts',
description: 'Let operators copy a sharp AI handoff directly from feature and status detail surfaces.',
column: 'now',
priority: 'must',
status: 'building',
acceptance_criteria: [
'Feature detail includes a one-click copy handoff action.',
'Status detail can copy a focused handoff without navigating the whole Export screen.',
'Copied prompt still respects the selected feature or first active Now item.',
],
scope_notes: 'This is the first concrete v0.4 step: less archaeology before a coding session starts.',
phase_id: 'phase_session_handoff',
release_id: 'release_v040_focused_handoffs',
release_role: 'required',
created_at: seedDate,
updated_at: seedDate,
},
{
id: 'feature_plan_screen',
title: 'Feature Plan screen',