@quicktvui/ai-cli 1.1.1 → 1.1.2

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
@@ -8,6 +8,15 @@ QuickTVUI skill runtime CLI.
8
8
  npm install -g @quicktvui/ai-cli @quicktvui/ai-skills
9
9
  ```
10
10
 
11
+ Starting from `@quicktvui/ai-cli@1.1.2`, global install/upgrade auto-runs
12
+ `quicktvui-ai update` to sync:
13
+
14
+ - `~/.agents/skills/quicktvui`
15
+ - `~/.gemini/GEMINI.md` bridge block
16
+ - `~/.gemini/settings.json` context file names
17
+
18
+ Set `QUICKTVUI_AI_SKIP_POSTINSTALL=1` to disable auto-sync.
19
+
11
20
  ## Commands
12
21
 
13
22
  ```bash
@@ -47,14 +56,12 @@ quicktvui-aicreate-project quick-tv-app
47
56
  - `--skip-node-install`: skip Node.js install stage in `setup-vue-env`
48
57
  - `--force-node-install`: force Node.js install stage in `setup-vue-env`
49
58
  - `--skip-yarn-install`: skip yarn global install in `setup-vue-env`
50
- - `--skip-quicktvui-cli-install`: skip `@quicktvui/cli` global install in `setup-vue-env`
51
59
  - `--skip-project-install`: skip project dependency install in `setup-vue-env`
52
60
  - `--auto-emulator <true|false>`: auto create/start emulator when no adb device
53
61
  - `--adb-path <path>`: custom adb path/command (or use env `QUICKTVUI_ADB_PATH`)
54
62
  - `--device-ip <ip[:port]>`: preferred real device endpoint for `adb connect`
55
63
  - `--avd-name <name>`: custom AVD name for `setup-android-env`
56
64
  - `--headless`: start emulator with `-no-window -no-audio`
57
- - `--runtime-setup-mode <direct|qui>`: runtime setup mode (default `direct`)
58
65
  - `--runtime-version <version>`: pin runtime version in `direct` mode
59
66
  - `--runtime-url <url>`: use custom runtime apk url in `direct` mode
60
67
  - `--server-host <ip>`: override debug server host IP
@@ -118,12 +125,6 @@ This command:
118
125
  10. Installs runtime APK and configures debug server host (direct mode by default).
119
126
  11. Launches runtime app and waits it enters running state.
120
127
 
121
- To use official interactive setup flow instead of direct mode:
122
-
123
- ```bash
124
- quicktvui-ai setup-android-env --project ./quick-tv-app --runtime-setup-mode qui
125
- ```
126
-
127
128
  ## Configure Vue env (Node + package manager)
128
129
 
