principles-disciple 1.28.2 → 1.29.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.
Files changed (93) hide show
  1. package/openclaw.plugin.json +1 -1
  2. package/package.json +1 -1
  3. package/scripts/acceptance-test.mjs +314 -0
  4. package/scripts/seed-nocturnal-scenarios.mjs +16 -9
  5. package/scripts/validate-live-path.ts +141 -17
  6. package/src/commands/archive-impl.ts +3 -0
  7. package/src/commands/context.ts +4 -1
  8. package/src/commands/disable-impl.ts +2 -2
  9. package/src/commands/evolution-status.ts +2 -2
  10. package/src/commands/focus.ts +4 -2
  11. package/src/commands/nocturnal-train.ts +9 -1
  12. package/src/commands/pain.ts +3 -1
  13. package/src/commands/pd-reflect.ts +2 -0
  14. package/src/commands/rollback-impl.ts +5 -1
  15. package/src/commands/rollback.ts +2 -1
  16. package/src/commands/samples.ts +1 -0
  17. package/src/commands/workflow-debug.ts +1 -0
  18. package/src/core/adaptive-thresholds.ts +2 -1
  19. package/src/core/code-implementation-storage.ts +2 -0
  20. package/src/core/config.ts +1 -0
  21. package/src/core/diagnostician-task-store.ts +2 -0
  22. package/src/core/empathy-keyword-matcher.ts +4 -1
  23. package/src/core/event-log.ts +6 -3
  24. package/src/core/evolution-engine.ts +4 -1
  25. package/src/core/evolution-logger.ts +1 -0
  26. package/src/core/external-training-contract.ts +2 -1
  27. package/src/core/focus-history.ts +15 -3
  28. package/src/core/init.ts +3 -1
  29. package/src/core/merge-gate-audit.ts +3 -0
  30. package/src/core/model-deployment-registry.ts +1 -0
  31. package/src/core/model-training-registry.ts +1 -0
  32. package/src/core/nocturnal-arbiter.ts +4 -3
  33. package/src/core/nocturnal-candidate-scoring.ts +5 -0
  34. package/src/core/nocturnal-compliance.ts +22 -1
  35. package/src/core/nocturnal-dataset.ts +3 -1
  36. package/src/core/nocturnal-export.ts +5 -0
  37. package/src/core/nocturnal-reasoning-deriver.ts +6 -1
  38. package/src/core/nocturnal-snapshot-contract.ts +1 -0
  39. package/src/core/nocturnal-trinity.ts +24 -3
  40. package/src/core/pain-context-extractor.ts +3 -1
  41. package/src/core/pain.ts +3 -1
  42. package/src/core/path-resolver.ts +10 -4
  43. package/src/core/pd-task-reconciler.ts +3 -1
  44. package/src/core/pd-task-store.ts +1 -0
  45. package/src/core/principle-internalization/deprecated-readiness.ts +2 -1
  46. package/src/core/principle-training-state.ts +2 -0
  47. package/src/core/principle-tree-ledger.ts +4 -0
  48. package/src/core/principle-tree-migration.ts +2 -1
  49. package/src/core/promotion-gate.ts +7 -1
  50. package/src/core/replay-engine.ts +10 -4
  51. package/src/core/risk-calculator.ts +2 -1
  52. package/src/core/rule-host.ts +3 -2
  53. package/src/core/session-tracker.ts +5 -2
  54. package/src/core/shadow-observation-registry.ts +1 -0
  55. package/src/core/thinking-os-parser.ts +1 -0
  56. package/src/core/trajectory.ts +9 -5
  57. package/src/hooks/bash-risk.ts +2 -0
  58. package/src/hooks/edit-verification.ts +3 -0
  59. package/src/hooks/gate-block-helper.ts +3 -0
  60. package/src/hooks/gate.ts +8 -0
  61. package/src/hooks/gfi-gate.ts +2 -0
  62. package/src/hooks/lifecycle.ts +1 -0
  63. package/src/hooks/llm.ts +1 -0
  64. package/src/hooks/pain.ts +3 -1
  65. package/src/hooks/progressive-trust-gate.ts +3 -0
  66. package/src/hooks/prompt.ts +5 -2
  67. package/src/hooks/subagent.ts +1 -0
  68. package/src/hooks/thinking-checkpoint.ts +1 -0
  69. package/src/hooks/trajectory-collector.ts +2 -1
  70. package/src/http/principles-console-route.ts +5 -2
  71. package/src/index.ts +7 -0
  72. package/src/service/central-health-service.ts +1 -0
  73. package/src/service/central-overview-service.ts +2 -0
  74. package/src/service/evolution-query-service.ts +1 -0
  75. package/src/service/evolution-worker.ts +31 -1
  76. package/src/service/health-query-service.ts +6 -6
  77. package/src/service/monitoring-query-service.ts +4 -0
  78. package/src/service/nocturnal-runtime.ts +7 -5
  79. package/src/service/nocturnal-service.ts +21 -0
  80. package/src/service/nocturnal-target-selector.ts +2 -0
  81. package/src/service/runtime-summary-service.ts +6 -5
  82. package/src/service/subagent-workflow/deep-reflect-workflow-manager.ts +2 -1
  83. package/src/service/subagent-workflow/empathy-observer-workflow-manager.ts +2 -0
  84. package/src/service/subagent-workflow/nocturnal-workflow-manager.ts +3 -2
  85. package/src/service/subagent-workflow/workflow-manager-base.ts +6 -1
  86. package/src/service/subagent-workflow/workflow-store.ts +2 -0
  87. package/src/tools/deep-reflect.ts +9 -0
  88. package/src/tools/model-index.ts +1 -0
  89. package/src/tools/write-pain-flag.ts +1 -0
  90. package/src/utils/file-lock.ts +1 -0
  91. package/src/utils/io.ts +2 -1
  92. package/tests/core/nocturnal-e2e.test.ts +10 -0
  93. package/tests/tools/write-pain-flag.test.ts +29 -13
