openfeel 1.0.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.
Files changed (196) hide show
  1. package/LICENSE +21 -0
  2. package/README.en.md +140 -0
  3. package/README.md +17 -0
  4. package/README.zh-CN.md +140 -0
  5. package/bin/openfeel.js +13 -0
  6. package/dist/cli/index.d.ts +11 -0
  7. package/dist/cli/index.d.ts.map +1 -0
  8. package/dist/cli/index.js +119 -0
  9. package/dist/cli/index.js.map +1 -0
  10. package/dist/cli/repl.d.ts +10 -0
  11. package/dist/cli/repl.d.ts.map +1 -0
  12. package/dist/cli/repl.js +74 -0
  13. package/dist/cli/repl.js.map +1 -0
  14. package/dist/commands/archive.d.ts +7 -0
  15. package/dist/commands/archive.d.ts.map +1 -0
  16. package/dist/commands/archive.js +38 -0
  17. package/dist/commands/archive.js.map +1 -0
  18. package/dist/commands/config.d.ts +15 -0
  19. package/dist/commands/config.d.ts.map +1 -0
  20. package/dist/commands/config.js +208 -0
  21. package/dist/commands/config.js.map +1 -0
  22. package/dist/commands/flow.d.ts +24 -0
  23. package/dist/commands/flow.d.ts.map +1 -0
  24. package/dist/commands/flow.js +1024 -0
  25. package/dist/commands/flow.js.map +1 -0
  26. package/dist/commands/init.d.ts +9 -0
  27. package/dist/commands/init.d.ts.map +1 -0
  28. package/dist/commands/init.js +62 -0
  29. package/dist/commands/init.js.map +1 -0
  30. package/dist/commands/instructions.d.ts +7 -0
  31. package/dist/commands/instructions.d.ts.map +1 -0
  32. package/dist/commands/instructions.js +36 -0
  33. package/dist/commands/instructions.js.map +1 -0
  34. package/dist/commands/knowledge.d.ts +7 -0
  35. package/dist/commands/knowledge.d.ts.map +1 -0
  36. package/dist/commands/knowledge.js +174 -0
  37. package/dist/commands/knowledge.js.map +1 -0
  38. package/dist/commands/lint.d.ts +12 -0
  39. package/dist/commands/lint.d.ts.map +1 -0
  40. package/dist/commands/lint.js +192 -0
  41. package/dist/commands/lint.js.map +1 -0
  42. package/dist/commands/plan.d.ts +7 -0
  43. package/dist/commands/plan.d.ts.map +1 -0
  44. package/dist/commands/plan.js +73 -0
  45. package/dist/commands/plan.js.map +1 -0
  46. package/dist/commands/project.d.ts +7 -0
  47. package/dist/commands/project.d.ts.map +1 -0
  48. package/dist/commands/project.js +189 -0
  49. package/dist/commands/project.js.map +1 -0
  50. package/dist/commands/roadmap.d.ts +7 -0
  51. package/dist/commands/roadmap.d.ts.map +1 -0
  52. package/dist/commands/roadmap.js +26 -0
  53. package/dist/commands/roadmap.js.map +1 -0
  54. package/dist/commands/stage.d.ts +17 -0
  55. package/dist/commands/stage.d.ts.map +1 -0
  56. package/dist/commands/stage.js +291 -0
  57. package/dist/commands/stage.js.map +1 -0
  58. package/dist/commands/update.d.ts +8 -0
  59. package/dist/commands/update.d.ts.map +1 -0
  60. package/dist/commands/update.js +87 -0
  61. package/dist/commands/update.js.map +1 -0
  62. package/dist/commands/view.d.ts +7 -0
  63. package/dist/commands/view.d.ts.map +1 -0
  64. package/dist/commands/view.js +77 -0
  65. package/dist/commands/view.js.map +1 -0
  66. package/dist/core/archive/merge.d.ts +20 -0
  67. package/dist/core/archive/merge.d.ts.map +1 -0
  68. package/dist/core/archive/merge.js +118 -0
  69. package/dist/core/archive/merge.js.map +1 -0
  70. package/dist/core/artifact-graph/graph.d.ts +62 -0
  71. package/dist/core/artifact-graph/graph.d.ts.map +1 -0
  72. package/dist/core/artifact-graph/graph.js +184 -0
  73. package/dist/core/artifact-graph/graph.js.map +1 -0
  74. package/dist/core/artifact-graph/index.d.ts +10 -0
  75. package/dist/core/artifact-graph/index.d.ts.map +1 -0
  76. package/dist/core/artifact-graph/index.js +8 -0
  77. package/dist/core/artifact-graph/index.js.map +1 -0
  78. package/dist/core/artifact-graph/instruction-loader.d.ts +35 -0
  79. package/dist/core/artifact-graph/instruction-loader.d.ts.map +1 -0
  80. package/dist/core/artifact-graph/instruction-loader.js +358 -0
  81. package/dist/core/artifact-graph/instruction-loader.js.map +1 -0
  82. package/dist/core/artifact-graph/resolver.d.ts +10 -0
  83. package/dist/core/artifact-graph/resolver.d.ts.map +1 -0
  84. package/dist/core/artifact-graph/resolver.js +32 -0
  85. package/dist/core/artifact-graph/resolver.js.map +1 -0
  86. package/dist/core/artifact-graph/state.d.ts +9 -0
  87. package/dist/core/artifact-graph/state.d.ts.map +1 -0
  88. package/dist/core/artifact-graph/state.js +24 -0
  89. package/dist/core/artifact-graph/state.js.map +1 -0
  90. package/dist/core/artifact-graph/types.d.ts +22 -0
  91. package/dist/core/artifact-graph/types.d.ts.map +1 -0
  92. package/dist/core/artifact-graph/types.js +2 -0
  93. package/dist/core/artifact-graph/types.js.map +1 -0
  94. package/dist/core/config.d.ts +256 -0
  95. package/dist/core/config.d.ts.map +1 -0
  96. package/dist/core/config.js +393 -0
  97. package/dist/core/config.js.map +1 -0
  98. package/dist/core/flow-manager.d.ts +492 -0
  99. package/dist/core/flow-manager.d.ts.map +1 -0
  100. package/dist/core/flow-manager.js +2379 -0
  101. package/dist/core/flow-manager.js.map +1 -0
  102. package/dist/core/i18n-data/en.d.ts +26 -0
  103. package/dist/core/i18n-data/en.d.ts.map +1 -0
  104. package/dist/core/i18n-data/en.js +492 -0
  105. package/dist/core/i18n-data/en.js.map +1 -0
  106. package/dist/core/i18n-data/types.d.ts +18 -0
  107. package/dist/core/i18n-data/types.d.ts.map +1 -0
  108. package/dist/core/i18n-data/types.js +8 -0
  109. package/dist/core/i18n-data/types.js.map +1 -0
  110. package/dist/core/i18n-data/zh-CN.d.ts +28 -0
  111. package/dist/core/i18n-data/zh-CN.d.ts.map +1 -0
  112. package/dist/core/i18n-data/zh-CN.js +524 -0
  113. package/dist/core/i18n-data/zh-CN.js.map +1 -0
  114. package/dist/core/i18n.d.ts +40 -0
  115. package/dist/core/i18n.d.ts.map +1 -0
  116. package/dist/core/i18n.js +135 -0
  117. package/dist/core/i18n.js.map +1 -0
  118. package/dist/core/init.d.ts +22 -0
  119. package/dist/core/init.d.ts.map +1 -0
  120. package/dist/core/init.js +292 -0
  121. package/dist/core/init.js.map +1 -0
  122. package/dist/core/metrics.d.ts +60 -0
  123. package/dist/core/metrics.d.ts.map +1 -0
  124. package/dist/core/metrics.js +137 -0
  125. package/dist/core/metrics.js.map +1 -0
  126. package/dist/core/pipeline-schema.d.ts +78 -0
  127. package/dist/core/pipeline-schema.d.ts.map +1 -0
  128. package/dist/core/pipeline-schema.js +57 -0
  129. package/dist/core/pipeline-schema.js.map +1 -0
  130. package/dist/core/plan/roadmap.d.ts +17 -0
  131. package/dist/core/plan/roadmap.d.ts.map +1 -0
  132. package/dist/core/plan/roadmap.js +71 -0
  133. package/dist/core/plan/roadmap.js.map +1 -0
  134. package/dist/core/plan/scheme.d.ts +34 -0
  135. package/dist/core/plan/scheme.d.ts.map +1 -0
  136. package/dist/core/plan/scheme.js +262 -0
  137. package/dist/core/plan/scheme.js.map +1 -0
  138. package/dist/core/plan/stage.d.ts +20 -0
  139. package/dist/core/plan/stage.d.ts.map +1 -0
  140. package/dist/core/plan/stage.js +120 -0
  141. package/dist/core/plan/stage.js.map +1 -0
  142. package/dist/core/public-logger.d.ts +84 -0
  143. package/dist/core/public-logger.d.ts.map +1 -0
  144. package/dist/core/public-logger.js +344 -0
  145. package/dist/core/public-logger.js.map +1 -0
  146. package/dist/core/schema.d.ts +70 -0
  147. package/dist/core/schema.d.ts.map +1 -0
  148. package/dist/core/schema.js +61 -0
  149. package/dist/core/schema.js.map +1 -0
  150. package/dist/core/template-loader.d.ts +22 -0
  151. package/dist/core/template-loader.d.ts.map +1 -0
  152. package/dist/core/template-loader.js +2848 -0
  153. package/dist/core/template-loader.js.map +1 -0
  154. package/dist/core/templates.d.ts +18 -0
  155. package/dist/core/templates.d.ts.map +1 -0
  156. package/dist/core/templates.js +50 -0
  157. package/dist/core/templates.js.map +1 -0
  158. package/dist/core/update.d.ts +40 -0
  159. package/dist/core/update.d.ts.map +1 -0
  160. package/dist/core/update.js +1569 -0
  161. package/dist/core/update.js.map +1 -0
  162. package/dist/core/view/entry.d.ts +37 -0
  163. package/dist/core/view/entry.d.ts.map +1 -0
  164. package/dist/core/view/entry.js +108 -0
  165. package/dist/core/view/entry.js.map +1 -0
  166. package/dist/core/workspace/identity.d.ts +60 -0
  167. package/dist/core/workspace/identity.d.ts.map +1 -0
  168. package/dist/core/workspace/identity.js +169 -0
  169. package/dist/core/workspace/identity.js.map +1 -0
  170. package/dist/core/workspace/knowledge.d.ts +55 -0
  171. package/dist/core/workspace/knowledge.d.ts.map +1 -0
  172. package/dist/core/workspace/knowledge.js +230 -0
  173. package/dist/core/workspace/knowledge.js.map +1 -0
  174. package/dist/core/workspace/structure.d.ts +9 -0
  175. package/dist/core/workspace/structure.d.ts.map +1 -0
  176. package/dist/core/workspace/structure.js +59 -0
  177. package/dist/core/workspace/structure.js.map +1 -0
  178. package/dist/index.d.ts +7 -0
  179. package/dist/index.d.ts.map +1 -0
  180. package/dist/index.js +7 -0
  181. package/dist/index.js.map +1 -0
  182. package/dist/utils/kb-dedup.d.ts +46 -0
  183. package/dist/utils/kb-dedup.d.ts.map +1 -0
  184. package/dist/utils/kb-dedup.js +169 -0
  185. package/dist/utils/kb-dedup.js.map +1 -0
  186. package/dist/utils/path.d.ts +22 -0
  187. package/dist/utils/path.d.ts.map +1 -0
  188. package/dist/utils/path.js +37 -0
  189. package/dist/utils/path.js.map +1 -0
  190. package/package.json +61 -0
  191. package/schemas/spec-driven/schema.yaml +50 -0
  192. package/schemas/spec-driven/templates/design.md +43 -0
  193. package/schemas/spec-driven/templates/plan.md +46 -0
  194. package/schemas/spec-driven/templates/proposal.md +35 -0
  195. package/schemas/spec-driven/templates/tasks.md +39 -0
  196. package/scripts/patch-inquirer.js +70 -0
