refactor: simplify session ID handling and improve Taskfile options

- Include hostname in workflow ID for better audit log organization
- Extract sanitizeHostname utility to audit/utils.ts for reuse
- Remove unused generateSessionLogPath and buildLogFilePath functions
- Simplify Taskfile with CONFIG/OUTPUT/CLEAN named parameters
This commit is contained in:
ajmallesh
2026-01-12 17:18:28 -08:00
parent b84c1d3bb0
commit 69f2d8ffe7
5 changed files with 34 additions and 42 deletions

View File

@@ -24,11 +24,18 @@ tasks:
echo " task stop Stop all containers"
echo " task help Show this help message"
echo ""
echo "Options for 'start':"
echo " CONFIG=<path> Configuration file (YAML)"
echo " OUTPUT=<path> Output directory for reports"
echo ""
echo "Options for 'stop':"
echo " CLEAN=true Remove all data including volumes"
echo ""
echo "Examples:"
echo " task start URL=https://example.com REPO=/path/to/repo"
echo " task start URL=https://example.com REPO=/path/to/repo -- --pipeline-testing"
echo " task start URL=https://example.com REPO=/path/to/repo -- --config ./config.yaml"
echo " task start URL=https://example.com REPO=/path/to/repo CONFIG=./config.yaml"
echo " task query ID=shannon-1234567890"
echo " task stop CLEAN=true"
echo ""
echo "Monitor workflows at http://localhost:8233"
@@ -52,8 +59,12 @@ tasks:
sleep 2
done
- |
ARGS=""
{{if .CONFIG}}ARGS="$ARGS --config {{.CONFIG}}"{{end}}
{{if .OUTPUT}}ARGS="$ARGS --output {{.OUTPUT}}"{{end}}
{{if eq .PIPELINE_TESTING "true"}}ARGS="$ARGS --pipeline-testing"{{end}}
docker compose -f {{.COMPOSE_FILE}} exec -T worker \
node dist/temporal/client.js "{{.URL}}" "/target-repo" {{.CLI_ARGS}}
node dist/temporal/client.js "{{.URL}}" "/target-repo" $ARGS {{.CLI_ARGS}}
logs:
desc: View real-time worker logs
@@ -76,8 +87,8 @@ tasks:
silent: true
cmds:
- |
if [ "{{.CLI_ARGS}}" = "--clean" ]; then
docker compose -f {{.COMPOSE_FILE}} down -v
else
docker compose -f {{.COMPOSE_FILE}} down
fi
{{if eq .CLEAN "true"}}
docker compose -f {{.COMPOSE_FILE}} down -v
{{else}}
docker compose -f {{.COMPOSE_FILE}} down
{{end}}

View File

@@ -15,7 +15,6 @@ import { timingResults, Timer } from '../utils/metrics.js';
import { formatTimestamp } from '../utils/formatting.js';
import { createGitCheckpoint, commitGitSuccess, rollbackGitWorkspace, getGitCommitHash } from '../utils/git-manager.js';
import { AGENT_VALIDATORS, MCP_AGENT_MAPPING } from '../constants.js';
import { generateSessionLogPath } from '../session-manager.js';
import { AuditSession } from '../audit/index.js';
import { createShannonHelperServer } from '../../mcp-server/dist/index.js';
import type { SessionMetadata } from '../audit/utils.js';
@@ -39,7 +38,6 @@ export interface ClaudePromptResult {
cost: number;
partialCost?: number;
apiErrorDetected?: boolean;
logFile?: string;
error?: string;
errorType?: string;
prompt?: string;
@@ -215,10 +213,7 @@ export async function runClaudePrompt(
);
const auditLogger = createAuditLogger(auditSession);
const logFilePath = buildLogFilePath(sessionMetadata, execContext.agentKey, attemptNumber);
if (!logFilePath) {
console.log(chalk.blue(` Running Claude Code: ${description}...`));
}
console.log(chalk.blue(` Running Claude Code: ${description}...`));
const mcpServers = buildMcpServers(sourceDir, agentName);
const options = {
@@ -262,7 +257,7 @@ export async function runClaudePrompt(
progress.finish(formatCompletionMessage(execContext, description, turnCount, duration));
const returnData: ClaudePromptResult = {
return {
result,
success: true,
duration,
@@ -271,10 +266,6 @@ export async function runClaudePrompt(
partialCost: totalCost,
apiErrorDetected
};
if (logFilePath) {
returnData.logFile = logFilePath;
}
return returnData;
} catch (error) {
const duration = timer.stop();
@@ -299,18 +290,6 @@ export async function runClaudePrompt(
}
}
function buildLogFilePath(
sessionMetadata: SessionMetadata | null,
agentKey: string,
attemptNumber: number
): string | null {
if (!sessionMetadata || !sessionMetadata.webUrl || !sessionMetadata.id) {
return null;
}
const timestamp = formatTimestamp().replace(/T/, '_').replace(/[:.]/g, '-').slice(0, 19);
const logDir = generateSessionLogPath(sessionMetadata.webUrl, sessionMetadata.id);
return path.join(logDir, `${timestamp}_${agentKey}_attempt-${attemptNumber}.log`);
}
interface MessageLoopResult {
turnCount: number;

View File

@@ -31,12 +31,18 @@ export interface SessionMetadata {
}
/**
* Generate standardized session identifier: {hostname}_{sessionId}
* Extract and sanitize hostname from URL for use in identifiers
*/
export function sanitizeHostname(url: string): string {
return new URL(url).hostname.replace(/[^a-zA-Z0-9-]/g, '-');
}
/**
* Generate standardized session identifier from workflow ID
* Workflow IDs already contain hostname, so we use them directly
*/
export function generateSessionIdentifier(sessionMetadata: SessionMetadata): string {
const { id, webUrl } = sessionMetadata;
const hostname = new URL(webUrl).hostname.replace(/[^a-zA-Z0-9-]/g, '-');
return `${hostname}_${id}`;
return sessionMetadata.id;
}
/**

View File

@@ -126,10 +126,4 @@ export const AGENT_PHASE_MAP: Readonly<Record<AgentName, PhaseName>> = Object.fr
'report': 'reporting',
});
// Generate a session-based log folder path (used by claude-executor.ts)
export const generateSessionLogPath = (webUrl: string, sessionId: string): string => {
const hostname = new URL(webUrl).hostname.replace(/[^a-zA-Z0-9-]/g, '-');
const sessionFolderName = `${hostname}_${sessionId}`;
return path.join(process.cwd(), 'agent-logs', sessionFolderName);
};

View File

@@ -30,6 +30,7 @@ import { Connection, Client } from '@temporalio/client';
import dotenv from 'dotenv';
import chalk from 'chalk';
import { displaySplashScreen } from '../splash-screen.js';
import { sanitizeHostname } from '../audit/utils.js';
// Import types only - these don't pull in workflow runtime code
import type { PipelineInput, PipelineState, PipelineProgress } from './shared.js';
@@ -126,7 +127,8 @@ async function startPipeline(): Promise<void> {
const client = new Client({ connection });
try {
const workflowId = customWorkflowId || `shannon-${Date.now()}`;
const hostname = sanitizeHostname(webUrl);
const workflowId = customWorkflowId || `${hostname}_shannon-${Date.now()}`;
const input: PipelineInput = {
webUrl,