@lmzhen/dsh-evolution-learning-graph 0.3.67 → 0.3.69
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 +55 -22
- package/lib/types/index.d.ts +0 -18
- package/package.json +5 -3
package/lib/index.js
CHANGED
|
@@ -13,6 +13,9 @@ import { SKILL_NAME_RE, SkillLibrary, contentHash, evolutionIoAdapter, relatedSk
|
|
|
13
13
|
* edit/delete can reject a stale index (E-21).
|
|
14
14
|
* @module @lmzhen/dsh-evolution-learning-graph
|
|
15
15
|
*/
|
|
16
|
+
/** V27 INS-04: how many skill files one `/graph` batch reads concurrently.
|
|
17
|
+
* Bounded so a large library cannot open every file at once (EMFILE). */
|
|
18
|
+
const SKILL_READ_BATCH = 16;
|
|
16
19
|
function graphDensity(graph) {
|
|
17
20
|
const linked = /* @__PURE__ */ new Set();
|
|
18
21
|
let relatedEdges = 0;
|
|
@@ -220,12 +223,12 @@ function apply(ctx, rawConfig = {}) {
|
|
|
220
223
|
const graphSkillsRoot = resolveSkillsRoot(rawConfig);
|
|
221
224
|
ctx.inject(["commands"], (commandCtx) => {
|
|
222
225
|
const commands = commandCtx.commands;
|
|
223
|
-
|
|
226
|
+
const graphCommand = {
|
|
224
227
|
name: "graph",
|
|
225
228
|
description: "Show the learning graph, or act on a node: graph [detail|edit|delete] <nodeId>",
|
|
226
229
|
recordInput: false,
|
|
227
230
|
input: { hint: "[detail|edit|delete] <nodeId> [text]" },
|
|
228
|
-
|
|
231
|
+
run: async (invocation) => {
|
|
229
232
|
const ok = (text) => ({
|
|
230
233
|
kind: "success",
|
|
231
234
|
text
|
|
@@ -241,24 +244,49 @@ function apply(ctx, rawConfig = {}) {
|
|
|
241
244
|
const usage = usageService;
|
|
242
245
|
const memory = memoryService;
|
|
243
246
|
const io = ioService;
|
|
244
|
-
const session = invocation.agent
|
|
245
|
-
const input =
|
|
247
|
+
const session = invocation.agent.session;
|
|
248
|
+
const input = invocation.rawInput.trim();
|
|
246
249
|
const detail = /^detail\s+(\S+)$/.exec(input);
|
|
247
250
|
if (detail && detail[1]) return await nodeDetail(detail[1]);
|
|
248
251
|
const edit = /^edit\s+(\S+)\s+([\s\S]+)$/.exec(input);
|
|
249
|
-
if (edit && edit[1] && edit[2] !== void 0)
|
|
252
|
+
if (edit && edit[1] && edit[2] !== void 0) {
|
|
253
|
+
if (!edit[1].startsWith("memory:")) {
|
|
254
|
+
if (await withSkills().read(edit[1]).catch(() => null) === null) return err(`Skill "${edit[1]}" not found in the live skill library — nothing to edit. (The graph may be showing a stale node.)`);
|
|
255
|
+
}
|
|
256
|
+
return await nodeEdit(edit[1], edit[2]);
|
|
257
|
+
}
|
|
250
258
|
const remove = /^delete\s+(\S+)$/.exec(input);
|
|
251
|
-
if (remove && remove[1])
|
|
259
|
+
if (remove && remove[1]) {
|
|
260
|
+
if (!remove[1].startsWith("memory:")) {
|
|
261
|
+
if (await withSkills().read(remove[1]).catch(() => null) === null) return err(`Skill "${remove[1]}" not found in the live skill library — nothing to delete.`);
|
|
262
|
+
}
|
|
263
|
+
return await nodeDelete(remove[1]);
|
|
264
|
+
}
|
|
252
265
|
const directory = await renderGraph();
|
|
253
266
|
if (input !== "") return err(`Unknown graph subcommand "${input.split(" ")[0]}". ${directory}`);
|
|
254
267
|
return ok(directory);
|
|
255
268
|
async function renderGraph() {
|
|
256
|
-
const
|
|
269
|
+
const usageReport = await usage.report();
|
|
270
|
+
const usageMap = new Map([...usageReport].filter(([, record]) => record.state !== "archived"));
|
|
257
271
|
const memoryEntries = await memory.read("memory");
|
|
258
272
|
const userEntries = await memory.read("user");
|
|
259
273
|
const skills = withSkills();
|
|
260
274
|
const names = [...usageMap.keys()];
|
|
261
|
-
const contents =
|
|
275
|
+
const contents = [];
|
|
276
|
+
let unreadable = 0;
|
|
277
|
+
for (let offset = 0; offset < names.length; offset += SKILL_READ_BATCH) {
|
|
278
|
+
const batch = names.slice(offset, offset + SKILL_READ_BATCH);
|
|
279
|
+
const batchContents = await Promise.all(batch.map(async (name) => {
|
|
280
|
+
try {
|
|
281
|
+
return await skills.read(name);
|
|
282
|
+
} catch {
|
|
283
|
+
unreadable += 1;
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
}));
|
|
287
|
+
contents.push(...batchContents);
|
|
288
|
+
}
|
|
289
|
+
if (unreadable > 0) ctx.logger.warn(`evolution-learning-graph: ${unreadable} skill file(s) could not be read; their related_skills edges are missing from this graph`);
|
|
262
290
|
const related = /* @__PURE__ */ new Map();
|
|
263
291
|
names.forEach((name, index) => {
|
|
264
292
|
const content = contents[index];
|
|
@@ -291,7 +319,7 @@ function apply(ctx, rawConfig = {}) {
|
|
|
291
319
|
if (parsed === null) return err(`Invalid node id "${id}". Skill names or memory:<source>:<index> expected.`);
|
|
292
320
|
if (parsed.kind === "skill") {
|
|
293
321
|
const approval = ctx.get("evolutionApproval");
|
|
294
|
-
const origins = resolveOrigins(session
|
|
322
|
+
const origins = resolveOrigins(session.header.origin);
|
|
295
323
|
if (approval) {
|
|
296
324
|
const sessionPolicyEdit = effectiveSessionPolicy(ctx, session);
|
|
297
325
|
const stagesForeground = approval.stageForeground !== false;
|
|
@@ -312,8 +340,8 @@ function apply(ctx, rawConfig = {}) {
|
|
|
312
340
|
libraryOrigin: origins.library
|
|
313
341
|
},
|
|
314
342
|
origin: origins.approval,
|
|
315
|
-
...session
|
|
316
|
-
|
|
343
|
+
...session.id ? { sessionId: session.id } : {},
|
|
344
|
+
session,
|
|
317
345
|
...sessionPolicy !== void 0 ? { sessionPolicy } : {}
|
|
318
346
|
});
|
|
319
347
|
if (decision.action === "staged") return ok(decision.message);
|
|
@@ -326,7 +354,7 @@ function apply(ctx, rawConfig = {}) {
|
|
|
326
354
|
if (!check.ok) return err(check.message ?? "Memory index check failed.");
|
|
327
355
|
const memoryApproval = ctx.get("evolutionApproval");
|
|
328
356
|
if (memoryApproval) {
|
|
329
|
-
const originsM = resolveOrigins(session
|
|
357
|
+
const originsM = resolveOrigins(session.header.origin);
|
|
330
358
|
const sessionPolicyM = effectiveSessionPolicy(ctx, session);
|
|
331
359
|
if (memoryApproval.isEnabled !== false && sessionPolicyM !== "never" && (originsM.approval === "background_review" || memoryApproval.stageForeground !== false) && !memoryApproval.hasRunner("memory")) return err("Graph memory write cannot be staged: no memory replay runner is registered — mount the tool-memory row (evolution-all bundle, or the evolution-preset overlay; the host bundle does not carry it) or disable evolution-approval.");
|
|
332
360
|
const decision = await memoryApproval.request({
|
|
@@ -341,8 +369,8 @@ function apply(ctx, rawConfig = {}) {
|
|
|
341
369
|
}]
|
|
342
370
|
},
|
|
343
371
|
origin: originsM.approval,
|
|
344
|
-
...session
|
|
345
|
-
|
|
372
|
+
...session.id ? { sessionId: session.id } : {},
|
|
373
|
+
session,
|
|
346
374
|
...sessionPolicyM !== void 0 ? { sessionPolicy: sessionPolicyM } : {}
|
|
347
375
|
});
|
|
348
376
|
if (decision.action === "staged") return ok(decision.message);
|
|
@@ -360,7 +388,7 @@ function apply(ctx, rawConfig = {}) {
|
|
|
360
388
|
if (parsed.kind === "skill") {
|
|
361
389
|
const approval = ctx.get("evolutionApproval");
|
|
362
390
|
if (approval) {
|
|
363
|
-
const origins = resolveOrigins(session
|
|
391
|
+
const origins = resolveOrigins(session.header.origin);
|
|
364
392
|
const sessionPolicy = effectiveSessionPolicy(ctx, session);
|
|
365
393
|
if (approval.isEnabled !== false && sessionPolicy !== "never" && (origins.approval === "background_review" || approval.stageForeground !== false) && !approval.hasRunner("skill")) return err("Graph skill delete cannot be staged: no skill replay runner is registered — mount the tool-skill-manage row (evolution-agent preset) or disable evolution-approval.");
|
|
366
394
|
const decision = await approval.request({
|
|
@@ -375,8 +403,8 @@ function apply(ctx, rawConfig = {}) {
|
|
|
375
403
|
libraryOrigin: origins.library
|
|
376
404
|
},
|
|
377
405
|
origin: origins.approval,
|
|
378
|
-
...session
|
|
379
|
-
|
|
406
|
+
...session.id ? { sessionId: session.id } : {},
|
|
407
|
+
session,
|
|
380
408
|
...sessionPolicy !== void 0 ? { sessionPolicy } : {}
|
|
381
409
|
});
|
|
382
410
|
if (decision.action === "staged") return ok(decision.message);
|
|
@@ -389,7 +417,7 @@ function apply(ctx, rawConfig = {}) {
|
|
|
389
417
|
if (!check.ok) return err(check.message ?? "Memory index check failed.");
|
|
390
418
|
const memoryApproval = ctx.get("evolutionApproval");
|
|
391
419
|
if (memoryApproval) {
|
|
392
|
-
const origins = resolveOrigins(session
|
|
420
|
+
const origins = resolveOrigins(session.header.origin);
|
|
393
421
|
const sessionPolicy = effectiveSessionPolicy(ctx, session);
|
|
394
422
|
if (memoryApproval.isEnabled !== false && sessionPolicy !== "never" && (origins.approval === "background_review" || memoryApproval.stageForeground !== false) && !memoryApproval.hasRunner("memory")) return err("Graph memory delete cannot be staged: no memory replay runner is registered — mount the tool-memory row (evolution-all bundle, or the evolution-preset overlay; the host bundle does not carry it) or disable evolution-approval.");
|
|
395
423
|
const decision = await memoryApproval.request({
|
|
@@ -403,8 +431,8 @@ function apply(ctx, rawConfig = {}) {
|
|
|
403
431
|
}]
|
|
404
432
|
},
|
|
405
433
|
origin: origins.approval,
|
|
406
|
-
...session
|
|
407
|
-
|
|
434
|
+
...session.id ? { sessionId: session.id } : {},
|
|
435
|
+
session,
|
|
408
436
|
...sessionPolicy !== void 0 ? { sessionPolicy } : {}
|
|
409
437
|
});
|
|
410
438
|
if (decision.action === "staged") return ok(decision.message);
|
|
@@ -415,8 +443,13 @@ function apply(ctx, rawConfig = {}) {
|
|
|
415
443
|
}]);
|
|
416
444
|
return result.ok ? ok(result.message) : err(result.message);
|
|
417
445
|
}
|
|
418
|
-
}
|
|
419
|
-
|
|
446
|
+
},
|
|
447
|
+
handler: (invocation) => graphCommand.run(invocation).catch((error) => ({
|
|
448
|
+
kind: "error",
|
|
449
|
+
text: `graph: command failed: ${error instanceof Error ? error.message : String(error)}\nCheck the node id and the skills/memory files under the evolution root, then retry.`
|
|
450
|
+
}))
|
|
451
|
+
};
|
|
452
|
+
commandCtx.effect(() => commands.register(graphCommand), "evolution-learning-graph.command");
|
|
420
453
|
});
|
|
421
454
|
}
|
|
422
455
|
//#endregion
|
package/lib/types/index.d.ts
CHANGED
|
@@ -37,24 +37,6 @@ export interface GraphDensity {
|
|
|
37
37
|
edgesPerNode: number;
|
|
38
38
|
isolatedPct: number;
|
|
39
39
|
}
|
|
40
|
-
/**
|
|
41
|
-
* The command invocation contract (N1, v12): the platform command handler
|
|
42
|
-
* freezes the invoking agent onto the invocation object — evolution-commands
|
|
43
|
-
* `/evolution learn` already reads `invocation.agent` — so the graph can pass
|
|
44
|
-
* `agent.session` to the approval service (tool-skill-manage pattern) instead
|
|
45
|
-
* of deriving every approval as foreground.
|
|
46
|
-
*/
|
|
47
|
-
export interface GraphInvocation {
|
|
48
|
-
rawInput?: string;
|
|
49
|
-
agent?: {
|
|
50
|
-
session?: {
|
|
51
|
-
id?: string;
|
|
52
|
-
header?: {
|
|
53
|
-
origin?: string;
|
|
54
|
-
};
|
|
55
|
-
};
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
40
|
export declare function graphDensity(graph: LearningGraph): GraphDensity;
|
|
59
41
|
/**
|
|
60
42
|
* Render one node's display line for `/evolution graph`.
|
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.3.
|
|
4
|
+
"version": "0.3.69",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -31,14 +31,16 @@
|
|
|
31
31
|
"license": "MIT",
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@deepseek-ai/schemastery": "^3.18.1",
|
|
34
|
-
"@lmzhen/dsh-evolution-approval": "^0.3.
|
|
35
|
-
"@lmzhen/dsh-evolution-core": "^0.3.
|
|
34
|
+
"@lmzhen/dsh-evolution-approval": "^0.3.69",
|
|
35
|
+
"@lmzhen/dsh-evolution-core": "^0.3.69"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
|
+
"@deepseek-ai/dsh-commands": "^0.1.1-rc.2",
|
|
38
39
|
"@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
|
|
39
40
|
"@deepseek-ai/cordis": "^4.0.1"
|
|
40
41
|
},
|
|
41
42
|
"devDependencies": {
|
|
43
|
+
"@deepseek-ai/dsh-commands": "^0.1.1-rc.2",
|
|
42
44
|
"@deepseek-ai/dsh-invariants": "^0.1.1-rc.2"
|
|
43
45
|
}
|
|
44
46
|
}
|