@locode2/harness 0.1.0-preview.1

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.
Files changed (162) hide show
  1. package/README.md +27 -0
  2. package/THIRD_PARTY_LICENSES.txt +32769 -0
  3. package/THIRD_PARTY_NOTICES.md +13 -0
  4. package/apps/host/dist/document-parser-worker.js +215 -0
  5. package/apps/host/dist/frontend-runtime-worker.js +1755 -0
  6. package/apps/host/dist/index.js +23380 -0
  7. package/apps/web/dist/assets/LocalMonacoEditor-CXkKwxiP.css +1 -0
  8. package/apps/web/dist/assets/LocalMonacoEditor-WKAHQmzG.js +940 -0
  9. package/apps/web/dist/assets/LogsView-BFFFSFB-.js +1 -0
  10. package/apps/web/dist/assets/PluginsView-DM_ZnENS.js +1 -0
  11. package/apps/web/dist/assets/SettingsView-Cb5Q4ile.js +1 -0
  12. package/apps/web/dist/assets/abap-DLDM7-KI.js +1 -0
  13. package/apps/web/dist/assets/apex-DNDY2TF8.js +1 -0
  14. package/apps/web/dist/assets/azcli-Y6nb8tq_.js +1 -0
  15. package/apps/web/dist/assets/bat-BwHxbl9M.js +1 -0
  16. package/apps/web/dist/assets/bicep-CFznDFnq.js +2 -0
  17. package/apps/web/dist/assets/cameligo-Bf6VGUru.js +1 -0
  18. package/apps/web/dist/assets/clojure-Dnu-v4kV.js +1 -0
  19. package/apps/web/dist/assets/codicon-Brq4_Ui5.ttf +0 -0
  20. package/apps/web/dist/assets/coffee-Bd8akH9Z.js +1 -0
  21. package/apps/web/dist/assets/cpp-BbWJElDN.js +1 -0
  22. package/apps/web/dist/assets/csharp-Co3qMtFm.js +1 -0
  23. package/apps/web/dist/assets/csp-D-4FJmMZ.js +1 -0
  24. package/apps/web/dist/assets/css-DdJfP1eB.js +3 -0
  25. package/apps/web/dist/assets/css.worker-11mhRRLC.js +97 -0
  26. package/apps/web/dist/assets/cssMode-L5f5LAEn.js +1 -0
  27. package/apps/web/dist/assets/cypher-cTPe9QuQ.js +1 -0
  28. package/apps/web/dist/assets/dart-BOtBlQCF.js +1 -0
  29. package/apps/web/dist/assets/dockerfile-BG73LgW2.js +1 -0
  30. package/apps/web/dist/assets/ecl-BEgZUVRK.js +1 -0
  31. package/apps/web/dist/assets/editor.worker-DysRFSaV.js +30 -0
  32. package/apps/web/dist/assets/elixir-BkW5O-1t.js +1 -0
  33. package/apps/web/dist/assets/flow9-BeJ5waoc.js +1 -0
  34. package/apps/web/dist/assets/freemarker2-UOwftS75.js +3 -0
  35. package/apps/web/dist/assets/fsharp-PahG7c26.js +1 -0
  36. package/apps/web/dist/assets/go-acbASCJo.js +1 -0
  37. package/apps/web/dist/assets/graphql-BxJiqAUM.js +1 -0
  38. package/apps/web/dist/assets/handlebars-C_E41ffr.js +1 -0
  39. package/apps/web/dist/assets/hcl-DtV1sZF8.js +1 -0
  40. package/apps/web/dist/assets/html-HsrixH2x.js +1 -0
  41. package/apps/web/dist/assets/html.worker-C8Tw8ncf.js +474 -0
  42. package/apps/web/dist/assets/htmlMode-DipGmEOi.js +1 -0
  43. package/apps/web/dist/assets/index-COUF63cT.js +213 -0
  44. package/apps/web/dist/assets/index-SNSmF2-c.css +1 -0
  45. package/apps/web/dist/assets/ini-Kd9XrMLS.js +1 -0
  46. package/apps/web/dist/assets/java-CXBNlu9o.js +1 -0
  47. package/apps/web/dist/assets/javascript-D36WEqF9.js +1 -0
  48. package/apps/web/dist/assets/json.worker-BzkYZgJ7.js +62 -0
  49. package/apps/web/dist/assets/jsonMode-D9BrIats.js +7 -0
  50. package/apps/web/dist/assets/julia-cl7-CwDS.js +1 -0
  51. package/apps/web/dist/assets/kotlin-s7OhZKlX.js +1 -0
  52. package/apps/web/dist/assets/less-9HpZscsL.js +2 -0
  53. package/apps/web/dist/assets/lexon-OrD6JF1K.js +1 -0
  54. package/apps/web/dist/assets/liquid-DES89Tjc.js +1 -0
  55. package/apps/web/dist/assets/lock-keyhole-jo-FJcGq.js +1 -0
  56. package/apps/web/dist/assets/lspLanguageFeatures-YKkgcn4q.js +4 -0
  57. package/apps/web/dist/assets/lua-Cyyb5UIc.js +1 -0
  58. package/apps/web/dist/assets/m3-B8OfTtLu.js +1 -0
  59. package/apps/web/dist/assets/markdown-BFxVWTOG.js +1 -0
  60. package/apps/web/dist/assets/mdx-D1Bfax8e.js +1 -0
  61. package/apps/web/dist/assets/mips-CiqrrVzr.js +1 -0
  62. package/apps/web/dist/assets/msdax-DmeGPVcC.js +1 -0
  63. package/apps/web/dist/assets/mysql-C_tMU-Nz.js +1 -0
  64. package/apps/web/dist/assets/objective-c-BDtDVThU.js +1 -0
  65. package/apps/web/dist/assets/pascal-vHIfCaH5.js +1 -0
  66. package/apps/web/dist/assets/pascaligo-DtZ0uQbO.js +1 -0
  67. package/apps/web/dist/assets/perl-Ub6l9XKa.js +1 -0
  68. package/apps/web/dist/assets/pgsql-BlNEE0v7.js +1 -0
  69. package/apps/web/dist/assets/php-BBUBE1dy.js +1 -0
  70. package/apps/web/dist/assets/pla-DSh2-awV.js +1 -0
  71. package/apps/web/dist/assets/postiats-CocnycG-.js +1 -0
  72. package/apps/web/dist/assets/powerquery-tScXyioY.js +1 -0
  73. package/apps/web/dist/assets/powershell-COWaemsV.js +1 -0
  74. package/apps/web/dist/assets/protobuf-Brw8urJB.js +2 -0
  75. package/apps/web/dist/assets/pug-8SOpv6rk.js +1 -0
  76. package/apps/web/dist/assets/python-DKhPhY0N.js +1 -0
  77. package/apps/web/dist/assets/qsharp-Bw9ernYp.js +1 -0
  78. package/apps/web/dist/assets/r-j7ic8hl3.js +1 -0
  79. package/apps/web/dist/assets/razor-Cha8qrI6.js +1 -0
  80. package/apps/web/dist/assets/redis-Bu5POkcn.js +1 -0
  81. package/apps/web/dist/assets/redshift-Bs9aos_-.js +1 -0
  82. package/apps/web/dist/assets/restructuredtext-CqXO7rUv.js +1 -0
  83. package/apps/web/dist/assets/ruby-zBfavPgS.js +1 -0
  84. package/apps/web/dist/assets/rust-BzKRNQWT.js +1 -0
  85. package/apps/web/dist/assets/sb-BBc9UKZt.js +1 -0
  86. package/apps/web/dist/assets/scala-D9hQfWCl.js +1 -0
  87. package/apps/web/dist/assets/scheme-BPhDTwHR.js +1 -0
  88. package/apps/web/dist/assets/scss-CBJaRo0y.js +3 -0
  89. package/apps/web/dist/assets/shell-DiJ1NA_G.js +1 -0
  90. package/apps/web/dist/assets/solidity-Db0IVjzk.js +1 -0
  91. package/apps/web/dist/assets/sophia-CnS9iZB_.js +1 -0
  92. package/apps/web/dist/assets/sparql-CJmd_6j2.js +1 -0
  93. package/apps/web/dist/assets/sql-ClhHkBeG.js +1 -0
  94. package/apps/web/dist/assets/st-CHwy0fLd.js +1 -0
  95. package/apps/web/dist/assets/swift-CnmFD0ga.js +1 -0
  96. package/apps/web/dist/assets/systemverilog-Bs9z6M-B.js +1 -0
  97. package/apps/web/dist/assets/tcl-Dm6ycUr_.js +1 -0
  98. package/apps/web/dist/assets/ts.worker-Bupg6llt.js +67722 -0
  99. package/apps/web/dist/assets/tsMode-CEhssXv8.js +11 -0
  100. package/apps/web/dist/assets/twig-Csy3S7wG.js +1 -0
  101. package/apps/web/dist/assets/typescript-DWqmw58R.js +1 -0
  102. package/apps/web/dist/assets/typespec-Btyra-wh.js +1 -0
  103. package/apps/web/dist/assets/vb-Db0cS2oM.js +1 -0
  104. package/apps/web/dist/assets/wgsl-DumH7NcR.js +298 -0
  105. package/apps/web/dist/assets/workers-BmZvNFRq.js +1 -0
  106. package/apps/web/dist/assets/xml-WQTAFV9b.js +1 -0
  107. package/apps/web/dist/assets/yaml-Ke2Lf79d.js +1 -0
  108. package/apps/web/dist/index.html +15 -0
  109. package/bin/launch.mjs +71 -0
  110. package/bin/locode-mini.mjs +12 -0
  111. package/bin/options.mjs +49 -0
  112. package/bin/restore-assets.mjs +40 -0
  113. package/bundled-plugins/fast-frontend/.gitignore +2 -0
  114. package/bundled-plugins/fast-frontend/README.md +29 -0
  115. package/bundled-plugins/fast-frontend/harness.plugin.json +123 -0
  116. package/bundled-plugins/fast-frontend/runtimes/antd-admin/PUBLIC_CONTRACT.md +139 -0
  117. package/bundled-plugins/fast-frontend/runtimes/antd-admin/contracts/app.schema.json +24 -0
  118. package/bundled-plugins/fast-frontend/runtimes/antd-admin/contracts/route.schema.json +52 -0
  119. package/bundled-plugins/fast-frontend/runtimes/antd-admin/examples/app.json +9 -0
  120. package/bundled-plugins/fast-frontend/runtimes/antd-admin/examples/route.json +8 -0
  121. package/bundled-plugins/fast-frontend/runtimes/antd-admin/index.html +17 -0
  122. package/bundled-plugins/fast-frontend/runtimes/antd-admin/package.json +31 -0
  123. package/bundled-plugins/fast-frontend/runtimes/antd-admin/scripts/smoke-build.mjs +40 -0
  124. package/bundled-plugins/fast-frontend/runtimes/antd-admin/src/inspector/index.ts +612 -0
  125. package/bundled-plugins/fast-frontend/runtimes/antd-admin/src/main.tsx +17 -0
  126. package/bundled-plugins/fast-frontend/runtimes/antd-admin/src/sdk/index.ts +1028 -0
  127. package/bundled-plugins/fast-frontend/runtimes/antd-admin/src/shell/RuntimeApp.tsx +380 -0
  128. package/bundled-plugins/fast-frontend/runtimes/antd-admin/src/shell/runtime.css +246 -0
  129. package/bundled-plugins/fast-frontend/runtimes/antd-admin/tsconfig.json +20 -0
  130. package/bundled-plugins/fast-frontend/runtimes/antd-admin/types/runtime.consumer-smoke.ts +70 -0
  131. package/bundled-plugins/fast-frontend/runtimes/antd-admin/types/runtime.d.ts +227 -0
  132. package/bundled-plugins/fast-frontend/templates/antd-admin/.gitignore +9 -0
  133. package/bundled-plugins/fast-frontend/templates/antd-admin/.harness/template.json +10 -0
  134. package/bundled-plugins/fast-frontend/templates/antd-admin/index.html +13 -0
  135. package/bundled-plugins/fast-frontend/templates/antd-admin/package.json +34 -0
  136. package/bundled-plugins/fast-frontend/templates/antd-admin/pnpm-lock.yaml +1451 -0
  137. package/bundled-plugins/fast-frontend/templates/antd-admin/pnpm-workspace.yaml +4 -0
  138. package/bundled-plugins/fast-frontend/templates/antd-admin/public/generated/.gitkeep +1 -0
  139. package/bundled-plugins/fast-frontend/templates/antd-admin/scripts/validate-routes.mjs +153 -0
  140. package/bundled-plugins/fast-frontend/templates/antd-admin/src/app/App.tsx +27 -0
  141. package/bundled-plugins/fast-frontend/templates/antd-admin/src/app/NotFoundPage.tsx +15 -0
  142. package/bundled-plugins/fast-frontend/templates/antd-admin/src/features/.gitkeep +1 -0
  143. package/bundled-plugins/fast-frontend/templates/antd-admin/src/layouts/MainLayout.tsx +77 -0
  144. package/bundled-plugins/fast-frontend/templates/antd-admin/src/main.tsx +14 -0
  145. package/bundled-plugins/fast-frontend/templates/antd-admin/src/mocks/dashboard.ts +48 -0
  146. package/bundled-plugins/fast-frontend/templates/antd-admin/src/pages/dashboard/page.tsx +151 -0
  147. package/bundled-plugins/fast-frontend/templates/antd-admin/src/pages/dashboard/route.ts +9 -0
  148. package/bundled-plugins/fast-frontend/templates/antd-admin/src/routes/definition.ts +21 -0
  149. package/bundled-plugins/fast-frontend/templates/antd-admin/src/routes/menu.tsx +44 -0
  150. package/bundled-plugins/fast-frontend/templates/antd-admin/src/routes/registry.ts +48 -0
  151. package/bundled-plugins/fast-frontend/templates/antd-admin/src/routes/router.tsx +34 -0
  152. package/bundled-plugins/fast-frontend/templates/antd-admin/src/shared/components/business/.gitkeep +1 -0
  153. package/bundled-plugins/fast-frontend/templates/antd-admin/src/shared/components/business/BusinessProviders.tsx +9 -0
  154. package/bundled-plugins/fast-frontend/templates/antd-admin/src/styles/global.css +180 -0
  155. package/bundled-plugins/fast-frontend/templates/antd-admin/src/vite-env.d.ts +1 -0
  156. package/bundled-plugins/fast-frontend/templates/antd-admin/tsconfig.app.json +24 -0
  157. package/bundled-plugins/fast-frontend/templates/antd-admin/tsconfig.json +7 -0
  158. package/bundled-plugins/fast-frontend/templates/antd-admin/tsconfig.node.json +17 -0
  159. package/bundled-plugins/fast-frontend/templates/antd-admin/vite.config.ts +39 -0
  160. package/npm-shrinkwrap.json +9737 -0
  161. package/package.json +80 -0
  162. package/release-integrity.json +168 -0
