release: v0.6.0 — security audit fixes + 7 new features
All checks were successful
PR Check / check (pull_request) Successful in 57s
All checks were successful
PR Check / check (pull_request) Successful in 57s
Audit corrections (security, concurrency, stability): - chat_engine: bound resp.Choices[0] access, release tool slot per-iteration - conversation_multi: synchronous save under existing lock (was racy fire-and-forget) - workflow/engine: short-circuit on failed deps (no more infinite busy-wait); track failed/skipped status - handlers_workflow: rune-aware truncate for plan goal (UTF-8 safe) - server: CORS limited to localhost origins (was wildcard) - handlers_info / terminal: mask API keys and SSH passwords as "***" in GET responses; preserve stored secret if "***" sent on update - terminal: sshpass uses -e + SSHPASS env var (was both -p and -e) - handlers_chat: MaxBytesReader 50 MB on /api/chat - image_cache: 10 MB cap per image - handlers_config: font size <= 72; profile-save unmarshal errors propagated - handlers_info: /lsp/auto-install ProjectDir restricted to user home - Shell.jsx: parenthesized resize-condition (operator precedence) - orchestrator_test: CleanAIResponse capitalization (fixes failing vet) New features: - platform: detect OS name (Debian, Ubuntu, Windows 11, macOS X.Y) and inject in Studio system prompt next to the date - agents: default timeout 30 min for crush_run/claude_run (cap also 30 min) - agents: new cwd, wsl_distro, wsl_user params; on Windows hosts launch via "wsl -d <distro> -u <user> --cd <cwd> --" - agents: new claude_run tool (mirror of crush_run for Claude Code CLI) - terminal: list installed WSL distros individually in new-tab menu (Windows only) - studio: system prompt rewritten around BMAD-METHOD personas + mandatory delegation template - studio: "Réflexion avancée" toggle — inactive provider produces a preliminary report injected as [RAPPORT PRÉALABLE] context for the active provider - studio: "Historique compressé" toggle — collapses past tool calls to last action only, with "Tout afficher" expansion
This commit is contained in:
@@ -124,13 +124,16 @@ func NewTerminalTool() (*ToolDefinition, error) {
|
||||
}
|
||||
|
||||
type CrushRunParams struct {
|
||||
Task string `json:"task" description:"The task description for Crush to execute"`
|
||||
Timeout int `json:"timeout,omitempty" description:"Maximum execution time in seconds (default 600, max 900)"`
|
||||
Task string `json:"task" description:"The task description for Crush to execute"`
|
||||
Timeout int `json:"timeout,omitempty" description:"Maximum execution time in seconds (default 1800, max 1800)"`
|
||||
Cwd string `json:"cwd,omitempty" description:"Working directory in which to launch the agent (absolute path; falls back to user home)"`
|
||||
WSLDistro string `json:"wsl_distro,omitempty" description:"On Windows host: WSL distribution to launch the agent in (e.g. 'Ubuntu')"`
|
||||
WSLUser string `json:"wsl_user,omitempty" description:"On Windows host: WSL user to run the agent as"`
|
||||
}
|
||||
|
||||
func NewCrushRunTool() (*ToolDefinition, error) {
|
||||
return NewTool("crush_run",
|
||||
"Delegate a complex coding task to the Crush AI agent. Crush has access to file editing, code search, bash execution, and other development tools. Use this for multi-step coding tasks like refactoring, debugging, implementing features, or code review. Returns the agent's final output.",
|
||||
"Delegate a complex coding task to the Crush AI agent. Crush has access to file editing, code search, bash execution, and other development tools. Use this for multi-step coding tasks like refactoring, debugging, implementing features, or code review. Optionally pass cwd to run in a specific directory, or wsl_distro/wsl_user to launch inside a WSL distribution under a specific user (Windows hosts only). Returns the agent's final output.",
|
||||
func(ctx context.Context, p CrushRunParams) (ToolResponse, error) {
|
||||
if p.Task == "" {
|
||||
return TextErrorResponse("task is required"), nil
|
||||
@@ -138,15 +141,18 @@ func NewCrushRunTool() (*ToolDefinition, error) {
|
||||
|
||||
timeout := time.Duration(p.Timeout) * time.Second
|
||||
if timeout == 0 {
|
||||
timeout = 600 * time.Second
|
||||
timeout = 1800 * time.Second
|
||||
}
|
||||
if timeout > 900*time.Second {
|
||||
timeout = 900 * time.Second
|
||||
if timeout > 1800*time.Second {
|
||||
timeout = 1800 * time.Second
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(ctx, timeout)
|
||||
defer cancel()
|
||||
|
||||
cmd := exec.CommandContext(ctx, "crush", "run", p.Task)
|
||||
cmd, prepErr := buildAgentCommand(ctx, "crush", []string{"run", p.Task}, p.Cwd, p.WSLDistro, p.WSLUser)
|
||||
if prepErr != nil {
|
||||
return TextErrorResponse(prepErr.Error()), nil
|
||||
}
|
||||
output, err := cmd.CombinedOutput()
|
||||
|
||||
result := string(output)
|
||||
@@ -169,6 +175,58 @@ func NewCrushRunTool() (*ToolDefinition, error) {
|
||||
})
|
||||
}
|
||||
|
||||
type ClaudeRunParams struct {
|
||||
Task string `json:"task" description:"The task description for Claude Code to execute"`
|
||||
Timeout int `json:"timeout,omitempty" description:"Maximum execution time in seconds (default 1800, max 1800)"`
|
||||
Cwd string `json:"cwd,omitempty" description:"Working directory in which to launch the agent (absolute path; falls back to user home)"`
|
||||
WSLDistro string `json:"wsl_distro,omitempty" description:"On Windows host: WSL distribution to launch the agent in (e.g. 'Ubuntu')"`
|
||||
WSLUser string `json:"wsl_user,omitempty" description:"On Windows host: WSL user to run the agent as"`
|
||||
}
|
||||
|
||||
func NewClaudeRunTool() (*ToolDefinition, error) {
|
||||
return NewTool("claude_run",
|
||||
"Delegate a complex coding task to the Claude Code CLI agent. Claude has access to file editing, code search, bash execution. Use for multi-step coding tasks. Same cwd/wsl_distro/wsl_user options as crush_run.",
|
||||
func(ctx context.Context, p ClaudeRunParams) (ToolResponse, error) {
|
||||
if p.Task == "" {
|
||||
return TextErrorResponse("task is required"), nil
|
||||
}
|
||||
|
||||
timeout := time.Duration(p.Timeout) * time.Second
|
||||
if timeout == 0 {
|
||||
timeout = 1800 * time.Second
|
||||
}
|
||||
if timeout > 1800*time.Second {
|
||||
timeout = 1800 * time.Second
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(ctx, timeout)
|
||||
defer cancel()
|
||||
|
||||
cmd, prepErr := buildAgentCommand(ctx, "claude", []string{"-p", p.Task}, p.Cwd, p.WSLDistro, p.WSLUser)
|
||||
if prepErr != nil {
|
||||
return TextErrorResponse(prepErr.Error()), nil
|
||||
}
|
||||
output, err := cmd.CombinedOutput()
|
||||
|
||||
result := string(output)
|
||||
if len(result) > 15000 {
|
||||
result = result[:15000] + "\n... [truncated]"
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
errMsg := fmt.Sprintf("Claude error: %v", err)
|
||||
if ctx.Err() == context.DeadlineExceeded {
|
||||
errMsg = fmt.Sprintf("Claude timed out after %d seconds. Try splitting the task into smaller parts.", int(timeout.Seconds()))
|
||||
}
|
||||
if result != "" {
|
||||
errMsg += "\n\n" + result
|
||||
}
|
||||
return TextErrorResponse(errMsg), nil
|
||||
}
|
||||
|
||||
return TextResponse(result), nil
|
||||
})
|
||||
}
|
||||
|
||||
type ReadFileParams struct {
|
||||
Path string `json:"path" description:"Absolute or relative path to the file to read"`
|
||||
Offset int `json:"offset,omitempty" description:"Line number to start reading from (0-based, default 0)"`
|
||||
@@ -371,6 +429,7 @@ func DefaultRegistry() *Registry {
|
||||
tools := []*ToolDefinition{
|
||||
must(NewTerminalTool()),
|
||||
must(NewCrushRunTool()),
|
||||
must(NewClaudeRunTool()),
|
||||
must(NewReadFileTool()),
|
||||
must(NewListFilesTool()),
|
||||
must(NewSearchFilesTool()),
|
||||
|
||||
Reference in New Issue
Block a user