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:
gsxdsm
2026-04-10 21:12:40 -07:00
parent 54fdeb66df
commit 1a3ff011d3
13 changed files with 279 additions and 17 deletions

View File

@@ -78,6 +78,12 @@ describe("resolveAgentInstructions", () => {
expect(result).toBe("");
});
it("returns soul-only agent with no instructions", async () => {
const agent = makeAgent({ soul: "Be thorough and analytical." });
const result = await resolveAgentInstructions(agent, testDir);
expect(result).toBe("## Soul\n\nBe thorough and analytical.");
});
it("returns instructionsText when set", async () => {
const agent = makeAgent({ instructionsText: "Always write tests." });
const result = await resolveAgentInstructions(agent, testDir);
@@ -204,6 +210,36 @@ describe("resolveAgentInstructions", () => {
expect(result.length).toBe(50000);
});
it("truncates oversized soul", async () => {
const oversized = "s".repeat(10010);
const agent = makeAgent({ soul: oversized });
const result = await resolveAgentInstructions(agent, testDir);
expect(result.length).toBe(10000 + "## Soul\n\n".length);
});
it("places soul section after instructionsText and before performance feedback", async () => {
const filePath = join(testDir, "file-instructions.md");
await writeFile(filePath, "File-based instructions here.");
const agent = makeAgent({
instructionsText: "Inline instructions.",
instructionsPath: "file-instructions.md",
soul: "Be methodical and detailed.",
});
const result = await resolveAgentInstructions(agent, testDir);
// Verify section order
const soulIndex = result.indexOf("## Soul");
const instructionsTextIndex = result.indexOf("Inline instructions.");
const instructionsFileIndex = result.indexOf("File-based instructions here.");
expect(instructionsTextIndex).toBeLessThan(soulIndex);
expect(instructionsFileIndex).toBeLessThan(soulIndex);
expect(soulIndex).toBeLessThan(result.indexOf("## Soul") + 10); // Soul section is present
});
});
describe("resolveAgentInstructions with rating summary", () => {
@@ -243,6 +279,29 @@ describe("resolveAgentInstructions with rating summary", () => {
expect(result).toContain(' - "Could communicate blockers sooner" (score: 4.0)');
});
it("places soul section before performance feedback and after instructions", async () => {
const agent = makeAgent({
instructionsText: "Implement the feature.",
soul: "Be pragmatic and efficient.",
});
const summary = makeRatingSummary({
totalRatings: 3,
trend: "stable",
});
const result = await resolveAgentInstructions(agent, testDir, summary);
// Verify section order: instructionsText → soul → Performance Feedback
const instructionsIndex = result.indexOf("Implement the feature.");
const soulIndex = result.indexOf("## Soul");
const feedbackIndex = result.indexOf("## Performance Feedback");
expect(instructionsIndex).toBeLessThan(soulIndex);
expect(soulIndex).toBeLessThan(feedbackIndex);
expect(result).toContain("## Soul");
expect(result).toContain("## Performance Feedback");
});
it("shows the correct trend indicator for all trend states", async () => {
const agent = makeAgent({ instructionsText: "Base instructions" });
const trends: Array<[AgentRatingSummary["trend"], string]> = [

View File

@@ -4,6 +4,7 @@ import type { Agent, AgentRatingSummary, AgentStore } from "@fusion/core";
const MAX_INSTRUCTIONS_PATH_LENGTH = 500;
const MAX_INSTRUCTIONS_TEXT_LENGTH = 50_000;
const MAX_SOUL_LENGTH = 10_000;
function trimAndClamp(value: string, maxLength: number, label: string, agentId: string): string {
const trimmed = value.trim();
@@ -77,6 +78,14 @@ function getTrendLabel(trend: AgentRatingSummary["trend"]): string {
}
}
function formatSoulSection(soul: string, agentId: string): string {
const trimmed = trimAndClamp(soul, MAX_SOUL_LENGTH, "soul", agentId);
if (!trimmed) {
return "";
}
return `## Soul\n\n${trimmed}`;
}
function formatPerformanceFeedbackSection(ratingSummary: AgentRatingSummary): string {
const lines: string[] = [
"## Performance Feedback",
@@ -170,6 +179,14 @@ export async function resolveAgentInstructions(
}
}
// Soul/personality section (after instructions, before performance feedback)
if (agent.soul?.trim()) {
const soulSection = formatSoulSection(agent.soul, agent.id);
if (soulSection) {
parts.push(soulSection);
}
}
if (ratingSummary && ratingSummary.totalRatings > 0) {
parts.push(formatPerformanceFeedbackSection(ratingSummary));
}

View File

@@ -365,7 +365,10 @@ export class SelfHealingManager {
async archiveStaleDoneTasks(): Promise<number> {
try {
const tasks = await this.store.listTasks();
// Slim listing — we only need id/column/columnMovedAt/updatedAt to decide
// staleness. Pulling full task payloads (logs, comments, steps) here used
// to drag in tens of MB on busy boards and stalled the maintenance loop.
const tasks = await this.store.listTasks({ slim: true });
const cutoff = Date.now() - SelfHealingManager.AUTO_ARCHIVE_AFTER_MS;
const stale = tasks.filter((t) => {