feat(mcp): delete tasks, create task lists and lists, agent badge; export/import settings category
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 2m21s
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 2m21s
New MCP tools delete_task (tasks:write), create_task_list (tasks:write) and create_list (lists:write); list_task_lists now returns the board columns so agents know the valid kanbanStatus values. Task deletion is a shared helper (deleteTask) for REST and MCP. Tasks and list items get agent_mark (migration 12): "created" when an agent adds them via MCP, "edited" when an agent changes them; a change by the user clears it. The new AgentBadge shows "KI" / "KI geändert" in task rows, Kanban cards, the task detail, the inbox and lists. Settings: export and import move out of "Webhooks, KI-Agenten & Export" into their own category "Export & Import". Docs, help, README and changelog updated; v0.29.0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
8faed7a160
commit
ac068248d7
28 files changed
+441
-65
No files matched your search
@@ -513,10 +513,10 @@ export const HelpView: React.FC<HelpViewProps> = ({ onBack }) => {
|
||||
content: (
|
||||
<div className="space-y-2 text-muted leading-relaxed">
|
||||
<p>
|
||||
Unter <em className="text-main">Kontoeinstellungen → Webhooks, KI-Agenten & Export</em> kannst du persönliche API-Schlüssel erzeugen. Pro Schlüssel legst du mit Schaltern fest, was er darf: Gedanken in die Inbox, Aufgaben oder Listeneinträge einliefern (Webhooks) oder für KI-Agenten Aufgaben und Listen lesen und ändern. Notizen erreicht ein Schlüssel nie.
|
||||
Unter <em className="text-main">Kontoeinstellungen → Webhooks & KI-Agenten</em> kannst du persönliche API-Schlüssel erzeugen. Pro Schlüssel legst du mit Schaltern fest, was er darf: Gedanken in die Inbox, Aufgaben oder Listeneinträge einliefern (Webhooks) oder für KI-Agenten Aufgaben und Listen lesen und ändern. Notizen erreicht ein Schlüssel nie.
|
||||
</p>
|
||||
<p>
|
||||
<strong className="text-main">KI-Agenten:</strong> MindSift ist ein MCP-Server (<code className="text-accent bg-panel px-1 py-0.5 rounded font-mono">POST /api/v1/mcp</code>). Claude Code, OpenAI Codex, Claude Desktop, Cursor und eigene Agenten können damit offene Aufgaben auslesen, abhaken und anlegen sowie Einkaufs- und Checklisten führen. Die Einstellungen zeigen den fertigen Befehl bzw. die Konfiguration für den jeweiligen Agenten; der Agent sieht nur die Werkzeuge, für die der Schlüssel freigegeben ist.
|
||||
<strong className="text-main">KI-Agenten:</strong> MindSift ist ein MCP-Server (<code className="text-accent bg-panel px-1 py-0.5 rounded font-mono">POST /api/v1/mcp</code>). Claude Code, OpenAI Codex, Claude Desktop, Cursor und eigene Agenten können damit offene Aufgaben auslesen, anlegen, abhaken und löschen, neue Aufgabenlisten und Listen anlegen sowie Einkaufs- und Checklisten führen. Die Einstellungen zeigen den fertigen Befehl bzw. die Konfiguration für den jeweiligen Agenten; der Agent sieht nur die Werkzeuge, für die der Schlüssel freigegeben ist. Was ein Agent angelegt oder geändert hat, trägt das Zeichen <strong className="text-main">KI</strong> bzw. <strong className="text-main">KI geändert</strong>, bis du den Eintrag selbst änderst.
|
||||
</p>
|
||||
<p>
|
||||
Mit dem Feld <code className="text-accent bg-panel px-1 py-0.5 rounded font-mono">"target"</code> wählst du das Ziel: <code className="font-mono">triage</code> (Standard), <code className="font-mono">task</code> (optional mit <code className="font-mono">taskListId</code>) oder <code className="font-mono">list_item</code> (mit <code className="font-mono">listId</code>). Der Simulator in den Einstellungen zeigt passende Beispiele.
|
||||
@@ -664,7 +664,7 @@ export const HelpView: React.FC<HelpViewProps> = ({ onBack }) => {
|
||||
<strong className="text-main">Eigenes Theme:</strong> Vorlage herunterladen oder einfügen, Farben und Rundungen anpassen, als <code className="text-accent bg-panel px-1 py-0.5 rounded font-mono">.css</code>-Datei hochladen oder einfügen und „Speichern & aktivieren“. Das Theme greift sofort und steht dir auf allen Geräten zur Verfügung.
|
||||
</li>
|
||||
<li>
|
||||
<strong className="text-main">Server-Backups:</strong> Hat die Administration automatische Backups eingeschaltet, findest du unter <em>Kontoeinstellungen → Webhooks, KI-Agenten & Export</em> die täglichen Sicherungen deiner Daten. Du kannst sie herunterladen oder wieder einspielen, auch nur für einzelne Bereiche wie Listen oder Aufgaben.
|
||||
<strong className="text-main">Server-Backups:</strong> Hat die Administration automatische Backups eingeschaltet, findest du unter <em>Kontoeinstellungen → Export & Import</em> die täglichen Sicherungen deiner Daten. Du kannst sie herunterladen oder wieder einspielen, auch nur für einzelne Bereiche wie Listen oder Aufgaben.
|
||||
</li>
|
||||
<li>
|
||||
<strong className="text-main">Ohne Internet:</strong> Als App installiert (oder im Browser) startet MindSift auch offline mit dem zuletzt geladenen Stand. Gedanken erfassen sowie Aufgaben und Listeneinträge abhaken geht weiter; ein Hinweis unten zeigt, wie viele Änderungen warten, und sie werden automatisch übertragen, sobald die Verbindung zurück ist.
|
||||
|
||||
@@ -16,6 +16,7 @@ import { OFFLINE_ITEM_PREFIX, pendingListItems } from '../../lib/offline';
|
||||
import { UnifiedShareModal } from '../../components/UnifiedShareModal';
|
||||
import { AvatarStack, AvatarPerson } from '../../components/AvatarStack';
|
||||
import { CountBadge } from '../../components/CountBadge';
|
||||
import { AgentBadge } from '../../components/AgentBadge';
|
||||
import { FormSheet } from '../../components/FormSheet';
|
||||
import { useMobileActions } from '../../context/MobileActionContext';
|
||||
|
||||
@@ -1390,6 +1391,7 @@ export const SharedListsView: React.FC<SharedListsViewProps> = ({ onRefreshGloba
|
||||
)}
|
||||
</div>
|
||||
|
||||
<AgentBadge mark={item.agentMark} size="xs" />
|
||||
{renderItemAuthor(item)}
|
||||
<button
|
||||
type="button"
|
||||
@@ -1499,6 +1501,7 @@ export const SharedListsView: React.FC<SharedListsViewProps> = ({ onRefreshGloba
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<AgentBadge mark={item.agentMark} size="xs" />
|
||||
{renderItemAuthor(item)}
|
||||
{item.completedByName && (
|
||||
<span className="text-xs text-faint">✓ {item.completedByName}</span>
|
||||
|
||||
@@ -35,7 +35,7 @@ type SimTarget = 'triage' | 'task' | 'list_item';
|
||||
type McpClient = 'claude' | 'codex' | 'json';
|
||||
|
||||
// Personal API keys with scopes (switches), MCP connection snippets, a webhook simulator and copyable
|
||||
// examples (settings → Webhooks, KI-Agenten & Export)
|
||||
// examples (settings → Webhooks & KI-Agenten)
|
||||
export const ApiKeysPanel: React.FC<ApiKeysPanelProps> = ({ onIngested }) => {
|
||||
const [keys, setKeys] = useState<APIKey[]>([]);
|
||||
const [newKeyName, setNewKeyName] = useState('');
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
Upload,
|
||||
Pencil,
|
||||
Copy,
|
||||
Archive,
|
||||
} from 'lucide-react';
|
||||
import { AuthStatus, NotificationEvents, NotificationSettings, PushDevice, User, UserTheme } from '../../lib/types';
|
||||
import { ApiKeysPanel } from './ApiKeysPanel';
|
||||
@@ -65,7 +66,7 @@ interface UserSettingsViewProps {
|
||||
onBack: () => void;
|
||||
}
|
||||
|
||||
type UserSettingsSection = 'profile' | 'appearance' | 'alarms' | 'webhooks';
|
||||
type UserSettingsSection = 'profile' | 'appearance' | 'alarms' | 'webhooks' | 'data';
|
||||
|
||||
export function buildNotificationSettings(user: User): NotificationSettings {
|
||||
const hasLegacy = Array.isArray(user.alarmChannels);
|
||||
@@ -582,7 +583,7 @@ export const UserSettingsView: React.FC<UserSettingsViewProps> = ({
|
||||
<div>
|
||||
<h1 className="text-base font-bold text-main tracking-tight">Kontoeinstellungen</h1>
|
||||
<p className="text-xs text-muted">
|
||||
Persönliches Profil, Design-Themes, Aufgaben-Alarme, Webhooks, KI-Agenten & Daten-Backup
|
||||
Persönliches Profil, Design-Themes, Aufgaben-Alarme, Webhooks, KI-Agenten, Export & Import
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -651,8 +652,23 @@ export const UserSettingsView: React.FC<UserSettingsViewProps> = ({
|
||||
>
|
||||
<Key className="w-4 h-4 text-accent flex-shrink-0" />
|
||||
<div>
|
||||
<p className="font-semibold">Webhooks, KI-Agenten & Export</p>
|
||||
<p className="text-[10px] text-faint">API-Keys, MCP, Curl & JSON-Backup</p>
|
||||
<p className="font-semibold">Webhooks & KI-Agenten</p>
|
||||
<p className="text-[10px] text-faint">API-Keys, MCP & Curl</p>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={() => setSection('data')}
|
||||
className={`w-full px-3.5 py-3 text-left text-xs font-medium flex items-center gap-2.5 transition-colors ${
|
||||
section === 'data'
|
||||
? 'bg-panel-elevated text-main border-l-2 border-l-accent'
|
||||
: 'text-muted hover:text-main hover:bg-panel-hover'
|
||||
}`}
|
||||
>
|
||||
<Archive className="w-4 h-4 text-accent flex-shrink-0" />
|
||||
<div>
|
||||
<p className="font-semibold">Export & Import</p>
|
||||
<p className="text-[10px] text-faint">Backups, Obsidian & Wiederherstellen</p>
|
||||
</div>
|
||||
</button>
|
||||
</aside>
|
||||
@@ -1849,14 +1865,12 @@ export const UserSettingsView: React.FC<UserSettingsViewProps> = ({
|
||||
)}
|
||||
|
||||
{/* ================================================================= */}
|
||||
{/* SECTION 4: PRIVATE WEBHOOKS & EXPORT */}
|
||||
{/* SECTION 4: PRIVATE WEBHOOKS & AI AGENTS */}
|
||||
{/* ================================================================= */}
|
||||
{section === 'webhooks' && (
|
||||
<div className="space-y-5">
|
||||
<div className="border-b border-border pb-3">
|
||||
<h2 className="text-sm font-bold text-main">
|
||||
Webhooks, KI-Agenten & Daten-Export
|
||||
</h2>
|
||||
<h2 className="text-sm font-bold text-main">Webhooks & KI-Agenten</h2>
|
||||
<p className="text-muted mt-0.5">
|
||||
Erstelle persönliche API-Schlüssel, um aus Skripten, Smarthome oder Bots Aufgaben und Gedanken
|
||||
einzuspeisen oder KI-Agenten wie Claude Code und Codex an deine Aufgaben und Listen zu lassen.
|
||||
@@ -1864,11 +1878,24 @@ export const UserSettingsView: React.FC<UserSettingsViewProps> = ({
|
||||
</div>
|
||||
|
||||
<ApiKeysPanel />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="pt-4 border-t border-border">
|
||||
<ServerBackupsCard />
|
||||
{/* ================================================================= */}
|
||||
{/* SECTION 5: EXPORT & IMPORT */}
|
||||
{/* ================================================================= */}
|
||||
{section === 'data' && (
|
||||
<div className="space-y-5">
|
||||
<div className="border-b border-border pb-3">
|
||||
<h2 className="text-sm font-bold text-main">Export & Import</h2>
|
||||
<p className="text-muted mt-0.5">
|
||||
Lade deine Daten als Backup oder Markdown-Archiv herunter, spiele Server-Backups zurück oder importiere
|
||||
MindSift-Daten und Obsidian-Vaults.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<ServerBackupsCard />
|
||||
|
||||
{/* Full Data Backup */}
|
||||
<div className="pt-4 border-t border-border flex flex-col sm:flex-row sm:items-center justify-between gap-3">
|
||||
<div>
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
} from 'lucide-react';
|
||||
import { Thought, TaskList, TaskListMember, KanbanColumn, User, Recurrence } from '../../lib/types';
|
||||
import { UserAvatar } from '../../components/UserAvatar';
|
||||
import { AgentBadge } from '../../components/AgentBadge';
|
||||
import { UserAutocomplete } from '../UserAutocomplete';
|
||||
import { api, triggerHaptic } from '../../lib/api';
|
||||
import { MarkdownViewer } from '../../lib/markdown';
|
||||
@@ -244,6 +245,7 @@ const TaskDetailModalContent: React.FC<TaskDetailModalProps & { task: Thought }>
|
||||
<span>Webhook</span>
|
||||
</span>
|
||||
)}
|
||||
<AgentBadge mark={task.agentMark} />
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-1.5">
|
||||
|
||||
@@ -35,6 +35,7 @@ import { useKanbanTouchDrag } from './useKanbanTouchDrag';
|
||||
import { api, triggerHaptic } from '../../lib/api';
|
||||
import { UnifiedShareModal } from '../../components/UnifiedShareModal';
|
||||
import { TaskDetailModal } from './TaskDetailModal';
|
||||
import { AgentBadge } from '../../components/AgentBadge';
|
||||
import { ManageColumnsModal, DEFAULT_KANBAN_COLUMNS } from './ManageColumnsModal';
|
||||
import { AvatarStack, AvatarPerson } from '../../components/AvatarStack';
|
||||
import { CountBadge } from '../../components/CountBadge';
|
||||
@@ -287,7 +288,7 @@ export const TasksView: React.FC<TasksViewProps> = ({
|
||||
}
|
||||
} else if (msg.event === 'TASK_REORDERED') {
|
||||
loadData();
|
||||
} else if (msg.event === 'TASK_LIST_UPDATED' || msg.event === 'TASK_LIST_DELETED') {
|
||||
} else if (msg.event === 'TASK_LIST_CREATED' || msg.event === 'TASK_LIST_UPDATED' || msg.event === 'TASK_LIST_DELETED') {
|
||||
// Payload only carries the list ID; reload so permissions reflect this user's view
|
||||
api.getTaskLists().then((lists) => setTaskLists(Array.isArray(lists) ? lists : [])).catch(() => {});
|
||||
}
|
||||
@@ -1352,6 +1353,7 @@ export const TasksView: React.FC<TasksViewProps> = ({
|
||||
<span>Webhook</span>
|
||||
</span>
|
||||
)}
|
||||
<AgentBadge mark={task.agentMark} />
|
||||
|
||||
{/* Note indicator */}
|
||||
{task.notes && (
|
||||
@@ -2435,6 +2437,7 @@ export const TasksView: React.FC<TasksViewProps> = ({
|
||||
<span>Webhook</span>
|
||||
</span>
|
||||
)}
|
||||
<AgentBadge mark={task.agentMark} size="xs" />
|
||||
{task.dueDate && (
|
||||
<span
|
||||
className={`inline-flex items-center gap-0.5 text-[9px] ${!task.isCompleted && isOverdue(task.dueDate) ? 'text-status-err font-semibold' : 'text-muted'}`}
|
||||
|
||||
@@ -25,6 +25,7 @@ import {
|
||||
import { SharedList, Thought } from '../../lib/types';
|
||||
import { addDays, formatDue } from '../../lib/due';
|
||||
import { api, triggerHaptic } from '../../lib/api';
|
||||
import { AgentBadge } from '../../components/AgentBadge';
|
||||
|
||||
interface TriageDeckProps {
|
||||
deck: Thought[];
|
||||
@@ -158,6 +159,7 @@ const SwipeableQueueItem: React.FC<SwipeableQueueItemProps> = ({
|
||||
<Mic className="w-2.5 h-2.5" /> Diktat
|
||||
</span>
|
||||
)}
|
||||
<AgentBadge mark={item.agentMark} />
|
||||
</div>
|
||||
|
||||
{/* Desktop quick buttons (hidden on mobile so queue items are clean & easy to tap/swipe) */}
|
||||
@@ -521,6 +523,7 @@ export const TriageDeck: React.FC<TriageDeckProps> = ({
|
||||
<div className="flex items-center gap-1.5">
|
||||
{priorityBadge(nextCard.priority)}
|
||||
{sourceBadge(nextCard.source)}
|
||||
<AgentBadge mark={nextCard.agentMark} />
|
||||
</div>
|
||||
<p className="text-sm text-muted line-clamp-2">{nextCard.content}</p>
|
||||
<div className="text-[11px] text-faint">Nächster Quick Dump…</div>
|
||||
@@ -590,6 +593,7 @@ export const TriageDeck: React.FC<TriageDeckProps> = ({
|
||||
<div className="flex items-center gap-1.5">
|
||||
{priorityBadge(activeCard.priority)}
|
||||
{sourceBadge(activeCard.source)}
|
||||
<AgentBadge mark={activeCard.agentMark} />
|
||||
</div>
|
||||
<div
|
||||
className="flex items-center gap-2"
|
||||
|
||||
Reference in new issue
Block a user