@lmzhen/dsh-evolution-commands 0.1.0-rc.9 → 0.1.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 CHANGED
@@ -1,6 +1,10 @@
1
+ import { createUserMessage } from "@deepseek-ai/dsh-llm";
2
+ import { appendEvolutionEvent, buildLearnPrompt, eventsFile } from "@lmzhen/dsh-evolution-core";
3
+ import { homedir } from "node:os";
4
+ import { join } from "node:path";
1
5
  //#region lib/types/index.js
2
6
  /**
3
- * Human commands for the evolution family: /evolution status|pending.
7
+ * Human commands for the evolution family: /evolution learn|pending|curator|restore|consolidate.
4
8
  * @module @lmzhen/dsh-evolution-commands
5
9
  */
6
10
  const name = "evolution-commands";
@@ -12,69 +16,153 @@ function apply(ctx) {
12
16
  recordInput: false,
13
17
  async handler(invocation) {
14
18
  const input = invocation.rawInput?.trim() ?? "";
19
+ const ok = (text) => ({
20
+ kind: "success",
21
+ text
22
+ });
23
+ const err = (text) => ({
24
+ kind: "error",
25
+ text
26
+ });
15
27
  const approval = ctx.get("evolutionApproval");
16
28
  if (input === "pending") {
17
29
  const pending = approval ? await approval.list("pending") : [];
18
- return { text: pending.length === 0 ? "No pending evolution writes." : pending.map((p) => `${p.id} ${p.kind} ${p.summary}`).join("\n") };
30
+ return ok(pending.length === 0 ? "No pending evolution writes." : pending.map((p) => `${p.id} ${p.kind} ${p.summary}`).join("\n"));
19
31
  }
20
32
  if (input.startsWith("approve ")) {
21
33
  const id = input.slice(8).trim();
22
- return { text: (approval ? await approval.approve(id) : {
34
+ const result = approval ? await approval.approve(id) : {
23
35
  ok: false,
24
36
  message: "approval service not mounted"
25
- }).message };
37
+ };
38
+ return result.ok ? ok(result.message) : err(result.message);
26
39
  }
27
40
  if (input.startsWith("reject ")) {
28
41
  const id = input.slice(7).trim();
29
- return { text: (approval ? await approval.reject(id) : {
42
+ const result = approval ? await approval.reject(id) : {
30
43
  ok: false,
31
44
  message: "approval service not mounted"
32
- }).message };
45
+ };
46
+ return result.ok ? ok(result.message) : err(result.message);
33
47
  }
34
48
  if (input === "curator run") {
35
49
  const curator = ctx.get("evolutionCurator");
36
- if (!curator) return { text: "Curator service not mounted." };
37
- const result = await curator.run();
38
- return { text: `Curator run complete: ${result.stale.length} stale, ${result.archived.length} archived, ${result.errors.length} failed.\nrunId=${result.report.runId}${result.report.snapshotPath ? `\nsnapshot=${result.report.snapshotPath}` : ""}` };
50
+ if (!curator) return err("Curator service not mounted.");
51
+ const result = await curator.run({ ignoreGates: true });
52
+ return ok(`Curator run complete: ${result.stale.length} stale, ${result.archived.length} archived, ${result.errors.length} failed.\nrunId=${result.report.runId}${result.report.snapshotPath ? `\nsnapshot=${result.report.snapshotPath}` : ""}`);
53
+ }
54
+ if (input === "curator pause" || input === "curator resume") {
55
+ const curator = ctx.get("evolutionCurator");
56
+ if (!curator) return err("Curator service not mounted.");
57
+ const paused = input === "curator pause";
58
+ await curator.setPaused(paused);
59
+ return ok(paused ? "Curator automatic curation paused. Manual /evolution curator run is unaffected; resume with /evolution curator resume." : "Curator automatic curation resumed. The next scheduled pass waits one interval (first-run defer semantics).");
60
+ }
61
+ if (input === "curator status") {
62
+ const curator = ctx.get("evolutionCurator");
63
+ if (!curator) return err("Curator service not mounted.");
64
+ const state = await curator.status();
65
+ if (!state) return ok("No curator state yet: the first automatic pass is deferred until the interval elapses.");
66
+ const lastRun = typeof state.lastRunAt === "number" && Number.isFinite(state.lastRunAt) && state.lastRunAt > 0 ? new Date(state.lastRunAt).toISOString() : "unknown";
67
+ return ok([
68
+ `paused=${state.paused}`,
69
+ `runs=${state.runCount}`,
70
+ `lastRun=${lastRun}`,
71
+ `summary=${state.lastSummary}`
72
+ ].join("\n"));
73
+ }
74
+ if (input === "mutations") {
75
+ const curator = ctx.get("evolutionCurator");
76
+ if (!curator) return err("Curator service not mounted.");
77
+ const records = await curator.skills.listMutations();
78
+ if (records.length === 0) return ok("No mutation records yet.");
79
+ const recent = records.slice(-5).reverse().map((record) => `${record.at.slice(0, 19)} ${record.skillName} ${record.action} ${record.summary}`);
80
+ return ok(`Mutations: ${records.length} recorded (recent 5):\n${recent.join("\n")}`);
81
+ }
82
+ if (input === "curator scope") {
83
+ const curator = ctx.get("evolutionCurator");
84
+ if (!curator) return err("Curator service not mounted.");
85
+ const view = await curator.scopeView();
86
+ const line = (label, names) => `${label}: ${names.length}${names.length === 0 ? "" : `\n ${names.join(", ")}`}`;
87
+ return ok([
88
+ `Lifecycle scope at ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`,
89
+ line("Managed (may transition)", view.managed),
90
+ line("Watched (stale / quality-warned)", view.watched),
91
+ line("Quality-warned", view.qualityWarned),
92
+ line("Exempted (exclude / referenced)", view.exempted),
93
+ line("Protected (pinned / bundled / hub)", view.protected)
94
+ ].join("\n"));
39
95
  }
40
96
  if (input === "curator report") {
41
97
  const curator = ctx.get("evolutionCurator");
42
- if (!curator) return { text: "Curator service not mounted." };
98
+ if (!curator) return err("Curator service not mounted.");
43
99
  const report = await curator.latestReport();
44
- if (!report) return { text: "No curator report available." };
45
- return { text: [
100
+ if (!report) return ok("No curator report available.");
101
+ return ok([
46
102
  `runId=${report.runId}`,
47
103
  `startedAt=${report.startedAt}`,
48
104
  `archived=${report.archived.map((item) => item.name).join(", ") || "(none)"}`,
49
105
  `failed=${report.failed.map((item) => `${item.name}: ${item.reason}`).join(", ") || "(none)"}`
50
- ].join("\n") };
106
+ ].join("\n"));
51
107
  }
52
108
  if (input.startsWith("restore ")) {
53
109
  const curator = ctx.get("evolutionCurator");
54
- return { text: (curator ? await curator.skills.restoreLatestSnapshot() : {
110
+ const result = curator ? await curator.restoreSnapshot() : {
55
111
  ok: false,
56
112
  message: "Curator service not mounted."
57
- }).message };
113
+ };
114
+ return result.ok ? ok(result.message) : err(result.message);
58
115
  }
59
116
  if (input.startsWith("consolidate ")) {
60
117
  const [target, ...sources] = input.slice(12).trim().split(/\s+/).filter(Boolean);
61
- if (!target || sources.length === 0) return { text: "Usage: /evolution consolidate <target> <source...>" };
118
+ if (!target || sources.length === 0) return err("Usage: /evolution consolidate <target> <source...>");
62
119
  const curator = ctx.get("evolutionCurator");
63
- return { text: (curator ? await curator.consolidate(target, sources) : {
120
+ const result = curator ? await curator.consolidate(target, sources) : {
64
121
  ok: false,
65
122
  message: "Curator service not mounted."
66
- }).message };
123
+ };
124
+ return result.ok ? ok(result.message) : err(result.message);
67
125
  }
68
126
  if (input.startsWith("skill restore ")) {
69
127
  const name = input.slice(14).trim();
70
- if (!name) return { text: "Usage: /evolution skill restore <name>" };
128
+ if (!name) return err("Usage: /evolution skill restore <name>");
71
129
  const curator = ctx.get("evolutionCurator");
72
- return { text: (curator ? await curator.restore(name) : {
130
+ const result = curator ? await curator.restore(name) : {
73
131
  ok: false,
74
132
  message: "Curator service not mounted."
75
- }).message };
133
+ };
134
+ return result.ok ? ok(result.message) : err(result.message);
135
+ }
136
+ if (input === "learn" || input.startsWith("learn ")) {
137
+ const request = input === "learn" ? "" : input.slice(6).trim();
138
+ invocation.agent.inject(createUserMessage({
139
+ content: [{
140
+ type: "text",
141
+ text: buildLearnPrompt(request)
142
+ }],
143
+ source: {
144
+ kind: "plugin",
145
+ plugin: "dsh-evolution-commands",
146
+ form: "notice",
147
+ summary: "learn request"
148
+ }
149
+ }));
150
+ const eventIo = ctx.get("evolutionIo")?.provider();
151
+ if (eventIo) appendEvolutionEvent(eventIo, eventsFile(process.env.DSH_HOME ?? join(homedir(), ".dsh")), {
152
+ type: "learn",
153
+ source: "manual",
154
+ ...request ? { request } : {}
155
+ }).catch((error) => {
156
+ ctx.logger.warn(`evolution-commands: failed to record learn event: ${String(error)}`);
157
+ });
158
+ return ok("Learning request sent to this session. Follow it now.");
159
+ }
160
+ if (input === "replay") {
161
+ const replay = ctx.get("evolutionReplay");
162
+ if (!replay) return err("Replay service not mounted.");
163
+ return ok(replay.compare().report);
76
164
  }
77
- return { text: "Evolution: memory, skills, review, curator. Use /evolution pending | curator run | curator report | restore | consolidate <target> <source...> | skill restore <name>." };
165
+ return ok("Evolution: memory, skills, review, curator. Use /evolution pending | approve <id> | reject <id> | curator run | curator status | curator pause | curator resume | curator report | curator scope | restore | consolidate <target> <source...> | skill restore <name> | learn [request] | replay.");
78
166
  }
79
167
  });
