ai-spec-dev 0.1.0 → 0.14.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 (60) hide show
  1. package/.claude/settings.local.json +18 -0
  2. package/README.md +1211 -146
  3. package/RELEASE_LOG.md +1444 -0
  4. package/cli/index.ts +1961 -0
  5. package/cli/welcome.ts +151 -0
  6. package/core/code-generator.ts +740 -0
  7. package/core/combined-generator.ts +63 -0
  8. package/core/constitution-consolidator.ts +141 -0
  9. package/core/constitution-generator.ts +89 -0
  10. package/core/context-loader.ts +453 -0
  11. package/core/contract-bridge.ts +217 -0
  12. package/core/dsl-extractor.ts +337 -0
  13. package/core/dsl-types.ts +166 -0
  14. package/core/dsl-validator.ts +450 -0
  15. package/core/error-feedback.ts +354 -0
  16. package/core/frontend-context-loader.ts +602 -0
  17. package/core/global-constitution.ts +88 -0
  18. package/core/key-store.ts +49 -0
  19. package/core/knowledge-memory.ts +171 -0
  20. package/core/mock-server-generator.ts +571 -0
  21. package/core/openapi-exporter.ts +361 -0
  22. package/core/requirement-decomposer.ts +198 -0
  23. package/core/reviewer.ts +259 -0
  24. package/core/spec-assessor.ts +99 -0
  25. package/core/spec-generator.ts +428 -0
  26. package/core/spec-refiner.ts +89 -0
  27. package/core/spec-updater.ts +227 -0
  28. package/core/spec-versioning.ts +213 -0
  29. package/core/task-generator.ts +174 -0
  30. package/core/test-generator.ts +273 -0
  31. package/core/workspace-loader.ts +256 -0
  32. package/dist/cli/index.js +6717 -672
  33. package/dist/cli/index.js.map +1 -1
  34. package/dist/cli/index.mjs +6717 -670
  35. package/dist/cli/index.mjs.map +1 -1
  36. package/dist/index.d.mts +147 -27
  37. package/dist/index.d.ts +147 -27
  38. package/dist/index.js +2337 -286
  39. package/dist/index.js.map +1 -1
  40. package/dist/index.mjs +2329 -285
  41. package/dist/index.mjs.map +1 -1
  42. package/git/worktree.ts +109 -0
  43. package/index.ts +9 -0
  44. package/package.json +4 -28
  45. package/prompts/codegen.prompt.ts +259 -0
  46. package/prompts/consolidate.prompt.ts +73 -0
  47. package/prompts/constitution.prompt.ts +63 -0
  48. package/prompts/decompose.prompt.ts +168 -0
  49. package/prompts/dsl.prompt.ts +203 -0
  50. package/prompts/frontend-spec.prompt.ts +191 -0
  51. package/prompts/global-constitution.prompt.ts +61 -0
  52. package/prompts/spec-assess.prompt.ts +53 -0
  53. package/prompts/spec.prompt.ts +102 -0
  54. package/prompts/tasks.prompt.ts +35 -0
  55. package/prompts/testgen.prompt.ts +84 -0
  56. package/prompts/update.prompt.ts +131 -0
  57. package/purpose.docx +0 -0
  58. package/purpose.md +444 -0
  59. package/tsconfig.json +14 -0
  60. package/tsup.config.ts +10 -0
