@@ -26,6 +26,31 @@ import (
2626)
2727
2828var tools = map [string ]types.Tool {
29+ "sys.workspace.ls" : {
30+ Parameters : types.Parameters {
31+ Description : "Lists the contents of a directory relative to the current workspace" ,
32+ Arguments : types .ObjectSchema (
33+ "dir" , "The directory to list" ),
34+ },
35+ BuiltinFunc : SysWorkspaceLs ,
36+ },
37+ "sys.workspace.write" : {
38+ Parameters : types.Parameters {
39+ Description : "Write the contents to a file relative to the current workspace" ,
40+ Arguments : types .ObjectSchema (
41+ "filename" , "The name of the file to write to" ,
42+ "content" , "The content to write" ),
43+ },
44+ BuiltinFunc : SysWorkspaceWrite ,
45+ },
46+ "sys.workspace.read" : {
47+ Parameters : types.Parameters {
48+ Description : "Reads the contents of a file relative to the current workspace" ,
49+ Arguments : types .ObjectSchema (
50+ "filename" , "The name of the file to read" ),
51+ },
52+ BuiltinFunc : SysWorkspaceRead ,
53+ },
2954 "sys.ls" : {
3055 Parameters : types.Parameters {
3156 Description : "Lists the contents of a directory" ,
@@ -297,19 +322,46 @@ func SysExec(ctx context.Context, env []string, input string) (string, error) {
297322 return string (out ), err
298323}
299324
325+ func getWorkspaceDir (envs []string ) (string , error ) {
326+ for _ , env := range envs {
327+ dir , ok := strings .CutPrefix (env , "GPTSCRIPT_WORKSPACE_DIR=" )
328+ if ok && dir != "" {
329+ return dir , nil
330+ }
331+ }
332+ return "" , fmt .Errorf ("no workspace directory found in env" )
333+ }
334+
335+ func SysWorkspaceLs (_ context.Context , env []string , input string ) (string , error ) {
336+ dir , err := getWorkspaceDir (env )
337+ if err != nil {
338+ return "" , err
339+ }
340+ return sysLs (dir , input )
341+ }
342+
300343func SysLs (_ context.Context , _ []string , input string ) (string , error ) {
344+ return sysLs ("" , input )
345+ }
346+
347+ func sysLs (base , input string ) (string , error ) {
301348 var params struct {
302349 Dir string `json:"dir,omitempty"`
303350 }
304351 if err := json .Unmarshal ([]byte (input ), & params ); err != nil {
305352 return "" , err
306353 }
307354
308- if params .Dir == "" {
309- params .Dir = "."
355+ dir := params .Dir
356+ if dir == "" {
357+ dir = "."
358+ }
359+
360+ if base != "" {
361+ dir = filepath .Join (base , dir )
310362 }
311363
312- entries , err := os .ReadDir (params . Dir )
364+ entries , err := os .ReadDir (dir )
313365 if errors .Is (err , fs .ErrNotExist ) {
314366 return fmt .Sprintf ("directory does not exist: %s" , params .Dir ), nil
315367 } else if err != nil {
@@ -328,20 +380,38 @@ func SysLs(_ context.Context, _ []string, input string) (string, error) {
328380 return strings .Join (result , "\n " ), nil
329381}
330382
383+ func SysWorkspaceRead (ctx context.Context , env []string , input string ) (string , error ) {
384+ dir , err := getWorkspaceDir (env )
385+ if err != nil {
386+ return "" , err
387+ }
388+
389+ return sysRead (ctx , dir , env , input )
390+ }
391+
331392func SysRead (ctx context.Context , env []string , input string ) (string , error ) {
393+ return sysRead (ctx , "" , env , input )
394+ }
395+
396+ func sysRead (ctx context.Context , base string , env []string , input string ) (string , error ) {
332397 var params struct {
333398 Filename string `json:"filename,omitempty"`
334399 }
335400 if err := json .Unmarshal ([]byte (input ), & params ); err != nil {
336401 return "" , err
337402 }
338403
404+ file := params .Filename
405+ if base != "" {
406+ file = filepath .Join (base , file )
407+ }
408+
339409 // Lock the file to prevent concurrent writes from other tool calls.
340- locker .RLock (params . Filename )
341- defer locker .RUnlock (params . Filename )
410+ locker .RLock (file )
411+ defer locker .RUnlock (file )
342412
343- log .Debugf ("Reading file %s" , params . Filename )
344- data , err := os .ReadFile (params . Filename )
413+ log .Debugf ("Reading file %s" , file )
414+ data , err := os .ReadFile (file )
345415 if errors .Is (err , fs .ErrNotExist ) {
346416 return fmt .Sprintf ("The file %s does not exist" , params .Filename ), nil
347417 } else if err != nil {
@@ -354,7 +424,19 @@ func SysRead(ctx context.Context, env []string, input string) (string, error) {
354424 return string (data ), nil
355425}
356426
427+ func SysWorkspaceWrite (ctx context.Context , env []string , input string ) (string , error ) {
428+ dir , err := getWorkspaceDir (env )
429+ if err != nil {
430+ return "" , err
431+ }
432+ return sysWrite (ctx , dir , env , input )
433+ }
434+
357435func SysWrite (ctx context.Context , env []string , input string ) (string , error ) {
436+ return sysWrite (ctx , "" , env , input )
437+ }
438+
439+ func sysWrite (ctx context.Context , base string , env []string , input string ) (string , error ) {
358440 var params struct {
359441 Filename string `json:"filename,omitempty"`
360442 Content string `json:"content,omitempty"`
@@ -363,28 +445,33 @@ func SysWrite(ctx context.Context, env []string, input string) (string, error) {
363445 return "" , err
364446 }
365447
448+ file := params .Filename
449+ if base != "" {
450+ file = filepath .Join (base , file )
451+ }
452+
366453 // Lock the file to prevent concurrent writes from other tool calls.
367- locker .Lock (params . Filename )
368- defer locker .Unlock (params . Filename )
454+ locker .Lock (file )
455+ defer locker .Unlock (file )
369456
370- dir := filepath .Dir (params . Filename )
457+ dir := filepath .Dir (file )
371458 if _ , err := os .Stat (dir ); errors .Is (err , fs .ErrNotExist ) {
372459 log .Debugf ("Creating dir %s" , dir )
373460 if err := os .MkdirAll (dir , 0755 ); err != nil {
374461 return "" , fmt .Errorf ("creating dir %s: %w" , dir , err )
375462 }
376463 }
377464
378- if _ , err := os .Stat (params . Filename ); err == nil {
465+ if _ , err := os .Stat (file ); err == nil {
379466 if err := confirm .Promptf (ctx , "Overwrite: %s" , params .Filename ); err != nil {
380467 return "" , err
381468 }
382469 }
383470
384471 data := []byte (params .Content )
385- log .Debugf ("Wrote %d bytes to file %s" , len (data ), params . Filename )
472+ log .Debugf ("Wrote %d bytes to file %s" , len (data ), file )
386473
387- return "" , os .WriteFile (params . Filename , data , 0644 )
474+ return "" , os .WriteFile (file , data , 0644 )
388475}
389476
390477func SysAppend (ctx context.Context , env []string , input string ) (string , error ) {
0 commit comments