@@ -26,6 +26,31 @@ import (
26
26
)
27
27
28
28
var 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
+ },
29
54
"sys.ls" : {
30
55
Parameters : types.Parameters {
31
56
Description : "Lists the contents of a directory" ,
@@ -297,19 +322,46 @@ func SysExec(ctx context.Context, env []string, input string) (string, error) {
297
322
return string (out ), err
298
323
}
299
324
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
+
300
343
func SysLs (_ context.Context , _ []string , input string ) (string , error ) {
344
+ return sysLs ("" , input )
345
+ }
346
+
347
+ func sysLs (base , input string ) (string , error ) {
301
348
var params struct {
302
349
Dir string `json:"dir,omitempty"`
303
350
}
304
351
if err := json .Unmarshal ([]byte (input ), & params ); err != nil {
305
352
return "" , err
306
353
}
307
354
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 )
310
362
}
311
363
312
- entries , err := os .ReadDir (params . Dir )
364
+ entries , err := os .ReadDir (dir )
313
365
if errors .Is (err , fs .ErrNotExist ) {
314
366
return fmt .Sprintf ("directory does not exist: %s" , params .Dir ), nil
315
367
} else if err != nil {
@@ -328,20 +380,38 @@ func SysLs(_ context.Context, _ []string, input string) (string, error) {
328
380
return strings .Join (result , "\n " ), nil
329
381
}
330
382
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
+
331
392
func 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 ) {
332
397
var params struct {
333
398
Filename string `json:"filename,omitempty"`
334
399
}
335
400
if err := json .Unmarshal ([]byte (input ), & params ); err != nil {
336
401
return "" , err
337
402
}
338
403
404
+ file := params .Filename
405
+ if base != "" {
406
+ file = filepath .Join (base , file )
407
+ }
408
+
339
409
// 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 )
342
412
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 )
345
415
if errors .Is (err , fs .ErrNotExist ) {
346
416
return fmt .Sprintf ("The file %s does not exist" , params .Filename ), nil
347
417
} else if err != nil {
@@ -354,7 +424,19 @@ func SysRead(ctx context.Context, env []string, input string) (string, error) {
354
424
return string (data ), nil
355
425
}
356
426
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
+
357
435
func 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 ) {
358
440
var params struct {
359
441
Filename string `json:"filename,omitempty"`
360
442
Content string `json:"content,omitempty"`
@@ -363,28 +445,33 @@ func SysWrite(ctx context.Context, env []string, input string) (string, error) {
363
445
return "" , err
364
446
}
365
447
448
+ file := params .Filename
449
+ if base != "" {
450
+ file = filepath .Join (base , file )
451
+ }
452
+
366
453
// 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 )
369
456
370
- dir := filepath .Dir (params . Filename )
457
+ dir := filepath .Dir (file )
371
458
if _ , err := os .Stat (dir ); errors .Is (err , fs .ErrNotExist ) {
372
459
log .Debugf ("Creating dir %s" , dir )
373
460
if err := os .MkdirAll (dir , 0755 ); err != nil {
374
461
return "" , fmt .Errorf ("creating dir %s: %w" , dir , err )
375
462
}
376
463
}
377
464
378
- if _ , err := os .Stat (params . Filename ); err == nil {
465
+ if _ , err := os .Stat (file ); err == nil {
379
466
if err := confirm .Promptf (ctx , "Overwrite: %s" , params .Filename ); err != nil {
380
467
return "" , err
381
468
}
382
469
}
383
470
384
471
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 )
386
473
387
- return "" , os .WriteFile (params . Filename , data , 0644 )
474
+ return "" , os .WriteFile (file , data , 0644 )
388
475
}
389
476
390
477
func SysAppend (ctx context.Context , env []string , input string ) (string , error ) {
0 commit comments