@androperator/emulator 0.1.0 → 0.2.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.
@@ -0,0 +1,137 @@
1
+ ---
2
+ name: create-android-emulator
3
+ description: Create or recreate an Android development emulator with the @androperator/emulator library or CLI, choose an installed phone image and profile, configure practical storage, and verify boot and guest capacity. Use for local AVD provisioning, including insufficient storage during repeated APK installs.
4
+ ---
5
+
6
+ # Create Android Emulator
7
+
8
+ Use `@androperator/emulator` for AVD lifecycle operations. Prefer its JSON CLI for
9
+ interactive provisioning; use the library exports when integrating into code.
10
+ This skill creates a device, not an Android UI automation workflow.
11
+
12
+ ## Discover and choose
13
+
14
+ Find an installed `androperator-emulator` and check `--version` and `--help`.
15
+ In this library's source checkout, use `npm ci` if dependencies are missing,
16
+ `npm run build`, then `node dist/cli.js` as the CLI. Outside the checkout, use
17
+ `npm install -g @androperator/emulator` when installation is within the request.
18
+ Requires Node.js 24+, Android SDK tools and their Java runtime. Missing SDK or
19
+ Java prerequisites should be reported before provisioning; the package does not
20
+ install the SDK itself.
21
+
22
+ CLI tool overrides are `ADB_PATH`, `EMULATOR_PATH`, `SDKMANAGER_PATH` and
23
+ `AVDMANAGER_PATH`. Otherwise discovery checks `ANDROID_HOME`, `ANDROID_SDK_ROOT`,
24
+ standard macOS/Linux SDK roots, then PATH. Use the same resolved tools for the SDK
25
+ and adb commands below. Keep `ANDROID_AVD_HOME` consistent across all commands
26
+ if set; other custom Android home conventions are not supported by the library.
27
+
28
+ Inspect before mutating:
29
+
30
+ ```sh
31
+ androperator-emulator list
32
+ androperator-emulator status
33
+ "$sdkmanager" --list_installed
34
+ "$avdmanager" list device -c
35
+ ```
36
+
37
+ Here `$sdkmanager`, `$avdmanager` and later `$adb` stand for the resolved executable
38
+ paths. The CLI has no image/profile enumeration command, so use SDK tools for
39
+ those read-only queries.
40
+
41
+ Respect requested API, image, profile, storage and name. Otherwise prefer:
42
+
43
+ - Name: `Android_Dev_API_<api>`.
44
+ - Data capacity: `24G`, for repeated development APK installs.
45
+ - Image: highest installed stable API with a Google Play phone image matching
46
+ the host architecture (`arm64-v8a` on ARM, `x86_64` on x86).
47
+ - Profile: newest installed Pixel phone profile compatible with that image.
48
+
49
+ Use actual package and profile IDs from discovery, not guessed IDs. If no suitable
50
+ Google Play image is installed, choose an installed compatible Google APIs phone
51
+ image when Play Store access is unnecessary. If an image must be downloaded,
52
+ query `"$sdkmanager" --list` and choose an available compatible package. Creation
53
+ installs a missing selected image. `--accept-licenses` accepts **all outstanding
54
+ SDK licenses**, so use it only with explicit authorization for that acceptance.
55
+
56
+ ## Create and boot
57
+
58
+ Set `$name`, `$image` and `$profile` to the selected values. For a fresh device:
59
+
60
+ ```sh
61
+ androperator-emulator create "$name" \
62
+ --image "$image" --profile "$profile" --storage-size 24G
63
+ androperator-emulator inspect "$name"
64
+ androperator-emulator start "$name" --headless
65
+ ```
66
+
67
+ Substitute the requested capacity for `24G`. Omit `--headless` for a visible
68
+ emulator. Every CLI invocation returns one JSON envelope; check exit status and
69
+ `ok` before using `data`. Stop on failure, inspect the error and relevant state,
70
+ and retry only after addressing its cause. A failed start can leave an emulator
71
+ running; check `status` before launching again.
72
+
73
+ Existing names are refused. Reuse a suitable existing device or choose a fresh
74
+ name. Use `create --replace` only when the user has authorized discarding that
75
+ AVD's data. Before replacement, stop the target if running, then poll `status`
76
+ with a bounded timeout to confirm its serial disappears. `stop` only requests
77
+ shutdown. Replacement/deletion refuse running AVDs and fail closed on uncertain
78
+ ADB state; resolve that state instead of bypassing the checks. Serialize lifecycle
79
+ operations for the same AVD.
80
+
81
+ `storage` changes configured capacity only; it does not resize existing userdata.
82
+ Prefer a fresh AVD for a capacity change. Creation does not configure an SD card,
83
+ force qcow2 allocation, or disable snapshot saving. Do not promise the reference
84
+ AVD workflow's sparse disk or snapshot-free behavior. CLI launch disables snapshot
85
+ loading. If snapshot saving must be disabled, use library `startAvd` with
86
+ `["-no-snapshot-save"]`, then both readiness waits described below.
87
+
88
+ ## Verify and report
89
+
90
+ Successful CLI `start` returns `data.serial` and `booted: true` after registration
91
+ and both boot properties pass. Use that returned serial, never assume port 5554.
92
+ If reusing an already-running target, resolve its serial by AVD name in `status`
93
+ and use `wait <serial>` to verify readiness.
94
+
95
+ ```sh
96
+ "$adb" -s "$serial" shell df -h /data
97
+ ```
98
+
99
+ Check actual total and free guest capacity against the requested size; `inspect`
100
+ reports device metadata, not storage capacity. If an APK is supplied for a smoke
101
+ test, install it on this serial with `"$adb" -s "$serial" install -r "$apk"`.
102
+ If host disk usage matters, obtain the actual config path with library
103
+ `getAvdConfigPath(name)` (AVD locator files may redirect it), and measure its
104
+ parent directory with `du -sh`. Inspect existing userdata with SDK `qemu-img info`
105
+ only when that tool and file exist; report measured allocation rather than
106
+ assuming qcow2 or a small physical size.
107
+
108
+ Leave a requested development device running. Stop a device launched only for
109
+ verification when the requested outcome does not require it running; confirm
110
+ shutdown before reporting it stopped. Do not delete the created AVD as cleanup.
111
+ Report name, API/image/profile, configured capacity, measured `/data` total/free,
112
+ serial and boot state, APK result if tested, and the normal launch command.
113
+ Distinguish unavailable measurements from verified results.
114
+
115
+ ## Library integration
116
+
117
+ The root export supplies `getDefaultRuntimeConfig`, `createAvd`,
118
+ `inspectConfiguredAvd`, `listRunningEmulators`, `startAvd`,
119
+ `waitForEmulatorRegistration`, `waitForBootCompletion`, `stopAvd`, and
120
+ `getAvdConfigPath`. Use the same selections and replacement/license boundaries.
121
+
122
+ ```js
123
+ import {
124
+ getDefaultRuntimeConfig, createAvd, startAvd,
125
+ waitForEmulatorRegistration, waitForBootCompletion,
126
+ } from '@androperator/emulator';
127
+
128
+ const config = getDefaultRuntimeConfig();
129
+ await createAvd(config, {
130
+ name, systemImage: image, deviceProfile: profile, dataPartitionSize: '24G',
131
+ });
132
+ await startAvd(config, name, ['-no-window', '-no-audio']);
133
+ const serial = await waitForEmulatorRegistration(config, name);
134
+ await waitForBootCompletion(config, serial);
135
+ ```
136
+
137
+ `startAvd` confirms spawn only; both waits are required to confirm readiness.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Create Android Emulator"
3
+ short_description: "Create and verify an Android development emulator"
4
+ default_prompt: "Use $create-android-emulator to create an Android development emulator with @androperator/emulator."
package/README.md CHANGED
@@ -12,19 +12,37 @@ npm ci
12
12
  npm run build
