diff --git a/src/audit/utils.ts b/src/audit/utils.ts index 5f70bf5..b518c93 100644 --- a/src/audit/utils.ts +++ b/src/audit/utils.ts @@ -187,14 +187,49 @@ export async function fileExists(filePath: string): Promise { /** * Initialize audit directory structure for a session - * Creates: audit-logs/{sessionId}/, agents/, prompts/ + * Creates: audit-logs/{sessionId}/, agents/, prompts/, deliverables/ */ export async function initializeAuditStructure(sessionMetadata: SessionMetadata): Promise { const auditPath = generateAuditPath(sessionMetadata); const agentsPath = path.join(auditPath, 'agents'); const promptsPath = path.join(auditPath, 'prompts'); + const deliverablesPath = path.join(auditPath, 'deliverables'); await ensureDirectory(auditPath); await ensureDirectory(agentsPath); await ensureDirectory(promptsPath); + await ensureDirectory(deliverablesPath); +} + +/** + * Copy deliverable files from repo to audit-logs for self-contained audit trail. + * No-ops if source directory doesn't exist. Idempotent and parallel-safe. + */ +export async function copyDeliverablesToAudit( + sessionMetadata: SessionMetadata, + repoPath: string +): Promise { + const sourceDir = path.join(repoPath, 'deliverables'); + const destDir = path.join(generateAuditPath(sessionMetadata), 'deliverables'); + + let entries: string[]; + try { + entries = await fs.readdir(sourceDir); + } catch { + // Source directory doesn't exist yet — nothing to copy + return; + } + + await ensureDirectory(destDir); + + for (const entry of entries) { + const sourcePath = path.join(sourceDir, entry); + const destPath = path.join(destDir, entry); + + // Only copy files, skip subdirectories + const stat = await fs.stat(sourcePath); + if (stat.isFile()) { + await fs.copyFile(sourcePath, destPath); + } + } } diff --git a/src/temporal/activities.ts b/src/temporal/activities.ts index 90572b0..a351a94 100644 --- a/src/temporal/activities.ts +++ b/src/temporal/activities.ts @@ -74,7 +74,7 @@ import type { WorkflowSummary } from '../audit/workflow-logger.js'; import type { AgentName } from '../types/agents.js'; import type { AgentMetrics } from './shared.js'; import type { DistributedConfig } from '../types/config.js'; -import type { SessionMetadata } from '../audit/utils.js'; +import { copyDeliverablesToAudit, type SessionMetadata } from '../audit/utils.js'; const HEARTBEAT_INTERVAL_MS = 2000; // Must be < heartbeatTimeout (10min production, 5min testing) @@ -251,6 +251,13 @@ async function runAgentActivity( }); await commitGitSuccess(repoPath, agentName); + // 9.5. Copy deliverables to audit-logs (non-fatal) + try { + await copyDeliverablesToAudit(sessionMetadata, repoPath); + } catch (copyErr) { + console.error(`Failed to copy deliverables to audit-logs for ${agentName}:`, copyErr); + } + // 10. Return metrics return { durationMs: Date.now() - startTime,