129
130
  ```bash
@@ -133,7 +134,7 @@ quicktvui-ai setup-vue-env --project ./quick-tv-app
133
134
  This command:
134
135
 
135
136
  1. Ensures Node.js LTS (macOS/Windows auto install).
136
- 2. Ensures `yarn` and `@quicktvui/cli` are installed globally.
137
+ 2. Ensures `yarn` is installed globally.
137
138
  3. Installs project dependencies (`yarn install` or `npm install` fallback).
138
139
 
139
140
  ## Configure All Dev Envs
package/lib/index.js CHANGED
@@ -7,7 +7,13 @@ const https = require("https");
7
7
  const net = require("net");
8
8
  const { spawnSync, spawn } = require("child_process");
9
9
 
10
- const PACKAGE_VERSION = "0.1.4";
10
+ const PACKAGE_VERSION = (() => {
11
+ try {
12
+ return require("../package.json").version || "0.0.0";
13
+ } catch (error) {
14
+ return "0.0.0";
15
+ }
16
+ })();
11
17
  const DEFAULT_INSTALL_DIR = path.join(
12
18
  os.homedir(),
13
19
  ".agents",
@@ -33,6 +39,8 @@ const REQUIRED_SKILL_FILES = [
33
39
  "SKILL.md",
34
40
  path.join("references", "scaffold-checklist.md"),
35
41
  path.join("references", "create-project-checklist.md"),
42
+ path.join("references", "dev-env-checklist.md"),
43
+ path.join("references", "esapp-protocol-cheatsheet.md"),
36
44
  path.join("references", "lookup-checklist.md"),
37
45
  path.join("references", "bug-report-template.md"),
38
46
  ];
@@ -1783,10 +1791,6 @@ async function runSetupVueEnv(args) {
1783
1791
  );
1784
1792
  const skipNodeInstall = toBooleanFlag(args["skip-node-install"], false);
1785
1793
  const skipYarnInstall = toBooleanFlag(args["skip-yarn-install"], false);
1786
- const skipQuicktvuiCliInstall = toBooleanFlag(
1787
- args["skip-quicktvui-cli-install"],
1788
- false,
1789
- );
1790
1794
  const skipProjectInstall = toBooleanFlag(args["skip-project-install"], false);
1791
1795
 
1792
1796
  if (
@@ -1818,13 +1822,6 @@ async function runSetupVueEnv(args) {
1818
1822
  runCommand("npm", ["install", "-g", "yarn"], { stdio: "inherit" });
1819
1823
  }
1820
1824
 
1821
- if (!skipQuicktvuiCliInstall && !commandCanRun("qui", ["--help"])) {
1822
- console.log("Installing @quicktvui/cli globally...");
1823
- runCommand("npm", ["install", "-g", "@quicktvui/cli@latest"], {
1824
- stdio: "inherit",
1825
- });
1826
- }
1827
-
1828
1825
  if (!skipProjectInstall) {
1829
1826
  if (!exists(path.join(projectRoot, "package.json"))) {
1830
1827
  throw new Error(`Missing package.json in project root: ${projectRoot}`);
@@ -1865,10 +1862,6 @@ async function runSetupAndroidEnv(args) {
1865
1862
  const projectRoot = args.project ? path.resolve(args.project) : process.cwd();
1866
1863
  const skipRuntimeSetup = toBooleanFlag(args["skip-runtime-setup"], false);
1867
1864
  const autoEmulator = toBooleanFlag(args["auto-emulator"], true);
1868
- const runtimeSetupMode =
1869
- typeof args["runtime-setup-mode"] === "string"
1870
- ? String(args["runtime-setup-mode"]).trim().toLowerCase()
1871
- : "direct";
1872
1865
  const avdName =
1873
1866
  typeof args["avd-name"] === "string" && args["avd-name"].trim()
1874
1867
  ? args["avd-name"].trim()
@@ -2025,23 +2018,12 @@ async function runSetupAndroidEnv(args) {
2025
2018
 
2026
2019
  let hostIp = getLocalIPv4Address();
2027
2020
  if (!skipRuntimeSetup) {
2028
- if (runtimeSetupMode === "qui") {
2029
- if (!commandCanRun("qui", ["--help"])) {
2030
- throw new Error(
2031
- "QuickTVUI CLI 'qui' is unavailable. Run: npm install -g @quicktvui/cli@latest",
2032
- );
2033
- }
2034
- console.log("Running 'qui setup' to configure runtime APK...");
2035
- runCommand("qui", ["setup"], { cwd: projectRoot });
2036
- hostIp = getLocalIPv4Address();
2037
- } else {
2038
- const runtimeResult = await ensureRuntimeInstalledAndConfigured(
2039
- adbPath,
2040
- targetSerial,
2041
- args,
2042
- );
2043
- hostIp = runtimeResult.hostIp;
2044
- }
2021
+ const runtimeResult = await ensureRuntimeInstalledAndConfigured(
2022
+ adbPath,
2023
+ targetSerial,
2024
+ args,
2025
+ );
2026
+ hostIp = runtimeResult.hostIp;
2045
2027
  } else {
2046
2028
  console.log("Skip runtime setup due to --skip-runtime-setup.");
2047
2029
  }
@@ -2216,34 +2198,155 @@ async function runRunEsapp(args) {
2216
2198
  console.log("ES app launch command sent.");
2217
2199
  }
2218
2200
 
2219
- function resolveSkillsSource() {
2201
+ function parseVersionSegments(version) {
2202
+ const normalized = String(version || "0.0.0")
2203
+ .trim()
2204
+ .split("-")[0];
2205
+ const parts = normalized ? normalized.split(".") : [];
2206
+ if (parts.length === 0) return [0, 0, 0];
2207
+
2208
+ return parts.map((part) => {
2209
+ const parsed = Number.parseInt(part, 10);
2210
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : 0;
2211
+ });
2212
+ }
2213
+
2214
+ function compareVersionStrings(left, right) {
2215
+ const leftParts = parseVersionSegments(left);
2216
+ const rightParts = parseVersionSegments(right);
2217
+ const total = Math.max(leftParts.length, rightParts.length);
2218
+ for (let i = 0; i < total; i += 1) {
2219
+ const leftValue = leftParts[i] || 0;
2220
+ const rightValue = rightParts[i] || 0;
2221
+ if (leftValue > rightValue) return 1;
2222
+ if (leftValue < rightValue) return -1;
2223
+ }
2224
+ return 0;
2225
+ }
2226
+
2227
+ function buildSkillsSourceCandidateFromPackageRoot(packageRoot, sourceLabel) {
2228
+ if (!packageRoot) return null;
2229
+ const resolvedPackageRoot = path.resolve(packageRoot);
2230
+ const sourceDir = path.join(resolvedPackageRoot, "skills", "quicktvui");
2231
+ if (!exists(sourceDir)) return null;
2232
+
2233
+ let version = "0.0.0";
2234
+ const packageJsonPath = path.join(resolvedPackageRoot, "package.json");
2235
+ if (exists(packageJsonPath)) {
2236
+ try {
2237
+ const packageJson = readJsonFile(packageJsonPath);
2238
+ if (
2239
+ packageJson &&
2240
+ typeof packageJson.version === "string" &&
2241
+ packageJson.version.trim()
2242
+ ) {
2243
+ version = packageJson.version.trim();
2244
+ }
2245
+ } catch (error) {
2246
+ // Ignore parse errors; keep default version for ordering.
2247
+ }
2248
+ }
2249
+
2250
+ return {
2251
+ sourceLabel,
2252
+ sourceDir,
2253
+ packageRoot: resolvedPackageRoot,
2254
+ version,
2255
+ };
2256
+ }
2257
+
2258
+ function buildSkillsSourceCandidateFromRequire() {
2220
2259
  try {
2221
- // Preferred: installed dependency
2222
2260
  const { getSkillsRoot } = require("@quicktvui/ai-skills");
2223
- const resolved = path.join(getSkillsRoot(), "quicktvui");
2224
- if (exists(resolved)) return resolved;
2261
+ if (typeof getSkillsRoot !== "function") return null;
2262
+ const resolvedSkillsRoot = getSkillsRoot();
2263
+ const sourceDir = path.join(resolvedSkillsRoot, "quicktvui");
2264
+ if (!exists(sourceDir)) return null;
2265
+
2266
+ let packageRoot = null;
2267
+ let version = "0.0.0";
2268
+ try {
2269
+ const packageJsonPath =
2270
+ require.resolve("@quicktvui/ai-skills/package.json");
2271
+ packageRoot = path.dirname(packageJsonPath);
2272
+ const packageJson = readJsonFile(packageJsonPath);
2273
+ if (
2274
+ packageJson &&
2275
+ typeof packageJson.version === "string" &&
2276
+ packageJson.version.trim()
2277
+ ) {
2278
+ version = packageJson.version.trim();
2279
+ }
2280
+ } catch (error) {
2281
+ // Keep fallback metadata if package.json cannot be resolved.
2282
+ }
2283
+
2284
+ return {
2285
+ sourceLabel: "dependency-resolved",
2286
+ sourceDir: path.resolve(sourceDir),
2287
+ packageRoot: packageRoot ? path.resolve(packageRoot) : null,
2288
+ version,
2289
+ };
2225
2290
  } catch (error) {
2226
- // Fallback for monorepo local development
2291
+ return null;
2227
2292
  }
2293
+ }
2294
+
2295
+ function resolveSkillsSource() {
2296
+ const candidates = [];
2297
+ const seenSourceDirs = new Set();
2228
2298
 
2229
- const localFallback = path.resolve(
2299
+ function addCandidate(candidate) {
2300
+ if (!candidate || !candidate.sourceDir) return;
2301
+ const key = path.resolve(candidate.sourceDir);
2302
+ if (seenSourceDirs.has(key)) return;
2303
+ seenSourceDirs.add(key);
2304
+ candidates.push(candidate);
2305
+ }
2306
+
2307
+ // Prefer globally upgraded sibling package if present.
2308
+ const globalSiblingPackageRoot = path.resolve(
2309
+ __dirname,
2310
+ "..",
2311
+ "..",
2312
+ "ai-skills",
2313
+ );
2314
+ addCandidate(
2315
+ buildSkillsSourceCandidateFromPackageRoot(
2316
+ globalSiblingPackageRoot,
2317
+ "global-sibling",
2318
+ ),
2319
+ );
2320
+
2321
+ // Dependency resolution keeps compatibility when only @quicktvui/ai-cli is installed.
2322
+ addCandidate(buildSkillsSourceCandidateFromRequire());
2323
+
2324
+ // Monorepo fallback for local development.
2325
+ const monorepoPackageRoot = path.resolve(
2230
2326
  __dirname,
2231
2327
  "..",
2232
2328
  "..",
2233
2329
  "..",
2234
2330
  "packages",
2235
2331
  "quicktvui-ai-skills",
2236
- "skills",
2237
- "quicktvui",
2332
+ );
2333
+ addCandidate(
2334
+ buildSkillsSourceCandidateFromPackageRoot(monorepoPackageRoot, "monorepo"),
2238
2335
  );
2239
2336
 
2240
- if (!exists(localFallback)) {
2337
+ if (candidates.length === 0) {
2241
2338
  throw new Error(
2242
2339
  "Unable to locate QuickTVUI skill assets. Install @quicktvui/ai-skills or use repository local layout.",
2243
2340
  );
2244
2341
  }
2245
2342
 
2246
- return localFallback;
2343
+ candidates.sort((left, right) => {
2344
+ const versionOrder = compareVersionStrings(right.version, left.version);
2345
+ if (versionOrder !== 0) return versionOrder;
2346
+ return left.sourceDir.localeCompare(right.sourceDir);
2347
+ });
2348
+
2349
+ return candidates[0].sourceDir;
2247
2350
  }
2248
2351
 
2249
2352
  function getInstallDir(args) {
@@ -2295,7 +2398,7 @@ Commands:
2295
2398
  validate Strict check for required skill files (non-zero exit if missing)
2296
2399
  update Reinstall skill assets to target directory
2297
2400
  create-project Create a QuickTVUI project (remote clone, local fallback)
2298
- setup-vue-env Setup Vue development environment (Node/yarn/quicktvui cli)
2401
+ setup-vue-env Setup Vue development environment (Node/yarn)
2299
2402
  setup-android-env Configure Android device/emulator + runtime environment
2300
2403
  setup-all-env Setup both Vue and Android development environments
2301
2404
  run-dev Run project dev command (optionally checks Android env first)
@@ -2319,14 +2422,12 @@ Options:
2319
2422
  --skip-node-install Skip Node.js auto-install stage in setup-vue-env
2320
2423
  --force-node-install Force Node.js auto-install even if current version is ok
2321
2424
  --skip-yarn-install Skip yarn global install in setup-vue-env
2322
- --skip-quicktvui-cli-install Skip @quicktvui/cli global install in setup-vue-env
2323
2425
  --skip-project-install Skip project dependency install in setup-vue-env
2324
2426
  --auto-emulator <true|false> Auto create/start emulator when no adb device
2325
2427
  --adb-path <path> Custom adb binary path/command (or set QUICKTVUI_ADB_PATH)
2326
2428
  --device-ip <ip[:port]> Preferred real device endpoint for adb connect
2327
2429
  --avd-name <name> Custom AVD name for setup-android-env
2328
2430
  --headless Start emulator with -no-window -no-audio
2329
- --runtime-setup-mode <direct|qui> Runtime setup mode in setup-android-env (default: direct)
2330
2431
  --runtime-version <version> Pin runtime version when direct mode is used
2331
2432
  --runtime-url <url> Use custom runtime apk url in direct mode
2332
2433
  --server-host <ip> Override local debug server host IP
@@ -2771,7 +2872,7 @@ async function runCreateProject(args) {
2771
2872
  "- ensured: package.json name/version updated and @quicktvui/ai added to devDependencies",
2772
2873
  );
2773
2874
  console.log(
2774
- "- next: if not configured, run 'npm install -g @quicktvui/cli@latest' and 'qui setup'",
2875
+ "- next: run 'quicktvui-ai setup-all-env --project <project-path>' to prepare development and runtime environments",
2775
2876
  );
2776
2877
  }
2777
2878
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quicktvui/ai-cli",
3
- "version": "1.1.1",
3
+ "version": "1.1.2",
4
4
  "description": "CLI for installing and validating QuickTVUI AI skills",
5
5
  "bin": {
6
6
  "quicktvui-ai": "bin/quicktvui-ai.js",
@@ -8,6 +8,9 @@
8
8
  "quicktvui-aicreate-project": "bin/quicktvui-aicreate-project.js"
9
9
  },
10
10
  "main": "lib/index.js",
11
+ "scripts": {
12
+ "postinstall": "node scripts/postinstall-sync.js"
13
+ },
11
14
  "files": [
12
15
  "bin",
13
16
  "lib",
@@ -25,6 +28,6 @@
25
28
  "author": "QuickTVUI",
26
29
  "license": "MIT",
27
30
  "dependencies": {
28
- "@quicktvui/ai-skills": "^0.1.0"
31
+ "@quicktvui/ai-skills": "^1.1.1"
29
32
  }
30
33
  }
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { runCli } = require("../lib/index");
4
+
5
+ function isTruthy(value) {
6
+ return value === true || value === "true" || value === "1";
7
+ }
8
+
9
+ function isGlobalInstall() {
10
+ if (isTruthy(process.env.npm_config_global)) return true;
11
+ return process.env.npm_config_location === "global";
12
+ }
13
+
14
+ async function main() {
15
+ if (isTruthy(process.env.QUICKTVUI_AI_SKIP_POSTINSTALL)) {
16
+ return;
17
+ }
18
+ if (!isGlobalInstall()) {
19
+ return;
20
+ }
21
+
22
+ try {
23
+ await runCli(["update"]);
24
+ console.log(
25
+ "[quicktvui-ai] postinstall: synced latest skill files into ~/.agents/skills/quicktvui.",
26
+ );
27
+ } catch (error) {
28
+ console.warn(
29
+ `[quicktvui-ai] postinstall: unable to auto-sync skill files (${error.message}). Run 'quicktvui-ai update' manually.`,
30
+ );
31
+ }
32
+ }
33
+
34
+ main();