@aipt/cli 0.1.0
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 +116 -0
- package/dist/catalog/foundation.standalone-npm-package/1.0.0/assets/package.json +4 -0
- package/dist/catalog/foundation.standalone-npm-package/1.0.0/assets/pnpm-workspace.yaml +1 -0
- package/dist/catalog/foundation.standalone-npm-package/1.0.0/assets/src/index.test.ts +8 -0
- package/dist/catalog/foundation.standalone-npm-package/1.0.0/assets/src/index.ts +3 -0
- package/dist/catalog/foundation.standalone-npm-package/1.0.0/assets/tsconfig.build.json +12 -0
- package/dist/catalog/foundation.standalone-npm-package/1.0.0/assets/tsconfig.json +14 -0
- package/dist/catalog/foundation.standalone-npm-package/1.0.0/release.json +29 -0
- package/dist/catalog/foundation.typescript-quality/1.0.0/assets/package.json +21 -0
- package/dist/catalog/foundation.typescript-quality/1.0.0/assets/pnpm-workspace.yaml +1 -0
- package/dist/catalog/foundation.typescript-quality/1.0.0/assets/src/index.test.ts +8 -0
- package/dist/catalog/foundation.typescript-quality/1.0.0/assets/src/index.ts +3 -0
- package/dist/catalog/foundation.typescript-quality/1.0.0/assets/tsconfig.json +14 -0
- package/dist/catalog/foundation.typescript-quality/1.0.0/release.json +57 -0
- package/dist/catalog/foundation.workspace-node-application/1.0.0/assets/package.json +4 -0
- package/dist/catalog/foundation.workspace-node-application/1.0.0/assets/src/app.test.ts +21 -0
- package/dist/catalog/foundation.workspace-node-application/1.0.0/assets/src/app.ts +14 -0
- package/dist/catalog/foundation.workspace-node-application/1.0.0/assets/src/index.test.ts +14 -0
- package/dist/catalog/foundation.workspace-node-application/1.0.0/assets/src/index.ts +53 -0
- package/dist/catalog/foundation.workspace-node-application/1.0.0/assets/tsconfig.build.json +12 -0
- package/dist/catalog/foundation.workspace-node-application/1.0.0/assets/tsconfig.json +7 -0
- package/dist/catalog/foundation.workspace-node-application/1.0.0/release.json +19 -0
- package/dist/catalog/foundation.workspace-npm-package/1.0.0/assets/package.json +4 -0
- package/dist/catalog/foundation.workspace-npm-package/1.0.0/assets/src/index.test.ts +8 -0
- package/dist/catalog/foundation.workspace-npm-package/1.0.0/assets/src/index.ts +3 -0
- package/dist/catalog/foundation.workspace-npm-package/1.0.0/assets/tsconfig.build.json +12 -0
- package/dist/catalog/foundation.workspace-npm-package/1.0.0/assets/tsconfig.json +7 -0
- package/dist/catalog/foundation.workspace-npm-package/1.0.0/release.json +17 -0
- package/dist/catalog/foundation.workspace-root/1.0.0/assets/package.json +16 -0
- package/dist/catalog/foundation.workspace-root/1.0.0/assets/packages/README.md +3 -0
- package/dist/catalog/foundation.workspace-root/1.0.0/assets/pnpm-workspace.yaml +3 -0
- package/dist/catalog/foundation.workspace-root/1.0.0/assets/tsconfig.base.json +12 -0
- package/dist/catalog/foundation.workspace-root/1.0.0/release.json +16 -0
- package/dist/catalog/foundation.workspace-root/1.1.0/assets/apps/README.md +3 -0
- package/dist/catalog/foundation.workspace-root/1.1.0/assets/package.json +16 -0
- package/dist/catalog/foundation.workspace-root/1.1.0/assets/packages/README.md +3 -0
- package/dist/catalog/foundation.workspace-root/1.1.0/assets/pnpm-workspace.yaml +3 -0
- package/dist/catalog/foundation.workspace-root/1.1.0/assets/tsconfig.base.json +12 -0
- package/dist/catalog/foundation.workspace-root/1.1.0/release.json +17 -0
- package/dist/catalog/foundation.workspace-web-application/1.0.0/assets/index.html +14 -0
- package/dist/catalog/foundation.workspace-web-application/1.0.0/assets/package.json +4 -0
- package/dist/catalog/foundation.workspace-web-application/1.0.0/assets/src/App.css +26 -0
- package/dist/catalog/foundation.workspace-web-application/1.0.0/assets/src/App.test.tsx +21 -0
- package/dist/catalog/foundation.workspace-web-application/1.0.0/assets/src/App.tsx +51 -0
- package/dist/catalog/foundation.workspace-web-application/1.0.0/assets/src/index.css +6 -0
- package/dist/catalog/foundation.workspace-web-application/1.0.0/assets/src/main.tsx +13 -0
- package/dist/catalog/foundation.workspace-web-application/1.0.0/assets/src/test/setup.ts +1 -0
- package/dist/catalog/foundation.workspace-web-application/1.0.0/assets/tsconfig.app.json +17 -0
- package/dist/catalog/foundation.workspace-web-application/1.0.0/assets/tsconfig.json +7 -0
- package/dist/catalog/foundation.workspace-web-application/1.0.0/assets/tsconfig.node.json +16 -0
- package/dist/catalog/foundation.workspace-web-application/1.0.0/assets/vite.config.ts +11 -0
- package/dist/catalog/foundation.workspace-web-application/1.0.0/release.json +24 -0
- package/dist/catalog/foundation.workspace-web-application/1.1.0/assets/index.html +14 -0
- package/dist/catalog/foundation.workspace-web-application/1.1.0/assets/package.json +4 -0
- package/dist/catalog/foundation.workspace-web-application/1.1.0/assets/src/App.css +26 -0
- package/dist/catalog/foundation.workspace-web-application/1.1.0/assets/src/App.test.tsx +21 -0
- package/dist/catalog/foundation.workspace-web-application/1.1.0/assets/src/App.tsx +51 -0
- package/dist/catalog/foundation.workspace-web-application/1.1.0/assets/src/index.css +6 -0
- package/dist/catalog/foundation.workspace-web-application/1.1.0/assets/src/main.tsx +16 -0
- package/dist/catalog/foundation.workspace-web-application/1.1.0/assets/src/runtime-error-reporter.test.ts +13 -0
- package/dist/catalog/foundation.workspace-web-application/1.1.0/assets/src/runtime-error-reporter.ts +30 -0
- package/dist/catalog/foundation.workspace-web-application/1.1.0/assets/src/test/setup.ts +1 -0
- package/dist/catalog/foundation.workspace-web-application/1.1.0/assets/tsconfig.app.json +17 -0
- package/dist/catalog/foundation.workspace-web-application/1.1.0/assets/tsconfig.json +7 -0
- package/dist/catalog/foundation.workspace-web-application/1.1.0/assets/tsconfig.node.json +16 -0
- package/dist/catalog/foundation.workspace-web-application/1.1.0/assets/vite.config.ts +11 -0
- package/dist/catalog/foundation.workspace-web-application/1.1.0/release.json +131 -0
- package/dist/cli.js +12027 -0
- package/package.json +25 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"capabilityId": "foundation.workspace-root",
|
|
4
|
+
"version": "1.1.0",
|
|
5
|
+
"integrity": "sha256:0764015bb9ef22e05569d3735c2e1f685955be577130cb03ee838172643521ad",
|
|
6
|
+
"consumerProfile": "workspace-root",
|
|
7
|
+
"compatibility": { "node": ">=24.18.0 <25", "pnpm": "11.21.0", "typescript": "6.0.3" },
|
|
8
|
+
"assets": [
|
|
9
|
+
{ "path": "apps/README.md", "ownership": "owned-file", "digest": "sha256:f15e8f25a62a5757bb40e52d322a68493d8828df13970b90119aa6a28e36567c", "mode": 420 },
|
|
10
|
+
{ "path": "package.json", "ownership": "owned-file", "digest": "sha256:59420801655582958906c77d0b893498ccfc447462f693d2147ac74c24c4f4b1", "mode": 420 },
|
|
11
|
+
{ "path": "packages/README.md", "ownership": "owned-file", "digest": "sha256:89ef48abb0e71878e4f8c267cf449e0356aeb467429a9897a4d51f22f94fc2fb", "mode": 420 },
|
|
12
|
+
{ "path": "pnpm-workspace.yaml", "ownership": "owned-file", "digest": "sha256:316f2a0038d464f103abd64d7338dacefc35d0d09e57c8296defa0d5ddb898fe", "mode": 420 },
|
|
13
|
+
{ "path": "tsconfig.base.json", "ownership": "owned-file", "digest": "sha256:075bf5c84e6dd6e0215084de39a4ce2ef96f083a1b19deb0e0f6586d98c8ac87", "mode": 420 }
|
|
14
|
+
],
|
|
15
|
+
"verifiers": [{ "id": "workspace.structure" }],
|
|
16
|
+
"exit": { "ownedAssets": ["apps/README.md", "package.json", "packages/README.md", "pnpm-workspace.yaml", "tsconfig.base.json"] }
|
|
17
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
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="theme-color" content="#0d1b1e" />
|
|
7
|
+
<meta name="description" content="一个具备完整工程基线的工作区 Web 应用。" />
|
|
8
|
+
<title>工作区 Web 应用</title>
|
|
9
|
+
</head>
|
|
10
|
+
<body data-application-shell>
|
|
11
|
+
<div id="root"></div>
|
|
12
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
13
|
+
</body>
|
|
14
|
+
</html>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
main { min-height: 100vh; overflow: hidden; }
|
|
2
|
+
nav { height: 82px; padding: 0 clamp(24px, 5vw, 76px); display: flex; align-items: center; justify-content: space-between; border-bottom: 1px solid rgba(16,36,39,.16); }
|
|
3
|
+
.brand { display: flex; align-items: center; gap: 12px; color: inherit; text-decoration: none; font: 700 12px/1 "Manrope", sans-serif; letter-spacing: .12em; }
|
|
4
|
+
.brand-mark { width: 34px; height: 34px; display: grid; place-items: center; border-radius: 50%; color: #f3f0e8; background: #102427; font-size: 14px; }
|
|
5
|
+
.status { display: flex; align-items: center; gap: 10px; font-size: 13px; color: #3e5557; }
|
|
6
|
+
.status > span { width: 8px; height: 8px; border-radius: 50%; background: #2f886c; box-shadow: 0 0 0 5px rgba(47,136,108,.12); }
|
|
7
|
+
.hero { min-height: calc(100vh - 82px); padding: clamp(72px, 11vh, 128px) clamp(24px, 8vw, 128px) 80px; position: relative; }
|
|
8
|
+
.hero::after { content: ""; position: absolute; width: min(42vw, 560px); aspect-ratio: 1; right: -8%; top: 8%; border: 1px solid rgba(16,36,39,.13); border-radius: 50%; box-shadow: 0 0 0 72px rgba(16,36,39,.025), 0 0 0 144px rgba(16,36,39,.018); pointer-events: none; }
|
|
9
|
+
.eyebrow { margin: 0 0 26px; font: 600 11px/1 "Manrope", sans-serif; letter-spacing: .18em; color: #4d686a; }
|
|
10
|
+
h1, h2 { margin: 0; font-family: "Manrope", sans-serif; letter-spacing: -.055em; font-weight: 600; }
|
|
11
|
+
h1 { max-width: 900px; font-size: clamp(64px, 10vw, 144px); line-height: .88; }
|
|
12
|
+
.intro { max-width: 520px; margin: 40px 0 34px; font-size: clamp(17px, 1.5vw, 21px); line-height: 1.58; color: #425a5c; }
|
|
13
|
+
.actions { display: flex; flex-wrap: wrap; align-items: center; gap: 28px; }
|
|
14
|
+
.actions button { border: 0; border-radius: 999px; padding: 15px 20px 15px 24px; color: #f8f5ee; background: #102427; cursor: pointer; display: flex; align-items: center; gap: 18px; }
|
|
15
|
+
.actions button span { min-width: 28px; height: 28px; display: grid; place-items: center; border-radius: 50%; background: #d66a3c; }
|
|
16
|
+
.actions a { color: #102427; text-underline-offset: 5px; }
|
|
17
|
+
.foundation { padding: clamp(80px, 10vw, 144px) clamp(24px, 8vw, 128px); color: #eef2e9; background: #102427; display: grid; grid-template-columns: minmax(250px, .8fr) minmax(420px, 1.2fr); gap: 10vw; }
|
|
18
|
+
.foundation .eyebrow { color: #88a1a0; }
|
|
19
|
+
h2 { font-size: clamp(42px, 5vw, 72px); line-height: 1; }
|
|
20
|
+
.capability-list { border-top: 1px solid rgba(238,242,233,.22); }
|
|
21
|
+
article { display: grid; grid-template-columns: 56px 1fr; gap: 20px; padding: 28px 0; border-bottom: 1px solid rgba(238,242,233,.22); }
|
|
22
|
+
article > span { color: #d66a3c; font: 600 12px/1.4 "Manrope", sans-serif; }
|
|
23
|
+
article h3 { margin: 0 0 8px; font: 600 22px/1.2 "Manrope", sans-serif; }
|
|
24
|
+
article p { margin: 0; max-width: 450px; color: #aebdbc; line-height: 1.55; }
|
|
25
|
+
@media (max-width: 760px) { nav { height: 70px; } .status { font-size: 0; } .hero { min-height: calc(100vh - 70px); padding-top: 80px; } .hero::after { top: 22%; opacity: .6; } .foundation { grid-template-columns: 1fr; gap: 64px; } }
|
|
26
|
+
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { cleanup, fireEvent, render, screen } from "@testing-library/react";
|
|
2
|
+
import { afterEach, describe, expect, it } from "vitest";
|
|
3
|
+
import { App } from "./App.js";
|
|
4
|
+
|
|
5
|
+
afterEach(cleanup);
|
|
6
|
+
|
|
7
|
+
describe("workspace web application", () => {
|
|
8
|
+
it("presents the production foundation", () => {
|
|
9
|
+
render(<App />);
|
|
10
|
+
expect(screen.getByRole("heading", { level: 1, name: /从清晰的起点.*开始创造/ })).toBeVisible();
|
|
11
|
+
expect(screen.getByText("准备就绪")).toBeVisible();
|
|
12
|
+
expect(screen.getAllByRole("article")).toHaveLength(3);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("supports an observable interaction", () => {
|
|
16
|
+
render(<App />);
|
|
17
|
+
const button = screen.getByRole("button", { name: /测试交互 0/ });
|
|
18
|
+
fireEvent.click(button);
|
|
19
|
+
expect(screen.getByRole("button", { name: /测试交互 1/ })).toBeVisible();
|
|
20
|
+
});
|
|
21
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import "./App.css";
|
|
3
|
+
|
|
4
|
+
const capabilities = [
|
|
5
|
+
{ number: "01", title: "开发", detail: "通过专注且快速的 Vite 开发服务器获得即时反馈。" },
|
|
6
|
+
{ number: "02", title: "验证", detail: "类型、组件、生产构建与预览检查已经就绪。" },
|
|
7
|
+
{ number: "03", title: "交付", detail: "优化后的静态产物让部署边界保持清晰。" },
|
|
8
|
+
];
|
|
9
|
+
|
|
10
|
+
export function App() {
|
|
11
|
+
const [count, setCount] = useState(0);
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<main>
|
|
15
|
+
<nav aria-label="应用导航">
|
|
16
|
+
<a className="brand" href="#top" aria-label="工作区 Web 应用首页">
|
|
17
|
+
<span aria-hidden="true" className="brand-mark">D</span>
|
|
18
|
+
<span>工作区 / WEB</span>
|
|
19
|
+
</a>
|
|
20
|
+
<span className="status"><span aria-hidden="true" />准备就绪</span>
|
|
21
|
+
</nav>
|
|
22
|
+
|
|
23
|
+
<section className="hero" id="top">
|
|
24
|
+
<p className="eyebrow">React 19 · Vite 8 · TypeScript 6</p>
|
|
25
|
+
<h1>从清晰的起点<br />开始创造。</h1>
|
|
26
|
+
<p className="intro">这个应用刻意从小处开始:一个明确归属的界面、一条经过验证的生产链路,以及留给产品决策的充足空间。</p>
|
|
27
|
+
<div className="actions">
|
|
28
|
+
<button type="button" onClick={() => setCount((value) => value + 1)}>
|
|
29
|
+
测试交互 <span aria-live="polite">{count}</span>
|
|
30
|
+
</button>
|
|
31
|
+
<a href="#foundation">查看工程基线 <span aria-hidden="true">↓</span></a>
|
|
32
|
+
</div>
|
|
33
|
+
</section>
|
|
34
|
+
|
|
35
|
+
<section className="foundation" id="foundation" aria-labelledby="foundation-title">
|
|
36
|
+
<header>
|
|
37
|
+
<p className="eyebrow">工程基线</p>
|
|
38
|
+
<h2 id="foundation-title">界面保持轻盈,<br />契约足够坚实。</h2>
|
|
39
|
+
</header>
|
|
40
|
+
<div className="capability-list">
|
|
41
|
+
{capabilities.map((capability) => (
|
|
42
|
+
<article key={capability.number}>
|
|
43
|
+
<span>{capability.number}</span>
|
|
44
|
+
<div><h3>{capability.title}</h3><p>{capability.detail}</p></div>
|
|
45
|
+
</article>
|
|
46
|
+
))}
|
|
47
|
+
</div>
|
|
48
|
+
</section>
|
|
49
|
+
</main>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
:root { font-family: Inter, ui-sans-serif, system-ui, sans-serif; color: #102427; background: #f3f0e8; font-synthesis: none; text-rendering: optimizeLegibility; }
|
|
2
|
+
* { box-sizing: border-box; }
|
|
3
|
+
html { scroll-behavior: smooth; }
|
|
4
|
+
body { margin: 0; min-width: 320px; min-height: 100vh; }
|
|
5
|
+
button, a { font: inherit; }
|
|
6
|
+
button:focus-visible, a:focus-visible { outline: 3px solid #ffb648; outline-offset: 4px; }
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { StrictMode } from "react";
|
|
2
|
+
import { createRoot } from "react-dom/client";
|
|
3
|
+
import { App } from "./App.js";
|
|
4
|
+
import "./index.css";
|
|
5
|
+
|
|
6
|
+
const root = document.getElementById("root");
|
|
7
|
+
if (root === null) throw new Error("Application root is unavailable");
|
|
8
|
+
|
|
9
|
+
createRoot(root).render(
|
|
10
|
+
<StrictMode>
|
|
11
|
+
<App />
|
|
12
|
+
</StrictMode>,
|
|
13
|
+
);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "@testing-library/jest-dom/vitest";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"tsBuildInfoFile": "./node_modules/.cache/tsconfig.app.tsbuildinfo",
|
|
5
|
+
"target": "ES2023",
|
|
6
|
+
"lib": ["ES2023", "DOM", "DOM.Iterable"],
|
|
7
|
+
"module": "ESNext",
|
|
8
|
+
"moduleResolution": "Bundler",
|
|
9
|
+
"allowImportingTsExtensions": true,
|
|
10
|
+
"verbatimModuleSyntax": true,
|
|
11
|
+
"moduleDetection": "force",
|
|
12
|
+
"noEmit": true,
|
|
13
|
+
"jsx": "react-jsx",
|
|
14
|
+
"types": ["vite/client", "vitest/globals", "@testing-library/jest-dom"]
|
|
15
|
+
},
|
|
16
|
+
"include": ["src"]
|
|
17
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"tsBuildInfoFile": "./node_modules/.cache/tsconfig.node.tsbuildinfo",
|
|
5
|
+
"target": "ES2023",
|
|
6
|
+
"lib": ["ES2023"],
|
|
7
|
+
"module": "ESNext",
|
|
8
|
+
"moduleResolution": "Bundler",
|
|
9
|
+
"allowImportingTsExtensions": true,
|
|
10
|
+
"verbatimModuleSyntax": true,
|
|
11
|
+
"moduleDetection": "force",
|
|
12
|
+
"noEmit": true,
|
|
13
|
+
"types": ["node"]
|
|
14
|
+
},
|
|
15
|
+
"include": ["vite.config.ts"]
|
|
16
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import react from "@vitejs/plugin-react";
|
|
2
|
+
import { defineConfig } from "vitest/config";
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
plugins: [react()],
|
|
6
|
+
build: { sourcemap: true },
|
|
7
|
+
test: {
|
|
8
|
+
environment: "jsdom",
|
|
9
|
+
setupFiles: "./src/test/setup.ts",
|
|
10
|
+
},
|
|
11
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"capabilityId": "foundation.workspace-web-application",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"integrity": "sha256:469f2e63e95023f6980c3d7eab54ab9092aed508558f38418cb2a3dc557ac18f",
|
|
6
|
+
"consumerProfile": "workspace-web-application",
|
|
7
|
+
"compatibility": { "node": ">=24.18.0 <25", "pnpm": "11.21.0", "typescript": "6.0.3" },
|
|
8
|
+
"assets": [
|
|
9
|
+
{ "path": "index.html", "ownership": "owned-file", "digest": "sha256:d8a6db98333d1dfca2e4cde69e102205103f7b97bba005223b9fb0bc5ff61a13", "mode": 420 },
|
|
10
|
+
{ "path": "package.json", "ownership": "owned-file", "digest": "sha256:989cd76c8c84d0608d72087cd6ecea6943f99739bd6aeaec6dff6e91eb4ff716", "mode": 420, "renderer": "web-application-package-json-v1" },
|
|
11
|
+
{ "path": "src/App.css", "ownership": "owned-file", "digest": "sha256:653c3b8acf85c051ab28cbd62026555e61369deacb2c89673e69c26375d1ba2c", "mode": 420 },
|
|
12
|
+
{ "path": "src/App.test.tsx", "ownership": "owned-file", "digest": "sha256:e0b402ab1c03cc54a77b98f98fe84f2ff838574d896db3d7e9b67a892c0cd94a", "mode": 420 },
|
|
13
|
+
{ "path": "src/App.tsx", "ownership": "owned-file", "digest": "sha256:0a91406b782e6e9f2f9aaf4303d1bf12e68b642cefce898a7f903c2dcfbed845", "mode": 420 },
|
|
14
|
+
{ "path": "src/index.css", "ownership": "owned-file", "digest": "sha256:052cf619027ea3611412e3e668c66c3ce3fe9b6d413bfcd13f9726d5c0285b96", "mode": 420 },
|
|
15
|
+
{ "path": "src/main.tsx", "ownership": "owned-file", "digest": "sha256:16b797ba50a7c70470cc5887d14d81c60328984ad3d5a0de5852e6fc52cc5005", "mode": 420 },
|
|
16
|
+
{ "path": "src/test/setup.ts", "ownership": "owned-file", "digest": "sha256:9b328c4843431fa76d8de00008fc159e95f99a840211085ff3b8f25e53d14409", "mode": 420 },
|
|
17
|
+
{ "path": "tsconfig.app.json", "ownership": "owned-file", "digest": "sha256:e225b26679d9b79e148bad705190ee08eb9b2c44af48268cd68e6f8a4d5cbdfc", "mode": 420 },
|
|
18
|
+
{ "path": "tsconfig.json", "ownership": "owned-file", "digest": "sha256:770b4140bbb581e2dfd9ea9946ffc9c75a1d86ba7d2db5f77c83e37cbdf9d808", "mode": 420 },
|
|
19
|
+
{ "path": "tsconfig.node.json", "ownership": "owned-file", "digest": "sha256:283a0697a4f1102628f6b19285e6b3f2ffdcba9c6ef64dc3d0148243fcd14a52", "mode": 420 },
|
|
20
|
+
{ "path": "vite.config.ts", "ownership": "owned-file", "digest": "sha256:c7f4054808eaf928355a57cf017c54cb84f95545b1f41ceb9918c90f9b48463d", "mode": 420 }
|
|
21
|
+
],
|
|
22
|
+
"verifiers": [{ "id": "typescript.typecheck" }, { "id": "vitest.run" }, { "id": "web.application-build" }, { "id": "web.application-smoke" }],
|
|
23
|
+
"exit": { "ownedAssets": ["index.html", "package.json", "src/App.css", "src/App.test.tsx", "src/App.tsx", "src/index.css", "src/main.tsx", "src/test/setup.ts", "tsconfig.app.json", "tsconfig.json", "tsconfig.node.json", "vite.config.ts"] }
|
|
24
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
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="theme-color" content="#0d1b1e" />
|
|
7
|
+
<meta name="description" content="一个具备完整工程基线的工作区 Web 应用。" />
|
|
8
|
+
<title>工作区 Web 应用</title>
|
|
9
|
+
</head>
|
|
10
|
+
<body data-application-shell>
|
|
11
|
+
<div id="root"></div>
|
|
12
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
13
|
+
</body>
|
|
14
|
+
</html>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
main { min-height: 100vh; overflow: hidden; }
|
|
2
|
+
nav { height: 82px; padding: 0 clamp(24px, 5vw, 76px); display: flex; align-items: center; justify-content: space-between; border-bottom: 1px solid rgba(16,36,39,.16); }
|
|
3
|
+
.brand { display: flex; align-items: center; gap: 12px; color: inherit; text-decoration: none; font: 700 12px/1 "Manrope", sans-serif; letter-spacing: .12em; }
|
|
4
|
+
.brand-mark { width: 34px; height: 34px; display: grid; place-items: center; border-radius: 50%; color: #f3f0e8; background: #102427; font-size: 14px; }
|
|
5
|
+
.status { display: flex; align-items: center; gap: 10px; font-size: 13px; color: #3e5557; }
|
|
6
|
+
.status > span { width: 8px; height: 8px; border-radius: 50%; background: #2f886c; box-shadow: 0 0 0 5px rgba(47,136,108,.12); }
|
|
7
|
+
.hero { min-height: calc(100vh - 82px); padding: clamp(72px, 11vh, 128px) clamp(24px, 8vw, 128px) 80px; position: relative; }
|
|
8
|
+
.hero::after { content: ""; position: absolute; width: min(42vw, 560px); aspect-ratio: 1; right: -8%; top: 8%; border: 1px solid rgba(16,36,39,.13); border-radius: 50%; box-shadow: 0 0 0 72px rgba(16,36,39,.025), 0 0 0 144px rgba(16,36,39,.018); pointer-events: none; }
|
|
9
|
+
.eyebrow { margin: 0 0 26px; font: 600 11px/1 "Manrope", sans-serif; letter-spacing: .18em; color: #4d686a; }
|
|
10
|
+
h1, h2 { margin: 0; font-family: "Manrope", sans-serif; letter-spacing: -.055em; font-weight: 600; }
|
|
11
|
+
h1 { max-width: 900px; font-size: clamp(64px, 10vw, 144px); line-height: .88; }
|
|
12
|
+
.intro { max-width: 520px; margin: 40px 0 34px; font-size: clamp(17px, 1.5vw, 21px); line-height: 1.58; color: #425a5c; }
|
|
13
|
+
.actions { display: flex; flex-wrap: wrap; align-items: center; gap: 28px; }
|
|
14
|
+
.actions button { border: 0; border-radius: 999px; padding: 15px 20px 15px 24px; color: #f8f5ee; background: #102427; cursor: pointer; display: flex; align-items: center; gap: 18px; }
|
|
15
|
+
.actions button span { min-width: 28px; height: 28px; display: grid; place-items: center; border-radius: 50%; background: #d66a3c; }
|
|
16
|
+
.actions a { color: #102427; text-underline-offset: 5px; }
|
|
17
|
+
.foundation { padding: clamp(80px, 10vw, 144px) clamp(24px, 8vw, 128px); color: #eef2e9; background: #102427; display: grid; grid-template-columns: minmax(250px, .8fr) minmax(420px, 1.2fr); gap: 10vw; }
|
|
18
|
+
.foundation .eyebrow { color: #88a1a0; }
|
|
19
|
+
h2 { font-size: clamp(42px, 5vw, 72px); line-height: 1; }
|
|
20
|
+
.capability-list { border-top: 1px solid rgba(238,242,233,.22); }
|
|
21
|
+
article { display: grid; grid-template-columns: 56px 1fr; gap: 20px; padding: 28px 0; border-bottom: 1px solid rgba(238,242,233,.22); }
|
|
22
|
+
article > span { color: #d66a3c; font: 600 12px/1.4 "Manrope", sans-serif; }
|
|
23
|
+
article h3 { margin: 0 0 8px; font: 600 22px/1.2 "Manrope", sans-serif; }
|
|
24
|
+
article p { margin: 0; max-width: 450px; color: #aebdbc; line-height: 1.55; }
|
|
25
|
+
@media (max-width: 760px) { nav { height: 70px; } .status { font-size: 0; } .hero { min-height: calc(100vh - 70px); padding-top: 80px; } .hero::after { top: 22%; opacity: .6; } .foundation { grid-template-columns: 1fr; gap: 64px; } }
|
|
26
|
+
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { cleanup, fireEvent, render, screen } from "@testing-library/react";
|
|
2
|
+
import { afterEach, describe, expect, it } from "vitest";
|
|
3
|
+
import { App } from "./App.js";
|
|
4
|
+
|
|
5
|
+
afterEach(cleanup);
|
|
6
|
+
|
|
7
|
+
describe("workspace web application", () => {
|
|
8
|
+
it("presents the production foundation", () => {
|
|
9
|
+
render(<App />);
|
|
10
|
+
expect(screen.getByRole("heading", { level: 1, name: /从清晰的起点.*开始创造/ })).toBeVisible();
|
|
11
|
+
expect(screen.getByText("准备就绪")).toBeVisible();
|
|
12
|
+
expect(screen.getAllByRole("article")).toHaveLength(3);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("supports an observable interaction", () => {
|
|
16
|
+
render(<App />);
|
|
17
|
+
const button = screen.getByRole("button", { name: /测试交互 0/ });
|
|
18
|
+
fireEvent.click(button);
|
|
19
|
+
expect(screen.getByRole("button", { name: /测试交互 1/ })).toBeVisible();
|
|
20
|
+
});
|
|
21
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import "./App.css";
|
|
3
|
+
|
|
4
|
+
const capabilities = [
|
|
5
|
+
{ number: "01", title: "开发", detail: "通过专注且快速的 Vite 开发服务器获得即时反馈。" },
|
|
6
|
+
{ number: "02", title: "验证", detail: "类型、组件、生产构建与预览检查已经就绪。" },
|
|
7
|
+
{ number: "03", title: "交付", detail: "优化后的静态产物让部署边界保持清晰。" },
|
|
8
|
+
];
|
|
9
|
+
|
|
10
|
+
export function App() {
|
|
11
|
+
const [count, setCount] = useState(0);
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<main>
|
|
15
|
+
<nav aria-label="应用导航">
|
|
16
|
+
<a className="brand" href="#top" aria-label="工作区 Web 应用首页">
|
|
17
|
+
<span aria-hidden="true" className="brand-mark">D</span>
|
|
18
|
+
<span>工作区 / WEB</span>
|
|
19
|
+
</a>
|
|
20
|
+
<span className="status"><span aria-hidden="true" />准备就绪</span>
|
|
21
|
+
</nav>
|
|
22
|
+
|
|
23
|
+
<section className="hero" id="top">
|
|
24
|
+
<p className="eyebrow">React 19 · Vite 8 · TypeScript 6</p>
|
|
25
|
+
<h1>从清晰的起点<br />开始创造。</h1>
|
|
26
|
+
<p className="intro">这个应用刻意从小处开始:一个明确归属的界面、一条经过验证的生产链路,以及留给产品决策的充足空间。</p>
|
|
27
|
+
<div className="actions">
|
|
28
|
+
<button type="button" onClick={() => setCount((value) => value + 1)}>
|
|
29
|
+
测试交互 <span aria-live="polite">{count}</span>
|
|
30
|
+
</button>
|
|
31
|
+
<a href="#foundation">查看工程基线 <span aria-hidden="true">↓</span></a>
|
|
32
|
+
</div>
|
|
33
|
+
</section>
|
|
34
|
+
|
|
35
|
+
<section className="foundation" id="foundation" aria-labelledby="foundation-title">
|
|
36
|
+
<header>
|
|
37
|
+
<p className="eyebrow">工程基线</p>
|
|
38
|
+
<h2 id="foundation-title">界面保持轻盈,<br />契约足够坚实。</h2>
|
|
39
|
+
</header>
|
|
40
|
+
<div className="capability-list">
|
|
41
|
+
{capabilities.map((capability) => (
|
|
42
|
+
<article key={capability.number}>
|
|
43
|
+
<span>{capability.number}</span>
|
|
44
|
+
<div><h3>{capability.title}</h3><p>{capability.detail}</p></div>
|
|
45
|
+
</article>
|
|
46
|
+
))}
|
|
47
|
+
</div>
|
|
48
|
+
</section>
|
|
49
|
+
</main>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
:root { font-family: Inter, ui-sans-serif, system-ui, sans-serif; color: #102427; background: #f3f0e8; font-synthesis: none; text-rendering: optimizeLegibility; }
|
|
2
|
+
* { box-sizing: border-box; }
|
|
3
|
+
html { scroll-behavior: smooth; }
|
|
4
|
+
body { margin: 0; min-width: 320px; min-height: 100vh; }
|
|
5
|
+
button, a { font: inherit; }
|
|
6
|
+
button:focus-visible, a:focus-visible { outline: 3px solid #ffb648; outline-offset: 4px; }
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { StrictMode } from "react";
|
|
2
|
+
import { createRoot } from "react-dom/client";
|
|
3
|
+
import { App } from "./App.js";
|
|
4
|
+
import "./index.css";
|
|
5
|
+
import { installRuntimeErrorReporter } from "./runtime-error-reporter.js";
|
|
6
|
+
|
|
7
|
+
void installRuntimeErrorReporter();
|
|
8
|
+
|
|
9
|
+
const root = document.getElementById("root");
|
|
10
|
+
if (root === null) throw new Error("Application root is unavailable");
|
|
11
|
+
|
|
12
|
+
createRoot(root).render(
|
|
13
|
+
<StrictMode>
|
|
14
|
+
<App />
|
|
15
|
+
</StrictMode>,
|
|
16
|
+
);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { createRuntimeErrorReporter } from "./runtime-error-reporter.js";
|
|
3
|
+
|
|
4
|
+
describe("runtime error reporter", () => {
|
|
5
|
+
it("sends a normalized event with stable release and deployment context", async () => {
|
|
6
|
+
const fetcher = vi.fn(async () => new Response(null, { status: 202 }));
|
|
7
|
+
const reporter = createRuntimeErrorReporter({ schemaVersion: 1, applicationId: "web", releaseId: `sha256:${"a".repeat(64)}`, deploymentId: `sha256:${"b".repeat(64)}`, collectorEndpoint: "http://127.0.0.1:4318" }, fetcher);
|
|
8
|
+
reporter.report({ kind: "reported-error", error: new Error("验收错误") });
|
|
9
|
+
await vi.waitFor(() => expect(fetcher).toHaveBeenCalledOnce());
|
|
10
|
+
const call = fetcher.mock.calls[0] as unknown as [string, RequestInit];
|
|
11
|
+
expect(JSON.parse(String(call[1].body))).toMatchObject({ applicationId: "web", kind: "reported-error", error: { message: "验收错误" }, page: { origin: "http://localhost:3000", path: "/" } });
|
|
12
|
+
});
|
|
13
|
+
});
|
package/dist/catalog/foundation.workspace-web-application/1.1.0/assets/src/runtime-error-reporter.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export type RuntimeObservabilityConfig = { schemaVersion: 1; applicationId: string; releaseId: `sha256:${string}`; deploymentId: `sha256:${string}`; collectorEndpoint: string };
|
|
2
|
+
type ReportInput = { kind: "uncaught-error" | "unhandled-rejection" | "reported-error"; error: unknown };
|
|
3
|
+
|
|
4
|
+
function normalize(error: unknown) {
|
|
5
|
+
const value = error instanceof Error ? error : new Error(typeof error === "string" ? error : "未知运行时错误");
|
|
6
|
+
const frames = (value.stack ?? "").split("\n").slice(1, 21).flatMap((line) => { const match = line.match(/(?:at\s+(.*?)\s+\()?(.+?):(\d+):(\d+)\)?$/); return match ? [{ file: match[2]!, line: Number(match[3]), column: Number(match[4]), ...(match[1] ? { function: match[1] } : {}) }] : []; });
|
|
7
|
+
return { type: value.name.slice(0, 256), message: value.message.slice(0, 4096), frames };
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function createRuntimeErrorReporter(config: RuntimeObservabilityConfig, fetcher: typeof fetch = fetch) {
|
|
11
|
+
const pending: Array<{ body: string; attempt: number }> = []; let sending = false;
|
|
12
|
+
async function drain() {
|
|
13
|
+
if (sending) return; sending = true;
|
|
14
|
+
while (pending.length > 0) {
|
|
15
|
+
const item = pending[0]!;
|
|
16
|
+
try { const response = await fetcher(`${config.collectorEndpoint}/v1/runtime-errors`, { method: "POST", headers: { "content-type": "application/json" }, body: item.body, keepalive: true }); if (!response.ok) throw new Error("collector rejected event"); pending.shift(); }
|
|
17
|
+
catch { item.attempt += 1; if (item.attempt > 3) pending.shift(); else await new Promise((resolve) => setTimeout(resolve, 100 * 2 ** item.attempt)); }
|
|
18
|
+
}
|
|
19
|
+
sending = false;
|
|
20
|
+
}
|
|
21
|
+
function report(input: ReportInput) {
|
|
22
|
+
const body = JSON.stringify({ schemaVersion: 1, eventId: crypto.randomUUID(), occurredAt: new Date().toISOString(), applicationId: config.applicationId, releaseId: config.releaseId, deploymentId: config.deploymentId, kind: input.kind, error: normalize(input.error), page: { origin: location.origin, path: location.pathname } });
|
|
23
|
+
if (pending.length === 20) pending.shift(); pending.push({ body, attempt: 0 }); void drain();
|
|
24
|
+
}
|
|
25
|
+
return { report, install() { addEventListener("error", (event) => report({ kind: "uncaught-error", error: event.error ?? event.message })); addEventListener("unhandledrejection", (event) => report({ kind: "unhandled-rejection", error: event.reason })); } };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export async function installRuntimeErrorReporter(): Promise<ReturnType<typeof createRuntimeErrorReporter> | null> {
|
|
29
|
+
try { const response = await fetch("/dyyto-runtime-config.json", { cache: "no-store" }); if (!response.ok) return null; const config = await response.json() as RuntimeObservabilityConfig; if (config.schemaVersion !== 1) return null; const reporter = createRuntimeErrorReporter(config); reporter.install(); return reporter; } catch { return null; }
|
|
30
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "@testing-library/jest-dom/vitest";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"tsBuildInfoFile": "./node_modules/.cache/tsconfig.app.tsbuildinfo",
|
|
5
|
+
"target": "ES2023",
|
|
6
|
+
"lib": ["ES2023", "DOM", "DOM.Iterable"],
|
|
7
|
+
"module": "ESNext",
|
|
8
|
+
"moduleResolution": "Bundler",
|
|
9
|
+
"allowImportingTsExtensions": true,
|
|
10
|
+
"verbatimModuleSyntax": true,
|
|
11
|
+
"moduleDetection": "force",
|
|
12
|
+
"noEmit": true,
|
|
13
|
+
"jsx": "react-jsx",
|
|
14
|
+
"types": ["vite/client", "vitest/globals", "@testing-library/jest-dom"]
|
|
15
|
+
},
|
|
16
|
+
"include": ["src"]
|
|
17
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"tsBuildInfoFile": "./node_modules/.cache/tsconfig.node.tsbuildinfo",
|
|
5
|
+
"target": "ES2023",
|
|
6
|
+
"lib": ["ES2023"],
|
|
7
|
+
"module": "ESNext",
|
|
8
|
+
"moduleResolution": "Bundler",
|
|
9
|
+
"allowImportingTsExtensions": true,
|
|
10
|
+
"verbatimModuleSyntax": true,
|
|
11
|
+
"moduleDetection": "force",
|
|
12
|
+
"noEmit": true,
|
|
13
|
+
"types": ["node"]
|
|
14
|
+
},
|
|
15
|
+
"include": ["vite.config.ts"]
|
|
16
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import react from "@vitejs/plugin-react";
|
|
2
|
+
import { defineConfig } from "vitest/config";
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
plugins: [react()],
|
|
6
|
+
build: { sourcemap: "hidden" },
|
|
7
|
+
test: {
|
|
8
|
+
environment: "jsdom",
|
|
9
|
+
setupFiles: "./src/test/setup.ts",
|
|
10
|
+
},
|
|
11
|
+
});
|