@lmzhen/dsh-evolution-approval 0.23.0 → 0.25.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/lib/index.js +38 -38
- package/package.json +7 -7
package/lib/index.js
CHANGED
|
@@ -32,11 +32,11 @@ function makeApprovalRoutes(approval) {
|
|
|
32
32
|
/** Guard: trust fence, then method. Every refusal is a JSON body, never an empty response. */
|
|
33
33
|
const guard = (req, res, method) => {
|
|
34
34
|
if (!isLoopbackRequest(req)) {
|
|
35
|
-
writeJson(res, 403, { error: "
|
|
35
|
+
writeJson(res, 403, { error: "禁止访问:仅限回环地址" });
|
|
36
36
|
return false;
|
|
37
37
|
}
|
|
38
38
|
if (req.method !== method) {
|
|
39
|
-
writeJson(res, 405, { error: "
|
|
39
|
+
writeJson(res, 405, { error: "方法不允许:" + method });
|
|
40
40
|
return false;
|
|
41
41
|
}
|
|
42
42
|
return true;
|
|
@@ -82,7 +82,7 @@ function makeApprovalRoutes(approval) {
|
|
|
82
82
|
writeJson(res, 400, {
|
|
83
83
|
ok: false,
|
|
84
84
|
code: "bad-request",
|
|
85
|
-
message: "status
|
|
85
|
+
message: "status 必须是以下之一:" + PENDING_STATUSES.join(", ")
|
|
86
86
|
});
|
|
87
87
|
return;
|
|
88
88
|
}
|
|
@@ -118,7 +118,7 @@ function makeApprovalRoutes(approval) {
|
|
|
118
118
|
writeJson(res, 400, {
|
|
119
119
|
ok: false,
|
|
120
120
|
code: "bad-request",
|
|
121
|
-
message: "id
|
|
121
|
+
message: "缺少 id"
|
|
122
122
|
});
|
|
123
123
|
return;
|
|
124
124
|
}
|
|
@@ -128,7 +128,7 @@ function makeApprovalRoutes(approval) {
|
|
|
128
128
|
writeJson(res, 200, {
|
|
129
129
|
ok: false,
|
|
130
130
|
code: "not-found",
|
|
131
|
-
message: "
|
|
131
|
+
message: "没有 id 为「" + id + "」的待批准写入"
|
|
132
132
|
});
|
|
133
133
|
return;
|
|
134
134
|
}
|
|
@@ -138,7 +138,7 @@ function makeApprovalRoutes(approval) {
|
|
|
138
138
|
ok: true,
|
|
139
139
|
data: {
|
|
140
140
|
available: false,
|
|
141
|
-
reason: "
|
|
141
|
+
reason: "类型 \"" + record.kind + "\" 的写入没有可预览内容"
|
|
142
142
|
}
|
|
143
143
|
});
|
|
144
144
|
return;
|
|
@@ -182,7 +182,7 @@ function makeApprovalRoutes(approval) {
|
|
|
182
182
|
writeJson(res, 400, {
|
|
183
183
|
ok: false,
|
|
184
184
|
code: "bad-request",
|
|
185
|
-
message: "id
|
|
185
|
+
message: "缺少 id"
|
|
186
186
|
});
|
|
187
187
|
return;
|
|
188
188
|
}
|
|
@@ -199,7 +199,7 @@ function makeApprovalRoutes(approval) {
|
|
|
199
199
|
writeJson(res, 400, {
|
|
200
200
|
ok: false,
|
|
201
201
|
code: "bad-request",
|
|
202
|
-
message: "id
|
|
202
|
+
message: "缺少 id"
|
|
203
203
|
});
|
|
204
204
|
return;
|
|
205
205
|
}
|
|
@@ -349,12 +349,12 @@ var EvolutionApproval = class extends Service {
|
|
|
349
349
|
async run(kind, args, intent) {
|
|
350
350
|
if (intent?.interface !== "background_review") return {
|
|
351
351
|
ok: false,
|
|
352
|
-
message: "approval.run
|
|
352
|
+
message: "approval.run 是后台复核的回放通道;直接执行必须走工具路径(对前台而言,暂存是唯一的门禁旁路)。"
|
|
353
353
|
};
|
|
354
354
|
const runner = this.runners.get(kind);
|
|
355
355
|
if (!runner) return {
|
|
356
356
|
ok: false,
|
|
357
|
-
message:
|
|
357
|
+
message: `没有为类型「${kind}」注册回放运行器。`
|
|
358
358
|
};
|
|
359
359
|
return await runner(args);
|
|
360
360
|
}
|
|
@@ -363,11 +363,11 @@ var EvolutionApproval = class extends Service {
|
|
|
363
363
|
const summary = normalizeSummary(input);
|
|
364
364
|
if (!this.enabled) return {
|
|
365
365
|
action: "allow",
|
|
366
|
-
message: "
|
|
366
|
+
message: "批准已禁用。"
|
|
367
367
|
};
|
|
368
368
|
if ((this.deriveSessionPolicy(input.sessionId, input.session) ?? (this.ctx.get("approval") ? void 0 : input.sessionPolicy)) === "never") return {
|
|
369
369
|
action: "allow",
|
|
370
|
-
message: "
|
|
370
|
+
message: "会话批准策略是「never」:写入无需暂存,直接放行。"
|
|
371
371
|
};
|
|
372
372
|
if (input.origin === "background_review" || this.stageForeground) {
|
|
373
373
|
if (input.kind !== "capability" && !this.runners.has(input.kind)) this.ctx.logger.warn(`evolution-approval: staging "${input.kind}" write with no replay runner registered - it will not be approvable`);
|
|
@@ -385,12 +385,12 @@ var EvolutionApproval = class extends Service {
|
|
|
385
385
|
return {
|
|
386
386
|
action: "staged",
|
|
387
387
|
pendingId: record.id,
|
|
388
|
-
message:
|
|
388
|
+
message: `写入已暂存待批准。用 /evolution pending 查看,并批准 ${record.id}。`
|
|
389
389
|
};
|
|
390
390
|
}
|
|
391
391
|
return {
|
|
392
392
|
action: "allow",
|
|
393
|
-
message: "
|
|
393
|
+
message: "前台写入已放行。"
|
|
394
394
|
};
|
|
395
395
|
}
|
|
396
396
|
/** T4-09/A51: the effective expiry of the staged window, 0 = never. Read by the command surface
|
|
@@ -474,26 +474,26 @@ var EvolutionApproval = class extends Service {
|
|
|
474
474
|
if (!executing) {
|
|
475
475
|
if ((await this.state().listPending("pending")).find((item) => item.id === id)) return {
|
|
476
476
|
ok: false,
|
|
477
|
-
message:
|
|
477
|
+
message: `待批准写入「${id}」已经在待批准窗口里:直接批准或拒绝它。`
|
|
478
478
|
};
|
|
479
479
|
return {
|
|
480
480
|
ok: false,
|
|
481
|
-
message:
|
|
481
|
+
message: `待批准写入「${id}」不在执行窗口中:没有可释放的。`
|
|
482
482
|
};
|
|
483
483
|
}
|
|
484
484
|
if (this.inFlight.has(`approve:${id}`) || this.inFlight.has(`reject:${id}`)) return {
|
|
485
485
|
ok: false,
|
|
486
|
-
message:
|
|
486
|
+
message: `待批准写入「${id}」在本进程里有正在运行的批准或拒绝:不要释放它。改为核验效果;已完成的批准会自行了结该记录。`
|
|
487
487
|
};
|
|
488
488
|
const claimId = typeof executing.claimedBy === "string" ? executing.claimedBy : "";
|
|
489
489
|
if (claimId === "") return {
|
|
490
490
|
ok: false,
|
|
491
|
-
message:
|
|
491
|
+
message: `待批准写入「${id}」没有可释放的占用声明(记录形状异常):请改为拒绝它。`
|
|
492
492
|
};
|
|
493
493
|
const holderPid = claimHolderPid(claimId);
|
|
494
494
|
if (holderPid !== null && holderPid > 0 && holderPid !== process.pid && isProcessAlive(holderPid)) return {
|
|
495
495
|
ok: false,
|
|
496
|
-
message:
|
|
496
|
+
message: `待批准写入「${id}」被 pid ${holderPid} 占用且该进程仍存活:可能有另一个进程正在执行这次批准。不要释放它:改为核验写入效果,并让那次运行跑完(已完成的批准会自行了结该记录)。`
|
|
497
497
|
};
|
|
498
498
|
let released = false;
|
|
499
499
|
let failure = "";
|
|
@@ -506,11 +506,11 @@ var EvolutionApproval = class extends Service {
|
|
|
506
506
|
}
|
|
507
507
|
if (!released) return {
|
|
508
508
|
ok: false,
|
|
509
|
-
message:
|
|
509
|
+
message: `释放「${id}」没有生效(${failure === "" ? "the claim no longer matches the record — a concurrent writer moved it" : failure}):除非它已了结,否则仍处于 EXECUTING 且保留占用声明,写入效果也仍未核验。请重试,或拒绝它以在不重放的情况下关闭记录。`
|
|
510
510
|
};
|
|
511
511
|
return {
|
|
512
512
|
ok: true,
|
|
513
|
-
message:
|
|
513
|
+
message: `已把「${id}」放回待批准窗口。${holderPid === null ? " Its claim carries no pid, so liveness could NOT be verified: another process may still be running this approve." : ""} 批准前请先核验效果:批准会重跑该写入,非幂等的重放会造成效果重复;改为拒绝则可关闭该记录。`
|
|
514
514
|
};
|
|
515
515
|
}
|
|
516
516
|
async reject(id) {
|
|
@@ -519,14 +519,14 @@ var EvolutionApproval = class extends Service {
|
|
|
519
519
|
if (!await this.state().claimPending(id, claimId)) {
|
|
520
520
|
if ((await this.state().listPending("executing")).find((item) => item.id === id)) return (await this.state().tryResolvePending(id, "rejected")).applied ? {
|
|
521
521
|
ok: true,
|
|
522
|
-
message:
|
|
522
|
+
message: `已拒绝执行中的写入「${id}」(未持有占用声明:这可能与在途的批准运行器抢跑;如果写入已落地,其效果按现状保留。请手动核验写入状态)。`
|
|
523
523
|
} : {
|
|
524
524
|
ok: false,
|
|
525
|
-
message:
|
|
525
|
+
message: `待批准写入「${id}」无法拒绝:它并发地了结了。`
|
|
526
526
|
};
|
|
527
527
|
return {
|
|
528
528
|
ok: false,
|
|
529
|
-
message:
|
|
529
|
+
message: `待批准写入「${id}」不在待批准窗口里(已轮转或已了结)。`
|
|
530
530
|
};
|
|
531
531
|
}
|
|
532
532
|
const resolution = await this.state().tryResolvePending(id, "rejected", claimId);
|
|
@@ -534,12 +534,12 @@ var EvolutionApproval = class extends Service {
|
|
|
534
534
|
await this.state().releasePendingClaim(id, claimId);
|
|
535
535
|
return {
|
|
536
536
|
ok: false,
|
|
537
|
-
message:
|
|
537
|
+
message: `待批准写入「${id}」已不在待批准状态(已了结或不存在)。`
|
|
538
538
|
};
|
|
539
539
|
}
|
|
540
540
|
return {
|
|
541
541
|
ok: true,
|
|
542
|
-
message:
|
|
542
|
+
message: `已拒绝 ${resolution.record.kind} 写入「${id}」。`
|
|
543
543
|
};
|
|
544
544
|
});
|
|
545
545
|
}
|
|
@@ -583,11 +583,11 @@ var EvolutionApproval = class extends Service {
|
|
|
583
583
|
if (!record) {
|
|
584
584
|
if ((await this.state().listPending("executing")).find((item) => item.id === id)) return {
|
|
585
585
|
ok: false,
|
|
586
|
-
message:
|
|
586
|
+
message: `待批准写入「${id}」正在执行:可能有另一个写入方正在了结它,或此前一次批准跑过之后崩了。如果不是你发起的这次批准,就不要拒绝它(在途的运行会自行完成);改为核验效果。确实卡住的记录(运行器没有任何动静)仍然可以拒绝 —— /evolution pending 会把它显示为 EXECUTING。`
|
|
587
587
|
};
|
|
588
588
|
return {
|
|
589
589
|
ok: false,
|
|
590
|
-
message:
|
|
590
|
+
message: `待批准写入「${id}」不在待批准窗口里(已轮转或已了结)。`
|
|
591
591
|
};
|
|
592
592
|
}
|
|
593
593
|
const runner = this.runners.get(record.kind);
|
|
@@ -596,22 +596,22 @@ var EvolutionApproval = class extends Service {
|
|
|
596
596
|
if (!(await this.state().tryResolvePending(id, "approved", claimId)).applied) {
|
|
597
597
|
if ((await this.state().listPending("rejected")).find((item) => item.id === id)) return {
|
|
598
598
|
ok: false,
|
|
599
|
-
message:
|
|
599
|
+
message: `能力「${id}」已获批准,但记录被并发地了结为「rejected」:没有代码运行,也无需重放;重新提交前请先核验。`
|
|
600
600
|
};
|
|
601
601
|
return {
|
|
602
602
|
ok: false,
|
|
603
|
-
message:
|
|
603
|
+
message: `待批准写入「${id}」已被另一个写入方了结。`
|
|
604
604
|
};
|
|
605
605
|
}
|
|
606
606
|
return {
|
|
607
607
|
ok: true,
|
|
608
|
-
message: "
|
|
608
|
+
message: "能力已批准,可在 Creator 模式下手动激活(未执行任何代码)。"
|
|
609
609
|
};
|
|
610
610
|
}
|
|
611
611
|
await this.state().releasePendingClaim(id, claimId);
|
|
612
612
|
return {
|
|
613
613
|
ok: false,
|
|
614
|
-
message:
|
|
614
|
+
message: `没有为类型「${record.kind}」注册回放运行器。`
|
|
615
615
|
};
|
|
616
616
|
}
|
|
617
617
|
try {
|
|
@@ -620,7 +620,7 @@ var EvolutionApproval = class extends Service {
|
|
|
620
620
|
await this.state().releasePendingClaim(id, claimId);
|
|
621
621
|
return {
|
|
622
622
|
ok: false,
|
|
623
|
-
message:
|
|
623
|
+
message: (/* @__PURE__ */ new RegExp("changed since this plan|no entry matching|not found|no longer exists|path traversal|在图渲染之后被改动过|匹配到多条不同条目|已不存在|不存在|路径穿越|不在技能|找不到|被改动过|已改动|不匹配|已过期|changed since it was read", "i")).test(result.message) ? `${result.message} 同一计划里的兄弟写入可能已改动该目标,反复批准会一直失败;除非目标再次变更,请驳回该记录。` : result.message
|
|
624
624
|
};
|
|
625
625
|
}
|
|
626
626
|
} catch (error) {
|
|
@@ -628,7 +628,7 @@ var EvolutionApproval = class extends Service {
|
|
|
628
628
|
this.ctx.logger.warn(error);
|
|
629
629
|
return {
|
|
630
630
|
ok: false,
|
|
631
|
-
message: "
|
|
631
|
+
message: "回放运行器失败:该待批准写入仍处于待批准状态。"
|
|
632
632
|
};
|
|
633
633
|
}
|
|
634
634
|
const resolution = await this.state().tryResolvePending(id, "approved", claimId).catch((error) => {
|
|
@@ -637,21 +637,21 @@ var EvolutionApproval = class extends Service {
|
|
|
637
637
|
});
|
|
638
638
|
if (typeof resolution === "string") return {
|
|
639
639
|
ok: false,
|
|
640
|
-
message:
|
|
640
|
+
message: `已批准写入「${id}」已重放,但了结记录失败(${resolution.slice(8)}):效果已经落地,而审计行仍停在「executing」。请手动核验该写入;批准不会再次重跑它。`
|
|
641
641
|
};
|
|
642
642
|
if (!resolution.applied) {
|
|
643
643
|
if ((await this.state().listPending("rejected")).find((item) => item.id === id)) return {
|
|
644
644
|
ok: false,
|
|
645
|
-
message:
|
|
645
|
+
message: `已批准写入「${id}」已重放,但记录被并发地了结为「rejected」:效果已落地,而审计显示为 rejected。请核验该写入,且不要重放它。`
|
|
646
646
|
};
|
|
647
647
|
return {
|
|
648
648
|
ok: false,
|
|
649
|
-
message:
|
|
649
|
+
message: `待批准写入「${id}」已被另一个写入方了结。`
|
|
650
650
|
};
|
|
651
651
|
}
|
|
652
652
|
return {
|
|
653
653
|
ok: true,
|
|
654
|
-
message:
|
|
654
|
+
message: `已批准 ${record.kind} 写入「${id}」(${record.summary})。`
|
|
655
655
|
};
|
|
656
656
|
}
|
|
657
657
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lmzhen/dsh-evolution-approval",
|
|
3
3
|
"description": "Stage/pending approval service for Hermes-style self-evolution writes (community build)",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.25.0",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -27,18 +27,18 @@
|
|
|
27
27
|
"license": "MIT",
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@deepseek-ai/schemastery": "^3.18.4",
|
|
30
|
-
"@lmzhen/dsh-evolution-core": "^0.
|
|
30
|
+
"@lmzhen/dsh-evolution-core": "^0.25.0"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
34
34
|
"@deepseek-ai/dsh-host-webserver": "^0.2.0-rc.1",
|
|
35
|
-
"@lmzhen/dsh-evolution-state-storage": "^0.
|
|
36
|
-
"@lmzhen/dsh-evolution-state": "^0.
|
|
35
|
+
"@lmzhen/dsh-evolution-state-storage": "^0.25.0",
|
|
36
|
+
"@lmzhen/dsh-evolution-state": "^0.25.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@deepseek-ai/dsh-host-webserver": "^0.2.0-rc.1",
|
|
40
|
-
"@lmzhen/dsh-evolution-core": "^0.
|
|
41
|
-
"@lmzhen/dsh-evolution-state-storage": "^0.
|
|
42
|
-
"@lmzhen/dsh-evolution-state": "^0.
|
|
40
|
+
"@lmzhen/dsh-evolution-core": "^0.25.0",
|
|
41
|
+
"@lmzhen/dsh-evolution-state-storage": "^0.25.0",
|
|
42
|
+
"@lmzhen/dsh-evolution-state": "^0.25.0"
|
|
43
43
|
}
|
|
44
44
|
}
|