@siming-org/core 0.7.3 → 0.8.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.
- package/dist/index.d.ts +21 -8
- package/dist/index.js +49 -5
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1294,24 +1294,26 @@ type TaskRepo = Repo<Task> & {
|
|
|
1294
1294
|
declare function createTaskRepo(db: Db): TaskRepo;
|
|
1295
1295
|
|
|
1296
1296
|
/**
|
|
1297
|
-
* Issue 相关 Schemas(T202609150002
|
|
1298
|
-
* 小问题轻量跟进:入池 → 整理(合并/拆分)→
|
|
1297
|
+
* Issue 相关 Schemas(T202609150002 问题池;T202609200001 直接标记完成 + 审批原话)
|
|
1298
|
+
* 小问题轻量跟进:入池 → 整理(合并/拆分)→ 转任务(多对多)或直接标记完成。
|
|
1299
1299
|
*
|
|
1300
|
-
* 状态语义(PRD 3.2
|
|
1301
|
-
* - pending 待整理 / partial 部分转任务(存在未覆盖遗留)/ converted 已转任务 / cancelled 已取消
|
|
1300
|
+
* 状态语义(PRD 3.2 四态基础上 T202609200001 增 done,终态禁止回转):
|
|
1301
|
+
* - pending 待整理 / partial 部分转任务(存在未覆盖遗留)/ converted 已转任务 / cancelled 已取消 / done 已直接标记完成
|
|
1302
|
+
* - done:无需转任务、在某个任务/改动中顺带解决时的人工收尾终态(taskLinks 保留——已建立关联时进度可读)
|
|
1302
1303
|
* - 任务后续演进(完成/取消)不触碰问题状态,进度是读时聚合(taskLinks × tasks.status)
|
|
1303
1304
|
*
|
|
1304
1305
|
* 关联模型(D1):单一真相源在 Issue 侧(taskLinks 嵌入数组),Task 零改动;
|
|
1305
1306
|
* 多对多,同项目内组合;取消问题时 taskLinks 终止条目拷入 history(D8 结构化追溯)。
|
|
1306
1307
|
*/
|
|
1307
|
-
/** 池内状态(终态 = converted / cancelled,状态机保护见 issue.repo) */
|
|
1308
|
-
declare const ISSUE_STATUSES: readonly ["pending", "partial", "converted", "cancelled"];
|
|
1308
|
+
/** 池内状态(终态 = converted / cancelled / done,状态机保护见 issue.repo) */
|
|
1309
|
+
declare const ISSUE_STATUSES: readonly ["pending", "partial", "converted", "cancelled", "done"];
|
|
1309
1310
|
type IssueStatus = (typeof ISSUE_STATUSES)[number];
|
|
1310
1311
|
declare const IssueStatusSchema: z.ZodEnum<{
|
|
1311
1312
|
pending: "pending";
|
|
1312
1313
|
cancelled: "cancelled";
|
|
1313
1314
|
partial: "partial";
|
|
1314
1315
|
converted: "converted";
|
|
1316
|
+
done: "done";
|
|
1315
1317
|
}>;
|
|
1316
1318
|
/** 可参与转出/取消的非终态集合(事务内条件更新的并发安全带) */
|
|
1317
1319
|
declare const ISSUE_ACTIVE_STATUSES: readonly ["pending", "partial"];
|
|
@@ -1360,12 +1362,14 @@ declare const IssueHistoryEntrySchema: z.ZodObject<{
|
|
|
1360
1362
|
cancelled: "cancelled";
|
|
1361
1363
|
partial: "partial";
|
|
1362
1364
|
converted: "converted";
|
|
1365
|
+
done: "done";
|
|
1363
1366
|
}>>;
|
|
1364
1367
|
to: z.ZodOptional<z.ZodEnum<{
|
|
1365
1368
|
pending: "pending";
|
|
1366
1369
|
cancelled: "cancelled";
|
|
1367
1370
|
partial: "partial";
|
|
1368
1371
|
converted: "converted";
|
|
1372
|
+
done: "done";
|
|
1369
1373
|
}>>;
|
|
1370
1374
|
taskId: z.ZodOptional<z.ZodString>;
|
|
1371
1375
|
reason: z.ZodOptional<z.ZodString>;
|
|
@@ -1388,7 +1392,9 @@ declare const IssueSchema: z.ZodObject<{
|
|
|
1388
1392
|
cancelled: "cancelled";
|
|
1389
1393
|
partial: "partial";
|
|
1390
1394
|
converted: "converted";
|
|
1395
|
+
done: "done";
|
|
1391
1396
|
}>>;
|
|
1397
|
+
approved: z.ZodOptional<z.ZodString>;
|
|
1392
1398
|
taskLinks: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
1393
1399
|
taskId: z.ZodString;
|
|
1394
1400
|
mode: z.ZodEnum<{
|
|
@@ -1410,12 +1416,14 @@ declare const IssueSchema: z.ZodObject<{
|
|
|
1410
1416
|
cancelled: "cancelled";
|
|
1411
1417
|
partial: "partial";
|
|
1412
1418
|
converted: "converted";
|
|
1419
|
+
done: "done";
|
|
1413
1420
|
}>>;
|
|
1414
1421
|
to: z.ZodOptional<z.ZodEnum<{
|
|
1415
1422
|
pending: "pending";
|
|
1416
1423
|
cancelled: "cancelled";
|
|
1417
1424
|
partial: "partial";
|
|
1418
1425
|
converted: "converted";
|
|
1426
|
+
done: "done";
|
|
1419
1427
|
}>>;
|
|
1420
1428
|
taskId: z.ZodOptional<z.ZodString>;
|
|
1421
1429
|
reason: z.ZodOptional<z.ZodString>;
|
|
@@ -1428,10 +1436,13 @@ type Issue = z.infer<typeof IssueSchema>;
|
|
|
1428
1436
|
/**
|
|
1429
1437
|
* 录入输入:source/projectId 由服务端按通道/项目解析注入,不入客户端 schema
|
|
1430
1438
|
* (source 是统计信息非权限依据;projectId 缺省按 key=default 解析)。
|
|
1439
|
+
* approved(T202609200001):人类审批原话逐字(1-500 字);AI 通道(mcp/cli)强制在 server 路由层
|
|
1440
|
+
* (source 感知),schema 保持通道中立——Web 录入无此字段。
|
|
1431
1441
|
*/
|
|
1432
1442
|
declare const IssueCreateSchema: z.ZodObject<{
|
|
1433
1443
|
title: z.ZodString;
|
|
1434
1444
|
description: z.ZodOptional<z.ZodString>;
|
|
1445
|
+
approved: z.ZodOptional<z.ZodString>;
|
|
1435
1446
|
}, z.core.$strip>;
|
|
1436
1447
|
type IssueCreate = z.infer<typeof IssueCreateSchema>;
|
|
1437
1448
|
/** 编辑输入(独立 object 不派生——Zod4 UpdateSchema 范式;任意状态可编辑,终态无副作用) */
|
|
@@ -1473,8 +1484,8 @@ type TaskIssueView = {
|
|
|
1473
1484
|
};
|
|
1474
1485
|
|
|
1475
1486
|
/**
|
|
1476
|
-
* Issue 仓储(T202609150002)
|
|
1477
|
-
* 状态机保护在此层:终态(converted/cancelled)禁止 cancel/convert
|
|
1487
|
+
* Issue 仓储(T202609150002;T202609200001 直接标记完成 done)
|
|
1488
|
+
* 状态机保护在此层:终态(converted/cancelled/done)禁止 cancel/convert/markDone 写入——
|
|
1478
1489
|
* 条件更新双保险(filter 携带 status ∈ {pending, partial},命中 0 行即并发终态)。
|
|
1479
1490
|
* 进度计算两步批查(D2:不用 $lookup——Zod parse 单源 + 一次 $in 往返 + 内存映射)。
|
|
1480
1491
|
*/
|
|
@@ -1511,6 +1522,8 @@ type IssueRepo = Repo<Issue> & {
|
|
|
1511
1522
|
getByIssueId(issueId: string): Promise<Issue | null>;
|
|
1512
1523
|
updateIssue(issueId: string, patch: IssueUpdate): Promise<Issue>;
|
|
1513
1524
|
cancelIssue(issueId: string, reason?: string): Promise<Issue>;
|
|
1525
|
+
/** 直接标记完成(T202609200001):终态三值互斥;taskLinks 保留(D3),note 落 history reason */
|
|
1526
|
+
markDone(issueId: string, note?: string): Promise<Issue>;
|
|
1514
1527
|
/** 列表(进度聚合 + view=open 过滤;两支合并 createdAt 降序统一切片) */
|
|
1515
1528
|
listIssues(filter?: IssueListFilter): Promise<{
|
|
1516
1529
|
items: IssueWithProgress[];
|
package/dist/index.js
CHANGED
|
@@ -157,7 +157,8 @@ var BIZ_CODE_MESSAGES = {
|
|
|
157
157
|
UPGRADE_DECISION_REQUIRED: "\u672C\u5730\u5DF2\u4FEE\u6539\u7684\u8282\u70B9\u5FC5\u987B\u663E\u5F0F\u51B3\u7B56\uFF08upgrade/keep/skip\uFF09",
|
|
158
158
|
UPGRADE_STALE: "\u6A21\u677F\u72B6\u6001\u4E0E\u5347\u7EA7\u8BA1\u5212\u4E0D\u7B26\uFF08\u8BA1\u5212\u540E\u6A21\u677F\u5DF2\u88AB\u7F16\u8F91\uFF09\uFF0C\u8BF7\u91CD\u65B0\u83B7\u53D6\u5347\u7EA7\u8BA1\u5212",
|
|
159
159
|
FLOW_MANIFEST_INVALID: "\u8282\u70B9\u5E93 manifest \u683C\u5F0F\u6216\u7248\u672C\u4E0D\u652F\u6301",
|
|
160
|
-
// T202609150002
|
|
160
|
+
// T202609150002:问题池域(终态含 done 自身,T202609200001;message 由路由层按状态差异化——
|
|
161
|
+
// 已转任务携带关联任务标识 / 已取消提示废弃 / done 提示不可再次终态)
|
|
161
162
|
ISSUE_NOT_FOUND: "\u95EE\u9898\u4E0D\u5B58\u5728",
|
|
162
163
|
ISSUE_INVALID_TRANSITION: "\u95EE\u9898\u5DF2\u662F\u7EC8\u6001\uFF0C\u7981\u6B62\u8BE5\u64CD\u4F5C\uFF08\u7EC8\u6001\u65E0\u56DE\u8F6C\uFF09",
|
|
163
164
|
ISSUE_PROJECT_MISMATCH: "\u95EE\u9898\u4E0E\u76EE\u6807\u9879\u76EE\u5F52\u5C5E\u4E0D\u4E00\u81F4\uFF0C\u7981\u6B62\u8DE8\u9879\u76EE\u7EC4\u5408\u8F6C\u51FA",
|
|
@@ -2063,7 +2064,7 @@ function generateEntryId(existing) {
|
|
|
2063
2064
|
|
|
2064
2065
|
// src/schemas/issue.ts
|
|
2065
2066
|
import { z as z5 } from "zod";
|
|
2066
|
-
var ISSUE_STATUSES = ["pending", "partial", "converted", "cancelled"];
|
|
2067
|
+
var ISSUE_STATUSES = ["pending", "partial", "converted", "cancelled", "done"];
|
|
2067
2068
|
var IssueStatusSchema = z5.enum(ISSUE_STATUSES);
|
|
2068
2069
|
var ISSUE_ACTIVE_STATUSES = ["pending", "partial"];
|
|
2069
2070
|
var ISSUE_SOURCES = ["mcp", "cli", "web"];
|
|
@@ -2095,6 +2096,8 @@ var IssueSchema = z5.object({
|
|
|
2095
2096
|
source: IssueSourceSchema,
|
|
2096
2097
|
projectId: z5.string().regex(OBJECT_ID_HEX, "projectId must be a valid ObjectId hex"),
|
|
2097
2098
|
status: IssueStatusSchema.default("pending"),
|
|
2099
|
+
/** 人类审批原话(T202609200001:AI 通道 mcp/cli 录入必须携带用户批准时的原文逐字,供事后审计;Web 豁免——人工录入天然即批准) */
|
|
2100
|
+
approved: z5.string().min(1).max(500).optional(),
|
|
2098
2101
|
taskLinks: z5.array(TaskLinkSchema).default([]),
|
|
2099
2102
|
history: z5.array(IssueHistoryEntrySchema).default([]),
|
|
2100
2103
|
createdAt: z5.date().optional(),
|
|
@@ -2102,7 +2105,8 @@ var IssueSchema = z5.object({
|
|
|
2102
2105
|
});
|
|
2103
2106
|
var IssueCreateSchema = z5.object({
|
|
2104
2107
|
title: z5.string().min(1).max(200),
|
|
2105
|
-
description: z5.string().max(1e4).optional()
|
|
2108
|
+
description: z5.string().max(1e4).optional(),
|
|
2109
|
+
approved: z5.string().min(1).max(500).optional()
|
|
2106
2110
|
});
|
|
2107
2111
|
var IssueUpdateSchema = z5.object({
|
|
2108
2112
|
title: z5.string().min(1).max(200).optional(),
|
|
@@ -2145,6 +2149,8 @@ function createIssueRepo(db) {
|
|
|
2145
2149
|
issueId,
|
|
2146
2150
|
title: data.title,
|
|
2147
2151
|
...data.description !== void 0 ? { description: data.description } : {},
|
|
2152
|
+
// 审批原话(T202609200001):AI 通道强制已在 server 路由层校验,repo 仅透传落库
|
|
2153
|
+
...data.approved !== void 0 ? { approved: data.approved } : {},
|
|
2148
2154
|
source,
|
|
2149
2155
|
projectId,
|
|
2150
2156
|
status: "pending",
|
|
@@ -2179,7 +2185,7 @@ function createIssueRepo(db) {
|
|
|
2179
2185
|
if (!current) {
|
|
2180
2186
|
throw new NotFoundError("issue", issueId, { bizCode: "ISSUE_NOT_FOUND" });
|
|
2181
2187
|
}
|
|
2182
|
-
if (current.status === "converted" || current.status === "cancelled") {
|
|
2188
|
+
if (current.status === "converted" || current.status === "cancelled" || current.status === "done") {
|
|
2183
2189
|
throw new ConflictError("issue", issueId, {
|
|
2184
2190
|
bizCode: "ISSUE_INVALID_TRANSITION",
|
|
2185
2191
|
message: `\u95EE\u9898\u5DF2\u662F\u7EC8\u6001\uFF08${String(current.status)}\uFF09\uFF0C\u7981\u6B62\u53D6\u6D88`
|
|
@@ -2220,7 +2226,45 @@ function createIssueRepo(db) {
|
|
|
2220
2226
|
if (!result) {
|
|
2221
2227
|
throw new ConflictError("issue", issueId, {
|
|
2222
2228
|
bizCode: "ISSUE_INVALID_TRANSITION",
|
|
2223
|
-
message: "\u95EE\u9898\u5DF2\u88AB\u5E76\u53D1\u5904\u7406\uFF08\u8F6C\u51FA/\u53D6\u6D88\uFF09\uFF0C\u8BF7\u5237\u65B0\u540E\u91CD\u8BD5"
|
|
2229
|
+
message: "\u95EE\u9898\u5DF2\u88AB\u5E76\u53D1\u5904\u7406\uFF08\u8F6C\u51FA/\u53D6\u6D88/\u5B8C\u6210\uFF09\uFF0C\u8BF7\u5237\u65B0\u540E\u91CD\u8BD5"
|
|
2230
|
+
});
|
|
2231
|
+
}
|
|
2232
|
+
return toEntity(result);
|
|
2233
|
+
},
|
|
2234
|
+
async markDone(issueId, note) {
|
|
2235
|
+
const current = await base._collection.findOne({ issueId });
|
|
2236
|
+
if (!current) {
|
|
2237
|
+
throw new NotFoundError("issue", issueId, { bizCode: "ISSUE_NOT_FOUND" });
|
|
2238
|
+
}
|
|
2239
|
+
if (current.status === "converted" || current.status === "cancelled" || current.status === "done") {
|
|
2240
|
+
throw new ConflictError("issue", issueId, {
|
|
2241
|
+
bizCode: "ISSUE_INVALID_TRANSITION",
|
|
2242
|
+
message: `\u95EE\u9898\u5DF2\u662F\u7EC8\u6001\uFF08${String(current.status)}\uFF09\uFF0C\u7981\u6B62\u6807\u8BB0\u5B8C\u6210`
|
|
2243
|
+
});
|
|
2244
|
+
}
|
|
2245
|
+
const now = /* @__PURE__ */ new Date();
|
|
2246
|
+
const result = await base._collection.findOneAndUpdate(
|
|
2247
|
+
// 并发安全带:读后窗口内外部转出/取消/完成 → 命中 0 行报终态冲突(终态以先到者为准)
|
|
2248
|
+
{ issueId, status: { $in: ISSUE_ACTIVE_STATUSES } },
|
|
2249
|
+
{
|
|
2250
|
+
$set: { status: "done", updatedAt: now },
|
|
2251
|
+
$push: {
|
|
2252
|
+
history: {
|
|
2253
|
+
id: generateEntryId([]),
|
|
2254
|
+
action: "status-change",
|
|
2255
|
+
from: current.status,
|
|
2256
|
+
to: "done",
|
|
2257
|
+
...note !== void 0 ? { reason: note } : {},
|
|
2258
|
+
at: now
|
|
2259
|
+
}
|
|
2260
|
+
}
|
|
2261
|
+
},
|
|
2262
|
+
{ returnDocument: "after" }
|
|
2263
|
+
);
|
|
2264
|
+
if (!result) {
|
|
2265
|
+
throw new ConflictError("issue", issueId, {
|
|
2266
|
+
bizCode: "ISSUE_INVALID_TRANSITION",
|
|
2267
|
+
message: "\u95EE\u9898\u5DF2\u88AB\u5E76\u53D1\u5904\u7406\uFF08\u8F6C\u51FA/\u53D6\u6D88/\u5B8C\u6210\uFF09\uFF0C\u8BF7\u5237\u65B0\u540E\u91CD\u8BD5"
|
|
2224
2268
|
});
|
|
2225
2269
|
}
|
|
2226
2270
|
return toEntity(result);
|