agent-relay-server 0.10.20 → 0.10.21

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.
package/docs/openapi.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "openapi": "3.1.0",
3
3
  "info": {
4
4
  "title": "Agent Relay API",
5
- "version": "0.10.19",
5
+ "version": "0.10.20",
6
6
  "description": "Real-time message bus for inter-agent communication. Agent-first: this spec is designed for machine consumption — agents can self-discover the full API surface via GET /api/spec.",
7
7
  "license": {
8
8
  "name": "MIT",
@@ -2631,10 +2631,11 @@
2631
2631
  "/api/orchestrators/{id}/actions": {
2632
2632
  "post": {
2633
2633
  "operationId": "postOrchestratorAction",
2634
- "summary": "Post Orchestrator Action",
2634
+ "summary": "Run an orchestrator action",
2635
2635
  "tags": [
2636
2636
  "Orchestrators"
2637
2637
  ],
2638
+ "description": "Dispatches a host action to the orchestrator over the command bus. `restart`/`shutdown` target a managed agent (omit `agentId` for all). `upgrade` triggers a remote self-upgrade: the relay stamps a desired version and the orchestrator installs it via the bundled `agent-relay upgrade --no-restart` CLI, then restarts itself decoupled (systemd-run) so the bus keepalive survives its own teardown. The upgrade command is intentionally left `running` — the relay settles it (succeeded/failed) by reconciling the version the orchestrator reports on its post-restart re-register, within a deadline. Safety rails: semver-only `targetVersion` (defaults to the relay's own version), npm-registry providers only, and no downgrade unless `force` is set. Requires systemd --user supervision on the orchestrator host.",
2638
2639
  "parameters": [
2639
2640
  {
2640
2641
  "name": "id",
@@ -2651,27 +2652,57 @@
2651
2652
  "application/json": {
2652
2653
  "schema": {
2653
2654
  "type": "object",
2655
+ "required": [
2656
+ "action"
2657
+ ],
2654
2658
  "properties": {
2655
2659
  "action": {
2656
- "type": "string"
2660
+ "type": "string",
2661
+ "enum": [
2662
+ "restart",
2663
+ "shutdown",
2664
+ "upgrade"
2665
+ ],
2666
+ "description": "Action to dispatch."
2667
+ },
2668
+ "targetVersion": {
2669
+ "type": "string",
2670
+ "description": "upgrade only — semver (e.g. 0.10.21) to install. Defaults to the relay's own version (fleet target) when omitted."
2671
+ },
2672
+ "providers": {
2673
+ "type": "array",
2674
+ "items": {
2675
+ "type": "string"
2676
+ },
2677
+ "description": "upgrade only — packages to upgrade. Defaults to [\"orchestrator\"]."
2678
+ },
2679
+ "force": {
2680
+ "type": "boolean",
2681
+ "description": "upgrade only — allow a downgrade (targetVersion < current)."
2657
2682
  },
2658
2683
  "agentId": {
2659
- "type": "string"
2684
+ "type": "string",
2685
+ "description": "restart/shutdown only — managed agent id to target; omit to target all."
2660
2686
  },
2661
2687
  "policyName": {
2662
- "type": "string"
2688
+ "type": "string",
2689
+ "description": "restart/shutdown only — managed policy correlation."
2663
2690
  },
2664
2691
  "spawnRequestId": {
2665
- "type": "string"
2692
+ "type": "string",
2693
+ "description": "restart/shutdown only — spawn request correlation."
2666
2694
  },
2667
2695
  "sessionName": {
2668
- "type": "string"
2696
+ "type": "string",
2697
+ "description": "restart/shutdown only."
2669
2698
  },
2670
2699
  "tmuxSession": {
2671
- "type": "string"
2700
+ "type": "string",
2701
+ "description": "restart/shutdown only."
2672
2702
  },
2673
2703
  "reason": {
2674
- "type": "string"
2704
+ "type": "string",
2705
+ "description": "restart/shutdown only — human-readable reason (default \"manual\")."
2675
2706
  }
2676
2707
  }
2677
2708
  }
@@ -2679,37 +2710,17 @@
2679
2710
  }
2680
2711
  },
2681
2712
  "responses": {
2682
- "200": {
2683
- "description": "Success",
2684
- "content": {
2685
- "application/json": {}
2686
- }
2687
- },
2688
2713
  "202": {
2689
- "description": "HTTP 202",
2690
- "content": {
2691
- "application/json": {}
2692
- }
2714
+ "description": "Accepted. The command was created and emitted on the bus. For `upgrade`, the response includes the created command and the resolved `targetVersion`, and the orchestrator's `upgrade` state is stamped `pending` (settled later via version reconciliation)."
2693
2715
  },
2694
2716
  "400": {
2695
- "description": "Bad request",
2696
- "content": {
2697
- "application/json": {
2698
- "schema": {
2699
- "$ref": "#/components/schemas/Error"
2700
- }
2701
- }
2702
- }
2717
+ "description": "Invalid body — missing/unknown `action`, or `targetVersion` is not valid semver."
2703
2718
  },
2704
2719
  "404": {
2705
- "description": "Not found",
2706
- "content": {
2707
- "application/json": {
2708
- "schema": {
2709
- "$ref": "#/components/schemas/Error"
2710
- }
2711
- }
2712
- }
2720
+ "description": "Orchestrator not found."
2721
+ },
2722
+ "409": {
2723
+ "description": "Refusing downgrade — `targetVersion` is older than the orchestrator's current version; pass `force: true` to override."
2713
2724
  }
2714
2725
  },
2715
2726
  "security": [
@@ -3492,6 +3503,95 @@
3492
3503
  ]
3493
3504
  }
3494
3505
  },
3506
+ "/api/workspaces/orphans": {
3507
+ "get": {
3508
+ "operationId": "getWorkspaceOrphans",
3509
+ "summary": "List orphaned worktrees",
3510
+ "tags": [
3511
+ "Other"
3512
+ ],
3513
+ "description": "Worktrees found on disk (agent/* branches) with no live workspace row — left behind by crashes or failed cleanups. Probes each known repo's owning online orchestrator and subtracts active DB rows. Returns `{ orphans: [...] }` (empty with a `reason` when no orchestrator is online). Reclaim via POST /api/workspaces/orphans/reclaim.",
3514
+ "responses": {
3515
+ "200": {
3516
+ "description": "Success",
3517
+ "content": {
3518
+ "application/json": {}
3519
+ }
3520
+ }
3521
+ },
3522
+ "security": [
3523
+ {
3524
+ "bearerAuth": []
3525
+ },
3526
+ {
3527
+ "tokenHeader": []
3528
+ },
3529
+ {
3530
+ "tokenQuery": []
3531
+ }
3532
+ ]
3533
+ }
3534
+ },
3535
+ "/api/workspaces/orphans/reclaim": {
3536
+ "post": {
3537
+ "operationId": "postWorkspaceOrphanReclaim",
3538
+ "summary": "Reclaim an orphaned worktree",
3539
+ "tags": [
3540
+ "Other"
3541
+ ],
3542
+ "description": "Removes an orphaned worktree (and its branch) from the host via a `workspace.cleanup` command. Body: `worktreePath`, `repoRoot`, optional `branch`. Refuses (409) if the path still backs a live workspace row, or if no online orchestrator owns the path. Requires `command:write`. Returns 202 with the created command.",
3543
+ "requestBody": {
3544
+ "required": true,
3545
+ "content": {
3546
+ "application/json": {
3547
+ "schema": {
3548
+ "type": "object",
3549
+ "required": [
3550
+ "worktreePath",
3551
+ "repoRoot"
3552
+ ],
3553
+ "properties": {
3554
+ "worktreePath": {
3555
+ "type": "string",
3556
+ "description": "Absolute path of the orphaned worktree to remove."
3557
+ },
3558
+ "repoRoot": {
3559
+ "type": "string",
3560
+ "description": "Repo root the worktree belongs to (for orchestrator routing)."
3561
+ },
3562
+ "branch": {
3563
+ "type": "string",
3564
+ "description": "Agent branch to delete after worktree removal."
3565
+ }
3566
+ }
3567
+ }
3568
+ }
3569
+ }
3570
+ },
3571
+ "responses": {
3572
+ "202": {
3573
+ "description": "Reclaim command created and emitted."
3574
+ },
3575
+ "400": {
3576
+ "description": "Missing worktreePath/repoRoot."
3577
+ },
3578
+ "409": {
3579
+ "description": "Path backs a live workspace, or no online orchestrator owns it."
3580
+ }
3581
+ },
3582
+ "security": [
3583
+ {
3584
+ "bearerAuth": []
3585
+ },
3586
+ {
3587
+ "tokenHeader": []
3588
+ },
3589
+ {
3590
+ "tokenQuery": []
3591
+ }
3592
+ ]
3593
+ }
3594
+ },
3495
3595
  "/api/workspaces/{id}": {
3496
3596
  "get": {
3497
3597
  "operationId": "getWorkspaceById",
@@ -3538,15 +3638,201 @@
3538
3638
  "tokenQuery": []
3539
3639
  }
3540
3640
  ]
3641
+ },
3642
+ "delete": {
3643
+ "operationId": "deleteWorkspaceById",
3644
+ "summary": "Purge a workspace record (last resort)",
3645
+ "tags": [
3646
+ "Other"
3647
+ ],
3648
+ "description": "Removes the workspace's DB row only — it does NOT touch the worktree on disk. Use the `cleanup` action to remove the worktree. This is the escape hatch for rows whose owning orchestrator is gone for good and can no longer run a cleanup command. Requires `command:write` scope.",
3649
+ "parameters": [
3650
+ {
3651
+ "name": "id",
3652
+ "in": "path",
3653
+ "required": true,
3654
+ "schema": {
3655
+ "type": "string"
3656
+ }
3657
+ }
3658
+ ],
3659
+ "responses": {
3660
+ "200": {
3661
+ "description": "Success",
3662
+ "content": {
3663
+ "application/json": {}
3664
+ }
3665
+ },
3666
+ "404": {
3667
+ "description": "Not found",
3668
+ "content": {
3669
+ "application/json": {
3670
+ "schema": {
3671
+ "$ref": "#/components/schemas/Error"
3672
+ }
3673
+ }
3674
+ }
3675
+ }
3676
+ },
3677
+ "security": [
3678
+ {
3679
+ "bearerAuth": []
3680
+ },
3681
+ {
3682
+ "tokenHeader": []
3683
+ },
3684
+ {
3685
+ "tokenQuery": []
3686
+ }
3687
+ ]
3688
+ }
3689
+ },
3690
+ "/api/workspaces/{id}/git-state": {
3691
+ "get": {
3692
+ "operationId": "getWorkspaceGitState",
3693
+ "summary": "Get live git state of a workspace worktree",
3694
+ "tags": [
3695
+ "Other"
3696
+ ],
3697
+ "description": "Returns ahead/behind base commit counts, dirty file count, and last commit for the workspace's isolated worktree, computed on the host by the owning orchestrator. Degrades to `{ available: false, reason }` when no online orchestrator owns the path or the workspace has no worktree.",
3698
+ "parameters": [
3699
+ {
3700
+ "name": "id",
3701
+ "in": "path",
3702
+ "required": true,
3703
+ "schema": {
3704
+ "type": "string"
3705
+ }
3706
+ },
3707
+ {
3708
+ "name": "strategy",
3709
+ "in": "query",
3710
+ "schema": {
3711
+ "type": "string"
3712
+ }
3713
+ }
3714
+ ],
3715
+ "responses": {
3716
+ "200": {
3717
+ "description": "Success",
3718
+ "content": {
3719
+ "application/json": {}
3720
+ }
3721
+ }
3722
+ },
3723
+ "security": [
3724
+ {
3725
+ "bearerAuth": []
3726
+ },
3727
+ {
3728
+ "tokenHeader": []
3729
+ },
3730
+ {
3731
+ "tokenQuery": []
3732
+ }
3733
+ ]
3734
+ }
3735
+ },
3736
+ "/api/workspaces/{id}/merge-preview": {
3737
+ "get": {
3738
+ "operationId": "getWorkspaceMergePreview",
3739
+ "summary": "Pre-flight check for merging a workspace's work",
3740
+ "tags": [
3741
+ "Other"
3742
+ ],
3743
+ "description": "Returns whether the workspace's branch can be cleanly integrated into its base: ahead/behind counts, predicted conflict (three-way merge-tree), clean-fast-forward eligibility, whether a remote and `gh` are available, and the strategy `auto` would resolve to (`pr` when a remote + gh + base branch exist, else `rebase-ff`). Computed on the host by the owning orchestrator. Optional `?strategy=` (`pr`|`rebase-ff`|`auto`) overrides the resolved strategy. Degrades to `{ available: false, reason }` when no online orchestrator owns the path or the workspace has no worktree.",
3744
+ "parameters": [
3745
+ {
3746
+ "name": "id",
3747
+ "in": "path",
3748
+ "required": true,
3749
+ "schema": {
3750
+ "type": "string"
3751
+ }
3752
+ },
3753
+ {
3754
+ "name": "strategy",
3755
+ "in": "query",
3756
+ "schema": {
3757
+ "type": "string"
3758
+ }
3759
+ }
3760
+ ],
3761
+ "responses": {
3762
+ "200": {
3763
+ "description": "Success",
3764
+ "content": {
3765
+ "application/json": {}
3766
+ }
3767
+ }
3768
+ },
3769
+ "security": [
3770
+ {
3771
+ "bearerAuth": []
3772
+ },
3773
+ {
3774
+ "tokenHeader": []
3775
+ },
3776
+ {
3777
+ "tokenQuery": []
3778
+ }
3779
+ ]
3780
+ }
3781
+ },
3782
+ "/api/workspaces/{id}/diff": {
3783
+ "get": {
3784
+ "operationId": "getWorkspaceDiff",
3785
+ "summary": "Diff a workspace against its base",
3786
+ "tags": [
3787
+ "Other"
3788
+ ],
3789
+ "description": "Per-file line counts and a size-capped unified patch for the workspace's committed work (base...HEAD), computed on the host by the owning orchestrator. `?patch=0` omits the patch body (file list only). Degrades to `{ available: false, reason }` when the host is offline or there's no worktree.",
3790
+ "parameters": [
3791
+ {
3792
+ "name": "id",
3793
+ "in": "path",
3794
+ "required": true,
3795
+ "schema": {
3796
+ "type": "string"
3797
+ }
3798
+ },
3799
+ {
3800
+ "name": "patch",
3801
+ "in": "query",
3802
+ "schema": {
3803
+ "type": "string"
3804
+ }
3805
+ }
3806
+ ],
3807
+ "responses": {
3808
+ "200": {
3809
+ "description": "Success",
3810
+ "content": {
3811
+ "application/json": {}
3812
+ }
3813
+ }
3814
+ },
3815
+ "security": [
3816
+ {
3817
+ "bearerAuth": []
3818
+ },
3819
+ {
3820
+ "tokenHeader": []
3821
+ },
3822
+ {
3823
+ "tokenQuery": []
3824
+ }
3825
+ ]
3541
3826
  }
3542
3827
  },
3543
3828
  "/api/workspaces/{id}/actions": {
3544
3829
  "post": {
3545
3830
  "operationId": "postWorkspaceAction",
3546
- "summary": "Post Workspace Action",
3831
+ "summary": "Run a workspace action",
3547
3832
  "tags": [
3548
3833
  "Other"
3549
3834
  ],
3835
+ "description": "Transitions a workspace's lifecycle state and, for command actions, dispatches to the owning orchestrator over the command bus. Actions: `status` (read), `ready`, `request-review`, `conflict-found`, `merge-plan` (soft labels), `merge` (real integration — `workspace.merge` command: rebase + fast-forward into base or open a PR via `gh`, then delete the branch on success; accepts `strategy` (`pr`|`rebase-ff`|`auto`, default `auto`), `prTitle`, `prBody`, `deleteBranch`), `cleanup` (remove the worktree), and `abandon`. `merge`/`cleanup` require an online orchestrator owning the path and return 202 with the created command; the final status is reconciled from the command result.",
3550
3836
  "parameters": [
3551
3837
  {
3552
3838
  "name": "id",
@@ -3563,18 +3849,52 @@
3563
3849
  "application/json": {
3564
3850
  "schema": {
3565
3851
  "type": "object",
3852
+ "required": [
3853
+ "action"
3854
+ ],
3566
3855
  "properties": {
3567
3856
  "action": {
3568
- "type": "string"
3857
+ "type": "string",
3858
+ "enum": [
3859
+ "status",
3860
+ "ready",
3861
+ "request-review",
3862
+ "conflict-found",
3863
+ "merge-plan",
3864
+ "merge",
3865
+ "cleanup",
3866
+ "abandon"
3867
+ ],
3868
+ "description": "Lifecycle action to apply."
3869
+ },
3870
+ "strategy": {
3871
+ "type": "string",
3872
+ "enum": [
3873
+ "pr",
3874
+ "rebase-ff",
3875
+ "auto"
3876
+ ],
3877
+ "description": "merge only — integration strategy. `auto` picks PR when a remote + gh + base branch exist, else rebase-ff. Defaults to `auto`."
3878
+ },
3879
+ "prTitle": {
3880
+ "type": "string",
3881
+ "description": "merge (pr strategy) only — PR title. Defaults to the last commit subject."
3882
+ },
3883
+ "prBody": {
3884
+ "type": "string",
3885
+ "description": "merge (pr strategy) only — PR body."
3886
+ },
3887
+ "deleteBranch": {
3888
+ "type": "boolean",
3889
+ "description": "merge only — delete the agent branch + remove the worktree after a successful rebase-ff. Defaults to true."
3569
3890
  },
3570
3891
  "agentId": {
3571
- "type": "string"
3892
+ "type": "string",
3893
+ "description": "Optional agent id recorded as the actor."
3572
3894
  },
3573
3895
  "detail": {
3574
- "type": "string"
3575
- },
3576
- "metadata": {
3577
- "type": "string"
3896
+ "type": "string",
3897
+ "description": "Optional human-readable note."
3578
3898
  }
3579
3899
  }
3580
3900
  }
@@ -3583,40 +3903,19 @@
3583
3903
  },
3584
3904
  "responses": {
3585
3905
  "200": {
3586
- "description": "Success",
3587
- "content": {
3588
- "application/json": {}
3589
- }
3906
+ "description": "State updated (non-command actions)."
3907
+ },
3908
+ "202": {
3909
+ "description": "Accepted — a `merge`/`cleanup` command was created and emitted on the bus. Final workspace status is reconciled from the command result."
3590
3910
  },
3591
3911
  "400": {
3592
- "description": "Bad request",
3593
- "content": {
3594
- "application/json": {
3595
- "schema": {
3596
- "$ref": "#/components/schemas/Error"
3597
- }
3598
- }
3599
- }
3912
+ "description": "Invalid body or unknown action."
3600
3913
  },
3601
3914
  "404": {
3602
- "description": "Not found",
3603
- "content": {
3604
- "application/json": {
3605
- "schema": {
3606
- "$ref": "#/components/schemas/Error"
3607
- }
3608
- }
3609
- }
3915
+ "description": "Workspace not found."
3610
3916
  },
3611
3917
  "409": {
3612
- "description": "Conflict",
3613
- "content": {
3614
- "application/json": {
3615
- "schema": {
3616
- "$ref": "#/components/schemas/Error"
3617
- }
3618
- }
3619
- }
3918
+ "description": "No online orchestrator owns the workspace path."
3620
3919
  }
3621
3920
  },
3622
3921
  "security": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-relay-server",
3
- "version": "0.10.20",
3
+ "version": "0.10.21",
4
4
  "description": "Lightweight HTTP message relay for inter-agent communication across machines",
5
5
  "module": "src/index.ts",
6
6
  "type": "module",
@@ -32,7 +32,7 @@
32
32
  "CONTRIBUTING.md"
33
33
  ],
34
34
  "dependencies": {
35
- "agent-relay-sdk": "0.2.1"
35
+ "agent-relay-sdk": "0.2.2"
36
36
  },
37
37
  "scripts": {
38
38
  "postinstall": "node scripts/install-bin-shim.cjs",