@h-ai/cli 0.1.0-alpha.37 → 0.1.0-alpha.38
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/dist/{chunk-5IGMJVV5.js → chunk-WUYLYCW2.js} +17 -8
- package/dist/chunk-WUYLYCW2.js.map +1 -0
- package/dist/{cli-skill-templates-JMSV2SVW.js → cli-skill-templates-ZIWYMS4Y.js} +3 -3
- package/dist/{cli-skill-templates-JMSV2SVW.js.map → cli-skill-templates-ZIWYMS4Y.js.map} +1 -1
- package/dist/index.js +9 -4
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/Cargo.toml.hbs +7 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/tauri.conf.json.hbs +7 -2
- package/templates/base/package.json.hbs +1 -1
- package/templates/skills/bridges/fullstack/{AGENTS.md → AGENTS.md.hbs} +10 -10
- package/templates/skills/bridges/fullstack/{CLAUDE.md → CLAUDE.md.hbs} +1 -1
- package/templates/skills/bridges/fullstack/{copilot-instructions.md → copilot-instructions.md.hbs} +5 -5
- package/dist/chunk-5IGMJVV5.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@h-ai/cli",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.0-alpha.
|
|
4
|
+
"version": "0.1.0-alpha.38",
|
|
5
5
|
"description": "Hai Framework CLI for project scaffolding and code generation.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"keywords": [
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"ora": "^9.1.0",
|
|
35
35
|
"prompts": "^2.4.2",
|
|
36
36
|
"yaml": "^2.7.0",
|
|
37
|
-
"@h-ai/core": "0.1.0-alpha.
|
|
37
|
+
"@h-ai/core": "0.1.0-alpha.38"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/fs-extra": "^11.0.4",
|
|
@@ -11,6 +11,13 @@ edition = "2021"
|
|
|
11
11
|
name = "{{fullstack.nativeAppIdSegment}}_desktop_lib"
|
|
12
12
|
crate-type = ["staticlib", "cdylib", "rlib"]
|
|
13
13
|
|
|
14
|
+
[profile.release]
|
|
15
|
+
opt-level = "z"
|
|
16
|
+
lto = true
|
|
17
|
+
codegen-units = 1
|
|
18
|
+
panic = "abort"
|
|
19
|
+
strip = true
|
|
20
|
+
|
|
14
21
|
[build-dependencies]
|
|
15
22
|
tauri-build = { version = "2", features = [] }
|
|
16
23
|
|
|
@@ -23,12 +23,17 @@
|
|
|
23
23
|
}
|
|
24
24
|
],
|
|
25
25
|
"security": {
|
|
26
|
-
"
|
|
26
|
+
"headers": {
|
|
27
|
+
"Cross-Origin-Opener-Policy": "same-origin",
|
|
28
|
+
"Cross-Origin-Embedder-Policy": "require-corp",
|
|
29
|
+
"Cross-Origin-Resource-Policy": "same-origin"
|
|
30
|
+
},
|
|
31
|
+
"csp": "default-src 'self'; img-src 'self' data: https:; style-src 'self' 'unsafe-inline'; script-src 'self' 'wasm-unsafe-eval'; worker-src 'self' blob:; connect-src 'self' http://localhost:3000 http://127.0.0.1:3000 ws://localhost:* ws://127.0.0.1:*; font-src 'self' data:"
|
|
27
32
|
}
|
|
28
33
|
},
|
|
29
34
|
"bundle": {
|
|
30
35
|
"active": true,
|
|
31
|
-
"targets": "
|
|
36
|
+
"targets": ["nsis"],
|
|
32
37
|
"icon": [
|
|
33
38
|
"icons/32x32.png",
|
|
34
39
|
"icons/128x128.png",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "{{projectName}}",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.38",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "{{#if_eq appType 'admin'}}Enterprise management system built with hai Agent Framework{{/if_eq}}{{#if_eq appType 'website'}}Enterprise website built with hai Agent Framework{{/if_eq}}{{#if_eq appType 'h5'}}Mobile H5 app built with hai Agent Framework{{/if_eq}}{{#if_eq appType 'api'}}REST API service built with hai Agent Framework{{/if_eq}}{{#if_eq appType 'mobile-app'}}Mobile app built with hai Agent Framework{{/if_eq}}",
|
|
6
6
|
"keywords": ["hai", {{#unless isSvelteOnlyApp}}"sveltekit", {{/unless}}"svelte5", "{{appType}}"],
|
|
@@ -21,21 +21,21 @@
|
|
|
21
21
|
|
|
22
22
|
## 影响分析(M / L 任务必须输出)
|
|
23
23
|
|
|
24
|
-
- 直接影响:哪些 `packages
|
|
24
|
+
- 直接影响:哪些 `packages/{{projectName}}-contract`、`packages/{{projectName}}-serv`、`packages/{{projectName}}-shared`、`apps/{{projectName}}-*`、README、测试、打包脚本会变。
|
|
25
25
|
- 间接影响:哪些 workspace 依赖、typed client、Capacitor/Tauri 配置、i18n 编译和 e2e 需要同步。
|
|
26
26
|
|
|
27
27
|
## 项目概述
|
|
28
28
|
|
|
29
29
|
本项目是 hai-framework fullstack 工作区:
|
|
30
30
|
|
|
31
|
-
- `packages
|
|
32
|
-
- `packages
|
|
33
|
-
- `packages
|
|
34
|
-
- `apps
|
|
35
|
-
- `apps
|
|
36
|
-
- `apps
|
|
31
|
+
- `packages/{{projectName}}-contract`:前后端共享 API contract、Zod schema 与类型。
|
|
32
|
+
- `packages/{{projectName}}-serv`:后端服务,使用 `@h-ai/serv` 实现业务 API。
|
|
33
|
+
- `packages/{{projectName}}-shared`:跨端共享 UI Shell、主题、语言切换和 typed API client。
|
|
34
|
+
- `apps/{{projectName}}-web`:Svelte 5 + Vite Web 前端。
|
|
35
|
+
- `apps/{{projectName}}-app`:Svelte 5 + Vite + Capacitor 移动端 SPA。
|
|
36
|
+
- `apps/{{projectName}}-desktop`:Svelte 5 + Vite + Tauri v2 桌面端。
|
|
37
37
|
|
|
38
|
-
前端只做 UI 与请求编排;后端业务逻辑放在 `packages
|
|
38
|
+
前端只做 UI 与请求编排;后端业务逻辑放在 `packages/{{projectName}}-serv`,不要写进前端组件。
|
|
39
39
|
|
|
40
40
|
## 架构边界
|
|
41
41
|
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
- 公共 API 返回 `HaiResult<T>`,错误直接透传,不重新包装。
|
|
44
44
|
- 用户可见文本走 i18n:shared 放跨端文案,各 app 放本端文案。
|
|
45
45
|
- 移动端 token 使用 Capacitor 安全存储;Web 使用 httpOnly cookie;桌面端按 Tauri 安全边界配置。
|
|
46
|
-
- Web / App / Desktop 前端不承载后端业务逻辑;服务端逻辑统一放在 `packages
|
|
47
|
-
- 共享 UI、typed API client、主题与语言切换放在 `packages
|
|
46
|
+
- Web / App / Desktop 前端不承载后端业务逻辑;服务端逻辑统一放在 `packages/{{projectName}}-serv`。
|
|
47
|
+
- 共享 UI、typed API client、主题与语言切换放在 `packages/{{projectName}}-shared`。
|
|
48
48
|
- 本样板默认不使用 `@h-ai/kit`;不要把 fullstack 后端逻辑写回 SvelteKit 式 `load` / route 模式。
|
|
49
49
|
|
|
50
50
|
## 工作流程
|
package/templates/skills/bridges/fullstack/{copilot-instructions.md → copilot-instructions.md.hbs}
RENAMED
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
|
|
11
11
|
## 技术栈要点
|
|
12
12
|
|
|
13
|
-
- Contract:`packages
|
|
14
|
-
- Fullstack 服务端:`packages
|
|
15
|
-
- Shared:`packages
|
|
13
|
+
- Contract:`packages/{{projectName}}-contract` 定义 API contract、schema 与共享类型。
|
|
14
|
+
- Fullstack 服务端:`packages/{{projectName}}-serv` 使用 `@h-ai/serv` 实现业务 API。
|
|
15
|
+
- Shared:`packages/{{projectName}}-shared` 放跨端 Shell、i18n、主题和 typed API client。
|
|
16
16
|
- Web:Svelte 5 + Vite 前端。
|
|
17
17
|
- App:Svelte 5 + Vite + Capacitor 原生壳。
|
|
18
18
|
- Desktop:Svelte 5 + Vite + Tauri v2 纯客户端壳。
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
## 开发流程
|
|
32
32
|
|
|
33
33
|
1. 先检索相关 package、app、workspace 脚本、messages 和测试。
|
|
34
|
-
2.
|
|
34
|
+
2. 修改公共契约后,全局检索并更新 serv procedure、shared client、所有受影响的 `packages/*`、`apps/*` 和 e2e。
|
|
35
35
|
3. 修改 App / Desktop 时,同时检查 Capacitor / Tauri v2 原生壳配置与打包脚本。
|
|
36
36
|
4. 不要把未运行或失败的门禁写成“已通过”。
|
|
37
37
|
|
|
@@ -50,5 +50,5 @@ pnpm package
|
|
|
50
50
|
## 完成条件
|
|
51
51
|
|
|
52
52
|
- README、`.agents/skills/**/SKILL.md`、i18n、测试与实现同步。
|
|
53
|
-
- 修改公共契约后,全局检索并更新所有受影响的 `packages/*`、`apps/*` 和
|
|
53
|
+
- 修改公共契约后,全局检索并更新所有受影响的 `packages/*`、`apps/*` 和 e2e。
|
|
54
54
|
- 交付说明中列出门禁状态、受影响 package/app 与未完成项。
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/cli-skill-templates.ts"],"names":[],"mappings":"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","file":"chunk-5IGMJVV5.js","sourcesContent":["/**\n * @h-ai/cli — Skill 模板生成\n *\n * 将 Skill 模板文件复制到用户项目中,供 AI 编程助手使用。\n * @module cli-skill-templates\n */\n\nimport type { AppType } from '../cli-types.js'\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport fse from 'fs-extra'\n\n/**\n * 模块名到 Skill 目录名的映射\n */\nconst MODULE_SKILL_MAP: Record<string, string> = {\n 'db': 'hai-reldb',\n 'reldb': 'hai-reldb',\n 'cache': 'hai-cache',\n 'iam': 'hai-iam',\n 'storage': 'hai-storage',\n 'ai': 'hai-ai',\n 'crypto': 'hai-crypto',\n 'payment': 'hai-payment',\n 'vecdb': 'hai-vecdb',\n 'datapipe': 'hai-datapipe',\n 'reach': 'hai-reach',\n 'scheduler': 'hai-scheduler',\n 'audit': 'hai-audit',\n 'deploy': 'hai-deploy',\n 'kit': 'hai-kit',\n 'ui': 'hai-ui',\n 'api-client': 'hai-api-client',\n 'capacitor': 'hai-capacitor',\n}\n\n/**\n * 各 appType 互斥的 Skill。\n *\n * 生成样板工程时,默认复制 templates/skills 下所有 hai-* Skill,\n * 仅排除与当前样板技术栈明显冲突的少数 Skill。\n */\nconst SKILL_EXCLUSIONS_BY_APP_TYPE: Partial<Record<AppType, string[]>> = {\n 'admin': ['hai-serv', 'hai-api-contract', 'hai-api-client', 'hai-capacitor'],\n 'website': ['hai-serv', 'hai-api-contract', 'hai-api-client', 'hai-capacitor'],\n 'h5': ['hai-serv', 'hai-api-contract', 'hai-api-client', 'hai-capacitor'],\n 'api': ['hai-ui', 'hai-kit', 'hai-capacitor'],\n 'mobile-app': ['hai-core', 'hai-kit', 'hai-serv', 'hai-api-contract'],\n 'fullstack': ['hai-kit'],\n}\n\nconst WORKFLOW_SKILLS = [\n 'hai-build',\n 'hai-app-create',\n 'hai-app-review',\n 'hai-app-tests',\n]\n\nconst PACKAGE_SKILL_MAP: Record<string, string> = {\n '@h-ai/api-contract': 'hai-api-contract',\n '@h-ai/api-client': 'hai-api-client',\n '@h-ai/core': 'hai-core',\n '@h-ai/serv': 'hai-serv',\n '@h-ai/kit': 'hai-kit',\n '@h-ai/ui': 'hai-ui',\n '@h-ai/reldb': 'hai-reldb',\n '@h-ai/cache': 'hai-cache',\n '@h-ai/iam': 'hai-iam',\n '@h-ai/storage': 'hai-storage',\n '@h-ai/ai': 'hai-ai',\n '@h-ai/crypto': 'hai-crypto',\n '@h-ai/payment': 'hai-payment',\n '@h-ai/vecdb': 'hai-vecdb',\n '@h-ai/datapipe': 'hai-datapipe',\n '@h-ai/reach': 'hai-reach',\n '@h-ai/scheduler': 'hai-scheduler',\n '@h-ai/audit': 'hai-audit',\n '@h-ai/deploy': 'hai-deploy',\n '@h-ai/capacitor': 'hai-capacitor',\n}\n\nconst SKILL_TARGET_DIRS = ['.agents/skills'] as const\n\nconst BRIDGE_FILES = [\n {\n source: 'copilot-instructions.md',\n destination: '.github/copilot-instructions.md',\n },\n {\n source: 'CLAUDE.md',\n destination: 'CLAUDE.md',\n },\n {\n source: 'AGENTS.md',\n destination: 'AGENTS.md',\n },\n {\n source: 'opencode.json',\n destination: 'opencode.json',\n },\n] as const\n\nconst BRIDGE_PROFILE_REGEX = /^[a-z0-9-]+$/\n\nasync function listTemplateSkillNames(templatesDir: string): Promise<string[]> {\n const entries = await fse.readdir(templatesDir, { withFileTypes: true })\n const skillNames: string[] = []\n\n for (const entry of entries) {\n if (!entry.isDirectory() || !entry.name.startsWith('hai-')) {\n continue\n }\n\n const skillFilePath = path.join(templatesDir, entry.name, 'SKILL.md')\n if (await fse.pathExists(skillFilePath)) {\n skillNames.push(entry.name)\n }\n }\n\n return skillNames.sort((a, b) => a.localeCompare(b))\n}\n\nexport function resolveCompatibleSkillNames(\n skillNames: string[],\n appType?: AppType,\n): string[] {\n const excludedSkills = new Set(appType ? SKILL_EXCLUSIONS_BY_APP_TYPE[appType] ?? [] : [])\n return skillNames.filter(skillName => !excludedSkills.has(skillName))\n}\n\n/**\n * 获取 templates/skills/ 目录的绝对路径\n *\n * 兼容两种运行环境:\n * - 构建后:dist/cli-skill-templates.js → ../templates/skills\n * - 测试时:src/commands/cli-skill-templates.ts → ../../templates/skills\n */\nfunction getSkillTemplatesDir(): string {\n const currentDir = path.dirname(fileURLToPath(import.meta.url))\n const distPath = path.resolve(currentDir, '..', 'templates', 'skills')\n if (fse.pathExistsSync(distPath)) {\n return distPath\n }\n return path.resolve(currentDir, '..', '..', 'templates', 'skills')\n}\n\n/**\n * 复制单个 Skill 目录到项目\n *\n * @param templatesDir - Skill 模板根目录\n * @param skillName - Skill 目录名(如 'hai-reldb')\n * @param projectPath - 用户项目根目录\n */\nasync function copySkill(\n templatesDir: string,\n skillName: string,\n projectPath: string,\n targetDirs: readonly string[] = SKILL_TARGET_DIRS,\n overwrite = true,\n): Promise<string[]> {\n const src = path.join(templatesDir, skillName)\n\n if (!(await fse.pathExists(src))) {\n return []\n }\n\n const copiedFiles: string[] = []\n\n for (const targetDir of targetDirs) {\n const dest = path.join(projectPath, targetDir, skillName)\n const skillFilePath = path.join(dest, 'SKILL.md')\n\n if (!overwrite && await fse.pathExists(skillFilePath)) {\n continue\n }\n\n await fse.copy(src, dest, { overwrite: true })\n copiedFiles.push(`${targetDir}/${skillName}/SKILL.md`)\n }\n\n return copiedFiles\n}\n\nasync function copySkills(\n templatesDir: string,\n skillNames: string[],\n projectPath: string,\n targetDirs: readonly string[] = SKILL_TARGET_DIRS,\n overwrite = true,\n): Promise<string[]> {\n const copiedFiles: string[] = []\n\n for (const skillName of new Set(skillNames)) {\n copiedFiles.push(...await copySkill(templatesDir, skillName, projectPath, targetDirs, overwrite))\n }\n\n return copiedFiles\n}\n\n/**\n * 复制桥接文件到项目\n *\n * @param templatesDir - Skill 模板根目录\n * @param projectPath - 用户项目根目录\n */\nasync function copyBridgeFiles(\n templatesDir: string,\n projectPath: string,\n overwrite = true,\n appType?: string,\n): Promise<string[]> {\n const copiedFiles: string[] = []\n\n for (const file of BRIDGE_FILES) {\n const src = await resolveBridgeSource(templatesDir, file.source, appType)\n const dest = path.join(projectPath, file.destination)\n\n if (!src) {\n continue\n }\n\n if (!overwrite && await fse.pathExists(dest)) {\n continue\n }\n\n await fse.copy(src, dest, { overwrite })\n copiedFiles.push(file.destination)\n }\n\n return copiedFiles\n}\n\nasync function resolveBridgeSource(\n templatesDir: string,\n source: string,\n appType?: string,\n): Promise<string | null> {\n const profile = appType && BRIDGE_PROFILE_REGEX.test(appType) ? appType : 'generic'\n const candidates = [\n path.join(templatesDir, 'bridges', profile, source),\n path.join(templatesDir, 'bridges', 'generic', source),\n path.join(templatesDir, source),\n ]\n\n for (const candidate of candidates) {\n if (await fse.pathExists(candidate)) {\n return candidate\n }\n }\n\n return null\n}\n\n/**\n * 为新项目生成完整的 Skill 文件。\n *\n * 默认复制 templates/skills 下所有 hai-* Skill,再按 appType 排除互斥项。\n *\n * @param projectPath - 用户项目根目录\n * @param _features - 预留参数;保留签名兼容 createProject 调用方\n * @param appType - 应用类型(api 类型不复制 UI Skill)\n */\nexport async function generateSkillFiles(\n projectPath: string,\n _features: string[],\n appType?: string,\n): Promise<string[]> {\n const templatesDir = getSkillTemplatesDir()\n\n if (!(await fse.pathExists(templatesDir))) {\n return []\n }\n\n const copiedFiles: string[] = []\n\n const templateSkillNames = await listTemplateSkillNames(templatesDir)\n const compatibleSkillNames = resolveCompatibleSkillNames(templateSkillNames, appType as AppType | undefined)\n\n copiedFiles.push(...await copySkills(templatesDir, compatibleSkillNames, projectPath))\n\n // 复制桥接文件\n copiedFiles.push(...await copyBridgeFiles(templatesDir, projectPath, true, appType))\n\n return copiedFiles\n}\n\n/**\n * 为已有项目添加单个模块的 Skill 文件\n *\n * 在 `hai add <module>` 时调用,仅复制对应模块的 Skill 文件。\n *\n * @param projectPath - 用户项目根目录\n * @param moduleId - 模块标识(如 'db'、'iam')\n * @returns 复制的文件路径,若模块无对应 Skill 则返回 null\n */\nexport async function generateModuleSkillFile(\n projectPath: string,\n moduleId: string,\n): Promise<string[] | null> {\n const skillName = MODULE_SKILL_MAP[moduleId]\n if (!skillName) {\n return null\n }\n\n const templatesDir = getSkillTemplatesDir()\n if (!(await fse.pathExists(templatesDir))) {\n return null\n }\n\n const missingTargetDirs: string[] = []\n\n for (const targetDir of SKILL_TARGET_DIRS) {\n const skillFilePath = path.join(projectPath, targetDir, skillName, 'SKILL.md')\n if (!(await fse.pathExists(skillFilePath))) {\n missingTargetDirs.push(targetDir)\n }\n }\n\n const copiedBridgeFiles = await copyBridgeFiles(templatesDir, projectPath, false)\n if (missingTargetDirs.length === 0) {\n return copiedBridgeFiles.length > 0 ? copiedBridgeFiles : null\n }\n\n const copiedSkillFiles = await copySkill(templatesDir, skillName, projectPath, missingTargetDirs)\n const copiedFiles = [...copiedBridgeFiles, ...copiedSkillFiles]\n\n if (copiedFiles.length === 0) {\n return null\n }\n\n return copiedFiles\n}\n\nexport function resolveSkillNamesForPackages(packageNames: string[]): string[] {\n const skillNames = [...WORKFLOW_SKILLS]\n\n for (const packageName of packageNames) {\n const skillName = PACKAGE_SKILL_MAP[packageName]\n if (skillName) {\n skillNames.push(skillName)\n }\n }\n\n return [...new Set(skillNames)]\n}\n\nexport async function generateProjectAiSupport(\n projectPath: string,\n skillNames: string[],\n options: {\n overwriteSkills?: boolean\n overwriteBridgeFiles?: boolean\n appType?: string\n } = {},\n): Promise<string[]> {\n const templatesDir = getSkillTemplatesDir()\n\n if (!(await fse.pathExists(templatesDir))) {\n return []\n }\n\n const {\n overwriteSkills = true,\n overwriteBridgeFiles = true,\n } = options\n\n const copiedFiles: string[] = []\n copiedFiles.push(...await copySkills(templatesDir, skillNames, projectPath, SKILL_TARGET_DIRS, overwriteSkills))\n copiedFiles.push(...await copyBridgeFiles(templatesDir, projectPath, overwriteBridgeFiles, options.appType))\n\n return copiedFiles\n}\n"]}
|