🎉 feat: 建立阶段 0 工程骨架与 OpenAPI 契约机器化(WP-01 起步)

- Makefile:统一命令入口(backend/engine/docker/openapi/generate,含 make help)
- backend:FastAPI + uv 最小工程,统一错误体(契约第 7 节)、ADR-015 平台 ID 生成与校验(uuid-utils);pytest 7 项、ruff、mypy strict、启动冒烟全部通过
- engine:灵台引擎 C++23/CMake 骨架,按 Lingtai C ABI 契约实现 lingtai.h(13 个 HjStatus、版本协商、句柄表防二次释放、线程局部错误上下文);doctest 5 用例通过,nm 验证仅导出 hj_* 符号
- openapi:OpenAPI 3.1 单一真源初始版(错误体/分页/Money/首批平台 ID/ContentBlock 全 21 类型/流事件 envelope),Redocly lint 0 错误、bundle 通过
- frontend:Next.js 最小骨架,openapi-typescript 生成 API 类型并通过 strict tsc
- docker:hunjing-postgres(pgvector:17)compose;.env.example 与 config 示例
- ADR-025:登记测试与契约工具链(doctest/libFuzzer/Redocly/openapi-typescript/uuid-utils)
- desktop:Tauri v2 占位与初始化说明(WP-10 启动)
This commit is contained in:
chenxin committed 2026-09-09 21:45:04 +08:00
1 parent 5da1efe921
commit 3fbcd0437c
32 files changed
+11459

No files matched your search

