@lmzhen/dsh-evolution-learning-graph 0.25.9 → 0.26.26
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 +65 -3
- package/lib/types/index.d.ts +24 -0
- package/package.json +3 -3
package/lib/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { SKILL_NAME_RE, authorityFrom, contentHash, errorText, evolutionIoAdapter, isPresent, isUnknown, newSkillLibrary, relatedSkillNames, resolveExecOrigins, runWriteGates, skillWriteGateContext } from "@lmzhen/dsh-evolution-core";
|
|
1
2
|
import { effectiveSessionPolicy } from "@lmzhen/dsh-evolution-approval";
|
|
2
3
|
import z from "@deepseek-ai/schemastery";
|
|
3
|
-
import { SKILL_NAME_RE, contentHash, errorText, evolutionIoAdapter, newSkillLibrary, relatedSkillNames, resolveExecOrigins } from "@lmzhen/dsh-evolution-core";
|
|
4
4
|
//#region lib/types/index.js
|
|
5
5
|
/**
|
|
6
6
|
* Learning graph over skills and memory, plus node-level commands
|
|
@@ -219,6 +219,41 @@ function capRenderedLines(lines) {
|
|
|
219
219
|
if (lines.length <= 200) return lines.join("\n");
|
|
220
220
|
return [...lines.slice(0, 200), `…${lines.length - 200} more`].join("\n");
|
|
221
221
|
}
|
|
222
|
+
/**
|
|
223
|
+
* G1/1.2: the graph commands' write-admission call, as a NAMED function.
|
|
224
|
+
*
|
|
225
|
+
* The gates run at the execution point: these commands write at the bytes, exactly like the tool's
|
|
226
|
+
* execution path, so the read-before-write gate does not apply and a missing session read set is not a
|
|
227
|
+
* refusal. `delete` archives (reversible) and is allowed through by the protection gate by design;
|
|
228
|
+
* `update` is what a protected skill is refused for.
|
|
229
|
+
*
|
|
230
|
+
* Named rather than inlined because the wiring it represents - "this command passes the SAME sequence" -
|
|
231
|
+
* has to be provable by a case that fails when the call disappears.
|
|
232
|
+
* @param services - the policy source and the warn sink, both from the command's own context.
|
|
233
|
+
* @param request - the action, the target name, the new body for an update, and the library write origin.
|
|
234
|
+
* @returns the refusal message, or null when the write may proceed.
|
|
235
|
+
*/
|
|
236
|
+
async function graphWriteGate(services, request) {
|
|
237
|
+
const isUpdate = request.action === "update";
|
|
238
|
+
const args = isUpdate ? {
|
|
239
|
+
action: "update",
|
|
240
|
+
name: request.name,
|
|
241
|
+
content: request.content ?? ""
|
|
242
|
+
} : {
|
|
243
|
+
action: "delete",
|
|
244
|
+
name: request.name
|
|
245
|
+
};
|
|
246
|
+
return runWriteGates(skillWriteGateContext({
|
|
247
|
+
policy: services.policy,
|
|
248
|
+
confirm: void 0,
|
|
249
|
+
readNames: isUpdate ? new Set([request.name]) : void 0,
|
|
250
|
+
warn: services.warn
|
|
251
|
+
}, {
|
|
252
|
+
point: isUpdate ? "admission" : "execution",
|
|
253
|
+
args,
|
|
254
|
+
origin: request.origin
|
|
255
|
+
}));
|
|
256
|
+
}
|
|
222
257
|
function apply(ctx, rawConfig = {}) {
|
|
223
258
|
ctx.inject(["commands"], (commandCtx) => {
|
|
224
259
|
const commands = commandCtx.commands;
|
|
@@ -235,6 +270,12 @@ function apply(ctx, rawConfig = {}) {
|
|
|
235
270
|
kind: "error",
|
|
236
271
|
text
|
|
237
272
|
});
|
|
273
|
+
let writeGateWarned = false;
|
|
274
|
+
const warnWriteGateOnce = (message) => {
|
|
275
|
+
if (writeGateWarned) return;
|
|
276
|
+
writeGateWarned = true;
|
|
277
|
+
ctx.logger.warn(message);
|
|
278
|
+
};
|
|
238
279
|
const usageService = ctx.get("skillUsage");
|
|
239
280
|
const memoryService = ctx.get("memory");
|
|
240
281
|
const ioService = ctx.get("evolutionIo");
|
|
@@ -318,6 +359,7 @@ function apply(ctx, rawConfig = {}) {
|
|
|
318
359
|
}
|
|
319
360
|
function withSkills() {
|
|
320
361
|
return newSkillLibrary({
|
|
362
|
+
authority: authorityFrom({ origin: "foreground" }),
|
|
321
363
|
config: rawConfig,
|
|
322
364
|
io: evolutionIoAdapter(() => io.provider()),
|
|
323
365
|
ctx,
|
|
@@ -344,7 +386,8 @@ function apply(ctx, rawConfig = {}) {
|
|
|
344
386
|
const stagesForeground = approval.stageForeground !== false;
|
|
345
387
|
if (approval.isEnabled !== false && sessionPolicyEdit !== "never" && (origins.approval === "background_review" || stagesForeground) && !approval.hasRunner("skill")) return err("无法暂存 graph 技能写入:没有注册技能回放运行器 —— 请挂载 tool-skill-manage 行(evolution-agent 预设),或禁用 evolution-approval。");
|
|
346
388
|
const sessionPolicy = sessionPolicyEdit;
|
|
347
|
-
const
|
|
389
|
+
const stageProbe = await withSkills().readSkillProbe(parsed.name);
|
|
390
|
+
const stageCurrent = isUnknown(stageProbe) ? void 0 : isPresent(stageProbe) ? stageProbe.value : null;
|
|
348
391
|
const decision = await approval.request({
|
|
349
392
|
kind: "skill",
|
|
350
393
|
summary: `graph edit ${parsed.name}`,
|
|
@@ -365,6 +408,16 @@ function apply(ctx, rawConfig = {}) {
|
|
|
365
408
|
});
|
|
366
409
|
if (decision.action === "staged") return ok(decision.message);
|
|
367
410
|
}
|
|
411
|
+
const graphRefusal = await graphWriteGate({
|
|
412
|
+
policy: ctx.get("evolutionPolicy"),
|
|
413
|
+
warn: warnWriteGateOnce
|
|
414
|
+
}, {
|
|
415
|
+
action: "update",
|
|
416
|
+
name: parsed.name,
|
|
417
|
+
content,
|
|
418
|
+
origin: resolveExecOrigins(invocationAgent && { agent: invocationAgent }).library
|
|
419
|
+
});
|
|
420
|
+
if (graphRefusal !== null) return err(graphRefusal);
|
|
368
421
|
const result = await withSkills().update(parsed.name, content, origins.library);
|
|
369
422
|
if (result.ok && result.noop !== true) await usageService.record?.(parsed.name, "patch");
|
|
370
423
|
return result.ok ? ok(result.message) : err(result.message);
|
|
@@ -428,6 +481,15 @@ function apply(ctx, rawConfig = {}) {
|
|
|
428
481
|
});
|
|
429
482
|
if (decision.action === "staged") return ok(decision.message);
|
|
430
483
|
}
|
|
484
|
+
const graphRefusal = await graphWriteGate({
|
|
485
|
+
policy: ctx.get("evolutionPolicy"),
|
|
486
|
+
warn: warnWriteGateOnce
|
|
487
|
+
}, {
|
|
488
|
+
action: "delete",
|
|
489
|
+
name: parsed.name,
|
|
490
|
+
origin: resolveExecOrigins(invocationAgent && { agent: invocationAgent }).library
|
|
491
|
+
});
|
|
492
|
+
if (graphRefusal !== null) return err(graphRefusal);
|
|
431
493
|
const result = await withSkills().archive(parsed.name);
|
|
432
494
|
if (result.ok) await usageService?.markArchived?.(parsed.name);
|
|
433
495
|
return result.ok ? ok(result.message) : err(result.message);
|
|
@@ -472,4 +534,4 @@ function apply(ctx, rawConfig = {}) {
|
|
|
472
534
|
});
|
|
473
535
|
}
|
|
474
536
|
//#endregion
|
|
475
|
-
export { Config, GRAPH_RENDER_LINE_CAP, apply, buildLearningGraph, capRenderedLines, graphDensity, memorySnapshotOf, name, parseGraphNodeId, readMemoryIndex, renderNodeLine, resolveGraphNode };
|
|
537
|
+
export { Config, GRAPH_RENDER_LINE_CAP, apply, buildLearningGraph, capRenderedLines, graphDensity, graphWriteGate, memorySnapshotOf, name, parseGraphNodeId, readMemoryIndex, renderNodeLine, resolveGraphNode };
|
package/lib/types/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* @module @lmzhen/dsh-evolution-learning-graph
|
|
11
11
|
*/
|
|
12
12
|
import type { Context } from '@deepseek-ai/cordis';
|
|
13
|
+
import { type WriteOrigin } from '@lmzhen/dsh-evolution-core';
|
|
13
14
|
import z from '@deepseek-ai/schemastery';
|
|
14
15
|
export interface GraphNode {
|
|
15
16
|
id: string;
|
|
@@ -150,5 +151,28 @@ export declare const Config: z<Config>;
|
|
|
150
151
|
export declare const GRAPH_RENDER_LINE_CAP = 200;
|
|
151
152
|
/** Join lines under the render cap; overflow is summarized, not dropped silently. */
|
|
152
153
|
export declare function capRenderedLines(lines: string[]): string;
|
|
154
|
+
/**
|
|
155
|
+
* G1/1.2: the graph commands' write-admission call, as a NAMED function.
|
|
156
|
+
*
|
|
157
|
+
* The gates run at the execution point: these commands write at the bytes, exactly like the tool's
|
|
158
|
+
* execution path, so the read-before-write gate does not apply and a missing session read set is not a
|
|
159
|
+
* refusal. `delete` archives (reversible) and is allowed through by the protection gate by design;
|
|
160
|
+
* `update` is what a protected skill is refused for.
|
|
161
|
+
*
|
|
162
|
+
* Named rather than inlined because the wiring it represents - "this command passes the SAME sequence" -
|
|
163
|
+
* has to be provable by a case that fails when the call disappears.
|
|
164
|
+
* @param services - the policy source and the warn sink, both from the command's own context.
|
|
165
|
+
* @param request - the action, the target name, the new body for an update, and the library write origin.
|
|
166
|
+
* @returns the refusal message, or null when the write may proceed.
|
|
167
|
+
*/
|
|
168
|
+
export declare function graphWriteGate(services: {
|
|
169
|
+
readonly policy: unknown;
|
|
170
|
+
readonly warn: (message: string) => void;
|
|
171
|
+
}, request: {
|
|
172
|
+
readonly action: 'update' | 'delete';
|
|
173
|
+
readonly name: string;
|
|
174
|
+
readonly content?: string | undefined;
|
|
175
|
+
readonly origin: WriteOrigin;
|
|
176
|
+
}): Promise<string | null>;
|
|
153
177
|
export declare function apply(ctx: Context, rawConfig?: Config): void;
|
|
154
178
|
//# sourceMappingURL=index.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lmzhen/dsh-evolution-learning-graph",
|
|
3
3
|
"description": "Learning graph over skills and memory (community build)",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.26.26",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"license": "MIT",
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@deepseek-ai/schemastery": "^3.18.4",
|
|
30
|
-
"@lmzhen/dsh-evolution-approval": "^0.
|
|
31
|
-
"@lmzhen/dsh-evolution-core": "^0.
|
|
30
|
+
"@lmzhen/dsh-evolution-approval": "^0.26.26",
|
|
31
|
+
"@lmzhen/dsh-evolution-core": "^0.26.26"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"@deepseek-ai/dsh-commands": "^0.2.0-rc.1",
|