relay-flow 0.2.10-alpha → 0.3.0-alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,6 +3,7 @@ package orca
3
3
  import (
4
4
  "context"
5
5
  "errors"
6
+ "os"
6
7
  "os/exec"
7
8
  "strings"
8
9
  "testing"
@@ -404,7 +405,7 @@ func TestCloseTerminalsContinuesAfterStaleHandle(t *testing.T) {
404
405
  func TestCleanupRunDeletesWorktreeAfterStaleHandle(t *testing.T) {
405
406
  fx := &fakeCLI{
406
407
  repos: []orcacli.Repo{{ID: "r1", DisplayName: "app", Path: "/srv/app"}},
407
- worktrees: []orcacli.Worktree{{ID: "wt-PAY-1", RepoID: "r1", DisplayName: "PAY-1"}},
408
+ worktrees: []orcacli.Worktree{{ID: "wt-PAY-1", RepoID: "r1", DisplayName: "PAY-1", Path: "/wt/PAY-1"}},
408
409
  listedTerminals: []orcacli.Terminal{{Handle: "term-stale", Title: "PAY-1:implement", Connected: true}},
409
410
  closeErrors: map[string]error{"term-stale": orcacli.ErrTerminalUnavailable},
410
411
  }
@@ -422,6 +423,107 @@ func TestCleanupRunDeletesWorktreeAfterStaleHandle(t *testing.T) {
422
423
  }
423
424
  }
424
425
 
426
+ func TestCleanupRunBlocksDirtyCheckoutBeforeResourceCleanup(t *testing.T) {
427
+ repo := newOrcaCleanCheckout(t)
428
+ if err := os.WriteFile(repo+"/dirty.txt", []byte("uncommitted\n"), 0o644); err != nil {
429
+ t.Fatal(err)
430
+ }
431
+ fx := &fakeCLI{
432
+ repos: []orcacli.Repo{{ID: "r1", DisplayName: "app", Path: repo}},
433
+ worktrees: []orcacli.Worktree{{ID: "wt-PAY-1", RepoID: "r1", DisplayName: "PAY-1", Path: repo}},
434
+ listedTerminals: []orcacli.Terminal{{Handle: "term-live", Title: "PAY-1:implement", Connected: true}},
435
+ }
436
+ a, err := New(fx, config.RawValues{})
437
+ if err != nil {
438
+ t.Fatal(err)
439
+ }
440
+ err = a.CleanupRun(context.Background(), runner.RunSpec{RepoName: "app", RepoPath: repo, TicketKey: "PAY-1"})
441
+ if err == nil || !strings.Contains(err.Error(), "commit required") {
442
+ t.Fatalf("CleanupRun error = %v, want commit-required dirty-check error", err)
443
+ }
444
+ if len(fx.closedHandles) != 0 || len(fx.deletedWorktrees) != 0 {
445
+ t.Fatalf("dirty cleanup touched runner resources: closed=%v deleted=%v", fx.closedHandles, fx.deletedWorktrees)
446
+ }
447
+ }
448
+
449
+ func TestCleanupRunAllowsCleanCheckoutAndLaterRetry(t *testing.T) {
450
+ repo := newOrcaCleanCheckout(t)
451
+ dirty := repo + "/dirty.txt"
452
+ if err := os.WriteFile(dirty, []byte("uncommitted\n"), 0o644); err != nil {
453
+ t.Fatal(err)
454
+ }
455
+ fx := &fakeCLI{
456
+ repos: []orcacli.Repo{{ID: "r1", DisplayName: "app", Path: repo}},
457
+ worktrees: []orcacli.Worktree{{ID: "wt-PAY-1", RepoID: "r1", DisplayName: "PAY-1", Path: repo}},
458
+ listedTerminals: []orcacli.Terminal{{Handle: "term-live", Title: "PAY-1:implement", Connected: true}},
459
+ }
460
+ a, err := New(fx, config.RawValues{})
461
+ if err != nil {
462
+ t.Fatal(err)
463
+ }
464
+ spec := runner.RunSpec{RepoName: "app", RepoPath: repo, TicketKey: "PAY-1"}
465
+ if err := a.CleanupRun(context.Background(), spec); err == nil {
466
+ t.Fatal("dirty CleanupRun succeeded")
467
+ }
468
+ if err := os.Remove(dirty); err != nil {
469
+ t.Fatal(err)
470
+ }
471
+ if err := a.CleanupRun(context.Background(), spec); err != nil {
472
+ t.Fatalf("clean retry CleanupRun = %v", err)
473
+ }
474
+ if len(fx.closedHandles) != 1 || len(fx.deletedWorktrees) != 1 {
475
+ t.Fatalf("clean retry resources: closed=%v deleted=%v", fx.closedHandles, fx.deletedWorktrees)
476
+ }
477
+ }
478
+
479
+ func TestCleanupRunPropagatesGitStatusFailureBeforeResourceCleanup(t *testing.T) {
480
+ repo := t.TempDir()
481
+ fx := &fakeCLI{
482
+ repos: []orcacli.Repo{{ID: "r1", DisplayName: "app", Path: repo}},
483
+ worktrees: []orcacli.Worktree{{ID: "wt-PAY-1", RepoID: "r1", DisplayName: "PAY-1", Path: repo}},
484
+ }
485
+ a, err := New(fx, config.RawValues{})
486
+ if err != nil {
487
+ t.Fatal(err)
488
+ }
489
+ if err := a.CleanupRun(context.Background(), runner.RunSpec{RepoName: "app", RepoPath: repo, TicketKey: "PAY-1"}); err == nil {
490
+ t.Fatal("CleanupRun treated Git status failure as clean")
491
+ }
492
+ if len(fx.closedHandles) != 0 || len(fx.deletedWorktrees) != 0 {
493
+ t.Fatalf("Git status failure touched runner resources: closed=%v deleted=%v", fx.closedHandles, fx.deletedWorktrees)
494
+ }
495
+ }
496
+
497
+ func newOrcaCleanCheckout(t *testing.T) string {
498
+ t.Helper()
499
+ repo := t.TempDir()
500
+ for _, args := range [][]string{
501
+ {"init", "-q", "-b", "main"},
502
+ {"config", "user.email", "relay-flow@example.invalid"},
503
+ {"config", "user.name", "Relay Flow"},
504
+ } {
505
+ cmd := exec.Command("git", args...)
506
+ cmd.Dir = repo
507
+ if output, err := cmd.CombinedOutput(); err != nil {
508
+ t.Fatalf("git %v: %v: %s", args, err, output)
509
+ }
510
+ }
511
+ if err := os.WriteFile(repo+"/tracked.txt", []byte("clean\n"), 0o644); err != nil {
512
+ t.Fatal(err)
513
+ }
514
+ cmd := exec.Command("git", "add", "tracked.txt")
515
+ cmd.Dir = repo
516
+ if output, err := cmd.CombinedOutput(); err != nil {
517
+ t.Fatalf("git add: %v: %s", err, output)
518
+ }
519
+ cmd = exec.Command("git", "commit", "-qm", "initial")
520
+ cmd.Dir = repo
521
+ if output, err := cmd.CombinedOutput(); err != nil {
522
+ t.Fatalf("git commit: %v: %s", err, output)
523
+ }
524
+ return repo
525
+ }
526
+
425
527
  // An existing ticket branch must win even over a configured baseRef. Passing
426
528
  // any other base would make Orca hit its branch-name collision behavior.
427
529
  func TestEnsureEnvironment_ExistingTicketBranchAvoidsCollision(t *testing.T) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "relay-flow",
3
- "version": "0.2.10-alpha",
3
+ "version": "0.3.0-alpha",
4
4
  "description": "Graph-based agent workflow engine — tracker-agnostic, pluggable runners",
5
5
  "bin": {
6
6
  "relay-flow": "./bin/relay-flow.js",