@runuai/host 0.9.75 → 0.9.76

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.
@@ -22,6 +22,8 @@
22
22
  import { spawn } from "node:child_process";
23
23
 
24
24
  import type { DockerResult } from "./docker-exec";
25
+ import { createHash } from "node:crypto";
26
+
25
27
  import type {
26
28
  MachineInfo,
27
29
  MachineProvider,
@@ -282,6 +284,28 @@ export function createAwsMachineProvider(
282
284
  async launch(spec: MachineSpec): Promise<MachineInfo> {
283
285
  const machineId = awsMachineName(spec.taskId);
284
286
  const type = (config.instanceType ?? defaultInstanceType)(spec);
287
+ // The idempotency token binds the machine id TO these exact launch
288
+ // arguments: EC2 remembers a client token's arguments for ~24h (even
289
+ // past termination) and rejects reuse with different ones
290
+ // (IdempotentParameterMismatch — live 2026-08-27: a Resume after a
291
+ // provider fix changed the user-data and the retry was refused). An
292
+ // identical retry still cannot mint a second instance; a CHANGED
293
+ // launch legitimately gets a fresh token, and the resume-aware
294
+ // provision's describe-first step remains the guard against doubling
295
+ // a live machine.
296
+ const launchFingerprint = createHash("sha256")
297
+ .update(
298
+ JSON.stringify([
299
+ spec.image,
300
+ type,
301
+ spec.authorizedPublicKey ?? null,
302
+ config.subnetId ?? null,
303
+ config.securityGroupId ?? null,
304
+ config.iamInstanceProfileArn ?? null,
305
+ ]),
306
+ )
307
+ .digest("hex")
308
+ .slice(0, 16);
285
309
  const args = [
286
310
  "ec2",
287
311
  "run-instances",
@@ -294,7 +318,7 @@ export function createAwsMachineProvider(
294
318
  // Idempotency across crashed/retried provisions: the same token can
295
319
  // never mint a second instance.
296
320
  "--client-token",
297
- machineId,
321
+ `${machineId}-${launchFingerprint}`.slice(0, 64),
298
322
  "--tag-specifications",
299
323
  `ResourceType=instance,Tags=[{Key=${AWS_MACHINE_TAG},Value=${spec.taskId}},{Key=Name,Value=${machineId}}]`,
300
324
  ...(spec.authorizedPublicKey
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@runuai/host",
3
- "version": "0.9.75",
3
+ "version": "0.9.76",
4
4
  "description": "Uai host — runs ephemeral AI tasks in containers on a machine you control.",
5
5
  "license": "MIT",
6
6
  "author": "Uai Tech <team@runuai.com>",