summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsoryu <soryu@soryu.co>2026-02-13 00:28:22 +0000
committersoryu <soryu@soryu.co>2026-02-13 00:28:22 +0000
commit37a5e807425a436b7aa7be5f72ee370b4d07471c (patch)
treefefbde5fdacc87422e854ad96b0995db1c053ef3
parent3aee52212f554c80ec3cd82c0147bca6d3df592a (diff)
downloadsoryu-makima/makima-jp--full-build-verification-and-integration-335affa1.tar.gz
soryu-makima/makima-jp--full-build-verification-and-integration-335affa1.zip
-rw-r--r--makima/frontend/src/components/directives/DirectiveDetail.tsx53
-rw-r--r--makima/frontend/src/hooks/useDirectiveMemories.ts122
-rw-r--r--makima/frontend/tsconfig.tsbuildinfo2
3 files changed, 69 insertions, 108 deletions
diff --git a/makima/frontend/src/components/directives/DirectiveDetail.tsx b/makima/frontend/src/components/directives/DirectiveDetail.tsx
index ab6ddbb..e66325a 100644
--- a/makima/frontend/src/components/directives/DirectiveDetail.tsx
+++ b/makima/frontend/src/components/directives/DirectiveDetail.tsx
@@ -18,10 +18,12 @@ const CATEGORY_COLORS: Record<MemoryCategory, { text: string; border: string; bg
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" },
+ issue: { text: "text-red-400", border: "border-red-800", bg: "bg-red-900/20", label: "Issue" },
+ progress: { text: "text-blue-400", border: "border-blue-800", bg: "bg-blue-900/20", label: "Progress" },
other: { text: "text-[#7788aa]", border: "border-[#2a3a5a]", bg: "bg-[#1a2540]", label: "Other" },
};
-const ALL_CATEGORIES: MemoryCategory[] = ["decision", "context", "preference", "learning", "other"];
+const ALL_CATEGORIES: MemoryCategory[] = ["decision", "context", "preference", "learning", "issue", "progress", "other"];
interface DirectiveDetailProps {
directive: DirectiveWithSteps;
@@ -65,23 +67,22 @@ export function DirectiveDetail({
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);
+ const totalMemories = Object.values(grouped).reduce(
+ (sum: number, arr: unknown[]) => sum + arr.length,
+ 0
+ );
// Build task map from directive steps and orchestrator
const taskMap = useMemo(() => {
@@ -126,10 +127,8 @@ export function DirectiveDetail({
await addMemory({
category: newCategory,
content: newContent.trim(),
- source: newSource.trim() || undefined,
});
setNewContent("");
- setNewSource("");
setAddingMemory(false);
};
@@ -358,21 +357,6 @@ export function DirectiveDetail({
</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 */}
@@ -389,14 +373,13 @@ export function DirectiveDetail({
) : 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 catEntries = grouped[cat];
+ if (catEntries.length === 0) return null;
const style = CATEGORY_COLORS[cat];
return (
<div key={cat}>
@@ -405,11 +388,11 @@ export function DirectiveDetail({
{style.label}
</span>
<span className="text-[9px] font-mono text-[#556677]">
- ({entries.length})
+ ({catEntries.length})
</span>
</div>
<div className="flex flex-col gap-1">
- {entries.map((entry) => (
+ {catEntries.map((entry) => (
<div
key={entry.id}
className={`flex items-start gap-2 px-2 py-1.5 rounded border ${style.border} ${style.bg}`}
@@ -418,11 +401,6 @@ export function DirectiveDetail({
<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"
@@ -515,13 +493,6 @@ export function DirectiveDetail({
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"
@@ -533,7 +504,7 @@ export function DirectiveDetail({
</button>
<button
type="button"
- onClick={() => { setAddingMemory(false); setNewContent(""); setNewSource(""); }}
+ onClick={() => { setAddingMemory(false); setNewContent(""); }}
className="text-[10px] font-mono text-[#7788aa] hover:text-white border border-[#2a3a5a] rounded px-2 py-0.5"
>
Cancel
diff --git a/makima/frontend/src/hooks/useDirectiveMemories.ts b/makima/frontend/src/hooks/useDirectiveMemories.ts
index 3844c44..db1f3fa 100644
--- a/makima/frontend/src/hooks/useDirectiveMemories.ts
+++ b/makima/frontend/src/hooks/useDirectiveMemories.ts
@@ -1,41 +1,35 @@
import { useState, useEffect, useCallback } from "react";
import {
- type DirectiveMemoryEntry,
- type DirectiveMemoryConfig,
+ type DirectiveMemory,
type MemoryCategory,
type CreateDirectiveMemoryRequest,
- getDirectiveMemoryConfig,
- setDirectiveMemoryEnabled,
listDirectiveMemories,
- addDirectiveMemory,
+ createDirectiveMemory,
deleteDirectiveMemory,
- clearDirectiveMemories,
} from "../lib/api";
+const ALL_CATEGORIES: MemoryCategory[] = [
+ "decision",
+ "learning",
+ "context",
+ "preference",
+ "issue",
+ "progress",
+ "other",
+];
+
export function useDirectiveMemories(directiveId: string | undefined) {
- const [memories, setMemories] = useState<DirectiveMemoryEntry[]>([]);
- const [config, setConfig] = useState<DirectiveMemoryConfig | null>(null);
+ const [memories, setMemories] = useState<DirectiveMemory[]>([]);
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);
+ const response = await listDirectiveMemories(directiveId);
+ setMemories(response.memories);
} catch (e) {
setError(e instanceof Error ? e.message : "Failed to load memories");
} finally {
@@ -43,75 +37,71 @@ export function useDirectiveMemories(directiveId: string | undefined) {
}
}, [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]);
+ refreshMemories();
+ }, [refreshMemories]);
- 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 add = useCallback(
+ async (req: CreateDirectiveMemoryRequest) => {
+ if (!directiveId) return;
+ try {
+ setError(null);
+ await createDirectiveMemory(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 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);
+ // Delete all memories one by one (no bulk clear endpoint)
+ for (const m of memories) {
+ await deleteDirectiveMemory(directiveId, m.id);
+ }
setMemories([]);
} catch (e) {
setError(e instanceof Error ? e.message : "Failed to clear memories");
}
- }, [directiveId]);
+ }, [directiveId, memories]);
/** Group entries by category */
- const grouped = memories.reduce<Record<MemoryCategory, DirectiveMemoryEntry[]>>(
+ const grouped = memories.reduce<Record<MemoryCategory, DirectiveMemory[]>>(
(acc, entry) => {
- acc[entry.category].push(entry);
+ const cat = entry.category || "other";
+ acc[cat].push(entry);
return acc;
},
- { decision: [], context: [], preference: [], learning: [], other: [] },
+ ALL_CATEGORIES.reduce(
+ (init, cat) => ({ ...init, [cat]: [] }),
+ {} as Record<MemoryCategory, DirectiveMemory[]>
+ )
);
return {
memories,
grouped,
- config,
loading,
error,
- refresh,
- toggleEnabled,
+ refresh: refreshMemories,
add,
remove,
clearAll,
diff --git a/makima/frontend/tsconfig.tsbuildinfo b/makima/frontend/tsconfig.tsbuildinfo
index f36c337..210212c 100644
--- a/makima/frontend/tsconfig.tsbuildinfo
+++ b/makima/frontend/tsconfig.tsbuildinfo
@@ -1 +1 @@
-{"root":["./src/main.tsx","./src/vite-env.d.ts","./src/components/gridoverlay.tsx","./src/components/japanesehovertext.tsx","./src/components/logo.tsx","./src/components/masthead.tsx","./src/components/navstrip.tsx","./src/components/phaseconfirmationnotification.tsx","./src/components/protectedroute.tsx","./src/components/rewritelink.tsx","./src/components/simplemarkdown.tsx","./src/components/supervisorquestionnotification.tsx","./src/components/charts/chartrenderer.tsx","./src/components/contracts/commandmodepanel.tsx","./src/components/contracts/contractcliinput.tsx","./src/components/contracts/contractcontextmenu.tsx","./src/components/contracts/contractdetail.tsx","./src/components/contracts/contractlist.tsx","./src/components/contracts/phasebadge.tsx","./src/components/contracts/phaseconfirmationmodal.tsx","./src/components/contracts/phasedeliverablespanel.tsx","./src/components/contracts/phasehint.tsx","./src/components/contracts/phaseprogressbar.tsx","./src/components/contracts/quickactionbuttons.tsx","./src/components/contracts/repositorypanel.tsx","./src/components/contracts/taskderivationpreview.tsx","./src/components/directives/directivedag.tsx","./src/components/directives/directivedetail.tsx","./src/components/directives/directivelist.tsx","./src/components/directives/stepnode.tsx","./src/components/files/bodyrenderer.tsx","./src/components/files/cliinput.tsx","./src/components/files/conflictnotification.tsx","./src/components/files/elementcontextmenu.tsx","./src/components/files/filedetail.tsx","./src/components/files/filelist.tsx","./src/components/files/reposyncindicator.tsx","./src/components/files/updatenotification.tsx","./src/components/files/versionhistorydropdown.tsx","./src/components/history/checkpointcard.tsx","./src/components/history/checkpointlist.tsx","./src/components/history/conversationmessage.tsx","./src/components/history/conversationview.tsx","./src/components/history/historyfilters.tsx","./src/components/history/resumecontrols.tsx","./src/components/history/timelineeventcard.tsx","./src/components/history/timelinelist.tsx","./src/components/history/index.ts","./src/components/listen/contractpickermodal.tsx","./src/components/listen/controlpanel.tsx","./src/components/listen/discusscontractmodal.tsx","./src/components/listen/speakerpanel.tsx","./src/components/listen/transcriptanalysispanel.tsx","./src/components/listen/transcriptpanel.tsx","./src/components/mesh/branchtaskmodal.tsx","./src/components/mesh/contractcompletequestion.tsx","./src/components/mesh/directoryinput.tsx","./src/components/mesh/gitactionspanel.tsx","./src/components/mesh/inlinesubtaskeditor.tsx","./src/components/mesh/mergeconflictresolver.tsx","./src/components/mesh/overlaydiffviewer.tsx","./src/components/mesh/prpreview.tsx","./src/components/mesh/patcheslistpanel.tsx","./src/components/mesh/subtasktree.tsx","./src/components/mesh/taskdetail.tsx","./src/components/mesh/tasklist.tsx","./src/components/mesh/taskoutput.tsx","./src/components/mesh/tasktree.tsx","./src/components/mesh/unifiedmeshchatinput.tsx","./src/components/mesh/worktreefilespanel.tsx","./src/components/workflow/phasecolumn.tsx","./src/components/workflow/workflowboard.tsx","./src/components/workflow/workflowcontractcard.tsx","./src/contexts/authcontext.tsx","./src/contexts/supervisorquestionscontext.tsx","./src/hooks/usecontracts.ts","./src/hooks/usedirectives.ts","./src/hooks/usefilesubscription.ts","./src/hooks/usefiles.ts","./src/hooks/usemeshchathistory.ts","./src/hooks/usemicrophone.ts","./src/hooks/usespeakwebsocket.ts","./src/hooks/usetasksubscription.ts","./src/hooks/usetasks.ts","./src/hooks/usetextscramble.ts","./src/hooks/useversionhistory.ts","./src/hooks/usewebsocket.ts","./src/lib/api.ts","./src/lib/listenapi.ts","./src/lib/markdown.ts","./src/lib/supabase.ts","./src/routes/_index.tsx","./src/routes/contract-file.tsx","./src/routes/contracts.tsx","./src/routes/directives.tsx","./src/routes/files.tsx","./src/routes/history.tsx","./src/routes/listen.tsx","./src/routes/login.tsx","./src/routes/mesh.tsx","./src/routes/settings.tsx","./src/routes/speak.tsx","./src/routes/workflow.tsx","./src/types/messages.ts"],"version":"5.9.3"} \ No newline at end of file
+{"root":["./src/main.tsx","./src/vite-env.d.ts","./src/components/gridoverlay.tsx","./src/components/japanesehovertext.tsx","./src/components/logo.tsx","./src/components/masthead.tsx","./src/components/navstrip.tsx","./src/components/phaseconfirmationnotification.tsx","./src/components/protectedroute.tsx","./src/components/rewritelink.tsx","./src/components/simplemarkdown.tsx","./src/components/supervisorquestionnotification.tsx","./src/components/charts/chartrenderer.tsx","./src/components/contracts/commandmodepanel.tsx","./src/components/contracts/contractcliinput.tsx","./src/components/contracts/contractcontextmenu.tsx","./src/components/contracts/contractdetail.tsx","./src/components/contracts/contractlist.tsx","./src/components/contracts/phasebadge.tsx","./src/components/contracts/phaseconfirmationmodal.tsx","./src/components/contracts/phasedeliverablespanel.tsx","./src/components/contracts/phasehint.tsx","./src/components/contracts/phaseprogressbar.tsx","./src/components/contracts/quickactionbuttons.tsx","./src/components/contracts/repositorypanel.tsx","./src/components/contracts/taskderivationpreview.tsx","./src/components/directives/directivedag.tsx","./src/components/directives/directivedetail.tsx","./src/components/directives/directivelist.tsx","./src/components/directives/directivelogstream.tsx","./src/components/directives/stepnode.tsx","./src/components/files/bodyrenderer.tsx","./src/components/files/cliinput.tsx","./src/components/files/conflictnotification.tsx","./src/components/files/elementcontextmenu.tsx","./src/components/files/filedetail.tsx","./src/components/files/filelist.tsx","./src/components/files/reposyncindicator.tsx","./src/components/files/updatenotification.tsx","./src/components/files/versionhistorydropdown.tsx","./src/components/history/checkpointcard.tsx","./src/components/history/checkpointlist.tsx","./src/components/history/conversationmessage.tsx","./src/components/history/conversationview.tsx","./src/components/history/historyfilters.tsx","./src/components/history/resumecontrols.tsx","./src/components/history/timelineeventcard.tsx","./src/components/history/timelinelist.tsx","./src/components/history/index.ts","./src/components/listen/contractpickermodal.tsx","./src/components/listen/controlpanel.tsx","./src/components/listen/discusscontractmodal.tsx","./src/components/listen/speakerpanel.tsx","./src/components/listen/transcriptanalysispanel.tsx","./src/components/listen/transcriptpanel.tsx","./src/components/mesh/branchtaskmodal.tsx","./src/components/mesh/contractcompletequestion.tsx","./src/components/mesh/directoryinput.tsx","./src/components/mesh/gitactionspanel.tsx","./src/components/mesh/inlinesubtaskeditor.tsx","./src/components/mesh/mergeconflictresolver.tsx","./src/components/mesh/overlaydiffviewer.tsx","./src/components/mesh/prpreview.tsx","./src/components/mesh/patcheslistpanel.tsx","./src/components/mesh/subtasktree.tsx","./src/components/mesh/taskdetail.tsx","./src/components/mesh/tasklist.tsx","./src/components/mesh/taskoutput.tsx","./src/components/mesh/tasktree.tsx","./src/components/mesh/unifiedmeshchatinput.tsx","./src/components/mesh/worktreefilespanel.tsx","./src/components/workflow/phasecolumn.tsx","./src/components/workflow/workflowboard.tsx","./src/components/workflow/workflowcontractcard.tsx","./src/contexts/authcontext.tsx","./src/contexts/supervisorquestionscontext.tsx","./src/hooks/usecontracts.ts","./src/hooks/usedirectivememories.ts","./src/hooks/usedirectives.ts","./src/hooks/usefilesubscription.ts","./src/hooks/usefiles.ts","./src/hooks/usemeshchathistory.ts","./src/hooks/usemicrophone.ts","./src/hooks/usemultitasksubscription.ts","./src/hooks/usespeakwebsocket.ts","./src/hooks/usetasksubscription.ts","./src/hooks/usetasks.ts","./src/hooks/usetextscramble.ts","./src/hooks/useversionhistory.ts","./src/hooks/usewebsocket.ts","./src/lib/api.ts","./src/lib/listenapi.ts","./src/lib/markdown.ts","./src/lib/supabase.ts","./src/routes/_index.tsx","./src/routes/contract-file.tsx","./src/routes/contracts.tsx","./src/routes/directives.tsx","./src/routes/files.tsx","./src/routes/history.tsx","./src/routes/listen.tsx","./src/routes/login.tsx","./src/routes/mesh.tsx","./src/routes/settings.tsx","./src/routes/speak.tsx","./src/routes/workflow.tsx","./src/types/messages.ts"],"version":"5.9.3"} \ No newline at end of file