chore: snapshot WIP across dashboard, engine, and core
Bundles staged work-in-progress modifications across multiple packages (routes, store, agent-instructions, self-healing, QuickEntryBox, etc.) plus the dashboard theme-data.css preload fix. Note: an unstaged 621-line deletion in .fusion/memory.md was deliberately NOT committed — it appears to be an accidental overwrite of architecture notes and is left in the working tree for review. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1323,7 +1323,7 @@ describe("TaskStore", () => {
|
||||
expect(paged[0].id).toBe("FN-002");
|
||||
});
|
||||
|
||||
it("slim mode returns metadata but drops heavy fields (log/comments/steps)", async () => {
|
||||
it("slim mode drops the agent log but keeps board-visible fields (steps/comments)", async () => {
|
||||
const task = await store.createTask({ description: "Slim test" });
|
||||
await store.logEntry(task.id, "heavy log entry that should not appear in slim list");
|
||||
|
||||
@@ -1333,13 +1333,22 @@ describe("TaskStore", () => {
|
||||
const full = fullList.find((t) => t.id === task.id)!;
|
||||
const slim = slimList.find((t) => t.id === task.id)!;
|
||||
|
||||
// Sanity: the full row really has the log we wrote.
|
||||
expect(full.log.length).toBeGreaterThan(0);
|
||||
|
||||
// Slim must drop the heavy log payload (the only field worth slimming).
|
||||
expect(slim.id).toBe(task.id);
|
||||
expect(slim.description).toBe("Slim test");
|
||||
expect(slim.column).toBe(full.column);
|
||||
expect(slim.log).toEqual([]);
|
||||
expect(slim.steps).toEqual([]);
|
||||
expect(slim.comments).toBeUndefined();
|
||||
|
||||
// Slim must STILL include the small JSON columns the board UI reads:
|
||||
// step progress, comment counts, workflow status, steering badges.
|
||||
// (Dropping them silently broke TaskCard progress bars and the comments tab.)
|
||||
expect(slim.steps).toEqual(full.steps);
|
||||
expect(slim.comments).toEqual(full.comments);
|
||||
expect(slim.workflowStepResults).toEqual(full.workflowStepResults);
|
||||
expect(slim.steeringComments).toEqual(full.steeringComments);
|
||||
});
|
||||
|
||||
it("includeArchived=false excludes archived tasks; default includes them", async () => {
|
||||
|
||||
@@ -1316,10 +1316,22 @@ export class TaskStore extends EventEmitter<TaskStoreEvents> {
|
||||
* from each row to make list responses cheap for board-style consumers. Detail fields default
|
||||
* to empty arrays in the returned Task objects; use `getTask(id)` to load full data. */
|
||||
slim?: boolean;
|
||||
/** Restrict to a single column (e.g. 'in-review' for the auto-merge sweep). */
|
||||
column?: Column;
|
||||
}): Promise<Task[]> {
|
||||
const includeArchived = options?.includeArchived ?? true;
|
||||
const slim = options?.slim ?? false;
|
||||
const columnFilter = options?.column;
|
||||
|
||||
// Slim mode drops ONLY the agent log column. On busy boards `log` accounts
|
||||
// for ~99% of the row payload (60+ MB across 1200 tasks); every other JSON
|
||||
// column combined is under 500 KB and is needed by the board UI:
|
||||
// - `steps` → step progress badge on TaskCard
|
||||
// - `comments` → comment count badge on TaskCard
|
||||
// - `workflowStepResults` → workflow status indicators
|
||||
// - `steeringComments` → steering badge
|
||||
// Use `getTask(id)` to load the full row (including `log`) for the
|
||||
// TaskDetailModal's Activity tab and Agent Log subview.
|
||||
const slimColumns = `
|
||||
id, title, description, "column", status, size, reviewLevel, currentStep,
|
||||
worktree, blockedBy, paused, baseBranch, branch, baseCommitSha,
|
||||
@@ -1329,17 +1341,25 @@ export class TaskStore extends EventEmitter<TaskStoreEvents> {
|
||||
mergeRetries, stuckKillCount, recoveryRetryCount, nextRecoveryAt,
|
||||
error, summary, thinkingLevel,
|
||||
createdAt, updatedAt, columnMovedAt,
|
||||
dependencies,
|
||||
dependencies, steps, comments, workflowStepResults, steeringComments,
|
||||
attachments, prInfo, issueInfo, mergeDetails,
|
||||
breakIntoSubtasks, enabledWorkflowSteps, modifiedFiles,
|
||||
missionId, sliceId, assignedAgentId, assigneeUserId,
|
||||
checkedOutBy, checkedOutAt
|
||||
`;
|
||||
const selectClause = slim ? slimColumns : '*';
|
||||
const whereClause = includeArchived ? '' : ` WHERE "column" != 'archived'`;
|
||||
const whereParts: string[] = [];
|
||||
const params: string[] = [];
|
||||
if (columnFilter) {
|
||||
whereParts.push(`"column" = ?`);
|
||||
params.push(columnFilter);
|
||||
} else if (!includeArchived) {
|
||||
whereParts.push(`"column" != 'archived'`);
|
||||
}
|
||||
const whereClause = whereParts.length > 0 ? ` WHERE ${whereParts.join(" AND ")}` : "";
|
||||
const sql = `SELECT ${selectClause} FROM tasks${whereClause} ORDER BY createdAt ASC`;
|
||||
|
||||
const rows = this.db.prepare(sql).all();
|
||||
const rows = this.db.prepare(sql).all(...params);
|
||||
const tasks = (rows as any[]).map((row) => this.rowToTask(row));
|
||||
|
||||
// Sort by createdAt, then by numeric ID suffix for tie-breaking
|
||||
@@ -2699,6 +2719,11 @@ export class TaskStore extends EventEmitter<TaskStoreEvents> {
|
||||
|
||||
// Store current lastModified
|
||||
this.lastKnownModified = this.db.getLastModified();
|
||||
// Initialize lastPollTime so the first checkForChanges() cycle filters by
|
||||
// "modified since now" instead of doing a full SELECT * + emitting an
|
||||
// update event for every cached task. Without this, dashboard startup
|
||||
// re-loaded the entire tasks table 1s after watch() began.
|
||||
this.lastPollTime = new Date().toISOString();
|
||||
|
||||
// Use a sentinel watcher object so existing code that checks `this.watcher` still works
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user