@h-ai/cli 0.1.0-alpha.51 → 0.1.0-alpha.54
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 +14 -0
- package/dist/{chunk-U4PA632G.js → chunk-FVDXJYMO.js} +34 -67
- package/dist/chunk-FVDXJYMO.js.map +1 -0
- package/dist/cli-config-templates-WGN2I23J.js +5 -0
- package/dist/{cli-config-templates-GSXKLGU5.js.map → cli-config-templates-WGN2I23J.js.map} +1 -1
- package/dist/index.js +299 -127
- package/dist/index.js.map +1 -1
- package/dist/{src-QNEJJ3BV.js → src-6ZBWDBUB.js} +127 -87
- package/dist/{src-QNEJJ3BV.js.map → src-6ZBWDBUB.js.map} +1 -1
- package/package.json +13 -4
- package/templates/apps/api/Dockerfile.hbs +6 -3
- package/templates/apps/api/apps/{{projectName}}-contract/package.json.hbs +1 -0
- package/templates/apps/api/apps/{{projectName}}-service/data/.gitkeep.hbs +1 -0
- package/templates/apps/api/apps/{{projectName}}-service/package.json.hbs +1 -0
- package/templates/apps/api/package.json.hbs +1 -0
- package/templates/apps/fullstack/.dockerignore.hbs +2 -0
- package/templates/apps/fullstack/Dockerfile.hbs +23 -36
- package/templates/apps/fullstack/apps/{{projectName}}-app/package.json.hbs +1 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/package.json.hbs +1 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/index.html.hbs +2 -1
- package/templates/apps/fullstack/apps/{{projectName}}-web/package.json.hbs +1 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/public/runtime-config.js.hbs +1 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/tests/api.test.ts.hbs +27 -0
- package/templates/apps/fullstack/docker/19-runtime-config.envsh.hbs +5 -0
- package/templates/apps/fullstack/docker/nginx.conf.hbs +6 -0
- package/templates/apps/fullstack/docker/runtime-config.js.template.hbs +3 -0
- package/templates/apps/fullstack/package.json.hbs +3 -4
- package/templates/apps/fullstack/packages/{{projectName}}-contract/package.json.hbs +1 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/README.md.hbs +3 -2
- package/templates/apps/fullstack/packages/{{projectName}}-serv/data/.gitkeep.hbs +1 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/package.json.hbs +1 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/package.json.hbs +1 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/api/api-client.ts.hbs +9 -1
- package/templates/base/.gitignore.hbs +2 -1
- package/templates/base/Dockerfile.hbs +10 -4
- package/templates/base/eslint.config.js.hbs +1 -0
- package/templates/base/package.json.hbs +3 -1
- package/templates/skills/hai-ai/SKILL.md +4 -0
- package/templates/skills/hai-ai/reference.md +5 -1
- package/templates/skills/hai-app-create/SKILL.md +3 -1
- package/templates/skills/hai-app-review/SKILL.md +6 -0
- package/templates/skills/hai-build/SKILL.md +8 -0
- package/templates/skills/hai-cache/SKILL.md +2 -0
- package/templates/skills/hai-capacitor/SKILL.md +2 -0
- package/templates/skills/hai-ci/SKILL.md +12 -0
- package/templates/skills/hai-core/SKILL.md +2 -0
- package/templates/skills/hai-crypto/SKILL.md +2 -0
- package/templates/skills/hai-deploy/SKILL.md +12 -0
- package/templates/skills/hai-iam/SKILL.md +6 -0
- package/templates/skills/hai-scheduler/SKILL.md +12 -0
- package/templates/skills/hai-ui/SKILL.md +4 -0
- package/dist/chunk-U4PA632G.js.map +0 -1
- package/dist/cli-config-templates-GSXKLGU5.js +0 -5
- package/templates/apps/fullstack/docker/fullstack-server.mjs.hbs +0 -194
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { generateConfigFile } from './chunk-
|
|
2
|
+
import { generateConfigFile } from './chunk-FVDXJYMO.js';
|
|
3
3
|
import './chunk-WUYLYCW2.js';
|
|
4
4
|
import './chunk-2H7UOFLK.js';
|
|
5
5
|
import process3 from 'process';
|
|
@@ -1076,7 +1076,7 @@ async function createProject(options) {
|
|
|
1076
1076
|
});
|
|
1077
1077
|
await generateFromTemplates(projectPath, context);
|
|
1078
1078
|
if (resolvedOptions.appType !== "fullstack") {
|
|
1079
|
-
const { generateConfigFile: generateConfigFile2, generateEnvExample } = await import('./cli-config-templates-
|
|
1079
|
+
const { generateConfigFile: generateConfigFile2, generateEnvExample } = await import('./cli-config-templates-WGN2I23J.js');
|
|
1080
1080
|
const configs = resolvedOptions.moduleConfigs;
|
|
1081
1081
|
const isApiWorkspace = resolvedOptions.appType === "api";
|
|
1082
1082
|
const configDir = isApiWorkspace ? path2.join(projectPath, "apps", `${resolvedOptions.name}-service`, "config") : path2.join(projectPath, "config");
|
|
@@ -1617,15 +1617,20 @@ function generateReadme(name, appTypeLabel, pm, appType) {
|
|
|
1617
1617
|
const isStaticImage = appType === "mobile-app";
|
|
1618
1618
|
const containerPort = isStaticImage ? 8080 : 3e3;
|
|
1619
1619
|
const runtimeOptions = isStaticImage ? "" : ` --env-file .env --mount type=bind,source=/absolute/path/to/config,target=/app/config,readonly --mount type=volume,source=${name}-data,target=/app/data`;
|
|
1620
|
-
const
|
|
1621
|
-
\
|
|
1622
|
-
|
|
1623
|
-
\`\`\`bash
|
|
1620
|
+
const embeddedDataBuild = isStaticImage ? "" : `
|
|
1621
|
+
# \u5E26 data/ \u521D\u59CB\u6570\u636E\u6784\u5EFA\uFF08\u4E8C\u9009\u4E00\uFF09
|
|
1624
1622
|
${getRunCommand(pm, "docker:build:data")}
|
|
1625
|
-
|
|
1623
|
+
${getRunCommand(pm, "podman:build:data")}`;
|
|
1624
|
+
const runtimeNotes = isStaticImage ? "- \u8BE5\u6A21\u677F\u751F\u6210\u9759\u6001 Web \u955C\u50CF\uFF0C\u4E0D\u5305\u542B\u53EF\u5199\u6570\u636E\u5E93\u76EE\u5F55\u3002" : `\u4EE5\u4E0A\u4E09\u4E2A\u8FD0\u884C\u65F6\u53C2\u6570\u5747\u53EF\u6309\u9700\u5220\u9664\uFF1A
|
|
1626
1625
|
|
|
1627
|
-
\
|
|
1628
|
-
|
|
1626
|
+
| \u53C2\u6570 | \u7528\u9014 | \u53EF\u9009\u6027 |
|
|
1627
|
+
| --- | --- | --- |
|
|
1628
|
+
| \`--env-file .env\` | \u6279\u91CF\u4F20\u5165\u73AF\u5883\u53D8\u91CF\uFF1B\u4E5F\u53EF\u6539\u7528\u591A\u4E2A \`-e NAME=value\`\u3002 | \u53EF\u9009\uFF1B\u5220\u9664\u540E\u4F7F\u7528\u955C\u50CF\u548C YAML \u9ED8\u8BA4\u503C\u3002 |
|
|
1629
|
+
| \`--mount type=bind,...target=/app/config,readonly\` | \u7528\u5BBF\u4E3B\u673A\u914D\u7F6E\u76EE\u5F55\u8986\u76D6\u955C\u50CF\u5185 \`/app/config\`\uFF1B\u5FC5\u987B\u628A \`source\` \u6539\u6210\u771F\u5B9E\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\`readonly\` \u9632\u6B62\u5BB9\u5668\u4FEE\u6539\u914D\u7F6E\u3002 | \u53EF\u9009\uFF1B\u5220\u9664\u540E\u4F7F\u7528\u955C\u50CF\u81EA\u5E26\u914D\u7F6E\u3002 |
|
|
1630
|
+
| \`--mount type=volume,...target=/app/data\` | \u521B\u5EFA\u6216\u590D\u7528 named volume\uFF0C\u6301\u4E45\u5316 SQLite \u548C\u672C\u5730\u5B58\u50A8\u3002 | \u53EF\u9009\u4F46\u751F\u4EA7\u73AF\u5883\u5EFA\u8BAE\u4FDD\u7559\uFF1B\u5220\u9664\u540E\u6570\u636E\u53EA\u5199\u5165\u5BB9\u5668\u5C42\uFF0C\u4F7F\u7528 \`--rm\` \u5220\u9664\u5BB9\u5668\u65F6\u4F1A\u4E22\u5931\u3002 |
|
|
1631
|
+
|
|
1632
|
+
- \u5E26\u6570\u636E\u6784\u5EFA\u4F1A\u628A\u5F53\u524D \`data/\`\uFF08\u4F8B\u5982\u9884\u7F6E SQLite \u6587\u4EF6\uFF09\u56FA\u5316\u4E3A\u955C\u50CF\u521D\u59CB\u5FEB\u7167\uFF1B\u8FD0\u884C\u540E\u4EA7\u751F\u7684\u65B0\u6570\u636E\u4ECD\u5E94\u5199\u5165 \`/app/data\` volume\u3002`;
|
|
1633
|
+
const testPath = isStaticImage ? "/health" : "/";
|
|
1629
1634
|
return `# ${name}
|
|
1630
1635
|
|
|
1631
1636
|
\u57FA\u4E8E hai Agent Framework \u6784\u5EFA\u7684${appTypeLabel}\u5E94\u7528\u3002
|
|
@@ -1645,13 +1650,31 @@ ${getRunCommand(pm, "i18n:compile")}
|
|
|
1645
1650
|
${getRunCommand(pm, "preview")}
|
|
1646
1651
|
\`\`\`
|
|
1647
1652
|
|
|
1648
|
-
##
|
|
1653
|
+
## \u5BB9\u5668\u8FD0\u884C
|
|
1654
|
+
|
|
1655
|
+
### \u6784\u5EFA\u955C\u50CF
|
|
1649
1656
|
|
|
1650
1657
|
\`\`\`bash
|
|
1658
|
+
# \u666E\u901A\u6784\u5EFA\uFF08\u4E8C\u9009\u4E00\uFF09
|
|
1651
1659
|
${getRunCommand(pm, "docker:build")}
|
|
1652
|
-
|
|
1660
|
+
${getRunCommand(pm, "podman:build")}${embeddedDataBuild}
|
|
1661
|
+
\`\`\`
|
|
1662
|
+
|
|
1663
|
+
### \u8FD0\u884C\u955C\u50CF
|
|
1664
|
+
|
|
1665
|
+
\`\`\`bash
|
|
1666
|
+
# Docker\uFF1B\u4F7F\u7528 Podman \u65F6\u5C06 docker \u66FF\u6362\u4E3A podman
|
|
1667
|
+
docker run --rm -d --name ${name} -p ${containerPort}:${containerPort}${runtimeOptions} ${name}:latest
|
|
1653
1668
|
\`\`\`
|
|
1654
|
-
|
|
1669
|
+
|
|
1670
|
+
### \u6D4B\u8BD5\u955C\u50CF
|
|
1671
|
+
|
|
1672
|
+
\`\`\`bash
|
|
1673
|
+
curl --fail http://127.0.0.1:${containerPort}${testPath}
|
|
1674
|
+
docker stop ${name}
|
|
1675
|
+
\`\`\`
|
|
1676
|
+
|
|
1677
|
+
${runtimeNotes}
|
|
1655
1678
|
|
|
1656
1679
|
## \u6587\u6863
|
|
1657
1680
|
|
|
@@ -1686,18 +1709,50 @@ ${pm} test
|
|
|
1686
1709
|
${pm} test:e2e
|
|
1687
1710
|
\`\`\`
|
|
1688
1711
|
|
|
1689
|
-
##
|
|
1712
|
+
## \u5BB9\u5668\u8FD0\u884C
|
|
1713
|
+
|
|
1714
|
+
### \u6784\u5EFA\u955C\u50CF
|
|
1690
1715
|
|
|
1691
1716
|
\`\`\`bash
|
|
1717
|
+
# \u666E\u901A\u6784\u5EFA\uFF08\u4E8C\u9009\u4E00\uFF09
|
|
1692
1718
|
${pm} docker:build
|
|
1693
|
-
|
|
1719
|
+
${pm} podman:build
|
|
1720
|
+
|
|
1721
|
+
# \u5C06 apps/${name}-service/data \u4F5C\u4E3A\u955C\u50CF\u521D\u59CB\u6570\u636E\u6784\u5EFA\uFF08\u4E8C\u9009\u4E00\uFF09
|
|
1722
|
+
${pm} docker:build:data
|
|
1723
|
+
${pm} podman:build:data
|
|
1724
|
+
\`\`\`
|
|
1725
|
+
|
|
1726
|
+
### \u8FD0\u884C\u955C\u50CF
|
|
1727
|
+
|
|
1728
|
+
\`\`\`bash
|
|
1729
|
+
# \u4F7F\u7528 Podman \u65F6\u5C06 docker \u66FF\u6362\u4E3A podman
|
|
1730
|
+
docker run --rm -d --name ${name} -p 3000:3000 --env-file .env \\
|
|
1694
1731
|
--mount type=bind,source=/absolute/path/to/config,target=/app/config,readonly \\
|
|
1695
1732
|
--mount type=volume,source=${name}-data,target=/app/data \\
|
|
1696
1733
|
${name}:latest
|
|
1697
1734
|
\`\`\`
|
|
1698
1735
|
|
|
1736
|
+
### \u6D4B\u8BD5\u955C\u50CF
|
|
1737
|
+
|
|
1738
|
+
\`\`\`bash
|
|
1739
|
+
curl --fail http://127.0.0.1:3000/health
|
|
1740
|
+
curl --fail http://127.0.0.1:3000/ready
|
|
1741
|
+
curl --fail --request POST http://127.0.0.1:3000/api/v1/app/info \\
|
|
1742
|
+
--header "Content-Type: application/json" --data '{}'
|
|
1743
|
+
docker stop ${name}
|
|
1744
|
+
\`\`\`
|
|
1745
|
+
|
|
1699
1746
|
- \u914D\u7F6E\u9ED8\u8BA4\u6765\u81EA \`apps/${name}-service/config\`\uFF1B\u8FD0\u884C\u65F6\u53EF\u53EA\u8BFB\u6302\u8F7D\u5230 \`/app/config\` \u8986\u76D6\uFF0C\u5E76\u7528 YAML \u7684 \`\${ENV_NAME:default}\` \u5360\u4F4D\u7B26\u63A5\u6536\u73AF\u5883\u53D8\u91CF\u3002
|
|
1700
|
-
- \
|
|
1747
|
+
- \u5E26\u6570\u636E\u6784\u5EFA\u4F1A\u628A \`apps/${name}-service/data\` \u56FA\u5316\u4E3A\u955C\u50CF\u521D\u59CB\u6570\u636E\uFF1B\u751F\u4EA7\u5199\u5165\u4ECD\u5EFA\u8BAE\u4F7F\u7528 \`/app/data\` volume\u3002
|
|
1748
|
+
|
|
1749
|
+
\u4EE5\u4E0A\u4E09\u4E2A\u8FD0\u884C\u65F6\u53C2\u6570\u5747\u53EF\u6309\u9700\u5220\u9664\uFF1A
|
|
1750
|
+
|
|
1751
|
+
| \u53C2\u6570 | \u7528\u9014 | \u53EF\u9009\u6027 |
|
|
1752
|
+
| --- | --- | --- |
|
|
1753
|
+
| \`--env-file .env\` | \u6279\u91CF\u4F20\u5165\u73AF\u5883\u53D8\u91CF\uFF1B\u4E5F\u53EF\u6539\u7528\u591A\u4E2A \`-e NAME=value\`\u3002 | \u53EF\u9009\uFF1B\u5220\u9664\u540E\u4F7F\u7528\u955C\u50CF\u548C YAML \u9ED8\u8BA4\u503C\u3002 |
|
|
1754
|
+
| \`--mount type=bind,...target=/app/config,readonly\` | \u7528\u5BBF\u4E3B\u673A\u914D\u7F6E\u76EE\u5F55\u8986\u76D6\u955C\u50CF\u5185 \`/app/config\`\uFF1B\u5FC5\u987B\u628A \`source\` \u6539\u6210\u771F\u5B9E\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\`readonly\` \u9632\u6B62\u5BB9\u5668\u4FEE\u6539\u914D\u7F6E\u3002 | \u53EF\u9009\uFF1B\u5220\u9664\u540E\u4F7F\u7528\u955C\u50CF\u81EA\u5E26\u914D\u7F6E\u3002 |
|
|
1755
|
+
| \`--mount type=volume,...target=/app/data\` | \u521B\u5EFA\u6216\u590D\u7528 named volume\uFF0C\u6301\u4E45\u5316 SQLite \u548C\u672C\u5730\u5B58\u50A8\u3002 | \u53EF\u9009\u4F46\u751F\u4EA7\u73AF\u5883\u5EFA\u8BAE\u4FDD\u7559\uFF1B\u5220\u9664\u540E\u6570\u636E\u53EA\u5199\u5165\u5BB9\u5668\u5C42\uFF0C\u4F7F\u7528 \`--rm\` \u5220\u9664\u5BB9\u5668\u65F6\u4F1A\u4E22\u5931\u3002 |
|
|
1701
1756
|
|
|
1702
1757
|
## \u6269\u5C55\u5EFA\u8BAE
|
|
1703
1758
|
|
|
@@ -1715,6 +1770,20 @@ docker run --rm -p 3000:3000 --env-file .env \\
|
|
|
1715
1770
|
}
|
|
1716
1771
|
function generateFullstackReadme(name, pm, frontends) {
|
|
1717
1772
|
const enabledFrontends = frontends.map((target) => FRONTEND_TARGETS[target].name).join(" / ");
|
|
1773
|
+
const webBuildCommands = frontends.includes("web") ? `
|
|
1774
|
+
# Web \u9759\u6001\u955C\u50CF\uFF08\u4E8C\u9009\u4E00\uFF09
|
|
1775
|
+
${pm} docker:build:web
|
|
1776
|
+
${pm} podman:build:web` : "";
|
|
1777
|
+
const webRunCommand = frontends.includes("web") ? `
|
|
1778
|
+
|
|
1779
|
+
# Web\uFF1BPUBLIC_API_BASE \u5728\u5BB9\u5668\u542F\u52A8\u65F6\u6CE8\u5165\uFF0C\u4E0D\u9700\u8981\u91CD\u65B0\u6784\u5EFA\u955C\u50CF
|
|
1780
|
+
docker run --rm -d --name ${name}-web -p 8080:8080 \\
|
|
1781
|
+
-e PUBLIC_API_BASE=https://api.example.com \\
|
|
1782
|
+
${name}-web:latest` : "";
|
|
1783
|
+
const webTestCommands = frontends.includes("web") ? `curl --fail http://127.0.0.1:8080/health
|
|
1784
|
+
curl --fail http://127.0.0.1:8080/runtime-config.js
|
|
1785
|
+
` : "";
|
|
1786
|
+
const containerNames = frontends.includes("web") ? `${name} ${name}-web` : name;
|
|
1718
1787
|
return `# ${name}
|
|
1719
1788
|
|
|
1720
1789
|
\u57FA\u4E8E hai Agent Framework \u6784\u5EFA\u7684\u524D\u540E\u7AEF\u5206\u79BB\u591A\u5305\u5DE5\u7A0B\u3002
|
|
@@ -1747,22 +1816,56 @@ ${pm} package
|
|
|
1747
1816
|
${pm} deploy
|
|
1748
1817
|
\`\`\`
|
|
1749
1818
|
|
|
1750
|
-
##
|
|
1819
|
+
## \u5BB9\u5668\u8FD0\u884C
|
|
1820
|
+
|
|
1821
|
+
\u9ED8\u8BA4\u955C\u50CF\u76F4\u63A5\u8FD0\u884C API Service\uFF0C\u5916\u90E8\u7AEF\u53E3\u4E3A 3000\u3002
|
|
1751
1822
|
|
|
1752
|
-
\
|
|
1823
|
+
### \u6784\u5EFA\u955C\u50CF
|
|
1753
1824
|
|
|
1754
1825
|
\`\`\`bash
|
|
1826
|
+
# Service \u666E\u901A\u6784\u5EFA\uFF08\u4E8C\u9009\u4E00\uFF09
|
|
1755
1827
|
${pm} docker:build
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1828
|
+
${pm} podman:build
|
|
1829
|
+
|
|
1830
|
+
# \u5C06 packages/${name}-serv/data \u4F5C\u4E3A\u955C\u50CF\u521D\u59CB\u6570\u636E\u6784\u5EFA\uFF08\u4E8C\u9009\u4E00\uFF09
|
|
1831
|
+
${pm} docker:build:data
|
|
1832
|
+
${pm} podman:build:data
|
|
1833
|
+
${webBuildCommands}
|
|
1834
|
+
\`\`\`
|
|
1835
|
+
|
|
1836
|
+
### \u8FD0\u884C\u955C\u50CF
|
|
1837
|
+
|
|
1838
|
+
\`\`\`bash
|
|
1839
|
+
# Service\uFF1B\u4F7F\u7528 Podman \u65F6\u5C06 docker \u66FF\u6362\u4E3A podman
|
|
1840
|
+
docker run --rm -d --name ${name} -p 3000:3000 --env-file .env \\
|
|
1841
|
+
--mount type=bind,source=/absolute/path/to/config,target=/app/config,readonly \\
|
|
1842
|
+
--mount type=volume,source=${name}-data,target=/app/data \\
|
|
1759
1843
|
${name}:latest
|
|
1844
|
+
${webRunCommand}
|
|
1760
1845
|
\`\`\`
|
|
1761
1846
|
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1847
|
+
### \u6D4B\u8BD5\u955C\u50CF
|
|
1848
|
+
|
|
1849
|
+
\`\`\`bash
|
|
1850
|
+
curl --fail http://127.0.0.1:3000/health
|
|
1851
|
+
curl --fail http://127.0.0.1:3000/ready
|
|
1852
|
+
curl --fail --request POST http://127.0.0.1:3000/api/v1/app/info \\
|
|
1853
|
+
--header "Content-Type: application/json" --data '{}'
|
|
1854
|
+
${webTestCommands}docker stop ${containerNames}
|
|
1855
|
+
\`\`\`
|
|
1856
|
+
|
|
1857
|
+
- \u914D\u7F6E\u9ED8\u8BA4\u6765\u81EA \`packages/${name}-serv/config\`\uFF0C\u4E5F\u53EF\u6302\u8F7D\u5230 \`/app/config\`\uFF1BYAML \u4E2D\u7684 \`\${ENV_NAME:default}\` \u53EF\u7531 \`--env-file\` \u6216 \`-e\` \u6CE8\u5165\u3002
|
|
1858
|
+
- \u5E26\u6570\u636E\u6784\u5EFA\u4F1A\u628A \`packages/${name}-serv/data\` \u56FA\u5316\u4E3A\u955C\u50CF\u521D\u59CB\u6570\u636E\uFF1B\u6301\u4E45\u5316\u5199\u5165\u4ECD\u5E94\u4F7F\u7528 volume\u3002
|
|
1859
|
+
- Service \u7531 \`@h-ai/serv\` \u76F4\u63A5\u5BF9\u5916\u76D1\u542C\uFF0C\u4E0D\u989D\u5916\u542F\u52A8 Web \u8F6C\u53D1\u5C42\u3002
|
|
1860
|
+
${frontends.includes("web") ? `- Web \u4F7F\u7528\u72EC\u7ACB\u9759\u6001\u955C\u50CF\u5E76\u652F\u6301\u4E00\u6B21\u6784\u5EFA\u3001\u591A\u73AF\u5883\u90E8\u7F72\uFF1B\u6784\u5EFA\u53EA\u9700\u8FD0\u884C \`${pm} docker:build:web\`\uFF0C\u542F\u52A8\u5BB9\u5668\u65F6\u901A\u8FC7 \`-e PUBLIC_API_BASE=https://api.example.com\` \u6307\u5411 Service \u5BF9\u5916\u5730\u5740\u3002\u672A\u8BBE\u7F6E\u65F6\u9ED8\u8BA4\u4F7F\u7528 Web \u9875\u9762\u81EA\u8EAB origin\u3002` : ""}
|
|
1861
|
+
|
|
1862
|
+
\u4EE5\u4E0A\u4E09\u4E2A Service \u8FD0\u884C\u65F6\u53C2\u6570\u5747\u53EF\u6309\u9700\u5220\u9664\uFF1A
|
|
1863
|
+
|
|
1864
|
+
| \u53C2\u6570 | \u7528\u9014 | \u53EF\u9009\u6027 |
|
|
1865
|
+
| --- | --- | --- |
|
|
1866
|
+
| \`--env-file .env\` | \u6279\u91CF\u4F20\u5165\u73AF\u5883\u53D8\u91CF\uFF1B\u4E5F\u53EF\u6539\u7528\u591A\u4E2A \`-e NAME=value\`\u3002 | \u53EF\u9009\uFF1B\u5220\u9664\u540E\u4F7F\u7528\u955C\u50CF\u548C YAML \u9ED8\u8BA4\u503C\u3002 |
|
|
1867
|
+
| \`--mount type=bind,...target=/app/config,readonly\` | \u7528\u5BBF\u4E3B\u673A\u914D\u7F6E\u76EE\u5F55\u8986\u76D6\u955C\u50CF\u5185 \`/app/config\`\uFF1B\u5FC5\u987B\u628A \`source\` \u6539\u6210\u771F\u5B9E\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\`readonly\` \u9632\u6B62\u5BB9\u5668\u4FEE\u6539\u914D\u7F6E\u3002 | \u53EF\u9009\uFF1B\u5220\u9664\u540E\u4F7F\u7528\u955C\u50CF\u81EA\u5E26\u914D\u7F6E\u3002 |
|
|
1868
|
+
| \`--mount type=volume,...target=/app/data\` | \u521B\u5EFA\u6216\u590D\u7528 named volume\uFF0C\u6301\u4E45\u5316 SQLite \u548C\u672C\u5730\u5B58\u50A8\u3002 | \u53EF\u9009\u4F46\u751F\u4EA7\u73AF\u5883\u5EFA\u8BAE\u4FDD\u7559\uFF1B\u5220\u9664\u540E\u6570\u636E\u53EA\u5199\u5165\u5BB9\u5668\u5C42\uFF0C\u4F7F\u7528 \`--rm\` \u5220\u9664\u5BB9\u5668\u65F6\u4F1A\u4E22\u5931\u3002 |
|
|
1766
1869
|
|
|
1767
1870
|
\u524D\u7AEF\u5355\u72EC\u4EA4\u4ED8\u547D\u4EE4\uFF1A
|
|
1768
1871
|
|
|
@@ -2015,6 +2118,69 @@ async function addModule(options) {
|
|
|
2015
2118
|
throw error;
|
|
2016
2119
|
}
|
|
2017
2120
|
}
|
|
2121
|
+
|
|
2122
|
+
// messages/en-US.json
|
|
2123
|
+
var en_US_default = {
|
|
2124
|
+
cli_invalidGenerateName: "Use a name starting with a letter, with only letters, digits, hyphens or underscores",
|
|
2125
|
+
cli_generateOutsideWorkspace: "Generated files must remain inside the workspace, including symbolic link targets",
|
|
2126
|
+
cli_generateExists: "File already exists: {path}. Use --force to overwrite it",
|
|
2127
|
+
cli_deploy_module_missing: "Deploy module not found. Install @h-ai/deploy first:",
|
|
2128
|
+
cli_deploy_load_credentials: "Loading credentials...",
|
|
2129
|
+
cli_deploy_credentials_failed: "Failed to load credentials: {message}",
|
|
2130
|
+
cli_deploy_credentials_loaded: "Loaded {count} credentials",
|
|
2131
|
+
cli_deploy_load_config: "Loading deploy config...",
|
|
2132
|
+
cli_deploy_config_missing: "Deploy config not found: {path}",
|
|
2133
|
+
cli_deploy_config_hint: "Run: hai add deploy to generate config template",
|
|
2134
|
+
cli_deploy_config_loaded: "Deploy config loaded",
|
|
2135
|
+
cli_deploy_scanning: "Scanning application...",
|
|
2136
|
+
cli_deploy_scan_failed: "Scan failed: {message}",
|
|
2137
|
+
cli_deploy_scanned: "Scanned: {name} (SvelteKit: {sveltekit}, Services: {services})",
|
|
2138
|
+
cli_deploy_none: "none",
|
|
2139
|
+
cli_deploy_initializing: "Initializing deploy module...",
|
|
2140
|
+
cli_deploy_init_failed: "Init failed: {message}",
|
|
2141
|
+
cli_deploy_initialized: "Deploy module initialized",
|
|
2142
|
+
cli_deploy_deploying: "Deploying application...",
|
|
2143
|
+
cli_deploy_failed: "Deploy failed: {message}",
|
|
2144
|
+
cli_deploy_success: "Deployment successful!",
|
|
2145
|
+
cli_deploy_url: " URL: {url}",
|
|
2146
|
+
cli_deploy_id: " ID: {id}",
|
|
2147
|
+
cli_deploy_env: " Env: {names}",
|
|
2148
|
+
cli_deploy_command_failed: "Deploy command failed"
|
|
2149
|
+
};
|
|
2150
|
+
|
|
2151
|
+
// messages/zh-CN.json
|
|
2152
|
+
var zh_CN_default = {
|
|
2153
|
+
cli_invalidGenerateName: "\u540D\u79F0\u5FC5\u987B\u4EE5\u5B57\u6BCD\u5F00\u5934\uFF0C\u4E14\u4EC5\u5305\u542B\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u77ED\u6A2A\u7EBF\u6216\u4E0B\u5212\u7EBF",
|
|
2154
|
+
cli_generateOutsideWorkspace: "\u751F\u6210\u6587\u4EF6\u5FC5\u987B\u4F4D\u4E8E\u5DE5\u4F5C\u76EE\u5F55\u5185\uFF0C\u7B26\u53F7\u94FE\u63A5\u76EE\u6807\u4E5F\u4E0D\u5F97\u8D8A\u754C",
|
|
2155
|
+
cli_generateExists: "\u6587\u4EF6\u5DF2\u5B58\u5728\uFF1A{path}\u3002\u4F7F\u7528 --force \u624D\u53EF\u8986\u76D6",
|
|
2156
|
+
cli_deploy_module_missing: "\u672A\u627E\u5230\u90E8\u7F72\u6A21\u5757\uFF0C\u8BF7\u5148\u5B89\u88C5 @h-ai/deploy\uFF1A",
|
|
2157
|
+
cli_deploy_load_credentials: "\u6B63\u5728\u52A0\u8F7D\u51ED\u8BC1\u2026",
|
|
2158
|
+
cli_deploy_credentials_failed: "\u52A0\u8F7D\u51ED\u8BC1\u5931\u8D25\uFF1A{message}",
|
|
2159
|
+
cli_deploy_credentials_loaded: "\u5DF2\u52A0\u8F7D {count} \u9879\u51ED\u8BC1",
|
|
2160
|
+
cli_deploy_load_config: "\u6B63\u5728\u52A0\u8F7D\u90E8\u7F72\u914D\u7F6E\u2026",
|
|
2161
|
+
cli_deploy_config_missing: "\u672A\u627E\u5230\u90E8\u7F72\u914D\u7F6E\uFF1A{path}",
|
|
2162
|
+
cli_deploy_config_hint: "\u8FD0\u884C hai add deploy \u751F\u6210\u90E8\u7F72\u914D\u7F6E\u6A21\u677F",
|
|
2163
|
+
cli_deploy_config_loaded: "\u90E8\u7F72\u914D\u7F6E\u5DF2\u52A0\u8F7D",
|
|
2164
|
+
cli_deploy_scanning: "\u6B63\u5728\u626B\u63CF\u5E94\u7528\u2026",
|
|
2165
|
+
cli_deploy_scan_failed: "\u626B\u63CF\u5931\u8D25\uFF1A{message}",
|
|
2166
|
+
cli_deploy_scanned: "\u5DF2\u626B\u63CF\uFF1A{name}\uFF08SvelteKit\uFF1A{sveltekit}\uFF0C\u670D\u52A1\uFF1A{services}\uFF09",
|
|
2167
|
+
cli_deploy_none: "\u65E0",
|
|
2168
|
+
cli_deploy_initializing: "\u6B63\u5728\u521D\u59CB\u5316\u90E8\u7F72\u6A21\u5757\u2026",
|
|
2169
|
+
cli_deploy_init_failed: "\u521D\u59CB\u5316\u5931\u8D25\uFF1A{message}",
|
|
2170
|
+
cli_deploy_initialized: "\u90E8\u7F72\u6A21\u5757\u5DF2\u521D\u59CB\u5316",
|
|
2171
|
+
cli_deploy_deploying: "\u6B63\u5728\u90E8\u7F72\u5E94\u7528\u2026",
|
|
2172
|
+
cli_deploy_failed: "\u90E8\u7F72\u5931\u8D25\uFF1A{message}",
|
|
2173
|
+
cli_deploy_success: "\u90E8\u7F72\u6210\u529F\uFF01",
|
|
2174
|
+
cli_deploy_url: " \u5730\u5740\uFF1A{url}",
|
|
2175
|
+
cli_deploy_id: " \u6807\u8BC6\uFF1A{id}",
|
|
2176
|
+
cli_deploy_env: " \u73AF\u5883\u53D8\u91CF\uFF1A{names}",
|
|
2177
|
+
cli_deploy_command_failed: "\u90E8\u7F72\u547D\u4EE4\u5931\u8D25"
|
|
2178
|
+
};
|
|
2179
|
+
|
|
2180
|
+
// src/cli-i18n.ts
|
|
2181
|
+
var cliM = core.i18n.createMessageGetter({ "en-US": en_US_default, "zh-CN": zh_CN_default });
|
|
2182
|
+
|
|
2183
|
+
// src/commands/cli-deploy.ts
|
|
2018
2184
|
async function deployCommand(options) {
|
|
2019
2185
|
const spinner = ora();
|
|
2020
2186
|
const cwd = options.cwd ?? process3.cwd();
|
|
@@ -2023,67 +2189,68 @@ async function deployCommand(options) {
|
|
|
2023
2189
|
try {
|
|
2024
2190
|
let deployModule;
|
|
2025
2191
|
try {
|
|
2026
|
-
deployModule = await import('./src-
|
|
2192
|
+
deployModule = await import('./src-6ZBWDBUB.js');
|
|
2027
2193
|
} catch {
|
|
2028
|
-
core.logger.error(chalk.red("
|
|
2194
|
+
core.logger.error(chalk.red(cliM("cli_deploy_module_missing")));
|
|
2029
2195
|
core.logger.info(chalk.cyan(" pnpm add @h-ai/deploy"));
|
|
2030
|
-
|
|
2196
|
+
throw new Error(cliM("cli_deploy_module_missing"));
|
|
2031
2197
|
}
|
|
2032
2198
|
const { deploy } = deployModule;
|
|
2033
|
-
spinner.start("
|
|
2199
|
+
spinner.start(cliM("cli_deploy_load_credentials"));
|
|
2034
2200
|
const credResult = deploy.credentials.load();
|
|
2035
2201
|
if (!credResult.success) {
|
|
2036
|
-
|
|
2037
|
-
return;
|
|
2202
|
+
throw new Error(cliM("cli_deploy_credentials_failed", { params: { message: credResult.error.message } }));
|
|
2038
2203
|
}
|
|
2039
|
-
spinner.succeed(
|
|
2040
|
-
spinner.start("
|
|
2204
|
+
spinner.succeed(cliM("cli_deploy_credentials_loaded", { params: { count: credResult.data.length } }));
|
|
2205
|
+
spinner.start(cliM("cli_deploy_load_config"));
|
|
2041
2206
|
const configPath = resolve(appDir, "config", "_deploy.yml");
|
|
2042
2207
|
if (!existsSync(configPath)) {
|
|
2043
|
-
spinner.fail(chalk.red(
|
|
2044
|
-
core.logger.info(chalk.cyan("
|
|
2045
|
-
|
|
2208
|
+
spinner.fail(chalk.red(cliM("cli_deploy_config_missing", { params: { path: configPath } })));
|
|
2209
|
+
core.logger.info(chalk.cyan(cliM("cli_deploy_config_hint")));
|
|
2210
|
+
throw new Error(cliM("cli_deploy_config_missing", { params: { path: configPath } }));
|
|
2046
2211
|
}
|
|
2047
2212
|
const configContent = readFileSync(configPath, "utf-8");
|
|
2048
2213
|
const rawConfig = interpolateEnvFallback(configContent);
|
|
2049
2214
|
const deployConfig = parse(rawConfig);
|
|
2050
|
-
spinner.succeed("
|
|
2051
|
-
spinner.start("
|
|
2215
|
+
spinner.succeed(cliM("cli_deploy_config_loaded"));
|
|
2216
|
+
spinner.start(cliM("cli_deploy_scanning"));
|
|
2052
2217
|
const scanResult = await deploy.scan(appDir);
|
|
2053
2218
|
if (!scanResult.success) {
|
|
2054
|
-
|
|
2055
|
-
return;
|
|
2219
|
+
throw new Error(cliM("cli_deploy_scan_failed", { params: { message: scanResult.error.message } }));
|
|
2056
2220
|
}
|
|
2057
2221
|
const scan = scanResult.data;
|
|
2058
|
-
spinner.succeed(
|
|
2059
|
-
spinner.start("
|
|
2222
|
+
spinner.succeed(cliM("cli_deploy_scanned", { params: { name: scan.appName, sveltekit: String(scan.isSvelteKit), services: scan.requiredServices.join(", ") || cliM("cli_deploy_none") } }));
|
|
2223
|
+
spinner.start(cliM("cli_deploy_initializing"));
|
|
2060
2224
|
const initResult = await deploy.init(deployConfig);
|
|
2061
2225
|
if (!initResult.success) {
|
|
2062
|
-
|
|
2063
|
-
return;
|
|
2226
|
+
throw new Error(cliM("cli_deploy_init_failed", { params: { message: initResult.error.message } }));
|
|
2064
2227
|
}
|
|
2065
2228
|
closeDeploy = () => deploy.close();
|
|
2066
|
-
spinner.succeed("
|
|
2067
|
-
spinner.start("
|
|
2229
|
+
spinner.succeed(cliM("cli_deploy_initialized"));
|
|
2230
|
+
spinner.start(cliM("cli_deploy_deploying"));
|
|
2068
2231
|
const deployResult = await deploy.deployApp(appDir, {
|
|
2069
2232
|
projectName: options.projectName,
|
|
2070
2233
|
skipProvision: options.skipProvision,
|
|
2071
2234
|
skipBuild: options.skipBuild
|
|
2072
2235
|
});
|
|
2073
2236
|
if (!deployResult.success) {
|
|
2074
|
-
|
|
2075
|
-
|
|
2237
|
+
if (deployResult.error.ext?.recovery) {
|
|
2238
|
+
core.logger.warn(deployResult.error.suggestion ?? cliM("cli_deploy_command_failed"), {
|
|
2239
|
+
recovery: deployResult.error.ext.recovery
|
|
2240
|
+
});
|
|
2241
|
+
}
|
|
2242
|
+
throw new Error(cliM("cli_deploy_failed", { params: { message: deployResult.error.message } }));
|
|
2076
2243
|
}
|
|
2077
|
-
spinner.succeed(chalk.green("
|
|
2244
|
+
spinner.succeed(chalk.green(cliM("cli_deploy_success")));
|
|
2078
2245
|
core.logger.info("");
|
|
2079
|
-
core.logger.info(chalk.cyan(
|
|
2080
|
-
core.logger.info(chalk.gray(
|
|
2246
|
+
core.logger.info(chalk.cyan(cliM("cli_deploy_url", { params: { url: deployResult.data.url } })));
|
|
2247
|
+
core.logger.info(chalk.gray(cliM("cli_deploy_id", { params: { id: deployResult.data.deploymentId } })));
|
|
2081
2248
|
if (deployResult.data.envVarsSet.length > 0) {
|
|
2082
|
-
core.logger.info(chalk.gray(
|
|
2249
|
+
core.logger.info(chalk.gray(cliM("cli_deploy_env", { params: { names: deployResult.data.envVarsSet.join(", ") } })));
|
|
2083
2250
|
}
|
|
2084
2251
|
core.logger.info("");
|
|
2085
2252
|
} catch (error) {
|
|
2086
|
-
spinner.fail(chalk.red("
|
|
2253
|
+
spinner.fail(chalk.red(cliM("cli_deploy_command_failed")));
|
|
2087
2254
|
core.logger.error(error instanceof Error ? error.message : String(error));
|
|
2088
2255
|
throw error;
|
|
2089
2256
|
} finally {
|
|
@@ -2092,6 +2259,7 @@ async function deployCommand(options) {
|
|
|
2092
2259
|
await closeDeploy();
|
|
2093
2260
|
} catch (error) {
|
|
2094
2261
|
core.logger.error("Failed to close deploy module", { error });
|
|
2262
|
+
process3.exitCode = 1;
|
|
2095
2263
|
}
|
|
2096
2264
|
}
|
|
2097
2265
|
}
|
|
@@ -2141,24 +2309,41 @@ async function generate(options) {
|
|
|
2141
2309
|
if (!generator) {
|
|
2142
2310
|
throw new Error(`\u672A\u77E5\u7684\u751F\u6210\u5668\u7C7B\u578B: ${resolvedOptions.type}`);
|
|
2143
2311
|
}
|
|
2312
|
+
if (!/^[a-z][a-z0-9]*(?:[-_][a-z0-9]+)*$/i.test(resolvedOptions.name))
|
|
2313
|
+
throw new Error(cliM("cli_invalidGenerateName"));
|
|
2144
2314
|
const outputDir = path2.resolve(cwd, resolvedOptions.output || generator.defaultPath);
|
|
2145
2315
|
const resolvedCwd = path2.resolve(cwd);
|
|
2146
2316
|
if (!outputDir.startsWith(resolvedCwd + path2.sep) && outputDir !== resolvedCwd) {
|
|
2147
|
-
|
|
2148
|
-
return;
|
|
2317
|
+
throw new Error(cliM("cli_generateOutsideWorkspace"));
|
|
2149
2318
|
}
|
|
2150
2319
|
const context = createTemplateContext(resolvedOptions.name, {
|
|
2151
2320
|
projectName: project?.name
|
|
2152
2321
|
});
|
|
2153
2322
|
spinner.start(`\u751F\u6210 ${generator.description}...`);
|
|
2154
|
-
const files = await generator.generate(
|
|
2323
|
+
const files = await generator.generate(context, outputDir);
|
|
2324
|
+
const realCwd = await fse.realpath(resolvedCwd);
|
|
2325
|
+
for (const file of files) {
|
|
2326
|
+
if (!resolvedOptions.force && await fse.pathExists(file.path))
|
|
2327
|
+
throw new Error(cliM("cli_generateExists", { params: { path: file.path } }));
|
|
2328
|
+
let ancestor = file.path;
|
|
2329
|
+
while (!await fse.pathExists(ancestor))
|
|
2330
|
+
ancestor = path2.dirname(ancestor);
|
|
2331
|
+
const realAncestor = await fse.realpath(ancestor);
|
|
2332
|
+
const relative = path2.relative(realCwd, realAncestor);
|
|
2333
|
+
if (relative === ".." || relative.startsWith(`..${path2.sep}`) || path2.isAbsolute(relative))
|
|
2334
|
+
throw new Error(cliM("cli_generateOutsideWorkspace"));
|
|
2335
|
+
}
|
|
2336
|
+
for (const file of files) {
|
|
2337
|
+
await fse.ensureDir(path2.dirname(file.path));
|
|
2338
|
+
await fse.writeFile(file.path, file.content, { encoding: "utf-8", flag: resolvedOptions.force ? "w" : "wx" });
|
|
2339
|
+
}
|
|
2155
2340
|
spinner.succeed();
|
|
2156
2341
|
core.logger.info("", {});
|
|
2157
2342
|
core.logger.info(chalk.green("\u2714 \u751F\u6210\u5B8C\u6210\uFF01"));
|
|
2158
2343
|
core.logger.info("", {});
|
|
2159
2344
|
core.logger.info("\u521B\u5EFA\u7684\u6587\u4EF6:");
|
|
2160
2345
|
files.forEach((file) => {
|
|
2161
|
-
core.logger.info(chalk.cyan(` ${path2.relative(cwd, file)}`));
|
|
2346
|
+
core.logger.info(chalk.cyan(` ${path2.relative(cwd, file.path)}`));
|
|
2162
2347
|
});
|
|
2163
2348
|
core.logger.info("", {});
|
|
2164
2349
|
} catch (error) {
|
|
@@ -2202,76 +2387,72 @@ async function resolveGenerateOptions(options) {
|
|
|
2202
2387
|
cwd: options.cwd ?? "."
|
|
2203
2388
|
};
|
|
2204
2389
|
}
|
|
2205
|
-
async function generatePage(
|
|
2390
|
+
async function generatePage(context, outputDir) {
|
|
2206
2391
|
const files = [];
|
|
2207
2392
|
const pageDir = path2.join(outputDir, context.kebabCase);
|
|
2208
|
-
const pageContent =
|
|
2209
|
-
/**
|
|
2210
|
-
* ${context.pascalCase} \u9875\u9762
|
|
2211
|
-
*/
|
|
2212
|
-
</script>
|
|
2213
|
-
|
|
2393
|
+
const pageContent = `<!-- ${context.pascalCase} \u9875\u9762 -->
|
|
2214
2394
|
<svelte:head>
|
|
2215
2395
|
<title>${context.pascalCase}</title>
|
|
2216
2396
|
</svelte:head>
|
|
2217
2397
|
|
|
2218
|
-
<div class=
|
|
2219
|
-
<h1 class=
|
|
2220
|
-
|
|
2398
|
+
<div class='container mx-auto p-4'>
|
|
2399
|
+
<h1 class='text-2xl font-bold mb-4'>${context.pascalCase}</h1>
|
|
2400
|
+
|
|
2221
2401
|
<!-- \u9875\u9762\u5185\u5BB9 -->
|
|
2222
2402
|
</div>
|
|
2223
2403
|
`;
|
|
2224
2404
|
const pagePath = path2.join(pageDir, "+page.svelte");
|
|
2225
|
-
|
|
2226
|
-
files.push(pagePath);
|
|
2405
|
+
files.push({ path: pagePath, content: pageContent });
|
|
2227
2406
|
const serverContent = `/**
|
|
2228
2407
|
* ${context.pascalCase} \u9875\u9762\u670D\u52A1\u7AEF
|
|
2229
2408
|
*/
|
|
2230
|
-
import type {
|
|
2409
|
+
import type { Actions, PageServerLoad } from './$types'
|
|
2231
2410
|
|
|
2232
|
-
export const load: PageServerLoad = async (
|
|
2411
|
+
export const load: PageServerLoad = async () => {
|
|
2233
2412
|
return {
|
|
2234
2413
|
// \u9875\u9762\u6570\u636E
|
|
2235
2414
|
}
|
|
2236
2415
|
}
|
|
2237
2416
|
|
|
2238
2417
|
export const actions: Actions = {
|
|
2239
|
-
default: async (
|
|
2418
|
+
default: async () => {
|
|
2240
2419
|
// \u8868\u5355\u5904\u7406
|
|
2241
2420
|
},
|
|
2242
2421
|
}
|
|
2243
2422
|
`;
|
|
2244
2423
|
const serverPath = path2.join(pageDir, "+page.server.ts");
|
|
2245
|
-
|
|
2246
|
-
files.push(serverPath);
|
|
2424
|
+
files.push({ path: serverPath, content: serverContent });
|
|
2247
2425
|
return files;
|
|
2248
2426
|
}
|
|
2249
|
-
async function generateComponent(
|
|
2427
|
+
async function generateComponent(context, outputDir) {
|
|
2250
2428
|
const files = [];
|
|
2251
|
-
const componentContent = `<script lang=
|
|
2429
|
+
const componentContent = `<script lang='ts'>
|
|
2430
|
+
import type { Snippet } from 'svelte'
|
|
2431
|
+
|
|
2252
2432
|
/**
|
|
2253
2433
|
* ${context.pascalCase} \u7EC4\u4EF6
|
|
2254
2434
|
*/
|
|
2255
|
-
|
|
2435
|
+
|
|
2256
2436
|
interface Props {
|
|
2257
2437
|
/** \u81EA\u5B9A\u4E49 class */
|
|
2258
2438
|
class?: string
|
|
2439
|
+
/** \u5B50\u5185\u5BB9\uFF08Svelte 5 snippet\uFF09 */
|
|
2440
|
+
children?: Snippet
|
|
2259
2441
|
}
|
|
2260
|
-
|
|
2261
|
-
|
|
2442
|
+
|
|
2443
|
+
const { class: className = '', children }: Props = $props()
|
|
2262
2444
|
</script>
|
|
2263
2445
|
|
|
2264
2446
|
<div class={className}>
|
|
2265
2447
|
<!-- \u7EC4\u4EF6\u5185\u5BB9 -->
|
|
2266
|
-
|
|
2448
|
+
{@render children?.()}
|
|
2267
2449
|
</div>
|
|
2268
2450
|
`;
|
|
2269
2451
|
const componentPath = path2.join(outputDir, `${context.pascalCase}.svelte`);
|
|
2270
|
-
|
|
2271
|
-
files.push(componentPath);
|
|
2452
|
+
files.push({ path: componentPath, content: componentContent });
|
|
2272
2453
|
return files;
|
|
2273
2454
|
}
|
|
2274
|
-
async function generateApi(
|
|
2455
|
+
async function generateApi(context, outputDir) {
|
|
2275
2456
|
const files = [];
|
|
2276
2457
|
const apiDir = path2.join(outputDir, context.kebabCase);
|
|
2277
2458
|
const serverContent = `/**
|
|
@@ -2279,44 +2460,35 @@ async function generateApi(_name, context, outputDir) {
|
|
|
2279
2460
|
*/
|
|
2280
2461
|
import type { RequestHandler } from './$types'
|
|
2281
2462
|
import { kit } from '@h-ai/kit'
|
|
2463
|
+
import { z } from 'zod'
|
|
2464
|
+
|
|
2465
|
+
/** \u793A\u4F8B\u8F93\u5165\uFF1B\u6DFB\u52A0\u4E1A\u52A1\u903B\u8F91\u524D\u6269\u5C55\u5B57\u6BB5\u548C\u7EA6\u675F\u3002 */
|
|
2466
|
+
const InputSchema = z.object({
|
|
2467
|
+
/** \u4E1A\u52A1\u540D\u79F0\uFF08\u975E\u7A7A\uFF09 */
|
|
2468
|
+
name: z.string().min(1),
|
|
2469
|
+
})
|
|
2282
2470
|
|
|
2283
2471
|
/**
|
|
2284
2472
|
* GET ${context.kebabCase}
|
|
2285
2473
|
*/
|
|
2286
|
-
export const GET: RequestHandler = async ({ locals }) => {
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
return kit.response.ok({ message: 'Hello from ${context.kebabCase}' }, requestId)
|
|
2291
|
-
}
|
|
2292
|
-
catch (error) {
|
|
2293
|
-
return kit.response.internalError()
|
|
2294
|
-
}
|
|
2295
|
-
}
|
|
2474
|
+
export const GET: RequestHandler = kit.handler(async ({ locals }) => {
|
|
2475
|
+
return kit.response.ok({ items: [] }, locals.requestId)
|
|
2476
|
+
})
|
|
2296
2477
|
|
|
2297
2478
|
/**
|
|
2298
2479
|
* POST ${context.kebabCase}
|
|
2299
2480
|
*/
|
|
2300
|
-
export const POST: RequestHandler = async ({ request, locals }) => {
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
// \u5904\u7406\u8BF7\u6C42
|
|
2306
|
-
|
|
2307
|
-
return kit.response.ok({ success: true }, requestId)
|
|
2308
|
-
}
|
|
2309
|
-
catch (error) {
|
|
2310
|
-
return kit.response.internalError()
|
|
2311
|
-
}
|
|
2312
|
-
}
|
|
2481
|
+
export const POST: RequestHandler = kit.handler(async ({ request, locals }) => {
|
|
2482
|
+
const body = await kit.validate.body(request, InputSchema)
|
|
2483
|
+
// \u6821\u9A8C\u901A\u8FC7\u540E\u518D\u6267\u884C\u4E1A\u52A1\u64CD\u4F5C\uFF1B\u793A\u4F8B\u4EC5\u56DE\u4F20\u6570\u636E\uFF0C\u4E0D\u6267\u884C\u5199\u5165\u3002
|
|
2484
|
+
return kit.response.ok(body, locals.requestId)
|
|
2485
|
+
})
|
|
2313
2486
|
`;
|
|
2314
2487
|
const serverPath = path2.join(apiDir, "+server.ts");
|
|
2315
|
-
|
|
2316
|
-
files.push(serverPath);
|
|
2488
|
+
files.push({ path: serverPath, content: serverContent });
|
|
2317
2489
|
return files;
|
|
2318
2490
|
}
|
|
2319
|
-
async function generateModel(
|
|
2491
|
+
async function generateModel(context, outputDir) {
|
|
2320
2492
|
const files = [];
|
|
2321
2493
|
const modelContent = `/**
|
|
2322
2494
|
* ${context.pascalCase} \u6A21\u578B
|
|
@@ -2327,9 +2499,13 @@ import { z } from 'zod'
|
|
|
2327
2499
|
* ${context.pascalCase} Schema
|
|
2328
2500
|
*/
|
|
2329
2501
|
export const ${context.camelCase}Schema = z.object({
|
|
2502
|
+
/** \u8BB0\u5F55\u552F\u4E00\u6807\u8BC6 */
|
|
2330
2503
|
id: z.string(),
|
|
2504
|
+
/** \u663E\u793A\u540D\u79F0 */
|
|
2331
2505
|
name: z.string().min(1),
|
|
2506
|
+
/** \u521B\u5EFA\u65F6\u95F4 */
|
|
2332
2507
|
createdAt: z.date(),
|
|
2508
|
+
/** \u6700\u540E\u4FEE\u6539\u65F6\u95F4 */
|
|
2333
2509
|
updatedAt: z.date(),
|
|
2334
2510
|
})
|
|
2335
2511
|
|
|
@@ -2355,39 +2531,35 @@ export type Create${context.pascalCase} = z.infer<typeof create${context.pascalC
|
|
|
2355
2531
|
export type Update${context.pascalCase} = z.infer<typeof update${context.pascalCase}Schema>
|
|
2356
2532
|
`;
|
|
2357
2533
|
const modelPath = path2.join(outputDir, `${context.kebabCase}.ts`);
|
|
2358
|
-
|
|
2359
|
-
files.push(modelPath);
|
|
2534
|
+
files.push({ path: modelPath, content: modelContent });
|
|
2360
2535
|
return files;
|
|
2361
2536
|
}
|
|
2362
|
-
async function generateMigration(
|
|
2537
|
+
async function generateMigration(context, outputDir) {
|
|
2363
2538
|
const files = [];
|
|
2364
2539
|
const timestamp = Date.now();
|
|
2365
2540
|
const migrationContent = `/**
|
|
2366
2541
|
* \u8FC1\u79FB: ${context.pascalCase}
|
|
2367
2542
|
* \u65F6\u95F4: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
2368
2543
|
*/
|
|
2369
|
-
import
|
|
2544
|
+
import { reldb } from '@h-ai/reldb'
|
|
2370
2545
|
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
)
|
|
2380
|
-
\`)
|
|
2546
|
+
/** \u5347\u7EA7\uFF1A\u8C03\u7528\u524D\u521D\u59CB\u5316 reldb\uFF0C\u8C03\u7528\u65B9\u5FC5\u987B\u68C0\u67E5\u8FD4\u56DE\u7684 HaiResult\u3002 */
|
|
2547
|
+
export function up() {
|
|
2548
|
+
return reldb.ddl.createTable('hai_app_${context.snakeCase}', {
|
|
2549
|
+
id: { type: 'TEXT', primaryKey: true },
|
|
2550
|
+
name: { type: 'TEXT', notNull: true },
|
|
2551
|
+
created_at: { type: 'TIMESTAMP', notNull: true },
|
|
2552
|
+
updated_at: { type: 'TIMESTAMP', notNull: true },
|
|
2553
|
+
})
|
|
2381
2554
|
}
|
|
2382
2555
|
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2556
|
+
/** \u56DE\u6EDA\u4F1A\u5220\u9664\u6574\u5F20\u8868\uFF1B\u7531\u5E94\u7528\u786E\u8BA4\u6570\u636E\u53EF\u5220\u9664\u540E\u663E\u5F0F\u8C03\u7528\u3002 */
|
|
2557
|
+
export function down() {
|
|
2558
|
+
return reldb.ddl.dropTable('hai_app_${context.snakeCase}')
|
|
2386
2559
|
}
|
|
2387
2560
|
`;
|
|
2388
2561
|
const migrationPath = path2.join(outputDir, `${timestamp}_${context.snakeCase}.ts`);
|
|
2389
|
-
|
|
2390
|
-
files.push(migrationPath);
|
|
2562
|
+
files.push({ path: migrationPath, content: migrationContent });
|
|
2391
2563
|
return files;
|
|
2392
2564
|
}
|
|
2393
2565
|
var MODULE_CONFIG_MAP = {
|