fix: remove buildProjectContext usage causing build error

This commit is contained in:
zenchantlive 2026-03-01 21:22:46 -08:00
parent 842f931f71
commit c8c91736b8
9 changed files with 13403 additions and 8 deletions

View file

@ -0,0 +1,99 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import fs from 'fs/promises';
import path from 'path';
// Test that GraphNodeData interface includes livenessMap field
test('GraphNodeData interface includes livenessMap field', async () => {
const fileContent = await fs.readFile(path.join(process.cwd(), 'src/components/graph/graph-node-card.tsx'), 'utf-8');
assert.ok(
/livenessMap/.test(fileContent),
'GraphNodeData should include livenessMap field'
);
});
// Test that GraphNodeData includes assignee field for liveness lookup
test('GraphNodeData interface includes assignee field', async () => {
const fileContent = await fs.readFile(path.join(process.cwd(), 'src/components/graph/graph-node-card.tsx'), 'utf-8');
assert.ok(
/assignee/.test(fileContent),
'GraphNodeData should include assignee field for liveness lookup'
);
});
// Test that GraphNodeCard imports AgentAvatar
test('GraphNodeCard imports AgentAvatar component', async () => {
const fileContent = await fs.readFile(path.join(process.cwd(), 'src/components/graph/graph-node-card.tsx'), 'utf-8');
assert.ok(
fileContent.includes('AgentAvatar'),
'GraphNodeCard should import and use AgentAvatar'
);
});
// Test that GraphNodeCard renders AgentAvatar based on liveness
test('GraphNodeCard renders AgentAvatar with stale/evicted liveness pulse', async () => {
const fileContent = await fs.readFile(path.join(process.cwd(), 'src/components/graph/graph-node-card.tsx'), 'utf-8');
// Should check for stale or evicted liveness state
assert.ok(
fileContent.includes('stale') || fileContent.includes('evicted'),
'GraphNodeCard should handle stale/evicted liveness for pulse animation'
);
});
// Test that WorkflowGraph accepts livenessMap prop
test('WorkflowGraph accepts livenessMap prop', async () => {
const fileContent = await fs.readFile(path.join(process.cwd(), 'src/components/shared/workflow-graph.tsx'), 'utf-8');
assert.ok(
/livenessMap/.test(fileContent),
'WorkflowGraph should accept livenessMap prop'
);
});
// Test that WorkflowGraph passes livenessMap to node data
test('WorkflowGraph passes livenessMap to node data', async () => {
const fileContent = await fs.readFile(path.join(process.cwd(), 'src/components/shared/workflow-graph.tsx'), 'utf-8');
assert.ok(
fileContent.includes('livenessMap'),
'WorkflowGraph should pass livenessMap into node data'
);
});
// Test that SmartDag passes livenessMap to WorkflowGraph
test('SmartDag passes livenessMap prop to WorkflowGraph', async () => {
const fileContent = await fs.readFile(path.join(process.cwd(), 'src/components/graph/smart-dag.tsx'), 'utf-8');
assert.ok(
fileContent.includes('livenessMap'),
'SmartDag should accept and pass livenessMap to WorkflowGraph'
);
});
// Test that SmartDag destructures livenessMap from props
test('SmartDag destructures livenessMap from its props', async () => {
const fileContent = await fs.readFile(path.join(process.cwd(), 'src/components/graph/smart-dag.tsx'), 'utf-8');
// Check that the function signature includes livenessMap
const funcMatch = fileContent.match(/export function SmartDag\s*\(\s*\{([^}]+)\}/s);
assert.ok(
funcMatch && funcMatch[1].includes('livenessMap'),
'SmartDag function should destructure livenessMap from props'
);
});
// Test that AgentAvatar is overlaid at bottom-right of node card
test('GraphNodeCard overlays AgentAvatar at bottom-right position', async () => {
const fileContent = await fs.readFile(path.join(process.cwd(), 'src/components/graph/graph-node-card.tsx'), 'utf-8');
// Should use absolute positioning for the overlay
assert.ok(
fileContent.includes('absolute') && fileContent.includes('AgentAvatar'),
'GraphNodeCard should use absolute positioning for AgentAvatar overlay'
);
});
// Test liveness-to-status mapping covers stuck states
test('GraphNodeCard maps stale/evicted liveness to stuck/stale AgentAvatar status', async () => {
const fileContent = await fs.readFile(path.join(process.cwd(), 'src/components/graph/graph-node-card.tsx'), 'utf-8');
// Should map liveness values to AgentAvatar status prop
assert.ok(
(fileContent.includes('stale') || fileContent.includes('stuck')) && fileContent.includes('AgentAvatar'),
'GraphNodeCard should map liveness to AgentAvatar status for stuck/stale agents'
);
});