13
13
  npm test
14
14
  npm pack
15
- npm install -g ./androperator-emulator-0.1.0.tgz
15
+ npm install -g ./androperator-emulator-0.2.0.tgz
16
16
  androperator-emulator --version
17
17
  ```
18
18
 
19
- The package is not yet published. Consumers can install the packed archive without
20
- this checkout or development dependencies. After publication, install with
21
- `npm install -g @androperator/emulator`.
19
+ Install the published CLI with `npm install -g @androperator/emulator`.
20
+ Consumers can also install the packed archive without this checkout or development
21
+ dependencies.
22
22
  The executable remains `androperator-emulator`. See [provenance](docs/provenance.md)
23
23
  for source history and [plan](docs/plan.md) for follow-on work.
24
24
 
25
+ ## Homebrew installation
26
+
27
+ ```sh
28
+ brew install androperator/tap/emulator
29
+ brew upgrade androperator/tap/emulator
30
+ ```
31
+
32
+ The executable remains `androperator-emulator`. Homebrew manages Node and uses
33
+ this package's npm release archive. Android SDK tools and Java are configured
34
+ separately. When moving from a global npm installation, first remove it with
35
+ `npm uninstall -g @androperator/emulator` to avoid executable conflicts.
36
+ New versions become available after automatic tap validation; Homebrew can
37
+ hold newly published dependencies for 24 hours. Do not upgrade a Homebrew
38
+ installation using npm.
39
+
25
40
  ## CLI
26
41
 
27
42
  ```sh
