principles-disciple 1.5.4

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.
Files changed (189) hide show
  1. package/dist/commands/capabilities.d.ts +3 -0
  2. package/dist/commands/capabilities.js +73 -0
  3. package/dist/commands/evolver.d.ts +9 -0
  4. package/dist/commands/evolver.js +26 -0
  5. package/dist/commands/pain.d.ts +5 -0
  6. package/dist/commands/pain.js +114 -0
  7. package/dist/commands/strategy.d.ts +3 -0
  8. package/dist/commands/strategy.js +29 -0
  9. package/dist/commands/thinking-os.d.ts +2 -0
  10. package/dist/commands/thinking-os.js +162 -0
  11. package/dist/commands/trust.d.ts +4 -0
  12. package/dist/commands/trust.js +95 -0
  13. package/dist/core/agent-loader.d.ts +44 -0
  14. package/dist/core/agent-loader.js +147 -0
  15. package/dist/core/config-service.d.ts +15 -0
  16. package/dist/core/config-service.js +26 -0
  17. package/dist/core/config.d.ts +103 -0
  18. package/dist/core/config.js +186 -0
  19. package/dist/core/detection-funnel.d.ts +33 -0
  20. package/dist/core/detection-funnel.js +100 -0
  21. package/dist/core/detection-service.d.ts +15 -0
  22. package/dist/core/detection-service.js +28 -0
  23. package/dist/core/dictionary-service.d.ts +15 -0
  24. package/dist/core/dictionary-service.js +26 -0
  25. package/dist/core/dictionary.d.ts +36 -0
  26. package/dist/core/dictionary.js +136 -0
  27. package/dist/core/event-log.d.ts +53 -0
  28. package/dist/core/event-log.js +196 -0
  29. package/dist/core/evolution-engine.d.ts +119 -0
  30. package/dist/core/evolution-engine.js +542 -0
  31. package/dist/core/evolution-types.d.ts +126 -0
  32. package/dist/core/evolution-types.js +56 -0
  33. package/dist/core/hygiene/tracker.d.ts +22 -0
  34. package/dist/core/hygiene/tracker.js +106 -0
  35. package/dist/core/init.d.ts +12 -0
  36. package/dist/core/init.js +117 -0
  37. package/dist/core/migration.d.ts +6 -0
  38. package/dist/core/migration.js +90 -0
  39. package/dist/core/pain.d.ts +4 -0
  40. package/dist/core/pain.js +70 -0
  41. package/dist/core/path-resolver.d.ts +43 -0
  42. package/dist/core/path-resolver.js +259 -0
  43. package/dist/core/paths.d.ts +60 -0
  44. package/dist/core/paths.js +67 -0
  45. package/dist/core/profile.d.ts +62 -0
  46. package/dist/core/profile.js +210 -0
  47. package/dist/core/risk-calculator.d.ts +7 -0
  48. package/dist/core/risk-calculator.js +39 -0
  49. package/dist/core/session-tracker.d.ts +76 -0
  50. package/dist/core/session-tracker.js +286 -0
  51. package/dist/core/system-logger.d.ts +8 -0
  52. package/dist/core/system-logger.js +31 -0
  53. package/dist/core/trust-engine.d.ts +91 -0
  54. package/dist/core/trust-engine.js +284 -0
  55. package/dist/core/workspace-context.d.ts +64 -0
  56. package/dist/core/workspace-context.js +134 -0
  57. package/dist/hooks/gate.d.ts +6 -0
  58. package/dist/hooks/gate.js +487 -0
  59. package/dist/hooks/lifecycle.d.ts +5 -0
  60. package/dist/hooks/lifecycle.js +180 -0
  61. package/dist/hooks/llm.d.ts +4 -0
  62. package/dist/hooks/llm.js +153 -0
  63. package/dist/hooks/pain.d.ts +5 -0
  64. package/dist/hooks/pain.js +173 -0
  65. package/dist/hooks/prompt.d.ts +38 -0
  66. package/dist/hooks/prompt.js +285 -0
  67. package/dist/hooks/subagent.d.ts +2 -0
  68. package/dist/hooks/subagent.js +70 -0
  69. package/dist/i18n/commands.d.ts +26 -0
  70. package/dist/i18n/commands.js +88 -0
  71. package/dist/index.d.ts +7 -0
  72. package/dist/index.js +204 -0
  73. package/dist/service/evolution-worker.d.ts +17 -0
  74. package/dist/service/evolution-worker.js +293 -0
  75. package/dist/tools/agent-spawn.d.ts +33 -0
  76. package/dist/tools/agent-spawn.js +170 -0
  77. package/dist/tools/critique-prompt.d.ts +14 -0
  78. package/dist/tools/critique-prompt.js +81 -0
  79. package/dist/tools/deep-reflect.d.ts +19 -0
  80. package/dist/tools/deep-reflect.js +174 -0
  81. package/dist/tools/model-index.d.ts +9 -0
  82. package/dist/tools/model-index.js +82 -0
  83. package/dist/types/event-types.d.ts +229 -0
  84. package/dist/types/event-types.js +73 -0
  85. package/dist/types/hygiene-types.d.ts +20 -0
  86. package/dist/types/hygiene-types.js +12 -0
  87. package/dist/types.d.ts +1 -0
  88. package/dist/types.js +1 -0
  89. package/dist/utils/file-lock.d.ts +64 -0
  90. package/dist/utils/file-lock.js +270 -0
  91. package/dist/utils/glob-match.d.ts +28 -0
  92. package/dist/utils/glob-match.js +49 -0
  93. package/dist/utils/hashing.d.ts +9 -0
  94. package/dist/utils/hashing.js +25 -0
  95. package/dist/utils/io.d.ts +6 -0
  96. package/dist/utils/io.js +106 -0
  97. package/dist/utils/nlp.d.ts +9 -0
  98. package/dist/utils/nlp.js +59 -0
  99. package/dist/utils/plugin-logger.d.ts +39 -0
  100. package/dist/utils/plugin-logger.js +70 -0
  101. package/openclaw.plugin.json +46 -0
  102. package/package.json +63 -0
  103. package/templates/langs/en/core/AGENTS.md +206 -0
  104. package/templates/langs/en/core/BOOT.md +60 -0
  105. package/templates/langs/en/core/BOOTSTRAP.md +250 -0
  106. package/templates/langs/en/core/HEARTBEAT.md +74 -0
  107. package/templates/langs/en/core/IDENTITY.md +8 -0
  108. package/templates/langs/en/core/PRINCIPLES.md +10 -0
  109. package/templates/langs/en/core/SOUL.md +76 -0
  110. package/templates/langs/en/core/TOOLS.md +53 -0
  111. package/templates/langs/en/core/USER.md +10 -0
  112. package/templates/langs/en/pain/00_seed_samples.md +23 -0
  113. package/templates/langs/en/pain_dictionary.json +22 -0
  114. package/templates/langs/en/skills/admin/SKILL.md +40 -0
  115. package/templates/langs/en/skills/bootstrap-tools/SKILL.md +53 -0
  116. package/templates/langs/en/skills/deductive-audit/SKILL.md +36 -0
  117. package/templates/langs/en/skills/evolution-framework-update/SKILL.md +31 -0
  118. package/templates/langs/en/skills/evolve-system/SKILL.md +46 -0
  119. package/templates/langs/en/skills/evolve-task/SKILL.md +83 -0
  120. package/templates/langs/en/skills/feedback/SKILL.md +51 -0
  121. package/templates/langs/en/skills/init-strategy/SKILL.md +54 -0
  122. package/templates/langs/en/skills/inject-rule/SKILL.md +19 -0
  123. package/templates/langs/en/skills/manage-okr/SKILL.md +96 -0
  124. package/templates/langs/en/skills/pain/SKILL.md +19 -0
  125. package/templates/langs/en/skills/pd-daily/SKILL.md +199 -0
  126. package/templates/langs/en/skills/pd-grooming/SKILL.md +46 -0
  127. package/templates/langs/en/skills/pd-mentor/SKILL.md +230 -0
  128. package/templates/langs/en/skills/plan-script/SKILL.md +32 -0
  129. package/templates/langs/en/skills/profile/SKILL.md +24 -0
  130. package/templates/langs/en/skills/reflection/SKILL.md +40 -0
  131. package/templates/langs/en/skills/reflection-log/SKILL.md +37 -0
  132. package/templates/langs/en/skills/report/SKILL.md +13 -0
  133. package/templates/langs/en/skills/root-cause/SKILL.md +33 -0
  134. package/templates/langs/en/skills/triage/SKILL.md +29 -0
  135. package/templates/langs/en/skills/watch-evolution/SKILL.md +33 -0
  136. package/templates/langs/zh/core/AGENTS.md +207 -0
  137. package/templates/langs/zh/core/BOOT.md +60 -0
  138. package/templates/langs/zh/core/BOOTSTRAP.md +250 -0
  139. package/templates/langs/zh/core/HEARTBEAT.md +74 -0
  140. package/templates/langs/zh/core/IDENTITY.md +8 -0
  141. package/templates/langs/zh/core/SOUL.md +76 -0
  142. package/templates/langs/zh/core/TOOLS.md +53 -0
  143. package/templates/langs/zh/core/USER.md +10 -0
  144. package/templates/langs/zh/pain/00_seed_samples.md +24 -0
  145. package/templates/langs/zh/pain_dictionary.json +18 -0
  146. package/templates/langs/zh/skills/admin/SKILL.md +42 -0
  147. package/templates/langs/zh/skills/bootstrap-tools/SKILL.md +52 -0
  148. package/templates/langs/zh/skills/deductive-audit/SKILL.md +36 -0
  149. package/templates/langs/zh/skills/evolution-framework-update/SKILL.md +31 -0
  150. package/templates/langs/zh/skills/evolve-system/SKILL.md +46 -0
  151. package/templates/langs/zh/skills/evolve-task/SKILL.md +83 -0
  152. package/templates/langs/zh/skills/feedback/SKILL.md +53 -0
  153. package/templates/langs/zh/skills/init-strategy/SKILL.md +54 -0
  154. package/templates/langs/zh/skills/inject-rule/SKILL.md +19 -0
  155. package/templates/langs/zh/skills/manage-okr/SKILL.md +109 -0
  156. package/templates/langs/zh/skills/pain/SKILL.md +19 -0
  157. package/templates/langs/zh/skills/pd-daily/SKILL.md +199 -0
  158. package/templates/langs/zh/skills/pd-grooming/SKILL.md +46 -0
  159. package/templates/langs/zh/skills/pd-mentor/SKILL.md +230 -0
  160. package/templates/langs/zh/skills/plan-script/SKILL.md +32 -0
  161. package/templates/langs/zh/skills/profile/SKILL.md +24 -0
  162. package/templates/langs/zh/skills/reflection/SKILL.md +40 -0
  163. package/templates/langs/zh/skills/reflection-log/SKILL.md +37 -0
  164. package/templates/langs/zh/skills/report/SKILL.md +13 -0
  165. package/templates/langs/zh/skills/root-cause/SKILL.md +33 -0
  166. package/templates/langs/zh/skills/triage/SKILL.md +29 -0
  167. package/templates/langs/zh/skills/watch-evolution/SKILL.md +33 -0
  168. package/templates/pain_dictionary.json +36 -0
  169. package/templates/pain_settings.json +77 -0
  170. package/templates/workspace/.principles/00-kernel.md +51 -0
  171. package/templates/workspace/.principles/DECISION_POLICY.json +44 -0
  172. package/templates/workspace/.principles/PRINCIPLES.md +20 -0
  173. package/templates/workspace/.principles/PROFILE.json +52 -0
  174. package/templates/workspace/.principles/PROFILE.schema.json +56 -0
  175. package/templates/workspace/.principles/THINKING_OS.md +64 -0
  176. package/templates/workspace/.principles/THINKING_OS_ARCHIVE.md +7 -0
  177. package/templates/workspace/.principles/THINKING_OS_CANDIDATES.md +9 -0
  178. package/templates/workspace/.principles/models/_INDEX.md +27 -0
  179. package/templates/workspace/.principles/models/first_principles.md +62 -0
  180. package/templates/workspace/.principles/models/marketing_4p.md +52 -0
  181. package/templates/workspace/.principles/models/porter_five.md +63 -0
  182. package/templates/workspace/.principles/models/swot.md +60 -0
  183. package/templates/workspace/.principles/models/user_story_map.md +63 -0
  184. package/templates/workspace/.state/WORKBOARD.json +4 -0
  185. package/templates/workspace/AUDIT.md +15 -0
  186. package/templates/workspace/PLAN.md +2 -0
  187. package/templates/workspace/okr/RECOVERY_PROTOCOL.md +56 -0
  188. package/templates/workspace/okr/TASK_CHANGES.jsonl +6 -0
  189. package/templates/workspace/okr/WEEK_TASKS.json +6 -0