View file

@ -0,0 +1,133 @@
import { describe, it } from 'node:test';
import assert from 'node:assert';
/**
* TDD tests for SocialCard liveness avatar rendering.
*
* SocialCard should accept a `livenessMap` prop (Record<string, string>).
* When `data.assignee` is set and exists as a key in `livenessMap`, the card
* should render an AgentAvatar for that assignee using the mapped AgentStatus.
*
* Liveness AgentStatus mapping:
* 'active' 'active'
* 'stale' 'stale'
* 'idle' 'idle'
* 'evicted' 'dead'
*/
describe('SocialCard liveness prop contract', () => {
it('SocialCard exports a function component', async () => {
const mod = await import('../../../src/components/social/social-card');
assert.ok(mod.SocialCard, 'SocialCard should be exported');
assert.equal(typeof mod.SocialCard, 'function', 'SocialCard should be a function');
});
it('SocialCard accepts a livenessMap prop without throwing', async () => {
await import('../../../src/components/social/social-card');
// Calling a React component as a plain function should not throw when
// given valid props including livenessMap.
assert.doesNotThrow(() => {
const mockData = {
id: 'task-1',
title: 'Test Task',
status: 'in_progress' as const,
blocks: [],
unblocks: [],
agents: [],
lastActivity: new Date(),
priority: 'P1' as const,
assignee: 'agent-42',
};
// Just check the component function accepts the prop shape; we do not
// need to render it via DOM in this test environment.
const props = {
data: mockData,
livenessMap: { 'agent-42': 'active' },
};
assert.ok(props.livenessMap, 'livenessMap should be truthy');
});
});
});
describe('SocialCard liveness → AgentStatus mapping', () => {
it('mapLiveness converts active → active', async () => {
const mod = await import('../../../src/components/social/social-card');
// The mapLiveness helper is exposed for testing via named export.
// If it doesn't exist yet this test will fail (TDD red phase).
assert.ok(
typeof (mod as any).mapLiveness === 'function',
'social-card should export a mapLiveness helper',
);
assert.equal((mod as any).mapLiveness('active'), 'active');
});
it('mapLiveness converts stale → stale', async () => {
const mod = await import('../../../src/components/social/social-card');
assert.equal((mod as any).mapLiveness('stale'), 'stale');
});
it('mapLiveness converts idle → idle', async () => {
const mod = await import('../../../src/components/social/social-card');
assert.equal((mod as any).mapLiveness('idle'), 'idle');
});
it('mapLiveness converts evicted → dead', async () => {
const mod = await import('../../../src/components/social/social-card');
assert.equal((mod as any).mapLiveness('evicted'), 'dead');
});
it('mapLiveness returns idle for unknown liveness strings', async () => {
const mod = await import('../../../src/components/social/social-card');
assert.equal((mod as any).mapLiveness('unknown-value'), 'idle');
});
});
describe('SocialCard SocialCardData assignee field', () => {
it('SocialCard data type supports assignee field', async () => {
// Verify social-cards.ts exports a type that includes assignee.
// We do this by inspecting the buildSocialCards output with a mock bead.
const { buildSocialCards } = await import('../../../src/lib/social-cards');
const mockBead = {
id: 'task-99',
title: 'Assignee Test',
description: null,
status: 'in_progress' as const,
priority: 1,
issue_type: 'task' as const,
assignee: 'bot-7',
templateId: null,
owner: null,
labels: [],
dependencies: [],
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
closed_at: null,
close_reason: null,
closed_by_session: null,
created_by: null,
due_at: null,
estimated_minutes: null,
external_ref: null,
metadata: {},
};
const cards = buildSocialCards([mockBead]);
assert.equal(cards.length, 1, 'should produce one card');
// agents array should contain the assignee
assert.ok(
cards[0].agents.some((a) => a.name === 'bot-7'),
'card.agents should include the assignee name',
);
});
});
describe('SocialPage passes livenessMap to SocialCard', () => {
it('SocialPage component accepts livenessMap prop', async () => {
const mod = await import('../../../src/components/social/social-page');
assert.ok(mod.SocialPage, 'SocialPage should be exported');
assert.equal(typeof mod.SocialPage, 'function', 'SocialPage should be a function');
// The livenessMap prop is part of the interface; TypeScript verifies this
// at build time. Here we just confirm the module loads cleanly.
});
});