43
+ androperator-emulator profiles
44
+ androperator-emulator images
45
+ androperator-emulator images --installed
28
46
  androperator-emulator list
29
47
  androperator-emulator inspect My_AVD
30
48
  androperator-emulator status
@@ -52,6 +70,37 @@ The `--version` response identifies the package and machine protocol without SDK
52
70
  access. ADBuddy can probe this command after finding the separately installed
53
71
  executable; native discovery and installation UI are separate work.
54
72
 
73
+ ### Creation catalogs
74
+
75
+ `profiles` returns `{profiles: [{id, name, manufacturer, tag}]}` from the SDK's
76
+ hardware definitions. Pass the stable `id` to `create --profile`; the SDK's
77
+ numeric row index is not returned. Missing manufacturer or tag values are null.
78
+
79
+ `images` queries installed and available SDK packages and returns
80
+ `{images: [{id, platform, apiLevel, tag, abi, description, installed,
81
+ installedVersion, availableVersion}]}`. `images --installed` queries only local
82
+ packages, so it does not require fetching the remote catalog. Pass `id` directly
83
+ to `create --image`. IDs use semicolons regardless of the SDK output format.
84
+ Versions remain strings; an absent installed or available version is null.
85
+ `platform` preserves the complete platform identifier, including minor versions
86
+ or preview names. `apiLevel` is the numeric major API for numeric platforms and
87
+ null for codenames. Results are sorted by ID, with each image appearing once.
88
+
89
+ These are catalogs, not compatibility recommendations. Callers must select a
90
+ suitable image/profile/host combination; do not assume every listed image runs
91
+ on this Mac. Remote queries can require network access and may take longer than
92
+ local queries. Tool or unrecognized-format failures return
93
+ `ANDROID_CATALOG_QUERY_FAILED`; empty recognized catalogs return empty arrays.
94
+ The legacy SDK table and the Android CLI shim's slash-separated table are supported.
95
+
96
+ Library consumers can call `listHardwareProfiles(config)` and
97
+ `listSystemImages(config, {installedOnly: true})`; omitting the latter option
98
+ includes available images. Neither command starts ADB or accepts licenses.
99
+ `--version` now includes `capabilities: ["catalog.profiles", "catalog.images"]`
100
+ in its data object. Consumers should treat missing capabilities as unsupported;
101
+ the JSON envelope remains protocol version 1. Earlier published versions lack
102
+ these catalog commands.
103
+
55
104
  Create requires explicit image, hardware profile and storage capacity. Existing
56
105
  AVDs are refused unless `--replace` is supplied, which discards existing data.
57
106
  Replacement and deletion refuse running AVDs and fail closed if ADB discovery
@@ -75,6 +124,31 @@ It does not resize existing userdata, guarantee free space, or impose a host dis
75
124
  quota. Use a fresh AVD when changing capacity. Dynamic qcow2 allocation and
76
125
  snapshot-free storage are follow-on capabilities.
77
126
 
