@yh-ui/yh-ui-skill 1.0.30
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 +40 -0
- package/assets/llms-full.txt +38 -0
- package/assets/llms.txt +22 -0
- package/assets/metadata.json +4 -0
- package/assets/skills/yh-ui/LICENSE.txt +21 -0
- package/assets/skills/yh-ui/README.md +53 -0
- package/assets/skills/yh-ui/SKILL.md +179 -0
- package/assets/skills/yh-ui/evals/model-eval-2026-05-16.md +47 -0
- package/assets/skills/yh-ui/references/agent-workflows.md +53 -0
- package/assets/skills/yh-ui/references/ai-components.md +82 -0
- package/assets/skills/yh-ui/references/api-cheatsheet.md +203 -0
- package/assets/skills/yh-ui/references/codegen-rubric.md +36 -0
- package/assets/skills/yh-ui/references/component-map.md +70 -0
- package/assets/skills/yh-ui/references/eval-scenarios.md +92 -0
- package/assets/skills/yh-ui/references/flow.md +54 -0
- package/assets/skills/yh-ui/references/nuxt.md +50 -0
- package/assets/skills/yh-ui/references/recipes-ai.md +58 -0
- package/assets/skills/yh-ui/references/recipes-flow.md +56 -0
- package/assets/skills/yh-ui/references/recipes-form-schema.md +82 -0
- package/assets/skills/yh-ui/references/recipes-table.md +83 -0
- package/assets/skills/yh-ui/references/request.md +70 -0
- package/assets/skills/yh-ui/references/source-truth.md +205 -0
- package/assets/skills/yh-ui/references/usage-patterns.md +111 -0
- package/assets/skills/yh-ui/references/vue-component-practices.md +84 -0
- package/dist/args.d.ts +2 -0
- package/dist/args.mjs +76 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.mjs +153 -0
- package/dist/fs.d.ts +5 -0
- package/dist/fs.mjs +23 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.mjs +10 -0
- package/dist/install.d.ts +4 -0
- package/dist/install.mjs +117 -0
- package/dist/targets.d.ts +6 -0
- package/dist/targets.mjs +64 -0
- package/dist/types.d.ts +53 -0
- package/dist/types.mjs +1 -0
- package/package.json +44 -0
package/dist/args.mjs
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { INSTALL_TARGETS } from "./types.mjs";
|
|
2
|
+
import { isInstallTarget } from "./targets.mjs";
|
|
3
|
+
export function parseArgs(argv) {
|
|
4
|
+
const parsed = {
|
|
5
|
+
command: "install",
|
|
6
|
+
force: false,
|
|
7
|
+
dryRun: false,
|
|
8
|
+
json: false,
|
|
9
|
+
help: false,
|
|
10
|
+
version: false
|
|
11
|
+
};
|
|
12
|
+
const args = [...argv];
|
|
13
|
+
const first = args[0];
|
|
14
|
+
if (first && !first.startsWith("-")) {
|
|
15
|
+
if (first === "install" || first === "doctor" || first === "help") {
|
|
16
|
+
parsed.command = first;
|
|
17
|
+
args.shift();
|
|
18
|
+
} else {
|
|
19
|
+
throw new Error(`Unknown command "${first}".`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
23
|
+
const current = args[index];
|
|
24
|
+
switch (current) {
|
|
25
|
+
case "--target":
|
|
26
|
+
case "-t": {
|
|
27
|
+
const value = args[index + 1];
|
|
28
|
+
if (!value) {
|
|
29
|
+
throw new Error(`Missing value for ${current}.`);
|
|
30
|
+
}
|
|
31
|
+
if (!isInstallTarget(value)) {
|
|
32
|
+
throw new Error(
|
|
33
|
+
`Invalid target "${value}". Expected one of: ${INSTALL_TARGETS.join(", ")}.`
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
parsed.target = value;
|
|
37
|
+
index += 1;
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
case "--out-dir":
|
|
41
|
+
case "-o": {
|
|
42
|
+
const value = args[index + 1];
|
|
43
|
+
if (!value) {
|
|
44
|
+
throw new Error(`Missing value for ${current}.`);
|
|
45
|
+
}
|
|
46
|
+
parsed.outDir = value;
|
|
47
|
+
index += 1;
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
case "--force":
|
|
51
|
+
case "-f":
|
|
52
|
+
parsed.force = true;
|
|
53
|
+
break;
|
|
54
|
+
case "--dry-run":
|
|
55
|
+
parsed.dryRun = true;
|
|
56
|
+
break;
|
|
57
|
+
case "--json":
|
|
58
|
+
parsed.json = true;
|
|
59
|
+
break;
|
|
60
|
+
case "--help":
|
|
61
|
+
case "-h":
|
|
62
|
+
parsed.help = true;
|
|
63
|
+
break;
|
|
64
|
+
case "--version":
|
|
65
|
+
case "-v":
|
|
66
|
+
parsed.version = true;
|
|
67
|
+
break;
|
|
68
|
+
default:
|
|
69
|
+
throw new Error(`Unknown option "${current}".`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (parsed.help) {
|
|
73
|
+
parsed.command = "help";
|
|
74
|
+
}
|
|
75
|
+
return parsed;
|
|
76
|
+
}
|
package/dist/cli.d.ts
ADDED
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import process from "node:process";
|
|
3
|
+
import { createInterface } from "node:readline/promises";
|
|
4
|
+
import { stdin as input, stdout as output } from "node:process";
|
|
5
|
+
import { INSTALL_TARGETS } from "./types.mjs";
|
|
6
|
+
import { parseArgs } from "./args.mjs";
|
|
7
|
+
import {
|
|
8
|
+
autoSelectTarget,
|
|
9
|
+
defaultBaseDirForTarget,
|
|
10
|
+
detectInstallTargetCandidates,
|
|
11
|
+
resolveInstallPlan
|
|
12
|
+
} from "./targets.mjs";
|
|
13
|
+
import { getPackageVersion, inspectInstallation, installSkill } from "./install.mjs";
|
|
14
|
+
function printHelp() {
|
|
15
|
+
console.log(`YH-UI skill installer
|
|
16
|
+
|
|
17
|
+
Usage:
|
|
18
|
+
yh-ui-skill install [options]
|
|
19
|
+
yh-ui-skill doctor [options]
|
|
20
|
+
yh-ui-skill --version
|
|
21
|
+
|
|
22
|
+
Options:
|
|
23
|
+
-t, --target <target> project | cursor | claude | codex | markdown
|
|
24
|
+
-o, --out-dir <path> Override the default target directory
|
|
25
|
+
-f, --force Overwrite an existing installation
|
|
26
|
+
--dry-run Print the install plan without copying files
|
|
27
|
+
--json Print machine-readable output
|
|
28
|
+
-h, --help Show help
|
|
29
|
+
-v, --version Show package version
|
|
30
|
+
`);
|
|
31
|
+
}
|
|
32
|
+
function resolveTargetSelection(value, fallback) {
|
|
33
|
+
if (!value) {
|
|
34
|
+
return fallback;
|
|
35
|
+
}
|
|
36
|
+
const numericIndex = Number(value);
|
|
37
|
+
if (!Number.isNaN(numericIndex) && numericIndex >= 1 && numericIndex <= INSTALL_TARGETS.length) {
|
|
38
|
+
return INSTALL_TARGETS[numericIndex - 1];
|
|
39
|
+
}
|
|
40
|
+
if (INSTALL_TARGETS.includes(value)) {
|
|
41
|
+
return value;
|
|
42
|
+
}
|
|
43
|
+
throw new Error(`Invalid target "${value}".`);
|
|
44
|
+
}
|
|
45
|
+
async function promptForInstallOptions(cwd) {
|
|
46
|
+
const candidates = await detectInstallTargetCandidates(cwd);
|
|
47
|
+
const defaultTarget = candidates.find((candidate) => candidate.detected)?.target ?? "project";
|
|
48
|
+
const rl = createInterface({ input, output });
|
|
49
|
+
try {
|
|
50
|
+
console.log("Select an installation target:");
|
|
51
|
+
INSTALL_TARGETS.forEach((target2, index) => {
|
|
52
|
+
const candidate = candidates.find((item) => item.target === target2);
|
|
53
|
+
const detectedLabel = candidate?.detected ? " [detected]" : "";
|
|
54
|
+
console.log(
|
|
55
|
+
` ${index + 1}. ${target2} (${defaultBaseDirForTarget(target2)})${detectedLabel} - ${candidate?.reason ?? ""}`
|
|
56
|
+
);
|
|
57
|
+
});
|
|
58
|
+
const defaultIndex = INSTALL_TARGETS.indexOf(defaultTarget) + 1;
|
|
59
|
+
const answer = (await rl.question(`Target [${defaultIndex} ${defaultTarget}]: `)).trim();
|
|
60
|
+
const target = resolveTargetSelection(answer, defaultTarget);
|
|
61
|
+
const defaultDir = defaultBaseDirForTarget(target);
|
|
62
|
+
const override = (await rl.question(
|
|
63
|
+
`Directory override (leave blank to use ${defaultDir}, accepts relative or absolute paths): `
|
|
64
|
+
)).trim();
|
|
65
|
+
if (!override) {
|
|
66
|
+
return { target };
|
|
67
|
+
}
|
|
68
|
+
return { target, outDir: override };
|
|
69
|
+
} finally {
|
|
70
|
+
rl.close();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
async function main() {
|
|
74
|
+
const parsed = parseArgs(process.argv.slice(2));
|
|
75
|
+
if (parsed.version) {
|
|
76
|
+
console.log(await getPackageVersion());
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (parsed.command === "help") {
|
|
80
|
+
printHelp();
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const cwd = process.cwd();
|
|
84
|
+
const resolvedInput = parsed.target || parsed.outDir ? { target: parsed.target ?? await autoSelectTarget(cwd), outDir: parsed.outDir } : parsed.command === "install" && process.stdin.isTTY && process.stdout.isTTY ? await promptForInstallOptions(cwd) : { target: await autoSelectTarget(cwd), outDir: void 0 };
|
|
85
|
+
const options = {
|
|
86
|
+
cwd,
|
|
87
|
+
target: resolvedInput.target,
|
|
88
|
+
outDir: resolvedInput.outDir,
|
|
89
|
+
force: parsed.force,
|
|
90
|
+
dryRun: parsed.dryRun
|
|
91
|
+
};
|
|
92
|
+
if (parsed.command === "doctor") {
|
|
93
|
+
const result2 = await inspectInstallation(options);
|
|
94
|
+
if (parsed.json) {
|
|
95
|
+
console.log(JSON.stringify(result2, null, 2));
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
console.log(`Target: ${result2.plan.target}`);
|
|
99
|
+
console.log(`Base dir: ${result2.plan.baseDir}`);
|
|
100
|
+
console.log(`Current CLI version: ${result2.currentVersion}`);
|
|
101
|
+
console.log(`Installed version: ${result2.version ?? "not installed"}`);
|
|
102
|
+
if (result2.exists && result2.upToDate) {
|
|
103
|
+
console.log("Status: installed and up to date");
|
|
104
|
+
} else if (result2.exists) {
|
|
105
|
+
console.log("Status: installed but needs refresh");
|
|
106
|
+
} else {
|
|
107
|
+
console.log("Status: missing files");
|
|
108
|
+
}
|
|
109
|
+
console.log("Checks:");
|
|
110
|
+
result2.checks.forEach((check) => {
|
|
111
|
+
console.log(`- ${check.exists ? "OK" : "MISS"} ${check.label}: ${check.path}`);
|
|
112
|
+
});
|
|
113
|
+
const detectedTargets = result2.detectedTargets.filter((candidate) => candidate.detected);
|
|
114
|
+
if (detectedTargets.length > 0) {
|
|
115
|
+
console.log("Detected targets:");
|
|
116
|
+
detectedTargets.forEach((candidate) => {
|
|
117
|
+
console.log(`- ${candidate.target}: ${candidate.baseDir} (${candidate.reason})`);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
if (result2.exists && result2.upToDate) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
if (result2.missingItems.length > 0) {
|
|
124
|
+
console.log("Missing items:");
|
|
125
|
+
result2.missingItems.forEach((item) => {
|
|
126
|
+
console.log(`- ${item}`);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
process.exitCode = 1;
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
const result = await installSkill(options);
|
|
133
|
+
if (parsed.json) {
|
|
134
|
+
console.log(JSON.stringify(result, null, 2));
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const plan = resolveInstallPlan(options);
|
|
138
|
+
if (parsed.dryRun) {
|
|
139
|
+
console.log(`Dry run complete for ${result.version}`);
|
|
140
|
+
} else {
|
|
141
|
+
console.log(`Installed YH-UI skill ${result.version}`);
|
|
142
|
+
}
|
|
143
|
+
console.log(`Target: ${plan.target}`);
|
|
144
|
+
console.log(`Base dir: ${plan.baseDir}`);
|
|
145
|
+
console.log(`Skill: ${plan.skillDir}`);
|
|
146
|
+
console.log(`LLMS: ${plan.llmsPath}`);
|
|
147
|
+
console.log(`LLMS Full: ${plan.llmsFullPath}`);
|
|
148
|
+
}
|
|
149
|
+
main().catch((error) => {
|
|
150
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
151
|
+
console.error(`yh-ui-skill: ${message}`);
|
|
152
|
+
process.exit(1);
|
|
153
|
+
});
|
package/dist/fs.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function pathExists(filePath: string): Promise<boolean>;
|
|
2
|
+
export declare function ensureParentDir(filePath: string): Promise<void>;
|
|
3
|
+
export declare function copyDirectory(sourceDir: string, targetDir: string): Promise<void>;
|
|
4
|
+
export declare function copyFile(sourcePath: string, targetPath: string): Promise<void>;
|
|
5
|
+
export declare function removePath(filePath: string): Promise<void>;
|
package/dist/fs.mjs
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { access, cp, mkdir, rm } from "node:fs/promises";
|
|
2
|
+
import { dirname } from "node:path";
|
|
3
|
+
export async function pathExists(filePath) {
|
|
4
|
+
try {
|
|
5
|
+
await access(filePath);
|
|
6
|
+
return true;
|
|
7
|
+
} catch {
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export async function ensureParentDir(filePath) {
|
|
12
|
+
await mkdir(dirname(filePath), { recursive: true });
|
|
13
|
+
}
|
|
14
|
+
export async function copyDirectory(sourceDir, targetDir) {
|
|
15
|
+
await cp(sourceDir, targetDir, { recursive: true, force: true });
|
|
16
|
+
}
|
|
17
|
+
export async function copyFile(sourcePath, targetPath) {
|
|
18
|
+
await ensureParentDir(targetPath);
|
|
19
|
+
await cp(sourcePath, targetPath, { force: true });
|
|
20
|
+
}
|
|
21
|
+
export async function removePath(filePath) {
|
|
22
|
+
await rm(filePath, { recursive: true, force: true });
|
|
23
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { parseArgs } from './args';
|
|
2
|
+
export { installSkill, inspectInstallation, getPackageVersion } from './install';
|
|
3
|
+
export { autoSelectTarget, defaultBaseDirForTarget, detectInstallTargetCandidates, isInstallTarget, resolveInstallPlan } from './targets';
|
|
4
|
+
export { INSTALL_TARGETS } from './types';
|
|
5
|
+
export type { DoctorResult, InstallOptions, InstallResult, InstallTarget, ParsedArgs, TargetCandidate } from './types';
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { parseArgs } from "./args.mjs";
|
|
2
|
+
export { installSkill, inspectInstallation, getPackageVersion } from "./install.mjs";
|
|
3
|
+
export {
|
|
4
|
+
autoSelectTarget,
|
|
5
|
+
defaultBaseDirForTarget,
|
|
6
|
+
detectInstallTargetCandidates,
|
|
7
|
+
isInstallTarget,
|
|
8
|
+
resolveInstallPlan
|
|
9
|
+
} from "./targets.mjs";
|
|
10
|
+
export { INSTALL_TARGETS } from "./types.mjs";
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { DoctorResult, InstallOptions, InstallResult } from './types';
|
|
2
|
+
export declare function getPackageVersion(): Promise<string>;
|
|
3
|
+
export declare function installSkill(options: InstallOptions): Promise<InstallResult>;
|
|
4
|
+
export declare function inspectInstallation(options: InstallOptions): Promise<DoctorResult>;
|
package/dist/install.mjs
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { join, relative } from "node:path";
|
|
4
|
+
import { copyDirectory, copyFile, ensureParentDir, pathExists, removePath } from "./fs.mjs";
|
|
5
|
+
import { detectInstallTargetCandidates, resolveInstallPlan } from "./targets.mjs";
|
|
6
|
+
const PACKAGE_ROOT = fileURLToPath(new URL("..", import.meta.url));
|
|
7
|
+
const ASSETS_ROOT = join(PACKAGE_ROOT, "assets");
|
|
8
|
+
const SKILL_ASSET_DIR = join(ASSETS_ROOT, "skills", "yh-ui");
|
|
9
|
+
const LLMS_ASSET_PATH = join(ASSETS_ROOT, "llms.txt");
|
|
10
|
+
const LLMS_FULL_ASSET_PATH = join(ASSETS_ROOT, "llms-full.txt");
|
|
11
|
+
export async function getPackageVersion() {
|
|
12
|
+
const packageJson = JSON.parse(await readFile(join(PACKAGE_ROOT, "package.json"), "utf8"));
|
|
13
|
+
return packageJson.version;
|
|
14
|
+
}
|
|
15
|
+
async function assertAssetsAvailable() {
|
|
16
|
+
const requiredPaths = [SKILL_ASSET_DIR, LLMS_ASSET_PATH, LLMS_FULL_ASSET_PATH];
|
|
17
|
+
for (const requiredPath of requiredPaths) {
|
|
18
|
+
if (!await pathExists(requiredPath)) {
|
|
19
|
+
throw new Error(
|
|
20
|
+
`Skill assets are missing at "${requiredPath}". Run the package build before publishing or using the CLI.`
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export async function installSkill(options) {
|
|
26
|
+
await assertAssetsAvailable();
|
|
27
|
+
const plan = resolveInstallPlan(options);
|
|
28
|
+
const version = await getPackageVersion();
|
|
29
|
+
const alreadyInstalled = await pathExists(plan.skillDir);
|
|
30
|
+
if (alreadyInstalled && !options.force) {
|
|
31
|
+
throw new Error(
|
|
32
|
+
`Destination "${plan.skillDir}" already exists. Re-run with --force to overwrite the previous installation.`
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
if (!options.dryRun && options.force) {
|
|
36
|
+
await Promise.all([
|
|
37
|
+
removePath(plan.skillDir),
|
|
38
|
+
removePath(plan.llmsPath),
|
|
39
|
+
removePath(plan.llmsFullPath),
|
|
40
|
+
removePath(plan.manifestPath)
|
|
41
|
+
]);
|
|
42
|
+
}
|
|
43
|
+
if (!options.dryRun) {
|
|
44
|
+
await ensureParentDir(plan.skillDir);
|
|
45
|
+
await copyDirectory(SKILL_ASSET_DIR, plan.skillDir);
|
|
46
|
+
await copyFile(LLMS_ASSET_PATH, plan.llmsPath);
|
|
47
|
+
await copyFile(LLMS_FULL_ASSET_PATH, plan.llmsFullPath);
|
|
48
|
+
const manifest = {
|
|
49
|
+
packageName: "@yh-ui/yh-ui-skill",
|
|
50
|
+
version,
|
|
51
|
+
target: plan.target,
|
|
52
|
+
baseDir: plan.baseDir,
|
|
53
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
54
|
+
files: [
|
|
55
|
+
"skills/yh-ui",
|
|
56
|
+
"skills/yh-ui/SKILL.md",
|
|
57
|
+
"llms.txt",
|
|
58
|
+
"llms-full.txt",
|
|
59
|
+
"yh-ui-skill.manifest.json"
|
|
60
|
+
]
|
|
61
|
+
};
|
|
62
|
+
await ensureParentDir(plan.manifestPath);
|
|
63
|
+
await writeFile(plan.manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
64
|
+
`, "utf8");
|
|
65
|
+
}
|
|
66
|
+
return { plan, version };
|
|
67
|
+
}
|
|
68
|
+
export async function inspectInstallation(options) {
|
|
69
|
+
const plan = resolveInstallPlan(options);
|
|
70
|
+
const currentVersion = await getPackageVersion();
|
|
71
|
+
const missingItems = [];
|
|
72
|
+
const checks = [
|
|
73
|
+
{
|
|
74
|
+
label: "Skill directory",
|
|
75
|
+
path: plan.skillDir,
|
|
76
|
+
exists: await pathExists(plan.skillDir)
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
label: "Skill entry",
|
|
80
|
+
path: join(plan.skillDir, "SKILL.md"),
|
|
81
|
+
exists: await pathExists(join(plan.skillDir, "SKILL.md"))
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
label: "llms.txt",
|
|
85
|
+
path: plan.llmsPath,
|
|
86
|
+
exists: await pathExists(plan.llmsPath)
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
label: "llms-full.txt",
|
|
90
|
+
path: plan.llmsFullPath,
|
|
91
|
+
exists: await pathExists(plan.llmsFullPath)
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
label: "Install manifest",
|
|
95
|
+
path: plan.manifestPath,
|
|
96
|
+
exists: await pathExists(plan.manifestPath)
|
|
97
|
+
}
|
|
98
|
+
];
|
|
99
|
+
checks.filter((check) => !check.exists).forEach((check) => missingItems.push(relative(plan.baseDir, check.path).replace(/\\/g, "/")));
|
|
100
|
+
let version = null;
|
|
101
|
+
if (checks.at(-1)?.exists) {
|
|
102
|
+
const manifest = JSON.parse(await readFile(plan.manifestPath, "utf8"));
|
|
103
|
+
version = manifest.version;
|
|
104
|
+
}
|
|
105
|
+
const exists = missingItems.length === 0;
|
|
106
|
+
const upToDate = exists && version === currentVersion;
|
|
107
|
+
return {
|
|
108
|
+
plan,
|
|
109
|
+
version,
|
|
110
|
+
currentVersion,
|
|
111
|
+
exists,
|
|
112
|
+
upToDate,
|
|
113
|
+
missingItems,
|
|
114
|
+
checks,
|
|
115
|
+
detectedTargets: await detectInstallTargetCandidates(options.cwd)
|
|
116
|
+
};
|
|
117
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { InstallPlan, InstallTarget, ResolveInstallPlanOptions, TargetCandidate } from './types';
|
|
2
|
+
export declare function isInstallTarget(value: string): value is InstallTarget;
|
|
3
|
+
export declare function defaultBaseDirForTarget(target: InstallTarget): string;
|
|
4
|
+
export declare function detectInstallTargetCandidates(cwd: string): Promise<TargetCandidate[]>;
|
|
5
|
+
export declare function autoSelectTarget(cwd: string): Promise<InstallTarget>;
|
|
6
|
+
export declare function resolveInstallPlan(options: ResolveInstallPlanOptions): InstallPlan;
|
package/dist/targets.mjs
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import { pathExists } from "./fs.mjs";
|
|
3
|
+
const TARGET_BASE_DIRS = {
|
|
4
|
+
project: ".yh-ui",
|
|
5
|
+
cursor: ".cursor",
|
|
6
|
+
claude: ".claude",
|
|
7
|
+
codex: ".codex",
|
|
8
|
+
markdown: "yh-ui-skill"
|
|
9
|
+
};
|
|
10
|
+
export function isInstallTarget(value) {
|
|
11
|
+
return Object.hasOwn(TARGET_BASE_DIRS, value);
|
|
12
|
+
}
|
|
13
|
+
export function defaultBaseDirForTarget(target) {
|
|
14
|
+
return TARGET_BASE_DIRS[target];
|
|
15
|
+
}
|
|
16
|
+
export async function detectInstallTargetCandidates(cwd) {
|
|
17
|
+
const packageJsonExists = await pathExists(resolve(cwd, "package.json"));
|
|
18
|
+
const candidates = await Promise.all(
|
|
19
|
+
["cursor", "claude", "codex", "project", "markdown"].map(
|
|
20
|
+
async (target) => {
|
|
21
|
+
const baseDir = resolve(cwd, defaultBaseDirForTarget(target));
|
|
22
|
+
const baseDirExists = await pathExists(baseDir);
|
|
23
|
+
if (target === "project") {
|
|
24
|
+
return {
|
|
25
|
+
target,
|
|
26
|
+
baseDir,
|
|
27
|
+
detected: packageJsonExists || baseDirExists,
|
|
28
|
+
reason: packageJsonExists ? "Detected package.json in the current workspace" : "Install into the default project knowledge directory"
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
if (target === "markdown") {
|
|
32
|
+
return {
|
|
33
|
+
target,
|
|
34
|
+
baseDir,
|
|
35
|
+
detected: false,
|
|
36
|
+
reason: "Export a portable Markdown knowledge bundle"
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
target,
|
|
41
|
+
baseDir,
|
|
42
|
+
detected: baseDirExists,
|
|
43
|
+
reason: baseDirExists ? `Detected an existing ${defaultBaseDirForTarget(target)} directory` : `Use the default ${defaultBaseDirForTarget(target)} directory`
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
)
|
|
47
|
+
);
|
|
48
|
+
return candidates.sort((left, right) => Number(right.detected) - Number(left.detected));
|
|
49
|
+
}
|
|
50
|
+
export async function autoSelectTarget(cwd) {
|
|
51
|
+
const candidates = await detectInstallTargetCandidates(cwd);
|
|
52
|
+
return candidates.find((candidate) => candidate.detected)?.target ?? "project";
|
|
53
|
+
}
|
|
54
|
+
export function resolveInstallPlan(options) {
|
|
55
|
+
const baseDir = resolve(options.cwd, options.outDir ?? defaultBaseDirForTarget(options.target));
|
|
56
|
+
return {
|
|
57
|
+
target: options.target,
|
|
58
|
+
baseDir,
|
|
59
|
+
skillDir: resolve(baseDir, "skills", "yh-ui"),
|
|
60
|
+
llmsPath: resolve(baseDir, "llms.txt"),
|
|
61
|
+
llmsFullPath: resolve(baseDir, "llms-full.txt"),
|
|
62
|
+
manifestPath: resolve(baseDir, "yh-ui-skill.manifest.json")
|
|
63
|
+
};
|
|
64
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export declare const INSTALL_TARGETS: readonly ["project", "cursor", "claude", "codex", "markdown"];
|
|
2
|
+
export type InstallTarget = (typeof INSTALL_TARGETS)[number];
|
|
3
|
+
export interface ResolveInstallPlanOptions {
|
|
4
|
+
cwd: string;
|
|
5
|
+
target: InstallTarget;
|
|
6
|
+
outDir?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface InstallPlan {
|
|
9
|
+
target: InstallTarget;
|
|
10
|
+
baseDir: string;
|
|
11
|
+
skillDir: string;
|
|
12
|
+
llmsPath: string;
|
|
13
|
+
llmsFullPath: string;
|
|
14
|
+
manifestPath: string;
|
|
15
|
+
}
|
|
16
|
+
export interface TargetCandidate {
|
|
17
|
+
target: InstallTarget;
|
|
18
|
+
baseDir: string;
|
|
19
|
+
detected: boolean;
|
|
20
|
+
reason: string;
|
|
21
|
+
}
|
|
22
|
+
export interface InstallOptions extends ResolveInstallPlanOptions {
|
|
23
|
+
force?: boolean;
|
|
24
|
+
dryRun?: boolean;
|
|
25
|
+
}
|
|
26
|
+
export interface InstallResult {
|
|
27
|
+
plan: InstallPlan;
|
|
28
|
+
version: string;
|
|
29
|
+
}
|
|
30
|
+
export interface DoctorResult {
|
|
31
|
+
plan: InstallPlan;
|
|
32
|
+
version: string | null;
|
|
33
|
+
currentVersion: string;
|
|
34
|
+
exists: boolean;
|
|
35
|
+
upToDate: boolean;
|
|
36
|
+
missingItems: string[];
|
|
37
|
+
checks: Array<{
|
|
38
|
+
label: string;
|
|
39
|
+
path: string;
|
|
40
|
+
exists: boolean;
|
|
41
|
+
}>;
|
|
42
|
+
detectedTargets: TargetCandidate[];
|
|
43
|
+
}
|
|
44
|
+
export interface ParsedArgs {
|
|
45
|
+
command: 'install' | 'doctor' | 'help';
|
|
46
|
+
target?: InstallTarget;
|
|
47
|
+
outDir?: string;
|
|
48
|
+
force: boolean;
|
|
49
|
+
dryRun: boolean;
|
|
50
|
+
json: boolean;
|
|
51
|
+
help: boolean;
|
|
52
|
+
version: boolean;
|
|
53
|
+
}
|
package/dist/types.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const INSTALL_TARGETS = ["project", "cursor", "claude", "codex", "markdown"];
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@yh-ui/yh-ui-skill",
|
|
3
|
+
"version": "1.0.30",
|
|
4
|
+
"description": "YH-UI skill installer for modern AI coding tools",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"yh-ui-skill": "./dist/cli.mjs"
|
|
8
|
+
},
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.mjs"
|
|
13
|
+
},
|
|
14
|
+
"./package.json": "./package.json"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"assets"
|
|
19
|
+
],
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "https://github.com/1079161148/yh-ui.git",
|
|
26
|
+
"directory": "packages/yh-ui-skill"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"yh-ui",
|
|
30
|
+
"ai",
|
|
31
|
+
"skill",
|
|
32
|
+
"cli",
|
|
33
|
+
"agent"
|
|
34
|
+
],
|
|
35
|
+
"homepage": "https://1079161148.github.io/yh-ui/",
|
|
36
|
+
"author": "YH-UI Team",
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "node ../../scripts/sync-yh-ui-skill-assets.mjs && unbuild",
|
|
40
|
+
"dev": "node ../../scripts/sync-yh-ui-skill-assets.mjs && unbuild --stub",
|
|
41
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
42
|
+
"lint": "eslint ."
|
|
43
|
+
}
|
|
44
|
+
}
|