mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-10 02:24:35 +08:00
feat: Enhance CLI output handling with structured Intermediate Representation (IR)
- Introduced `CliOutputUnit` and `IOutputParser` interfaces for unified output processing. - Implemented `PlainTextParser` and `JsonLinesParser` for parsing raw CLI output into structured units. - Updated `executeCliTool` to utilize output parsers and handle structured output. - Added `flattenOutputUnits` utility for extracting clean output from structured data. - Enhanced `ConversationTurn` and `ExecutionRecord` interfaces to include structured output. - Created comprehensive documentation for CLI Output Converter usage and integration. - Improved error handling and type mapping for various output formats.
This commit is contained in:
@@ -118,8 +118,9 @@ export async function csrfValidation(ctx: CsrfMiddlewareContext): Promise<boolea
|
||||
const method = (req.method || 'GET').toUpperCase();
|
||||
if (!['POST', 'PUT', 'PATCH', 'DELETE'].includes(method)) return true;
|
||||
|
||||
// Always allow token acquisition routes.
|
||||
// Always allow token acquisition routes and webhook endpoints.
|
||||
if (pathname === '/api/auth/token') return true;
|
||||
if (pathname === '/api/hook') return true;
|
||||
|
||||
// Requests authenticated via Authorization header do not require CSRF protection.
|
||||
const authorization = getHeaderValue(req.headers.authorization);
|
||||
|
||||
@@ -627,7 +627,18 @@ export async function handleClaudeRoutes(ctx: RouteContext): Promise<boolean> {
|
||||
stream: false,
|
||||
category: 'internal',
|
||||
id: syncId
|
||||
}, onOutput);
|
||||
}, (unit) => {
|
||||
// CliOutputUnit handler: convert to string content for broadcast
|
||||
const content = typeof unit.content === 'string' ? unit.content : JSON.stringify(unit.content);
|
||||
broadcastToClients({
|
||||
type: 'CLI_OUTPUT',
|
||||
payload: {
|
||||
executionId: syncId,
|
||||
chunkType: unit.type,
|
||||
data: content
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Broadcast CLI_EXECUTION_COMPLETED event
|
||||
broadcastToClients({
|
||||
|
||||
@@ -195,7 +195,7 @@ export async function handleCliRoutes(ctx: RouteContext): Promise<boolean> {
|
||||
}
|
||||
|
||||
// API: Get/Update Tool Config
|
||||
const configMatch = pathname.match(/^\/api\/cli\/config\/(gemini|qwen|codex)$/);
|
||||
const configMatch = pathname.match(/^\/api\/cli\/config\/(gemini|qwen|codex|claude|opencode)$/);
|
||||
if (configMatch) {
|
||||
const tool = configMatch[1];
|
||||
|
||||
@@ -216,7 +216,7 @@ export async function handleCliRoutes(ctx: RouteContext): Promise<boolean> {
|
||||
if (req.method === 'PUT') {
|
||||
handlePostRequest(req, res, async (body: unknown) => {
|
||||
try {
|
||||
const updates = body as { enabled?: boolean; primaryModel?: string; secondaryModel?: string };
|
||||
const updates = body as { enabled?: boolean; primaryModel?: string; secondaryModel?: string; tags?: string[] };
|
||||
const updated = updateToolConfig(initialPath, tool, updates);
|
||||
|
||||
// Broadcast config updated event
|
||||
@@ -559,19 +559,22 @@ export async function handleCliRoutes(ctx: RouteContext): Promise<boolean> {
|
||||
category: category || 'user',
|
||||
parentExecutionId,
|
||||
stream: true
|
||||
}, (chunk) => {
|
||||
// Append chunk to active execution buffer
|
||||
}, (unit) => {
|
||||
// CliOutputUnit handler: convert to string content
|
||||
const content = typeof unit.content === 'string' ? unit.content : JSON.stringify(unit.content);
|
||||
|
||||
// Append to active execution buffer
|
||||
const activeExec = activeExecutions.get(executionId);
|
||||
if (activeExec) {
|
||||
activeExec.output += chunk.data || '';
|
||||
activeExec.output += content || '';
|
||||
}
|
||||
|
||||
broadcastToClients({
|
||||
type: 'CLI_OUTPUT',
|
||||
payload: {
|
||||
executionId,
|
||||
chunkType: chunk.type,
|
||||
data: chunk.data
|
||||
chunkType: unit.type,
|
||||
data: content
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1007,7 +1007,18 @@ RULES: Be concise. Focus on practical understanding. Include function signatures
|
||||
stream: false,
|
||||
category: 'internal',
|
||||
id: syncId
|
||||
}, onOutput);
|
||||
}, (unit) => {
|
||||
// CliOutputUnit handler: convert to string content for broadcast
|
||||
const content = typeof unit.content === 'string' ? unit.content : JSON.stringify(unit.content);
|
||||
broadcastToClients({
|
||||
type: 'CLI_OUTPUT',
|
||||
payload: {
|
||||
executionId: syncId,
|
||||
chunkType: unit.type,
|
||||
data: content
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Broadcast CLI_EXECUTION_COMPLETED event
|
||||
broadcastToClients({
|
||||
|
||||
@@ -661,13 +661,15 @@ FILE NAME: ${fileName}`;
|
||||
|
||||
// Create onOutput callback for real-time streaming
|
||||
const onOutput = broadcastToClients
|
||||
? (chunk: { type: string; data: string }) => {
|
||||
? (unit: import('../../tools/cli-output-converter.js').CliOutputUnit) => {
|
||||
// CliOutputUnit handler: convert to string content for broadcast
|
||||
const content = typeof unit.content === 'string' ? unit.content : JSON.stringify(unit.content);
|
||||
broadcastToClients({
|
||||
type: 'CLI_OUTPUT',
|
||||
payload: {
|
||||
executionId,
|
||||
chunkType: chunk.type,
|
||||
data: chunk.data
|
||||
chunkType: unit.type,
|
||||
data: content
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -746,13 +748,15 @@ FILE NAME: ${fileName}`;
|
||||
|
||||
// Create onOutput callback for review step
|
||||
const reviewOnOutput = broadcastToClients
|
||||
? (chunk: { type: string; data: string }) => {
|
||||
? (unit: import('../../tools/cli-output-converter.js').CliOutputUnit) => {
|
||||
// CliOutputUnit handler: convert to string content for broadcast
|
||||
const content = typeof unit.content === 'string' ? unit.content : JSON.stringify(unit.content);
|
||||
broadcastToClients({
|
||||
type: 'CLI_OUTPUT',
|
||||
payload: {
|
||||
executionId: reviewExecutionId,
|
||||
chunkType: chunk.type,
|
||||
data: chunk.data
|
||||
chunkType: unit.type,
|
||||
data: content
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -579,13 +579,15 @@ Create a new Claude Code skill with the following specifications:
|
||||
|
||||
// Create onOutput callback for real-time streaming
|
||||
const onOutput = broadcastToClients
|
||||
? (chunk: { type: string; data: string }) => {
|
||||
? (unit: import('../../tools/cli-output-converter.js').CliOutputUnit) => {
|
||||
// CliOutputUnit handler: convert to string content for broadcast
|
||||
const content = typeof unit.content === 'string' ? unit.content : JSON.stringify(unit.content);
|
||||
broadcastToClients({
|
||||
type: 'CLI_OUTPUT',
|
||||
payload: {
|
||||
executionId,
|
||||
chunkType: chunk.type,
|
||||
data: chunk.data
|
||||
chunkType: unit.type,
|
||||
data: content
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -357,7 +357,7 @@ export async function startServer(options: ServerOptions = {}): Promise<http.Ser
|
||||
const tokenManager = getTokenManager();
|
||||
const secretKey = tokenManager.getSecretKey();
|
||||
tokenManager.getOrCreateAuthToken();
|
||||
const unauthenticatedPaths = new Set<string>(['/api/auth/token', '/api/csrf-token']);
|
||||
const unauthenticatedPaths = new Set<string>(['/api/auth/token', '/api/csrf-token', '/api/hook']);
|
||||
|
||||
const server = http.createServer(async (req, res) => {
|
||||
const url = new URL(req.url ?? '/', `http://localhost:${serverPort}`);
|
||||
|
||||
Reference in New Issue
Block a user