@@ -0,0 +1,40 @@
1
+ // npm/pacote changes .gitignore to .npmignore while extracting a package.
2
+ // Restore exactly the two first-party asset names during installation; this
3
+ // neither builds code nor creates user data or changes global configuration.
4
+ import { createHash } from "node:crypto";
5
+ import { readFile, lstat, rename, unlink } from "node:fs/promises";
6
+ import { dirname, join, resolve } from "node:path";
7
+ import { fileURLToPath } from "node:url";
8
+
9
+ export const DOTFILES = [
10
+ "bundled-plugins/fast-frontend/.gitignore",
11
+ "bundled-plugins/fast-frontend/templates/antd-admin/.gitignore",
12
+ ];
13
+
14
+ export async function restoreAssets(root) {
15
+ const integrity = JSON.parse(await readFile(join(root, "release-integrity.json"), "utf8"));
16
+ const verified = async (path, expected) => {
17
+ const info = await lstat(path).catch(() => undefined);
18
+ if (!info) return false;
19
+ if (!info.isFile() || info.isSymbolicLink() || createHash("sha256").update(await readFile(path)).digest("hex") !== expected) {
20
+ throw new Error(`安装资产内容不匹配:${path}`);
21
+ }
22
+ return true;
23
+ };
24
+ for (const file of DOTFILES) {
25
+ const expected = integrity.files[file];
26
+ if (!/^[a-f0-9]{64}$/u.test(expected)) throw new Error(`安装资产缺少哈希:${file}`);
27
+ const target = join(root, file);
28
+ const renamed = join(dirname(target), ".npmignore");
29
+ const present = await verified(target, expected);
30
+ const npmRenamed = await verified(renamed, expected);
31
+ if (present) {
32
+ if (npmRenamed) await unlink(renamed);
33
+ } else if (npmRenamed) await rename(renamed, target);
34
+ else throw new Error(`安装资产缺失:${file}`);
35
+ }
36
+ }
37
+
38
+ if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
39
+ await restoreAssets(fileURLToPath(new URL("../", import.meta.url)));
40
+ }
@@ -0,0 +1,2 @@
1
+ !templates/antd-admin/.harness/
2
+ !templates/antd-admin/.harness/template.json
@@ -0,0 +1,29 @@
1
+ # 快速前台插件
2
+
3
+ Runtime 2.0.8 在 Harness 页面预览中支持“视觉圈改”:按住 Ctrl/⌘ 可临时画圈,也可通过预览工具栏锁定连续圈选。绘制过程直接跟随鼠标轨迹,识别后会自动吸附到目标元素边界并按其圆角规范显示;标注摘要可悬停查看详情、编辑或删除。标注经 Host 验签、校验当前源码哈希后可批量追加到 AI 助手草稿,且不会自动发送;静态导出不会包含检查器或内部源码标记。
4
+
5
+ 这是 Harness Studio 的第一方静态插件。它没有 Host 或 UI 入口,贡献:
6
+
7
+ - `antd-admin-runtime` Runtime 2.0 共享运行时;
8
+ - `fast-frontend` Runtime 2.0 助手模式;
9
+ - `antd-admin` 旧项目模板,仅用于识别并继续运行已有 `.harness/template.json` 项目。
10
+
11
+ 模板安装器应递归复制 `templates/antd-admin` 到目标项目,将
12
+ `.harness/template.json` 中的安装占位符替换为真实插件内容哈希与安装时间,并在复制
13
+ 完成后把每个受保护文件的 SHA-256 写入 `protectedFiles`。标记文件自身不加入哈希映射,
14
+ 避免自引用哈希。业务目录保持可编辑;模板升级只能修改基线未发生变化的受保护文件。
15
+
16
+ 模板预览使用 `pnpm exec vite`,Host 应把 `--host`、`--port` 和 `--strictPort`
17
+ 参数直接追加在其后。
18
+
19
+ 新应用直接使用所选项目根目录。初始化不要求目录为空,也不再限制为仅含 README;已有
20
+ 文件会原样保留,只有 Runtime 声明的业务源码和生成资源会参与预览、校验及静态导出。
21
+ `.harness/**` 是 Host 保留目录,存在非受管内容时仍会拒绝初始化,避免覆盖元数据。
22
+ Runtime 不会复制共享框架,也不会生成或改写项目级 `package.json`、`node_modules` 或 Vite
23
+ 配置。Host 根据 `frontendRuntimes[].root` 安装并缓存只读 Runtime,根据 `entry` 启动
24
+ shell,并把 `@harness/frontend-runtime` 映射到 `sdkEntry`。Runtime 的公开业务契约见
25
+ `runtimes/antd-admin/PUBLIC_CONTRACT.md`。
26
+
27
+ 生成资源统一放在 `public/generated/**`:应用清单和 TSX/JSX 使用
28
+ `./generated/<文件>`,`src/styles.css` 使用 `/generated/<文件>`;Host 在静态导出时
29
+ 将 CSS URL 改写为可部署到任意子路径的相对地址。
@@ -0,0 +1,123 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "apiVersion": "0.1",
4
+ "id": "harness.fast-frontend",
5
+ "name": "快速前台",
6
+ "version": "2.0.8",
7
+ "publisher": "Harness Studio",
8
+ "dependencies": {},
9
+ "permissions": [],
10
+ "contributes": {
11
+ "projectTemplates": [
12
+ {
13
+ "id": "antd-admin",
14
+ "version": "1.1.0",
15
+ "title": "Ant Design 管理后台",
16
+ "description": "开箱即用的 React、TypeScript、Vite 与 Ant Design 管理后台模板,路由和菜单由页面元数据统一生成。",
17
+ "assets": [
18
+ {
19
+ "source": "templates/antd-admin",
20
+ "target": "."
21
+ }
22
+ ],
23
+ "editablePaths": [
24
+ "src/pages/**",
25
+ "src/features/**",
26
+ "src/mocks/**",
27
+ "src/shared/components/business/**",
28
+ "public/generated/**"
29
+ ],
30
+ "protectedPaths": [
31
+ ".harness/template.json",
32
+ ".gitignore",
33
+ "index.html",
34
+ "package.json",
35
+ "pnpm-lock.yaml",
36
+ "pnpm-workspace.yaml",
37
+ "tsconfig.json",
38
+ "tsconfig.app.json",
39
+ "tsconfig.node.json",
40
+ "vite.config.ts",
41
+ "scripts/**",
42
+ "src/main.tsx",
43
+ "src/vite-env.d.ts",
44
+ "src/app/**",
45
+ "src/layouts/**",
46
+ "src/routes/**",
47
+ "src/styles/**"
48
+ ],
49
+ "commands": {
50
+ "install": {
51
+ "command": "pnpm",
52
+ "args": ["install", "--frozen-lockfile", "--prefer-offline", "--ignore-scripts"],
53
+ "cwd": "."
54
+ },
55
+ "preview": {
56
+ "command": "pnpm",
57
+ "args": ["exec", "vite", "--config", "vite.config.ts"],
58
+ "cwd": "."
59
+ },
60
+ "validate": {
61
+ "command": "pnpm",
62
+ "args": ["run", "validate"],
63
+ "cwd": "."
64
+ }
65
+ }
66
+ }
67
+ ],
68
+ "frontendRuntimes": [
69
+ {
70
+ "id": "antd-admin-runtime",
71
+ "version": "2.0.8",
72
+ "abiVersion": "1",
73
+ "title": "Ant Design 管理后台 Runtime",
74
+ "description": "由 Harness 托管的 React、TypeScript、Vite 与 Ant Design 共享运行时,业务项目只保存页面和业务源码。",
75
+ "root": "runtimes/antd-admin",
76
+ "entry": "src/main.tsx",
77
+ "sdkEntry": "src/sdk/index.ts",
78
+ "publicContract": "PUBLIC_CONTRACT.md",
79
+ "typeDeclarations": "types/runtime.d.ts",
80
+ "dependencies": {
81
+ "@ant-design/charts": "2.6.7",
82
+ "@ant-design/icons": "6.3.2",
83
+ "@types/node": "24.13.3",
84
+ "@types/react": "19.2.18",
85
+ "@types/react-dom": "19.2.5",
86
+ "@vitejs/plugin-react": "6.1.0",
87
+ "antd": "6.6.1",
88
+ "dayjs": "1.11.23",
89
+ "react": "19.2.8",
90
+ "react-dom": "19.2.8",
91
+ "react-router-dom": "7.18.2",
92
+ "typescript": "5.9.2",
93
+ "vite": "8.2.2"
94
+ },
95
+ "readablePaths": [
96
+ "README.md",
97
+ "src/**",
98
+ "public/generated/**"
99
+ ],
100
+ "editablePaths": [
101
+ "src/app.json",
102
+ "src/app/providers.tsx",
103
+ "src/pages/**",
104
+ "src/features/**",
105
+ "src/mocks/**",
106
+ "src/shared/**",
107
+ "src/styles.css",
108
+ "public/generated/**"
109
+ ]
110
+ }
111
+ ],
112
+ "assistantModes": [
113
+ {
114
+ "id": "fast-frontend",
115
+ "title": "快速前台",
116
+ "description": "使用 Harness 共享 Ant Design Runtime,只生成业务页面、业务状态、模拟数据与声明式路由。",
117
+ "runtimeId": "antd-admin-runtime",
118
+ "instructions": "你处于快速前台 Runtime 2.0。无需也不得扫描、复制或修改框架源码;Host 已注入 Runtime 公共契约和 README。项目根不含 package.json、node_modules、Vite 配置或框架入口。只读 README.md、src/**、public/generated/**,只改 Runtime 的 editablePaths。页面写入 src/pages/<id>/page.tsx 并默认导出 React 组件;同目录 route.json 声明 id、path、title、icon、order、parentId、hidden,Host 据此生成路由和菜单。src/app.json 配置名称和主题;src/app/providers.tsx 放全局 Provider;业务逻辑、模拟数据、共享代码、样式和资源分别放 src/features/**、src/mocks/**、src/shared/**、src/styles.css、public/generated/**。可使用 React、Ant Design、@ant-design/icons、React Router、dayjs、@ant-design/charts、@harness/frontend-runtime;禁止 Node 内置模块、远程导入及其他依赖。禁止直接访问 localStorage 或 sessionStorage;同步存储使用 getFrontendStorage(namespace?)。不要执行安装、构建或开发服务器命令。依据当前请求决定是否实现页面,普通对话不需要编译验证。修改业务源码后调用 frontend_validate,并如实报告结果;失败时修复相关问题,无法修复时说明原因后结束,不宣称检查通过。源码未变不要重复检查。框架或依赖需变更时提示关闭快速前台。",
119
+ "fallbackDirectory": "."
120
+ }
121
+ ]
122
+ }
123
+ }
@@ -0,0 +1,139 @@
1
+ # Harness Ant Design Runtime 公共契约
2
+
3
+ ABI:`1`。业务应用只保存需求、业务源码和生成资源;不得创建 `package.json`、
4
+ `node_modules`、Vite 配置、框架入口或路由注册中心。Runtime 源码由 Host 隔离,Agent
5
+ 不需要也不能读取它。
6
+
7
+ ## 业务目录
8
+
9
+ ```text
10
+ README.md
11
+ src/app.json
12
+ src/app/providers.tsx
13
+ src/pages/<页面标识>/page.tsx
14
+ src/pages/<页面标识>/route.json
15
+ src/features/**
16
+ src/mocks/**
17
+ src/shared/**
18
+ src/styles.css
19
+ public/generated/**
20
+ ```
21
+
22
+ - `page.tsx` 默认导出无必填属性的 React 页面组件。
23
+ - `route.json` 必须符合 `contracts/route.schema.json`。`id` 和 `path` 在应用内唯一;
24
+ `parentId` 必须引用其他路由且不得形成循环。`path` 支持 React Router 动态参数。
25
+ - `route.json` 的最小形式是
26
+ `{ "id": "dashboard", "path": "/dashboard", "title": "仪表盘" }`;可选字段为
27
+ `order`(整数)、`parentId`、`hidden` 和 `icon`。`icon` 只能取
28
+ `AppstoreOutlined`、`BarChartOutlined`、`DashboardOutlined`、`FileTextOutlined`、
29
+ `FormOutlined`、`HomeOutlined`、`SettingOutlined`、`TeamOutlined`、
30
+ `UnorderedListOutlined`;不需要图标时请省略该字段。
31
+ - `src/app.json` 可选,符合 `contracts/app.schema.json`;未提供时使用 Runtime 默认值。
32
+ Logo 只能使用 `./generated/**` 形式引用本地资源,不能使用根路径或远程 URL。
33
+ 支持的完整结构是
34
+ `{ "name": "应用名称", "logo": "./generated/logo.svg", "theme":
35
+ { "colorPrimary": "#1677ff", "borderRadius": 8, "compact": false } }`,各字段均可省略。
36
+ - `src/app/providers.tsx` 可选,默认导出一个接收 `children` 的 React Provider。Host 将其
37
+ 放入虚拟注册表的 `providers` 数组。`children` 必须保持可选;全局操作、当前用户和用户
38
+ 切换器必须通过 `FrontendShellProvider` 注册到 Runtime 已有 Header,不得再创建第二个
39
+ `Layout.Header`。Ant Design 中文环境可按以下方式组合:
40
+
41
+ ```tsx
42
+ import type { ReactNode } from "react";
43
+ import { ConfigProvider, Select } from "antd";
44
+ import zhCN from "antd/locale/zh_CN";
45
+ import { FrontendShellProvider } from "@harness/frontend-runtime";
46
+
47
+ export default function Providers({ children }: { children?: ReactNode }) {
48
+ return (
49
+ <ConfigProvider locale={zhCN}>
50
+ <FrontendShellProvider
51
+ currentUser={{ name: "张三", description: "管理员" }}
52
+ userSwitcher={<Select aria-label="切换用户" options={[]} />}
53
+ >
54
+ {children}
55
+ </FrontendShellProvider>
56
+ </ConfigProvider>
57
+ );
58
+ }
59
+ ```
60
+ - `src/styles.css` 可选,只作用于当前业务应用。生成图片等资源放入
61
+ `public/generated/**`。`src/app.json` 和 TSX/JSX 运行时字符串使用
62
+ `./generated/<文件>`;CSS 的 `url(...)` 使用 `/generated/<文件>`,Host 在静态导出时
63
+ 会改写为相对路径,二者都兼容任意子路径部署。Runtime 已固定视口高度并让内容区独立
64
+ 滚动;业务样式不得重设 `html`、`body`、`#root` 或 `.harness-runtime-*` 的高度与
65
+ `overflow`,也不得覆盖 Runtime Shell 的布局规则。
66
+
67
+ ## 可用依赖
68
+
69
+ 业务源码只可导入 React、React DOM、Ant Design、Ant Design Icons、React Router、
70
+ dayjs、Ant Design Charts 和 `@harness/frontend-runtime`。Runtime 保证 React、Router
71
+ 与 Ant Design 为单例。禁止 Node 内置模块、远程 URL/资源、项目外路径和其他 npm 包;
72
+ Runtime CSP 仅允许同源、`data:` 图片和 `blob:` 图片。
73
+
74
+ Ant Design 原生组件始终可以直接使用,不要求把页面改写成 Runtime 组件。下面的 Runtime
75
+ 原语只是可选的高质量默认实现,用来减少重复样板代码和页面间视觉漂移。
76
+
77
+ `@harness/frontend-runtime` 公开:
78
+
79
+ - `useFrontendRuntime()`:读取应用信息、路由元数据、当前路径并执行导航;
80
+ - `defineFrontendProviders()`:为多个全局业务 Provider 提供类型检查;
81
+ - `getFrontendStorage(namespace?)`:同步、按命名空间隔离的存储;预览经 Host 桥接持久化,
82
+ 不可用时降级为内存;
83
+ - `FrontendShellProvider` / `useFrontendShell()`:把 `headerActions`、`currentUser`、
84
+ `userSwitcher` 注册到 Runtime 唯一的顶栏;
85
+ - `PageContainer` / `useFrontendPage()`:把页面标题、说明、标题操作和
86
+ `standard | wide | full` 内容宽度注册到 Runtime;`PageContainer` 本身不会再渲染一套
87
+ 标题或 Header;
88
+ - `MetricGrid`、`DataTable`、`CrudDrawer`、`StatusTag`:可选的 Ant Design 统计卡、
89
+ 表格卡、表单抽屉和状态标签原语;它们的属性仍基于对应 Ant Design 类型;
90
+ - `createFrontendStore(initialState)`:小型、无额外依赖的同步业务状态容器,提供
91
+ `getState`、`setState`、`update`、`reset`、`subscribe` 和选择器式 `useStore`;
92
+ - `usePersistentFrontendState(key, initialState, options?)`:与 `useState` 相同的同步接口,
93
+ 通过安全 Storage 适配器持久化;
94
+ - `FrontendBusinessAppManifest`、`FrontendRouteMetadata`、`FrontendRuntimeProvider` 等类型。
95
+
96
+ 推荐的页面根节点如下。Runtime 已负责应用 Header、侧边菜单、面包屑和页面标题;业务页
97
+ 不得重复渲染这些框架元素:
98
+
99
+ ```tsx
100
+ import { Button, Space } from "antd";
101
+ import { DataTable, PageContainer, StatusTag } from "@harness/frontend-runtime";
102
+
103
+ export default function TaskListPage() {
104
+ return (
105
+ <PageContainer
106
+ title="待办事项"
107
+ description="查看并处理当前待办"
108
+ width="wide"
109
+ titleActions={<Space><Button type="primary">新建事项</Button></Space>}
110
+ >
111
+ <DataTable
112
+ rowKey="id"
113
+ dataSource={[]}
114
+ columns={[{ title: "状态", render: () => <StatusTag status="进行中" /> }]}
115
+ />
116
+ </PageContainer>
117
+ );
118
+ }
119
+ ```
120
+
121
+ 预览 iframe 无 `allow-same-origin`,业务源码禁止直接访问 `localStorage` 或
122
+ `sessionStorage`;同步存储必须使用 `getFrontendStorage(namespace?)`。
123
+
124
+ ## Host 虚拟模块
125
+
126
+ Host 生成 `virtual:harness-business-registry`,固定导出:
127
+
128
+ ```ts
129
+ export const routes: readonly {
130
+ metadata: FrontendRouteMetadata;
131
+ Component: React.LazyExoticComponent<React.ComponentType<Record<string, never>>>;
132
+ }[];
133
+ export const appManifest: FrontendBusinessAppManifest;
134
+ export const providers: readonly FrontendRuntimeProvider[];
135
+ export const stylesUrl: string | undefined;
136
+ ```
137
+
138
+ 业务代码不得直接导入这个 Host 内部模块。页面源码或 `route.json` 改动由 Host 转换为
139
+ 虚拟模块更新;页面模块使用 Fast Refresh,路由结构变化触发整页刷新。
@@ -0,0 +1,24 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://harness.local/schemas/frontend-business-app-v1.json",
4
+ "title": "Harness Frontend Business App",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "properties": {
8
+ "name": { "type": "string", "minLength": 1, "maxLength": 160 },
9
+ "logo": {
10
+ "type": "string",
11
+ "pattern": "^\\./generated/(?:[^./][^/]*/)*[^./][^/]*$",
12
+ "maxLength": 2048
13
+ },
14
+ "theme": {
15
+ "type": "object",
16
+ "additionalProperties": false,
17
+ "properties": {
18
+ "colorPrimary": { "type": "string", "pattern": "^#[0-9a-fA-F]{6}$" },
19
+ "borderRadius": { "type": "integer", "minimum": 0, "maximum": 24 },
20
+ "compact": { "type": "boolean" }
21
+ }
22
+ }
23
+ }
24
+ }
@@ -0,0 +1,52 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://harness.local/schemas/frontend-route-v1.json",
4
+ "title": "Harness Frontend Route",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": ["id", "path", "title"],
8
+ "properties": {
9
+ "id": {
10
+ "type": "string",
11
+ "pattern": "^[a-zA-Z0-9][a-zA-Z0-9._:-]*$",
12
+ "maxLength": 160
13
+ },
14
+ "path": {
15
+ "type": "string",
16
+ "pattern": "^/",
17
+ "maxLength": 1024
18
+ },
19
+ "title": {
20
+ "type": "string",
21
+ "minLength": 1,
22
+ "maxLength": 160
23
+ },
24
+ "icon": {
25
+ "type": "string",
26
+ "enum": [
27
+ "AppstoreOutlined",
28
+ "BarChartOutlined",
29
+ "DashboardOutlined",
30
+ "FileTextOutlined",
31
+ "FormOutlined",
32
+ "HomeOutlined",
33
+ "SettingOutlined",
34
+ "TeamOutlined",
35
+ "UnorderedListOutlined"
36
+ ]
37
+ },
38
+ "order": {
39
+ "type": "integer",
40
+ "default": 0
41
+ },
42
+ "parentId": {
43
+ "type": "string",
44
+ "pattern": "^[a-zA-Z0-9][a-zA-Z0-9._:-]*$",
45
+ "maxLength": 160
46
+ },
47
+ "hidden": {
48
+ "type": "boolean",
49
+ "default": false
50
+ }
51
+ }
52
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "示例业务平台",
3
+ "logo": "./generated/logo.svg",
4
+ "theme": {
5
+ "colorPrimary": "#1677ff",
6
+ "borderRadius": 8,
7
+ "compact": false
8
+ }
9
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "id": "dashboard",
3
+ "path": "/dashboard",
4
+ "title": "数据概览",
5
+ "icon": "DashboardOutlined",
6
+ "order": 10,
7
+ "hidden": false
8
+ }
@@ -0,0 +1,17 @@
1
+ <!doctype html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <meta name="color-scheme" content="light" />
7
+ <meta
8
+ http-equiv="Content-Security-Policy"
9
+ content="default-src 'self'; base-uri 'none'; object-src 'none'; frame-src 'none'; form-action 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self' ws://127.0.0.1:* ws://localhost:*"
10
+ />
11
+ <title>Harness 快速前台</title>
12
+ </head>
13
+ <body>
14
+ <div id="root"></div>
15
+ <script type="module" src="/src/main.tsx"></script>
16
+ </body>
17
+ </html>
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@harness/bundled-antd-admin-runtime",
3
+ "version": "2.0.8",
4
+ "private": true,
5
+ "type": "module",
6
+ "engines": {
7
+ "node": ">=24.0.0"
8
+ },
9
+ "scripts": {
10
+ "typecheck": "tsc -p tsconfig.json --noEmit",
11
+ "smoke:build": "node scripts/smoke-build.mjs",
12
+ "validate": "pnpm run typecheck && pnpm run smoke:build"
13
+ },
14
+ "dependencies": {
15
+ "@ant-design/charts": "2.6.7",
16
+ "@ant-design/icons": "6.3.2",
17
+ "antd": "6.6.1",
18
+ "dayjs": "1.11.23",
19
+ "react": "19.2.8",
20
+ "react-dom": "19.2.8",
21
+ "react-router-dom": "7.18.2"
22
+ },
23
+ "devDependencies": {
24
+ "@types/node": "24.13.3",
25
+ "@types/react": "19.2.18",
26
+ "@types/react-dom": "19.2.5",
27
+ "@vitejs/plugin-react": "6.1.0",
28
+ "typescript": "5.9.2",
29
+ "vite": "8.2.2"
30
+ }
31
+ }
@@ -0,0 +1,40 @@
1
+ import path from "node:path";
2
+
3
+ import react from "@vitejs/plugin-react";
4
+ import { build } from "vite";
5
+
6
+ const virtualId = "virtual:harness-business-registry";
7
+ const resolvedVirtualId = `\0${virtualId}`;
8
+
9
+ await build({
10
+ root: process.cwd(),
11
+ base: "./",
12
+ configFile: false,
13
+ plugins: [
14
+ react(),
15
+ {
16
+ name: "harness-runtime-contract-smoke",
17
+ resolveId(id) {
18
+ return id === virtualId ? resolvedVirtualId : null;
19
+ },
20
+ load(id) {
21
+ if (id !== resolvedVirtualId) return null;
22
+ return [
23
+ "export const routes = [];",
24
+ "export const appManifest = { name: 'Runtime smoke test' };",
25
+ "export const providers = [];",
26
+ "export const stylesUrl = undefined;",
27
+ ].join("\n");
28
+ },
29
+ },
30
+ ],
31
+ resolve: {
32
+ alias: {
33
+ "@harness/frontend-runtime": path.resolve("src/sdk/index.ts"),
34
+ },
35
+ },
36
+ build: {
37
+ outDir: "node_modules/.cache/runtime-smoke-build",
38
+ emptyOutDir: true,
39
+ },
40
+ });