@astroanywhere/agent 0.1.0

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.
Files changed (203) hide show
  1. package/LICENSE +76 -0
  2. package/README.md +178 -0
  3. package/dist/cli.d.ts +15 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +401 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/commands/index.d.ts +9 -0
  8. package/dist/commands/index.d.ts.map +1 -0
  9. package/dist/commands/index.js +9 -0
  10. package/dist/commands/index.js.map +1 -0
  11. package/dist/commands/mcp.d.ts +16 -0
  12. package/dist/commands/mcp.d.ts.map +1 -0
  13. package/dist/commands/mcp.js +19 -0
  14. package/dist/commands/mcp.js.map +1 -0
  15. package/dist/commands/setup.d.ts +20 -0
  16. package/dist/commands/setup.d.ts.map +1 -0
  17. package/dist/commands/setup.js +585 -0
  18. package/dist/commands/setup.js.map +1 -0
  19. package/dist/commands/start.d.ts +16 -0
  20. package/dist/commands/start.d.ts.map +1 -0
  21. package/dist/commands/start.js +638 -0
  22. package/dist/commands/start.js.map +1 -0
  23. package/dist/commands/status.d.ts +5 -0
  24. package/dist/commands/status.d.ts.map +1 -0
  25. package/dist/commands/status.js +63 -0
  26. package/dist/commands/status.js.map +1 -0
  27. package/dist/commands/stop.d.ts +5 -0
  28. package/dist/commands/stop.d.ts.map +1 -0
  29. package/dist/commands/stop.js +85 -0
  30. package/dist/commands/stop.js.map +1 -0
  31. package/dist/execution/direct-strategy.d.ts +18 -0
  32. package/dist/execution/direct-strategy.d.ts.map +1 -0
  33. package/dist/execution/direct-strategy.js +156 -0
  34. package/dist/execution/direct-strategy.js.map +1 -0
  35. package/dist/execution/docker-strategy.d.ts +26 -0
  36. package/dist/execution/docker-strategy.d.ts.map +1 -0
  37. package/dist/execution/docker-strategy.js +222 -0
  38. package/dist/execution/docker-strategy.js.map +1 -0
  39. package/dist/execution/index.d.ts +14 -0
  40. package/dist/execution/index.d.ts.map +1 -0
  41. package/dist/execution/index.js +13 -0
  42. package/dist/execution/index.js.map +1 -0
  43. package/dist/execution/kubernetes-exec-strategy.d.ts +23 -0
  44. package/dist/execution/kubernetes-exec-strategy.d.ts.map +1 -0
  45. package/dist/execution/kubernetes-exec-strategy.js +232 -0
  46. package/dist/execution/kubernetes-exec-strategy.js.map +1 -0
  47. package/dist/execution/registry.d.ts +41 -0
  48. package/dist/execution/registry.d.ts.map +1 -0
  49. package/dist/execution/registry.js +84 -0
  50. package/dist/execution/registry.js.map +1 -0
  51. package/dist/execution/slurm-strategy.d.ts +22 -0
  52. package/dist/execution/slurm-strategy.d.ts.map +1 -0
  53. package/dist/execution/slurm-strategy.js +219 -0
  54. package/dist/execution/slurm-strategy.js.map +1 -0
  55. package/dist/execution/types.d.ts +72 -0
  56. package/dist/execution/types.d.ts.map +1 -0
  57. package/dist/execution/types.js +10 -0
  58. package/dist/execution/types.js.map +1 -0
  59. package/dist/index.d.ts +22 -0
  60. package/dist/index.d.ts.map +1 -0
  61. package/dist/index.js +22 -0
  62. package/dist/index.js.map +1 -0
  63. package/dist/lib/api-client.d.ts +35 -0
  64. package/dist/lib/api-client.d.ts.map +1 -0
  65. package/dist/lib/api-client.js +126 -0
  66. package/dist/lib/api-client.js.map +1 -0
  67. package/dist/lib/config.d.ts +174 -0
  68. package/dist/lib/config.d.ts.map +1 -0
  69. package/dist/lib/config.js +399 -0
  70. package/dist/lib/config.js.map +1 -0
  71. package/dist/lib/copy-worktree.d.ts +73 -0
  72. package/dist/lib/copy-worktree.d.ts.map +1 -0
  73. package/dist/lib/copy-worktree.js +374 -0
  74. package/dist/lib/copy-worktree.js.map +1 -0
  75. package/dist/lib/git-pr.d.ts +63 -0
  76. package/dist/lib/git-pr.d.ts.map +1 -0
  77. package/dist/lib/git-pr.js +224 -0
  78. package/dist/lib/git-pr.js.map +1 -0
  79. package/dist/lib/hardware-id.d.ts +25 -0
  80. package/dist/lib/hardware-id.d.ts.map +1 -0
  81. package/dist/lib/hardware-id.js +186 -0
  82. package/dist/lib/hardware-id.js.map +1 -0
  83. package/dist/lib/hpc-context.d.ts +35 -0
  84. package/dist/lib/hpc-context.d.ts.map +1 -0
  85. package/dist/lib/hpc-context.js +167 -0
  86. package/dist/lib/hpc-context.js.map +1 -0
  87. package/dist/lib/prompt-templates.d.ts +195 -0
  88. package/dist/lib/prompt-templates.d.ts.map +1 -0
  89. package/dist/lib/prompt-templates.js +353 -0
  90. package/dist/lib/prompt-templates.js.map +1 -0
  91. package/dist/lib/providers.d.ts +27 -0
  92. package/dist/lib/providers.d.ts.map +1 -0
  93. package/dist/lib/providers.js +372 -0
  94. package/dist/lib/providers.js.map +1 -0
  95. package/dist/lib/repo-context.d.ts +18 -0
  96. package/dist/lib/repo-context.d.ts.map +1 -0
  97. package/dist/lib/repo-context.js +61 -0
  98. package/dist/lib/repo-context.js.map +1 -0
  99. package/dist/lib/repo-utils.d.ts +35 -0
  100. package/dist/lib/repo-utils.d.ts.map +1 -0
  101. package/dist/lib/repo-utils.js +222 -0
  102. package/dist/lib/repo-utils.js.map +1 -0
  103. package/dist/lib/resources.d.ts +17 -0
  104. package/dist/lib/resources.d.ts.map +1 -0
  105. package/dist/lib/resources.js +227 -0
  106. package/dist/lib/resources.js.map +1 -0
  107. package/dist/lib/slurm-detect.d.ts +15 -0
  108. package/dist/lib/slurm-detect.d.ts.map +1 -0
  109. package/dist/lib/slurm-detect.js +148 -0
  110. package/dist/lib/slurm-detect.js.map +1 -0
  111. package/dist/lib/slurm-executor.d.ts +70 -0
  112. package/dist/lib/slurm-executor.d.ts.map +1 -0
  113. package/dist/lib/slurm-executor.js +402 -0
  114. package/dist/lib/slurm-executor.js.map +1 -0
  115. package/dist/lib/slurm-job-monitor.d.ts +52 -0
  116. package/dist/lib/slurm-job-monitor.d.ts.map +1 -0
  117. package/dist/lib/slurm-job-monitor.js +212 -0
  118. package/dist/lib/slurm-job-monitor.js.map +1 -0
  119. package/dist/lib/ssh-discovery.d.ts +17 -0
  120. package/dist/lib/ssh-discovery.d.ts.map +1 -0
  121. package/dist/lib/ssh-discovery.js +287 -0
  122. package/dist/lib/ssh-discovery.js.map +1 -0
  123. package/dist/lib/ssh-installer.d.ts +69 -0
  124. package/dist/lib/ssh-installer.d.ts.map +1 -0
  125. package/dist/lib/ssh-installer.js +230 -0
  126. package/dist/lib/ssh-installer.js.map +1 -0
  127. package/dist/lib/streaming-prompt.d.ts +48 -0
  128. package/dist/lib/streaming-prompt.d.ts.map +1 -0
  129. package/dist/lib/streaming-prompt.js +91 -0
  130. package/dist/lib/streaming-prompt.js.map +1 -0
  131. package/dist/lib/task-executor.d.ts +114 -0
  132. package/dist/lib/task-executor.d.ts.map +1 -0
  133. package/dist/lib/task-executor.js +753 -0
  134. package/dist/lib/task-executor.js.map +1 -0
  135. package/dist/lib/websocket-client.d.ts +200 -0
  136. package/dist/lib/websocket-client.d.ts.map +1 -0
  137. package/dist/lib/websocket-client.js +781 -0
  138. package/dist/lib/websocket-client.js.map +1 -0
  139. package/dist/lib/workdir-safety.d.ts +63 -0
  140. package/dist/lib/workdir-safety.d.ts.map +1 -0
  141. package/dist/lib/workdir-safety.js +247 -0
  142. package/dist/lib/workdir-safety.js.map +1 -0
  143. package/dist/lib/worktree-include.d.ts +14 -0
  144. package/dist/lib/worktree-include.d.ts.map +1 -0
  145. package/dist/lib/worktree-include.js +68 -0
  146. package/dist/lib/worktree-include.js.map +1 -0
  147. package/dist/lib/worktree-setup.d.ts +18 -0
  148. package/dist/lib/worktree-setup.d.ts.map +1 -0
  149. package/dist/lib/worktree-setup.js +60 -0
  150. package/dist/lib/worktree-setup.js.map +1 -0
  151. package/dist/lib/worktree.d.ts +37 -0
  152. package/dist/lib/worktree.d.ts.map +1 -0
  153. package/dist/lib/worktree.js +411 -0
  154. package/dist/lib/worktree.js.map +1 -0
  155. package/dist/mcp/index.d.ts +8 -0
  156. package/dist/mcp/index.d.ts.map +1 -0
  157. package/dist/mcp/index.js +8 -0
  158. package/dist/mcp/index.js.map +1 -0
  159. package/dist/mcp/server.d.ts +45 -0
  160. package/dist/mcp/server.d.ts.map +1 -0
  161. package/dist/mcp/server.js +153 -0
  162. package/dist/mcp/server.js.map +1 -0
  163. package/dist/mcp/session-bridge.d.ts +87 -0
  164. package/dist/mcp/session-bridge.d.ts.map +1 -0
  165. package/dist/mcp/session-bridge.js +317 -0
  166. package/dist/mcp/session-bridge.js.map +1 -0
  167. package/dist/mcp/tools.d.ts +70 -0
  168. package/dist/mcp/tools.d.ts.map +1 -0
  169. package/dist/mcp/tools.js +234 -0
  170. package/dist/mcp/tools.js.map +1 -0
  171. package/dist/mcp/types.d.ts +197 -0
  172. package/dist/mcp/types.d.ts.map +1 -0
  173. package/dist/mcp/types.js +16 -0
  174. package/dist/mcp/types.js.map +1 -0
  175. package/dist/providers/base-adapter.d.ts +56 -0
  176. package/dist/providers/base-adapter.d.ts.map +1 -0
  177. package/dist/providers/base-adapter.js +5 -0
  178. package/dist/providers/base-adapter.js.map +1 -0
  179. package/dist/providers/claude-code-adapter.d.ts +27 -0
  180. package/dist/providers/claude-code-adapter.d.ts.map +1 -0
  181. package/dist/providers/claude-code-adapter.js +298 -0
  182. package/dist/providers/claude-code-adapter.js.map +1 -0
  183. package/dist/providers/claude-sdk-adapter.d.ts +60 -0
  184. package/dist/providers/claude-sdk-adapter.d.ts.map +1 -0
  185. package/dist/providers/claude-sdk-adapter.js +632 -0
  186. package/dist/providers/claude-sdk-adapter.js.map +1 -0
  187. package/dist/providers/codex-adapter.d.ts +21 -0
  188. package/dist/providers/codex-adapter.d.ts.map +1 -0
  189. package/dist/providers/codex-adapter.js +197 -0
  190. package/dist/providers/codex-adapter.js.map +1 -0
  191. package/dist/providers/index.d.ts +26 -0
  192. package/dist/providers/index.d.ts.map +1 -0
  193. package/dist/providers/index.js +58 -0
  194. package/dist/providers/index.js.map +1 -0
  195. package/dist/providers/slurm-adapter.d.ts +26 -0
  196. package/dist/providers/slurm-adapter.d.ts.map +1 -0
  197. package/dist/providers/slurm-adapter.js +146 -0
  198. package/dist/providers/slurm-adapter.js.map +1 -0
  199. package/dist/types.d.ts +592 -0
  200. package/dist/types.d.ts.map +1 -0
  201. package/dist/types.js +5 -0
  202. package/dist/types.js.map +1 -0
  203. package/package.json +77 -0
