summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsoryu <soryu@soryu.co>2026-02-12 23:37:44 +0000
committersoryu <soryu@soryu.co>2026-02-12 23:37:44 +0000
commitd1b4f56109d4900c76c27b6a35763694323046af (patch)
treeaafc1825dfc4aaed2129b2a376010ad8e9556a42
parent355f10964c4dbec24a244a00caba5c17ed23fc65 (diff)
downloadsoryu-makima/makima-jp--remove-memory-system-from-frontend-228e0bd0.tar.gz
soryu-makima/makima-jp--remove-memory-system-from-frontend-228e0bd0.zip
feat: makima.jp: Remove memory system from frontendmakima/makima-jp--remove-memory-system-from-frontend-228e0bd0
-rw-r--r--makima/frontend/src/components/directives/DirectiveDetail.tsx261
-rw-r--r--makima/frontend/src/hooks/useDirectiveMemories.ts119
-rw-r--r--makima/frontend/src/lib/api.ts185
3 files changed, 1 insertions, 564 deletions
diff --git a/makima/frontend/src/components/directives/DirectiveDetail.tsx b/makima/frontend/src/components/directives/DirectiveDetail.tsx
index ab6ddbb..39eaa3f 100644
--- a/makima/frontend/src/components/directives/DirectiveDetail.tsx
+++ b/makima/frontend/src/components/directives/DirectiveDetail.tsx
@@ -1,8 +1,7 @@
import { useState, useMemo, useEffect, useRef } from "react";
-import type { DirectiveWithSteps, DirectiveStatus, MemoryCategory } from "../../lib/api";
+import type { DirectiveWithSteps, DirectiveStatus } from "../../lib/api";
import { DirectiveDAG } from "./DirectiveDAG";
import { DirectiveLogStream } from "./DirectiveLogStream";
-import { useDirectiveMemories } from "../../hooks/useDirectiveMemories";
import { useMultiTaskSubscription } from "../../hooks/useMultiTaskSubscription";
const STATUS_BADGE: Record<DirectiveStatus, { color: string; label: string }> = {
@@ -13,16 +12,6 @@ const STATUS_BADGE: Record<DirectiveStatus, { color: string; label: string }> =
archived: { color: "text-[#556677] border-[#2a3a5a]", label: "ARCHIVED" },
};
-const CATEGORY_COLORS: Record<MemoryCategory, { text: string; border: string; bg: string; label: string }> = {
- decision: { text: "text-amber-400", border: "border-amber-800", bg: "bg-amber-900/20", label: "Decision" },
- context: { text: "text-cyan-400", border: "border-cyan-800", bg: "bg-cyan-900/20", label: "Context" },
- preference: { text: "text-violet-400", border: "border-violet-800", bg: "bg-violet-900/20", label: "Preference" },
- learning: { text: "text-emerald-400", border: "border-emerald-800", bg: "bg-emerald-900/20", label: "Learning" },
- other: { text: "text-[#7788aa]", border: "border-[#2a3a5a]", bg: "bg-[#1a2540]", label: "Other" },
-};
-
-const ALL_CATEGORIES: MemoryCategory[] = ["decision", "context", "preference", "learning", "other"];
-
interface DirectiveDetailProps {
directive: DirectiveWithSteps;
onStart: () => void;
@@ -60,29 +49,6 @@ export function DirectiveDetail({
const totalSteps = directive.steps.length;
const progress = totalSteps > 0 ? Math.round((completedSteps / totalSteps) * 100) : 0;
- // Memory panel state
- const [memoryOpen, setMemoryOpen] = useState(false);
- const [addingMemory, setAddingMemory] = useState(false);
- const [newCategory, setNewCategory] = useState<MemoryCategory>("context");
- const [newContent, setNewContent] = useState("");
- const [newSource, setNewSource] = useState("");
- const [confirmClear, setConfirmClear] = useState(false);
-
- const {
- grouped,
- config: memoryConfig,
- loading: memoryLoading,
- error: memoryError,
- toggleEnabled,
- add: addMemory,
- remove: removeMemory,
- clearAll: clearMemories,
- refresh: refreshMemories,
- } = useDirectiveMemories(directive.id);
-
- const memoryEnabled = memoryConfig?.enabled ?? false;
- const totalMemories = Object.values(grouped).reduce((sum, arr) => sum + arr.length, 0);
-
// Build task map from directive steps and orchestrator
const taskMap = useMemo(() => {
const map = new Map<string, string>();
@@ -121,23 +87,6 @@ export function DirectiveDetail({
setEditingGoal(false);
};
- const handleAddMemory = async () => {
- if (!newContent.trim()) return;
- await addMemory({
- category: newCategory,
- content: newContent.trim(),
- source: newSource.trim() || undefined,
- });
- setNewContent("");
- setNewSource("");
- setAddingMemory(false);
- };
-
- const handleClearAll = async () => {
- await clearMemories();
- setConfirmClear(false);
- };
-
return (
<div className="flex flex-col h-full overflow-y-auto">
{/* Header */}
@@ -337,214 +286,6 @@ export function DirectiveDetail({
)}
</div>
- {/* Memory Panel */}
- <div className="px-4 py-3 border-b border-[rgba(117,170,252,0.1)]">
- {/* Memory header — always visible */}
- <div className="flex items-center justify-between">
- <button
- type="button"
- onClick={() => setMemoryOpen((v) => !v)}
- className="flex items-center gap-1.5 group"
- >
- <span className="text-[10px] font-mono text-[#556677] group-hover:text-[#9bc3ff] transition-colors">
- {memoryOpen ? "\u25BC" : "\u25B6"}
- </span>
- <span className="text-[10px] font-mono text-[#9bc3ff] uppercase tracking-wide">
- Memory
- </span>
- {totalMemories > 0 && (
- <span className="text-[9px] font-mono text-[#556677] ml-1">
- ({totalMemories})
- </span>
- )}
- </button>
- <div className="flex items-center gap-2">
- {/* Enable/disable toggle */}
- <button
- type="button"
- onClick={() => toggleEnabled(!memoryEnabled)}
- className={`text-[9px] font-mono border rounded px-1.5 py-0.5 transition-colors ${
- memoryEnabled
- ? "text-emerald-400 border-emerald-800 hover:text-emerald-300"
- : "text-[#556677] border-[#2a3a5a] hover:text-[#7788aa]"
- }`}
- title={memoryEnabled ? "Disable memory" : "Enable memory"}
- >
- {memoryEnabled ? "ON" : "OFF"}
- </button>
- </div>
- </div>
-
- {/* Collapsible content */}
- {memoryOpen && (
- <div className="mt-2">
- {memoryError && (
- <div className="text-[10px] font-mono text-red-400 mb-2 px-2 py-1 bg-red-900/10 border border-red-800/30 rounded">
- {memoryError}
- </div>
- )}
-
- {memoryLoading ? (
- <div className="text-[10px] font-mono text-[#556677] py-2">Loading...</div>
- ) : totalMemories === 0 ? (
- <div className="text-[10px] font-mono text-[#556677] py-2">
- No memory entries yet.
- {!memoryEnabled && " Enable memory to start capturing entries."}
- </div>
- ) : (
- /* Grouped entries */
- <div className="flex flex-col gap-2">
- {ALL_CATEGORIES.map((cat) => {
- const entries = grouped[cat];
- if (entries.length === 0) return null;
- const style = CATEGORY_COLORS[cat];
- return (
- <div key={cat}>
- <div className="flex items-center gap-1.5 mb-1">
- <span className={`text-[9px] font-mono ${style.text} uppercase tracking-wider`}>
- {style.label}
- </span>
- <span className="text-[9px] font-mono text-[#556677]">
- ({entries.length})
- </span>
- </div>
- <div className="flex flex-col gap-1">
- {entries.map((entry) => (
- <div
- key={entry.id}
- className={`flex items-start gap-2 px-2 py-1.5 rounded border ${style.border} ${style.bg}`}
- >
- <div className="flex-1 min-w-0">
- <p className="text-[10px] font-mono text-[#c0d0e0] whitespace-pre-wrap break-words">
- {entry.content}
- </p>
- {entry.source && (
- <span className="text-[9px] font-mono text-[#556677] mt-0.5 block">
- src: {entry.source}
- </span>
- )}
- </div>
- <button
- type="button"
- onClick={() => removeMemory(entry.id)}
- className="text-[9px] font-mono text-[#556677] hover:text-red-400 shrink-0 mt-0.5"
- title="Delete entry"
- >
- x
- </button>
- </div>
- ))}
- </div>
- </div>
- );
- })}
- </div>
- )}
-
- {/* Action bar: Add + Clear */}
- <div className="flex items-center gap-2 mt-2 pt-2 border-t border-[rgba(117,170,252,0.1)]">
- <button
- type="button"
- onClick={() => setAddingMemory((v) => !v)}
- className="text-[10px] font-mono text-[#75aafc] hover:text-white border border-[rgba(117,170,252,0.2)] rounded px-2 py-0.5"
- >
- {addingMemory ? "Cancel" : "+ Add"}
- </button>
- {totalMemories > 0 && (
- <>
- {confirmClear ? (
- <div className="flex items-center gap-1.5 ml-auto">
- <span className="text-[9px] font-mono text-red-400">Clear all?</span>
- <button
- type="button"
- onClick={handleClearAll}
- className="text-[9px] font-mono text-red-400 hover:text-red-300 border border-red-800 rounded px-1.5 py-0.5"
- >
- Yes
- </button>
- <button
- type="button"
- onClick={() => setConfirmClear(false)}
- className="text-[9px] font-mono text-[#7788aa] hover:text-white border border-[#2a3a5a] rounded px-1.5 py-0.5"
- >
- No
- </button>
- </div>
- ) : (
- <button
- type="button"
- onClick={() => setConfirmClear(true)}
- className="text-[10px] font-mono text-[#556677] hover:text-red-400 ml-auto"
- >
- Clear all
- </button>
- )}
- </>
- )}
- <button
- type="button"
- onClick={refreshMemories}
- className="text-[9px] font-mono text-[#556677] hover:text-[#75aafc]"
- title="Refresh memories"
- >
- [refresh]
- </button>
- </div>
-
- {/* Add form */}
- {addingMemory && (
- <div className="mt-2 p-2 bg-[#0a1628] border border-[rgba(117,170,252,0.15)] rounded flex flex-col gap-2">
- <div className="flex items-center gap-2">
- <label className="text-[9px] font-mono text-[#7788aa] shrink-0">Category</label>
- <select
- value={newCategory}
- onChange={(e) => setNewCategory(e.target.value as MemoryCategory)}
- className="bg-[#1a2540] border border-[rgba(117,170,252,0.2)] rounded px-1.5 py-0.5 text-[10px] font-mono text-white flex-1"
- >
- {ALL_CATEGORIES.map((c) => (
- <option key={c} value={c}>
- {CATEGORY_COLORS[c].label}
- </option>
- ))}
- </select>
- </div>
- <textarea
- value={newContent}
- onChange={(e) => setNewContent(e.target.value)}
- placeholder="Memory content..."
- className="w-full bg-[#1a2540] border border-[rgba(117,170,252,0.2)] rounded px-2 py-1.5 text-[10px] font-mono text-white resize-y min-h-[40px] placeholder:text-[#556677]"
- rows={2}
- />
- <input
- type="text"
- value={newSource}
- onChange={(e) => setNewSource(e.target.value)}
- placeholder="Source (optional)"
- className="w-full bg-[#1a2540] border border-[rgba(117,170,252,0.2)] rounded px-2 py-1 text-[10px] font-mono text-white placeholder:text-[#556677]"
- />
- <div className="flex gap-1.5">
- <button
- type="button"
- onClick={handleAddMemory}
- disabled={!newContent.trim()}
- className="text-[10px] font-mono text-emerald-400 hover:text-emerald-300 border border-emerald-800 rounded px-2 py-0.5 disabled:opacity-40 disabled:cursor-not-allowed"
- >
- Save
- </button>
- <button
- type="button"
- onClick={() => { setAddingMemory(false); setNewContent(""); setNewSource(""); }}
- className="text-[10px] font-mono text-[#7788aa] hover:text-white border border-[#2a3a5a] rounded px-2 py-0.5"
- >
- Cancel
- </button>
- </div>
- </div>
- )}
- </div>
- )}
- </div>
-
{/* DAG */}
<div className="px-4 py-3 flex-1">
<span className="text-[10px] font-mono text-[#9bc3ff] uppercase tracking-wide block mb-2">
diff --git a/makima/frontend/src/hooks/useDirectiveMemories.ts b/makima/frontend/src/hooks/useDirectiveMemories.ts
deleted file mode 100644
index 3844c44..0000000
--- a/makima/frontend/src/hooks/useDirectiveMemories.ts
+++ /dev/null
@@ -1,119 +0,0 @@
-import { useState, useEffect, useCallback } from "react";
-import {
- type DirectiveMemoryEntry,
- type DirectiveMemoryConfig,
- type MemoryCategory,
- type CreateDirectiveMemoryRequest,
- getDirectiveMemoryConfig,
- setDirectiveMemoryEnabled,
- listDirectiveMemories,
- addDirectiveMemory,
- deleteDirectiveMemory,
- clearDirectiveMemories,
-} from "../lib/api";
-
-export function useDirectiveMemories(directiveId: string | undefined) {
- const [memories, setMemories] = useState<DirectiveMemoryEntry[]>([]);
- const [config, setConfig] = useState<DirectiveMemoryConfig | null>(null);
- const [loading, setLoading] = useState(false);
- const [error, setError] = useState<string | null>(null);
-
- const refreshConfig = useCallback(async () => {
- if (!directiveId) return;
- try {
- const c = await getDirectiveMemoryConfig(directiveId);
- setConfig(c);
- } catch (e) {
- // Config may not exist yet — treat as disabled
- setConfig({ directiveId, enabled: false, updatedAt: new Date().toISOString() });
- }
- }, [directiveId]);
-
- const refreshMemories = useCallback(async () => {
- if (!directiveId) return;
- try {
- setLoading(true);
- setError(null);
- const entries = await listDirectiveMemories(directiveId);
- setMemories(entries);
- } catch (e) {
- setError(e instanceof Error ? e.message : "Failed to load memories");
- } finally {
- setLoading(false);
- }
- }, [directiveId]);
-
- const refresh = useCallback(async () => {
- await Promise.all([refreshConfig(), refreshMemories()]);
- }, [refreshConfig, refreshMemories]);
-
- useEffect(() => {
- refresh();
- }, [refresh]);
-
- const toggleEnabled = useCallback(async (enabled: boolean) => {
- if (!directiveId) return;
- try {
- setError(null);
- const c = await setDirectiveMemoryEnabled(directiveId, enabled);
- setConfig(c);
- } catch (e) {
- setError(e instanceof Error ? e.message : "Failed to toggle memory");
- }
- }, [directiveId]);
-
- const add = useCallback(async (req: CreateDirectiveMemoryRequest) => {
- if (!directiveId) return;
- try {
- setError(null);
- await addDirectiveMemory(directiveId, req);
- await refreshMemories();
- } catch (e) {
- setError(e instanceof Error ? e.message : "Failed to add memory");
- }
- }, [directiveId, refreshMemories]);
-
- const remove = useCallback(async (memoryId: string) => {
- if (!directiveId) return;
- try {
- setError(null);
- await deleteDirectiveMemory(directiveId, memoryId);
- await refreshMemories();
- } catch (e) {
- setError(e instanceof Error ? e.message : "Failed to delete memory");
- }
- }, [directiveId, refreshMemories]);
-
- const clearAll = useCallback(async () => {
- if (!directiveId) return;
- try {
- setError(null);
- await clearDirectiveMemories(directiveId);
- setMemories([]);
- } catch (e) {
- setError(e instanceof Error ? e.message : "Failed to clear memories");
- }
- }, [directiveId]);
-
- /** Group entries by category */
- const grouped = memories.reduce<Record<MemoryCategory, DirectiveMemoryEntry[]>>(
- (acc, entry) => {
- acc[entry.category].push(entry);
- return acc;
- },
- { decision: [], context: [], preference: [], learning: [], other: [] },
- );
-
- return {
- memories,
- grouped,
- config,
- loading,
- error,
- refresh,
- toggleEnabled,
- add,
- remove,
- clearAll,
- };
-}
diff --git a/makima/frontend/src/lib/api.ts b/makima/frontend/src/lib/api.ts
index 552829a..9d1f0ad 100644
--- a/makima/frontend/src/lib/api.ts
+++ b/makima/frontend/src/lib/api.ts
@@ -3023,8 +3023,6 @@ export interface Directive {
prUrl: string | null;
prBranch: string | null;
completionTaskId: string | null;
- /** Whether the memory system is enabled for this directive */
- memoryEnabled: boolean;
goalUpdatedAt: string;
startedAt: string | null;
version: number;
@@ -3062,8 +3060,6 @@ export interface DirectiveSummary {
orchestratorTaskId: string | null;
prUrl: string | null;
completionTaskId: string | null;
- /** Whether the memory system is enabled for this directive */
- memoryEnabled: boolean;
version: number;
createdAt: string;
updatedAt: string;
@@ -3084,8 +3080,6 @@ export interface CreateDirectiveRequest {
repositoryUrl?: string;
localPath?: string;
baseBranch?: string;
- /** Enable the memory system for this directive (default: false) */
- memoryEnabled?: boolean;
}
export interface UpdateDirectiveRequest {
@@ -3096,8 +3090,6 @@ export interface UpdateDirectiveRequest {
localPath?: string;
baseBranch?: string;
orchestratorTaskId?: string;
- /** Enable or disable the memory system for this directive */
- memoryEnabled?: boolean;
version?: number;
}
@@ -3237,180 +3229,3 @@ export async function updateDirectiveGoal(id: string, goal: string): Promise<Dir
if (!res.ok) throw new Error(`Failed to update goal: ${res.statusText}`);
return res.json();
}
-
-// =============================================================================
-// Directive Memory Types & API
-// =============================================================================
-
-/** Category of a directive memory entry */
-export type MemoryCategory =
- | "decision"
- | "learning"
- | "context"
- | "preference"
- | "issue"
- | "progress"
- | "other";
-
-/** A single memory entry associated with a directive */
-export interface DirectiveMemory {
- id: string;
- directiveId: string;
- /** The memory content text */
- content: string;
- /** Category for organizing memories */
- category: MemoryCategory;
- /** Which step created this memory (null if directive-level) */
- stepId: string | null;
- /** Which task created this memory (null if manually added) */
- taskId: string | null;
- /** Importance score (1-10, higher = more important) */
- importance: number;
- createdAt: string;
- updatedAt: string;
-}
-
-/** Response from listing directive memories */
-export interface DirectiveMemoryListResponse {
- memories: DirectiveMemory[];
- total: number;
-}
-
-/** Request to create a new directive memory */
-export interface CreateDirectiveMemoryRequest {
- content: string;
- category?: MemoryCategory;
- stepId?: string;
- taskId?: string;
- importance?: number;
-}
-
-/** Request to update a directive memory */
-export interface UpdateDirectiveMemoryRequest {
- content?: string;
- category?: MemoryCategory;
- importance?: number;
-}
-
-// Directive Memory API functions
-
-/**
- * List all memories for a directive.
- * Optionally filter by category or step.
- */
-export async function listDirectiveMemories(
- directiveId: string,
- params?: { category?: MemoryCategory; stepId?: string }
-): Promise<DirectiveMemoryListResponse> {
- const searchParams = new URLSearchParams();
- if (params?.category) searchParams.set("category", params.category);
- if (params?.stepId) searchParams.set("stepId", params.stepId);
- const query = searchParams.toString();
- const url = `${API_BASE}/api/v1/directives/${directiveId}/memories${query ? `?${query}` : ""}`;
- const res = await authFetch(url);
- if (!res.ok) throw new Error(`Failed to list directive memories: ${res.statusText}`);
- return res.json();
-}
-
-/**
- * Get a single memory entry by ID.
- */
-export async function getDirectiveMemory(
- directiveId: string,
- memoryId: string
-): Promise<DirectiveMemory> {
- const res = await authFetch(
- `${API_BASE}/api/v1/directives/${directiveId}/memories/${memoryId}`
- );
- if (!res.ok) throw new Error(`Failed to get directive memory: ${res.statusText}`);
- return res.json();
-}
-
-/**
- * Create a new memory entry for a directive.
- */
-export async function createDirectiveMemory(
- directiveId: string,
- req: CreateDirectiveMemoryRequest
-): Promise<DirectiveMemory> {
- const res = await authFetch(`${API_BASE}/api/v1/directives/${directiveId}/memories`, {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify(req),
- });
- if (!res.ok) throw new Error(`Failed to create directive memory: ${res.statusText}`);
- return res.json();
-}
-
-/**
- * Update an existing memory entry.
- */
-export async function updateDirectiveMemory(
- directiveId: string,
- memoryId: string,
- req: UpdateDirectiveMemoryRequest
-): Promise<DirectiveMemory> {
- const res = await authFetch(
- `${API_BASE}/api/v1/directives/${directiveId}/memories/${memoryId}`,
- {
- method: "PUT",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify(req),
- }
- );
- if (!res.ok) throw new Error(`Failed to update directive memory: ${res.statusText}`);
- return res.json();
-}
-
-/**
- * Delete a memory entry.
- */
-export async function deleteDirectiveMemory(
- directiveId: string,
- memoryId: string
-): Promise<void> {
- const res = await authFetch(
- `${API_BASE}/api/v1/directives/${directiveId}/memories/${memoryId}`,
- { method: "DELETE" }
- );
- if (!res.ok) throw new Error(`Failed to delete directive memory: ${res.statusText}`);
-}
-
-/**
- * Batch create multiple memory entries for a directive.
- * Useful when a task completes and wants to store multiple learnings at once.
- */
-export async function batchCreateDirectiveMemories(
- directiveId: string,
- memories: CreateDirectiveMemoryRequest[]
-): Promise<DirectiveMemory[]> {
- const res = await authFetch(
- `${API_BASE}/api/v1/directives/${directiveId}/memories/batch`,
- {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify(memories),
- }
- );
- if (!res.ok) throw new Error(`Failed to batch create directive memories: ${res.statusText}`);
- return res.json();
-}
-
-/**
- * Get a formatted memory context string for a directive.
- * This returns memories formatted for injection into task prompts.
- * Optionally filter by category or limit the number of memories returned.
- */
-export async function getDirectiveMemoryContext(
- directiveId: string,
- params?: { category?: MemoryCategory; limit?: number }
-): Promise<{ context: string; memoryCount: number }> {
- const searchParams = new URLSearchParams();
- if (params?.category) searchParams.set("category", params.category);
- if (params?.limit) searchParams.set("limit", params.limit.toString());
- const query = searchParams.toString();
- const url = `${API_BASE}/api/v1/directives/${directiveId}/memories/context${query ? `?${query}` : ""}`;
- const res = await authFetch(url);
- if (!res.ok) throw new Error(`Failed to get directive memory context: ${res.statusText}`);
- return res.json();
-}