mirror of
https://github.com/OpenRouterTeam/spawn.git
synced 2026-04-30 04:49:33 +00:00
fix(history): merge connection into history.json immediately at provision time (#2177)
Previously, saveVmConnection wrote to a single last-connection.json temp file that was only merged into history.json lazily when spawn ls was run. This caused connections to be silently dropped when: - Two servers spawned before running spawn ls (file overwritten) - The last history record already had a connection (merge skipped) Now saveVmConnection writes directly into history.json by finding the most recent record matching the cloud with no connection yet. The temp file is still written for backward compatibility but is no longer the primary storage. Also fixes saveLaunchCmd to update history.json directly, and consolidates sprite's local saveVmConnection to use the shared one. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: A <258483684+la14-1@users.noreply.github.com>
This commit is contained in:
parent
cb91b5d236
commit
c9ea6384da
1 changed files with 69 additions and 11 deletions
|
|
@ -62,7 +62,10 @@ export function getConnectionPath(): string {
|
|||
return join(getSpawnDir(), "last-connection.json");
|
||||
}
|
||||
|
||||
/** Save VM connection info to last-connection.json for later reconnection/deletion. */
|
||||
/** Save VM connection info directly into history.json.
|
||||
* Finds the most recent record matching this cloud that has no connection yet
|
||||
* and attaches the connection data to it. This is called during provisioning
|
||||
* so the connection is persisted immediately — not deferred to a lazy merge. */
|
||||
export function saveVmConnection(
|
||||
ip: string,
|
||||
user: string,
|
||||
|
|
@ -77,6 +80,38 @@ export function saveVmConnection(
|
|||
recursive: true,
|
||||
mode: 0o700,
|
||||
});
|
||||
|
||||
const connData: VMConnection = {
|
||||
ip,
|
||||
user,
|
||||
server_id: serverId || undefined,
|
||||
server_name: serverName || undefined,
|
||||
cloud: cloud || undefined,
|
||||
launch_cmd: launchCmd || undefined,
|
||||
metadata: metadata && Object.keys(metadata).length > 0 ? metadata : undefined,
|
||||
};
|
||||
|
||||
// Merge directly into history — find the most recent record for this cloud
|
||||
// that doesn't have a connection yet (the record created by saveSpawnRecord).
|
||||
const history = loadHistory();
|
||||
let merged = false;
|
||||
for (let i = history.length - 1; i >= 0; i--) {
|
||||
const r = history[i];
|
||||
if (r.cloud === cloud && !r.connection) {
|
||||
r.connection = connData;
|
||||
merged = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (merged) {
|
||||
writeFileSync(getHistoryPath(), JSON.stringify(history, null, 2) + "\n", {
|
||||
mode: 0o600,
|
||||
});
|
||||
}
|
||||
|
||||
// Also write last-connection.json for backward compatibility
|
||||
// (other tools or older CLI versions may still read it)
|
||||
const json: Record<string, unknown> = {
|
||||
ip,
|
||||
user,
|
||||
|
|
@ -101,8 +136,26 @@ export function saveVmConnection(
|
|||
});
|
||||
}
|
||||
|
||||
/** Save launch command to the last-connection.json file. */
|
||||
/** Save launch command to the most recent history record's connection. */
|
||||
export function saveLaunchCmd(launchCmd: string): void {
|
||||
// Update history directly — find the most recent record with a connection
|
||||
try {
|
||||
const history = loadHistory();
|
||||
for (let i = history.length - 1; i >= 0; i--) {
|
||||
const conn = history[i].connection;
|
||||
if (conn) {
|
||||
conn.launch_cmd = launchCmd;
|
||||
writeFileSync(getHistoryPath(), JSON.stringify(history, null, 2) + "\n", {
|
||||
mode: 0o600,
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// non-fatal
|
||||
}
|
||||
|
||||
// Also update last-connection.json for backward compatibility
|
||||
const connFile = getConnectionPath();
|
||||
try {
|
||||
const data = JSON.parse(readFileSync(connFile, "utf-8"));
|
||||
|
|
@ -281,17 +334,22 @@ function mergeLastConnection(): void {
|
|||
|
||||
const history = loadHistory();
|
||||
|
||||
if (history.length > 0) {
|
||||
// Update the most recent entry with connection info
|
||||
const latest = history[history.length - 1];
|
||||
if (!latest.connection) {
|
||||
latest.connection = connData;
|
||||
// Save updated history
|
||||
writeFileSync(getHistoryPath(), JSON.stringify(history, null, 2) + "\n", {
|
||||
mode: 0o600,
|
||||
});
|
||||
// Find the most recent entry without a connection and merge into it.
|
||||
// Search backwards so we match the right record even if earlier records
|
||||
// already have connections (e.g., from concurrent spawns).
|
||||
let merged = false;
|
||||
for (let i = history.length - 1; i >= 0; i--) {
|
||||
if (!history[i].connection) {
|
||||
history[i].connection = connData;
|
||||
merged = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (merged) {
|
||||
writeFileSync(getHistoryPath(), JSON.stringify(history, null, 2) + "\n", {
|
||||
mode: 0o600,
|
||||
});
|
||||
}
|
||||
|
||||
// Clean up the connection file after merging
|
||||
unlinkSync(connPath);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue