@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 +10 -9
- package/lib/index.js +148 -47
- package/package.json +5 -2
- package/scripts/postinstall-sync.js +34 -0
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`
|
|
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 =
|
|
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
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
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
|
|
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
|
-
|
|
2224
|
-
|
|
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
|
-
|
|
2291
|
+
return null;
|
|
2227
2292
|
}
|
|
2293
|
+
}
|
|
2294
|
+
|
|
2295
|
+
function resolveSkillsSource() {
|
|
2296
|
+
const candidates = [];
|
|
2297
|
+
const seenSourceDirs = new Set();
|
|
2228
2298
|
|
|
2229
|
-
|
|
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
|
-
|
|
2237
|
-
|
|
2332
|
+
);
|
|
2333
|
+
addCandidate(
|
|
2334
|
+
buildSkillsSourceCandidateFromPackageRoot(monorepoPackageRoot, "monorepo"),
|
|
2238
2335
|
);
|
|
2239
2336
|
|
|
2240
|
-
if (
|
|
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
|
-
|
|
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
|
|
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:
|
|
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.
|
|
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": "^
|
|
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();
|