aifastdb 2.2.2 → 2.2.6

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.
@@ -138,6 +138,7 @@ class DevPlanStore {
138
138
  this.projectName = projectName;
139
139
  this.docStore = new native_1.EnhancedDocumentStore(config.documentPath, (0, document_store_1.documentStoreProductionConfig)());
140
140
  this.taskStore = new native_1.EnhancedDocumentStore(config.taskPath, (0, document_store_1.documentStoreProductionConfig)());
141
+ this.moduleStore = new native_1.EnhancedDocumentStore(config.modulePath, (0, document_store_1.documentStoreProductionConfig)());
141
142
  }
142
143
  // ==========================================================================
143
144
  // Document Section Operations
@@ -155,15 +156,20 @@ class DevPlanStore {
155
156
  }
156
157
  const version = input.version || '1.0.0';
157
158
  const now = Date.now();
159
+ const finalModuleId = input.moduleId || existing?.moduleId;
160
+ const tags = [
161
+ `plan:${this.projectName}`,
162
+ `section:${input.section}`,
163
+ ...(input.subSection ? [`sub:${input.subSection}`] : []),
164
+ `ver:${version}`,
165
+ ];
166
+ if (finalModuleId) {
167
+ tags.push(`module:${finalModuleId}`);
168
+ }
158
169
  const docInput = {
159
170
  content: input.content,
160
171
  contentType: native_2.ContentType.Text,
161
- tags: [
162
- `plan:${this.projectName}`,
163
- `section:${input.section}`,
164
- ...(input.subSection ? [`sub:${input.subSection}`] : []),
165
- `ver:${version}`,
166
- ],
172
+ tags,
167
173
  metadata: {
168
174
  projectName: this.projectName,
169
175
  section: input.section,
@@ -171,6 +177,7 @@ class DevPlanStore {
171
177
  version,
172
178
  subSection: input.subSection || null,
173
179
  relatedSections: input.relatedSections || [],
180
+ moduleId: finalModuleId || null,
174
181
  createdAt: existing?.createdAt || now,
175
182
  updatedAt: now,
176
183
  },
@@ -302,20 +309,25 @@ class DevPlanStore {
302
309
  totalSubtasks: 0,
303
310
  completedSubtasks: 0,
304
311
  };
312
+ const tags = [
313
+ `plan:${this.projectName}`,
314
+ 'type:main-task',
315
+ `mtask:${input.taskId}`,
316
+ `priority:${input.priority}`,
317
+ 'status:pending',
318
+ ];
319
+ if (input.moduleId) {
320
+ tags.push(`module:${input.moduleId}`);
321
+ }
305
322
  const docInput = {
306
323
  content: JSON.stringify(taskData),
307
324
  contentType: native_2.ContentType.Text,
308
- tags: [
309
- `plan:${this.projectName}`,
310
- 'type:main-task',
311
- `mtask:${input.taskId}`,
312
- `priority:${input.priority}`,
313
- 'status:pending',
314
- ],
325
+ tags,
315
326
  metadata: {
316
327
  projectName: this.projectName,
317
328
  taskId: input.taskId,
318
329
  status: 'pending',
330
+ moduleId: input.moduleId || null,
319
331
  createdAt: now,
320
332
  updatedAt: now,
321
333
  completedAt: null,
@@ -328,6 +340,7 @@ class DevPlanStore {
328
340
  id,
329
341
  projectName: this.projectName,
330
342
  ...taskData,
343
+ moduleId: input.moduleId,
331
344
  status: 'pending',
332
345
  createdAt: now,
333
346
  updatedAt: now,
@@ -378,6 +391,7 @@ class DevPlanStore {
378
391
  this.deleteAndEnsureTimestampAdvance(this.taskStore, existing.id);
379
392
  const now = Date.now();
380
393
  const completedAt = finalStatus === 'completed' ? (existing.completedAt || now) : null;
394
+ const finalModuleId = input.moduleId || existing.moduleId;
381
395
  const taskData = {
382
396
  taskId: input.taskId,
383
397
  title: input.title,
@@ -388,20 +402,25 @@ class DevPlanStore {
388
402
  totalSubtasks: existing.totalSubtasks,
389
403
  completedSubtasks: existing.completedSubtasks,
390
404
  };
405
+ const tags = [
406
+ `plan:${this.projectName}`,
407
+ 'type:main-task',
408
+ `mtask:${input.taskId}`,
409
+ `priority:${input.priority}`,
410
+ `status:${finalStatus}`,
411
+ ];
412
+ if (finalModuleId) {
413
+ tags.push(`module:${finalModuleId}`);
414
+ }
391
415
  const docInput = {
392
416
  content: JSON.stringify(taskData),
393
417
  contentType: native_2.ContentType.Text,
394
- tags: [
395
- `plan:${this.projectName}`,
396
- 'type:main-task',
397
- `mtask:${input.taskId}`,
398
- `priority:${input.priority}`,
399
- `status:${finalStatus}`,
400
- ],
418
+ tags,
401
419
  metadata: {
402
420
  projectName: this.projectName,
403
421
  taskId: input.taskId,
404
422
  status: finalStatus,
423
+ moduleId: finalModuleId || null,
405
424
  createdAt: existing.createdAt,
406
425
  updatedAt: now,
407
426
  completedAt,
@@ -414,6 +433,7 @@ class DevPlanStore {
414
433
  ...taskData,
415
434
  id,
416
435
  projectName: this.projectName,
436
+ moduleId: finalModuleId,
417
437
  status: finalStatus,
418
438
  createdAt: existing.createdAt,
419
439
  updatedAt: now,
@@ -454,6 +474,10 @@ class DevPlanStore {
454
474
  const priorityTag = `priority:${filter.priority}`;
455
475
  docs = docs.filter((doc) => doc.tags.includes(priorityTag));
456
476
  }
477
+ if (filter?.moduleId) {
478
+ const moduleTag = `module:${filter.moduleId}`;
479
+ docs = docs.filter((doc) => doc.tags.includes(moduleTag));
480
+ }
457
481
  return docs.map((doc) => this.docToMainTask(doc));
458
482
  }
459
483
  /**
@@ -476,20 +500,25 @@ class DevPlanStore {
476
500
  totalSubtasks: mainTask.totalSubtasks,
477
501
  completedSubtasks: mainTask.completedSubtasks,
478
502
  };
503
+ const tags = [
504
+ `plan:${this.projectName}`,
505
+ 'type:main-task',
506
+ `mtask:${mainTask.taskId}`,
507
+ `priority:${mainTask.priority}`,
508
+ `status:${status}`,
509
+ ];
510
+ if (mainTask.moduleId) {
511
+ tags.push(`module:${mainTask.moduleId}`);
512
+ }
479
513
  const docInput = {
480
514
  content: JSON.stringify(taskData),
481
515
  contentType: native_2.ContentType.Text,
482
- tags: [
483
- `plan:${this.projectName}`,
484
- 'type:main-task',
485
- `mtask:${mainTask.taskId}`,
486
- `priority:${mainTask.priority}`,
487
- `status:${status}`,
488
- ],
516
+ tags,
489
517
  metadata: {
490
518
  projectName: this.projectName,
491
519
  taskId: mainTask.taskId,
492
520
  status,
521
+ moduleId: mainTask.moduleId || null,
493
522
  createdAt: mainTask.createdAt,
494
523
  updatedAt: now,
495
524
  completedAt,
@@ -968,6 +997,196 @@ class DevPlanStore {
968
997
  return md;
969
998
  }
970
999
  // ==========================================================================
1000
+ // Module Operations
1001
+ // ==========================================================================
1002
+ /**
1003
+ * 创建功能模块
1004
+ */
1005
+ createModule(input) {
1006
+ const existing = this.getModule(input.moduleId);
1007
+ if (existing) {
1008
+ throw new Error(`Module "${input.moduleId}" already exists for project "${this.projectName}"`);
1009
+ }
1010
+ const now = Date.now();
1011
+ const status = input.status || 'active';
1012
+ const moduleData = {
1013
+ moduleId: input.moduleId,
1014
+ name: input.name,
1015
+ description: input.description || '',
1016
+ };
1017
+ const docInput = {
1018
+ content: JSON.stringify(moduleData),
1019
+ contentType: native_2.ContentType.Text,
1020
+ tags: [
1021
+ `plan:${this.projectName}`,
1022
+ 'type:module',
1023
+ `module:${input.moduleId}`,
1024
+ `status:${status}`,
1025
+ ],
1026
+ metadata: {
1027
+ projectName: this.projectName,
1028
+ moduleId: input.moduleId,
1029
+ status,
1030
+ createdAt: now,
1031
+ updatedAt: now,
1032
+ },
1033
+ importance: 0.85,
1034
+ };
1035
+ const id = this.moduleStore.put(docInput);
1036
+ this.moduleStore.flush();
1037
+ return {
1038
+ id,
1039
+ projectName: this.projectName,
1040
+ moduleId: input.moduleId,
1041
+ name: input.name,
1042
+ description: input.description,
1043
+ status,
1044
+ mainTaskCount: 0,
1045
+ subTaskCount: 0,
1046
+ completedSubTaskCount: 0,
1047
+ docCount: 0,
1048
+ createdAt: now,
1049
+ updatedAt: now,
1050
+ };
1051
+ }
1052
+ /**
1053
+ * 获取功能模块(含自动计算的 taskCount/docCount)
1054
+ */
1055
+ getModule(moduleId) {
1056
+ const tag = `module:${moduleId}`;
1057
+ const docs = this.moduleStore.findByTag(tag)
1058
+ .filter((doc) => doc.tags.includes(`plan:${this.projectName}`));
1059
+ if (docs.length === 0)
1060
+ return null;
1061
+ const latest = docs.sort((a, b) => this.getDocUpdatedAt(b) - this.getDocUpdatedAt(a))[0];
1062
+ return this.docToModule(latest);
1063
+ }
1064
+ /**
1065
+ * 列出所有功能模块
1066
+ */
1067
+ listModules(filter) {
1068
+ let docs = this.moduleStore.findByTag(`plan:${this.projectName}`)
1069
+ .filter((doc) => doc.tags.includes('type:module'));
1070
+ // 按 moduleId 去重
1071
+ const latestMap = new Map();
1072
+ for (const doc of docs) {
1073
+ const data = JSON.parse(doc.content);
1074
+ const moduleId = data.moduleId;
1075
+ if (!moduleId)
1076
+ continue;
1077
+ const existing = latestMap.get(moduleId);
1078
+ if (!existing || this.getDocUpdatedAt(doc) > this.getDocUpdatedAt(existing)) {
1079
+ latestMap.set(moduleId, doc);
1080
+ }
1081
+ }
1082
+ docs = Array.from(latestMap.values());
1083
+ if (filter?.status) {
1084
+ const statusTag = `status:${filter.status}`;
1085
+ docs = docs.filter((doc) => doc.tags.includes(statusTag));
1086
+ }
1087
+ return docs.map((doc) => this.docToModule(doc));
1088
+ }
1089
+ /**
1090
+ * 更新功能模块
1091
+ */
1092
+ updateModule(moduleId, updates) {
1093
+ const existing = this.getModule(moduleId);
1094
+ if (!existing)
1095
+ return null;
1096
+ this.deleteAndEnsureTimestampAdvance(this.moduleStore, existing.id);
1097
+ const now = Date.now();
1098
+ const newName = updates.name || existing.name;
1099
+ const newDescription = updates.description !== undefined ? updates.description : existing.description;
1100
+ const newStatus = updates.status || existing.status;
1101
+ const moduleData = {
1102
+ moduleId,
1103
+ name: newName,
1104
+ description: newDescription || '',
1105
+ };
1106
+ const docInput = {
1107
+ content: JSON.stringify(moduleData),
1108
+ contentType: native_2.ContentType.Text,
1109
+ tags: [
1110
+ `plan:${this.projectName}`,
1111
+ 'type:module',
1112
+ `module:${moduleId}`,
1113
+ `status:${newStatus}`,
1114
+ ],
1115
+ metadata: {
1116
+ projectName: this.projectName,
1117
+ moduleId,
1118
+ status: newStatus,
1119
+ createdAt: existing.createdAt,
1120
+ updatedAt: now,
1121
+ },
1122
+ importance: 0.85,
1123
+ };
1124
+ const id = this.moduleStore.put(docInput);
1125
+ this.moduleStore.flush();
1126
+ return {
1127
+ id,
1128
+ projectName: this.projectName,
1129
+ moduleId,
1130
+ name: newName,
1131
+ description: newDescription,
1132
+ status: newStatus,
1133
+ mainTaskCount: existing.mainTaskCount,
1134
+ subTaskCount: existing.subTaskCount,
1135
+ completedSubTaskCount: existing.completedSubTaskCount,
1136
+ docCount: existing.docCount,
1137
+ createdAt: existing.createdAt,
1138
+ updatedAt: now,
1139
+ };
1140
+ }
1141
+ /**
1142
+ * 删除功能模块
1143
+ */
1144
+ deleteModule(moduleId) {
1145
+ const existing = this.getModule(moduleId);
1146
+ if (!existing)
1147
+ return false;
1148
+ this.moduleStore.delete(existing.id);
1149
+ this.moduleStore.flush();
1150
+ return true;
1151
+ }
1152
+ /**
1153
+ * 获取模块详情 — 包含关联的任务和文档
1154
+ */
1155
+ getModuleDetail(moduleId) {
1156
+ const mod = this.getModule(moduleId);
1157
+ if (!mod)
1158
+ return null;
1159
+ // 获取关联的主任务
1160
+ const moduleTag = `module:${moduleId}`;
1161
+ let taskDocs = this.taskStore.findByTag(moduleTag)
1162
+ .filter((doc) => doc.tags.includes(`plan:${this.projectName}`) &&
1163
+ doc.tags.includes('type:main-task'));
1164
+ taskDocs = this.deduplicateByTaskId(taskDocs);
1165
+ const mainTasks = taskDocs.map((doc) => this.docToMainTask(doc));
1166
+ // 获取关联的所有子任务(通过主任务间接关联)
1167
+ const subTasks = [];
1168
+ for (const mt of mainTasks) {
1169
+ const subs = this.listSubTasks(mt.taskId);
1170
+ subTasks.push(...subs);
1171
+ }
1172
+ // 获取关联的文档
1173
+ let docDocs = this.docStore.findByTag(moduleTag)
1174
+ .filter((doc) => doc.tags.includes(`plan:${this.projectName}`));
1175
+ // 按 section+subSection 去重
1176
+ const latestDocMap = new Map();
1177
+ for (const doc of docDocs) {
1178
+ const sectionTag = doc.tags.find((t) => t.startsWith('section:'));
1179
+ const subTag = doc.tags.find((t) => t.startsWith('sub:'));
1180
+ const key = `${sectionTag || 'unknown'}|${subTag || ''}`;
1181
+ const ex = latestDocMap.get(key);
1182
+ if (!ex || this.getDocUpdatedAt(doc) > this.getDocUpdatedAt(ex)) {
1183
+ latestDocMap.set(key, doc);
1184
+ }
1185
+ }
1186
+ const documents = Array.from(latestDocMap.values()).map((doc) => this.docToDevPlanDoc(doc));
1187
+ return { module: mod, mainTasks, subTasks, documents };
1188
+ }
1189
+ // ==========================================================================
971
1190
  // Utility
972
1191
  // ==========================================================================
973
1192
  /**
@@ -976,6 +1195,7 @@ class DevPlanStore {
976
1195
  sync() {
977
1196
  this.docStore.flush();
978
1197
  this.taskStore.flush();
1198
+ this.moduleStore.flush();
979
1199
  }
980
1200
  /**
981
1201
  * 获取项目名称
@@ -1058,6 +1278,8 @@ class DevPlanStore {
1058
1278
  const section = (sectionTag?.replace('section:', '') || 'custom');
1059
1279
  const subTag = doc.tags.find((t) => t.startsWith('sub:'));
1060
1280
  const subSection = subTag?.replace('sub:', '');
1281
+ const moduleTag = doc.tags.find((t) => t.startsWith('module:'));
1282
+ const moduleId = moduleTag?.replace('module:', '') || undefined;
1061
1283
  return {
1062
1284
  id: doc.id,
1063
1285
  projectName: this.projectName,
@@ -1067,6 +1289,7 @@ class DevPlanStore {
1067
1289
  version: doc.metadata?.version || '1.0.0',
1068
1290
  subSection,
1069
1291
  relatedSections: doc.metadata?.relatedSections || [],
1292
+ moduleId,
1070
1293
  createdAt: doc.metadata?.createdAt || doc.createdAt,
1071
1294
  updatedAt: doc.metadata?.updatedAt || doc.createdAt,
1072
1295
  };
@@ -1075,6 +1298,8 @@ class DevPlanStore {
1075
1298
  const data = JSON.parse(doc.content);
1076
1299
  const statusTag = doc.tags.find((t) => t.startsWith('status:'));
1077
1300
  const status = (statusTag?.replace('status:', '') || 'pending');
1301
+ const moduleTag = doc.tags.find((t) => t.startsWith('module:'));
1302
+ const moduleId = moduleTag?.replace('module:', '') || undefined;
1078
1303
  return {
1079
1304
  id: doc.id,
1080
1305
  projectName: this.projectName,
@@ -1084,6 +1309,7 @@ class DevPlanStore {
1084
1309
  description: data.description,
1085
1310
  estimatedHours: data.estimatedHours,
1086
1311
  relatedSections: data.relatedSections || [],
1312
+ moduleId,
1087
1313
  totalSubtasks: data.totalSubtasks || 0,
1088
1314
  completedSubtasks: data.completedSubtasks || 0,
1089
1315
  status,
@@ -1092,6 +1318,71 @@ class DevPlanStore {
1092
1318
  completedAt: doc.metadata?.completedAt || null,
1093
1319
  };
1094
1320
  }
1321
+ docToModule(doc) {
1322
+ const data = JSON.parse(doc.content);
1323
+ const statusTag = doc.tags.find((t) => t.startsWith('status:'));
1324
+ const status = (statusTag?.replace('status:', '') || 'active');
1325
+ const moduleId = data.moduleId;
1326
+ // 计算关联的主任务数(去重)
1327
+ const moduleTag = `module:${moduleId}`;
1328
+ const taskDocs = this.taskStore.findByTag(moduleTag)
1329
+ .filter((d) => d.tags.includes(`plan:${this.projectName}`) &&
1330
+ d.tags.includes('type:main-task'));
1331
+ const uniqueTaskIds = new Set();
1332
+ for (const td of taskDocs) {
1333
+ try {
1334
+ uniqueTaskIds.add(JSON.parse(td.content).taskId);
1335
+ }
1336
+ catch { }
1337
+ }
1338
+ // 计算关联的子任务数(遍历关联主任务下的所有子任务)
1339
+ let subTaskCount = 0;
1340
+ let completedSubTaskCount = 0;
1341
+ for (const mainTaskId of uniqueTaskIds) {
1342
+ const subDocs = this.taskStore.findByTag(`parent:${mainTaskId}`)
1343
+ .filter((d) => d.tags.includes(`plan:${this.projectName}`) &&
1344
+ d.tags.includes('type:sub-task'));
1345
+ // 按 taskId 去重
1346
+ const seenSubIds = new Set();
1347
+ for (const sd of subDocs) {
1348
+ try {
1349
+ const subData = JSON.parse(sd.content);
1350
+ if (seenSubIds.has(subData.taskId))
1351
+ continue;
1352
+ seenSubIds.add(subData.taskId);
1353
+ subTaskCount++;
1354
+ const subStatusTag = sd.tags.find((t) => t.startsWith('status:'));
1355
+ if (subStatusTag === 'status:completed') {
1356
+ completedSubTaskCount++;
1357
+ }
1358
+ }
1359
+ catch { }
1360
+ }
1361
+ }
1362
+ // 计算关联的文档数(按 section+subSection 去重)
1363
+ const docDocs = this.docStore.findByTag(moduleTag)
1364
+ .filter((d) => d.tags.includes(`plan:${this.projectName}`));
1365
+ const uniqueDocKeys = new Set();
1366
+ for (const dd of docDocs) {
1367
+ const st = dd.tags.find((t) => t.startsWith('section:'));
1368
+ const sub = dd.tags.find((t) => t.startsWith('sub:'));
1369
+ uniqueDocKeys.add(`${st || ''}|${sub || ''}`);
1370
+ }
1371
+ return {
1372
+ id: doc.id,
1373
+ projectName: this.projectName,
1374
+ moduleId,
1375
+ name: data.name,
1376
+ description: data.description || undefined,
1377
+ status,
1378
+ mainTaskCount: uniqueTaskIds.size,
1379
+ subTaskCount,
1380
+ completedSubTaskCount,
1381
+ docCount: uniqueDocKeys.size,
1382
+ createdAt: doc.metadata?.createdAt || doc.createdAt,
1383
+ updatedAt: doc.metadata?.updatedAt || doc.createdAt,
1384
+ };
1385
+ }
1095
1386
  docToSubTask(doc) {
1096
1387
  const data = JSON.parse(doc.content);
1097
1388
  const statusTag = doc.tags.find((t) => t.startsWith('status:'));
@@ -1140,20 +1431,25 @@ class DevPlanStore {
1140
1431
  totalSubtasks: subs.length,
1141
1432
  completedSubtasks: completedCount,
1142
1433
  };
1434
+ const tags = [
1435
+ `plan:${this.projectName}`,
1436
+ 'type:main-task',
1437
+ `mtask:${mainTask.taskId}`,
1438
+ `priority:${mainTask.priority}`,
1439
+ `status:${mainTask.status}`,
1440
+ ];
1441
+ if (mainTask.moduleId) {
1442
+ tags.push(`module:${mainTask.moduleId}`);
1443
+ }
1143
1444
  const docInput = {
1144
1445
  content: JSON.stringify(taskData),
1145
1446
  contentType: native_2.ContentType.Text,
1146
- tags: [
1147
- `plan:${this.projectName}`,
1148
- 'type:main-task',
1149
- `mtask:${mainTask.taskId}`,
1150
- `priority:${mainTask.priority}`,
1151
- `status:${mainTask.status}`,
1152
- ],
1447
+ tags,
1153
1448
  metadata: {
1154
1449
  projectName: this.projectName,
1155
1450
  taskId: mainTask.taskId,
1156
1451
  status: mainTask.status,
1452
+ moduleId: mainTask.moduleId || null,
1157
1453
  createdAt: mainTask.createdAt,
1158
1454
  updatedAt: now,
1159
1455
  completedAt: mainTask.completedAt,
@@ -1335,6 +1631,7 @@ function createDevPlan(projectName, basePath) {
1335
1631
  return new DevPlanStore(projectName, {
1336
1632
  documentPath: path.join(base, projectName, 'documents.jsonl'),
1337
1633
  taskPath: path.join(base, projectName, 'tasks.jsonl'),
1634
+ modulePath: path.join(base, projectName, 'modules.jsonl'),
1338
1635
  });
1339
1636
  }
1340
1637
  /**