@@ -32,7 +32,6 @@ func NewCmdClaude() *cobra.Command {
3232 orgID string
3333 token string
3434 resumeSessionID string
35- sandboxID string
3635 output string
3736 local bool
3837 repository * string
@@ -105,6 +104,18 @@ Subcommands:
105104 }
106105 ctx := cmd .Context ()
107106
107+ // Check if we're running inside a sandbox
108+ sandboxID := os .Getenv ("DEPOT_SANDBOX_ID" )
109+ if sandboxID != "" {
110+ // Force local mode when running inside a sandbox
111+ local = true
112+ defer func () {
113+ if err := shutdownSandbox (ctx , sandboxID ); err != nil {
114+ fmt .Fprintf (os .Stderr , "Warning: failed to shutdown sandbox: %v\n " , err )
115+ }
116+ }()
117+ }
118+
108119 claudeArgs := []string {}
109120 for i := 0 ; i < len (args ); i ++ {
110121 arg := args [i ]
@@ -156,20 +167,11 @@ Subcommands:
156167 } else {
157168 return fmt .Errorf ("--resume flag requires a session ID" )
158169 }
159- case "--sandbox-id" :
160- if i + 1 < len (args ) && ! strings .HasPrefix (args [i + 1 ], "-" ) {
161- sandboxID = args [i + 1 ]
162- i ++
163- } else {
164- return fmt .Errorf ("--sandbox-id flag requires a sandbox ID" )
165- }
166170 default :
167171 if strings .HasPrefix (arg , "--session-id=" ) {
168172 sessionID = strings .TrimPrefix (arg , "--session-id=" )
169173 } else if strings .HasPrefix (arg , "--resume=" ) {
170174 resumeSessionID = strings .TrimPrefix (arg , "--resume=" )
171- } else if strings .HasPrefix (arg , "--sandbox-id=" ) {
172- sandboxID = strings .TrimPrefix (arg , "--sandbox-id=" )
173175 } else if strings .HasPrefix (arg , "--org=" ) {
174176 orgID = strings .TrimPrefix (arg , "--org=" )
175177 } else if strings .HasPrefix (arg , "--token=" ) {
@@ -233,6 +235,11 @@ Subcommands:
233235 }
234236
235237 if ! local {
238+ // Check if we're already in a sandbox - prevent recursive remote sessions
239+ if sandboxID != "" {
240+ return fmt .Errorf ("cannot start a remote session from within a sandbox" )
241+ }
242+
236243 // Default repository to current git remote only if --repository flag was specified with empty value
237244 var repoValue string
238245 if repository != nil {
@@ -255,12 +262,10 @@ Subcommands:
255262 Branch : branch ,
256263 GitSecret : gitSecret ,
257264 ResumeSessionID : resumeSessionID ,
258- RemoteSessionID : sandboxID ,
259265 Wait : wait ,
260266 Stdin : os .Stdin ,
261267 Stdout : os .Stdout ,
262268 Stderr : os .Stderr ,
263- AgentType : "claude" ,
264269 }
265270 return RunAgentRemote (ctx , agentOpts )
266271 } else {
@@ -284,24 +289,20 @@ Subcommands:
284289}
285290
286291// returns the session file UUID that claude should resume from
287- func resumeSession (ctx context.Context , client agentv1connect.ClaudeServiceClient , token , sessionID , sessionDir , cwd , orgID string , retryCount int , retryDelay time.Duration ) (string , error ) {
288- var resp * connect.Response [agentv1.DownloadClaudeSessionResponse ]
292+ func resumeSession (ctx context.Context , client agentv1connect.SessionServiceClient , token , sessionID , sessionDir , cwd , orgID string , retryCount int , retryDelay time.Duration ) (string , error ) {
293+ var resp * connect.Response [agentv1.DownloadSessionResponse ]
289294 var lastErr error
290295
291296 for i := range retryCount {
292297 if i > 0 {
293298 time .Sleep (retryDelay )
294299 }
295300
296- req := & agentv1.DownloadClaudeSessionRequest {
297- SessionId : sessionID ,
298- OrganizationId : new (string ),
299- }
300- if orgID != "" {
301- req .OrganizationId = & orgID
301+ req := & agentv1.DownloadSessionRequest {
302+ SessionId : sessionID ,
302303 }
303304
304- resp , lastErr = client .DownloadClaudeSession (ctx , api .WithAuthentication (connect .NewRequest (req ), token ))
305+ resp , lastErr = client .DownloadSession (ctx , api .WithAuthenticationAndOrg (connect .NewRequest (req ), token , orgID ))
305306 if lastErr == nil {
306307 break
307308 }
@@ -319,7 +320,8 @@ func resumeSession(ctx context.Context, client agentv1connect.ClaudeServiceClien
319320
320321 reader := bytes .NewReader (resp .Msg .SessionData )
321322
322- sessionFilePath := filepath .Join (projectDir , fmt .Sprintf ("%s.jsonl" , resp .Msg .ClaudeSessionId ))
323+ claudeSessionID := resp .Msg .ToolSessionId
324+ sessionFilePath := filepath .Join (projectDir , fmt .Sprintf ("%s.jsonl" , claudeSessionID ))
323325 out , err := os .Create (sessionFilePath )
324326 if err != nil {
325327 return "" , fmt .Errorf ("failed to create session file: %w" , err )
@@ -330,10 +332,10 @@ func resumeSession(ctx context.Context, client agentv1connect.ClaudeServiceClien
330332 return "" , fmt .Errorf ("failed to write session file: %w" , err )
331333 }
332334
333- return resp . Msg . ClaudeSessionId , nil
335+ return claudeSessionID , nil
334336}
335337
336- func saveSession (ctx context.Context , client agentv1connect.ClaudeServiceClient , token , sessionID , sessionFilePath string , retryCount int , retryDelay time.Duration , orgID string ) error {
338+ func saveSession (ctx context.Context , client agentv1connect.SessionServiceClient , token , sessionID , sessionFilePath string , retryCount int , retryDelay time.Duration , orgID string ) error {
337339 data , err := os .ReadFile (sessionFilePath )
338340 if err != nil {
339341 return fmt .Errorf ("failed to read session file: %w" , err )
@@ -349,21 +351,18 @@ func saveSession(ctx context.Context, client agentv1connect.ClaudeServiceClient,
349351
350352 claudeSessionID := filepath .Base (strings .TrimSuffix (sessionFilePath , ".jsonl" ))
351353
352- req := & agentv1.UploadClaudeSessionRequest {
353- SessionData : data ,
354- SessionId : sessionID ,
355- OrganizationId : new (string ),
356- Summary : new ( string ) ,
357- ClaudeSessionId : claudeSessionID ,
354+ req := & agentv1.UploadSessionRequest {
355+ SessionData : data ,
356+ SessionId : sessionID ,
357+ Summary : new (string ),
358+ ToolSessionId : claudeSessionID ,
359+ AgentType : agentv1 . AgentType_AGENT_TYPE_CLAUDE_CODE ,
358360 }
359361 if summary != "" {
360362 req .Summary = & summary
361363 }
362- if orgID != "" {
363- req .OrganizationId = & orgID
364- }
365364
366- _ , err := client .UploadClaudeSession (ctx , api .WithAuthentication (connect .NewRequest (req ), token ))
365+ _ , err := client .UploadSession (ctx , api .WithAuthenticationAndOrg (connect .NewRequest (req ), token , orgID ))
367366 if err != nil {
368367 lastErr = err
369368 continue
@@ -422,7 +421,7 @@ func convertPathToProjectName(path string) string {
422421}
423422
424423// continuouslySaveSessionFile monitors the project directory for new or changed session files and automatically saves them
425- func continuouslySaveSessionFile (ctx context.Context , projectDir string , client agentv1connect.ClaudeServiceClient , token , sessionID , orgID string ) error {
424+ func continuouslySaveSessionFile (ctx context.Context , projectDir string , client agentv1connect.SessionServiceClient , token , sessionID , orgID string ) error {
426425 if err := os .MkdirAll (projectDir , 0755 ); err != nil {
427426 return fmt .Errorf ("failed to create project directory: %w" , err )
428427 }
@@ -526,7 +525,7 @@ func RunClaudeSession(ctx context.Context, opts *ClaudeSessionOptions) error {
526525 opts .OrgID = os .Getenv ("DEPOT_ORG_ID" )
527526 }
528527
529- client := api .NewClaudeClient ()
528+ client := api .NewSessionClient ()
530529
531530 // early auth check to prevent starting Claude if saving or resuming will fail
532531 if err := verifyAuthentication (ctx , client , token , opts .OrgID ); err != nil {
@@ -647,16 +646,29 @@ func extractSummaryFromSession(data []byte) string {
647646
648647// verifyAuthentication performs an early auth check by calling the list-sessions API
649648// this prevents starting Claude if authentication or organization access will fail
650- func verifyAuthentication (ctx context.Context , client agentv1connect.ClaudeServiceClient , token , orgID string ) error {
651- req := & agentv1.ListClaudeSessionsRequest {}
652- if orgID != "" {
653- req .OrganizationId = & orgID
654- }
649+ func verifyAuthentication (ctx context.Context , client agentv1connect.SessionServiceClient , token , orgID string ) error {
650+ req := & agentv1.ListSessionsRequest {}
655651
656- _ , err := client .ListClaudeSessions (ctx , api .WithAuthentication (connect .NewRequest (req ), token ))
652+ _ , err := client .ListSessions (ctx , api .WithAuthenticationAndOrg (connect .NewRequest (req ), token , orgID ))
657653 if err != nil {
658654 return fmt .Errorf ("authentication failed: %w" , err )
659655 }
660656
661657 return nil
662658}
659+
660+ // shutdownSandbox calls the Shutdown API to gracefully terminate and snapshot the sandbox
661+ func shutdownSandbox (ctx context.Context , sandboxID string ) error {
662+ client := api .NewSandboxClient ()
663+
664+ req := & agentv1.ShutdownRequest {
665+ SandboxId : sandboxID ,
666+ }
667+
668+ _ , err := client .Shutdown (ctx , connect .NewRequest (req ))
669+ if err != nil {
670+ return fmt .Errorf ("failed to shutdown sandbox: %w" , err )
671+ }
672+
673+ return nil
674+ }
0 commit comments