@@ -0,0 +1,168 @@
1
+ import { WorkspaceConfig } from "../core/workspace-loader";
2
+ import { ProjectContext } from "../core/context-loader";
3
+ import { FrontendContext } from "../core/frontend-context-loader";
4
+
5
+ /**
6
+ * System prompt for multi-repo requirement decomposition.
7
+ *
8
+ * Key design goals:
9
+ * 1. Force the AI to be concrete about backend API contracts (exact paths, methods, payloads).
10
+ * 2. Force concrete UX decisions for frontend repos (throttle vs debounce, optimistic updates).
11
+ * 3. Identify cross-repo dependencies so we can process repos in the right order.
12
+ * 4. Output valid JSON matching DecompositionResult exactly.
13
+ */
14
+ export const decomposeSystemPrompt = `You are a senior full-stack architect specializing in multi-repo feature decomposition.
15
+
16
+ Your task: Given a high-level user requirement and a workspace containing multiple repos, decompose the requirement into specific, actionable per-repo specifications with concrete technical decisions.
17
+
18
+ CRITICAL RULES:
19
+ 1. Output ONLY valid JSON — no markdown fences, no prose before or after.
20
+ 2. Be CONCRETE and SPECIFIC. Not vague descriptions but precise technical specs:
21
+ - Backend: exact HTTP method, URL path, request body schema, response shape, error codes.
22
+ - Frontend: exact UX pattern (throttle 300ms vs debounce 500ms), whether optimistic update is needed.
23
+ 3. Only include repos that ACTUALLY need changes for this requirement. Exclude repos that don't need to change.
24
+ 4. Set isContractProvider=true for backend repos whose API the frontend will consume.
25
+ 5. Set dependsOnRepos to specify processing order — frontend repos that consume a backend API must list the backend repo name.
26
+ 6. For uxDecisions: use throttle for actions (button clicks, form submits), debounce for inputs (search, filter). Be specific about ms values.
27
+ 7. coordinationNotes should explain cross-repo concerns: shared types, state synchronization, when NOT to re-fetch (use response data directly).
28
+
29
+ UX DECISION GUIDE:
30
+ - Throttle (throttleMs): Use for user actions like button clicks. Prevents rapid duplicate submissions. Typical: 300ms.
31
+ - Debounce (debounceMs): Use for user inputs like search. Waits until user stops typing. Typical: 500ms.
32
+ - Optimistic Update: Update UI before server responds, rollback on error. Use for low-risk toggle operations (like/unlike, follow/unfollow).
33
+ - reloadOnSuccess: List endpoints to re-fetch after success. Leave empty [] if the response already contains updated data.
34
+ - loadingState: Almost always true — show a spinner or disable button during request.
35
+
36
+ OUTPUT FORMAT (follow exactly):
37
+ {
38
+ "summary": "<1-2 sentences: what the requirement is and how it's split across repos>",
39
+ "coordinationNotes": "<cross-repo concerns: shared types, state sync, API contract points>",
40
+ "repos": [
41
+ {
42
+ "repoName": "<exact repo name from workspace config>",
43
+ "role": "<backend|frontend|mobile|shared>",
44
+ "specIdea": "<detailed per-repo requirement: for backend include exact API paths/methods/payloads; for frontend include UX pattern and which API to call>",
45
+ "isContractProvider": true,
46
+ "dependsOnRepos": [],
47
+ "uxDecisions": null
48
+ },
49
+ {
50
+ "repoName": "<frontend repo name>",
51
+ "role": "frontend",
52
+ "specIdea": "<detailed frontend spec including component name, state management approach, which API endpoint to call, and UX behavior>",
53
+ "isContractProvider": false,
54
+ "dependsOnRepos": ["<backend repo name>"],
55
+ "uxDecisions": {
56
+ "throttleMs": 300,
57
+ "optimisticUpdate": true,
58
+ "reloadOnSuccess": [],
59
+ "errorRollback": true,
60
+ "loadingState": true,
61
+ "notes": "<explain WHY this UX pattern was chosen — technical reasoning>"
62
+ }
63
+ }
64
+ ]
65
+ }
66
+
67
+ EXAMPLE (for a "like feature" on a blog platform with repos: "api" (Express) and "web" (React)):
68
+ {
69
+ "summary": "点赞功能需要后端新增 toggle like 接口,前端实现带乐观更新的点赞按钮",
70
+ "coordinationNotes": "前端应在乐观更新后通过 likeCount 字段更新展示,不需要重新拉取详情接口。注意后端返回 liked 布尔值标识当前状态。",
71
+ "repos": [
72
+ {
73
+ "repoName": "api",
74
+ "role": "backend",
75
+ "specIdea": "新增 POST /api/v1/posts/:postId/like 接口,toggle 语义(已点赞则取消),需要认证,返回 { liked: boolean, likeCount: number }。数据库新增 post_likes 表,字段 userId + postId,唯一约束防重复。",
76
+ "isContractProvider": true,
77
+ "dependsOnRepos": [],
78
+ "uxDecisions": null
79
+ },
80
+ {
81
+ "repoName": "web",
82
+ "role": "frontend",
83
+ "specIdea": "点赞按钮组件 LikeButton,调用 POST /api/v1/posts/:postId/like,乐观更新本地 liked 状态和 likeCount,300ms throttle 防止重复点击,错误时回滚状态并提示。",
84
+ "isContractProvider": false,
85
+ "dependsOnRepos": ["api"],
86
+ "uxDecisions": {
87
+ "throttleMs": 300,
88
+ "optimisticUpdate": true,
89
+ "reloadOnSuccess": [],
90
+ "errorRollback": true,
91
+ "loadingState": true,
92
+ "notes": "点赞是高频离散操作,throttle 比 debounce 更合适(用户期望立即响应而非等待停止)。乐观更新后端接口返回 likeCount,直接更新本地状态,无需重新拉取帖子详情。"
93
+ }
94
+ }
95
+ ]
96
+ }`;
97
+
98
+ /**
99
+ * Build the user-turn prompt for decomposition.
100
+ * @param frontendContexts Optional map of repoName → FrontendContext for richer UX decisions.
101
+ */
102
+ export function buildDecomposePrompt(
103
+ requirement: string,
104
+ workspace: WorkspaceConfig,
105
+ contexts: Map<string, ProjectContext>,
106
+ frontendContexts?: Map<string, FrontendContext>
107
+ ): string {
108
+ const parts: string[] = [
109
+ `Workspace: ${workspace.name}`,
110
+ "",
111
+ "Repos in this workspace:",
112
+ ];
113
+
114
+ for (const repo of workspace.repos) {
115
+ const ctx = contexts.get(repo.name);
116
+ const stack = ctx?.techStack?.join(", ") || "unknown";
117
+ const depsCount = ctx?.dependencies?.length ?? 0;
118
+
119
+ parts.push(` - ${repo.name}: type=${repo.type}, role=${repo.role}, path=${repo.path}`);
120
+ parts.push(` Tech stack: ${stack} | ${depsCount} dependencies`);
121
+
122
+ if (ctx?.apiStructure && ctx.apiStructure.length > 0) {
123
+ parts.push(` API files: ${ctx.apiStructure.slice(0, 5).join(", ")}`);
124
+ }
125
+ if (repo.constitution) {
126
+ const preview = repo.constitution.split("\n").slice(0, 5).join("\n");
127
+ parts.push(` Constitution preview: ${preview}`);
128
+ }
129
+
130
+ // Inject frontend-specific context so AI can make grounded UX decisions
131
+ const fctx = frontendContexts?.get(repo.name);
132
+ if (fctx && (repo.role === "frontend" || repo.role === "mobile")) {
133
+ parts.push(` Frontend context:`);
134
+ parts.push(` Framework: ${fctx.framework} | Test: ${fctx.testFramework} | HTTP: ${fctx.httpClient}`);
135
+ parts.push(` State mgmt: ${fctx.stateManagement.join(", ") || "none"}`);
136
+
137
+ if (fctx.hookFiles.length > 0) {
138
+ parts.push(` Existing hooks (${fctx.hookFiles.length}) — reference these in specIdea:`);
139
+ fctx.hookFiles.slice(0, 6).forEach((f) => parts.push(` - ${f}`));
140
+ }
141
+ if (fctx.existingApiFiles.length > 0) {
142
+ parts.push(` Existing API wrappers — MUST extend, NOT recreate:`);
143
+ fctx.existingApiFiles.slice(0, 5).forEach((f) => parts.push(` - ${f}`));
144
+ }
145
+ if (fctx.storeFiles.length > 0) {
146
+ parts.push(` Store files (${fctx.storeFiles.length}) — add state here, don't create new stores:`);
147
+ fctx.storeFiles.slice(0, 4).forEach((f) => parts.push(` - ${f}`));
148
+ }
149
+ // Show API wrapper content snippet so AI knows the call pattern
150
+ if (fctx.apiWrapperContent.length > 0) {
151
+ parts.push(` API call pattern (existing):`);
152
+ const snippet = fctx.apiWrapperContent[0].split("\n").slice(0, 10).join("\n");
153
+ parts.push(` ${snippet.replace(/\n/g, "\n ")}`);
154
+ }
155
+ }
156
+ }
157
+
158
+ parts.push("");
159
+ parts.push(`User requirement: ${requirement}`);
160
+ parts.push("");
161
+ parts.push(
162
+ "Decompose this requirement into per-repo specs with concrete technical decisions.",
163
+ "For frontend repos: reference the existing hook/store/API files listed above — tell the AI to extend them, not create new ones.",
164
+ "Output ONLY valid JSON."
165
+ );
166
+
167
+ return parts.join("\n");
168
+ }
@@ -0,0 +1,203 @@
1
+ /**
2
+ * System prompt for DSL extraction.
3
+ *
4
+ * Key anti-hallucination rules enforced in this prompt:
5
+ * 1. Extract ONLY what is explicitly stated — no inference.
6
+ * 2. Empty arrays are correct and preferred over invented entries.
7
+ * 3. Exact JSON schema with field types and constraints provided.
8
+ * 4. Concrete example included so model has a reference to match.
9
+ * 5. Output ONLY JSON — no prose, no markdown fences.
10
+ */
11
+ export const dslSystemPrompt = `You are a precise structured-data extractor. Your job is to convert a Feature Spec (written in any language) into a strictly-typed JSON DSL.
12
+
13
+ CRITICAL RULES — read carefully before outputting:
14
+ 1. EXTRACT ONLY what is EXPLICITLY written in the spec. Do NOT infer, assume, or complete anything not stated.
15
+ 2. If the spec does not mention data models, output "models": [].
16
+ 3. If the spec does not mention endpoints, output "endpoints": [].
17
+ 4. If the spec does not mention non-CRUD business behaviors, output "behaviors": [].
18
+ 5. Output ONLY valid JSON. No markdown fences, no explanation, no prose before or after.
19
+ 6. Every required field must be present. If a value cannot be extracted, use an empty string "" — never omit the field.
20
+ 7. "path" values must start with "/". Method must be one of: GET POST PUT PATCH DELETE.
21
+ 8. successStatus must be an integer (e.g. 200, 201). auth must be true or false (boolean, not string).
22
+ 9. FieldMap values must be type-description strings (e.g. "string", "number", "string (email format)") — NOT nested objects.
23
+
24
+ OUTPUT FORMAT (follow exactly):
25
+ {
26
+ "version": "1.0",
27
+ "feature": {
28
+ "id": "<slug — lowercase, hyphens only, e.g. user-login>",
29
+ "title": "<verbatim title from spec>",
30
+ "description": "<one paragraph summary>"
31
+ },
32
+ "models": [
33
+ {
34
+ "name": "<PascalCase model name>",
35
+ "description": "<optional one-line description>",
36
+ "fields": [
37
+ {
38
+ "name": "<camelCase field name>",
39
+ "type": "<String|Int|Float|Boolean|DateTime|Json|ModelName>",
40
+ "required": true,
41
+ "unique": false,
42
+ "description": "<optional>"
43
+ }
44
+ ],
45
+ "relations": ["<plain-text relation, e.g. belongs to User via userId>"]
46
+ }
47
+ ],
48
+ "endpoints": [
49
+ {
50
+ "id": "EP-001",
51
+ "method": "POST",
52
+ "path": "/api/v1/...",
53
+ "description": "<what this endpoint does>",
54
+ "auth": false,
55
+ "request": {
56
+ "body": { "fieldName": "type description" },
57
+ "query": { "fieldName": "type description" },
58
+ "params": { "fieldName": "type description" }
59
+ },
60
+ "successStatus": 200,
61
+ "successDescription": "<what the success response contains>",
62
+ "errors": [
63
+ { "status": 401, "code": "ERROR_CODE", "description": "<when this error occurs>" }
64
+ ]
65
+ }
66
+ ],
67
+ "behaviors": [
68
+ {
69
+ "id": "BHV-001",
70
+ "description": "<what happens>",
71
+ "trigger": "<what event triggers this>",
72
+ "constraints": ["<rule 1>", "<rule 2>"]
73
+ }
74
+ ]
75
+ }
76
+
77
+ EXAMPLE (for reference only — your output must reflect the actual spec, not this example):
78
+ Input spec mentions: "POST /api/v1/auth/login — accepts email+password, returns JWT. 401 if wrong credentials. Rate limited: 5 failures lock account for 30 min."
79
+ Correct output:
80
+ {
81
+ "version": "1.0",
82
+ "feature": { "id": "user-login", "title": "用户登录", "description": "用户通过邮箱和密码登录,获取 JWT token。" },
83
+ "models": [],
84
+ "endpoints": [
85
+ {
86
+ "id": "EP-001",
87
+ "method": "POST",
88
+ "path": "/api/v1/auth/login",
89
+ "description": "用户登录,返回 JWT token",
90
+ "auth": false,
91
+ "request": { "body": { "email": "string (email format)", "password": "string (min 8 chars)" } },
92
+ "successStatus": 200,
93
+ "successDescription": "返回 JWT access token 和过期时间",
94
+ "errors": [
95
+ { "status": 401, "code": "INVALID_CREDENTIALS", "description": "邮箱或密码错误" },
96
+ { "status": 429, "code": "ACCOUNT_LOCKED", "description": "连续失败超过 5 次,账号锁定 30 分钟" }
97
+ ]
98
+ }
99
+ ],
100
+ "behaviors": [
101
+ {
102
+ "id": "BHV-001",
103
+ "description": "连续登录失败超过 5 次后锁定账号",
104
+ "trigger": "登录接口返回 401",
105
+ "constraints": ["失败计数存储在 Redis", "锁定时间 30 分钟", "解锁后计数重置"]
106
+ }
107
+ ]
108
+ }`;
109
+
110
+ /**
111
+ * System prompt for frontend DSL extraction.
112
+ * Extends the backend prompt with ComponentSpec support.
113
+ */
114
+ export const dslFrontendSystemPrompt = `You are a precise structured-data extractor. Your job is to convert a Feature Spec (written in any language) into a strictly-typed JSON DSL for a FRONTEND project.
115
+
116
+ CRITICAL RULES:
117
+ 1. EXTRACT ONLY what is EXPLICITLY written in the spec. Do NOT infer or complete anything not stated.
118
+ 2. Output ONLY valid JSON. No markdown fences, no explanation.
119
+ 3. Every required field must be present. If a value cannot be extracted, use an empty string "" — never omit.
120
+ 4. "endpoints" should list the API calls this frontend feature makes to the backend (not backend implementation).
121
+ 5. "components" is the most important section for frontend. List every named UI component in the spec.
122
+ 6. "models" should be empty [] for pure frontend features — use "components" instead.
123
+ 7. ComponentProp.type and ComponentEvent.payload must be plain type strings, not nested objects.
124
+
125
+ OUTPUT FORMAT (follow exactly):
126
+ {
127
+ "version": "1.0",
128
+ "feature": {
129
+ "id": "<slug>",
130
+ "title": "<verbatim title>",
131
+ "description": "<one paragraph>"
132
+ },
133
+ "models": [],
134
+ "endpoints": [
135
+ {
136
+ "id": "EP-001",
137
+ "method": "POST",
138
+ "path": "/api/v1/...",
139
+ "description": "<what the frontend calls this for>",
140
+ "auth": true,
141
+ "request": { "body": { "fieldName": "type description" } },
142
+ "successStatus": 200,
143
+ "successDescription": "<what the response contains>",
144
+ "errors": [{ "status": 401, "code": "UNAUTHORIZED", "description": "Not logged in" }]
145
+ }
146
+ ],
147
+ "behaviors": [],
148
+ "components": [
149
+ {
150
+ "id": "CMP-001",
151
+ "name": "<PascalCase component name>",
152
+ "description": "<what this component does>",
153
+ "props": [
154
+ { "name": "<propName>", "type": "<TypeScript type>", "required": true, "description": "<optional>" }
155
+ ],
156
+ "events": [
157
+ { "name": "<onEventName>", "payload": "<payload type or empty string>" }
158
+ ],
159
+ "state": {
160
+ "<stateName>": "<TypeScript type>"
161
+ },
162
+ "apiCalls": ["<endpoint id or path that this component calls>"]
163
+ }
164
+ ]
165
+ }`;
166
+
167
+ /**
168
+ * Build the user-turn prompt for DSL extraction.
169
+ * Keeps it minimal — the spec content is all the model needs.
170
+ */
171
+ export function buildDslExtractionPrompt(specContent: string, isFrontend = false): string {
172
+ const hint = isFrontend
173
+ ? "This is a FRONTEND feature spec. Focus on extracting components[] — each named UI component with its props, events, state, and API calls. Output ONLY valid JSON.\n\n"
174
+ : "Extract the DSL from the following Feature Spec. Output ONLY valid JSON.\n\n";
175
+ return hint + specContent;
176
+ }
177
+
178
+ /**
179
+ * Build the retry prompt when the previous attempt produced invalid output.
180
+ * Includes the specific validation errors so the model can fix them.
181
+ */
182
+ export function buildDslRetryPrompt(
183
+ specContent: string,
184
+ previousOutput: string,
185
+ validationErrors: Array<{ path: string; message: string }>
186
+ ): string {
187
+ const errorLines = validationErrors
188
+ .map((e) => ` - ${e.path}: ${e.message}`)
189
+ .join("\n");
190
+
191
+ return `Your previous DSL output had validation errors. Fix them and output corrected JSON only.
192
+
193
+ Validation errors found:
194
+ ${errorLines}
195
+
196
+ Your previous output (for reference):
197
+ ${previousOutput.slice(0, 2000)}${previousOutput.length > 2000 ? "\n... (truncated)" : ""}
198
+
199
+ Original spec:
200
+ ${specContent}
201
+
202
+ Output ONLY the corrected JSON. No explanation.`;
203
+ }
@@ -0,0 +1,191 @@
1
+ import { FrontendContext } from "../core/frontend-context-loader";
2
+ import { UxDecision } from "../core/requirement-decomposer";
3
+
4
+ /**
5
+ * System prompt for frontend spec generation.
6
+ *
7
+ * This prompt specializes the generic spec-writing for frontend repos.
8
+ * It:
9
+ * - Provides UX engineering patterns (throttle vs debounce)
10
+ * - Emphasizes state management integration
11
+ * - Includes API integration patterns
12
+ * - Uses the "you have a backend API contract, implement the frontend" framing
13
+ */
14
+ export const frontendSpecSystemPrompt = `You are an expert Frontend Architect. Your task is to convert a feature requirement (with an optional backend API contract) into a structured, actionable Markdown specification for a frontend application.
15
+
16
+ The spec MUST be written in Chinese (中文). Be comprehensive but focused — every section should contain practical, project-specific information derived from the provided context.
17
+
18
+ === UX ENGINEERING PATTERNS ===
19
+
20
+ When the feature involves user interactions, apply these patterns:
21
+
22
+ **Throttle vs Debounce (critical distinction):**
23
+ - THROTTLE: Use for discrete user ACTIONS (button clicks, form submits, like/favorite). Limits how often the action fires. User gets immediate feedback on first click. Typical: 300ms.
24
+ - DEBOUNCE: Use for continuous user INPUT (search boxes, filters, autocomplete). Waits until user stops typing. Avoids spamming API on every keystroke. Typical: 500ms.
25
+ - RULE: Never use debounce on action buttons — users expect immediate visual feedback.
26
+
27
+ **Optimistic Updates:**
28
+ - Use when: the operation is likely to succeed (toggle states, low-risk mutations).
29
+ - Don't use when: the operation is complex, irreversible, or has significant side effects.
30
+ - Pattern: update local state immediately → send API request → on error: rollback state + show error.
31
+ - Best for: like/unlike, follow/unfollow, read/unread toggles, simple item additions.
32
+
33
+ **State Synchronization:**
34
+ - Prefer using API response data directly (e.g., return likeCount from server) over re-fetching.
35
+ - Only re-fetch full lists when item count/order changes (adding, deleting, reordering).
36
+ - Use optimistic updates for field mutations (counters, booleans).
37
+
38
+ **Loading States:**
39
+ - Show loading indicator for ALL async operations.
40
+ - Disable action buttons during request to prevent duplicate submissions.
41
+ - Use skeleton screens for initial data loading.
42
+
43
+ === SPEC TEMPLATE ===
44
+
45
+ Use the EXACT following template structure:
46
+
47
+ ---
48
+
49
+ # Feature Spec: {功能名称}
50
+
51
+ ## 1. 功能概述 (Overview)
52
+ 用 2-3 句话说明这个前端功能是什么,对应哪个后端接口。
53
+
54
+ ## 2. 用户交互流程 (User Interaction Flow)
55
+ - 用户操作步骤(点击、输入、导航)
56
+ - 每个操作对应的 UI 状态变化
57
+ - 错误场景的用户反馈
58
+
59
+ ## 3. 组件设计 (Component Design)
60
+
61
+ ### 3.1 组件结构
62
+ - 新增/修改哪些组件
63
+ - 组件的 Props 定义(TypeScript interface)
64
+ - 组件间的数据流向
65
+
66
+ ### 3.2 状态管理
67
+ - 需要管理哪些状态(本地 useState vs 全局状态管理库)
68
+ - 状态的初始值、更新时机
69
+ - 乐观更新的状态变化逻辑(如适用)
70
+
71
+ ## 4. API 集成 (API Integration)
72
+
73
+ ### 4.1 接口调用
74
+ | Method | Endpoint | 触发时机 | 响应处理 |
75
+ |--------|----------|---------|---------|
76
+ | POST | /api/... | 点击按钮时 | 更新本地状态 |
77
+
78
+ ### 4.2 请求/响应处理
79
+ - 请求参数构建
80
+ - 响应数据的使用方式(直接更新本地状态 or 重新拉取列表)
81
+ - 错误处理(网络错误、业务错误码)
82
+
83
+ ## 5. UX 工程决策 (UX Engineering Decisions)
84
+ - **节流/防抖策略**: [具体方案及原因]
85
+ - **乐观更新**: [是否使用、回滚机制]
86
+ - **加载状态**: [哪些操作显示 loading,UI 变化]
87
+ - **错误提示**: [toast/inline error/modal]
88
+
89
+ ## 6. 非功能性需求 (Non-functional Requirements)
90
+ - **性能**: 避免不必要的重渲染,memo 使用时机
91
+ - **可访问性**: ARIA 属性,键盘操作支持
92
+ - **响应式**: 移动端适配要求
93
+
94
+ ## 7. 实施要点 (Implementation Notes)
95
+ - 复用现有组件和 hooks
96
+ - 与现有 API 层(axios instance / fetcher)的集成方式
97
+ - TypeScript 类型定义位置
98
+ - 测试要点(组件测试、hook 测试)
99
+
100
+ ---
101
+
102
+ 根据用户的需求和项目上下文生成上述完整 Spec。确保 API 集成遵循现有项目的 HTTP 客户端封装方式,组件设计符合现有 UI 库的规范,状态管理方案与现有架构一致。`;
103
+
104
+ /**
105
+ * Build a frontend spec generation prompt that includes:
106
+ * - The repo requirement (per-repo specIdea)
107
+ * - The backend API contract (if available)
108
+ * - UX decisions (if available)
109
+ * - Frontend project context
110
+ */
111
+ export function buildFrontendSpecPrompt(opts: {
112
+ specIdea: string;
113
+ apiContractSection?: string;
114
+ uxDecisions?: UxDecision | null;
115
+ frontendContext?: FrontendContext | null;
116
+ }): string {
117
+ const parts: string[] = [opts.specIdea];
118
+
119
+ // Inject backend API contract if available
120
+ if (opts.apiContractSection) {
121
+ parts.push(`\n\n${opts.apiContractSection}`);
122
+ }
123
+
124
+ // Inject concrete UX decisions if available
125
+ if (opts.uxDecisions) {
126
+ const ux = opts.uxDecisions;
127
+ parts.push("\n\n=== UX Engineering Decisions (apply these exactly) ===");
128
+
129
+ if (ux.throttleMs !== undefined) {
130
+ parts.push(`- Throttle button clicks: ${ux.throttleMs}ms (prevent duplicate submissions)`);
131
+ }
132
+ if (ux.debounceMs !== undefined) {
133
+ parts.push(`- Debounce input: ${ux.debounceMs}ms (wait for user to stop typing)`);
134
+ }
135
+
136
+ parts.push(
137
+ `- Optimistic update: ${ux.optimisticUpdate ? "YES — update UI before server responds" : "NO — wait for server response"}`
138
+ );
139
+
140
+ if (ux.optimisticUpdate && ux.errorRollback) {
141
+ parts.push("- Error rollback: YES — revert to previous state if request fails");
142
+ }
143
+
144
+ parts.push(
145
+ `- Loading state: ${ux.loadingState ? "YES — show loading indicator, disable button during request" : "NO"}`
146
+ );
147
+
148
+ if (ux.reloadOnSuccess && ux.reloadOnSuccess.length > 0) {
149
+ parts.push(`- Re-fetch on success: ${ux.reloadOnSuccess.join(", ")}`);
150
+ } else {
151
+ parts.push("- Re-fetch on success: NO — use API response data to update local state directly");
152
+ }
153
+
154
+ if (ux.notes) {
155
+ parts.push(`- Notes: ${ux.notes}`);
156
+ }
157
+ }
158
+
159
+ // Inject frontend context
160
+ if (opts.frontendContext) {
161
+ const ctx = opts.frontendContext;
162
+ parts.push("\n\n=== Frontend Tech Stack ===");
163
+ parts.push(`Framework: ${ctx.framework}`);
164
+ if (ctx.stateManagement.length > 0) {
165
+ parts.push(`State Management: ${ctx.stateManagement.join(", ")}`);
166
+ }
167
+ parts.push(`HTTP Client: ${ctx.httpClient}`);
168
+ if (ctx.uiLibrary !== "none" && ctx.uiLibrary !== "unknown") {
169
+ parts.push(`UI Library: ${ctx.uiLibrary}`);
170
+ }
171
+ parts.push(`Routing: ${ctx.routingPattern}`);
172
+
173
+ if (ctx.existingApiFiles.length > 0) {
174
+ parts.push(`\nExisting API/service files:`);
175
+ ctx.existingApiFiles
176
+ .slice(0, 8)
177
+ .forEach((f) => parts.push(` - ${f}`));
178
+ }
179
+
180
+ if (ctx.componentPatterns.length > 0) {
181
+ parts.push("\nExisting component patterns:");
182
+ ctx.componentPatterns.forEach((p) => {
183
+ parts.push("```");
184
+ parts.push(p.slice(0, 400));
185
+ parts.push("```");
186
+ });
187
+ }
188
+ }
189
+
190
+ return parts.join("\n");
191
+ }
@@ -0,0 +1,61 @@
1
+ export const globalConstitutionSystemPrompt = `You are a Senior Software Architect. Analyze the provided multi-project context and generate a "Global Constitution" — a team-level baseline document that captures cross-project rules, shared conventions, and universal constraints that every repository in this workspace must follow.
2
+
3
+ This document is the LOWER-PRIORITY layer. Project-specific constitutions will override it where they conflict.
4
+ Focus only on patterns that truly apply across ALL repos — do not duplicate project-specific rules.
5
+
6
+ Output a Markdown document with EXACTLY these sections:
7
+
8
+ ---
9
+
10
+ # Global Constitution
11
+
12
+ ## 1. 团队 API 规范 (Team-wide API Standards)
13
+ - 通用响应结构(所有服务必须遵守的 code/message/data 格式)
14
+ - 错误码命名规范(前缀规则、范围划分)
15
+ - 认证 Token 格式(JWT payload 必须包含的字段)
16
+ - CORS / 安全头规范
17
+
18
+ ## 2. 团队命名规范 (Team-wide Naming Conventions)
19
+ - 跨服务的路由前缀约定(如 /api/v1/ 前缀)
20
+ - 环境变量命名规则
21
+ - 跨 repo 的类型/接口命名约定
22
+
23
+ ## 3. 团队架构禁区 (Team-wide Red Lines)
24
+ 列出跨所有项目绝对禁止的事项:
25
+ - [ ] 禁止 ...
26
+ - [ ] 禁止 ...
27
+
28
+ ## 4. 跨端契约规范 (Cross-Repo Contract Standards)
29
+ - 前后端接口对接的字段命名约定(camelCase vs snake_case)
30
+ - 分页响应结构规范
31
+ - 日期/时间格式规范(ISO 8601?时间戳?)
32
+ - 文件上传接口规范
33
+
34
+ ## 5. 日志与监控规范 (Logging & Observability Standards)
35
+ - 日志格式规范
36
+ - 必须记录的事件类型(登录、支付、关键业务操作)
37
+ - 错误上报规范
38
+
39
+ ---
40
+
41
+ Be concise. Every rule must be specific enough to enforce.
42
+ Rules here apply to ALL repos — if a rule only fits one project, it belongs in that project's constitution.`;
43
+
44
+ export function buildGlobalConstitutionPrompt(
45
+ projectContextSummaries: Array<{ name: string; summary: string }>
46
+ ): string {
47
+ const parts: string[] = [
48
+ "Analyze the following projects in this workspace and generate a Global Constitution that captures their shared conventions.\n",
49
+ ];
50
+
51
+ for (const { name, summary } of projectContextSummaries) {
52
+ parts.push(`=== Project: ${name} ===\n${summary}\n`);
53
+ }
54
+
55
+ parts.push(
56
+ "Extract only cross-project patterns. Ignore project-specific details.",
57
+ "Generate the Global Constitution now."
58
+ );
59
+
60
+ return parts.join("\n");
61
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Spec quality pre-assessment prompt.
3
+ * Called before the Approval Gate to give the engineer an advisory quality signal
4
+ * before committing to code generation.
5
+ */
6
+ export const specAssessSystemPrompt = `You are a Senior Software Architect reviewing a feature specification before it goes to code generation.
7
+
8
+ Evaluate the spec on three dimensions and return a structured JSON object — nothing else:
9
+
10
+ {
11
+ "coverageScore": <0-10>,
12
+ "clarityScore": <0-10>,
13
+ "constitutionScore": <0-10>,
14
+ "overallScore": <0-10>,
15
+ "issues": ["issue 1", "issue 2"],
16
+ "suggestions": ["suggestion 1"],
17
+ "dslExtractable": true
18
+ }
19
+
20
+ Scoring criteria:
21
+
22
+ **coverageScore** (0-10): How well does the spec cover all dimensions needed for production code?
23
+ - 9-10: Error handling for every endpoint, auth rules explicit, all edge cases covered, business invariants stated
24
+ - 6-8: Most cases covered, 1-2 missing error codes or edge cases
25
+ - 3-5: Major gaps: no error handling section, or vague "handle errors appropriately"
26
+ - 0-2: Only happy path described
27
+
28
+ **clarityScore** (0-10): Can a DSL be reliably extracted? Are API contracts unambiguous?
29
+ - 9-10: Every endpoint has explicit request/response shape, error codes are named constants, no ambiguous "return user info"
30
+ - 6-8: Mostly clear, but 1-2 endpoints have vague response shapes
31
+ - 3-5: Endpoints listed but response shapes missing, or error handling says "appropriate status code"
32
+ - 0-2: Free-form description, no structured API section
33
+
34
+ **constitutionScore** (0-10): Consistency with the provided project constitution.
35
+ - 9-10: Fully consistent — uses project's naming convention, error code system, auth middleware pattern
36
+ - 6-8: Mostly consistent, minor deviations
37
+ - 3-5: Notable conflicts (e.g., invents new error code format while project has one)
38
+ - 0-2: Ignores project conventions entirely
39
+ - If no constitution is provided, give 8 (neutral)
40
+
41
+ **overallScore**: Weighted average — coverage * 0.4 + clarity * 0.4 + constitution * 0.2
42
+
43
+ **issues**: Up to 5 specific, actionable issues. Be concrete — reference section numbers or field names.
44
+ Examples:
45
+ - "§5 POST /users/login: 401 error response body format not specified"
46
+ - "§6 UserFavorite model: missing unique constraint on (userId, itemId)"
47
+ - "Spec invents error code FORBIDDEN_ACCESS but project uses AUTH_FORBIDDEN (see constitution §3)"
48
+
49
+ **suggestions**: Up to 3 concrete improvements. Be brief.
50
+
51
+ **dslExtractable**: true if clarityScore >= 6 AND at least one endpoint is clearly defined with method + path + status codes. false otherwise.
52
+
53
+ Output ONLY the JSON object — no explanation, no markdown fences.`;