automify 0.3.0 → 0.3.1

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/README.md CHANGED
@@ -126,6 +126,9 @@ Pre-warm or refresh QEMU image caches:
126
126
  # Pre-warm the minimal QEMU CLI cache.
127
127
  npx automify-qemu-image
128
128
 
129
+ # Pre-warm a QEMU CLI cache for examples that need Node.js in the VM.
130
+ npx automify-qemu-image --package coreutils --package nodejs
131
+
129
132
  # Pre-warm the QEMU desktop cache with Xvfb/openbox/xterm/xdotool/scrot.
130
133
  npx automify-qemu-image --desktop
131
134
 
@@ -281,7 +284,7 @@ const cli = automify.virtualCli({
281
284
  memory: "2g",
282
285
  cpus: 2
283
286
  },
284
- additionalAptPackages: ["coreutils"],
287
+ additionalAptPackages: ["coreutils", "nodejs"],
285
288
  shared: { hostPath: process.cwd(), containerPath: "/workspace" }
286
289
  });
287
290
 
@@ -779,7 +782,7 @@ RUN_OPENAI_QEMU_DESKTOP_E2E=1 \
779
782
  node --test test/e2e/live-openai.e2e.test.js
780
783
  ```
781
784
 
782
- Use `AUTOMIFY_QEMU_DEFAULT_IMAGE_URL` to point the default Debian download at a mirror, and `AUTOMIFY_QEMU_IMAGE_CACHE_DIR` to choose the cache directory. By default, Automify caches the downloaded Debian base image and prepared Automify-ready Debian images on the user's computer. The CLI cache stays minimal; the desktop cache is a separate variant that bakes Xvfb/openbox/xterm/xdotool/scrot so warm desktop boots do not reinstall apt packages. Configure image caching with `defaultImageCache`, for example `defaultImageCache: { dir: "/var/cache/automify-qemu", forcePrepare: true }`. Run `npx automify-qemu-image` to pre-warm the QEMU CLI cache. Run `npx automify-qemu-image --desktop` to pre-warm the QEMU desktop cache. Run `npx automify-qemu-image --image-url https://example.com/path/linux.qcow2 --cache-dir /var/cache/automify-qemu-custom` to pre-warm an alternate cloud qcow2 cache, then use the same URL and cache directory at runtime with `vm.imageUrl` or `qemuImageUrl` plus `defaultImageCache`. Run `npx automify-qemu-image --force-download` to replace the cached base image and rebuild the prepared image. Local disks passed with `image` or `vm.image` are not prepared by the cache command; they must already be bootable with SSH access. On ARM hosts Automify auto-detects common QEMU UEFI firmware paths; set `AUTOMIFY_QEMU_FIRMWARE` if your QEMU install keeps the firmware elsewhere.
785
+ Use `AUTOMIFY_QEMU_DEFAULT_IMAGE_URL` to point the default Debian download at a mirror, and `AUTOMIFY_QEMU_IMAGE_CACHE_DIR` to choose the cache directory. By default, Automify caches the downloaded Debian base image and prepared Automify-ready Debian images on the user's computer. CLI cache variants bake the requested `packages` and `additionalAptPackages`; the desktop cache is a separate variant that bakes Xvfb/openbox/xterm/xdotool/scrot so warm desktop boots do not reinstall apt packages. Configure image caching with `defaultImageCache`, for example `defaultImageCache: { dir: "/var/cache/automify-qemu", forcePrepare: true }`. Run `npx automify-qemu-image` to pre-warm the minimal QEMU CLI cache, or add flags such as `--package coreutils --package nodejs` to pre-warm a package-specific CLI cache. Run `npx automify-qemu-image --desktop` to pre-warm the QEMU desktop cache. Run `npx automify-qemu-image --image-url https://example.com/path/linux.qcow2 --cache-dir /var/cache/automify-qemu-custom` to pre-warm an alternate cloud qcow2 cache, then use the same URL and cache directory at runtime with `vm.imageUrl` or `qemuImageUrl` plus `defaultImageCache`. Run `npx automify-qemu-image --force-download` to replace the cached base image and rebuild the prepared image. Local disks passed with `image` or `vm.image` are not prepared by the cache command; they must already be bootable with SSH access. On ARM hosts Automify auto-detects common QEMU UEFI firmware paths; set `AUTOMIFY_QEMU_FIRMWARE` if your QEMU install keeps the firmware elsewhere.
783
786
 
784
787
  ## License
785
788
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "automify",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "AI computer use for browser, CLI, and desktop in Node.js.",
5
5
  "homepage": "https://aldovincenti.github.io/automify",
6
6
  "bugs": {
@@ -19,6 +19,8 @@ const options = parseArgs(args);
19
19
  console.log("Preparing Automify QEMU default Debian image cache.");
20
20
  if (options.desktop) {
21
21
  console.log("Desktop cache enabled: the prepared image will include the default QEMU desktop packages.");
22
+ } else if (options.packages.length > 0) {
23
+ console.log("CLI cache enabled: the prepared image will include the requested apt packages.");
22
24
  } else {
23
25
  console.log("CLI cache enabled: the prepared image will stay minimal for QEMU virtual CLI runs.");
24
26
  }
@@ -39,7 +41,7 @@ try {
39
41
  imageUrl: options.imageUrl,
40
42
  defaultImageCache: options.defaultImageCache,
41
43
  preparedImageProfile: options.desktop ? "desktop" : undefined,
42
- preparedPackages: options.desktop ? uniquePackages([...DEFAULT_QEMU_DESKTOP_PACKAGES, ...options.packages]) : [],
44
+ preparedPackages: options.desktop ? uniquePackages([...DEFAULT_QEMU_DESKTOP_PACKAGES, ...options.packages]) : options.packages,
43
45
  vmName: "automify-qemu-image"
44
46
  });