@@ -99,6 +99,7 @@ function showStatus(workspaceDir: string, isZh: boolean): string {
99
99
  * Toggle a boolean setting
100
100
  */
101
101
 
102
+ // eslint-disable-next-line @typescript-eslint/max-params
102
103
  function toggleSetting(
103
104
  workspaceDir: string,
104
105
  key: 'thinkingOs' | 'reflectionLog',
@@ -214,6 +215,7 @@ function applyPreset(
214
215
  isZh: boolean
215
216
  ): string {
216
217
 
218
+ // eslint-disable-next-line @typescript-eslint/init-declarations
217
219
  let config: ContextInjectionConfig;
218
220
 
219
221
  switch (preset) {
@@ -305,7 +307,7 @@ function showHelp(isZh: boolean): string {
305
307
  /**
306
308
  * Main command handler
307
309
  */
308
- // eslint-disable-next-line complexity -- complexity 15, refactor candidate
310
+
309
311
  export function handleContextCommand(ctx: PluginCommandContext): PluginCommandResult {
310
312
  const workspaceDir = getWorkspaceDir(ctx);
311
313
  const args = (ctx.args || '').trim().split(/\s+/);
@@ -316,6 +318,7 @@ export function handleContextCommand(ctx: PluginCommandContext): PluginCommandRe
316
318
  const isZh = (ctx.config?.language as string) === 'zh';
317
319
 
318
320
 
321
+ // eslint-disable-next-line @typescript-eslint/init-declarations
319
322
  let result: string;
320
323
 
321
324
  switch (subCommand) {
@@ -70,7 +70,7 @@ function _handleListActive(
70
70
  }
71
71
 
72
72
 
73
- // eslint-disable-next-line complexity -- complexity 15, refactor candidate
73
+ // eslint-disable-next-line @typescript-eslint/max-params -- complexity 15, refactor candidate
74
74
  function _handleDisableImpl(
75
75
  workspaceDir: string,
76
76
  stateDir: string,
@@ -131,7 +131,7 @@ function _handleDisableImpl(
131
131
  * /pd-disable-impl <implId> - Disable an implementation
132
132
  * /pd-disable-impl <implId> --reason "<reason>" - Disable with reason
133
133
  */
134
- // eslint-disable-next-line complexity -- complexity 12, refactor candidate
134
+
135
135
  export function handleDisableImplCommand(ctx: PluginCommandContext): PluginCommandResult {
136
136
  const workspaceDir = (ctx.config?.workspaceDir as string) || process.cwd();
137
137
  const {stateDir} = WorkspaceContext.fromHookContext({ ...ctx, workspaceDir });
@@ -46,7 +46,7 @@ function formatRouteRecommendations(
46
46
  }
47
47
 
48
48
 
49
- // eslint-disable-next-line complexity -- complexity 15, refactor candidate
49
+ // eslint-disable-next-line @typescript-eslint/max-params -- complexity 15, refactor candidate
50
50
  function buildEnglishOutput(
51
51
  workspaceDir: string,
52
52
  sessionId: string | null,
@@ -99,7 +99,7 @@ function buildEnglishOutput(
99
99
  }
100
100
 
101
101
 
102
- // eslint-disable-next-line complexity -- complexity 15, refactor candidate
102
+ // eslint-disable-next-line @typescript-eslint/max-params -- complexity 15, refactor candidate
103
103
  function buildChineseOutput(
104
104
  workspaceDir: string,
105
105
  sessionId: string | null,
@@ -47,7 +47,7 @@ function getWorkspaceDir(ctx: PluginCommandContext): string {
47
47
  * - 清理:Working Memory 超过 10 条记录时保留最近 10 条
48
48
  * - 验证:文件引用指向不存在的文件时移除
49
49
  */
50
- // eslint-disable-next-line complexity -- complexity 13, refactor candidate
50
+
51
51
  function compressFocusContent(content: string, workspaceDir?: string): string {
52
52
  // 首先使用 cleanupStaleInfo 进行基础清理
53
53
  let result = cleanupStaleInfo(content, workspaceDir);
@@ -283,6 +283,7 @@ async function compressFocus(
283
283
 
284
284
  // 5. 压缩内容
285
285
 
286
+ // eslint-disable-next-line @typescript-eslint/init-declarations
286
287
  let compressedContent: string;
287
288
  try {
288
289
  compressedContent = compressFocusContent(oldContent, workspaceDir);
@@ -347,7 +348,7 @@ ${milestoneNote ? `${milestoneNote}\n` : ''}
347
348
  /**
348
349
  * 回滚到历史版本
349
350
  */
350
- // eslint-disable-next-line complexity -- complexity 13, refactor candidate
351
+
351
352
  function rollbackFocus(workspaceDir: string, index: number, isZh: boolean): string {
352
353
  const wctx = WorkspaceContext.fromHookContext({ workspaceDir });
353
354
  const focusPath = wctx.resolve('CURRENT_FOCUS');
@@ -480,6 +481,7 @@ export async function handleFocusCommand(
480
481
  const isZh = (ctx.config?.language as string) === 'zh';
481
482
 
482
483
 
484
+ // eslint-disable-next-line @typescript-eslint/init-declarations
483
485
  let result: string;
484
486
 
485
487
  switch (subCommand) {
@@ -285,6 +285,7 @@ Hardware tiers:
285
285
  fs.writeFileSync(specPath, JSON.stringify(spec, null, 2), 'utf-8');
286
286
 
287
287
 
288
+ // eslint-disable-next-line @typescript-eslint/init-declarations
288
289
  let trainerResult!: TrainingExperimentResult;
289
290
 
290
291
  try {
@@ -393,6 +394,7 @@ Hardware tiers:
393
394
  // Process trainer result (register checkpoint)
394
395
  // dry_run returns null (no checkpoint); other statuses throw on error
395
396
 
397
+ // eslint-disable-next-line @typescript-eslint/init-declarations
396
398
  let processed: { checkpointId: string; checkpointRef: string } | null;
397
399
  try {
398
400
  processed = program.processResult({
@@ -534,7 +536,7 @@ Next steps:
534
536
  }
535
537
  }
536
538
 
537
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Reason: JSON.parse returns dynamic JSON - type unknown at parse time, narrowed via type narrowing below
539
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/init-declarations -- Reason: JSON.parse returns dynamic JSON - type unknown at parse time, narrowed via type narrowing below
538
540
  let result: any;
539
541
  try {
540
542
  result = JSON.parse(resultJson);
@@ -566,6 +568,7 @@ Next steps:
566
568
  // Process the result
567
569
  const program = new TrainingProgram(workspaceDir);
568
570
 
571
+ // eslint-disable-next-line @typescript-eslint/init-declarations
569
572
  let processed: { checkpointId: string; checkpointRef: string } | null;
570
573
  try {
571
574
  processed = program.processResult({
@@ -753,10 +756,15 @@ Next steps:
753
756
  }
754
757
 
755
758
  // Destructure benchmark result - delta property contains the actual delta value
759
+ // eslint-disable-next-line @typescript-eslint/prefer-destructuring
756
760
  delta = benchmarkResult.delta.delta;
761
+ // eslint-disable-next-line @typescript-eslint/prefer-destructuring
757
762
  baselineScore = benchmarkResult.delta.baselineScore;
763
+ // eslint-disable-next-line @typescript-eslint/prefer-destructuring
758
764
  candidateScore = benchmarkResult.delta.candidateScore;
765
+ // eslint-disable-next-line @typescript-eslint/prefer-destructuring
759
766
  benchmarkId = benchmarkResult.benchmarkId;
767
+ // eslint-disable-next-line @typescript-eslint/prefer-destructuring
760
768
  verdict = benchmarkResult.verdict;
761
769
  } else {
762
770
  // Manual mode: require explicit delta and verdict
@@ -97,6 +97,7 @@ export function handlePainCommand(ctx: PluginCommandContext): PluginCommandResul
97
97
  // Handle empathy subcommand
98
98
  if (args.startsWith('empathy')) {
99
99
 
100
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
100
101
  return handleEmpathySubcommand(wctx, args, sessionId, isZh);
101
102
  }
102
103
 
@@ -137,6 +138,7 @@ export function handlePainCommand(ctx: PluginCommandContext): PluginCommandResul
137
138
 
138
139
  // Determine health status based on GFI
139
140
 
141
+ // eslint-disable-next-line @typescript-eslint/init-declarations
140
142
  let healthLabel: string;
141
143
  let suggestionText = '';
142
144
 
@@ -216,7 +218,7 @@ export function handlePainCommand(ctx: PluginCommandContext): PluginCommandResul
216
218
  * Handle /pd-status empathy subcommand
217
219
  */
218
220
 
219
- // eslint-disable-next-line complexity -- complexity 13, refactor candidate
221
+ // eslint-disable-next-line @typescript-eslint/max-params -- complexity 13, refactor candidate
220
222
  function handleEmpathySubcommand(
221
223
  wctx: WorkspaceContext,
222
224
  args: string,
@@ -22,6 +22,7 @@ export const handlePdReflect: PluginCommandDefinition = {
22
22
  requireAuth: false,
23
23
  handler: async (ctx: PdReflectContext): Promise<PluginCommandResult> => {
24
24
  try {
25
+ // eslint-disable-next-line @typescript-eslint/prefer-destructuring
25
26
  const workspaceDir = ctx.workspaceDir;
26
27
  if (!workspaceDir) {
27
28
  return { text: 'Cannot determine workspace directory. Ensure you are in an active workspace.', isError: true };
@@ -32,6 +33,7 @@ export const handlePdReflect: PluginCommandDefinition = {
32
33
 
33
34
  // Acquire lock before modifying queue
34
35
  const releaseLock = await acquireQueueLock(queuePath, ctx.api?.logger, EVOLUTION_QUEUE_LOCK_SUFFIX);
36
+ // eslint-disable-next-line @typescript-eslint/init-declarations
35
37
  let taskId: string | undefined;
36
38
  try {
37
39
  let rawQueue: unknown[] = [];
@@ -41,7 +41,7 @@ function getAllImplementations(stateDir: string): Implementation[] {
41
41
  * /pd-rollback-impl <implId> - Rollback current active
42
42
  * /pd-rollback-impl <implId> --reason "<reason>" - Rollback with reason
43
43
  */
44
- // eslint-disable-next-line complexity -- complexity 12, refactor candidate
44
+
45
45
  export function handleRollbackImplCommand(ctx: PluginCommandContext): PluginCommandResult {
46
46
  const workspaceDir = (ctx.config?.workspaceDir as string) || process.cwd();
47
47
  const {stateDir} = WorkspaceContext.fromHookContext({ ...ctx, workspaceDir });
@@ -59,10 +59,12 @@ export function handleRollbackImplCommand(ctx: PluginCommandContext): PluginComm
59
59
  // List active
60
60
  if (subcommand === 'list' || subcommand === '') {
61
61
 
62
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
62
63
  return _handleListActiveRollback(stateDir, isZh);
63
64
  }
64
65
 
65
66
 
67
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
66
68
  return _handleRollbackImpl(workspaceDir, stateDir, implId, reason, isZh, ctx.sessionId);
67
69
  }
68
70
 
@@ -105,6 +107,7 @@ function _handleListActiveRollback(
105
107
  }
106
108
 
107
109
 
110
+ // eslint-disable-next-line @typescript-eslint/max-params
108
111
  function _handleRollbackImpl(
109
112
  workspaceDir: string,
110
113
  stateDir: string,
@@ -140,6 +143,7 @@ function _handleRollbackImpl(
140
143
  transitionImplementationState(stateDir, implId, 'disabled');
141
144
 
142
145
 
146
+ // eslint-disable-next-line @typescript-eslint/init-declarations
143
147
  let restoredMessage: string;
144
148
 
145
149
  if (previousActiveId && allImpls.some((i) => i.id === previousActiveId)) {
@@ -45,8 +45,9 @@ Usage:
45
45
  }
46
46
 
47
47
 
48
+ // eslint-disable-next-line @typescript-eslint/init-declarations
48
49
  let eventId: string | null;
49
- // eslint-disable-next-line @typescript-eslint/no-unused-vars -- Reason: triggerMethod is reserved for future extension - tracking rollback trigger source
50
+
50
51
  const _triggerMethod = 'user_command' as const;
51
52
 
52
53
  if (args === 'last') {
@@ -30,6 +30,7 @@ export function handleSamplesCommand(ctx: PluginCommandContext): PluginCommandRe
30
30
  const normalizedDecision = decision === 'approve' ? 'approved' : 'rejected';
31
31
  const note = noteParts.join(' ').trim();
32
32
 
33
+ // eslint-disable-next-line @typescript-eslint/init-declarations
33
34
  let record;
34
35
  try {
35
36
  record = wctx.trajectory.reviewCorrectionSample(sampleId, normalizedDecision, note);
@@ -21,6 +21,7 @@ function formatState(state: string): string {
21
21
  }
22
22
 
23
23
 
24
+ // eslint-disable-next-line @typescript-eslint/max-params
24
25
  function buildOutput(
25
26
  workflowId: string,
26
27
  summary: ReturnType<InstanceType<typeof WorkflowStore>['getWorkflow']>,
@@ -301,6 +301,7 @@ export function getEffectiveThresholds(stateDir: string): ThresholdValues {
301
301
  * @returns UpdateThresholdResult
302
302
  */
303
303
 
304
+ // eslint-disable-next-line @typescript-eslint/max-params
304
305
  export function updateThresholdState(
305
306
  stateDir: string,
306
307
  thresholdName: ThresholdName,
@@ -407,7 +408,7 @@ export function getDetailedThresholdState(
407
408
  * @param signals - Observable signals
408
409
  * @returns UpdateThresholdResult describing the most significant change
409
410
  */
410
- // eslint-disable-next-line complexity -- complexity 15, refactor candidate
411
+
411
412
  export function adjustThresholdsFromSignals(
412
413
  stateDir: string,
413
414
  signals: ThresholdSignals
@@ -135,6 +135,7 @@ export function writeManifest(
135
135
  }
136
136
 
137
137
 
138
+ // eslint-disable-next-line @typescript-eslint/max-params
138
139
  export function writeEntrySource(
139
140
  stateDir: string,
140
141
  implId: string,
@@ -190,6 +191,7 @@ export function loadEntrySource(stateDir: string, implId: string): string | null
190
191
  * Idempotent: calling again with the same implId will NOT overwrite an existing entry.js.
191
192
  */
192
193
 
194
+ // eslint-disable-next-line @typescript-eslint/max-params
193
195
  export function createImplementationAssetDir(
194
196
  stateDir: string,
195
197
  implId: string,
@@ -291,6 +291,7 @@ export class PainConfig {
291
291
  * Basic validation for critical settings
292
292
  */
293
293
 
294
+ // eslint-disable-next-line @typescript-eslint/class-methods-use-this
294
295
  private validate(settings: PainSettings): void {
295
296
  // Ensure intervals are positive
296
297
  if (settings.intervals.worker_poll_ms < 1000) settings.intervals.worker_poll_ms = 15 * 60 * 1000;
@@ -83,6 +83,7 @@ export async function addDiagnosticianTask(
83
83
  const filePath = resolveTasksPath(stateDir);
84
84
  await withLockAsync(filePath, async () => {
85
85
 
86
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
86
87
  const store = readTaskStoreSync(filePath);
87
88
  store.tasks[taskId] = {
88
89
  prompt,
@@ -106,6 +107,7 @@ export async function completeDiagnosticianTask(
106
107
  const filePath = resolveTasksPath(stateDir);
107
108
  await withLockAsync(filePath, async () => {
108
109
 
110
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
109
111
  const store = readTaskStoreSync(filePath);
110
112
  delete store.tasks[taskId];
111
113
  const tmpPath = filePath + '.tmp';
@@ -81,6 +81,7 @@ export function loadKeywordStore(stateDir: string, language?: 'zh' | 'en'): Empa
81
81
  if (!fs.existsSync(filePath)) {
82
82
  const store = createDefaultKeywordStore(language);
83
83
 
84
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
84
85
  saveKeywordStore(stateDir, store);
85
86
  return store;
86
87
  }
@@ -93,6 +94,7 @@ export function loadKeywordStore(stateDir: string, language?: 'zh' | 'en'): Empa
93
94
  console.warn('[PD:Empathy] Invalid keyword store format, creating default');
94
95
  const store = createDefaultKeywordStore(language);
95
96
 
97
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
96
98
  saveKeywordStore(stateDir, store);
97
99
  return store;
98
100
  }
@@ -102,6 +104,7 @@ export function loadKeywordStore(stateDir: string, language?: 'zh' | 'en'): Empa
102
104
  console.warn(`[PD:Empathy] Failed to load keyword store: ${e}`);
103
105
  const store = createDefaultKeywordStore(language);
104
106
 
107
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
105
108
  saveKeywordStore(stateDir, store);
106
109
  return store;
107
110
  }
@@ -207,7 +210,7 @@ export function matchEmpathyKeywords(
207
210
  * This is called when the empathy optimizer subagent completes its analysis
208
211
  * and returns suggested updates to the keyword store.
209
212
  */
210
- // eslint-disable-next-line complexity -- complexity 13, refactor candidate
213
+
211
214
  export function applyKeywordUpdates(
212
215
  store: EmpathyKeywordStore,
213
216
  updates: Record<string, {
@@ -108,6 +108,7 @@ export class EventLog {
108
108
  }
109
109
 
110
110
 
111
+ // eslint-disable-next-line @typescript-eslint/max-params
111
112
  private record(
112
113
  type: EventType,
113
114
  category: EventCategory,
@@ -135,6 +136,7 @@ export class EventLog {
135
136
  }
136
137
 
137
138
 
139
+ // eslint-disable-next-line @typescript-eslint/class-methods-use-this
138
140
  private formatDate(date: Date): string {
139
141
  return date.toISOString().split('T')[0];
140
142
  }
@@ -160,7 +162,7 @@ export class EventLog {
160
162
  }
161
163
 
162
164
  if (entry.type === 'tool_call') {
163
- // eslint-disable-next-line @typescript-eslint/no-unused-vars -- Reason: data used for type narrowing only, actual fields accessed via stats
165
+
164
166
  const _data = entry.data as unknown as ToolCallEventData;
165
167
  stats.tools.total++;
166
168
  if (entry.category === 'success') stats.tools.success++;
@@ -244,7 +246,7 @@ export class EventLog {
244
246
  }
245
247
 
246
248
 
247
- // eslint-disable-next-line complexity -- complexity 13, refactor candidate
249
+ // eslint-disable-next-line @typescript-eslint/class-methods-use-this -- complexity 13, refactor candidate
248
250
  private getEventDedupKey(entry: EventLogEntry): string {
249
251
  const eventId = typeof (entry.data as { eventId?: unknown } | undefined)?.eventId === 'string'
250
252
  ? String((entry.data as { eventId?: string }).eventId)
@@ -341,7 +343,7 @@ export class EventLog {
341
343
  * @param range 'today' | 'week' | 'session'
342
344
  * @param sessionId Optional session ID for session-scoped stats
343
345
  */
344
- // eslint-disable-next-line complexity -- complexity 12, refactor candidate
346
+
345
347
  getEmpathyStats(range: 'today' | 'week' | 'session', sessionId?: string): EmpathyEventStats {
346
348
  const now = new Date();
347
349
  const today = this.formatDate(now);
@@ -462,6 +464,7 @@ export class EventLog {
462
464
  * Returns the rolled back score, or 0 if event not found.
463
465
  */
464
466
 
467
+ // eslint-disable-next-line @typescript-eslint/max-params
465
468
  rollbackEmpathyEvent(eventId: string, sessionId: string | undefined, reason: string, triggeredBy: 'user_command' | 'natural_language' | 'system'): number {
466
469
  const allEvents = this.getMergedEvents();
467
470
  let foundEvent: { entry: EventLogEntry; data: PainSignalEventData } | null = null;
@@ -165,7 +165,7 @@ export class EvolutionEngine {
165
165
 
166
166
  // ===== 记录失败 =====
167
167
 
168
- // eslint-disable-next-line complexity -- complexity 12, refactor candidate
168
+
169
169
  public recordFailure(
170
170
  toolName: string,
171
171
  options?: {
@@ -325,6 +325,7 @@ export class EvolutionEngine {
325
325
  // ===== 事件管理 =====
326
326
 
327
327
 
328
+ // eslint-disable-next-line @typescript-eslint/max-params
328
329
  private createEvent(
329
330
  type: 'success' | 'failure',
330
331
  taskHash: string,
@@ -387,6 +388,7 @@ export class EvolutionEngine {
387
388
  }
388
389
 
389
390
 
391
+ // eslint-disable-next-line @typescript-eslint/class-methods-use-this
390
392
  private createNewScorecard(): EvolutionScorecard {
391
393
  const now = new Date().toISOString();
392
394
  return {
@@ -529,6 +531,7 @@ export class EvolutionEngine {
529
531
  // ===== 工具方法 =====
530
532
 
531
533
 
534
+ // eslint-disable-next-line @typescript-eslint/class-methods-use-this
532
535
  private generateId(): string {
533
536
  return `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
534
537
  }
@@ -265,6 +265,7 @@ export class EvolutionLogger {
265
265
  principlesGenerated?: number;
266
266
  }): void {
267
267
 
268
+ // eslint-disable-next-line @typescript-eslint/init-declarations
268
269
  let summary: string;
269
270
  if (params.resolution === 'marker_detected' || params.resolution === 'late_marker_principle_created') {
270
271
  summary = `任务 ${params.taskId} 完成,已生成 ${params.principlesGenerated || 0} 条原则`;
@@ -285,7 +285,7 @@ export interface ValidationResult {
285
285
  * @param result - The trainer result to validate
286
286
  * @returns ValidationResult indicating pass/fail and any errors
287
287
  */
288
- // eslint-disable-next-line complexity -- complexity 11, slightly over threshold
288
+
289
289
  export function validateTrainerResult(
290
290
  spec: TrainingExperimentSpec,
291
291
  result: TrainingExperimentResult
@@ -405,6 +405,7 @@ export function computeConfigFingerprint(config: Partial<TrainingHyperparameters
405
405
  */
406
406
  export function computeDatasetFingerprint(exportPath: string, sampleCount: number): string {
407
407
 
408
+ // eslint-disable-next-line @typescript-eslint/init-declarations
408
409
  let contentHash: string;
409
410
  try {
410
411
  const content = fs.readFileSync(exportPath, 'utf-8');
@@ -265,7 +265,7 @@ export function compressFocus(focusPath: string, newContent: string): {
265
265
  * @param content CURRENT_FOCUS.md 内容
266
266
  * @param maxLines 最大行数
267
267
  */
268
- // eslint-disable-next-line complexity -- complexity 12, refactor candidate
268
+
269
269
  export function extractSummary(content: string, maxLines = 30): string {
270
270
  const lines = content.split('\n');
271
271
  const sections: { [key: string]: string[] } = {
@@ -430,6 +430,7 @@ export function extractWorkingMemory(
430
430
 
431
431
  // 尝试从文本中提取描述
432
432
 
433
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
433
434
  const description = extractDescription(text, filePath);
434
435
 
435
436
  snapshot.artifacts.push({
@@ -445,19 +446,23 @@ export function extractWorkingMemory(
445
446
 
446
447
  // 从文本中提取文件操作(备用方式)
447
448
 
449
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
448
450
  extractFileArtifacts(text, snapshot.artifacts, workspaceDir);
449
451
 
450
452
  // 提取问题
451
453
 
454
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
452
455
  extractProblems(text, snapshot.activeProblems);
453
456
 
454
457
  // 提取下一步
455
458
 
459
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
456
460
  extractNextActions(text, snapshot.nextActions);
457
461
  }
458
462
 
459
463
  // 去重和限制数量
460
464
 
465
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
461
466
  snapshot.artifacts = deduplicateArtifacts(snapshot.artifacts).slice(-MAX_ARTIFACTS);
462
467
  snapshot.activeProblems = snapshot.activeProblems.slice(-MAX_PROBLEMS);
463
468
  snapshot.nextActions = snapshot.nextActions.slice(-MAX_NEXT_ACTIONS);
@@ -478,6 +483,7 @@ function extractFileArtifacts(
478
483
  const filePathRegex = /(?:file_path|absolute_path)["']?\s*[:=]\s*["']([^"']+\.(ts|js|json|md|yaml|yml|py|sh|mjs|cjs))["']/gi;
479
484
 
480
485
 
486
+ // eslint-disable-next-line @typescript-eslint/init-declarations
481
487
  let match;
482
488
  while ((match = filePathRegex.exec(text)) !== null) {
483
489
  const [, filePath] = match;
@@ -508,6 +514,7 @@ function extractFileArtifacts(
508
514
 
509
515
  // 尝试提取描述(从附近的文本)
510
516
 
517
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
511
518
  const description = extractDescription(text, filePath);
512
519
 
513
520
  artifacts.push({
@@ -541,6 +548,7 @@ function extractFileArtifacts(
541
548
  }
542
549
 
543
550
 
551
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
544
552
  const description = extractDescription(text, filePath);
545
553
 
546
554
  artifacts.push({
@@ -589,6 +597,7 @@ function extractProblems(
589
597
  // 问题模式(匹配问题描述)
590
598
  const problemPattern = /(?:问题|problem|error|错误|失败|failed)[::]\s*([^\n]{5,100})/gi;
591
599
 
600
+ // eslint-disable-next-line @typescript-eslint/init-declarations
592
601
  let match;
593
602
  while ((match = problemPattern.exec(text)) !== null) {
594
603
  const content = match[1].trim();
@@ -632,6 +641,7 @@ function extractNextActions(text: string, actions: string[]): void {
632
641
 
633
642
  for (const pattern of patterns) {
634
643
 
644
+ // eslint-disable-next-line @typescript-eslint/init-declarations
635
645
  let match;
636
646
  while ((match = pattern.exec(text)) !== null) {
637
647
  const action = match[1].trim();
@@ -691,6 +701,7 @@ export function parseWorkingMemorySection(content: string): WorkingMemorySnapsho
691
701
  // | 文件路径 | 操作 | 描述 |
692
702
  const tableRegex = /\|\s*`?([^`|\n]+)`?\s*\|\s*(created|modified|deleted)\s*\|\s*([^|\n]*)\s*\|/gi;
693
703
 
704
+ // eslint-disable-next-line @typescript-eslint/init-declarations
694
705
  let match;
695
706
  while ((match = tableRegex.exec(wmContent)) !== null) {
696
707
  snapshot.artifacts.push({
@@ -730,6 +741,7 @@ export function mergeWorkingMemory(content: string, snapshot: WorkingMemorySnaps
730
741
 
731
742
  // 生成 Working Memory 章节
732
743
 
744
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
733
745
  const wmSection = generateWorkingMemorySection(snapshot);
734
746
 
735
747
  if (wmIndex === -1) {
@@ -806,7 +818,7 @@ function generateWorkingMemorySection(snapshot: WorkingMemorySnapshot): string {
806
818
  /**
807
819
  * 生成工作记忆注入字符串(用于 prompt 注入)
808
820
  */
809
- // eslint-disable-next-line complexity -- complexity 13, refactor candidate
821
+
810
822
  export function workingMemoryToInjection(snapshot: WorkingMemorySnapshot | null): string {
811
823
  if (!snapshot) return '';
812
824
 
@@ -886,7 +898,7 @@ interface CompressionConfig {
886
898
  * @param stateDir state 目录路径
887
899
  * @returns 压缩配置
888
900
  */
889
- // eslint-disable-next-line complexity -- complexity 11, slightly over threshold
901
+
890
902
  function loadCompressionConfig(stateDir?: string): CompressionConfig {
891
903
  if (!stateDir) {
892
904
  return DEFAULT_COMPRESSION_CONFIG;
package/src/core/init.ts CHANGED
@@ -34,7 +34,7 @@ function hasOutdatedCoreGuidance(file: string, content: string): boolean {
34
34
  * Ensures that the workspace has the necessary template files for Principles Disciple.
35
35
  * This function flattens 'core' templates to the root so OpenClaw can find them.
36
36
  */
37
- // eslint-disable-next-line complexity -- complexity 14, refactor candidate
37
+
38
38
  export function ensureWorkspaceTemplates(api: OpenClawPluginApi, workspaceDir: string, language = 'en') {
39
39
  try {
40
40
  const __filename = fileURLToPath(import.meta.url);
@@ -45,6 +45,7 @@ export function ensureWorkspaceTemplates(api: OpenClawPluginApi, workspaceDir: s
45
45
  if (fs.existsSync(commonTemplatesDir)) {
46
46
  api.logger.info(`[PD] Syncing workspace templates: ${workspaceDir}...`);
47
47
 
48
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
48
49
  copyRecursiveSync(commonTemplatesDir, workspaceDir, api);
49
50
  }
50
51
 
@@ -87,6 +88,7 @@ export function ensureWorkspaceTemplates(api: OpenClawPluginApi, workspaceDir: s
87
88
  fs.mkdirSync(painDestDir, { recursive: true });
88
89
  }
89
90
 
91
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
90
92
  copyRecursiveSync(painTemplatesDir, painDestDir, api);
91
93
  }
92
94
 
@@ -342,6 +342,7 @@ function hasValidEvidenceSummary(parsed: unknown): boolean {
342
342
  * Validate a single replay report file and return its category.
343
343
  */
344
344
  function validateSingleReplayReport(reportPath: string): ReplayValidationCategory {
345
+ // eslint-disable-next-line @typescript-eslint/init-declarations
345
346
  let rawContent: string;
346
347
  try {
347
348
  rawContent = fs.readFileSync(reportPath, 'utf-8');
@@ -349,6 +350,7 @@ function validateSingleReplayReport(reportPath: string): ReplayValidationCategor
349
350
  return 'io_error';
350
351
  }
351
352
 
353
+ // eslint-disable-next-line @typescript-eslint/init-declarations
352
354
  let parsed: unknown;
353
355
  try {
354
356
  parsed = JSON.parse(rawContent);
@@ -364,6 +366,7 @@ function validateSingleReplayReport(reportPath: string): ReplayValidationCategor
364
366
  return 'missing_evidence_summary';
365
367
  }
366
368
 
369
+ // eslint-disable-next-line @typescript-eslint/prefer-destructuring
367
370
  const evidenceSummary = parsed.evidenceSummary;
368
371
  if (parsed.overallDecision === 'pass' && evidenceSummary.totalSamples === 0) {
369
372
  return 'unsupported_pass';
@@ -350,6 +350,7 @@ export function assertPromotionGatePassed(stateDir: string, checkpointId: string
350
350
  * @throws Error if checkpoint's targetModelFamily violates profile constraints
351
351
  */
352
352
 
353
+ // eslint-disable-next-line @typescript-eslint/max-params
353
354
  export function bindCheckpointToWorkerProfile(
354
355
  stateDir: string,
355
356
  workerProfile: WorkerProfile,
@@ -322,6 +322,7 @@ export function registerTrainingRun(
322
322
  * @throws Error if run not found or transition is invalid
323
323
  */
324
324
 
325
+ // eslint-disable-next-line @typescript-eslint/max-params
325
326
  export function updateTrainingRunStatus(
326
327
  stateDir: string,
327
328
  trainRunId: string,