package/LICENSE ADDED
@@ -0,0 +1,76 @@
1
+ Business Source License 1.1
2
+
3
+ License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved.
4
+ “Business Source License” is a trademark of MariaDB Corporation Ab.
5
+
6
+ -----------------------------------------------------------------------------
7
+
8
+ Parameters
9
+
10
+ Licensor: Xi Fu, Zhuoran Yang
11
+
12
+ Licensed Work: astro-agent
13
+
14
+ Additional Use Grant: None
15
+
16
+ Change Date: 2030-02-23
17
+
18
+ Change License: Apache License, Version 2.0
19
+
20
+ -----------------------------------------------------------------------------
21
+
22
+ Terms
23
+
24
+ The Licensor hereby grants you the right to copy, modify, create derivative
25
+ works, redistribute, and make non-production use of the Licensed Work. The
26
+ Licensor may make an Additional Use Grant, above, permitting limited
27
+ production use.
28
+
29
+ Effective on the Change Date, or the fourth anniversary of the first publicly
30
+ available distribution of a specific version of the Licensed Work under this
31
+ License, whichever comes first, the Licensor hereby grants you rights under
32
+ the terms of the Change License, and the rights granted in the paragraph above
33
+ terminate.
34
+
35
+ If your use of the Licensed Work does not comply with the requirements
36
+ currently in effect as described in this License, you must purchase a
37
+ commercial license from the Licensor, its affiliated entities, or authorized
38
+ resellers, or you must refrain from using the Licensed Work.
39
+
40
+ All copies of the original and modified Licensed Work, and derivative works of
41
+ the Licensed Work, are subject to this License. This License applies
42
+ separately for each version of the Licensed Work and the Change Date may vary
43
+ for each version of the Licensed Work.
44
+
45
+ You must conspicuously display this License on each copy of the Licensed Work,
46
+ and you must retain the copyright notice for the Licensed Work in this License.
47
+
48
+ -----------------------------------------------------------------------------
49
+
50
+ Covenants of Licensor
51
+
52
+ In consideration of the right to use the Licensed Work granted to you by the
53
+ Licensor under this License, you covenant not to institute litigation against
54
+ the Licensor or any other licensee of the Licensed Work for patent
55
+ infringement claims arising from the Licensed Work. This covenant shall not
56
+ apply to claims that the Licensed Work infringes a patent that you own or
57
+ control, or to claims of patent infringement by combinations of the Licensed
58
+ Work with other software or hardware.
59
+
60
+ -----------------------------------------------------------------------------
61
+
62
+ Notice
63
+
64
+ This License does not grant you any right in any trademark or logo of Licensor
65
+ or its affiliates (provided that you may use a trademark or logo of Licensor
66
+ as expressly required by this License).
67
+
68
+ TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON AN
69
+ “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
70
+ EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
71
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
72
+ TITLE.
73
+
74
+ MariaDB hereby grants you permission to use this License’s text to license
75
+ your works, and to refer to it using the trademark “Business Source License”,
76
+ as long as you comply with the Covenants of Licensor above.
package/README.md ADDED
@@ -0,0 +1,178 @@
1
+ <h1 align="center">Astro Agent Runner</h1>
2
+ <p align="center">
3
+ <strong>Connect your machines. Let AI do the work.</strong>
4
+ <br />
5
+ <br />
6
+ <a href="https://www.npmjs.com/package/@astro/agent"><img src="https://img.shields.io/npm/v/@astro/agent?style=flat-square&color=0a0a1a&labelColor=0a0a1a&logo=npm&logoColor=white" alt="npm version"></a>
7
+ <a href="https://www.npmjs.com/package/@astro/agent"><img src="https://img.shields.io/npm/dm/@astro/agent?style=flat-square&color=0a0a1a&labelColor=0a0a1a&logo=npm&logoColor=white" alt="npm downloads"></a>
8
+ <a href="https://nodejs.org"><img src="https://img.shields.io/badge/node-%3E%3D18-0a0a1a?style=flat-square&labelColor=0a0a1a&logo=node.js&logoColor=white" alt="node version"></a>
9
+ <a href="./LICENSE"><img src="https://img.shields.io/badge/license-BSL--1.1-0a0a1a?style=flat-square&labelColor=0a0a1a" alt="license"></a>
10
+ <br />
11
+ <br />
12
+ <a href="https://astroanywhere.com/landing/">Website</a>
13
+ &nbsp;&middot;&nbsp;
14
+ <a href="https://astroanywhere.com">Dashboard</a>
15
+ &nbsp;&middot;&nbsp;
16
+ <a href="#install">Get Started</a>
17
+ <br />
18
+ <br />
19
+ </p>
20
+
21
+ ---
22
+
23
+ ## What is Astro?
24
+
25
+ [**Astro**](https://astroanywhere.com/landing/) is mission control for the AI age. It turns ambitious goals into dependency graphs, dispatches tasks across your machines in parallel, and surfaces the decisions that need you.
26
+
27
+ You plan in the browser. Your machines do the work. The **Agent Runner** is the piece that runs on your machines — it receives tasks, executes AI agents (Claude, Codex), and streams results back.
28
+
29
+ > **Self-hosting** is on the roadmap. Currently Astro runs as a hosted service at [astroanywhere.com](https://astroanywhere.com).
30
+
31
+ ## Prerequisites
32
+
33
+ Create an account at [astroanywhere.com](https://astroanywhere.com) &mdash; you'll need it to authenticate your machines.
34
+
35
+ ## Install
36
+
37
+ ```bash
38
+ npx @astro/agent launch
39
+ ```
40
+
41
+ One command. It detects your AI providers, finds your SSH hosts, authenticates you, sets up everything, and starts listening for tasks.
42
+
43
+ No global install. `npx` fetches the latest version.
44
+
45
+ ## What Happens
46
+
47
+ ```
48
+ $ npx @astro/agent launch
49
+
50
+ Detecting providers... claude-sdk, claude-code
51
+ Discovering SSH hosts... found 3: lab-gpu, hpc-login, aws-dev
52
+
53
+ To authenticate, open this URL in your browser:
54
+
55
+ https://astroanywhere.com/device?code=ABCD-1234
56
+
57
+ Waiting for approval...
58
+ ✓ Authenticated as you@example.com
59
+ ✓ Machine "my_laptop" registered
60
+
61
+ Installing on remote hosts...
62
+ ✓ lab-gpu: installed and started
63
+ ✓ hpc-login: installed and started
64
+ ✓ aws-dev: installed and started
65
+
66
+ Remote agents: 3 running, 0 failed
67
+ ✓ Connected to relay
68
+
69
+ Ready. Listening for tasks...
70
+ ```
71
+
72
+ Your laptop and all remote hosts appear in Astro's **Environments** page. Dispatch tasks to any of them.
73
+
74
+ ## What You Get with Astro Anywhere
75
+
76
+ | | Feature | |
77
+ |---|---|---|
78
+ | **Plan** | Describe a goal &rarr; Astro breaks it into a dependency graph | Graph, List, Timeline views |
79
+ | **Execute** | Dispatch to any machine &mdash; laptop, server, HPC | Parallel, isolated branches |
80
+ | **Monitor** | Real-time agent output, tool calls, file changes | Live streaming |
81
+ | **Decide** | Approve, reject, or redirect from any device | No terminal needed |
82
+ | **Ship** | PRs created automatically per task | Branch-per-task isolation |
83
+ | **Scale** | Multi-machine routing by load & capability | SSH config auto-discovery |
84
+
85
+ ## What the Agent Runner Does
86
+
87
+ When you execute a task in Astro, it lands on one of your machines. The agent runner:
88
+
89
+ - Creates an isolated git branch for the task
90
+ - Runs Claude (or Codex) with your project's full context
91
+ - Streams progress back to the Astro UI in real time
92
+ - Commits changes, pushes the branch, and opens a PR
93
+
94
+ Multiple tasks run in parallel &mdash; each on its own branch, no conflicts.
95
+
96
+ Your API keys stay on your machine. Astro never sees them.
97
+
98
+ ## Commands
99
+
100
+ ```bash
101
+ # First time — set up everything and start
102
+ npx @astro/agent launch
103
+
104
+ # Local only, skip SSH host discovery
105
+ npx @astro/agent launch --no-ssh-config
106
+
107
+ # Start (already set up)
108
+ npx @astro/agent start -f
109
+
110
+ # Stop
111
+ npx @astro/agent stop
112
+
113
+ # Check what's running
114
+ npx @astro/agent status
115
+
116
+ # Set up Claude authentication
117
+ npx @astro/agent auth
118
+
119
+ # View or change settings
120
+ npx @astro/agent config --show
121
+ npx @astro/agent config --set maxTasks=8
122
+ ```
123
+
124
+ ## Remote Machines
125
+
126
+ `launch` reads your `~/.ssh/config`, discovers hosts, installs the agent runner over SSH, and starts them &mdash; all from your laptop.
127
+
128
+ To set up a single remote machine manually, SSH in and run:
129
+
130
+ ```bash
131
+ npx @astro/agent launch --no-ssh-config
132
+ ```
133
+
134
+ Astro picks the best available machine for each task based on load and capabilities.
135
+
136
+ ## AI Providers
137
+
138
+ Auto-detected. No configuration needed if any of these are installed:
139
+
140
+ | Provider | How to Enable |
141
+ |---|---|
142
+ | **Claude SDK** | Run `astro-agent auth` or set `ANTHROPIC_API_KEY` |
143
+ | **Claude Code** | Install [Claude Code](https://claude.ai/code) |
144
+ | **Codex** | Install Codex CLI |
145
+
146
+ ## MCP Integration
147
+
148
+ Use the agent runner as an MCP server inside Claude Code:
149
+
150
+ ```bash
151
+ npx @astro/agent mcp
152
+ ```
153
+
154
+ This gives Claude Code access to Astro tools &mdash; attach to tasks, send updates, check status.
155
+
156
+ ## Configuration
157
+
158
+ Stored at `~/.config/astro-agent/config.json`. Most users never need to touch this.
159
+
160
+ | Setting | Default | Description |
161
+ |---|---|---|
162
+ | `maxTasks` | `4` | Max concurrent tasks |
163
+ | `logLevel` | `info` | Logging verbosity |
164
+ | `autoStart` | `false` | Start on login |
165
+
166
+ ## Environment Variables
167
+
168
+ | Variable | Description |
169
+ |---|---|
170
+ | `ANTHROPIC_API_KEY` | Claude API key (alternative to OAuth) |
171
+ | `ASTRO_MACHINE_NAME` | Custom machine name |
172
+ | `ASTRO_LOG_LEVEL` | Override log level |
173
+
174
+ ---
175
+
176
+ <p align="center">
177
+ <a href="https://astroanywhere.com/landing/">astroanywhere.com</a>
178
+ </p>
package/dist/cli.d.ts ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Astro Agent Runner CLI
4
+ *
5
+ * Lightweight agent runner for local, remote, and HPC environments.
6
+ * Connects to the Astro relay server to receive and execute tasks.
7
+ *
8
+ * Usage:
9
+ * npx @astro/agent setup - Initial setup and configuration
10
+ * npx @astro/agent start - Start the agent runner
11
+ * npx @astro/agent stop - Stop running agent
12
+ * npx @astro/agent status - Show current status
13
+ */
14
+ export {};
15
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;GAWG"}
package/dist/cli.js ADDED
@@ -0,0 +1,401 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Astro Agent Runner CLI
4
+ *
5
+ * Lightweight agent runner for local, remote, and HPC environments.
6
+ * Connects to the Astro relay server to receive and execute tasks.
7
+ *
8
+ * Usage:
9
+ * npx @astro/agent setup - Initial setup and configuration
10
+ * npx @astro/agent start - Start the agent runner
11
+ * npx @astro/agent stop - Stop running agent
12
+ * npx @astro/agent status - Show current status
13
+ */
14
+ import { Command } from 'commander';
15
+ import { setupCommand, startCommand, statusCommand, stopCommand, mcpCommand } from './commands/index.js';
16
+ const program = new Command();
17
+ program
18
+ .name('astro-agent')
19
+ .description('Astro Agent Runner - Execute tasks from the Astro planning platform')
20
+ .version('0.1.0');
21
+ // Setup command
22
+ program
23
+ .command('setup')
24
+ .description('Run initial setup: detect providers, authenticate, configure relay')
25
+ .option('--api <url>', 'API server URL')
26
+ .option('--relay <url>', 'Custom relay server URL')
27
+ .option('--hostname <hostname>', 'Machine hostname (defaults to system hostname)')
28
+ .option('--skip-auth', 'Skip device authentication')
29
+ .option('--non-interactive', 'Run in non-interactive mode')
30
+ .option('--with-ssh-config', 'Discover and configure remote hosts from SSH config')
31
+ .option('--auto-start', 'Enable auto-start on login')
32
+ .option('--install-mcp', 'Install MCP integration for Claude Code')
33
+ .action(async (options) => {
34
+ try {
35
+ await setupCommand({
36
+ api: options.api,
37
+ relay: options.relay,
38
+ hostname: options.hostname,
39
+ skipAuth: options.skipAuth,
40
+ nonInteractive: options.nonInteractive,
41
+ withSshConfig: options.withSshConfig,
42
+ autoStart: options.autoStart,
43
+ installMcp: options.installMcp,
44
+ });
45
+ }
46
+ catch (error) {
47
+ console.error('Setup failed:', error instanceof Error ? error.message : String(error));
48
+ process.exit(1);
49
+ }
50
+ });
51
+ // Start command
52
+ program
53
+ .command('start')
54
+ .description('Start the agent runner')
55
+ .option('-f, --foreground', 'Run in foreground (default: background)')
56
+ .option('--relay <url>', 'Override relay server URL')
57
+ .option('--max-tasks <number>', 'Maximum concurrent tasks', parseInt)
58
+ .option('--log-level <level>', 'Log level: debug, info, warn, error')
59
+ .option('--preserve-worktrees', 'Preserve worktrees after task completion (for debugging)')
60
+ .option('--allow-non-git', 'Allow execution in non-git directories without prompting')
61
+ .option('--sandbox', 'Always use sandbox mode (work on copies)')
62
+ .option('--max-sandbox-size <mb>', 'Maximum sandbox size in MB (default: 100)', parseInt)
63
+ .action(async (options) => {
64
+ try {
65
+ await startCommand({
66
+ foreground: options.foreground,
67
+ relay: options.relay,
68
+ maxTasks: options.maxTasks,
69
+ logLevel: options.logLevel,
70
+ preserveWorktrees: options.preserveWorktrees,
71
+ allowNonGit: options.allowNonGit,
72
+ useSandbox: options.sandbox,
73
+ maxSandboxSize: options.maxSandboxSize ? options.maxSandboxSize * 1024 * 1024 : undefined,
74
+ });
75
+ }
76
+ catch (error) {
77
+ console.error('Start failed:', error instanceof Error ? error.message : String(error));
78
+ process.exit(1);
79
+ }
80
+ });
81
+ // Connect command (alias for start --foreground)
82
+ program
83
+ .command('connect')
84
+ .description('Connect to relay server in foreground (alias for start --foreground)')
85
+ .option('--relay <url>', 'Override relay server URL')
86
+ .option('--max-tasks <number>', 'Maximum concurrent tasks', parseInt)
87
+ .option('--log-level <level>', 'Log level: debug, info, warn, error')
88
+ .option('--preserve-worktrees', 'Preserve worktrees after task completion (for debugging)')
89
+ .option('--allow-non-git', 'Allow execution in non-git directories without prompting')
90
+ .option('--sandbox', 'Always use sandbox mode (work on copies)')
91
+ .option('--max-sandbox-size <mb>', 'Maximum sandbox size in MB (default: 100)', parseInt)
92
+ .action(async (options) => {
93
+ try {
94
+ await startCommand({
95
+ foreground: true,
96
+ relay: options.relay,
97
+ maxTasks: options.maxTasks,
98
+ logLevel: options.logLevel,
99
+ preserveWorktrees: options.preserveWorktrees,
100
+ allowNonGit: options.allowNonGit,
101
+ useSandbox: options.sandbox,
102
+ maxSandboxSize: options.maxSandboxSize ? options.maxSandboxSize * 1024 * 1024 : undefined,
103
+ });
104
+ }
105
+ catch (error) {
106
+ console.error('Connect failed:', error instanceof Error ? error.message : String(error));
107
+ process.exit(1);
108
+ }
109
+ });
110
+ // Stop command
111
+ program
112
+ .command('stop')
113
+ .description('Stop the running agent')
114
+ .action(async () => {
115
+ try {
116
+ await stopCommand();
117
+ }
118
+ catch (error) {
119
+ console.error('Stop failed:', error instanceof Error ? error.message : String(error));
120
+ process.exit(1);
121
+ }
122
+ });
123
+ // Status command
124
+ program
125
+ .command('status')
126
+ .description('Show agent runner status')
127
+ .action(async () => {
128
+ try {
129
+ await statusCommand();
130
+ }
131
+ catch (error) {
132
+ console.error('Status check failed:', error instanceof Error ? error.message : String(error));
133
+ process.exit(1);
134
+ }
135
+ });
136
+ // Auth command (set Claude OAuth token)
137
+ program
138
+ .command('auth')
139
+ .description('Set Claude OAuth token for agent SDK authentication')
140
+ .option('--token <token>', 'Set token directly (from `claude setup-token` output)')
141
+ .option('--clear', 'Clear stored token')
142
+ .action(async (options) => {
143
+ const { config } = await import('./lib/config.js');
144
+ const chalk = (await import('chalk')).default;
145
+ if (options.clear) {
146
+ config.clearClaudeOauthToken();
147
+ console.log(chalk.green('✓ Claude OAuth token cleared'));
148
+ return;
149
+ }
150
+ if (options.token) {
151
+ config.setClaudeOauthToken(options.token);
152
+ console.log(chalk.green('✓ Claude OAuth token saved'));
153
+ console.log(chalk.dim(' Token will be used automatically when the agent starts'));
154
+ return;
155
+ }
156
+ // Interactive: prompt for token
157
+ const inquirer = (await import('inquirer')).default;
158
+ console.log(chalk.bold('\nClaude SDK Authentication\n'));
159
+ console.log(chalk.dim('Generate a long-lived token by running:'));
160
+ console.log(chalk.cyan(' claude setup-token\n'));
161
+ console.log(chalk.dim('Then paste the token below:\n'));
162
+ const { token } = await inquirer.prompt([
163
+ {
164
+ type: 'password',
165
+ name: 'token',
166
+ message: 'Paste your Claude OAuth token:',
167
+ },
168
+ ]);
169
+ if (token && token.trim().length > 10) {
170
+ config.setClaudeOauthToken(token.trim());
171
+ console.log(chalk.green('\n✓ Claude OAuth token saved'));
172
+ console.log(chalk.dim(' Restart the agent runner to apply'));
173
+ }
174
+ else {
175
+ console.log(chalk.yellow('No token provided'));
176
+ }
177
+ });
178
+ // Config command (show/edit config)
179
+ program
180
+ .command('config')
181
+ .description('Show or modify configuration')
182
+ .option('--show', 'Show current configuration')
183
+ .option('--reset', 'Reset configuration to defaults')
184
+ .option('--set <key=value>', 'Set a configuration value')
185
+ .action(async (options) => {
186
+ const { config } = await import('./lib/config.js');
187
+ if (options.reset) {
188
+ config.reset();
189
+ console.log('Configuration reset to defaults.');
190
+ return;
191
+ }
192
+ if (options.set) {
193
+ const [key, value] = options.set.split('=');
194
+ if (!key || value === undefined) {
195
+ console.error('Invalid format. Use: --set key=value');
196
+ process.exit(1);
197
+ }
198
+ switch (key) {
199
+ case 'api':
200
+ case 'apiUrl':
201
+ config.setApiUrl(value);
202
+ console.log(`Set API URL to: ${value}`);
203
+ break;
204
+ case 'relay':
205
+ case 'relayUrl':
206
+ config.setRelayUrl(value);
207
+ console.log(`Set relay URL to: ${value}`);
208
+ break;
209
+ case 'accessToken':
210
+ config.setAccessToken(value);
211
+ console.log('Set access token');
212
+ break;
213
+ case 'refreshToken':
214
+ config.setRefreshToken(value);
215
+ console.log('Set refresh token');
216
+ break;
217
+ case 'wsToken':
218
+ config.setWsToken(value);
219
+ console.log('Set WebSocket token');
220
+ break;
221
+ case 'machineId':
222
+ config.setMachineId(value);
223
+ console.log(`Set machine ID to: ${value}`);
224
+ break;
225
+ case 'logLevel':
226
+ if (!['debug', 'info', 'warn', 'error'].includes(value)) {
227
+ console.error('Invalid log level. Use: debug, info, warn, error');
228
+ process.exit(1);
229
+ }
230
+ config.setLogLevel(value);
231
+ console.log(`Set log level to: ${value}`);
232
+ break;
233
+ case 'claudeOauthToken':
234
+ config.setClaudeOauthToken(value);
235
+ console.log('Set Claude OAuth token');
236
+ break;
237
+ case 'autoStart':
238
+ config.setAutoStart(value === 'true');
239
+ console.log(`Set auto-start to: ${value}`);
240
+ break;
241
+ default:
242
+ console.error(`Unknown configuration key: ${key}`);
243
+ console.log('Available keys: apiUrl, relayUrl, accessToken, refreshToken, wsToken, claudeOauthToken, machineId, logLevel, autoStart');
244
+ process.exit(1);
245
+ }
246
+ return;
247
+ }
248
+ // Show configuration (default)
249
+ const currentConfig = config.getConfig();
250
+ console.log('\nCurrent Configuration:\n');
251
+ console.log(` Runner ID: ${currentConfig.runnerId || '(not set)'}`);
252
+ console.log(` Machine ID: ${currentConfig.machineId || '(not set)'}`);
253
+ console.log(` API URL: ${currentConfig.apiUrl}`);
254
+ console.log(` Relay URL: ${currentConfig.relayUrl}`);
255
+ console.log(` Auto-start: ${currentConfig.autoStart}`);
256
+ console.log(` Log level: ${currentConfig.logLevel}`);
257
+ console.log(` Providers: ${currentConfig.providers.length > 0 ? currentConfig.providers.join(', ') : '(none)'}`);
258
+ console.log(` Access token: ${currentConfig.accessToken ? 'configured' : 'not configured'}`);
259
+ console.log(` WS token: ${currentConfig.wsToken ? 'configured' : 'not configured'}`);
260
+ console.log(` Claude auth: ${config.getClaudeOauthToken() ? 'OAuth token configured' : process.env.ANTHROPIC_API_KEY ? 'API key (env)' : 'not configured'}`);
261
+ console.log(`\n Config file: ${config.getConfigPath()}`);
262
+ console.log();
263
+ });
264
+ // Providers command (list detected providers)
265
+ program
266
+ .command('providers')
267
+ .description('List detected agent providers')
268
+ .action(async () => {
269
+ const { detectProviders, formatProvidersSummary } = await import('./lib/providers.js');
270
+ console.log('\nDetecting agent providers...\n');
271
+ const providers = await detectProviders();
272
+ console.log(formatProvidersSummary(providers));
273
+ console.log();
274
+ });
275
+ // Resources command (show machine resources)
276
+ program
277
+ .command('resources')
278
+ .description('Show machine resources (CPU, memory, GPU)')
279
+ .action(async () => {
280
+ const { getMachineResources, formatResourceSummary } = await import('./lib/resources.js');
281
+ console.log('\nDetecting machine resources...\n');
282
+ const resources = await getMachineResources();
283
+ console.log(formatResourceSummary(resources));
284
+ console.log();
285
+ });
286
+ // Hosts command (discover SSH hosts)
287
+ program
288
+ .command('hosts')
289
+ .description('Discover remote hosts from SSH config')
290
+ .action(async () => {
291
+ const { discoverRemoteHosts, formatDiscoveredHosts } = await import('./lib/ssh-discovery.js');
292
+ console.log('\nDiscovering remote hosts...\n');
293
+ const hosts = await discoverRemoteHosts();
294
+ console.log(formatDiscoveredHosts(hosts));
295
+ });
296
+ // Launch command (setup + start in one step)
297
+ program
298
+ .command('launch')
299
+ .description('Setup (if needed) and start the agent runner in one step')
300
+ .option('--api <url>', 'API server URL')
301
+ .option('--relay <url>', 'Override relay server URL')
302
+ .option('--hostname <hostname>', 'Machine hostname')
303
+ .option('--skip-auth', 'Skip device authentication')
304
+ .option('--max-tasks <number>', 'Maximum concurrent tasks', parseInt)
305
+ .option('--log-level <level>', 'Log level: debug, info, warn, error')
306
+ .option('--force-setup', 'Force re-run setup even if already configured')
307
+ .option('--preserve-worktrees', 'Preserve worktrees after task completion')
308
+ .option('--allow-non-git', 'Allow execution in non-git directories without prompting')
309
+ .option('--sandbox', 'Always use sandbox mode')
310
+ .option('--max-sandbox-size <mb>', 'Maximum sandbox size in MB (default: 100)', parseInt)
311
+ .option('--no-ssh-config', 'Skip SSH host discovery (enabled by default)')
312
+ .option('--no-launch-all', 'Skip starting agents on remote hosts (enabled by default)')
313
+ .action(async (options) => {
314
+ try {
315
+ const { config } = await import('./lib/config.js');
316
+ const chalk = (await import('chalk')).default;
317
+ // SSH config discovery and launch-all are ON by default; --no-ssh-config / --no-launch-all disable them
318
+ const withSshConfig = options.sshConfig !== false;
319
+ const launchAll = options.launchAll !== false && withSshConfig;
320
+ let remoteHosts = [];
321
+ if (options.forceSetup || !config.isSetupComplete()) {
322
+ const result = await setupCommand({
323
+ api: options.api,
324
+ relay: options.relay,
325
+ hostname: options.hostname,
326
+ skipAuth: options.skipAuth,
327
+ withSshConfig,
328
+ returnInstalledHosts: launchAll,
329
+ });
330
+ if (launchAll && result.installedHosts) {
331
+ remoteHosts = result.installedHosts;
332
+ }
333
+ }
334
+ else if (launchAll) {
335
+ // Setup already complete — read stored remote hosts
336
+ remoteHosts = config.getRemoteHosts();
337
+ if (remoteHosts.length === 0) {
338
+ console.log(chalk.yellow('\nNo remote hosts configured. Run with --force-setup to discover SSH hosts.\n'));
339
+ }
340
+ }
341
+ // Start remote agents before starting local
342
+ if (launchAll && remoteHosts.length > 0) {
343
+ const { startRemoteAgents } = await import('./lib/ssh-installer.js');
344
+ console.log(chalk.bold(`\nStarting agents on ${remoteHosts.length} remote host(s)...\n`));
345
+ const results = await startRemoteAgents(remoteHosts, {
346
+ maxTasks: options.maxTasks,
347
+ logLevel: options.logLevel,
348
+ preserveWorktrees: options.preserveWorktrees,
349
+ }, (host, msg) => console.log(chalk.dim(` [${host}] ${msg}`)));
350
+ // Report results
351
+ for (const r of results) {
352
+ if (r.success) {
353
+ const tag = r.alreadyRunning ? 'already running' : 'started';
354
+ console.log(chalk.green(` ✓ ${r.host.name}: ${tag}`));
355
+ }
356
+ else {
357
+ console.log(chalk.red(` ✗ ${r.host.name}: ${r.message}`));
358
+ }
359
+ }
360
+ const ok = results.filter((r) => r.success).length;
361
+ const fail = results.filter((r) => !r.success).length;
362
+ console.log(chalk.dim(`\n Remote agents: ${ok} running, ${fail} failed\n`));
363
+ }
364
+ // Start local agent
365
+ await startCommand({
366
+ foreground: true,
367
+ relay: options.relay,
368
+ maxTasks: options.maxTasks,
369
+ logLevel: options.logLevel,
370
+ preserveWorktrees: options.preserveWorktrees,
371
+ allowNonGit: options.allowNonGit,
372
+ useSandbox: options.sandbox,
373
+ maxSandboxSize: options.maxSandboxSize ? options.maxSandboxSize * 1024 * 1024 : undefined,
374
+ });
375
+ }
376
+ catch (error) {
377
+ console.error('Launch failed:', error instanceof Error ? error.message : String(error));
378
+ process.exit(1);
379
+ }
380
+ });
381
+ // MCP command (start MCP server for Claude Code integration)
382
+ program
383
+ .command('mcp')
384
+ .description('Start MCP server for Claude Code integration (stdio mode)')
385
+ .option('--relay <url>', 'Override relay server URL')
386
+ .option('--log-level <level>', 'Log level: debug, info, warn, error', 'info')
387
+ .action(async (options) => {
388
+ try {
389
+ await mcpCommand({
390
+ relay: options.relay,
391
+ logLevel: options.logLevel,
392
+ });
393
+ }
394
+ catch (error) {
395
+ console.error('MCP server error:', error instanceof Error ? error.message : String(error));
396
+ process.exit(1);
397
+ }
398
+ });
399
+ // Parse arguments
400
+ program.parse();
401
+ //# sourceMappingURL=cli.js.map