+7
View File
@@ -0,0 +1,7 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
reactStrictMode: true,
};
export default nextConfig;
+1421
View File
File diff suppressed because it is too large. Load diff
+22
View File
@@ -0,0 +1,22 @@
{
"name": "hunjing-frontend",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"generate:api": "openapi-typescript ../openapi/openapi.yaml -o src/types/api.d.ts"
},
"dependencies": {
"next": "^15.1.0",
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"devDependencies": {
"@types/node": "^22.10.0",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"openapi-typescript": "^7.5.0",
"typescript": "^5.7.0"
}
}
+14
View File
@@ -0,0 +1,14 @@
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "魂镜 Hunjing",
description: "长期 AI 角色、Agent 与创作社区平台",
};
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="zh-CN">
<body>{children}</body>
</html>
);
}
+8
View File
@@ -0,0 +1,8 @@
export default function Home() {
return (
<main style={{ padding: "2rem", fontFamily: "system-ui, sans-serif" }}>
<h1>魂镜 Hunjing</h1>
<p>工程骨架已建立;界面随 WP-03/WP-10 工作包实现。</p>
</main>
);
}
+440
View File
@@ -0,0 +1,440 @@
/**
* This file was auto-generated by openapi-typescript.
* Do not make direct changes to the file.
*/
export interface paths {
"/healthz": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/** 服务健康探针 */
get: operations["getHealth"];
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
}
export type webhooks = Record<string, never>;
export interface components {
schemas: {
Error: {
/**
* @description 稳定机器错误码
* @example validation_failed
*/
code: string;
/** @description 可本地化消息 */
message: string;
/** Format: uuid */
trace_id?: string;
request_id?: string;
/** @description 不稳定细节,必须脱敏 */
details?: {
[key: string]: unknown;
};
};
ErrorEnvelope: {
error: components["schemas"]["Error"];
};
CursorPage: {
data: unknown[];
/** @description opaque cursor;客户端不得解析 */
next_cursor: string | null;
has_more: boolean;
};
Money: {
amount_minor: number;
currency: string;
};
UserId: string;
PersonalDomainId: string;
ConversationId: string;
BranchId: string;
MessageId: string;
ContentBlockId: string;
RunId: string;
TurnId: string;
/** @description 服务端生成,UUIDv4 */
RequestId: string;
/** @enum {string} */
BlockStatus: "pending" | "streaming" | "completed" | "failed" | "cancelled";
/** @description 类型化标注(citation/来源/敏感度/语言) */
BlockAnnotation: {
[key: string]: unknown;
};
BlockBase: {
id: components["schemas"]["ContentBlockId"];
status?: components["schemas"]["BlockStatus"];
annotations?: components["schemas"]["BlockAnnotation"][];
/** @description 只允许 Schema 登记字段,不存任意秘密 */
metadata?: {
[key: string]: unknown;
};
};
TextBlock: components["schemas"]["BlockBase"] & {
/** @enum {string} */
type?: "text";
text: string;
language?: string;
} & {
/**
* @description discriminator enum property added by openapi-typescript
* @enum {string}
*/
type: "TextBlock";
};
MarkdownBlock: components["schemas"]["BlockBase"] & {
/** @enum {string} */
type?: "markdown";
text: string;
/** @enum {string} */
flavor?: "hunjing-gfm-v1";
} & {
/**
* @description discriminator enum property added by openapi-typescript
* @enum {string}
*/
type: "MarkdownBlock";
};
CodeBlock: components["schemas"]["BlockBase"] & {
/** @enum {string} */
type?: "code";
source: string;
language?: string;
filename?: string;
} & {
/**
* @description discriminator enum property added by openapi-typescript
* @enum {string}
*/
type: "CodeBlock";
};
QuoteBlock: components["schemas"]["BlockBase"] & {
/** @enum {string} */
type?: "quote";
content: components["schemas"]["ContentBlock"][];
source_ref?: string;
} & {
/**
* @description discriminator enum property added by openapi-typescript
* @enum {string}
*/
type: "QuoteBlock";
};
TableBlock: components["schemas"]["BlockBase"] & {
/** @enum {string} */
type?: "table";
columns: string[];
rows: unknown[][];
caption?: string;
} & {
/**
* @description discriminator enum property added by openapi-typescript
* @enum {string}
*/
type: "TableBlock";
};
CalloutBlock: components["schemas"]["BlockBase"] & {
/** @enum {string} */
type?: "callout";
/** @enum {string} */
kind: "info" | "warning" | "danger" | "success";
title?: string;
content: components["schemas"]["ContentBlock"][];
} & {
/**
* @description discriminator enum property added by openapi-typescript
* @enum {string}
*/
type: "CalloutBlock";
};
MathBlock: components["schemas"]["BlockBase"] & {
/** @enum {string} */
type?: "math";
/** @enum {string} */
notation: "latex" | "asciimath";
/** @enum {string} */
display: "inline" | "block";
source: string;
/** @description 可访问性与解析失败降级描述 */
fallback_text?: string;
label?: string;
} & {
/**
* @description discriminator enum property added by openapi-typescript
* @enum {string}
*/
type: "MathBlock";
};
MermaidBlock: components["schemas"]["BlockBase"] & {
/** @enum {string} */
type?: "mermaid";
source: string;
title?: string;
caption?: string;
/** @default mermaid */
fallback_code_language: string;
} & {
/**
* @description discriminator enum property added by openapi-typescript
* @enum {string}
*/
type: "MermaidBlock";
};
ImageBlock: components["schemas"]["BlockBase"] & {
/** @enum {string} */
type?: "image";
file_id?: string;
/** @description 受控 URL;禁止 file://、javascript: 等协议 */
url_ref?: string;
alt: string;
width?: number;
height?: number;
caption?: string;
} & {
/**
* @description discriminator enum property added by openapi-typescript
* @enum {string}
*/
type: "ImageBlock";
};
VideoBlock: components["schemas"]["BlockBase"] & {
/** @enum {string} */
type?: "video";
file_id: string;
poster_file_id?: string;
caption?: string;
transcript_file_id?: string;
duration_ms?: number;
} & {
/**
* @description discriminator enum property added by openapi-typescript
* @enum {string}
*/
type: "VideoBlock";
};
AudioBlock: components["schemas"]["BlockBase"] & {
/** @enum {string} */
type?: "audio";
file_id: string;
transcript?: string;
duration_ms?: number;
waveform?: string;
} & {
/**
* @description discriminator enum property added by openapi-typescript
* @enum {string}
*/
type: "AudioBlock";
};
FileBlock: components["schemas"]["BlockBase"] & {
/** @enum {string} */
type?: "file";
file_id: string;
filename: string;
media_type: string;
size_bytes: number;
description?: string;
} & {
/**
* @description discriminator enum property added by openapi-typescript
* @enum {string}
*/
type: "FileBlock";
};
GalleryBlock: components["schemas"]["BlockBase"] & {
/** @enum {string} */
type?: "gallery";
items: (components["schemas"]["ImageBlock"] | components["schemas"]["VideoBlock"])[];
layout?: string;
} & {
/**
* @description discriminator enum property added by openapi-typescript
* @enum {string}
*/
type: "GalleryBlock";
};
AvatarBlock: components["schemas"]["BlockBase"] & {
/** @enum {string} */
type?: "avatar";
asset_id: string;
/** @enum {string} */
format: "live2d" | "vrm" | "gltf";
preview_file_id?: string;
} & {
/**
* @description discriminator enum property added by openapi-typescript
* @enum {string}
*/
type: "AvatarBlock";
};
ToolCallBlock: components["schemas"]["BlockBase"] & {
/** @enum {string} */
type?: "tool_call";
tool_name: string;
call_id: string;
/** @description 参数脱敏视图 */
arguments_redacted?: Record<string, never>;
approval_id?: string;
} & {
/**
* @description discriminator enum property added by openapi-typescript
* @enum {string}
*/
type: "ToolCallBlock";
};
ToolResultBlock: components["schemas"]["BlockBase"] & {
/** @enum {string} */
type?: "tool_result";
call_id: string;
summary?: {
[key: string]: unknown;
};
file_ids?: string[];
is_error?: boolean;
} & {
/**
* @description discriminator enum property added by openapi-typescript
* @enum {string}
*/
type: "ToolResultBlock";
};
AgentStatusBlock: components["schemas"]["BlockBase"] & {
/** @enum {string} */
type?: "agent_status";
agent_id?: string;
child_run_id?: string;
stage: string;
progress?: {
[key: string]: unknown;
};
waiting_reason?: string;
} & {
/**
* @description discriminator enum property added by openapi-typescript
* @enum {string}
*/
type: "AgentStatusBlock";
};
ApprovalRequestBlock: components["schemas"]["BlockBase"] & {
/** @enum {string} */
type?: "approval_request";
approval_id: string;
action: string;
impact?: string;
arguments_summary?: {
[key: string]: unknown;
};
/** Format: date-time */
expires_at?: string;
} & {
/**
* @description discriminator enum property added by openapi-typescript
* @enum {string}
*/
type: "ApprovalRequestBlock";
};
ArtifactBlock: components["schemas"]["BlockBase"] & {
/** @enum {string} */
type?: "artifact";
artifact_id: string;
artifact_type: string;
version?: number;
} & {
/**
* @description discriminator enum property added by openapi-typescript
* @enum {string}
*/
type: "ArtifactBlock";
};
CitationBlock: components["schemas"]["BlockBase"] & {
/** @enum {string} */
type?: "citation";
source_id: string;
title: string;
quoted_text: string;
/** @description 定位(文本区间、图像区域、PDF 页区、音视频时间码)与原文快照 */
locator?: {
[key: string]: unknown;
};
} & {
/**
* @description discriminator enum property added by openapi-typescript
* @enum {string}
*/
type: "CitationBlock";
};
ErrorBlock: components["schemas"]["BlockBase"] & {
/** @enum {string} */
type?: "error";
message: string;
retryable?: boolean;
fallback?: string;
} & {
/**
* @description discriminator enum property added by openapi-typescript
* @enum {string}
*/
type: "ErrorBlock";
};
ContentBlock: components["schemas"]["TextBlock"] | components["schemas"]["MarkdownBlock"] | components["schemas"]["CodeBlock"] | components["schemas"]["QuoteBlock"] | components["schemas"]["TableBlock"] | components["schemas"]["CalloutBlock"] | components["schemas"]["MathBlock"] | components["schemas"]["MermaidBlock"] | components["schemas"]["ImageBlock"] | components["schemas"]["VideoBlock"] | components["schemas"]["AudioBlock"] | components["schemas"]["FileBlock"] | components["schemas"]["GalleryBlock"] | components["schemas"]["AvatarBlock"] | components["schemas"]["ToolCallBlock"] | components["schemas"]["ToolResultBlock"] | components["schemas"]["AgentStatusBlock"] | components["schemas"]["ApprovalRequestBlock"] | components["schemas"]["ArtifactBlock"] | components["schemas"]["CitationBlock"] | components["schemas"]["ErrorBlock"];
StreamEvent: {
/** @enum {string} */
type: "content.block.started" | "content.block.delta" | "content.block.progress" | "content.block.completed" | "content.block.failed" | "content.block.cancelled" | "message.completed";
data: {
[key: string]: unknown;
};
/** @description Run 内单调递增 */
sequence?: number;
};
};
responses: never;
parameters: never;
requestBodies: never;
headers: never;
pathItems: never;
}
export type $defs = Record<string, never>;
export interface operations {
getHealth: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description 服务正常 */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": {
/** @enum {string} */
status: "ok";
env?: string;
};
};
};
/** @description 错误 */
default: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ErrorEnvelope"];
};
};
};
};
}
+21
View File
@@ -0,0 +1,21 @@
{
"compilerOptions": {
"target": "ES2022",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": false,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [{ "name": "next" }],
"paths": { "@/*": ["./src/*"] }
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}