feat(FN-3350): tokenize task detail danger/error styling

Fixes task detail modal danger/error styling by switching to token-based CSS variables for consistent theming across dark and light modes.

Fusion-Task-Id: FN-3350
This commit is contained in:
Fusion
2026-05-04 04:04:13 -07:00
committed by gsxdsm
parent fbb96b25a5
commit 8cb8055531
24 changed files with 487 additions and 53 deletions

View File

@@ -155,7 +155,7 @@ describe("Database", () => {
});
it("seeds schema version", () => {
expect(db.getSchemaVersion()).toBe(59);
expect(db.getSchemaVersion()).toBe(60);
});
it("seeds lastModified", () => {
@@ -178,7 +178,7 @@ describe("Database", () => {
it("is idempotent - calling init() twice does not fail", () => {
expect(() => db.init()).not.toThrow();
expect(db.getSchemaVersion()).toBe(59);
expect(db.getSchemaVersion()).toBe(60);
});
it("does not overwrite existing config on re-init", () => {
@@ -899,7 +899,7 @@ describe("schema migrations", () => {
db.init();
// Verify version bumped to 29 (includes v1→v2 through v26→v29)
expect(db.getSchemaVersion()).toBe(59);
expect(db.getSchemaVersion()).toBe(60);
// Verify new columns exist and existing data is intact
const cols = db.prepare("PRAGMA table_info(tasks)").all() as Array<{ name: string }>;
@@ -924,11 +924,11 @@ describe("schema migrations", () => {
const db = new Database(fusionDir);
db.init();
expect(db.getSchemaVersion()).toBe(59);
expect(db.getSchemaVersion()).toBe(60);
// Re-init should not fail
db.init();
expect(db.getSchemaVersion()).toBe(59);
expect(db.getSchemaVersion()).toBe(60);
db.close();
});
@@ -963,7 +963,7 @@ describe("schema migrations", () => {
db.init();
expect(db.getSchemaVersion()).toBe(59);
expect(db.getSchemaVersion()).toBe(60);
const cols = db.prepare("PRAGMA table_info(tasks)").all() as Array<{ name: string }>;
expect(cols.map((col) => col.name)).toContain("priority");
@@ -1004,7 +1004,7 @@ describe("schema migrations", () => {
db.init();
expect(db.getSchemaVersion()).toBe(59);
expect(db.getSchemaVersion()).toBe(60);
const cols = db.prepare("PRAGMA table_info(tasks)").all() as Array<{ name: string }>;
const colNames = cols.map((col) => col.name);
@@ -1073,7 +1073,7 @@ describe("schema migrations", () => {
db.init();
expect(db.getSchemaVersion()).toBe(59);
expect(db.getSchemaVersion()).toBe(60);
const cols = db.prepare("PRAGMA table_info(tasks)").all() as Array<{ name: string }>;
const colNames = cols.map((col) => col.name);
@@ -1176,7 +1176,7 @@ describe("schema migrations", () => {
db.init();
expect(db.getSchemaVersion()).toBe(59);
expect(db.getSchemaVersion()).toBe(60);
const cols = db.prepare("PRAGMA table_info(chat_messages)").all() as Array<{ name: string }>;
expect(cols.map((col) => col.name)).toContain("attachments");
@@ -1250,7 +1250,7 @@ describe("schema migrations", () => {
db.init();
expect(db.getSchemaVersion()).toBe(59);
expect(db.getSchemaVersion()).toBe(60);
const tables = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name = 'agentRatings'").all() as Array<{ name: string }>;
expect(tables).toEqual([{ name: "agentRatings" }]);
@@ -1274,7 +1274,7 @@ describe("schema migrations", () => {
db.init();
expect(db.getSchemaVersion()).toBe(59);
expect(db.getSchemaVersion()).toBe(60);
const tables = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name = 'mission_events'").all() as Array<{ name: string }>;
expect(tables).toEqual([{ name: "mission_events" }]);
@@ -1378,7 +1378,7 @@ describe("schema migrations", () => {
db.init();
// Verify version bumped to 29
expect(db.getSchemaVersion()).toBe(59);
expect(db.getSchemaVersion()).toBe(60);
// Verify new columns exist and existing data is intact
const cols = db.prepare("PRAGMA table_info(tasks)").all() as Array<{ name: string }>;
@@ -1847,7 +1847,7 @@ describe("createDatabase factory", () => {
const db = createDatabase(fusionDir);
db.init();
expect(db.getSchemaVersion()).toBe(59);
expect(db.getSchemaVersion()).toBe(60);
expect(db.getLastModified()).toBeGreaterThan(0);
db.close();

View File

@@ -869,7 +869,7 @@ describe("Migration: pre-33 DB upgrade", () => {
// Step 1: Create a fresh database at v33 (runs all migrations up to 33)
const db1 = createDatabase(legacyDir);
db1.init();
expect(db1.getSchemaVersion()).toBe(59);
expect(db1.getSchemaVersion()).toBe(60);
db1.close();
// Step 2: Manually downgrade to version 32 and drop insight tables
@@ -904,7 +904,7 @@ describe("Migration: pre-33 DB upgrade", () => {
expect(tableNamesBefore).not.toContain("project_insight_runs");
// Now run init — this triggers the v32→v33 migration
db3.init();
expect(db3.getSchemaVersion()).toBe(59);
expect(db3.getSchemaVersion()).toBe(60);
// Step 4: Verify insight tables exist after migration
const tablesAfter = db3.prepare(
@@ -935,12 +935,12 @@ describe("Migration: pre-33 DB upgrade", () => {
try {
const db1 = createDatabase(testDir);
db1.init();
expect(db1.getSchemaVersion()).toBe(59);
expect(db1.getSchemaVersion()).toBe(60);
db1.close();
const db2 = createDatabase(testDir);
expect(() => db2.init()).not.toThrow();
expect(db2.getSchemaVersion()).toBe(59);
expect(db2.getSchemaVersion()).toBe(60);
db2.close();
} finally {
rmSync(testDir, { recursive: true, force: true });

View File

@@ -2629,7 +2629,7 @@ describe("MissionStore", () => {
describe("Loop State & Validator Run Schema (v31)", () => {
it("schema version is 40 after migration", () => {
expect(db.getSchemaVersion()).toBe(59);
expect(db.getSchemaVersion()).toBe(60);
});
it("mission_features table has loop state columns", () => {

View File

@@ -742,7 +742,7 @@ describe("RoadmapStore", () => {
describe("schema version", () => {
it("schema version is 40 after init", () => {
expect(db.getSchemaVersion()).toBe(59);
expect(db.getSchemaVersion()).toBe(60);
});
});

View File

@@ -465,7 +465,7 @@ describe("Run Audit", () => {
});
it("schema version is bumped to 40", () => {
expect(db.getSchemaVersion()).toBe(59);
expect(db.getSchemaVersion()).toBe(60);
});
});
});

View File

@@ -480,6 +480,33 @@ describe("TaskStore", () => {
});
});
describe("pausedByAgentId persistence", () => {
it("creates and lists a task with pausedByAgentId", async () => {
const task = await store.createTask({ description: "Agent paused task" });
const updated = await store.updateTask(task.id, { pausedByAgentId: "agent-1" });
expect(updated.pausedByAgentId).toBe("agent-1");
const detail = await store.getTask(task.id);
expect(detail.pausedByAgentId).toBe("agent-1");
const tasks = await store.listTasks();
const listed = tasks.find((t) => t.id === task.id);
expect(listed?.pausedByAgentId).toBe("agent-1");
});
it("clears pausedByAgentId with null via updateTask", async () => {
const task = await store.createTask({ description: "Clear agent pause marker" });
await store.updateTask(task.id, { pausedByAgentId: "agent-2" });
const cleared = await store.updateTask(task.id, { pausedByAgentId: null });
expect(cleared.pausedByAgentId).toBeUndefined();
const detail = await store.getTask(task.id);
expect(detail.pausedByAgentId).toBeUndefined();
});
});
describe("nodeId persistence", () => {
it("creates a task with nodeId when provided", async () => {
const task = await store.createTask({
@@ -592,6 +619,36 @@ describe("TaskStore", () => {
});
});
describe("getTasksByAssignedAgent", () => {
it("returns only tasks assigned to the requested agent", async () => {
const mine = await store.createTask({ description: "mine", assignedAgentId: "agent-1" });
await store.createTask({ description: "other", assignedAgentId: "agent-2" });
await store.createTask({ description: "unassigned" });
const tasks = await store.getTasksByAssignedAgent("agent-1");
expect(tasks.map((task) => task.id)).toEqual([mine.id]);
});
it("supports pausedOnly filter", async () => {
const paused = await store.createTask({ description: "paused", assignedAgentId: "agent-1" });
const active = await store.createTask({ description: "active", assignedAgentId: "agent-1" });
await store.updateTask(paused.id, { paused: true });
const tasks = await store.getTasksByAssignedAgent("agent-1", { pausedOnly: true });
expect(tasks.map((task) => task.id)).toEqual([paused.id]);
expect(tasks.some((task) => task.id === active.id)).toBe(false);
});
it("supports excludeArchived filter", async () => {
const active = await store.createTask({ description: "active", assignedAgentId: "agent-1" });
const archived = await store.createTask({ description: "archived", assignedAgentId: "agent-1", column: "done" });
await store.archiveTask(archived.id, false);
const tasks = await store.getTasksByAssignedAgent("agent-1", { excludeArchived: true });
expect(tasks.map((task) => task.id)).toEqual([active.id]);
});
});
describe("selectNextTaskForAgent", () => {
it("returns null when no tasks exist", async () => {
await expect(store.selectNextTaskForAgent("agent-1")).resolves.toBeNull();
@@ -3546,6 +3603,39 @@ describe("TaskStore", () => {
fetched = await store.getTask(task.id);
expect(fetched.paused).toBe(true);
});
it("sets pausedByAgentId and logs agent pause reason", async () => {
const task = await createTestTask();
const paused = await store.pauseTask(task.id, true, undefined, { pausedByAgentId: "agent-1" });
expect(paused.pausedByAgentId).toBe("agent-1");
expect(paused.log.at(-1)?.action).toBe("Task paused (agent agent-1 paused)");
});
it("clears pausedByAgentId and logs agent resume reason", async () => {
const task = await createTestTask();
await store.pauseTask(task.id, true, undefined, { pausedByAgentId: "agent-2" });
const unpaused = await store.pauseTask(task.id, false);
expect(unpaused.pausedByAgentId).toBeUndefined();
expect(unpaused.log.at(-1)?.action).toBe("Task unpaused (agent agent-2 resumed)");
});
it("uses standard unpause log when task was not paused by an agent", async () => {
const task = await createTestTask();
await store.pauseTask(task.id, true);
const unpaused = await store.pauseTask(task.id, false);
expect(unpaused.pausedByAgentId).toBeUndefined();
expect(unpaused.log.at(-1)?.action).toBe("Task unpaused");
});
it("keeps pausedByAgentId undefined when pausing without agent options", async () => {
const task = await createTestTask();
const paused = await store.pauseTask(task.id, true);
expect(paused.pausedByAgentId).toBeUndefined();
});
});
describe("updateTask — paused", () => {

View File

@@ -51,7 +51,7 @@ describe("TaskStore task documents", () => {
expect(tableNames.has("task_documents")).toBe(true);
expect(tableNames.has("task_document_revisions")).toBe(true);
expect(db.getSchemaVersion()).toBe(59);
expect(db.getSchemaVersion()).toBe(60);
const index = db
.prepare(