@guanlin4924/devflow-pi 0.1.67 → 0.1.68
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/package.json +1 -1
- package/src/constants.ts +1 -1
- package/src/project-documents.ts +50 -1
package/package.json
CHANGED
package/src/constants.ts
CHANGED
package/src/project-documents.ts
CHANGED
|
@@ -157,6 +157,55 @@ function sourceTable(items: Array<{ source: SourceDocument; classification: Docu
|
|
|
157
157
|
if (!items.length) return "未发现可归类的已有文档。";
|
|
158
158
|
return table(["来源", "标题", "置信度", "理由"], items.map(item => [item.source.path, item.source.title, item.classification.confidence, item.classification.reasons.join(";")]));
|
|
159
159
|
}
|
|
160
|
+
function apiPath(fact: Fact): string {
|
|
161
|
+
return String(fact.value.path ?? fact.objectKey.replace(/^route:[^:]+:/, ""));
|
|
162
|
+
}
|
|
163
|
+
function apiDomain(route: string): string {
|
|
164
|
+
const first = route.split("?")[0].split("/").filter(Boolean)[0];
|
|
165
|
+
if (!first) return "root";
|
|
166
|
+
if (/^\{.+\}$/.test(first) || first.startsWith(":")) return "parameterized";
|
|
167
|
+
return first;
|
|
168
|
+
}
|
|
169
|
+
function humanDomain(value: string): string {
|
|
170
|
+
return value === "root" ? "根路径" : value === "parameterized" ? "参数化根路径" : value;
|
|
171
|
+
}
|
|
172
|
+
function validModelName(value: unknown): string | undefined {
|
|
173
|
+
const name = String(value ?? "").trim();
|
|
174
|
+
if (!/^[A-Za-z_][A-Za-z0-9_.-]{2,63}$/.test(name)) return undefined;
|
|
175
|
+
const stop = new Set(["and", "are", "for", "not", "is", "etc", "data", "arguments", "options", "output", "phrase", "definition", "converts"]);
|
|
176
|
+
if (stop.has(name.toLowerCase().replace(/[.]+$/, ""))) return undefined;
|
|
177
|
+
return name;
|
|
178
|
+
}
|
|
179
|
+
function architectureBody(context: ProjectContext, facts: Fact[], intro: string, snapshotId: string, knowledge: DocumentKnowledge, generation?: string): string {
|
|
180
|
+
const repositories = [...new Set(facts.map(fact => fact.repository).filter(Boolean))].sort();
|
|
181
|
+
const apis = facts.filter(fact => fact.kind === "api");
|
|
182
|
+
const models = [...new Set(facts.filter(fact => fact.kind === "data_model").map(fact => validModelName(fact.value.name ?? fact.objectKey)).filter((item): item is string => Boolean(item)))].sort();
|
|
183
|
+
const integrations = facts.filter(fact => fact.kind === "integration");
|
|
184
|
+
const groupedApis = new Map<string, string[]>();
|
|
185
|
+
for (const fact of apis) {
|
|
186
|
+
const route = apiPath(fact);
|
|
187
|
+
const domain = apiDomain(route);
|
|
188
|
+
groupedApis.set(domain, [...(groupedApis.get(domain) ?? []), route]);
|
|
189
|
+
}
|
|
190
|
+
const apiRows = [...groupedApis.entries()]
|
|
191
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
192
|
+
.slice(0, 30)
|
|
193
|
+
.map(([domain, routes]) => [humanDomain(domain), [...new Set(routes)].slice(0, 8).join("、"), routes.length]);
|
|
194
|
+
const evidence = [
|
|
195
|
+
"",
|
|
196
|
+
"## 已发现资料",
|
|
197
|
+
"",
|
|
198
|
+
sourceTable(sourcesFor("architecture", knowledge, "project")),
|
|
199
|
+
"",
|
|
200
|
+
"## 证据绑定",
|
|
201
|
+
"",
|
|
202
|
+
`- 初始化快照:${snapshotId}`,
|
|
203
|
+
`- 代码索引 generation:${generation ?? "未生成或已跳过"}`,
|
|
204
|
+
"- 本文档由项目初始化创建骨架,人工确认前均为 draft。",
|
|
205
|
+
"",
|
|
206
|
+
].join("\n");
|
|
207
|
+
return `${frontmatter({ type: "project-architecture", scope: "project", project: context.manifest.name, status: "draft", source_snapshot: snapshotId, code_index_generation: generation, managed: true })}# 项目架构设计\n\n${intro}\n\n## 当前结论\n\n- 当前项目识别到 ${repositories.length || "未确认"} 个代码库:${repositories.join("、") || "未确认"}。\n- 后端/API 侧观察到 ${apis.length} 条静态路由声明,以下按路径前缀粗分能力域。\n- 数据模型候选已过滤明显普通词;仍需人工确认真实表、实体和持久化边界。\n- 本文档只陈述静态可观察事实,不确认部署拓扑、运行时依赖或权限链路。\n\n## 系统组成\n\n${table(["代码库", "观察到的文件数", "观察到的能力"], repositories.map(repository => [repository, facts.filter(fact => fact.repository === repository && fact.kind === "asset").length, [...new Set(facts.filter(fact => fact.repository === repository && ["api", "page", "data_model", "integration"].includes(fact.kind)).map(fact => fact.kind))].join("、") || "未发现"]))}\n\n## API 能力分组\n\n${apiRows.length ? table(["能力域", "代表路径", "路径数量"], apiRows) : "未发现可分组 API。"}\n\n## 数据模型候选\n\n${models.length ? table(["模型或表名"], models.slice(0, 80).map(name => [name])) : "未发现可信数据模型候选。"}\n\n## 集成与运行时线索\n\n${integrations.length ? table(["类型", "对象"], integrations.slice(0, 80).map(fact => [fact.value.kind ?? fact.value.name ? "配置/任务" : "外部主机", fact.value.host ?? fact.value.name ?? fact.objectKey])) : "未发现外部集成线索。"}\n\n## 待确认架构问题\n\n- 前端、后端、任务执行器和外部服务的部署边界是什么?\n- 认证、授权和用户上下文如何在前后端之间传递?\n- 是否存在异步任务队列、调度器、设备/浏览器执行器或后台 worker?\n- 核心数据模型、数据库类型和迁移策略是什么?\n- 关键能力域之间的数据流、失败降级和监控指标是什么?\n${evidence}`;
|
|
208
|
+
}
|
|
160
209
|
|
|
161
210
|
async function narrative(context: ProjectContext, document: string, facts: Fact[], mode: DocumentGenerationMode, organizer?: LowTierDocumentOrganizer): Promise<{ text: string; modelRole?: string }> {
|
|
162
211
|
const knownFacts = facts.slice(0, 80).map(fact => `${fact.kind}: ${Object.values(fact.value).filter(value => typeof value === "string" || typeof value === "number").slice(0, 3).join(" / ")}`);
|
|
@@ -233,7 +282,7 @@ function projectKnowledgeBody(context: ProjectContext, type: KnowledgeDocumentTy
|
|
|
233
282
|
].join("\n");
|
|
234
283
|
if (type === "requirements") return `${header}# 项目总体需求\n\n${intro}\n\n## 项目范围\n\n${table(["代码库", "扫描事实数"], repositoryNames.map(repository => [repository, facts.filter(fact => fact.repository === repository).length]))}\n\n## 已观察业务能力\n\n${table(["类型", "对象"], [...pages, ...apis, ...models].slice(0, 80).map(fact => [fact.kind, fact.value.route ?? fact.value.path ?? fact.value.name ?? fact.objectKey]))}\n\n## 待人工补充\n\n- 项目目标与非目标\n- 用户角色与核心流程\n- 业务约束与优先级\n${evidence}`;
|
|
235
284
|
if (type === "product-design") return `${header}# 项目产品与交互设计\n\n${intro}\n\n## 已发现页面/入口\n\n${table(["代码库", "页面或入口"], pages.slice(0, 100).map(fact => [fact.repository, fact.value.route ?? fact.value.componentPath ?? fact.objectKey]))}\n\n## 待人工补充\n\n- 信息架构\n- 页面状态与异常态\n- 文案、权限与可访问性约束\n${evidence}`;
|
|
236
|
-
if (type === "architecture") return
|
|
285
|
+
if (type === "architecture") return architectureBody(context, facts, intro, snapshotId, knowledge, generation);
|
|
237
286
|
if (type === "frontend-tech") return `${header}# 项目前端技术方案\n\n${intro}\n\n## 已观察前端技术\n\n${table(["声明", "来源"], tech.filter(fact => /react|vue|vite|router|zustand|tailwind|typescript|eslint|vitest/i.test(String(fact.value.name ?? fact.value.extension ?? ""))).slice(0, 120).map(fact => [fact.value.name ?? fact.value.extension, fact.value.declaration ?? fact.value.path ?? "文件统计"]))}\n\n## 待人工补充\n\n- 路由、状态管理与组件边界\n- API 调用约定\n- 构建、测试与发布规则\n${evidence}`;
|
|
238
287
|
if (type === "backend-tech") return `${header}# 项目后端技术方案\n\n${intro}\n\n## 已观察后端事实\n\n${table(["类型", "对象"], [...apis, ...models, ...integrations].slice(0, 120).map(fact => [fact.kind, fact.value.path ?? fact.value.name ?? fact.value.host ?? fact.objectKey]))}\n\n## 待人工补充\n\n- handler/service/repository 分层\n- 数据库迁移与任务调度规则\n- 鉴权、错误码、日志与监控\n${evidence}`;
|
|
239
288
|
if (type === "test-cases") return `${header}# 项目用例与验收\n\n${intro}\n\n## 已发现测试/命令线索\n\n${table(["代码库", "名称", "命令或路径"], commands.slice(0, 120).map(fact => [fact.repository, fact.value.name ?? "test-definition", fact.value.command ?? fact.value.testDefinition ?? fact.objectKey]))}\n\n## 待人工补充\n\n- 核心主流程验收用例\n- 异常路径与权限用例\n- 回归范围与自动化策略\n${evidence}`;
|