chore: batch update - cleanup ghost commands, ccw-help index refresh, CLI session/orchestrator enhancements, skill minor fixes

- Add cleanup-ghost-commands.mjs script
- Refresh ccw-help index files (remove stale entries)
- CLI session manager: add instruction assembler and launch registry
- Frontend: orchestrator plan builder, property panel, dashboard toolbar updates
- Flow executor and type updates
- Minor fixes across multiple skills and commands
This commit is contained in:
catlog22
2026-02-17 21:53:51 +08:00
parent 1f53f2de27
commit 357f48a0c3
45 changed files with 751 additions and 1643 deletions

View File

@@ -46,7 +46,6 @@ import {
import { useIssues, useIssueQueue } from '@/hooks/useIssues';
import { useTerminalGridStore, selectTerminalGridFocusedPaneId } from '@/stores/terminalGridStore';
import { useWorkflowStore, selectProjectPath } from '@/stores/workflowStore';
import { sendCliSessionText } from '@/lib/api';
import { CliConfigModal, type CliSessionConfig } from './CliConfigModal';
// ========== Types ==========
@@ -84,14 +83,6 @@ type LaunchMode = 'default' | 'yolo';
const CLI_TOOLS = ['claude', 'gemini', 'qwen', 'codex', 'opencode'] as const;
type CliTool = (typeof CLI_TOOLS)[number];
const LAUNCH_COMMANDS: Record<CliTool, Record<LaunchMode, string>> = {
claude: { default: 'claude', yolo: 'claude --permission-mode bypassPermissions' },
gemini: { default: 'gemini', yolo: 'gemini --approval-mode yolo' },
qwen: { default: 'qwen', yolo: 'qwen --approval-mode yolo' },
codex: { default: 'codex', yolo: 'codex --full-auto' },
opencode: { default: 'opencode', yolo: 'opencode' },
};
// ========== Component ==========
export function DashboardToolbar({ activePanel, onTogglePanel, isFileSidebarOpen, onToggleFileSidebar, isSessionSidebarOpen, onToggleSessionSidebar, isFullscreen, onToggleFullscreen }: DashboardToolbarProps) {
@@ -151,22 +142,12 @@ export function DashboardToolbar({ activePanel, onTogglePanel, isFileSidebarOpen
const targetPaneId = getOrCreateFocusedPane();
if (!targetPaneId) return;
const created = await createSessionAndAssign(targetPaneId, {
await createSessionAndAssign(targetPaneId, {
workingDir: projectPath,
preferredShell: 'bash',
tool: selectedTool,
launchMode,
}, projectPath);
if (created?.session?.sessionKey) {
const command = LAUNCH_COMMANDS[selectedTool]?.[launchMode] ?? selectedTool;
setTimeout(() => {
sendCliSessionText(
created.session.sessionKey,
{ text: command, appendNewline: true },
projectPath
).catch((err) => console.error('[DashboardToolbar] auto-launch failed:', err));
}, 300);
}
} finally {
setIsCreating(false);
}
@@ -190,22 +171,12 @@ export function DashboardToolbar({ activePanel, onTogglePanel, isFileSidebarOpen
preferredShell: config.preferredShell,
tool: config.tool,
model: config.model,
launchMode: config.launchMode,
},
projectPath
);
if (!created?.session?.sessionKey) throw new Error('createSessionAndAssign failed');
const tool = config.tool as CliTool;
const mode = config.launchMode as LaunchMode;
const command = LAUNCH_COMMANDS[tool]?.[mode] ?? tool;
setTimeout(() => {
sendCliSessionText(
created.session.sessionKey,
{ text: command, appendNewline: true },
projectPath
).catch((err) => console.error('[DashboardToolbar] auto-launch failed:', err));
}, 300);
} finally {
setIsCreating(false);
}

View File

@@ -6336,6 +6336,8 @@ export interface CliSession {
createdAt: string;
updatedAt: string;
isPaused: boolean;
/** When set, this session is a native CLI interactive process. */
cliTool?: string;
}
export interface CreateCliSessionInput {
@@ -6346,6 +6348,8 @@ export interface CreateCliSessionInput {
tool?: string;
model?: string;
resumeKey?: string;
/** Launch mode for native CLI sessions (default or yolo). */
launchMode?: 'default' | 'yolo';
}
function withPath(url: string, projectPath?: string): string {
@@ -6397,6 +6401,8 @@ export interface ExecuteInCliSessionInput {
category?: 'user' | 'internal' | 'insight';
resumeKey?: string;
resumeStrategy?: 'nativeResume' | 'promptConcat';
instructionType?: 'prompt' | 'skill' | 'command';
skillName?: string;
}
export async function executeInCliSession(

View File

@@ -159,6 +159,8 @@ export async function dispatch(
category: options.category,
resumeKey: options.resumeKey ?? step.resumeKey,
resumeStrategy: options.resumeStrategy,
instructionType: step.instructionType,
skillName: step.skillName,
};
// Step 3: Execute in the resolved session

View File

@@ -104,13 +104,25 @@ export class OrchestrationPlanBuilder {
if (nodeData.slashCommand) {
executionType = 'slash-command';
} else if (nodeData.tool && nodeData.mode) {
// More sophisticated logic might be needed here to differentiate backend-flow
// For now, if tool/mode are present, assume frontend-cli or backend-flow
// depending on whether it's a direct CLI call or a backend orchestrator call.
// Assuming CLI tools are frontend-cli for now unless specified otherwise.
executionType = 'frontend-cli';
}
// Resolve instructionType and skillName
// Priority: explicit instructionType > slashCommand backward compat > default prompt
let instructionType = nodeData.instructionType;
let skillName = nodeData.skillName;
if (!instructionType) {
if (skillName) {
instructionType = 'skill';
} else if (nodeData.slashCommand) {
// Backward compat: map slashCommand to skill type
instructionType = 'skill';
skillName = nodeData.slashCommand;
} else {
instructionType = 'prompt';
}
}
steps.push({
id: node.id,
name: nodeData.label || `Step ${node.id}`,
@@ -128,6 +140,8 @@ export class OrchestrationPlanBuilder {
errorHandling: undefined,
executionType: executionType,
sourceNodeId: node.id,
instructionType,
skillName,
});
}

View File

@@ -1126,6 +1126,49 @@ function PromptTemplateProperties({ data, onChange }: PromptTemplatePropertiesPr
{/* CLI Session Routing (tmux-like) */}
{!isSlashCommandMode && (
<>
{/* Instruction Type for native CLI sessions */}
<div>
<label className="block text-sm font-medium text-foreground mb-1">
Instruction Type
</label>
<select
value={data.instructionType || 'prompt'}
onChange={(e) => {
const next = e.target.value as 'prompt' | 'skill' | 'command';
const updates: Partial<PromptTemplateNodeData> = { instructionType: next };
if (next !== 'skill') {
updates.skillName = undefined;
}
onChange(updates);
}}
className="w-full h-10 px-3 rounded-md border border-border bg-background text-foreground text-sm"
>
<option value="prompt">Prompt (direct text)</option>
<option value="skill">Skill (CLI-specific prefix)</option>
<option value="command">Command (CLI native)</option>
</select>
</div>
{/* Skill Name - shown when instructionType is 'skill' */}
{(data.instructionType === 'skill') && (
<div>
<label className="block text-sm font-medium text-foreground mb-1">
Skill Name
{data.tool && (
<span className="ml-2 text-xs text-muted-foreground font-normal">
{data.tool === 'claude' ? 'prefix: /' : data.tool === 'codex' ? 'prefix: $' : 'no prefix'}
</span>
)}
</label>
<Input
value={data.skillName || ''}
onChange={(e) => onChange({ skillName: e.target.value || undefined })}
placeholder={data.tool === 'claude' ? 'e.g. review-code' : data.tool === 'codex' ? 'e.g. fix' : 'skill name'}
className="font-mono text-sm"
/>
</div>
)}
<div>
<label className="block text-sm font-medium text-foreground mb-1">
{formatMessage({ id: 'orchestrator.propertyPanel.delivery' })}

View File

@@ -24,7 +24,7 @@ export type ExecutionStatus = 'pending' | 'running' | 'completed' | 'failed';
/**
* Available CLI tools for execution
*/
export type CliTool = 'gemini' | 'qwen' | 'codex' | 'claude';
export type CliTool = 'gemini' | 'qwen' | 'codex' | 'claude' | 'opencode';
/**
* Execution modes for prompt templates
@@ -117,6 +117,20 @@ export interface PromptTemplateNodeData {
*/
contextRefs?: string[];
/**
* Instruction type for CLI session execution.
* - prompt: raw text sent as conversation input
* - skill: CLI-specific skill invocation (Claude: /name, Codex: $name)
* - command: CLI native command
*/
instructionType?: 'prompt' | 'skill' | 'command';
/**
* Skill name for instructionType='skill'.
* The actual prefix (/ or $) is determined by the target CLI tool.
*/
skillName?: string;
/**
* Selected slash command name (e.g., "workflow:plan", "review-code")
* When set, overrides instruction during execution.

View File

@@ -145,6 +145,20 @@ export interface OrchestrationStep {
*/
executionType: ExecutionType;
/**
* Instruction type for native CLI session execution.
* - prompt: raw text conversation input
* - skill: CLI-specific skill invocation (prefix determined by CLI tool)
* - command: CLI native command
*/
instructionType?: 'prompt' | 'skill' | 'command';
/**
* Skill name for instructionType='skill'.
* The actual prefix (/ or $) is assembled by the backend InstructionAssembler.
*/
skillName?: string;
/**
* For flow-based plans, the ID of the source FlowNode.
*/