@@ -0,0 +1,230 @@
1
+ /**
2
+ * 知识库核心模块
3
+ * 管理 .openfeel/kb/ 目录,包含知识条目的增删查改、索引维护和解析。
4
+ */
5
+ import { readFileSync, writeFileSync, appendFileSync, existsSync, mkdirSync } from 'node:fs';
6
+ import { resolve } from 'node:path';
7
+ // ---------------------------------------------------------------------------
8
+ // 常量
9
+ // ---------------------------------------------------------------------------
10
+ /** 4 个标准分类 */
11
+ const CATEGORIES = ['architecture', 'patterns', 'troubleshooting', 'setup'];
12
+ /** 分类中文标题映射 */
13
+ const CATEGORY_TITLES = {
14
+ architecture: '架构决策',
15
+ patterns: '代码模式',
16
+ troubleshooting: '常见问题',
17
+ setup: '环境搭建',
18
+ };
19
+ /** index.md 模板 */
20
+ const INDEX_TEMPLATE = `# 知识库索引
21
+ > 项目知识库总索引
22
+
23
+ ## 分类概览
24
+
25
+ | 分类 | 描述 |
26
+ |------|------|
27
+ | architecture | 架构决策、设计理由、技术选型 |
28
+ | patterns | 代码模式、项目约定、最佳实践 |
29
+ | troubleshooting | 常见问题、调试流程、已知坑位 |
30
+ | setup | 环境搭建、构建流程、依赖管理 |
31
+
32
+ ## 最近更新
33
+
34
+ | 日期 | 分类 | 标题 |
35
+ |------|------|------|
36
+ `;
37
+ // ---------------------------------------------------------------------------
38
+ // 公开 API
39
+ // ---------------------------------------------------------------------------
40
+ /**
41
+ * 初始化知识库目录结构
42
+ * 在 .openfeel/kb/ 下创建 index.md 和 4 个分类文件。
43
+ * 已存在的文件不覆盖(幂等)。
44
+ * @returns 创建的文件路径列表
45
+ */
46
+ export function initKnowledgeBase(projectPath) {
47
+ const kbDir = resolve(projectPath, '.openfeel', 'kb');
48
+ const created = [];
49
+ // 确保 kb 目录存在
50
+ if (!existsSync(kbDir)) {
51
+ mkdirSync(kbDir, { recursive: true });
52
+ created.push('.openfeel/kb/');
53
+ }
54
+ // 创建 index.md(不覆盖已有)
55
+ const indexPath = resolve(kbDir, 'index.md');
56
+ if (!existsSync(indexPath)) {
57
+ writeFileSync(indexPath, INDEX_TEMPLATE, 'utf-8');
58
+ created.push('.openfeel/kb/index.md');
59
+ }
60
+ // 创建分类文件(不覆盖已有)
61
+ for (const cat of CATEGORIES) {
62
+ const filePath = resolve(kbDir, `${cat}.md`);
63
+ if (!existsSync(filePath)) {
64
+ writeFileSync(filePath, `# ${CATEGORY_TITLES[cat]} (${cat})\n`, 'utf-8');
65
+ created.push(`.openfeel/kb/${cat}.md`);
66
+ }
67
+ }
68
+ return created;
69
+ }
70
+ /**
71
+ * 添加知识条目
72
+ * 向分类文件追加条目,并同步更新 index.md 的"最近更新"表格。
73
+ * 若 kb 目录不存在则自动初始化。
74
+ * @throws {Error} 传入无效分类时抛出
75
+ */
76
+ export function addKnowledgeEntry(projectPath, category, title, content) {
77
+ // 校验分类有效性
78
+ if (!CATEGORIES.includes(category)) {
79
+ throw new Error(`无效分类 "${category}",有效值:${CATEGORIES.join(', ')}`);
80
+ }
81
+ const kbDir = resolve(projectPath, '.openfeel', 'kb');
82
+ // 自动初始化
83
+ if (!existsSync(kbDir)) {
84
+ initKnowledgeBase(projectPath);
85
+ }
86
+ const today = new Date().toISOString().slice(0, 10); // YYYY-MM-DD
87
+ // 追加条目到分类文件
88
+ const catPath = resolve(kbDir, `${category}.md`);
89
+ const entryText = `\n## [+] ${title} (${today})\n\n${content}\n`;
90
+ appendFileSync(catPath, entryText, 'utf-8');
91
+ // 更新 index.md 的"最近更新"表格(在表头分隔行后插入新行)
92
+ const indexPath = resolve(kbDir, 'index.md');
93
+ let indexContent = readFileSync(indexPath, 'utf-8');
94
+ const sepLine = '|------|------|------|';
95
+ const sepIdx = indexContent.indexOf(sepLine);
96
+ if (sepIdx !== -1) {
97
+ const insertPos = sepIdx + sepLine.length;
98
+ const newRow = `| ${today} | ${category} | ${title} |`;
99
+ indexContent = indexContent.slice(0, insertPos) + '\n' + newRow + indexContent.slice(insertPos);
100
+ writeFileSync(indexPath, indexContent, 'utf-8');
101
+ }
102
+ }
103
+ /**
104
+ * 列出知识条目
105
+ * @param category 可选分类过滤;不传则返回所有分类的条目
106
+ */
107
+ export function listKnowledge(projectPath, category) {
108
+ const kbDir = resolve(projectPath, '.openfeel', 'kb');
109
+ if (!existsSync(kbDir)) {
110
+ return [];
111
+ }
112
+ const targetCategories = category ? [category] : [...CATEGORIES];
113
+ const entries = [];
114
+ for (const cat of targetCategories) {
115
+ const filePath = resolve(kbDir, `${cat}.md`);
116
+ if (!existsSync(filePath)) {
117
+ continue;
118
+ }
119
+ const fileContent = readFileSync(filePath, 'utf-8');
120
+ const parsed = parseEntryFile(fileContent, cat);
121
+ entries.push(...parsed);
122
+ }
123
+ return entries;
124
+ }
125
+ /**
126
+ * 全文搜索知识条目
127
+ * 在 title 和 content 中进行不区分大小写的关键词搜索,并对匹配关键词用 ** 包裹高亮。
128
+ * @param projectPath 项目路径
129
+ * @param query 搜索关键词
130
+ * @param limit 返回结果数量上限(默认 10)
131
+ * @param offset 结果偏移量(默认 0)
132
+ */
133
+ export function searchKnowledge(projectPath, query, limit = 10, offset = 0) {
134
+ const entries = listKnowledge(projectPath);
135
+ const q = query.toLowerCase();
136
+ const matched = entries.filter((entry) => entry.title.toLowerCase().includes(q) || entry.content.toLowerCase().includes(q));
137
+ // 对匹配结果高亮关键词(标题和内容摘要中用 ** 包裹)
138
+ const highlighted = matched.map((entry) => highlightEntry(entry, q));
139
+ // 分页截取
140
+ return highlighted.slice(offset, offset + limit);
141
+ }
142
+ /**
143
+ * 获取知识库索引
144
+ * 从 index.md 解析分类概览和最近更新信息。
145
+ * 若 kb 目录或 index.md 不存在,返回默认值(空结构)。
146
+ */
147
+ export function getKnowledgeIndex(projectPath) {
148
+ const kbDir = resolve(projectPath, '.openfeel', 'kb');
149
+ const indexPath = resolve(kbDir, 'index.md');
150
+ // kb 目录或 index.md 不存在 → 返回默认值
151
+ if (!existsSync(indexPath)) {
152
+ return {
153
+ categories: CATEGORIES.map((name) => ({
154
+ name,
155
+ description: CATEGORY_TITLES[name],
156
+ })),
157
+ recentUpdates: [],
158
+ };
159
+ }
160
+ const content = readFileSync(indexPath, 'utf-8');
161
+ return {
162
+ categories: parseCategoriesTable(content),
163
+ recentUpdates: parseRecentUpdatesTable(content),
164
+ };
165
+ }
166
+ // ---------------------------------------------------------------------------
167
+ // 内部解析函数
168
+ // ---------------------------------------------------------------------------
169
+ /**
170
+ * 高亮条目中的匹配关键词(不区分大小写)
171
+ * 在标题和内容摘要中用 ** 包裹匹配词
172
+ */
173
+ function highlightEntry(entry, query) {
174
+ const escapedQuery = query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
175
+ const regex = new RegExp(`(${escapedQuery})`, 'gi');
176
+ return {
177
+ ...entry,
178
+ title: entry.title.replace(regex, '**$1**'),
179
+ content: entry.content.replace(regex, '**$1**'),
180
+ };
181
+ }
182
+ /**
183
+ * 解析分类文件的条目
184
+ * 条目头格式:## [+/-] Title (YYYY-MM-DD)
185
+ * 条目内容为标题行之后到下一个 ## 或文件末尾之间的文本。
186
+ */
187
+ function parseEntryFile(fileContent, category) {
188
+ const entries = [];
189
+ const headerRegex = /^## (\[[+-]\]) (.+?) \((\d{4}-\d{2}-\d{2})\)$/gm;
190
+ // 记录所有 ## 行的位置,用于判断条目内容的结束边界
191
+ const headingStarts = [...fileContent.matchAll(/^## /gm)].map((m) => m.index);
192
+ for (const match of fileContent.matchAll(headerRegex)) {
193
+ const contentStart = match.index + match[0].length + 1; // +1 跳过标题行末尾的换行
194
+ // 查找下一个 ## 标题行(跳过自身的标题)
195
+ const nextHeading = headingStarts.find((idx) => idx > match.index);
196
+ const contentEnd = nextHeading !== undefined ? nextHeading : fileContent.length;
197
+ const content = fileContent.slice(contentStart, contentEnd).trim();
198
+ entries.push({
199
+ title: match[2].trim(),
200
+ category,
201
+ date: match[3],
202
+ content,
203
+ enabled: match[1] === '[+]',
204
+ });
205
+ }
206
+ return entries;
207
+ }
208
+ /**
209
+ * 从 index.md 中解析分类概览表格
210
+ */
211
+ function parseCategoriesTable(content) {
212
+ const section = content.match(/## 分类概览\n\n([\s\S]*?)(?=\n## |$)/);
213
+ if (!section) {
214
+ return [];
215
+ }
216
+ const rows = [...section[1].matchAll(/\| ([a-z_]+) \| ([^|]+) \|/g)];
217
+ return rows.map((r) => ({ name: r[1].trim(), description: r[2].trim() }));
218
+ }
219
+ /**
220
+ * 从 index.md 中解析最近更新表格
221
+ */
222
+ function parseRecentUpdatesTable(content) {
223
+ const section = content.match(/## 最近更新\n\n([\s\S]*?)(?=\n## |$)/);
224
+ if (!section) {
225
+ return [];
226
+ }
227
+ const rows = [...section[1].matchAll(/\| (\d{4}-\d{2}-\d{2}) \| ([a-z_]+) \| ([^|]+) \|/g)];
228
+ return rows.map((r) => ({ date: r[1], category: r[2].trim(), title: r[3].trim() }));
229
+ }
230
+ //# sourceMappingURL=knowledge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"knowledge.js","sourceRoot":"","sources":["../../../src/core/workspace/knowledge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * 递归创建目录(若不存在)
3
+ */
4
+ export declare function ensureDir(path: string): void;
5
+ /**
6
+ * 创建 .openfeel/ 完整目录结构
7
+ */
8
+ export declare function createWorkspace(projectPath: string): string[];
9
+ //# sourceMappingURL=structure.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structure.d.ts","sourceRoot":"","sources":["../../../src/core/workspace/structure.ts"],"names":[],"mappings":"AAOA;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAI5C;AAkBD;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CA8B7D"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * 工作区目录创建
3
+ * 负责创建项目下的 .openfeel/ 完整目录结构。
4
+ */
5
+ import { mkdirSync, existsSync } from 'node:fs';
6
+ import { resolve } from 'node:path';
7
+ /**
8
+ * 递归创建目录(若不存在)
9
+ */
10
+ export function ensureDir(path) {
11
+ if (!existsSync(path)) {
12
+ mkdirSync(path, { recursive: true });
13
+ }
14
+ }
15
+ /** .openfeel/ 下的子目录清单 */
16
+ const WORKSPACE_DIRS = [
17
+ 'plan',
18
+ 'kb',
19
+ 'dev',
20
+ 'log',
21
+ 'code_review',
22
+ 'bugs',
23
+ 'users',
24
+ 'tmp',
25
+ 'manual',
26
+ ];
27
+ /** dev/ 下的子目录清单 */
28
+ const DEV_SUB_DIRS = ['note'];
29
+ /**
30
+ * 创建 .openfeel/ 完整目录结构
31
+ */
32
+ export function createWorkspace(projectPath) {
33
+ const base = resolve(projectPath, '.openfeel');
34
+ const created = [];
35
+ // 确保根目录存在
36
+ if (!existsSync(base)) {
37
+ mkdirSync(base, { recursive: true });
38
+ created.push('.openfeel/');
39
+ }
40
+ // 创建子目录
41
+ for (const dir of WORKSPACE_DIRS) {
42
+ const fullPath = resolve(base, dir);
43
+ if (!existsSync(fullPath)) {
44
+ mkdirSync(fullPath, { recursive: true });
45
+ created.push(`.openfeel/${dir}/`);
46
+ }
47
+ }
48
+ // 创建 dev 下的子目录
49
+ const devBase = resolve(base, 'dev');
50
+ for (const subDir of DEV_SUB_DIRS) {
51
+ const fullPath = resolve(devBase, subDir);
52
+ if (!existsSync(fullPath)) {
53
+ mkdirSync(fullPath, { recursive: true });
54
+ created.push(`.openfeel/dev/${subDir}/`);
55
+ }
56
+ }
57
+ return created;
58
+ }
59
+ //# sourceMappingURL=structure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structure.js","sourceRoot":"","sources":["../../../src/core/workspace/structure.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,SAAS,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACvC,CAAC;AACH,CAAC;AAED,yBAAyB;AACzB,MAAM,cAAc,GAAG;IACrB,MAAM;IACN,IAAI;IACJ,KAAK;IACL,KAAK;IACL,aAAa;IACb,MAAM;IACN,OAAO;IACP,KAAK;IACL,QAAQ;CACT,CAAC;AAEF,mBAAmB;AACnB,MAAM,YAAY,GAAG,CAAC,MAAM,CAAC,CAAC;AAE9B;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,WAAmB;IACjD,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IAC/C,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,UAAU;IACV,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,SAAS,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACrC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC7B,CAAC;IAED,QAAQ;IACR,KAAK,MAAM,GAAG,IAAI,cAAc,EAAE,CAAC;QACjC,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QACpC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1B,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACzC,OAAO,CAAC,IAAI,CAAC,aAAa,GAAG,GAAG,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAED,eAAe;IACf,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACrC,KAAK,MAAM,MAAM,IAAI,YAAY,EAAE,CAAC;QAClC,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC1C,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1B,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACzC,OAAO,CAAC,IAAI,CAAC,iBAAiB,MAAM,GAAG,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * OpenFeel 包主入口
3
+ * 公共 API 导出点(后续阶段逐步填充)
4
+ */
5
+ export {};
6
+ export declare const VERSION = "0.1.0";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,CAAC;AAGV,eAAO,MAAM,OAAO,UAAU,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * OpenFeel 包主入口
3
+ * 公共 API 导出点(后续阶段逐步填充)
4
+ */
5
+ // 版本号标识
6
+ export const VERSION = '0.1.0';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,QAAQ;AACR,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC"}
@@ -0,0 +1,46 @@
1
+ /** 知识库单条条目 */
2
+ export interface KbEntry {
3
+ /** 标题(不含 [+] / [-] 前缀和日期) */
4
+ title: string;
5
+ /** 日期字符串,如 "2026-06-27" */
6
+ date: string;
7
+ /** 启禁标记:+ 表示启用,- 表示禁用 */
8
+ status: '+' | '-';
9
+ /** 条目的正文内容(不含标题行和状态标记,含代码块和空行) */
10
+ content: string;
11
+ /** 原始标题行(如 "## [+] 标题 (日期)"),用于重建条目 */
12
+ rawLine: string;
13
+ }
14
+ /** 相似度计算结果 */
15
+ export interface SimilarityResult {
16
+ /** 匹配到的现有条目 */
17
+ entry: KbEntry;
18
+ /** Jaccard 相似度(0.0 ~ 1.0) */
19
+ similarity: number;
20
+ }
21
+ /**
22
+ * 在指定分类中查找与新内容相似的现有条目。
23
+ * 遍历分类文件中的所有条目,对每条条目计算 Jaccard 相似度。
24
+ *
25
+ * @param target - 新待归档的内容文本
26
+ * @param category - 知识库分类名(architecture | patterns | troubleshooting | setup)
27
+ * @returns 相似度 > 0 的条目列表,按相似度降序排列
28
+ */
29
+ export declare function findSimilarEntries(target: string, category: string): SimilarityResult[];
30
+ /**
31
+ * 判断相似度是否达到更新阈值(> 0.8)。
32
+ *
33
+ * @param similarity - Jaccard 相似度值
34
+ * @returns 相似度 > 0.8 时返回 true,否则返回 false
35
+ */
36
+ export declare function shouldUpdate(similarity: number): boolean;
37
+ /**
38
+ * 合并新旧条目内容。
39
+ * 保留原有 `[+]` / `[-]` 标记和日期信息,新内容以「更新于」块追加到条目末尾。
40
+ *
41
+ * @param existing - 已有的知识库条目
42
+ * @param newContent - 新的待合并内容
43
+ * @returns 合并后的条目(日期和标记来自原条目,内容为原文 + 更新块)
44
+ */
45
+ export declare function mergeEntry(existing: KbEntry, newContent: string): KbEntry;
46
+ //# sourceMappingURL=kb-dedup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kb-dedup.d.ts","sourceRoot":"","sources":["../../src/utils/kb-dedup.ts"],"names":[],"mappings":"AAOA,cAAc;AACd,MAAM,WAAW,OAAO;IACtB,6BAA6B;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,yBAAyB;IACzB,MAAM,EAAE,GAAG,GAAG,GAAG,CAAC;IAClB,kCAAkC;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,uCAAuC;IACvC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,cAAc;AACd,MAAM,WAAW,gBAAgB;IAC/B,eAAe;IACf,KAAK,EAAE,OAAO,CAAC;IACf,6BAA6B;IAC7B,UAAU,EAAE,MAAM,CAAC;CACpB;AAyHD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,gBAAgB,EAAE,CA2BvF;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAezE"}
@@ -0,0 +1,169 @@
1
+ /**
2
+ * 知识库去重模块
3
+ * 归档前检索现有条目,相似度 > 80% 时执行更新而非新增,避免 kb/ 中产生重复条目。
4
+ */
5
+ import { readFileSync, existsSync } from 'node:fs';
6
+ import { resolve } from 'node:path';
7
+ /** 相似度阈值,超过此值视为重复 */
8
+ const SIMILARITY_THRESHOLD = 0.8;
9
+ /** 知识库分类文件所在的基础目录 */
10
+ const KB_BASE_DIR = resolve('.openfeel/kb');
11
+ /** 分类名 → 文件名映射 */
12
+ const CATEGORY_FILES = {
13
+ architecture: 'architecture.md',
14
+ patterns: 'patterns.md',
15
+ troubleshooting: 'troubleshooting.md',
16
+ setup: 'setup.md',
17
+ };
18
+ /**
19
+ * 读取知识库分类文件并解析为 KbEntry 列表。
20
+ * 分类文件按 `## ` 开头的标题行分割条目,每条目以 `## [+/-] 标题 (日期)` 格式开头。
21
+ *
22
+ * @param filePath - 分类文件的绝对路径
23
+ * @returns 解析出的条目列表,文件不存在时返回空数组
24
+ */
25
+ function parseKbFile(filePath) {
26
+ if (!existsSync(filePath)) {
27
+ return [];
28
+ }
29
+ const content = readFileSync(filePath, 'utf-8');
30
+ const lines = content.split('\n');
31
+ const entries = [];
32
+ let i = 0;
33
+ while (i < lines.length) {
34
+ const line = lines[i];
35
+ // 匹配 ## [+] / ## [-] 开头的标题行
36
+ const headerMatch = line.match(/^##\s+\[([+-])\]\s+(.+?)\s+\((\d{4}-\d{2}-\d{2})\)$/);
37
+ if (headerMatch === null) {
38
+ i++;
39
+ continue;
40
+ }
41
+ const status = headerMatch[1];
42
+ const title = headerMatch[2];
43
+ const date = headerMatch[3];
44
+ // 收集条目正文(从下一行到下一个 ## 或文件末尾)
45
+ const bodyLines = [];
46
+ let j = i + 1;
47
+ while (j < lines.length && !lines[j].startsWith('## ')) {
48
+ bodyLines.push(lines[j]);
49
+ j++;
50
+ }
51
+ const entry = {
52
+ title,
53
+ date,
54
+ status,
55
+ content: bodyLines.join('\n').trim(),
56
+ rawLine: line,
57
+ };
58
+ entries.push(entry);
59
+ i = j; // 跳到下一个条目起始行
60
+ }
61
+ return entries;
62
+ }
63
+ /**
64
+ * 对文本做词袋分词,用于 Jaccard 相似度计算。
65
+ * 分词策略:按空白字符和常见标点切分,过滤空 token 和纯标点 token。
66
+ * [+] / [-] 标记不参与相似度计算(避免禁用标记变化影响匹配)。
67
+ *
68
+ * @param text - 待分词的文本
69
+ * @returns 去重后的 token 集合
70
+ */
71
+ function tokenize(text) {
72
+ // 去除行首的 [+] / [-] 标记(如 "## [+]" 中的状态标记)
73
+ const cleaned = text.replace(/^\[[+-]\](?!\s*\()/gm, '');
74
+ // 按空白和标点切分,保留中英文词汇
75
+ const tokens = cleaned
76
+ .toLowerCase()
77
+ .split(/[\s,,。.、;;::!!??()()【】\[\]{}""''""\/\\|@#$%^&*+=~`<>]+/)
78
+ .filter(t => t.length > 0 && /[\w\u4e00-\u9fff]/.test(t));
79
+ return new Set(tokens);
80
+ }
81
+ /**
82
+ * 计算两个词袋之间的 Jaccard 相似度。
83
+ * 公式:|A∩B| / |A∪B|
84
+ *
85
+ * @param tokensA - 文本 A 的词袋
86
+ * @param tokensB - 文本 B 的词袋
87
+ * @returns 0.0 到 1.0 之间的相似度值
88
+ */
89
+ function jaccardSimilarity(tokensA, tokensB) {
90
+ // 两个空文本时视为完全相同
91
+ if (tokensA.size === 0 && tokensB.size === 0) {
92
+ return 1.0;
93
+ }
94
+ // 计算交集大小
95
+ let intersection = 0;
96
+ for (const token of tokensA) {
97
+ if (tokensB.has(token)) {
98
+ intersection++;
99
+ }
100
+ }
101
+ // 计算并集大小
102
+ const union = tokensA.size + tokensB.size - intersection;
103
+ if (union === 0) {
104
+ return 0.0;
105
+ }
106
+ return intersection / union;
107
+ }
108
+ /**
109
+ * 在指定分类中查找与新内容相似的现有条目。
110
+ * 遍历分类文件中的所有条目,对每条条目计算 Jaccard 相似度。
111
+ *
112
+ * @param target - 新待归档的内容文本
113
+ * @param category - 知识库分类名(architecture | patterns | troubleshooting | setup)
114
+ * @returns 相似度 > 0 的条目列表,按相似度降序排列
115
+ */
116
+ export function findSimilarEntries(target, category) {
117
+ const fileName = CATEGORY_FILES[category];
118
+ if (fileName === undefined) {
119
+ return [];
120
+ }
121
+ const filePath = resolve(KB_BASE_DIR, fileName);
122
+ const existingEntries = parseKbFile(filePath);
123
+ if (existingEntries.length === 0) {
124
+ return [];
125
+ }
126
+ const targetTokens = tokenize(target);
127
+ const results = [];
128
+ for (const entry of existingEntries) {
129
+ const entryTokens = tokenize(entry.content);
130
+ const similarity = jaccardSimilarity(targetTokens, entryTokens);
131
+ if (similarity > 0) {
132
+ results.push({ entry, similarity });
133
+ }
134
+ }
135
+ // 按相似度降序排列
136
+ results.sort((a, b) => b.similarity - a.similarity);
137
+ return results;
138
+ }
139
+ /**
140
+ * 判断相似度是否达到更新阈值(> 0.8)。
141
+ *
142
+ * @param similarity - Jaccard 相似度值
143
+ * @returns 相似度 > 0.8 时返回 true,否则返回 false
144
+ */
145
+ export function shouldUpdate(similarity) {
146
+ return similarity > SIMILARITY_THRESHOLD;
147
+ }
148
+ /**
149
+ * 合并新旧条目内容。
150
+ * 保留原有 `[+]` / `[-]` 标记和日期信息,新内容以「更新于」块追加到条目末尾。
151
+ *
152
+ * @param existing - 已有的知识库条目
153
+ * @param newContent - 新的待合并内容
154
+ * @returns 合并后的条目(日期和标记来自原条目,内容为原文 + 更新块)
155
+ */
156
+ export function mergeEntry(existing, newContent) {
157
+ const today = new Date().toISOString().slice(0, 10);
158
+ const trimmedNew = newContent.trim();
159
+ // 如果新内容与原内容完全一致,不做无意义追加
160
+ if (trimmedNew === existing.content.trim()) {
161
+ return { ...existing };
162
+ }
163
+ const updateNote = `\n\n> **更新于 ${today}**:${trimmedNew}`;
164
+ return {
165
+ ...existing,
166
+ content: existing.content + updateNote,
167
+ };
168
+ }
169
+ //# sourceMappingURL=kb-dedup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kb-dedup.js","sourceRoot":"","sources":["../../src/utils/kb-dedup.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * 将 file:// URL 或普通路径解析为规范化文件系统路径。
3
+ * Windows 兼容:处理 file:///C:/... 格式。
4
+ *
5
+ * @param urlOrPath - file:// URL 或文件系统路径
6
+ * @returns 规范化后的绝对路径
7
+ *
8
+ * @example
9
+ * resolveFileUrl('file:///C:/project/src/index.ts') // Windows → 'C:\\project\\src\\index.ts'
10
+ * resolveFileUrl('file:///home/user/project/src/index.ts') // Linux → '/home/user/project/src/index.ts'
11
+ * resolveFileUrl('./src/index.ts') // 相对路径 → 相对于 cwd 的绝对路径
12
+ */
13
+ export declare function resolveFileUrl(urlOrPath: string): string;
14
+ /**
15
+ * 将文件系统路径转换为 file:// URL。
16
+ * Windows 兼容:C:\project\src → file:///C:/project/src
17
+ *
18
+ * @param filePath - 文件系统路径(绝对或相对)
19
+ * @returns file:// URL 字符串
20
+ */
21
+ export declare function toFileUrl(filePath: string): string;
22
+ //# sourceMappingURL=path.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../src/utils/path.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAMxD;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGlD"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * 跨平台路径工具
3
+ * 处理 file:// URL 与本地文件系统路径的相互转换
4
+ */
5
+ import { fileURLToPath, pathToFileURL } from 'node:url';
6
+ import { resolve } from 'node:path';
7
+ /**
8
+ * 将 file:// URL 或普通路径解析为规范化文件系统路径。
9
+ * Windows 兼容:处理 file:///C:/... 格式。
10
+ *
11
+ * @param urlOrPath - file:// URL 或文件系统路径
12
+ * @returns 规范化后的绝对路径
13
+ *
14
+ * @example
15
+ * resolveFileUrl('file:///C:/project/src/index.ts') // Windows → 'C:\\project\\src\\index.ts'
16
+ * resolveFileUrl('file:///home/user/project/src/index.ts') // Linux → '/home/user/project/src/index.ts'
17
+ * resolveFileUrl('./src/index.ts') // 相对路径 → 相对于 cwd 的绝对路径
18
+ */
19
+ export function resolveFileUrl(urlOrPath) {
20
+ if (urlOrPath.startsWith('file://')) {
21
+ // 处理 Windows 路径:file:///C:/... → C:/...
22
+ return fileURLToPath(urlOrPath);
23
+ }
24
+ return resolve(urlOrPath);
25
+ }
26
+ /**
27
+ * 将文件系统路径转换为 file:// URL。
28
+ * Windows 兼容:C:\project\src → file:///C:/project/src
29
+ *
30
+ * @param filePath - 文件系统路径(绝对或相对)
31
+ * @returns file:// URL 字符串
32
+ */
33
+ export function toFileUrl(filePath) {
34
+ const absolutePath = resolve(filePath);
35
+ return pathToFileURL(absolutePath).href;
36
+ }
37
+ //# sourceMappingURL=path.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path.js","sourceRoot":"","sources":["../../src/utils/path.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,cAAc,CAAC,SAAiB;IAC9C,IAAI,SAAS,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QACpC,wCAAwC;QACxC,OAAO,aAAa,CAAC,SAA+B,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,OAAO,CAAC,SAAS,CAAC,CAAC;AAC5B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,QAAgB;IACxC,MAAM,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACvC,OAAO,aAAa,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC;AAC1C,CAAC"}