claude-code-workflow 6.3.30 → 6.3.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/CLAUDE.md +2 -3
- package/.claude/commands/workflow/clean.md +3 -3
- package/.claude/commands/workflow/init.md +25 -12
- package/.claude/commands/workflow/lite-execute.md +2 -2
- package/.claude/commands/workflow/session/complete.md +31 -4
- package/.claude/commands/workflow/session/start.md +1 -1
- package/.claude/commands/workflow/tools/context-gather.md +2 -2
- package/.claude/skills/ccw-help/command.json +10 -1
- package/.claude/workflows/chinese-response.md +1 -1
- package/.claude/workflows/cli-templates/schemas/project-guidelines-schema.json +141 -0
- package/.claude/workflows/cli-templates/schemas/{project-json-schema.json → project-tech-schema.json} +2 -2
- package/.claude/workflows/cli-tools-usage.md +28 -4
- package/ccw/dist/cli.js +1 -1
- package/ccw/dist/cli.js.map +1 -1
- package/ccw/dist/commands/cli.d.ts +0 -1
- package/ccw/dist/commands/cli.d.ts.map +1 -1
- package/ccw/dist/commands/cli.js +4 -4
- package/ccw/dist/commands/cli.js.map +1 -1
- package/ccw/dist/core/data-aggregator.d.ts +13 -2
- package/ccw/dist/core/data-aggregator.d.ts.map +1 -1
- package/ccw/dist/core/data-aggregator.js +10 -16
- package/ccw/dist/core/data-aggregator.js.map +1 -1
- package/ccw/dist/core/routes/help-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/help-routes.js +156 -58
- package/ccw/dist/core/routes/help-routes.js.map +1 -1
- package/ccw/dist/core/routes/issue-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/issue-routes.js +67 -0
- package/ccw/dist/core/routes/issue-routes.js.map +1 -1
- package/ccw/dist/tools/cli-executor-core.d.ts.map +1 -1
- package/ccw/dist/tools/cli-executor-core.js +11 -36
- package/ccw/dist/tools/cli-executor-core.js.map +1 -1
- package/ccw/dist/tools/cli-executor-utils.d.ts.map +1 -1
- package/ccw/dist/tools/cli-executor-utils.js +16 -1
- package/ccw/dist/tools/cli-executor-utils.js.map +1 -1
- package/ccw/src/cli.ts +1 -1
- package/ccw/src/commands/cli.ts +5 -5
- package/ccw/src/core/data-aggregator.ts +25 -19
- package/ccw/src/core/routes/help-routes.ts +172 -60
- package/ccw/src/core/routes/issue-routes.ts +81 -0
- package/ccw/src/templates/dashboard-css/32-issue-manager.css +28 -0
- package/ccw/src/templates/dashboard-js/components/hook-manager.js +120 -0
- package/ccw/src/templates/dashboard-js/i18n.js +20 -0
- package/ccw/src/templates/dashboard-js/views/hook-manager.js +21 -5
- package/ccw/src/templates/dashboard-js/views/issue-manager.js +108 -0
- package/ccw/src/tools/cli-executor-core.ts +13 -38
- package/ccw/src/tools/cli-executor-utils.ts +15 -1
- package/package.json +1 -1
|
@@ -562,6 +562,9 @@ function renderQueueCard(queue, isActive) {
|
|
|
562
562
|
<i data-lucide="git-merge" class="w-3 h-3"></i>
|
|
563
563
|
</button>
|
|
564
564
|
` : ''}
|
|
565
|
+
<button class="btn-sm btn-danger" onclick="confirmDeleteQueue('${safeQueueId}')" title="${t('issues.deleteQueue') || 'Delete queue'}">
|
|
566
|
+
<i data-lucide="trash-2" class="w-3 h-3"></i>
|
|
567
|
+
</button>
|
|
565
568
|
</div>
|
|
566
569
|
</div>
|
|
567
570
|
`;
|
|
@@ -619,6 +622,33 @@ async function deactivateQueue(queueId) {
|
|
|
619
622
|
}
|
|
620
623
|
}
|
|
621
624
|
|
|
625
|
+
function confirmDeleteQueue(queueId) {
|
|
626
|
+
const msg = t('issues.confirmDeleteQueue') || 'Are you sure you want to delete this queue? This action cannot be undone.';
|
|
627
|
+
if (confirm(msg)) {
|
|
628
|
+
deleteQueue(queueId);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
async function deleteQueue(queueId) {
|
|
633
|
+
try {
|
|
634
|
+
const response = await fetch('/api/queue/' + encodeURIComponent(queueId) + '?path=' + encodeURIComponent(projectPath), {
|
|
635
|
+
method: 'DELETE'
|
|
636
|
+
});
|
|
637
|
+
const result = await response.json();
|
|
638
|
+
if (result.success) {
|
|
639
|
+
showNotification(t('issues.queueDeleted') || 'Queue deleted successfully', 'success');
|
|
640
|
+
queueData.expandedQueueId = null;
|
|
641
|
+
await Promise.all([loadQueueData(), loadAllQueues()]);
|
|
642
|
+
renderIssueView();
|
|
643
|
+
} else {
|
|
644
|
+
showNotification(result.error || 'Failed to delete queue', 'error');
|
|
645
|
+
}
|
|
646
|
+
} catch (err) {
|
|
647
|
+
console.error('Failed to delete queue:', err);
|
|
648
|
+
showNotification('Failed to delete queue', 'error');
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
622
652
|
async function renderExpandedQueueView(queueId) {
|
|
623
653
|
const safeQueueId = escapeHtml(queueId || '');
|
|
624
654
|
// Fetch queue detail
|
|
@@ -1405,6 +1435,23 @@ function renderIssueDetailPanel(issue) {
|
|
|
1405
1435
|
`).join('') : '<p class="text-sm text-muted-foreground">' + (t('issues.noTasks') || 'No tasks') + '</p>'}
|
|
1406
1436
|
</div>
|
|
1407
1437
|
</div>
|
|
1438
|
+
|
|
1439
|
+
<!-- Actions -->
|
|
1440
|
+
<div class="detail-section issue-detail-actions">
|
|
1441
|
+
<label class="detail-label">${t('issues.actions') || 'Actions'}</label>
|
|
1442
|
+
<div class="flex gap-2 flex-wrap">
|
|
1443
|
+
${!issue._isArchived ? `
|
|
1444
|
+
<button class="btn-secondary btn-sm" onclick="confirmArchiveIssue('${issue.id}')">
|
|
1445
|
+
<i data-lucide="archive" class="w-4 h-4"></i>
|
|
1446
|
+
${t('issues.archive') || 'Archive'}
|
|
1447
|
+
</button>
|
|
1448
|
+
` : ''}
|
|
1449
|
+
<button class="btn-secondary btn-sm btn-danger" onclick="confirmDeleteIssue('${issue.id}', ${issue._isArchived || false})">
|
|
1450
|
+
<i data-lucide="trash-2" class="w-4 h-4"></i>
|
|
1451
|
+
${t('issues.delete') || 'Delete'}
|
|
1452
|
+
</button>
|
|
1453
|
+
</div>
|
|
1454
|
+
</div>
|
|
1408
1455
|
</div>
|
|
1409
1456
|
`;
|
|
1410
1457
|
|
|
@@ -1419,6 +1466,67 @@ function closeIssueDetail() {
|
|
|
1419
1466
|
issueData.selectedIssue = null;
|
|
1420
1467
|
}
|
|
1421
1468
|
|
|
1469
|
+
// ========== Issue Delete & Archive ==========
|
|
1470
|
+
function confirmDeleteIssue(issueId, isArchived) {
|
|
1471
|
+
const msg = t('issues.confirmDeleteIssue') || 'Are you sure you want to delete this issue? This action cannot be undone.';
|
|
1472
|
+
if (confirm(msg)) {
|
|
1473
|
+
deleteIssue(issueId, isArchived);
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
async function deleteIssue(issueId, isArchived) {
|
|
1478
|
+
try {
|
|
1479
|
+
const response = await fetch('/api/issues/' + encodeURIComponent(issueId) + '?path=' + encodeURIComponent(projectPath), {
|
|
1480
|
+
method: 'DELETE'
|
|
1481
|
+
});
|
|
1482
|
+
const result = await response.json();
|
|
1483
|
+
if (result.success) {
|
|
1484
|
+
showNotification(t('issues.issueDeleted') || 'Issue deleted successfully', 'success');
|
|
1485
|
+
closeIssueDetail();
|
|
1486
|
+
if (isArchived) {
|
|
1487
|
+
issueData.historyIssues = issueData.historyIssues.filter(i => i.id !== issueId);
|
|
1488
|
+
} else {
|
|
1489
|
+
issueData.issues = issueData.issues.filter(i => i.id !== issueId);
|
|
1490
|
+
}
|
|
1491
|
+
renderIssueView();
|
|
1492
|
+
updateIssueBadge();
|
|
1493
|
+
} else {
|
|
1494
|
+
showNotification(result.error || 'Failed to delete issue', 'error');
|
|
1495
|
+
}
|
|
1496
|
+
} catch (err) {
|
|
1497
|
+
console.error('Failed to delete issue:', err);
|
|
1498
|
+
showNotification('Failed to delete issue', 'error');
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
function confirmArchiveIssue(issueId) {
|
|
1503
|
+
const msg = t('issues.confirmArchiveIssue') || 'Archive this issue? It will be moved to history.';
|
|
1504
|
+
if (confirm(msg)) {
|
|
1505
|
+
archiveIssue(issueId);
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
async function archiveIssue(issueId) {
|
|
1510
|
+
try {
|
|
1511
|
+
const response = await fetch('/api/issues/' + encodeURIComponent(issueId) + '/archive?path=' + encodeURIComponent(projectPath), {
|
|
1512
|
+
method: 'POST'
|
|
1513
|
+
});
|
|
1514
|
+
const result = await response.json();
|
|
1515
|
+
if (result.success) {
|
|
1516
|
+
showNotification(t('issues.issueArchived') || 'Issue archived successfully', 'success');
|
|
1517
|
+
closeIssueDetail();
|
|
1518
|
+
await loadIssueData();
|
|
1519
|
+
renderIssueView();
|
|
1520
|
+
updateIssueBadge();
|
|
1521
|
+
} else {
|
|
1522
|
+
showNotification(result.error || 'Failed to archive issue', 'error');
|
|
1523
|
+
}
|
|
1524
|
+
} catch (err) {
|
|
1525
|
+
console.error('Failed to archive issue:', err);
|
|
1526
|
+
showNotification('Failed to archive issue', 'error');
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1422
1530
|
function toggleSolutionExpand(solId) {
|
|
1423
1531
|
const el = document.getElementById('solution-' + solId);
|
|
1424
1532
|
if (el) {
|
|
@@ -160,7 +160,7 @@ interface ClaudeWithSettingsParams {
|
|
|
160
160
|
prompt: string;
|
|
161
161
|
settingsPath: string;
|
|
162
162
|
endpointId: string;
|
|
163
|
-
mode: 'analysis' | 'write' | 'auto';
|
|
163
|
+
mode: 'analysis' | 'write' | 'auto' | 'review';
|
|
164
164
|
workingDir: string;
|
|
165
165
|
cd?: string;
|
|
166
166
|
includeDirs?: string[];
|
|
@@ -351,12 +351,12 @@ type BuiltinCliTool = typeof BUILTIN_CLI_TOOLS[number];
|
|
|
351
351
|
const ParamsSchema = z.object({
|
|
352
352
|
tool: z.string().min(1, 'Tool is required'), // Accept any tool ID (built-in or custom endpoint)
|
|
353
353
|
prompt: z.string().min(1, 'Prompt is required'),
|
|
354
|
-
mode: z.enum(['analysis', 'write', 'auto']).default('analysis'),
|
|
354
|
+
mode: z.enum(['analysis', 'write', 'auto', 'review']).default('analysis'),
|
|
355
355
|
format: z.enum(['plain', 'yaml', 'json']).default('plain'), // Multi-turn prompt concatenation format
|
|
356
356
|
model: z.string().optional(),
|
|
357
357
|
cd: z.string().optional(),
|
|
358
358
|
includeDirs: z.string().optional(),
|
|
359
|
-
|
|
359
|
+
// timeout removed - controlled by external caller (bash timeout)
|
|
360
360
|
resume: z.union([z.boolean(), z.string()]).optional(), // true = last, string = single ID or comma-separated IDs
|
|
361
361
|
id: z.string().optional(), // Custom execution ID (e.g., IMPL-001-step1)
|
|
362
362
|
noNative: z.boolean().optional(), // Force prompt concatenation instead of native resume
|
|
@@ -388,7 +388,7 @@ async function executeCliTool(
|
|
|
388
388
|
throw new Error(`Invalid params: ${parsed.error.message}`);
|
|
389
389
|
}
|
|
390
390
|
|
|
391
|
-
const { tool, prompt, mode, format, model, cd, includeDirs,
|
|
391
|
+
const { tool, prompt, mode, format, model, cd, includeDirs, resume, id: customId, noNative, category, parentExecutionId, outputFormat } = parsed.data;
|
|
392
392
|
|
|
393
393
|
// Validate and determine working directory early (needed for conversation lookup)
|
|
394
394
|
let workingDir: string;
|
|
@@ -862,7 +862,6 @@ async function executeCliTool(
|
|
|
862
862
|
|
|
863
863
|
let stdout = '';
|
|
864
864
|
let stderr = '';
|
|
865
|
-
let timedOut = false;
|
|
866
865
|
|
|
867
866
|
// Handle stdout
|
|
868
867
|
child.stdout!.on('data', (data: Buffer) => {
|
|
@@ -924,18 +923,14 @@ async function executeCliTool(
|
|
|
924
923
|
debugLog('CLOSE', `Process closed`, {
|
|
925
924
|
exitCode: code,
|
|
926
925
|
duration: `${duration}ms`,
|
|
927
|
-
timedOut,
|
|
928
926
|
stdoutLength: stdout.length,
|
|
929
927
|
stderrLength: stderr.length,
|
|
930
928
|
outputUnitsCount: allOutputUnits.length
|
|
931
929
|
});
|
|
932
930
|
|
|
933
931
|
// Determine status - prioritize output content over exit code
|
|
934
|
-
let status: 'success' | 'error'
|
|
935
|
-
if (
|
|
936
|
-
status = 'timeout';
|
|
937
|
-
debugLog('STATUS', `Execution timed out after ${duration}ms`);
|
|
938
|
-
} else if (code !== 0) {
|
|
932
|
+
let status: 'success' | 'error' = 'success';
|
|
933
|
+
if (code !== 0) {
|
|
939
934
|
// Non-zero exit code doesn't always mean failure
|
|
940
935
|
// Check if there's valid output (AI response) - treat as success
|
|
941
936
|
const hasValidOutput = stdout.trim().length > 0;
|
|
@@ -1169,25 +1164,8 @@ async function executeCliTool(
|
|
|
1169
1164
|
reject(new Error(`Failed to spawn ${tool}: ${error.message}\n Command: ${command} ${args.join(' ')}\n Working Dir: ${workingDir}`));
|
|
1170
1165
|
});
|
|
1171
1166
|
|
|
1172
|
-
// Timeout
|
|
1173
|
-
|
|
1174
|
-
if (timeout > 0) {
|
|
1175
|
-
timeoutId = setTimeout(() => {
|
|
1176
|
-
timedOut = true;
|
|
1177
|
-
child.kill('SIGTERM');
|
|
1178
|
-
setTimeout(() => {
|
|
1179
|
-
if (!child.killed) {
|
|
1180
|
-
child.kill('SIGKILL');
|
|
1181
|
-
}
|
|
1182
|
-
}, 5000);
|
|
1183
|
-
}, timeout);
|
|
1184
|
-
}
|
|
1185
|
-
|
|
1186
|
-
child.on('close', () => {
|
|
1187
|
-
if (timeoutId) {
|
|
1188
|
-
clearTimeout(timeoutId);
|
|
1189
|
-
}
|
|
1190
|
-
});
|
|
1167
|
+
// Timeout controlled by external caller (bash timeout)
|
|
1168
|
+
// When parent process terminates, child will be cleaned up via process exit handler
|
|
1191
1169
|
});
|
|
1192
1170
|
}
|
|
1193
1171
|
|
|
@@ -1198,7 +1176,8 @@ export const schema: ToolSchema = {
|
|
|
1198
1176
|
Modes:
|
|
1199
1177
|
- analysis: Read-only operations (default)
|
|
1200
1178
|
- write: File modifications allowed
|
|
1201
|
-
- auto: Full autonomous operations (codex only)
|
|
1179
|
+
- auto: Full autonomous operations (codex only)
|
|
1180
|
+
- review: Code review mode (codex uses 'codex review' subcommand, others accept but no operation change)`,
|
|
1202
1181
|
inputSchema: {
|
|
1203
1182
|
type: 'object',
|
|
1204
1183
|
properties: {
|
|
@@ -1213,8 +1192,8 @@ Modes:
|
|
|
1213
1192
|
},
|
|
1214
1193
|
mode: {
|
|
1215
1194
|
type: 'string',
|
|
1216
|
-
enum: ['analysis', 'write', 'auto'],
|
|
1217
|
-
description: 'Execution mode (default: analysis)',
|
|
1195
|
+
enum: ['analysis', 'write', 'auto', 'review'],
|
|
1196
|
+
description: 'Execution mode (default: analysis). review mode uses codex review subcommand for codex tool.',
|
|
1218
1197
|
default: 'analysis'
|
|
1219
1198
|
},
|
|
1220
1199
|
model: {
|
|
@@ -1228,12 +1207,8 @@ Modes:
|
|
|
1228
1207
|
includeDirs: {
|
|
1229
1208
|
type: 'string',
|
|
1230
1209
|
description: 'Additional directories (comma-separated). Maps to --include-directories for gemini/qwen, --add-dir for codex'
|
|
1231
|
-
},
|
|
1232
|
-
timeout: {
|
|
1233
|
-
type: 'number',
|
|
1234
|
-
description: 'Timeout in milliseconds (default: 0 = disabled, controlled by external caller)',
|
|
1235
|
-
default: 0
|
|
1236
1210
|
}
|
|
1211
|
+
// timeout removed - controlled by external caller (bash timeout)
|
|
1237
1212
|
},
|
|
1238
1213
|
required: ['tool', 'prompt']
|
|
1239
1214
|
}
|
|
@@ -223,7 +223,21 @@ export function buildCommand(params: {
|
|
|
223
223
|
|
|
224
224
|
case 'codex':
|
|
225
225
|
useStdin = true;
|
|
226
|
-
if (
|
|
226
|
+
if (mode === 'review') {
|
|
227
|
+
// codex review mode: non-interactive code review
|
|
228
|
+
// Format: codex review [OPTIONS] [PROMPT]
|
|
229
|
+
args.push('review');
|
|
230
|
+
// Default to --uncommitted if no specific review target in prompt
|
|
231
|
+
args.push('--uncommitted');
|
|
232
|
+
if (model) {
|
|
233
|
+
args.push('-m', model);
|
|
234
|
+
}
|
|
235
|
+
// codex review uses positional prompt argument, not stdin
|
|
236
|
+
useStdin = false;
|
|
237
|
+
if (prompt) {
|
|
238
|
+
args.push(prompt);
|
|
239
|
+
}
|
|
240
|
+
} else if (nativeResume?.enabled) {
|
|
227
241
|
args.push('resume');
|
|
228
242
|
if (nativeResume.isLatest) {
|
|
229
243
|
args.push('--last');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-code-workflow",
|
|
3
|
-
"version": "6.3.
|
|
3
|
+
"version": "6.3.32",
|
|
4
4
|
"description": "JSON-driven multi-agent development framework with intelligent CLI orchestration (Gemini/Qwen/Codex), context-first architecture, and automated workflow execution",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "ccw/src/index.js",
|