@@ -0,0 +1,293 @@
1
+ import * as fs from 'fs';
2
+ import { createHash } from 'crypto';
3
+ import { DictionaryService } from '../core/dictionary-service.js';
4
+ import { DetectionService } from '../core/detection-service.js';
5
+ import { ensureStateTemplates } from '../core/init.js';
6
+ import { extractCommonSubstring } from '../utils/nlp.js';
7
+ import { SystemLogger } from '../core/system-logger.js';
8
+ import { WorkspaceContext } from '../core/workspace-context.js';
9
+ import { initPersistence, flushAllSessions } from '../core/session-tracker.js';
10
+ let intervalId = null;
11
+ function checkPainFlag(wctx, logger) {
12
+ try {
13
+ const painFlagPath = wctx.resolve('PAIN_FLAG');
14
+ if (!fs.existsSync(painFlagPath))
15
+ return;
16
+ const rawPain = fs.readFileSync(painFlagPath, 'utf8');
17
+ const lines = rawPain.split('\n');
18
+ let score = 0;
19
+ let source = 'unknown';
20
+ let reason = 'Systemic pain detected';
21
+ let preview = '';
22
+ let isQueued = false;
23
+ for (const line of lines) {
24
+ if (line.startsWith('score:'))
25
+ score = parseInt(line.split(':', 2)[1].trim(), 10) || 0;
26
+ if (line.startsWith('source:'))
27
+ source = line.split(':', 2)[1].trim();
28
+ if (line.startsWith('reason:'))
29
+ reason = line.slice('reason:'.length).trim();
30
+ if (line.startsWith('trigger_text_preview:'))
31
+ preview = line.slice('trigger_text_preview:'.length).trim();
32
+ if (line.startsWith('status: queued'))
33
+ isQueued = true;
34
+ }
35
+ if (isQueued || score < 30)
36
+ return;
37
+ if (logger)
38
+ logger.info(`[PD:EvolutionWorker] Detected pain flag (score: ${score}, source: ${source}). Enqueueing evolution task.`);
39
+ const queuePath = wctx.resolve('EVOLUTION_QUEUE');
40
+ let queue = [];
41
+ if (fs.existsSync(queuePath)) {
42
+ try {
43
+ queue = JSON.parse(fs.readFileSync(queuePath, 'utf8'));
44
+ }
45
+ catch (e) {
46
+ if (logger)
47
+ logger.error(`[PD:EvolutionWorker] Failed to parse evolution queue: ${String(e)}`);
48
+ }
49
+ }
50
+ const taskId = createHash('md5').update(`${source}:${score}:${new Date().toISOString()}`).digest('hex').substring(0, 8);
51
+ queue.push({
52
+ id: taskId,
53
+ score,
54
+ source,
55
+ reason,
56
+ trigger_text_preview: preview,
57
+ timestamp: new Date().toISOString(),
58
+ status: 'pending'
59
+ });
60
+ fs.writeFileSync(queuePath, JSON.stringify(queue, null, 2), 'utf8');
61
+ fs.appendFileSync(painFlagPath, '\nstatus: queued\n', 'utf8');
62
+ }
63
+ catch (err) {
64
+ if (logger)
65
+ logger.warn(`[PD:EvolutionWorker] Error processing pain flag: ${String(err)}`);
66
+ }
67
+ }
68
+ function processEvolutionQueue(wctx, logger, eventLog) {
69
+ try {
70
+ const queuePath = wctx.resolve('EVOLUTION_QUEUE');
71
+ if (!fs.existsSync(queuePath))
72
+ return;
73
+ const queue = JSON.parse(fs.readFileSync(queuePath, 'utf8'));
74
+ let queueChanged = false;
75
+ const config = wctx.config;
76
+ const timeout = config.get('intervals.task_timeout_ms') || (30 * 60 * 1000);
77
+ for (const task of queue) {
78
+ if (task.status === 'in_progress' && task.timestamp) {
79
+ const age = Date.now() - new Date(task.timestamp).getTime();
80
+ if (age > timeout) {
81
+ if (logger)
82
+ logger.info(`[PD:EvolutionWorker] Resetting timed-out task: ${task.id}`);
83
+ task.status = 'pending';
84
+ queueChanged = true;
85
+ }
86
+ }
87
+ }
88
+ const pendingTasks = queue.filter(t => t.status === 'pending');
89
+ if (pendingTasks.length > 0) {
90
+ const directivePath = wctx.resolve('EVOLUTION_DIRECTIVE');
91
+ const highestScoreTask = pendingTasks.sort((a, b) => b.score - a.score)[0];
92
+ const directive = {
93
+ active: true,
94
+ task: `Diagnose systemic pain [ID: ${highestScoreTask.id}]. Source: ${highestScoreTask.source}. Reason: ${highestScoreTask.reason}. ` +
95
+ `Trigger text: "${highestScoreTask.trigger_text_preview || 'N/A'}"`,
96
+ timestamp: new Date().toISOString()
97
+ };
98
+ fs.writeFileSync(directivePath, JSON.stringify(directive, null, 2), 'utf8');
99
+ highestScoreTask.status = 'in_progress';
100
+ queueChanged = true;
101
+ if (eventLog) {
102
+ eventLog.recordEvolutionTask({
103
+ taskId: highestScoreTask.id,
104
+ taskType: highestScoreTask.source,
105
+ reason: highestScoreTask.reason
106
+ });
107
+ }
108
+ }
109
+ if (queueChanged) {
110
+ fs.writeFileSync(queuePath, JSON.stringify(queue, null, 2), 'utf8');
111
+ }
112
+ }
113
+ catch (err) {
114
+ if (logger)
115
+ logger.warn(`[PD:EvolutionWorker] Error processing evolution queue: ${String(err)}`);
116
+ }
117
+ }
118
+ async function processDetectionQueue(wctx, api, eventLog) {
119
+ const logger = api.logger;
120
+ try {
121
+ const funnel = DetectionService.get(wctx.stateDir);
122
+ const queue = funnel.flushQueue();
123
+ if (queue.length === 0)
124
+ return;
125
+ if (logger)
126
+ logger.info(`[PD:EvolutionWorker] Processing ${queue.length} items from detection funnel.`);
127
+ const dictionary = DictionaryService.get(wctx.stateDir);
128
+ for (const text of queue) {
129
+ const match = dictionary.match(text);
130
+ if (match) {
131
+ if (eventLog) {
132
+ eventLog.recordRuleMatch(undefined, {
133
+ ruleId: match.ruleId,
134
+ layer: 'L2',
135
+ severity: match.severity,
136
+ textPreview: text.substring(0, 100)
137
+ });
138
+ }
139
+ }
140
+ else {
141
+ try {
142
+ const searchTool = api.runtime.tools?.createMemorySearchTool?.({ config: api.config });
143
+ if (searchTool) {
144
+ const searchResult = await searchTool.execute('pre-emptive-pain-check', {
145
+ query: text,
146
+ limit: 1,
147
+ threshold: 0.85
148
+ });
149
+ if (searchResult && searchResult.results?.length > 0) {
150
+ const hit = searchResult.results[0];
151
+ if (logger)
152
+ logger.info?.(`[PD:EvolutionWorker] L3 Semantic Hit: ${hit.id} (Score: ${hit.score})`);
153
+ funnel.updateCache(text, { detected: true, severity: 40 });
154
+ if (eventLog) {
155
+ eventLog.recordRuleMatch(undefined, {
156
+ ruleId: 'SEMANTIC_HIT',
157
+ layer: 'L3',
158
+ severity: 40,
159
+ textPreview: text.substring(0, 100)
160
+ });
161
+ }
162
+ }
163
+ }
164
+ }
165
+ catch (e) {
166
+ if (logger)
167
+ logger.debug?.(`[PD:EvolutionWorker] L3 Semantic search failed: ${String(e)}`);
168
+ }
169
+ trackPainCandidate(text, wctx);
170
+ }
171
+ }
172
+ }
173
+ catch (err) {
174
+ if (logger)
175
+ logger.warn(`[PD:EvolutionWorker] Detection queue failed: ${String(err)}`);
176
+ }
177
+ }
178
+ function trackPainCandidate(text, wctx) {
179
+ const candidatePath = wctx.resolve('PAIN_CANDIDATES');
180
+ let data = { candidates: {} };
181
+ if (fs.existsSync(candidatePath)) {
182
+ try {
183
+ data = JSON.parse(fs.readFileSync(candidatePath, 'utf8'));
184
+ }
185
+ catch (e) {
186
+ // Keep going with empty data if parse fails, but log it
187
+ console.error(`[PD:EvolutionWorker] Failed to parse pain candidates: ${String(e)}`);
188
+ }
189
+ }
190
+ const fingerprint = createHash('md5').update(text.substring(0, 50)).digest('hex').substring(0, 8);
191
+ if (!data.candidates[fingerprint]) {
192
+ data.candidates[fingerprint] = { count: 0, firstSeen: new Date().toISOString(), samples: [] };
193
+ }
194
+ const cand = data.candidates[fingerprint];
195
+ cand.count++;
196
+ if (cand.samples.length < 5)
197
+ cand.samples.push(text.substring(0, 200));
198
+ fs.writeFileSync(candidatePath, JSON.stringify(data, null, 2), 'utf8');
199
+ }
200
+ function processPromotion(wctx, logger, eventLog) {
201
+ const candidatePath = wctx.resolve('PAIN_CANDIDATES');
202
+ if (!fs.existsSync(candidatePath))
203
+ return;
204
+ try {
205
+ const config = wctx.config;
206
+ const dictionary = wctx.dictionary;
207
+ const data = JSON.parse(fs.readFileSync(candidatePath, 'utf8'));
208
+ const countThreshold = config.get('thresholds.promotion_count_threshold') || 3;
209
+ let promotedCount = 0;
210
+ for (const [fingerprint, cand] of Object.entries(data.candidates)) {
211
+ if (cand.status === 'pending' && cand.count >= countThreshold) {
212
+ const commonPhrases = extractCommonSubstring(cand.samples);
213
+ if (commonPhrases.length > 0) {
214
+ const phrase = commonPhrases[0];
215
+ const ruleId = `P_PROMOTED_${fingerprint.toUpperCase()}`;
216
+ if (logger)
217
+ logger.info(`[PD:EvolutionWorker] Promoting candidate ${fingerprint} to formal rule: ${ruleId}`);
218
+ SystemLogger.log(wctx.workspaceDir, 'RULE_PROMOTED', `Candidate ${fingerprint} promoted to rule ${ruleId}`);
219
+ dictionary.addRule(ruleId, {
220
+ type: 'exact_match',
221
+ phrases: [phrase],
222
+ severity: config.get('scores.default_confusion') || 35,
223
+ status: 'active'
224
+ });
225
+ cand.status = 'promoted';
226
+ promotedCount++;
227
+ }
228
+ }
229
+ }
230
+ if (promotedCount > 0) {
231
+ fs.writeFileSync(candidatePath, JSON.stringify(data, null, 2), 'utf8');
232
+ }
233
+ }
234
+ catch (err) {
235
+ if (logger)
236
+ logger.warn(`[PD:EvolutionWorker] Error during rule promotion: ${String(err)}`);
237
+ }
238
+ }
239
+ export const EvolutionWorkerService = {
240
+ id: 'principles-evolution-worker',
241
+ api: null,
242
+ start(ctx) {
243
+ const logger = ctx?.logger || console;
244
+ const api = this.api;
245
+ const workspaceDir = ctx?.workspaceDir;
246
+ if (!workspaceDir) {
247
+ if (logger)
248
+ logger.warn('[PD:EvolutionWorker] workspaceDir not found in service config. Evolution cycle disabled.');
249
+ return;
250
+ }
251
+ const wctx = WorkspaceContext.fromHookContext({ workspaceDir, ...ctx.config });
252
+ if (logger)
253
+ logger.info(`[PD:EvolutionWorker] Starting with workspaceDir=${wctx.workspaceDir}, stateDir=${wctx.stateDir}`);
254
+ initPersistence(wctx.stateDir);
255
+ const eventLog = wctx.eventLog;
256
+ const config = wctx.config;
257
+ const language = config.get('language') || 'en';
258
+ ensureStateTemplates({ logger }, wctx.stateDir, language);
259
+ const initialDelay = 5000;
260
+ const interval = config.get('intervals.worker_poll_ms') || (15 * 60 * 1000);
261
+ intervalId = setInterval(() => {
262
+ checkPainFlag(wctx, logger);
263
+ processEvolutionQueue(wctx, logger, eventLog);
264
+ if (api) {
265
+ processDetectionQueue(wctx, api, eventLog).catch(err => {
266
+ if (logger)
267
+ logger.error(`[PD:EvolutionWorker] Error in detection queue: ${String(err)}`);
268
+ });
269
+ }
270
+ processPromotion(wctx, logger, eventLog);
271
+ wctx.dictionary.flush();
272
+ flushAllSessions();
273
+ }, interval);
274
+ setTimeout(() => {
275
+ checkPainFlag(wctx, logger);
276
+ processEvolutionQueue(wctx, logger, eventLog);
277
+ if (api) {
278
+ processDetectionQueue(wctx, api, eventLog).catch(err => {
279
+ if (logger)
280
+ logger.error(`[PD:EvolutionWorker] Startup detection queue failed: ${String(err)}`);
281
+ });
282
+ }
283
+ processPromotion(wctx, logger, eventLog);
284
+ }, initialDelay);
285
+ },
286
+ stop(ctx) {
287
+ if (ctx?.logger)
288
+ ctx.logger.info('[PD:EvolutionWorker] Stopping background service...');
289
+ if (intervalId)
290
+ clearInterval(intervalId);
291
+ flushAllSessions();
292
+ }
293
+ };
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Agent Spawn Tool
3
+ *
4
+ * Provides a tool for spawning subagents with predefined agent definitions.
5
+ * Uses the low-level OpenClaw Subagent API.
6
+ */
7
+ import type { OpenClawPluginApi } from '../openclaw-sdk.js';
8
+ /**
9
+ * Agent Spawn Tool definition
10
+ */
11
+ export declare const agentSpawnTool: {
12
+ name: string;
13
+ description: string;
14
+ parameters: import("@sinclair/typebox").TObject<{
15
+ agentType: import("@sinclair/typebox").TString;
16
+ task: import("@sinclair/typebox").TString;
17
+ }>;
18
+ /**
19
+ * Execution logic for the agent spawn tool
20
+ */
21
+ execute(params: {
22
+ agentType: string;
23
+ task: string;
24
+ }, api: OpenClawPluginApi, _workspaceDir?: string): Promise<string>;
25
+ };
26
+ /**
27
+ * Batch spawn multiple agents in sequence
28
+ * Useful for evolution workflow
29
+ */
30
+ export declare function spawnAgentSequence(agents: Array<{
31
+ type: string;
32
+ task: string;
33
+ }>, api: OpenClawPluginApi, onProgress?: (agent: string, result: string) => void): Promise<Map<string, string>>;
@@ -0,0 +1,170 @@
1
+ /**
2
+ * Agent Spawn Tool
3
+ *
4
+ * Provides a tool for spawning subagents with predefined agent definitions.
5
+ * Uses the low-level OpenClaw Subagent API.
6
+ */
7
+ import { Type } from '@sinclair/typebox';
8
+ import { randomUUID } from 'node:crypto';
9
+ import { loadAgentDefinition, listAvailableAgents } from '../core/agent-loader.js';
10
+ /**
11
+ * Extract assistant text from session messages
12
+ */
13
+ function extractAssistantText(messages) {
14
+ if (!messages || typeof messages !== 'object')
15
+ return '';
16
+ const m = messages;
17
+ // Try assistantTexts helper first
18
+ if (m.assistantTexts && Array.isArray(m.assistantTexts)) {
19
+ return m.assistantTexts.join('\n');
20
+ }
21
+ // Fall back to parsing messages array
22
+ if (m.messages && Array.isArray(m.messages)) {
23
+ // Find the last assistant message
24
+ for (let i = m.messages.length - 1; i >= 0; i--) {
25
+ const msg = m.messages[i];
26
+ if (msg.role === 'assistant' && msg.content) {
27
+ if (typeof msg.content === 'string') {
28
+ return msg.content;
29
+ }
30
+ if (Array.isArray(msg.content)) {
31
+ const textParts = msg.content
32
+ .filter((c) => c.type === 'text' && c.text)
33
+ .map((c) => c.text);
34
+ if (textParts.length > 0) {
35
+ return textParts.join('\n');
36
+ }
37
+ }
38
+ }
39
+ }
40
+ }
41
+ return '';
42
+ }
43
+ /**
44
+ * Build the full system prompt for a subagent
45
+ * Combines the agent definition with any context-specific additions
46
+ */
47
+ function buildSubagentSystemPrompt(agentDef, _task) {
48
+ // The systemPrompt from the agent definition is the main content
49
+ // It will be appended to OpenClaw's minimal subagent prompt
50
+ return agentDef.systemPrompt;
51
+ }
52
+ /**
53
+ * Agent Spawn Tool definition
54
+ */
55
+ export const agentSpawnTool = {
56
+ name: 'pd_spawn_agent',
57
+ description: `启动指定类型的子智能体执行任务。
58
+
59
+ 可用的智能体类型:
60
+ - explorer: 快速收集证据(文件、日志、复现步骤)
61
+ - diagnostician: 根因分析(verb/adjective + 5Whys)
62
+ - auditor: 演绎审计(axiom/system/via-negativa)
63
+ - planner: 制定电影剧本计划
64
+ - implementer: 按计划执行代码修改
65
+ - reviewer: 代码审查(正确性、安全性、可维护性)
66
+ - reporter: 最终汇报(技术细节转管理报告)`,
67
+ parameters: Type.Object({
68
+ agentType: Type.String({
69
+ description: '智能体类型: explorer, diagnostician, auditor, planner, implementer, reviewer, reporter',
70
+ }),
71
+ task: Type.String({
72
+ description: '任务描述,详细说明子智能体需要完成的工作',
73
+ }),
74
+ }),
75
+ /**
76
+ * Execution logic for the agent spawn tool
77
+ */
78
+ async execute(params, api, _workspaceDir) {
79
+ const { agentType, task } = params;
80
+ // 1. Validate agent type
81
+ const availableAgents = listAvailableAgents();
82
+ if (!availableAgents.includes(agentType)) {
83
+ return `❌ 未找到智能体定义: "${agentType}"。
84
+
85
+ 可用的智能体: ${availableAgents.join(', ')}`;
86
+ }
87
+ // 2. Load agent definition
88
+ const agentDef = loadAgentDefinition(agentType);
89
+ if (!agentDef) {
90
+ return `❌ 无法加载智能体定义: ${agentType}`;
91
+ }
92
+ // 3. Check subagent runtime availability
93
+ const subagentRuntime = api.runtime?.subagent;
94
+ if (!subagentRuntime) {
95
+ return `❌ Subagent runtime 不可用。请确保 OpenClaw Gateway 正在运行。`;
96
+ }
97
+ // 4. Build session key
98
+ const sessionKey = `agent:${agentType}:${randomUUID()}`;
99
+ // 5. Build system prompt
100
+ const extraSystemPrompt = buildSubagentSystemPrompt(agentDef, task);
101
+ const startTime = Date.now();
102
+ try {
103
+ // 6. Run subagent
104
+ await subagentRuntime.run({
105
+ sessionKey,
106
+ message: task,
107
+ extraSystemPrompt,
108
+ lane: 'subagent',
109
+ deliver: false, // Critical: don't send directly to external channels
110
+ idempotencyKey: randomUUID(),
111
+ });
112
+ // 7. Wait for completion
113
+ const result = await subagentRuntime.waitForRun({
114
+ runId: sessionKey,
115
+ });
116
+ const duration = Date.now() - startTime;
117
+ // 8. Handle timeout
118
+ if (result.status === 'timeout') {
119
+ return `⚠️ 智能体 **${agentDef.name}** 执行超时 (${(duration / 1000).toFixed(1)}s)。
120
+
121
+ 建议:
122
+ - 简化任务描述
123
+ - 分解为多个子任务
124
+ - 检查任务是否需要更多上下文`;
125
+ }
126
+ // 9. Handle error
127
+ if (result.status === 'error') {
128
+ return `❌ 智能体 **${agentDef.name}** 执行失败: ${result.error || '未知错误'}`;
129
+ }
130
+ // 10. Get results
131
+ const messages = await subagentRuntime.getSessionMessages({ sessionKey });
132
+ const output = extractAssistantText(messages);
133
+ if (!output || output.trim() === '') {
134
+ return `⚠️ 智能体 **${agentDef.name}** 执行完成,但没有返回输出。`;
135
+ }
136
+ // 11. Return formatted result
137
+ return `✅ **${agentDef.name}** 执行完成 (${(duration / 1000).toFixed(1)}s)
138
+
139
+ ---
140
+
141
+ ${output}`;
142
+ }
143
+ catch (err) {
144
+ const errorMsg = err instanceof Error ? err.message : String(err);
145
+ return `❌ 智能体 **${agentDef.name}** 执行异常: ${errorMsg}`;
146
+ }
147
+ finally {
148
+ // 12. Cleanup session
149
+ try {
150
+ await subagentRuntime.deleteSession({ sessionKey });
151
+ }
152
+ catch {
153
+ // Ignore cleanup errors
154
+ }
155
+ }
156
+ },
157
+ };
158
+ /**
159
+ * Batch spawn multiple agents in sequence
160
+ * Useful for evolution workflow
161
+ */
162
+ export async function spawnAgentSequence(agents, api, onProgress) {
163
+ const results = new Map();
164
+ for (const { type, task } of agents) {
165
+ const result = await agentSpawnTool.execute({ agentType: type, task }, api);
166
+ results.set(type, result);
167
+ onProgress?.(type, result);
168
+ }
169
+ return results;
170
+ }
@@ -0,0 +1,14 @@
1
+ import type { OpenClawPluginApi } from '../openclaw-sdk.js';
2
+ /**
3
+ * 构建反思提示词 (Critique Prompt) V2
4
+ *
5
+ * 严格按照测试用例的调用习惯和断言要求进行重写。
6
+ * 增加 OpenClaw 兼容性路径解析。
7
+ */
8
+ export declare function buildCritiquePromptV2(params: {
9
+ context: string;
10
+ depth?: number;
11
+ model_id?: string;
12
+ workspaceDir?: string;
13
+ api?: OpenClawPluginApi;
14
+ }): string;
@@ -0,0 +1,81 @@
1
+ import { loadModelIndex } from './model-index.js';
2
+ /**
3
+ * 深度指令模板 (必须与测试用例中的 quick/balanced/thorough 关键字对齐)
4
+ */
5
+ const DEPTH_INSTRUCTIONS = {
6
+ 1: 'Provide a quick surface-level analysis.',
7
+ 2: 'Provide a balanced analysis with moderate depth.',
8
+ 3: 'Provide an extremely thorough and exhaustive analysis.',
9
+ };
10
+ /**
11
+ * 构建反思提示词 (Critique Prompt) V2
12
+ *
13
+ * 严格按照测试用例的调用习惯和断言要求进行重写。
14
+ * 增加 OpenClaw 兼容性路径解析。
15
+ */
16
+ export function buildCritiquePromptV2(params) {
17
+ const { context, depth = 2, model_id, workspaceDir, api } = params;
18
+ // 1. 确定工作区目录 (优先级:显式传入 > api.config > api.workspaceDir > api.resolvePath)
19
+ const effectiveWorkspaceDir = workspaceDir
20
+ || api?.config?.workspaceDir
21
+ || api?.workspaceDir
22
+ || api?.resolvePath?.('.');
23
+ if (!effectiveWorkspaceDir) {
24
+ throw new Error('Workspace directory is required for deep reflection.');
25
+ }
26
+ // 2. 深度校验与警告日志
27
+ let validatedDepth = 2;
28
+ if (typeof depth === 'number') {
29
+ if (depth >= 1 && depth <= 3) {
30
+ validatedDepth = depth;
31
+ }
32
+ else {
33
+ if (api?.logger) {
34
+ api.logger.warn(`[DeepReflect] Invalid depth value ${depth}. Falling back to 2.`);
35
+ }
36
+ }
37
+ }
38
+ const depthMsg = DEPTH_INSTRUCTIONS[validatedDepth];
39
+ // 3. 加载模型索引
40
+ const modelIndexMessage = loadModelIndex(effectiveWorkspaceDir, api);
41
+ // 4. 构造最终提示词
42
+ return `
43
+ # Role: Principal Critical Thinker & Strategist
44
+ ---
45
+ [SYSTEM_ID: Critical Analysis Engine]
46
+
47
+ ## Objective
48
+ Provide a high-intensity critical analysis and actionable feedback for the provided task context.
49
+
50
+ ## Depth Requirement
51
+ ${depthMsg}
52
+
53
+ ## Meta-Cognitive Models
54
+ The agent has inherited meta-cognitive models (T-01 to T-09) from the **thinking_os** framework. Use these as your foundational logic.
55
+
56
+ ## Model Selection Guidelines
57
+ Step 1: Determine if the task context is a **general planning** task or **domain-specific**.
58
+ Step 2: Select 1-2 relevant models.
59
+ Step 3: If no match is found, use **Fallback** to **Meta-Cognitive Models**.
60
+
61
+ ## Domain-Specific Models Index
62
+ ${modelIndexMessage}
63
+
64
+ ## Task Context to Analyze
65
+ ---
66
+ ${context}
67
+ ---
68
+
69
+ ## Instructions
70
+ 1. Apply the selected models rigorously.
71
+ 2. Identify blind spots and logic gaps.
72
+ 3. Provide high-impact recommendations.
73
+
74
+ ## Output Structure
75
+ - **Blind Spots**: ...
76
+ - **Risk Warnings**: ...
77
+ - **Alternative Approaches**: ...
78
+ - **Recommendations**: ...
79
+ - **Confidence Level**: [LOW/MEDIUM/HIGH]
80
+ `.trim();
81
+ }
@@ -0,0 +1,19 @@
1
+ import type { OpenClawPluginApi } from '../openclaw-sdk.js';
2
+ export declare const deepReflectTool: {
3
+ name: string;
4
+ description: string;
5
+ parameters: import("@sinclair/typebox").TObject<{
6
+ context: import("@sinclair/typebox").TString;
7
+ depth: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
8
+ model_id: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
9
+ }>;
10
+ /**
11
+ * Tool execution logic
12
+ * @param workspaceDir Optional parameter for unit testing
13
+ */
14
+ execute(params: {
15
+ context: string;
16
+ depth?: number;
17
+ model_id?: string;
18
+ }, api: OpenClawPluginApi, workspaceDir?: string): Promise<string>;
19
+ };