import { useEffect, useState } from 'react'; import { api } from '../api'; import type { ContribAction, ContribScreen, ContribWorkflow, ContributionsResponse } from '../types'; import type { SessionApi } from '../useSession'; // Actions INJECT a command into an agentic session — the Cockpit never runs the CLI. export function Actions({ refreshTick = 0, session, setComposer, goSessions }: { refreshTick?: number; session: SessionApi; setComposer: (v: string) => void; goSessions: () => void }) { const [actions, setActions] = useState([]); const [screens, setScreens] = useState([]); const [workflows, setWorkflows] = useState([]); const [err, setErr] = useState(''); const [note, setNote] = useState(''); useEffect(() => { api('/api/contributions').then((d) => { setActions(d.actions ?? []); setScreens(d.screens ?? []); setWorkflows(d.workflows ?? []); }).catch((e) => setErr((e as Error).message)); }, [refreshTick]); const inject = async (a: ContribAction) => { let command = a.inject.command; if (a.inject.needs_args) { const extra = prompt(`Arguments for ${a.title}${a.inject.args_hint ? ` (${a.inject.args_hint})` : ''}:`, ''); if (extra === null) return; if (extra.trim()) command += ' ' + extra.trim(); } await api('/api/audit/intent', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ event: 'action.inject.requested', detail: { action_id: a.id, source: a.source, target: a.inject.target ?? 'focused', command, controller_attached: session.isController, }, }), }).catch(() => undefined); if (session.isController && session.state.target && session.sendInput(command, session.state.target)) { setNote(`Injected "${command}" into the attached session — the agent runs it.`); } else { setComposer(command); // prefill the session composer; attach (drive) or start one, then Send setNote(`Ready to inject "${command}". Attach to a session (drive) or start one, then Send.`); } goSessions(); // actions target the sessions surface }; const copyCommand = async (a: ContribAction) => { await navigator.clipboard?.writeText(a.inject.command); setNote(`Copied "${a.inject.command}" to the clipboard.`); }; const actionById = new Map(actions.map((a) => [a.id, a])); const openScreen = (screen: ContribScreen) => { if (screen.source === 'cockpit://index/live') { window.location.hash = '#explore'; setNote('Opened the contributed Live Index screen.'); return; } if (screen.source === 'cockpit://issues/workbench') { window.location.hash = '#actions'; setNote('Issue Workbench is available here through the contributed issue actions and workflows.'); return; } setNote(`Unsupported contributed screen source: ${screen.source}`); }; return ( <>

Actions are contributed declaratively. Clicking one injects a command into an agentic session {' '}(focused, else it offers a new one); the agent runs it. The Cockpit never runs the CLI — agents do.

{err &&

{err}

}
{actions.length ? actions.map((a) => ( {a.trust_tier === 'sandboxed-third-party' && sandboxed} )) :

No contributed actions.

}

Screens

{screens.length ? screens.map((s) => (
{s.title}

{s.source}

)) :

No contributed screens.

}

Workflows

{workflows.length ? workflows.map((w) => (
{w.title} {w.description &&

{w.description}

}
{w.steps.map((step, idx) => { const action = actionById.get(step.action); return ( ); })}
)) :

No contributed workflows.

}

{note || 'Output appears in the session terminal — actions drop a command into a session and the agent executes it.'}

); }