@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.
- package/LICENSE +76 -0
- package/README.md +178 -0
- package/dist/cli.d.ts +15 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +401 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/index.d.ts +9 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +9 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/mcp.d.ts +16 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/mcp.js +19 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/setup.d.ts +20 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +585 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/start.d.ts +16 -0
- package/dist/commands/start.d.ts.map +1 -0
- package/dist/commands/start.js +638 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/commands/status.d.ts +5 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +63 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/stop.d.ts +5 -0
- package/dist/commands/stop.d.ts.map +1 -0
- package/dist/commands/stop.js +85 -0
- package/dist/commands/stop.js.map +1 -0
- package/dist/execution/direct-strategy.d.ts +18 -0
- package/dist/execution/direct-strategy.d.ts.map +1 -0
- package/dist/execution/direct-strategy.js +156 -0
- package/dist/execution/direct-strategy.js.map +1 -0
- package/dist/execution/docker-strategy.d.ts +26 -0
- package/dist/execution/docker-strategy.d.ts.map +1 -0
- package/dist/execution/docker-strategy.js +222 -0
- package/dist/execution/docker-strategy.js.map +1 -0
- package/dist/execution/index.d.ts +14 -0
- package/dist/execution/index.d.ts.map +1 -0
- package/dist/execution/index.js +13 -0
- package/dist/execution/index.js.map +1 -0
- package/dist/execution/kubernetes-exec-strategy.d.ts +23 -0
- package/dist/execution/kubernetes-exec-strategy.d.ts.map +1 -0
- package/dist/execution/kubernetes-exec-strategy.js +232 -0
- package/dist/execution/kubernetes-exec-strategy.js.map +1 -0
- package/dist/execution/registry.d.ts +41 -0
- package/dist/execution/registry.d.ts.map +1 -0
- package/dist/execution/registry.js +84 -0
- package/dist/execution/registry.js.map +1 -0
- package/dist/execution/slurm-strategy.d.ts +22 -0
- package/dist/execution/slurm-strategy.d.ts.map +1 -0
- package/dist/execution/slurm-strategy.js +219 -0
- package/dist/execution/slurm-strategy.js.map +1 -0
- package/dist/execution/types.d.ts +72 -0
- package/dist/execution/types.d.ts.map +1 -0
- package/dist/execution/types.js +10 -0
- package/dist/execution/types.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/api-client.d.ts +35 -0
- package/dist/lib/api-client.d.ts.map +1 -0
- package/dist/lib/api-client.js +126 -0
- package/dist/lib/api-client.js.map +1 -0
- package/dist/lib/config.d.ts +174 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +399 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/copy-worktree.d.ts +73 -0
- package/dist/lib/copy-worktree.d.ts.map +1 -0
- package/dist/lib/copy-worktree.js +374 -0
- package/dist/lib/copy-worktree.js.map +1 -0
- package/dist/lib/git-pr.d.ts +63 -0
- package/dist/lib/git-pr.d.ts.map +1 -0
- package/dist/lib/git-pr.js +224 -0
- package/dist/lib/git-pr.js.map +1 -0
- package/dist/lib/hardware-id.d.ts +25 -0
- package/dist/lib/hardware-id.d.ts.map +1 -0
- package/dist/lib/hardware-id.js +186 -0
- package/dist/lib/hardware-id.js.map +1 -0
- package/dist/lib/hpc-context.d.ts +35 -0
- package/dist/lib/hpc-context.d.ts.map +1 -0
- package/dist/lib/hpc-context.js +167 -0
- package/dist/lib/hpc-context.js.map +1 -0
- package/dist/lib/prompt-templates.d.ts +195 -0
- package/dist/lib/prompt-templates.d.ts.map +1 -0
- package/dist/lib/prompt-templates.js +353 -0
- package/dist/lib/prompt-templates.js.map +1 -0
- package/dist/lib/providers.d.ts +27 -0
- package/dist/lib/providers.d.ts.map +1 -0
- package/dist/lib/providers.js +372 -0
- package/dist/lib/providers.js.map +1 -0
- package/dist/lib/repo-context.d.ts +18 -0
- package/dist/lib/repo-context.d.ts.map +1 -0
- package/dist/lib/repo-context.js +61 -0
- package/dist/lib/repo-context.js.map +1 -0
- package/dist/lib/repo-utils.d.ts +35 -0
- package/dist/lib/repo-utils.d.ts.map +1 -0
- package/dist/lib/repo-utils.js +222 -0
- package/dist/lib/repo-utils.js.map +1 -0
- package/dist/lib/resources.d.ts +17 -0
- package/dist/lib/resources.d.ts.map +1 -0
- package/dist/lib/resources.js +227 -0
- package/dist/lib/resources.js.map +1 -0
- package/dist/lib/slurm-detect.d.ts +15 -0
- package/dist/lib/slurm-detect.d.ts.map +1 -0
- package/dist/lib/slurm-detect.js +148 -0
- package/dist/lib/slurm-detect.js.map +1 -0
- package/dist/lib/slurm-executor.d.ts +70 -0
- package/dist/lib/slurm-executor.d.ts.map +1 -0
- package/dist/lib/slurm-executor.js +402 -0
- package/dist/lib/slurm-executor.js.map +1 -0
- package/dist/lib/slurm-job-monitor.d.ts +52 -0
- package/dist/lib/slurm-job-monitor.d.ts.map +1 -0
- package/dist/lib/slurm-job-monitor.js +212 -0
- package/dist/lib/slurm-job-monitor.js.map +1 -0
- package/dist/lib/ssh-discovery.d.ts +17 -0
- package/dist/lib/ssh-discovery.d.ts.map +1 -0
- package/dist/lib/ssh-discovery.js +287 -0
- package/dist/lib/ssh-discovery.js.map +1 -0
- package/dist/lib/ssh-installer.d.ts +69 -0
- package/dist/lib/ssh-installer.d.ts.map +1 -0
- package/dist/lib/ssh-installer.js +230 -0
- package/dist/lib/ssh-installer.js.map +1 -0
- package/dist/lib/streaming-prompt.d.ts +48 -0
- package/dist/lib/streaming-prompt.d.ts.map +1 -0
- package/dist/lib/streaming-prompt.js +91 -0
- package/dist/lib/streaming-prompt.js.map +1 -0
- package/dist/lib/task-executor.d.ts +114 -0
- package/dist/lib/task-executor.d.ts.map +1 -0
- package/dist/lib/task-executor.js +753 -0
- package/dist/lib/task-executor.js.map +1 -0
- package/dist/lib/websocket-client.d.ts +200 -0
- package/dist/lib/websocket-client.d.ts.map +1 -0
- package/dist/lib/websocket-client.js +781 -0
- package/dist/lib/websocket-client.js.map +1 -0
- package/dist/lib/workdir-safety.d.ts +63 -0
- package/dist/lib/workdir-safety.d.ts.map +1 -0
- package/dist/lib/workdir-safety.js +247 -0
- package/dist/lib/workdir-safety.js.map +1 -0
- package/dist/lib/worktree-include.d.ts +14 -0
- package/dist/lib/worktree-include.d.ts.map +1 -0
- package/dist/lib/worktree-include.js +68 -0
- package/dist/lib/worktree-include.js.map +1 -0
- package/dist/lib/worktree-setup.d.ts +18 -0
- package/dist/lib/worktree-setup.d.ts.map +1 -0
- package/dist/lib/worktree-setup.js +60 -0
- package/dist/lib/worktree-setup.js.map +1 -0
- package/dist/lib/worktree.d.ts +37 -0
- package/dist/lib/worktree.d.ts.map +1 -0
- package/dist/lib/worktree.js +411 -0
- package/dist/lib/worktree.js.map +1 -0
- package/dist/mcp/index.d.ts +8 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +8 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/server.d.ts +45 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +153 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/session-bridge.d.ts +87 -0
- package/dist/mcp/session-bridge.d.ts.map +1 -0
- package/dist/mcp/session-bridge.js +317 -0
- package/dist/mcp/session-bridge.js.map +1 -0
- package/dist/mcp/tools.d.ts +70 -0
- package/dist/mcp/tools.d.ts.map +1 -0
- package/dist/mcp/tools.js +234 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/mcp/types.d.ts +197 -0
- package/dist/mcp/types.d.ts.map +1 -0
- package/dist/mcp/types.js +16 -0
- package/dist/mcp/types.js.map +1 -0
- package/dist/providers/base-adapter.d.ts +56 -0
- package/dist/providers/base-adapter.d.ts.map +1 -0
- package/dist/providers/base-adapter.js +5 -0
- package/dist/providers/base-adapter.js.map +1 -0
- package/dist/providers/claude-code-adapter.d.ts +27 -0
- package/dist/providers/claude-code-adapter.d.ts.map +1 -0
- package/dist/providers/claude-code-adapter.js +298 -0
- package/dist/providers/claude-code-adapter.js.map +1 -0
- package/dist/providers/claude-sdk-adapter.d.ts +60 -0
- package/dist/providers/claude-sdk-adapter.d.ts.map +1 -0
- package/dist/providers/claude-sdk-adapter.js +632 -0
- package/dist/providers/claude-sdk-adapter.js.map +1 -0
- package/dist/providers/codex-adapter.d.ts +21 -0
- package/dist/providers/codex-adapter.d.ts.map +1 -0
- package/dist/providers/codex-adapter.js +197 -0
- package/dist/providers/codex-adapter.js.map +1 -0
- package/dist/providers/index.d.ts +26 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +58 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/slurm-adapter.d.ts +26 -0
- package/dist/providers/slurm-adapter.d.ts.map +1 -0
- package/dist/providers/slurm-adapter.js +146 -0
- package/dist/providers/slurm-adapter.js.map +1 -0
- package/dist/types.d.ts +592 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +77 -0
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slurm Job Monitor
|
|
3
|
+
*
|
|
4
|
+
* Background poller that tracks submitted Slurm batch jobs (sbatch).
|
|
5
|
+
* Monitors job status via sacct and streams updates through the
|
|
6
|
+
* existing WebSocket relay protocol.
|
|
7
|
+
*/
|
|
8
|
+
import { execFile } from 'node:child_process';
|
|
9
|
+
import { promisify } from 'node:util';
|
|
10
|
+
import { open, stat } from 'node:fs/promises';
|
|
11
|
+
import { readFile } from 'node:fs/promises';
|
|
12
|
+
const execFileAsync = promisify(execFile);
|
|
13
|
+
/** SLURM job IDs are numeric (optionally with array syntax like 12345_1). Validates and returns. */
|
|
14
|
+
function sanitizedSlurmJobId(id) {
|
|
15
|
+
if (!/^\d+(_\d+)?$/.test(id)) {
|
|
16
|
+
throw new Error(`Invalid SLURM job ID (possible command injection): ${id}`);
|
|
17
|
+
}
|
|
18
|
+
return id;
|
|
19
|
+
}
|
|
20
|
+
/** Terminal Slurm states */
|
|
21
|
+
const TERMINAL_STATES = new Set([
|
|
22
|
+
'COMPLETED', 'FAILED', 'CANCELLED', 'TIMEOUT',
|
|
23
|
+
'PREEMPTED', 'NODE_FAIL', 'OUT_OF_MEMORY',
|
|
24
|
+
]);
|
|
25
|
+
export class SlurmJobMonitor {
|
|
26
|
+
jobs = new Map();
|
|
27
|
+
pollInterval = null;
|
|
28
|
+
wsClient;
|
|
29
|
+
pollIntervalMs;
|
|
30
|
+
constructor(wsClient, pollIntervalMs = 30_000) {
|
|
31
|
+
this.wsClient = wsClient;
|
|
32
|
+
this.pollIntervalMs = pollIntervalMs;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Track a submitted Slurm job
|
|
36
|
+
*/
|
|
37
|
+
trackJob(slurmJobId, executionId, nodeId, outputPath) {
|
|
38
|
+
console.log(`[slurm-monitor] Tracking job ${slurmJobId} for task ${executionId}`);
|
|
39
|
+
this.jobs.set(slurmJobId, {
|
|
40
|
+
slurmJobId,
|
|
41
|
+
executionId,
|
|
42
|
+
nodeId,
|
|
43
|
+
outputPath,
|
|
44
|
+
lastOutputOffset: 0,
|
|
45
|
+
stdoutSequence: 0,
|
|
46
|
+
trackingSince: new Date(),
|
|
47
|
+
});
|
|
48
|
+
// Start polling if not already running
|
|
49
|
+
if (!this.pollInterval) {
|
|
50
|
+
this.start();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Stop tracking a job
|
|
55
|
+
*/
|
|
56
|
+
untrackJob(slurmJobId) {
|
|
57
|
+
this.jobs.delete(slurmJobId);
|
|
58
|
+
if (this.jobs.size === 0) {
|
|
59
|
+
this.stop();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Check if any jobs are being tracked
|
|
64
|
+
*/
|
|
65
|
+
hasTrackedJobs() {
|
|
66
|
+
return this.jobs.size > 0;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Get tracked job IDs for a given execution
|
|
70
|
+
*/
|
|
71
|
+
getJobsForExecution(executionId) {
|
|
72
|
+
return Array.from(this.jobs.values())
|
|
73
|
+
.filter((j) => j.executionId === executionId)
|
|
74
|
+
.map((j) => j.slurmJobId);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Start the polling loop
|
|
78
|
+
*/
|
|
79
|
+
start() {
|
|
80
|
+
if (this.pollInterval)
|
|
81
|
+
return;
|
|
82
|
+
console.log(`[slurm-monitor] Starting poll loop (${this.pollIntervalMs}ms)`);
|
|
83
|
+
// Immediate first poll so we don't wait a full interval before checking
|
|
84
|
+
this.pollAll().catch((err) => {
|
|
85
|
+
console.error('[slurm-monitor] Poll error:', err);
|
|
86
|
+
});
|
|
87
|
+
this.pollInterval = setInterval(() => {
|
|
88
|
+
this.pollAll().catch((err) => {
|
|
89
|
+
console.error('[slurm-monitor] Poll error:', err);
|
|
90
|
+
});
|
|
91
|
+
}, this.pollIntervalMs);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Stop the polling loop
|
|
95
|
+
*/
|
|
96
|
+
stop() {
|
|
97
|
+
if (this.pollInterval) {
|
|
98
|
+
clearInterval(this.pollInterval);
|
|
99
|
+
this.pollInterval = null;
|
|
100
|
+
console.log('[slurm-monitor] Stopped poll loop');
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Poll all tracked jobs
|
|
105
|
+
*/
|
|
106
|
+
async pollAll() {
|
|
107
|
+
for (const [jobId, job] of this.jobs) {
|
|
108
|
+
try {
|
|
109
|
+
await this.pollJob(job);
|
|
110
|
+
}
|
|
111
|
+
catch (err) {
|
|
112
|
+
console.error(`[slurm-monitor] Error polling job ${jobId}:`, err);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Poll a single job's status via sacct
|
|
118
|
+
*/
|
|
119
|
+
async pollJob(job) {
|
|
120
|
+
const { slurmJobId, executionId } = job;
|
|
121
|
+
let state = 'UNKNOWN';
|
|
122
|
+
let exitCode;
|
|
123
|
+
let elapsed;
|
|
124
|
+
try {
|
|
125
|
+
const { stdout } = await execFileAsync('sacct', ['-j', sanitizedSlurmJobId(slurmJobId), '--format=State,ExitCode,Elapsed', '-n', '-P'], { timeout: 10_000 });
|
|
126
|
+
// sacct can return multiple lines (job + job.batch steps)
|
|
127
|
+
// Take the first line (main job)
|
|
128
|
+
const firstLine = stdout.trim().split('\n')[0];
|
|
129
|
+
if (firstLine) {
|
|
130
|
+
const parts = firstLine.split('|');
|
|
131
|
+
state = (parts[0] || 'UNKNOWN').replace(/\+$/, ''); // Remove trailing + from CANCELLED+
|
|
132
|
+
const exitParts = (parts[1] || '').split(':');
|
|
133
|
+
exitCode = parseInt(exitParts[0]) || undefined;
|
|
134
|
+
elapsed = parts[2] || undefined;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
// sacct not available or job not yet visible
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
// Report state changes
|
|
142
|
+
if (state !== job.lastState) {
|
|
143
|
+
job.lastState = state;
|
|
144
|
+
if (TERMINAL_STATES.has(state)) {
|
|
145
|
+
// Job finished — send result
|
|
146
|
+
const isSuccess = state === 'COMPLETED' && (!exitCode || exitCode === 0);
|
|
147
|
+
// Try to read final output
|
|
148
|
+
let output;
|
|
149
|
+
if (job.outputPath) {
|
|
150
|
+
try {
|
|
151
|
+
output = await readFile(job.outputPath, 'utf-8');
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
// Output file not accessible
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
const result = {
|
|
158
|
+
taskId: executionId,
|
|
159
|
+
status: isSuccess ? 'completed' : 'failed',
|
|
160
|
+
exitCode: exitCode ?? (isSuccess ? 0 : 1),
|
|
161
|
+
output: output || `Slurm job ${slurmJobId}: ${state}${elapsed ? ` (${elapsed})` : ''}`,
|
|
162
|
+
error: isSuccess ? undefined : `Slurm job ${state}`,
|
|
163
|
+
completedAt: new Date().toISOString(),
|
|
164
|
+
};
|
|
165
|
+
this.wsClient.sendTaskResult(result);
|
|
166
|
+
console.log(`[slurm-monitor] Job ${slurmJobId} terminal: ${state}`);
|
|
167
|
+
this.untrackJob(slurmJobId);
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
// Non-terminal state change — send progress
|
|
171
|
+
const progress = state === 'RUNNING' ? 50 : state === 'PENDING' ? 10 : 25;
|
|
172
|
+
const message = `Slurm job ${slurmJobId}: ${state}${elapsed ? ` (${elapsed})` : ''}`;
|
|
173
|
+
this.wsClient.sendTaskStatus(executionId, 'running', progress, message);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// Stream output file content if running
|
|
177
|
+
if (state === 'RUNNING' && job.outputPath) {
|
|
178
|
+
await this.streamOutput(job);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Stream new output from the job's output file
|
|
183
|
+
*/
|
|
184
|
+
async streamOutput(job) {
|
|
185
|
+
if (!job.outputPath)
|
|
186
|
+
return;
|
|
187
|
+
try {
|
|
188
|
+
const fileStat = await stat(job.outputPath);
|
|
189
|
+
if (fileStat.size <= job.lastOutputOffset)
|
|
190
|
+
return;
|
|
191
|
+
// Read only the new bytes to avoid byte/character offset mismatch
|
|
192
|
+
const bytesToRead = fileStat.size - job.lastOutputOffset;
|
|
193
|
+
const fd = await open(job.outputPath, 'r');
|
|
194
|
+
try {
|
|
195
|
+
const buffer = Buffer.alloc(bytesToRead);
|
|
196
|
+
await fd.read(buffer, 0, bytesToRead, job.lastOutputOffset);
|
|
197
|
+
job.lastOutputOffset = fileStat.size;
|
|
198
|
+
const newContent = buffer.toString('utf-8');
|
|
199
|
+
if (newContent.length > 0) {
|
|
200
|
+
this.wsClient.sendTaskOutput(job.executionId, 'stdout', newContent, job.stdoutSequence++);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
finally {
|
|
204
|
+
await fd.close();
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
// File not yet created or not accessible
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
//# sourceMappingURL=slurm-job-monitor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slurm-job-monitor.js","sourceRoot":"","sources":["../../src/lib/slurm-job-monitor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSH config discovery for remote host detection
|
|
3
|
+
*/
|
|
4
|
+
import type { DiscoveredHost } from '../types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Discover all remote hosts from various sources
|
|
7
|
+
*/
|
|
8
|
+
export declare function discoverRemoteHosts(): Promise<DiscoveredHost[]>;
|
|
9
|
+
/**
|
|
10
|
+
* Format discovered hosts for display
|
|
11
|
+
*/
|
|
12
|
+
export declare function formatDiscoveredHosts(hosts: DiscoveredHost[]): string;
|
|
13
|
+
/**
|
|
14
|
+
* Build SSH command for connecting to a host
|
|
15
|
+
*/
|
|
16
|
+
export declare function buildSSHCommand(host: DiscoveredHost, command?: string): string;
|
|
17
|
+
//# sourceMappingURL=ssh-discovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssh-discovery.d.ts","sourceRoot":"","sources":["../../src/lib/ssh-discovery.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAW,cAAc,EAAE,MAAM,aAAa,CAAC;AA2N3D;;GAEG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC,CAmDrE;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,MAAM,CAsCrE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAuB9E"}
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSH config discovery for remote host detection
|
|
3
|
+
*/
|
|
4
|
+
import { readFile } from 'node:fs/promises';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { homedir } from 'node:os';
|
|
7
|
+
/**
|
|
8
|
+
* Parse SSH config file and extract host configurations
|
|
9
|
+
*/
|
|
10
|
+
async function parseSSHConfig() {
|
|
11
|
+
const sshConfigPath = join(homedir(), '.ssh', 'config');
|
|
12
|
+
console.log(`[ssh-discovery] Parsing SSH config from: ${sshConfigPath}`);
|
|
13
|
+
try {
|
|
14
|
+
const content = await readFile(sshConfigPath, 'utf-8');
|
|
15
|
+
const hosts = [];
|
|
16
|
+
let currentHost = null;
|
|
17
|
+
let skippedCount = 0;
|
|
18
|
+
for (const line of content.split('\n')) {
|
|
19
|
+
const trimmed = line.trim();
|
|
20
|
+
// Skip comments and empty lines
|
|
21
|
+
if (!trimmed || trimmed.startsWith('#')) {
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
// Parse key-value pair
|
|
25
|
+
const match = trimmed.match(/^(\S+)\s+(.+)$/);
|
|
26
|
+
if (!match)
|
|
27
|
+
continue;
|
|
28
|
+
const [, key, value] = match;
|
|
29
|
+
const keyLower = key?.toLowerCase();
|
|
30
|
+
if (keyLower === 'host') {
|
|
31
|
+
// Save previous host if exists
|
|
32
|
+
if (currentHost) {
|
|
33
|
+
hosts.push(currentHost);
|
|
34
|
+
console.log(`[ssh-discovery] ✓ Added host: ${currentHost.name} (${currentHost.hostname})`);
|
|
35
|
+
}
|
|
36
|
+
const hostPattern = value?.trim() ?? '';
|
|
37
|
+
// Skip wildcard patterns and local-only patterns
|
|
38
|
+
if (hostPattern.includes('*') ||
|
|
39
|
+
hostPattern === 'localhost' ||
|
|
40
|
+
hostPattern === '127.0.0.1') {
|
|
41
|
+
console.log(`[ssh-discovery] ⊗ Skipped pattern/localhost: ${hostPattern}`);
|
|
42
|
+
skippedCount++;
|
|
43
|
+
currentHost = null;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
currentHost = {
|
|
47
|
+
name: hostPattern,
|
|
48
|
+
hostname: hostPattern, // Default to the host alias
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
else if (currentHost && value) {
|
|
52
|
+
switch (keyLower) {
|
|
53
|
+
case 'hostname':
|
|
54
|
+
currentHost.hostname = value.trim();
|
|
55
|
+
break;
|
|
56
|
+
case 'user':
|
|
57
|
+
currentHost.user = value.trim();
|
|
58
|
+
break;
|
|
59
|
+
case 'port':
|
|
60
|
+
currentHost.port = parseInt(value.trim(), 10);
|
|
61
|
+
break;
|
|
62
|
+
case 'identityfile':
|
|
63
|
+
currentHost.identityFile = value.trim().replace('~', homedir());
|
|
64
|
+
break;
|
|
65
|
+
case 'proxyjump':
|
|
66
|
+
currentHost.proxyJump = value.trim();
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// Don't forget the last host
|
|
72
|
+
if (currentHost) {
|
|
73
|
+
hosts.push(currentHost);
|
|
74
|
+
console.log(`[ssh-discovery] ✓ Added host: ${currentHost.name} (${currentHost.hostname})`);
|
|
75
|
+
}
|
|
76
|
+
console.log(`[ssh-discovery] Parsed ${hosts.length} valid hosts (skipped ${skippedCount} wildcards/localhost)`);
|
|
77
|
+
return hosts;
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
// SSH config doesn't exist or can't be read
|
|
81
|
+
if (error.code === 'ENOENT') {
|
|
82
|
+
console.log(`[ssh-discovery] No SSH config file found at ${sshConfigPath}`);
|
|
83
|
+
return [];
|
|
84
|
+
}
|
|
85
|
+
console.error(`[ssh-discovery] Error reading SSH config:`, error);
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Discover VS Code Remote SSH tunnel configurations
|
|
91
|
+
*/
|
|
92
|
+
async function discoverVSCodeTunnels() {
|
|
93
|
+
const hosts = [];
|
|
94
|
+
// VS Code stores remote configurations in different locations based on platform
|
|
95
|
+
const vscodeConfigPaths = [
|
|
96
|
+
join(homedir(), '.vscode-server', 'data', 'Machine', 'settings.json'),
|
|
97
|
+
join(homedir(), '.vscode', 'globalStorage', 'ms-vscode-remote.remote-ssh', 'hosts.json'),
|
|
98
|
+
join(homedir(), 'Library', 'Application Support', 'Code', 'User', 'globalStorage', 'ms-vscode-remote.remote-ssh', 'hosts.json'),
|
|
99
|
+
join(homedir(), '.config', 'Code', 'User', 'globalStorage', 'ms-vscode-remote.remote-ssh', 'hosts.json'),
|
|
100
|
+
];
|
|
101
|
+
for (const configPath of vscodeConfigPaths) {
|
|
102
|
+
try {
|
|
103
|
+
const content = await readFile(configPath, 'utf-8');
|
|
104
|
+
const config = JSON.parse(content);
|
|
105
|
+
// Handle different VS Code config formats
|
|
106
|
+
if (Array.isArray(config)) {
|
|
107
|
+
for (const entry of config) {
|
|
108
|
+
if (entry.host && entry.hostName) {
|
|
109
|
+
hosts.push({
|
|
110
|
+
name: entry.host,
|
|
111
|
+
hostname: entry.hostName,
|
|
112
|
+
user: entry.user,
|
|
113
|
+
port: entry.port,
|
|
114
|
+
identityFile: entry.identityFile,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else if (config.remote?.SSH?.remotePlatform) {
|
|
120
|
+
// Newer VS Code format
|
|
121
|
+
for (const hostName of Object.keys(config.remote.SSH.remotePlatform)) {
|
|
122
|
+
if (!hosts.some((h) => h.name === hostName)) {
|
|
123
|
+
hosts.push({
|
|
124
|
+
name: hostName,
|
|
125
|
+
hostname: hostName,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
// Config doesn't exist or is invalid, continue to next path
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return hosts;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Parse known_hosts file to find additional hosts
|
|
140
|
+
*/
|
|
141
|
+
async function parseKnownHosts() {
|
|
142
|
+
const knownHostsPath = join(homedir(), '.ssh', 'known_hosts');
|
|
143
|
+
try {
|
|
144
|
+
const content = await readFile(knownHostsPath, 'utf-8');
|
|
145
|
+
const hostnames = new Set();
|
|
146
|
+
for (const line of content.split('\n')) {
|
|
147
|
+
if (!line.trim() || line.startsWith('#')) {
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
// Known hosts format: hostname[,hostname,...] keytype key [comment]
|
|
151
|
+
const hostPart = line.split(' ')[0];
|
|
152
|
+
if (!hostPart) {
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
// Split by comma for multiple hostnames on same line
|
|
156
|
+
for (let hostname of hostPart.split(',')) {
|
|
157
|
+
// Remove port if present (e.g., [hostname]:port)
|
|
158
|
+
hostname = hostname.replace(/^\[(.+)\]:\d+$/, '$1');
|
|
159
|
+
// Skip IP addresses and localhost
|
|
160
|
+
if (hostname.match(/^\d+\.\d+\.\d+\.\d+$/) ||
|
|
161
|
+
hostname === 'localhost' ||
|
|
162
|
+
hostname === '127.0.0.1') {
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
// Skip hashed hostnames (start with |)
|
|
166
|
+
if (hostname.startsWith('|')) {
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
hostnames.add(hostname);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return Array.from(hostnames);
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
return [];
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Discover all remote hosts from various sources
|
|
180
|
+
*/
|
|
181
|
+
export async function discoverRemoteHosts() {
|
|
182
|
+
console.log('[ssh-discovery] Starting remote host discovery...');
|
|
183
|
+
const discovered = [];
|
|
184
|
+
const seenHosts = new Set();
|
|
185
|
+
// Parse SSH config (highest priority)
|
|
186
|
+
console.log('[ssh-discovery] 1/3 Checking SSH config (~/.ssh/config)...');
|
|
187
|
+
const sshHosts = await parseSSHConfig();
|
|
188
|
+
for (const host of sshHosts) {
|
|
189
|
+
seenHosts.add(host.name);
|
|
190
|
+
discovered.push({
|
|
191
|
+
...host,
|
|
192
|
+
source: 'ssh-config',
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
console.log(`[ssh-discovery] Found ${sshHosts.length} hosts from SSH config`);
|
|
196
|
+
// Discover VS Code tunnels
|
|
197
|
+
console.log('[ssh-discovery] 2/3 Checking VS Code Remote SSH...');
|
|
198
|
+
const vscodeTunnels = await discoverVSCodeTunnels();
|
|
199
|
+
for (const host of vscodeTunnels) {
|
|
200
|
+
if (!seenHosts.has(host.name)) {
|
|
201
|
+
seenHosts.add(host.name);
|
|
202
|
+
discovered.push({
|
|
203
|
+
...host,
|
|
204
|
+
source: 'vscode-tunnel',
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
console.log(`[ssh-discovery] Found ${vscodeTunnels.length} unique VS Code hosts`);
|
|
209
|
+
// Parse known_hosts (lowest priority - just suggests hostnames)
|
|
210
|
+
console.log('[ssh-discovery] 3/3 Checking known_hosts...');
|
|
211
|
+
const knownHostnames = await parseKnownHosts();
|
|
212
|
+
let knownHostsAdded = 0;
|
|
213
|
+
for (const hostname of knownHostnames) {
|
|
214
|
+
if (!seenHosts.has(hostname)) {
|
|
215
|
+
seenHosts.add(hostname);
|
|
216
|
+
discovered.push({
|
|
217
|
+
name: hostname,
|
|
218
|
+
hostname,
|
|
219
|
+
source: 'known-hosts',
|
|
220
|
+
});
|
|
221
|
+
knownHostsAdded++;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
console.log(`[ssh-discovery] Found ${knownHostsAdded} unique hosts from known_hosts`);
|
|
225
|
+
console.log(`[ssh-discovery] Discovery complete: ${discovered.length} total unique hosts`);
|
|
226
|
+
return discovered;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Format discovered hosts for display
|
|
230
|
+
*/
|
|
231
|
+
export function formatDiscoveredHosts(hosts) {
|
|
232
|
+
if (hosts.length === 0) {
|
|
233
|
+
return 'No remote hosts discovered.';
|
|
234
|
+
}
|
|
235
|
+
const lines = ['Discovered Remote Hosts:', ''];
|
|
236
|
+
// Group by source
|
|
237
|
+
const bySource = new Map();
|
|
238
|
+
for (const host of hosts) {
|
|
239
|
+
const existing = bySource.get(host.source) ?? [];
|
|
240
|
+
existing.push(host);
|
|
241
|
+
bySource.set(host.source, existing);
|
|
242
|
+
}
|
|
243
|
+
const sourceLabels = {
|
|
244
|
+
'ssh-config': 'From SSH config (~/.ssh/config):',
|
|
245
|
+
'vscode-tunnel': 'From VS Code Remote SSH:',
|
|
246
|
+
'known-hosts': 'From known hosts:',
|
|
247
|
+
};
|
|
248
|
+
for (const [source, sourceHosts] of bySource) {
|
|
249
|
+
lines.push(` ${sourceLabels[source] ?? source}`);
|
|
250
|
+
for (const host of sourceHosts) {
|
|
251
|
+
const details = [];
|
|
252
|
+
if (host.user)
|
|
253
|
+
details.push(`user: ${host.user}`);
|
|
254
|
+
if (host.port && host.port !== 22)
|
|
255
|
+
details.push(`port: ${host.port}`);
|
|
256
|
+
if (host.proxyJump)
|
|
257
|
+
details.push(`via: ${host.proxyJump}`);
|
|
258
|
+
const detailStr = details.length > 0 ? ` (${details.join(', ')})` : '';
|
|
259
|
+
const targetStr = host.hostname !== host.name ? ` → ${host.hostname}` : '';
|
|
260
|
+
lines.push(` • ${host.name}${targetStr}${detailStr}`);
|
|
261
|
+
}
|
|
262
|
+
lines.push('');
|
|
263
|
+
}
|
|
264
|
+
return lines.join('\n');
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Build SSH command for connecting to a host
|
|
268
|
+
*/
|
|
269
|
+
export function buildSSHCommand(host, command) {
|
|
270
|
+
const parts = ['ssh'];
|
|
271
|
+
if (host.port && host.port !== 22) {
|
|
272
|
+
parts.push('-p', String(host.port));
|
|
273
|
+
}
|
|
274
|
+
if (host.identityFile) {
|
|
275
|
+
parts.push('-i', host.identityFile);
|
|
276
|
+
}
|
|
277
|
+
if (host.proxyJump) {
|
|
278
|
+
parts.push('-J', host.proxyJump);
|
|
279
|
+
}
|
|
280
|
+
const target = host.user ? `${host.user}@${host.hostname}` : host.hostname;
|
|
281
|
+
parts.push(target);
|
|
282
|
+
if (command) {
|
|
283
|
+
parts.push(command);
|
|
284
|
+
}
|
|
285
|
+
return parts.join(' ');
|
|
286
|
+
}
|
|
287
|
+
//# sourceMappingURL=ssh-discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssh-discovery.js","sourceRoot":"","sources":["../../src/lib/ssh-discovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Remote SSH installation utilities for local dev.
|
|
3
|
+
*
|
|
4
|
+
* Packs the agent-runner locally, SCPs it to the target host,
|
|
5
|
+
* installs via npm, and pushes pre-provisioned tokens so the
|
|
6
|
+
* remote host skips its own device auth entirely.
|
|
7
|
+
*/
|
|
8
|
+
import type { DiscoveredHost } from '../types.js';
|
|
9
|
+
/**
|
|
10
|
+
* Detect the LAN IP of this machine so remote hosts can reach the dev server.
|
|
11
|
+
* Returns the first non-internal IPv4 address found.
|
|
12
|
+
*/
|
|
13
|
+
export declare function detectLocalIP(): string;
|
|
14
|
+
/**
|
|
15
|
+
* SSH to a host and check whether Node.js ≥ 18 is available.
|
|
16
|
+
* Returns { available, version } or throws on SSH failure.
|
|
17
|
+
*/
|
|
18
|
+
export declare function checkRemoteNode(host: DiscoveredHost): Promise<{
|
|
19
|
+
available: boolean;
|
|
20
|
+
version: string | null;
|
|
21
|
+
}>;
|
|
22
|
+
export interface InstallOptions {
|
|
23
|
+
host: DiscoveredHost;
|
|
24
|
+
apiUrl: string;
|
|
25
|
+
relayUrl: string;
|
|
26
|
+
accessToken: string;
|
|
27
|
+
refreshToken: string;
|
|
28
|
+
wsToken: string;
|
|
29
|
+
machineId: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Pack the local agent-runner, SCP it to the remote host, install, and configure.
|
|
33
|
+
*
|
|
34
|
+
* Steps:
|
|
35
|
+
* 1. `npm pack` in the agent-runner directory → tarball
|
|
36
|
+
* 2. `scp` tarball to remote ~/
|
|
37
|
+
* 3. `ssh npm install -g <tarball>` on remote
|
|
38
|
+
* 4. `ssh astro-agent setup --non-interactive --skip-auth` on remote
|
|
39
|
+
* 5. Push tokens via `ssh astro-agent config --set` commands
|
|
40
|
+
*/
|
|
41
|
+
export declare function packAndInstall(opts: InstallOptions, onProgress?: (msg: string) => void): Promise<void>;
|
|
42
|
+
export declare function buildSshArgs(host: DiscoveredHost, command: string): string[];
|
|
43
|
+
export declare function sshExec(host: DiscoveredHost, command: string): Promise<{
|
|
44
|
+
stdout: string;
|
|
45
|
+
stderr: string;
|
|
46
|
+
}>;
|
|
47
|
+
export interface StartRemoteOptions {
|
|
48
|
+
maxTasks?: number;
|
|
49
|
+
logLevel?: string;
|
|
50
|
+
preserveWorktrees?: boolean;
|
|
51
|
+
}
|
|
52
|
+
export interface RemoteStartResult {
|
|
53
|
+
host: DiscoveredHost;
|
|
54
|
+
success: boolean;
|
|
55
|
+
message: string;
|
|
56
|
+
alreadyRunning?: boolean;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Start agent runners on remote hosts.
|
|
60
|
+
*
|
|
61
|
+
* For each host:
|
|
62
|
+
* 1. Check if an agent is already running (pgrep)
|
|
63
|
+
* 2. Start via nohup + disown
|
|
64
|
+
* 3. Verify after 2s with pgrep
|
|
65
|
+
*
|
|
66
|
+
* One failure does not block others.
|
|
67
|
+
*/
|
|
68
|
+
export declare function startRemoteAgents(hosts: DiscoveredHost[], options?: StartRemoteOptions, onProgress?: (host: string, msg: string) => void): Promise<RemoteStartResult[]>;
|
|
69
|
+
//# sourceMappingURL=ssh-installer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssh-installer.d.ts","sourceRoot":"","sources":["../../src/lib/ssh-installer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAQlD;;;GAGG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAatC;AAMD;;;GAGG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,cAAc,GACnB,OAAO,CAAC;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CASzD;AAMD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,cAAc,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;GASG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,cAAc,EACpB,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GACjC,OAAO,CAAC,IAAI,CAAC,CAkEf;AAMD,wBAAgB,YAAY,CAAC,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAoB5E;AAuBD,wBAAsB,OAAO,CAC3B,IAAI,EAAE,cAAc,EACpB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAG7C;AAMD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,cAAc,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;;;;;GASG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,cAAc,EAAE,EACvB,OAAO,GAAE,kBAAuB,EAChC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,GAC/C,OAAO,CAAC,iBAAiB,EAAE,CAAC,CA8D9B"}
|