80
168
  });
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Human commands for the evolution family: /evolution status|pending.
2
+ * Human commands for the evolution family: /evolution learn|pending|curator|restore|consolidate.
3
3
  * @module @deepseek-ai/dsh-evolution-commands
4
4
  */
5
5
  import type { Context } from '@deepseek-ai/cordis';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lmzhen/dsh-evolution-commands",
3
3
  "description": "Human commands for the evolution family (community build)",
4
- "version": "0.1.0-rc.9",
4
+ "version": "0.1.0",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -32,13 +32,15 @@
32
32
  ],
33
33
  "license": "MIT",
34
34
  "dependencies": {
35
- "@deepseek-ai/schemastery": "^3.18.1"
35
+ "@deepseek-ai/schemastery": "^3.18.1",
36
+ "@lmzhen/dsh-evolution-core": "^0.1.0"
36
37
  },
37
38
  "peerDependencies": {
38
- "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6",
39
- "@deepseek-ai/cordis": "^4.0.1"
39
+ "@deepseek-ai/cordis": "^4.0.1",
40
+ "@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
41
+ "@deepseek-ai/dsh-llm": "^0.1.1-rc.2"
40
42
  },
41
43
  "devDependencies": {
42
- "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6"
44
+ "@deepseek-ai/dsh-invariants": "^0.1.1-rc.2"
43
45
  }
44
46
  }