127
+ ## Agent skill
128
+
129
+ [Create Android Emulator](.agents/skills/create-android-emulator/SKILL.md) guides an
130
+ agent through image/profile discovery, creation with practical development
131
+ storage (24G by default), boot verification and actual guest storage checks using
132
+ this package. Invoke it as `$create-android-emulator`.
133
+
134
+ The source lives in `.agents/skills/create-android-emulator/`, the repository
135
+ skill location supported by Codex. The same folder is included in the npm
136
+ archive; the release-only skill is excluded. Installing the npm package does
137
+ not automatically register its skill with an agent.
138
+
139
+ To use it in another project, copy the entire skill folder from
140
+ `node_modules/@androperator/emulator/.agents/skills/create-android-emulator/`
141
+ into that project's `.agents/skills/`. For a global npm installation, the source
142
+ is under `$(npm root -g)/@androperator/emulator/.agents/skills/`. For personal
143
+ Codex use across projects, copy it into `~/.agents/skills/` instead. Copies should
144
+ be refreshed when upgrading the library.
145
+
146
+ Each skill needs a `SKILL.md` with name/description frontmatter and instructions;
147
+ `agents/openai.yaml` supplies optional UI metadata. Repository skills work well
148
+ for checked-in workflows. Plugins provide an installation unit for broader skill
149
+ distribution and optional connectors. See the official
150
+ [skill discovery and distribution guidance](https://learn.chatgpt.com/docs/build-skills).
151
+
78
152
  ## Library
79
153
 
80
154
  ```js
@@ -0,0 +1,27 @@
1
+ import type { RuntimeConfig } from "./runtimeConfig.js";
2
+ export interface HardwareProfile {
3
+ /** Stable identifier accepted by create --profile; never the catalog row number. */
4
+ id: string;
5
+ name: string;
6
+ manufacturer: string | null;
7
+ tag: string | null;
8
+ }
9
+ export interface SystemImage {
10
+ /** Canonical semicolon-delimited identifier accepted by create --image. */
11
+ id: string;
12
+ platform: string;
13
+ apiLevel: number | null;
14
+ tag: string;
15
+ abi: string;
16
+ description: string;
17
+ installed: boolean;
18
+ installedVersion: string | null;
19
+ availableVersion: string | null;
20
+ }
21
+ export declare function parseHardwareProfiles(output: string): HardwareProfile[];
22
+ export declare function parseSystemImages(output: string): SystemImage[];
23
+ export declare function listHardwareProfiles(config: RuntimeConfig): Promise<HardwareProfile[]>;
24
+ export declare function listSystemImages(config: RuntimeConfig, options?: {
25
+ installedOnly?: boolean;
26
+ }): Promise<SystemImage[]>;
27
+ //# sourceMappingURL=catalog.d.ts.map
@@ -0,0 +1,98 @@
1
+ import { runAndroidSdkTool } from "./hostToolClient.js";
2
+ function catalogError(message) {
3
+ throw { code: "ANDROID_CATALOG_QUERY_FAILED", message };
4
+ }
5
+ export function parseHardwareProfiles(output) {
6
+ const profiles = [];
7
+ let profile;
8
+ function finish() {
9
+ if (!profile)
10
+ return;
11
+ if (!profile.name)
12
+ catalogError(`Missing name for hardware profile ${profile.id}`);
13
+ profiles.push(profile);
14
+ }
15
+ for (const line of output.split(/\r?\n/)) {
16
+ const id = /^\s*id:\s*\d+\s+or\s+"([^"]+)"\s*$/.exec(line);
17
+ if (id) {
18
+ finish();
19
+ profile = { id: id[1], name: "", manufacturer: null, tag: null };
20
+ }
21
+ else if (/^\s*id:/.test(line)) {
22
+ catalogError(`Unrecognized hardware profile identifier: ${line.trim()}`);
23
+ }
24
+ else if (profile) {
25
+ const field = /^\s*(Name|OEM|Tag)\s*:\s*(.*?)\s*$/.exec(line);
26
+ if (field?.[1] === "Name")
27
+ profile.name = field[2];
28
+ if (field?.[1] === "OEM")
29
+ profile.manufacturer = field[2] || null;
30
+ if (field?.[1] === "Tag")
31
+ profile.tag = field[2] || null;
32
+ }
33
+ }
34
+ finish();
35
+ if (!profiles.length && !output.includes("Available devices definitions:")) {
36
+ catalogError("Unrecognized hardware profile catalog; expected avdmanager list device output");
37
+ }
38
+ return profiles.sort((a, b) => a.id.localeCompare(b.id));
39
+ }
40
+ export function parseSystemImages(output) {
41
+ const images = new Map();
42
+ let section;
43
+ let recognized = false;
44
+ for (const line of output.split(/\r?\n/)) {
45
+ const heading = /^\s*(Installed packages|Available Packages|Available packages|Available Updates|Available updates):\s*$/.exec(line);
46
+ if (heading) {
47
+ recognized = true;
48
+ section = heading[1] === "Installed packages" ? "installed"
49
+ : heading[1].toLowerCase() === "available packages" ? "available" : undefined;
50
+ continue;
51
+ }
52
+ if (!/^\s*system-images[;/]/.test(line))
53
+ continue;
54
+ // Update tables have a different schema; their rows are already represented
55
+ // by the installed and available package sections.
56
+ if (!section)
57
+ continue;
58
+ const columns = line.includes("|") ? line.split("|").map((column) => column.trim())
59
+ : line.trim().split(/\s{2,}/);
60
+ const [rawId, version, description] = columns;
61
+ const id = rawId.replaceAll("/", ";");
62
+ const parts = /^system-images;(android-[^;\s]+);([^;\s]+);([^;\s]+)$/.exec(id);
63
+ if (!parts || !version || !description)
64
+ catalogError(`Unrecognized system image row: ${line.trim()}`);
65
+ const [, platform, tag, abi] = parts;
66
+ const api = /^android-(\d+)(?:\.\d+)*(?:-ext\d+)?$/.exec(platform);
67
+ const image = images.get(id) ?? {
68
+ id, platform, apiLevel: api ? Number(api[1]) : null, tag, abi, description,
69
+ installed: false, installedVersion: null, availableVersion: null,
70
+ };
71
+ if (section === "installed") {
72
+ image.installed = true;
73
+ image.installedVersion = version;
74
+ }
75
+ else {
76
+ image.availableVersion = version;
77
+ image.description = description;
78
+ }
79
+ images.set(id, image);
80
+ }
81
+ if (!recognized)
82
+ catalogError("Unrecognized system image catalog; expected sdkmanager package sections");
83
+ return [...images.values()].sort((a, b) => a.id.localeCompare(b.id));
84
+ }
85
+ export async function listHardwareProfiles(config) {
86
+ const result = await runAndroidSdkTool(config, "avdmanager", ["list", "device"], { timeoutMs: 30_000 });
87
+ if (result.code !== 0 || result.error)
88
+ catalogError(result.stderr || result.error?.message || "Could not list hardware profiles");
89
+ return parseHardwareProfiles(result.stdout);
90
+ }
91
+ export async function listSystemImages(config, options = {}) {
92
+ const result = await runAndroidSdkTool(config, "sdkmanager", [options.installedOnly ? "--list_installed" : "--list"], { timeoutMs: 120_000 });
93
+ if (result.code !== 0 || result.error)
94
+ catalogError(result.stderr || result.error?.message || "Could not list system images");
95
+ const images = parseSystemImages(result.stdout);
96
+ return options.installedOnly ? images.filter((image) => image.installed) : images;
97
+ }
98
+ //# sourceMappingURL=catalog.js.map
package/dist/cli.js CHANGED
@@ -1,8 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import { readFileSync } from "node:fs";
3
3
  import { parseArgs } from "node:util";
4
- import { getDefaultRuntimeConfig, listRunningEmulators, listConfiguredAvds, inspectConfiguredAvd, createAvd, startAvd, stopAvd, deleteAvd, waitForBootCompletion, waitForEmulatorRegistration, ensureSystemImageInstalled, setAvdDataPartitionSize } from "./index.js";
4
+ import { getDefaultRuntimeConfig, listRunningEmulators, listConfiguredAvds, inspectConfiguredAvd, createAvd, startAvd, stopAvd, deleteAvd, waitForBootCompletion, waitForEmulatorRegistration, ensureSystemImageInstalled, setAvdDataPartitionSize, listHardwareProfiles, listSystemImages } from "./index.js";
5
5
  const commands = {
6
+ profiles: "profiles", images: "images [--installed]",
6
7
  list: "list", inspect: "inspect <name>", status: "status",
7
8
  download: "download <system-image> [--accept-licenses]",
8
9
  create: "create <name> --image <system-image> --profile <hardware-profile> --storage-size <12G> [--replace] [--accept-licenses]",
@@ -14,7 +15,7 @@ function usage(message) {
14
15
  }
15
16
  async function main() {
16
17
  const { values, positionals } = parseArgs({ allowPositionals: true, strict: true, options: {
17
- help: { type: "boolean", short: "h" }, version: { type: "boolean" }, json: { type: "boolean" },
18
+ installed: { type: "boolean" }, help: { type: "boolean", short: "h" }, version: { type: "boolean" }, json: { type: "boolean" },
18
19
  output: { type: "string" }, image: { type: "string" }, profile: { type: "string" },
19
20
  "storage-size": { type: "string" }, replace: { type: "boolean" },
20
21
  "accept-licenses": { type: "boolean" }, headless: { type: "boolean" }, "timeout-ms": { type: "string" },
@@ -23,17 +24,18 @@ async function main() {
23
24
  usage("--output supports json; for example --output json list");
24
25
  if (values.version) {
25
26
  const { name, version } = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
26
- return { name, version, protocolVersion: 1 };
27
+ return { name, version, protocolVersion: 1, capabilities: ["catalog.profiles", "catalog.images"] };
27
28
  }
28
29
  if (values.help)
29
30
  return { commands, output: "One JSON envelope on stdout; exit 0 success, 1 operation failure, 2 usage error" };
30
31
  const [command, target, ...extra] = positionals;
31
32
  if (!Object.hasOwn(commands, command ?? ""))
32
33
  usage(`Unknown or missing command: ${command ?? ""}; use --help`);
33
- const needsTarget = !["list", "status"].includes(command);
34
+ const needsTarget = !["list", "status", "profiles", "images"].includes(command);
34
35
  if (extra.length || (needsTarget ? target === undefined || target.trim() === "" : target !== undefined))
35
36
  usage(`Use ${commands[command]}`);
36
37
  const allowed = {
38
+ images: ["installed"],
37
39
  create: ["image", "profile", "storage-size", "replace", "accept-licenses"],
38
40
  download: ["accept-licenses"], start: ["headless"], wait: ["timeout-ms"], storage: ["storage-size"],
39
41
  };
@@ -49,6 +51,8 @@ async function main() {
49
51
  }
50
52
  const config = getDefaultRuntimeConfig();
51
53
  switch (command) {
54
+ case "profiles": return { profiles: await listHardwareProfiles(config) };
55
+ case "images": return { images: await listSystemImages(config, { installedOnly: values.installed }) };
52
56
  case "status": return { devices: await listRunningEmulators(config) };
53
57
  case "list": {
54
58
  const running = await listRunningEmulators(config);
package/dist/errors.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export declare const ERROR_CODES: {
2
+ readonly ANDROID_CATALOG_QUERY_FAILED: "ANDROID_CATALOG_QUERY_FAILED";
2
3
  readonly ADB_QUERY_FAILED: "ADB_QUERY_FAILED";
3
4
  readonly ANDROID_AVD_CREATE_FAILED: "ANDROID_AVD_CREATE_FAILED";
4
5
  readonly ANDROID_SDK_TOOL_MISSING: "ANDROID_SDK_TOOL_MISSING";
package/dist/errors.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export const ERROR_CODES = {
2
+ ANDROID_CATALOG_QUERY_FAILED: "ANDROID_CATALOG_QUERY_FAILED",
2
3
  ADB_QUERY_FAILED: "ADB_QUERY_FAILED",
3
4
  ANDROID_AVD_CREATE_FAILED: "ANDROID_AVD_CREATE_FAILED",
4
5
  ANDROID_SDK_TOOL_MISSING: "ANDROID_SDK_TOOL_MISSING",
package/dist/index.d.ts CHANGED
@@ -8,4 +8,5 @@ export * from "./configuredAvds.js";
8
8
  export * from "./runningEmulators.js";
9
9
  export * from "./lifecycle.js";
10
10
  export * from "./validation.js";
11
+ export * from "./catalog.js";
11
12
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -8,4 +8,5 @@ export * from "./configuredAvds.js";
8
8
  export * from "./runningEmulators.js";
9
9
  export * from "./lifecycle.js";
10
10
  export * from "./validation.js";
11
+ export * from "./catalog.js";
11
12
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@androperator/emulator",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Android emulator lifecycle library and structured CLI extracted from Androperator",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -21,7 +21,8 @@
21
21
  "README.md",
22
22
  "LICENSE",
23
23
  "NOTICE",
24
- "docs/provenance.md"
24
+ "docs/provenance.md",
25
+ ".agents/skills/create-android-emulator/"
25
26
  ],
26
27
  "engines": {
27
28
  "node": ">=24"