mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-10 02:24:35 +08:00
Refactor project analysis phases: remove diagram generation phase, enhance report generation with detailed structure and quality checks, and introduce consolidation agent for cross-module analysis. Update CLI commands to support final output options and improve history management with copy functionality.
This commit is contained in:
@@ -195,6 +195,7 @@ export function run(argv: string[]): void {
|
||||
.option('--output-type <type>', 'Output type: stdout, stderr, both', 'both')
|
||||
.option('--turn <n>', 'Turn number for cache (default: latest)')
|
||||
.option('--raw', 'Raw output only (no formatting)')
|
||||
.option('--final', 'Output final result only with usage hint')
|
||||
.action((subcommand, args, options) => cliCommand(subcommand, args, options));
|
||||
|
||||
// Memory command
|
||||
|
||||
@@ -111,6 +111,7 @@ interface OutputViewOptions {
|
||||
outputType?: 'stdout' | 'stderr' | 'both';
|
||||
turn?: string;
|
||||
raw?: boolean;
|
||||
final?: boolean; // Only output final result with usage hint
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -328,6 +329,21 @@ async function outputAction(conversationId: string | undefined, options: OutputV
|
||||
return;
|
||||
}
|
||||
|
||||
if (options.final) {
|
||||
// Final result only with usage hint
|
||||
if (result.stdout) {
|
||||
console.log(result.stdout.content);
|
||||
}
|
||||
console.log();
|
||||
console.log(chalk.gray('─'.repeat(60)));
|
||||
console.log(chalk.dim(`Usage: ccw cli output ${conversationId} [options]`));
|
||||
console.log(chalk.dim(' --raw Raw output (no hint)'));
|
||||
console.log(chalk.dim(' --offset <n> Start from byte offset'));
|
||||
console.log(chalk.dim(' --limit <n> Limit output bytes'));
|
||||
console.log(chalk.dim(` --resume ccw cli -p "..." --resume ${conversationId}`));
|
||||
return;
|
||||
}
|
||||
|
||||
// Formatted output
|
||||
console.log(chalk.bold.cyan('Execution Output\n'));
|
||||
console.log(` ${chalk.gray('ID:')} ${result.conversationId}`);
|
||||
@@ -764,7 +780,8 @@ async function historyAction(options: HistoryOptions): Promise<void> {
|
||||
|
||||
console.log(chalk.bold.cyan('\n CLI Execution History\n'));
|
||||
|
||||
const history = await getExecutionHistoryAsync(process.cwd(), { limit: parseInt(limit, 10), tool, status });
|
||||
// Use recursive: true to aggregate history from parent and child projects (matches Dashboard behavior)
|
||||
const history = await getExecutionHistoryAsync(process.cwd(), { limit: parseInt(limit, 10), tool, status, recursive: true });
|
||||
|
||||
if (history.executions.length === 0) {
|
||||
console.log(chalk.gray(' No executions found.\n'));
|
||||
@@ -953,6 +970,12 @@ export async function cliCommand(
|
||||
console.log(chalk.gray(' full: inject all cached content (default for codex)'));
|
||||
console.log(chalk.gray(' progressive: inject first 64KB with MCP continuation hint'));
|
||||
console.log();
|
||||
console.log(' Output options (ccw cli output <id>):');
|
||||
console.log(chalk.gray(' --final Final result only with usage hint'));
|
||||
console.log(chalk.gray(' --raw Raw output only (no formatting, for piping)'));
|
||||
console.log(chalk.gray(' --offset <n> Start from byte offset'));
|
||||
console.log(chalk.gray(' --limit <n> Limit output bytes'));
|
||||
console.log();
|
||||
console.log(' Examples:');
|
||||
console.log(chalk.gray(' ccw cli -p "Analyze auth module" --tool gemini'));
|
||||
console.log(chalk.gray(' ccw cli -f prompt.txt --tool codex --mode write'));
|
||||
@@ -960,6 +983,7 @@ export async function cliCommand(
|
||||
console.log(chalk.gray(' ccw cli --resume --tool gemini'));
|
||||
console.log(chalk.gray(' ccw cli -p "..." --cache "@src/**/*.ts" --tool codex'));
|
||||
console.log(chalk.gray(' ccw cli -p "..." --cache "@src/**/*" --inject-mode progressive --tool gemini'));
|
||||
console.log(chalk.gray(' ccw cli output <id> --final # View result with usage hint'));
|
||||
console.log();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,9 @@ async function loadCliHistory(options = {}) {
|
||||
const { limit = cliHistoryLimit, tool = cliHistoryFilter, status = null } = options;
|
||||
|
||||
// Use history-native endpoint to get native session info
|
||||
let url = `/api/cli/history-native?path=${encodeURIComponent(projectPath)}&limit=${limit}`;
|
||||
// Use recursiveQueryEnabled setting (from cli-status.js) to control recursive query
|
||||
const recursive = typeof recursiveQueryEnabled !== 'undefined' ? recursiveQueryEnabled : true;
|
||||
let url = `/api/cli/history-native?path=${encodeURIComponent(projectPath)}&limit=${limit}&recursive=${recursive}`;
|
||||
if (tool) url += `&tool=${tool}`;
|
||||
if (status) url += `&status=${status}`;
|
||||
if (cliHistorySearch) url += `&search=${encodeURIComponent(cliHistorySearch)}`;
|
||||
@@ -36,9 +38,12 @@ async function loadCliHistory(options = {}) {
|
||||
async function loadNativeSessionContent(executionId, sourceDir) {
|
||||
try {
|
||||
// If sourceDir provided, use it to build the correct path
|
||||
const basePath = sourceDir && sourceDir !== '.'
|
||||
? projectPath + '/' + sourceDir
|
||||
: projectPath;
|
||||
// Check if sourceDir is absolute path (contains : or starts with /)
|
||||
let basePath = projectPath;
|
||||
if (sourceDir && sourceDir !== '.') {
|
||||
const isAbsolute = sourceDir.includes(':') || sourceDir.startsWith('/');
|
||||
basePath = isAbsolute ? sourceDir : projectPath + '/' + sourceDir;
|
||||
}
|
||||
const url = `/api/cli/native-session?path=${encodeURIComponent(basePath)}&id=${encodeURIComponent(executionId)}`;
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) return null;
|
||||
@@ -65,9 +70,12 @@ async function loadEnrichedConversation(executionId) {
|
||||
async function loadExecutionDetail(executionId, sourceDir) {
|
||||
try {
|
||||
// If sourceDir provided, use it to build the correct path
|
||||
const basePath = sourceDir && sourceDir !== '.'
|
||||
? projectPath + '/' + sourceDir
|
||||
: projectPath;
|
||||
// Check if sourceDir is absolute path (contains : or starts with /)
|
||||
let basePath = projectPath;
|
||||
if (sourceDir && sourceDir !== '.') {
|
||||
const isAbsolute = sourceDir.includes(':') || sourceDir.startsWith('/');
|
||||
basePath = isAbsolute ? sourceDir : projectPath + '/' + sourceDir;
|
||||
}
|
||||
const url = `/api/cli/execution?path=${encodeURIComponent(basePath)}&id=${encodeURIComponent(executionId)}`;
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) throw new Error('Execution not found');
|
||||
@@ -155,11 +163,14 @@ function renderCliHistory() {
|
||||
<div class="cli-history-meta">
|
||||
<span><i data-lucide="clock" class="w-3 h-3"></i> ${timeAgo}</span>
|
||||
<span><i data-lucide="timer" class="w-3 h-3"></i> ${duration}</span>
|
||||
<span><i data-lucide="hash" class="w-3 h-3"></i> ${exec.id.split('-')[0]}</span>
|
||||
<span title="${exec.id}"><i data-lucide="hash" class="w-3 h-3"></i> ${exec.id.substring(0, 13)}...${exec.id.split('-').pop()}</span>
|
||||
${turnBadge}
|
||||
</div>
|
||||
</div>
|
||||
<div class="cli-history-actions">
|
||||
<button class="btn-icon" onclick="event.stopPropagation(); copyCliExecutionId('${exec.id}')" title="Copy ID">
|
||||
<i data-lucide="copy" class="w-3.5 h-3.5"></i>
|
||||
</button>
|
||||
${hasNative ? `
|
||||
<button class="btn-icon" onclick="event.stopPropagation(); showNativeSessionDetail('${exec.id}', '${sourceDirEscaped}')" title="View Native Session">
|
||||
<i data-lucide="file-json" class="w-3.5 h-3.5"></i>
|
||||
@@ -431,9 +442,12 @@ function confirmDeleteExecution(executionId, sourceDir) {
|
||||
async function deleteExecution(executionId, sourceDir) {
|
||||
try {
|
||||
// Build correct path - use sourceDir if provided for recursive items
|
||||
const basePath = sourceDir && sourceDir !== '.'
|
||||
? projectPath + '/' + sourceDir
|
||||
: projectPath;
|
||||
// Check if sourceDir is absolute path (contains : or starts with /)
|
||||
let basePath = projectPath;
|
||||
if (sourceDir && sourceDir !== '.') {
|
||||
const isAbsolute = sourceDir.includes(':') || sourceDir.startsWith('/');
|
||||
basePath = isAbsolute ? sourceDir : projectPath + '/' + sourceDir;
|
||||
}
|
||||
|
||||
const response = await fetch(`/api/cli/execution?path=${encodeURIComponent(basePath)}&id=${encodeURIComponent(executionId)}`, {
|
||||
method: 'DELETE'
|
||||
@@ -461,6 +475,18 @@ async function deleteExecution(executionId, sourceDir) {
|
||||
}
|
||||
|
||||
// ========== Copy Functions ==========
|
||||
async function copyCliExecutionId(executionId) {
|
||||
if (navigator.clipboard) {
|
||||
try {
|
||||
await navigator.clipboard.writeText(executionId);
|
||||
showRefreshToast('ID copied: ' + executionId, 'success');
|
||||
} catch (err) {
|
||||
console.error('Failed to copy ID:', err);
|
||||
showRefreshToast('Failed to copy ID', 'error');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function copyExecutionPrompt(executionId) {
|
||||
const detail = await loadExecutionDetail(executionId);
|
||||
if (!detail) {
|
||||
|
||||
@@ -69,8 +69,10 @@ async function renderCliHistoryView() {
|
||||
'</div>'
|
||||
: '';
|
||||
|
||||
// Normalize sourceDir: convert backslashes to forward slashes for safe onclick handling
|
||||
var normalizedSourceDir = (exec.sourceDir || '').replace(/\\/g, '/');
|
||||
historyHtml += '<div class="history-item' + (isSelected ? ' history-item-selected' : '') + '" ' +
|
||||
'onclick="' + (isMultiSelectMode ? 'toggleExecutionSelection(\'' + exec.id + '\')' : 'showExecutionDetail(\'' + exec.id + '\', \'' + (exec.sourceDir || '').replace(/\'/g, "\\'") + '\')') + '">' +
|
||||
'onclick="' + (isMultiSelectMode ? 'toggleExecutionSelection(\'' + exec.id + '\')' : 'showExecutionDetail(\'' + exec.id + '\', \'' + normalizedSourceDir.replace(/'/g, "\\'") + '\')') + '">' +
|
||||
checkboxHtml +
|
||||
'<div class="history-item-main">' +
|
||||
'<div class="history-item-header">' +
|
||||
@@ -182,6 +184,16 @@ async function renderCliHistoryView() {
|
||||
}
|
||||
|
||||
// ========== Actions ==========
|
||||
async function copyExecutionId(executionId) {
|
||||
try {
|
||||
await navigator.clipboard.writeText(executionId);
|
||||
showRefreshToast('ID copied: ' + executionId, 'success');
|
||||
} catch (err) {
|
||||
console.error('Failed to copy ID:', err);
|
||||
showRefreshToast('Failed to copy ID', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
async function filterCliHistoryView(tool) {
|
||||
cliHistoryFilter = tool || null;
|
||||
await loadCliHistory();
|
||||
|
||||
Reference in New Issue
Block a user