45
47
 
@@ -132,7 +134,7 @@ Options:
132
134
  --force-prepare Rebuild only the prepared image
133
135
  --no-prepare Download only the base Debian qcow2
134
136
  --desktop Prepare the QEMU desktop cache variant
135
- --package <name> Add an apt package to the prepared desktop cache
137
+ --package <name> Add an apt package to the prepared cache
136
138
  --cache-dir <path> Cache root for base and prepared images
137
139
  --prepared-cache-dir <path>
138
140
  Cache directory for prepared images
@@ -143,6 +145,7 @@ Options:
143
145
 
144
146
  Examples:
145
147
  npx automify-qemu-image # pre-warm the QEMU CLI cache
148
+ npx automify-qemu-image --package coreutils --package nodejs
146
149
  npx automify-qemu-image --desktop # pre-warm the QEMU desktop cache
147
150
  npx automify-qemu-image --force-download
148
151
  npx automify-qemu-image --cache-dir ${root}/.automify-qemu-cache
@@ -34,6 +34,7 @@ const execFileAsync = promisify(execFile);
34
34
 
35
35
  const DEFAULT_CWD = "/workspace";
36
36
  const DEFAULT_TIMEOUT_MS = 30_000;
37
+ const DEFAULT_STARTUP_TIMEOUT_MS = 120_000;
37
38
  const VIRTUAL_CLI_OPTION_KEYS = mergeOptionKeys(AUTOMIFY_OPTION_KEYS, [
38
39
  "preset",
39
40
  "command",
@@ -195,6 +196,7 @@ export class QemuCliSession {
195
196
  this.originalSshKeyPath = options.sshKeyPath;
196
197
  this.originalSudo = options.sudo;
197
198
  this.defaultImage = null;
199
+ this.preparedPackages = new Set();
198
200
  this.usesDefaultImage = !this.image && !options.existingVM;
199
201
  this.name = options.vmName ?? `automify-vm-cli-${randomUUID()}`;
200
202
  this.cwd = normalizeGuestPath(options.cwd, DEFAULT_CWD);
@@ -251,7 +253,7 @@ export class QemuCliSession {
251
253
  this.started = true;
252
254
  await waitForSsh(this.execFile, this.sshCommand, this.sshOptions());
253
255
  await this.runSsh(this.startupScript(), {
254
- timeout: positiveInteger(this.options.timeoutMs) ?? DEFAULT_TIMEOUT_MS
256
+ timeout: this.startupTimeoutMs()
255
257
  });
256
258
  debugVirtualCli(this.options, "vm_ready", { vmName: this.name });
257
259
  } catch (error) {
@@ -288,13 +290,15 @@ export class QemuCliSession {
288
290
  sshPort: this.sshPort,
289
291
  sshTimeoutMs: this.options.sshTimeoutMs,
290
292
  startupTimeoutMs: this.options.startupTimeoutMs,
291
- timeoutMs: this.options.timeoutMs,
293
+ timeoutMs: this.startupTimeoutMs(),
292
294
  qemuTimeoutMs: this.options.qemuTimeoutMs,
293
295
  createCloudInitServer: this.options.createCloudInitServer,
296
+ preparedPackages: this.options.installDependencies === false ? [] : this.dependencyPackages(),
294
297
  spawn: this.spawn,
295
298
  vmName: this.name
296
299
  });
297
300
  this.defaultImage = prepared;
301
+ this.preparedPackages = new Set(prepared.preparedPackages ?? []);
298
302
  this.image = prepared.image;
299
303
  this.options = {
300
304
  ...this.options,
@@ -313,7 +317,7 @@ export class QemuCliSession {
313
317
  }
314
318
 
315
319
  startupScript() {
316
- const packages = uniquePackages([...(this.options.packages ?? []), ...(this.options.additionalAptPackages ?? [])]);
320
+ const packages = this.dependencyPackages().filter((pkg) => !this.preparedPackages.has(pkg));
317
321
  const startupCommand = this.options.startupCommand ?? ":";
318
322
  return [
319
323
  installCommand(packages, this.options),
@@ -323,6 +327,14 @@ export class QemuCliSession {
323
327
  ].join(" && ");
324
328
  }
325
329
 
330
+ dependencyPackages() {
331
+ return uniquePackages([...(this.options.packages ?? []), ...(this.options.additionalAptPackages ?? [])]);
332
+ }
333
+
334
+ startupTimeoutMs() {
335
+ return positiveInteger(this.options.startupTimeoutMs) ?? DEFAULT_STARTUP_TIMEOUT_MS;
336
+ }
337
+
326
338
  async run(command, options = {}) {
327
339
  await this.start();
328
340
  const cwd = normalizeGuestPath(options.cwd ?? this.cwd, this.cwd);
@@ -385,6 +397,7 @@ export class QemuCliSession {
385
397
  }
386
398
  await this.defaultImage?.close();
387
399
  this.defaultImage = null;
400
+ this.preparedPackages = new Set();
388
401
  if (this.usesDefaultImage) {
389
402
  this.image = null;
390
403
  this.options = {