fix(sandbox): update token generation and improve ClaudeRunner file handling

- Changed token generation from "sandbox:mcp" to "grpc:mcp" for both access and refresh tokens, aligning with updated service requirements.
- Enhanced ClaudeRunner to copy skills from the specified directory to the ".claude/skills" path, improving skill management.
- Updated MCP configuration file path to ".claude/mcp.json" for better organization and consistency in file handling.
- Added error logging for skill copying and exit code handling in stream execution, enhancing debugging capabilities.

Made-with: Cursor
This commit is contained in:
Max 2026-03-15 17:22:44 +08:00
parent 89e5840490
commit fddd137806
2 changed files with 17 additions and 13 deletions

View file

@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"io"
"os"
"path"
"strings"
"time"
@ -41,17 +42,17 @@ func (r *ClaudeRunner) Prepare(ctx context.Context, req *types.PrepareRequest) e
r.mode = "cli"
}
env := resolveOSEnv(req.Computer, req.Config)
steps := append([]types.PrepareStep{}, req.Config.Prepare...)
if req.SkillsDir != "" {
claudeDir := env.pathJoin(env.WorkDir, ".claude")
steps = append(steps, types.PrepareStep{
Action: "exec",
Cmd: env.mkdirCmd(claudeDir),
Once: true,
})
ws := req.Computer.Workplace()
if ws != nil {
src := "local:///" + req.SkillsDir
dst := ".claude/skills"
if _, err := ws.Copy(src, dst); err != nil {
fmt.Fprintf(os.Stderr, "[claude] warn: copy skills %s -> %s: %v\n", src, dst, err)
}
}
}
if len(req.MCPServers) > 0 {
@ -60,7 +61,7 @@ func (r *ClaudeRunner) Prepare(ctx context.Context, req *types.PrepareRequest) e
mcpJSON := buildMCPConfig(req.MCPServers)
steps = append(steps, types.PrepareStep{
Action: "file",
Path: env.pathJoin(env.WorkDir, ".mcp.json"),
Path: ".claude/mcp.json",
Content: mcpJSON,
})
}
@ -103,6 +104,8 @@ func (r *ClaudeRunner) Stream(ctx context.Context, req *types.StreamRequest, han
streamOpts = append(streamOpts, infra.WithStdin(stdin))
}
fmt.Fprintf(os.Stderr, "[claude] Stream cmd=%v hasMCP=%v isContinuation=%v stdinLen=%d\n", cmd, r.hasMCP, isContinuation, len(stdin))
execStream, err := computer.Stream(ctx, cmd, streamOpts...)
if err != nil {
return fmt.Errorf("computer.Stream: %w", err)
@ -157,6 +160,7 @@ func (r *ClaudeRunner) Stream(ctx context.Context, req *types.StreamRequest, han
return waitErr
}
if exitCode != 0 {
fmt.Fprintf(os.Stderr, "[claude] exit code=%d parseErr=%v waitErr=%v stderr=%q\n", exitCode, parseErr, waitErr, stderrStr)
if stderrStr != "" {
return fmt.Errorf("claude CLI exited with code %d: %s", exitCode, stderrStr)
}
@ -302,7 +306,7 @@ func (r *ClaudeRunner) buildCLICommand(req *types.StreamRequest, oe *osEnv, isCo
}
if r.hasMCP {
mcpPath := oe.pathJoin(oe.WorkDir, ".mcp.json")
mcpPath := oe.pathJoin(oe.WorkDir, ".claude", "mcp.json")
args = append(args, "--mcp-config", mcpPath)
if r.mcpToolPattern != "" {
args = append(args, "--allowedTools", r.mcpToolPattern)
@ -327,7 +331,7 @@ func buildMCPConfig(servers []types.MCPServer) []byte {
}
mcpServers[name] = map[string]any{
"command": "tai",
"args": []string{"mcp"},
"args": []string{"mcp", name},
}
}
if len(mcpServers) == 0 {

View file

@ -70,7 +70,7 @@ func IssueSandboxToken(teamID, userID string) (*types.SandboxToken, error) {
extraClaims["team_id"] = teamID
}
tokenStr, err := svc.MakeAccessToken("__yao.sandbox", "sandbox:mcp", subject,
tokenStr, err := svc.MakeAccessToken("__yao.sandbox", "grpc:mcp", subject,
int(accessTokenTTL.Seconds()), extraClaims)
if err != nil {
return nil, fmt.Errorf("sandbox token: issue access token: %w", err)
@ -78,7 +78,7 @@ func IssueSandboxToken(teamID, userID string) (*types.SandboxToken, error) {
tok := &types.SandboxToken{Token: tokenStr}
refreshStr, err := svc.MakeRefreshToken("__yao.sandbox", "sandbox:mcp", subject,
refreshStr, err := svc.MakeRefreshToken("__yao.sandbox", "grpc:mcp", subject,
int(refreshTokenTTL.Seconds()), extraClaims)
if err != nil {
return nil, fmt.Errorf("sandbox token: issue refresh token: %w", err)