principles-disciple 1.16.0 → 1.18.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 (132) hide show
  1. package/README.md +13 -5
  2. package/openclaw.plugin.json +4 -4
  3. package/package.json +1 -1
  4. package/src/commands/archive-impl.ts +3 -3
  5. package/src/commands/capabilities.ts +1 -1
  6. package/src/commands/context.ts +3 -3
  7. package/src/commands/disable-impl.ts +1 -1
  8. package/src/commands/evolution-status.ts +2 -2
  9. package/src/commands/focus.ts +2 -2
  10. package/src/commands/nocturnal-train.ts +6 -6
  11. package/src/commands/pain.ts +4 -4
  12. package/src/commands/pd-reflect.ts +87 -0
  13. package/src/commands/rollback-impl.ts +4 -4
  14. package/src/commands/rollback.ts +2 -2
  15. package/src/commands/samples.ts +2 -2
  16. package/src/commands/workflow-debug.ts +1 -1
  17. package/src/config/errors.ts +1 -1
  18. package/src/core/adaptive-thresholds.ts +1 -1
  19. package/src/core/code-implementation-storage.ts +2 -2
  20. package/src/core/config.ts +1 -1
  21. package/src/core/diagnostician-task-store.ts +2 -2
  22. package/src/core/empathy-keyword-matcher.ts +3 -3
  23. package/src/core/event-log.ts +5 -5
  24. package/src/core/evolution-engine.ts +4 -4
  25. package/src/core/evolution-logger.ts +1 -1
  26. package/src/core/evolution-reducer.ts +3 -3
  27. package/src/core/evolution-types.ts +5 -5
  28. package/src/core/external-training-contract.ts +1 -1
  29. package/src/core/focus-history.ts +14 -14
  30. package/src/core/hygiene/tracker.ts +1 -1
  31. package/src/core/init.ts +2 -2
  32. package/src/core/model-deployment-registry.ts +2 -2
  33. package/src/core/model-training-registry.ts +2 -2
  34. package/src/core/nocturnal-arbiter.ts +1 -1
  35. package/src/core/nocturnal-artificer.ts +2 -2
  36. package/src/core/nocturnal-candidate-scoring.ts +2 -2
  37. package/src/core/nocturnal-compliance.ts +4 -3
  38. package/src/core/nocturnal-dataset.ts +3 -3
  39. package/src/core/nocturnal-export.ts +4 -4
  40. package/src/core/nocturnal-rule-implementation-validator.ts +1 -1
  41. package/src/core/nocturnal-snapshot-contract.ts +112 -0
  42. package/src/core/nocturnal-trajectory-extractor.ts +7 -5
  43. package/src/core/nocturnal-trinity.ts +480 -158
  44. package/src/core/pain-context-extractor.ts +3 -3
  45. package/src/core/pain.ts +124 -11
  46. package/src/core/path-resolver.ts +4 -4
  47. package/src/core/pd-task-reconciler.ts +10 -10
  48. package/src/core/pd-task-service.ts +1 -1
  49. package/src/core/pd-task-store.ts +1 -1
  50. package/src/core/principle-internalization/deprecated-readiness.ts +1 -1
  51. package/src/core/principle-training-state.ts +2 -2
  52. package/src/core/principle-tree-ledger.ts +7 -7
  53. package/src/core/promotion-gate.ts +9 -9
  54. package/src/core/replay-engine.ts +12 -12
  55. package/src/core/risk-calculator.ts +1 -1
  56. package/src/core/rule-host-types.ts +2 -2
  57. package/src/core/rule-host.ts +5 -5
  58. package/src/core/schema/db-types.ts +1 -1
  59. package/src/core/schema/schema-definitions.ts +1 -1
  60. package/src/core/session-tracker.ts +96 -4
  61. package/src/core/shadow-observation-registry.ts +3 -3
  62. package/src/core/system-logger.ts +2 -2
  63. package/src/core/thinking-os-parser.ts +1 -1
  64. package/src/core/training-program.ts +2 -2
  65. package/src/core/trajectory.ts +8 -8
  66. package/src/core/workspace-context.ts +2 -2
  67. package/src/core/workspace-dir-service.ts +85 -0
  68. package/src/core/workspace-dir-validation.ts +30 -107
  69. package/src/hooks/bash-risk.ts +3 -3
  70. package/src/hooks/edit-verification.ts +4 -4
  71. package/src/hooks/gate-block-helper.ts +4 -4
  72. package/src/hooks/gate.ts +10 -10
  73. package/src/hooks/gfi-gate.ts +7 -7
  74. package/src/hooks/lifecycle.ts +2 -2
  75. package/src/hooks/llm.ts +1 -1
  76. package/src/hooks/pain.ts +25 -5
  77. package/src/hooks/progressive-trust-gate.ts +7 -7
  78. package/src/hooks/prompt.ts +24 -5
  79. package/src/hooks/subagent.ts +2 -2
  80. package/src/hooks/thinking-checkpoint.ts +2 -2
  81. package/src/hooks/trajectory-collector.ts +1 -1
  82. package/src/http/principles-console-route.ts +14 -6
  83. package/src/i18n/commands.ts +4 -0
  84. package/src/index.ts +181 -185
  85. package/src/service/central-health-service.ts +1 -1
  86. package/src/service/central-overview-service.ts +3 -3
  87. package/src/service/evolution-query-service.ts +1 -1
  88. package/src/service/evolution-worker.ts +221 -109
  89. package/src/service/health-query-service.ts +27 -17
  90. package/src/service/monitoring-query-service.ts +3 -3
  91. package/src/service/nocturnal-runtime.ts +4 -4
  92. package/src/service/nocturnal-service.ts +40 -23
  93. package/src/service/nocturnal-target-selector.ts +11 -4
  94. package/src/service/runtime-summary-service.ts +1 -1
  95. package/src/service/subagent-workflow/deep-reflect-workflow-manager.ts +1 -1
  96. package/src/service/subagent-workflow/empathy-observer-workflow-manager.ts +3 -3
  97. package/src/service/subagent-workflow/nocturnal-workflow-manager.ts +16 -13
  98. package/src/service/subagent-workflow/runtime-direct-driver.ts +10 -6
  99. package/src/service/subagent-workflow/types.ts +4 -4
  100. package/src/service/subagent-workflow/workflow-manager-base.ts +5 -5
  101. package/src/service/subagent-workflow/workflow-store.ts +2 -2
  102. package/src/tools/critique-prompt.ts +2 -3
  103. package/src/tools/deep-reflect.ts +17 -16
  104. package/src/tools/model-index.ts +1 -1
  105. package/src/utils/file-lock.ts +1 -1
  106. package/src/utils/io.ts +7 -2
  107. package/src/utils/nlp.ts +1 -1
  108. package/src/utils/plugin-logger.ts +2 -2
  109. package/src/utils/retry.ts +3 -2
  110. package/src/utils/subagent-probe.ts +20 -33
  111. package/templates/langs/en/skills/pd-pain-signal/SKILL.md +8 -7
  112. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/nocturnal-trinity-quality-enhancement.json +111 -0
  113. package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/task-specs.mjs +1 -1
  114. package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/run.mjs +1 -1
  115. package/templates/langs/zh/skills/pd-pain-signal/SKILL.md +8 -7
  116. package/templates/pain_settings.json +1 -1
  117. package/tests/build-artifacts.test.ts +4 -58
  118. package/tests/commands/pd-reflect.test.ts +49 -0
  119. package/tests/core/nocturnal-snapshot-contract.test.ts +70 -0
  120. package/tests/core/pain-auto-repair.test.ts +96 -0
  121. package/tests/core/pain-integration.test.ts +483 -0
  122. package/tests/core/pain.test.ts +5 -4
  123. package/tests/core/workspace-dir-service.test.ts +68 -0
  124. package/tests/core/workspace-dir-validation.test.ts +56 -192
  125. package/tests/hooks/pain.test.ts +20 -0
  126. package/tests/http/principles-console-route.test.ts +42 -20
  127. package/tests/integration/empathy-workflow-integration.test.ts +1 -2
  128. package/tests/integration/tool-hooks-workspace-dir.e2e.test.ts +9 -17
  129. package/tests/service/empathy-observer-workflow-manager.test.ts +1 -2
  130. package/tests/service/evolution-worker.nocturnal.test.ts +118 -109
  131. package/tests/service/nocturnal-runtime-hardening.test.ts +33 -0
  132. package/tests/utils/subagent-probe.test.ts +32 -0
package/src/index.ts CHANGED
@@ -38,6 +38,7 @@ import { handleFocusCommand } from './commands/focus.js';
38
38
  import { handleRollbackCommand } from './commands/rollback.js';
39
39
  import { handlePromoteImplCommand } from './commands/promote-impl.js';
40
40
  import { handleDisableImplCommand } from './commands/disable-impl.js';
41
+ import { handlePdReflect } from './commands/pd-reflect.js';
41
42
  import { handleArchiveImplCommand } from './commands/archive-impl.js';
42
43
  import { handleRollbackImplCommand } from './commands/rollback-impl.js';
43
44
  import { handleEvolutionStatusCommand } from './commands/evolution-status.js';
@@ -57,11 +58,44 @@ import { migrateDirectoryStructure } from './core/migration.js';
57
58
  import { SystemLogger } from './core/system-logger.js';
58
59
  import { createDeepReflectTool } from './tools/deep-reflect.js';
59
60
  import { PathResolver, resolveWorkspaceDirFromApi } from './core/path-resolver.js';
61
+ import { validateWorkspaceDir } from './core/workspace-dir-validation.js';
62
+ import { resolveRequiredWorkspaceDir, resolveWorkspaceDir, type WorkspaceResolutionContext } from './core/workspace-dir-service.js';
60
63
  import { createPrinciplesConsoleRoute } from './http/principles-console-route.js';
61
64
 
62
65
  // Track initialization to avoid repeated calls
63
66
  let workspaceInitialized = false;
64
67
 
68
+ /**
69
+ * Resolve workspaceDir for slash commands.
70
+ * Chain: ctx.workspaceDir → resolveWorkspaceDirFromApi (official OpenClaw API + env vars)
71
+ *
72
+ * CRITICAL: Throws if workspaceDir cannot be resolved. Silent failures are dangerous
73
+ * because commands might operate on the wrong directory.
74
+ */
75
+ function resolveCommandWorkspaceDir(
76
+ api: OpenClawPluginApi,
77
+ ctx: { workspaceDir?: string },
78
+ ): string {
79
+ // 1. Direct from command context (most reliable — set by OpenClaw for current session)
80
+ if (ctx.workspaceDir) {
81
+ const issue = validateWorkspaceDir(ctx.workspaceDir);
82
+ if (!issue) return ctx.workspaceDir;
83
+ api.logger.error(`[PD:Command] ctx.workspaceDir="${ctx.workspaceDir}" is invalid: ${issue}`);
84
+ }
85
+
86
+ // 2. Official OpenClaw API → env vars → config file
87
+ const resolved = resolveWorkspaceDirFromApi(api);
88
+ if (resolved) return resolved;
89
+
90
+ // CRITICAL FAILURE: Cannot determine workspace directory
91
+ const errorMsg = `[PD:Command] CRITICAL: Cannot resolve workspace directory. ` +
92
+ `ctx.workspaceDir="${ctx.workspaceDir}" is invalid, and all fallbacks failed. ` +
93
+ `Commands will NOT execute to prevent data corruption.`;
94
+ api.logger.error(errorMsg);
95
+
96
+ throw new Error(errorMsg);
97
+ }
98
+
65
99
  // Map from childSessionKey → shadowObservationId
66
100
  // Used to complete shadow observations when subagent ends
67
101
  const pendingShadowObservations = new Map<string, string>();
@@ -82,14 +116,19 @@ function computeRuntimeShadowTaskFingerprint(event: PluginHookSubagentSpawningEv
82
116
  return crypto.createHash('sha256').update(JSON.stringify(payload)).digest('hex').slice(0, 16);
83
117
  }
84
118
 
85
- import { resolveValidWorkspaceDir, validateWorkspaceDir } from './core/workspace-dir-validation.js';
119
+ function resolveCommandWorkspaceDirStrict(
120
+ api: OpenClawPluginApi,
121
+ ctx: WorkspaceResolutionContext,
122
+ ): string {
123
+ return resolveRequiredWorkspaceDir(api, ctx, { source: 'command' });
124
+ }
86
125
 
87
- function resolveToolHookWorkspaceDir(
88
- ctx: { workspaceDir?: string; agentId?: string },
126
+ function resolveToolHookWorkspaceDirSafe(
127
+ ctx: WorkspaceResolutionContext,
89
128
  api: OpenClawPluginApi,
90
129
  source: string,
91
- ): string {
92
- return resolveValidWorkspaceDir(ctx, api, { source });
130
+ ): string | undefined {
131
+ return resolveWorkspaceDir(api, ctx, { source });
93
132
  }
94
133
 
95
134
  const plugin = {
@@ -105,7 +144,7 @@ const plugin = {
105
144
  // Catches OpenClaw context bugs early (e.g., missing workspaceDir in tool hooks)
106
145
  setTimeout(() => {
107
146
  const testCtx = { agentId: 'main' };
108
- const toolWorkspaceDir = resolveToolHookWorkspaceDir(testCtx, api, 'startup.health_check');
147
+ const toolWorkspaceDir = resolveToolHookWorkspaceDirSafe(testCtx, api, 'startup.health_check');
109
148
  const toolIssue = validateWorkspaceDir(toolWorkspaceDir);
110
149
  if (toolIssue) {
111
150
  api.logger.error(`[PD:health] Tool hook workspaceDir is INVALID: "${toolWorkspaceDir}" - ${toolIssue}`);
@@ -121,9 +160,10 @@ const plugin = {
121
160
  api.on(
122
161
  'before_prompt_build',
123
162
  async (event: PluginHookBeforePromptBuildEvent, ctx: PluginHookAgentContext): Promise<PluginHookBeforePromptBuildResult | void> => {
163
+ const workspaceDir = resolveToolHookWorkspaceDirSafe(ctx, api, 'before_prompt_build');
164
+ if (!workspaceDir) return;
124
165
  try {
125
- const workspaceDir = ctx.workspaceDir || api.resolvePath('.');
126
- if (!workspaceInitialized && workspaceDir) {
166
+ if (!workspaceInitialized) {
127
167
  migrateDirectoryStructure(api, workspaceDir);
128
168
  ensureWorkspaceTemplates(api, workspaceDir, language);
129
169
  SystemLogger.log(workspaceDir, 'SYSTEM_BOOT', `Principles Disciple online. Language: ${language}`);
@@ -139,7 +179,6 @@ const plugin = {
139
179
 
140
180
  return result;
141
181
  } catch (err) {
142
- const workspaceDir = ctx.workspaceDir || api.resolvePath('.');
143
182
  WorkspaceContext.fromHookContext({ workspaceDir }).eventLog.recordHookExecution({
144
183
  hook: 'before_prompt_build',
145
184
  sessionId: ctx.sessionId,
@@ -154,7 +193,8 @@ const plugin = {
154
193
  api.on(
155
194
  'before_tool_call',
156
195
  (event: PluginHookBeforeToolCallEvent, ctx: PluginHookToolContext): PluginHookBeforeToolCallResult | void => {
157
- const workspaceDir = resolveToolHookWorkspaceDir(ctx, api, 'before_tool_call');
196
+ const workspaceDir = resolveToolHookWorkspaceDirSafe(ctx, api, 'before_tool_call');
197
+ if (!workspaceDir) return;
158
198
  try {
159
199
  const pluginConfig = api.pluginConfig ?? {};
160
200
  const {logger} = api;
@@ -166,8 +206,7 @@ const plugin = {
166
206
 
167
207
  return result;
168
208
  } catch (err) {
169
- const fallbackDir = resolveToolHookWorkspaceDir(ctx, api, 'before_tool_call');
170
- WorkspaceContext.fromHookContext({ workspaceDir: fallbackDir }).eventLog.recordHookExecution({
209
+ WorkspaceContext.fromHookContext({ workspaceDir }).eventLog.recordHookExecution({
171
210
  hook: 'before_tool_call',
172
211
  error: String(err)
173
212
  }, { flushImmediately: true });
@@ -180,7 +219,8 @@ const plugin = {
180
219
  api.on(
181
220
  'after_tool_call',
182
221
  (event: PluginHookAfterToolCallEvent, ctx: PluginHookToolContext): void => {
183
- const workspaceDir = resolveToolHookWorkspaceDir(ctx, api, 'after_tool_call');
222
+ const workspaceDir = resolveToolHookWorkspaceDirSafe(ctx, api, 'after_tool_call');
223
+ if (!workspaceDir) return;
184
224
  try {
185
225
  const pluginConfig = api.pluginConfig ?? {};
186
226
  // Pass api separately to handleAfterToolCall to maintain type safety
@@ -190,8 +230,7 @@ const plugin = {
190
230
  hook: 'after_tool_call'
191
231
  }, { flushImmediately: true });
192
232
  } catch (err) {
193
- const fallbackDir = resolveToolHookWorkspaceDir(ctx, api, 'after_tool_call');
194
- WorkspaceContext.fromHookContext({ workspaceDir: fallbackDir }).eventLog.recordHookExecution({
233
+ WorkspaceContext.fromHookContext({ workspaceDir }).eventLog.recordHookExecution({
195
234
  hook: 'after_tool_call',
196
235
  error: String(err)
197
236
  }, { flushImmediately: true });
@@ -204,7 +243,8 @@ const plugin = {
204
243
  api.on(
205
244
  'llm_output',
206
245
  (event: PluginHookLlmOutputEvent, ctx: PluginHookAgentContext): void => {
207
- const workspaceDir = resolveToolHookWorkspaceDir(ctx as unknown as Record<string, unknown>, api, 'llm_output');
246
+ const workspaceDir = resolveToolHookWorkspaceDirSafe(ctx as unknown as Record<string, unknown>, api, 'llm_output');
247
+ if (!workspaceDir) return;
208
248
  try {
209
249
  handleLlmOutput(event, { ...ctx, workspaceDir });
210
250
 
@@ -229,9 +269,10 @@ const plugin = {
229
269
  'after_tool_call',
230
270
  (event: PluginHookAfterToolCallEvent, ctx: PluginHookToolContext): void => {
231
271
  try {
232
- const workspaceDir = resolveToolHookWorkspaceDir(ctx, api, 'trajectory.after_tool_call');
272
+ const workspaceDir = resolveToolHookWorkspaceDirSafe(ctx, api, 'trajectory.after_tool_call');
273
+ if (!workspaceDir) return;
233
274
  TrajectoryCollector.handleAfterToolCall(event, { ...ctx, workspaceDir });
234
- // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars -- Reason: catch binding intentionally unused
275
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars -- Reason: catch binding intentionally unused
235
276
  } catch (_err) {
236
277
  // Non-critical: don't log, just skip
237
278
  }
@@ -242,9 +283,10 @@ const plugin = {
242
283
  'llm_output',
243
284
  (event: PluginHookLlmOutputEvent, ctx: PluginHookAgentContext): void => {
244
285
  try {
245
- const workspaceDir = resolveToolHookWorkspaceDir(ctx as unknown as Record<string, unknown>, api, 'trajectory.llm_output');
286
+ const workspaceDir = resolveToolHookWorkspaceDirSafe(ctx as unknown as Record<string, unknown>, api, 'trajectory.llm_output');
287
+ if (!workspaceDir) return;
246
288
  TrajectoryCollector.handleLlmOutput(event, { ...ctx, workspaceDir });
247
- // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars -- Reason: catch binding intentionally unused
289
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars -- Reason: catch binding intentionally unused
248
290
  } catch (_err) {
249
291
  // Non-critical: don't log, just skip
250
292
  }
@@ -254,7 +296,7 @@ const plugin = {
254
296
  // ── Hook: Subagent Loop Closure ──
255
297
  api.on(
256
298
  'subagent_spawning',
257
- // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars -- Reason: ctx param required by hook callback signature but not used in this handler
299
+
258
300
  (event: PluginHookSubagentSpawningEvent, _ctx: PluginHookSubagentContext): void | PluginHookSubagentSpawningResult => {
259
301
  try {
260
302
  // Resolve workspace via official API, falling back to PathResolver
@@ -327,17 +369,20 @@ const plugin = {
327
369
 
328
370
  // ── Hook: Lifecycle ──
329
371
  api.on('before_reset', (event: PluginHookBeforeResetEvent, ctx: PluginHookAgentContext) => {
330
- const workspaceDir = ctx.workspaceDir || api.resolvePath('.');
372
+ const workspaceDir = resolveToolHookWorkspaceDirSafe(ctx, api, 'before_reset');
373
+ if (!workspaceDir) return;
331
374
  return handleBeforeReset(event, { ...ctx, workspaceDir });
332
375
  });
333
376
 
334
377
  api.on('before_compaction', (event: PluginHookBeforeCompactionEvent, ctx: PluginHookAgentContext) => {
335
- const workspaceDir = ctx.workspaceDir || api.resolvePath('.');
378
+ const workspaceDir = resolveToolHookWorkspaceDirSafe(ctx, api, 'before_compaction');
379
+ if (!workspaceDir) return;
336
380
  return handleBeforeCompaction(event, { ...ctx, workspaceDir });
337
381
  });
338
382
 
339
383
  api.on('after_compaction', (event: PluginHookAfterCompactionEvent, ctx: PluginHookAgentContext) => {
340
- const workspaceDir = ctx.workspaceDir || api.resolvePath('.');
384
+ const workspaceDir = resolveToolHookWorkspaceDirSafe(ctx, api, 'after_compaction');
385
+ if (!workspaceDir) return;
341
386
  return handleAfterCompaction(event, { ...ctx, workspaceDir });
342
387
  });
343
388
 
@@ -353,165 +398,116 @@ const plugin = {
353
398
  }
354
399
 
355
400
  // ── Slash Commands ──
356
- api.registerCommand({
357
- name: "pd-init",
358
- description: getCommandDescription('pd-init', language),
359
- handler: (ctx) => handleInitStrategy(ctx)
360
- });
361
-
362
- api.registerCommand({
363
- name: "pd-okr",
364
- description: getCommandDescription('pd-okr', language),
365
- handler: (ctx) => handleManageOkr(ctx)
366
- });
367
-
368
- api.registerCommand({
369
- name: "pd-bootstrap",
370
- description: getCommandDescription('pd-bootstrap', language),
371
- handler: (ctx) => handleBootstrapTools(ctx)
372
- });
373
-
374
- api.registerCommand({
375
- name: "pd-research",
376
- description: getCommandDescription('pd-research', language),
377
- handler: (ctx) => handleResearchTools(ctx)
378
- });
379
-
380
- api.registerCommand({
381
- name: "pd-thinking",
382
- description: getCommandDescription('pd-thinking', language),
383
- acceptsArgs: true,
384
- handler: (ctx) => handleThinkingOs(ctx)
385
- });
386
-
387
- api.registerCommand({
388
- name: "pd-daily",
389
- description: getCommandDescription('pd-daily', language),
390
- handler: () => {
391
- return { text: language === 'zh'
392
- ? "请执行 pd-daily 技能来配置并发送进化日报。系统将引导你完成配置流程,包括发送时间、渠道和报告风格偏好。"
393
- : "Please execute the pd-daily skill to configure and send your daily evolution report. The system will guide you through the configuration process." };
401
+ // Register command with optional short alias
402
+ const registerCommandWithAlias = (name: string, alias: string | null, desc: string, handler: any, opts?: { acceptsArgs?: boolean }) => {
403
+ const base = {
404
+ name,
405
+ description: desc,
406
+ handler,
407
+ ...(opts?.acceptsArgs ? { acceptsArgs: true } : {}),
408
+ };
409
+ api.registerCommand(base);
410
+ if (alias) {
411
+ api.registerCommand({
412
+ ...base,
413
+ name: alias,
414
+ description: `${desc} (alias of /${name})`,
415
+ });
394
416
  }
395
- });
396
-
397
- api.registerCommand({
398
- name: "pd-grooming",
399
- description: getCommandDescription('pd-grooming', language),
400
- handler: () => {
401
- return { text: language === 'zh'
402
- ? "请执行 pd-grooming 技能来执行大扫除。例如输入: '执行 pd-grooming 技能'"
403
- : "Please execute the pd-grooming skill to clean up. For example: 'Execute pd-grooming skill'" };
417
+ };
418
+
419
+ registerCommandWithAlias('pd-init', 'pdi', getCommandDescription('pd-init', language), (ctx: any) => handleInitStrategy(ctx));
420
+ registerCommandWithAlias('pd-okr', 'pdk', getCommandDescription('pd-okr', language), (ctx: any) => handleManageOkr(ctx));
421
+ registerCommandWithAlias('pd-bootstrap', 'pdb', getCommandDescription('pd-bootstrap', language), (ctx: any) => handleBootstrapTools(ctx));
422
+ registerCommandWithAlias('pd-research', 'pdr', getCommandDescription('pd-research', language), (ctx: any) => handleResearchTools(ctx));
423
+ registerCommandWithAlias('pd-thinking', 'pdt', getCommandDescription('pd-thinking', language), (ctx: any) => handleThinkingOs(ctx), { acceptsArgs: true });
424
+ registerCommandWithAlias('pd-reflect', 'pdrl', getCommandDescription('pd-reflect', language), (ctx: any) => {
425
+ try {
426
+ const workspaceDir = resolveCommandWorkspaceDirStrict(api, ctx);
427
+ return handlePdReflect.handler({ ...ctx, api, workspaceDir } as any);
428
+ } catch (err) {
429
+ api.logger.error(`[PD] Command /pd-reflect failed: ${String(err)}`);
430
+ return { text: language === 'zh' ? "命令执行失败,请检查日志。" : "Command failed. Check logs." };
404
431
  }
405
432
  });
406
-
407
- api.registerCommand({
408
- name: "pd-help",
409
- description: getCommandDescription('pd-help', language),
410
- handler: () => {
433
+ registerCommandWithAlias('pd-daily', 'pdd', getCommandDescription('pd-daily', language), () => ({
434
+ text: language === 'zh'
435
+ ? "请执行 pd-daily 技能来配置并发送进化日报。系统将引导你完成配置流程,包括发送时间、渠道和报告风格偏好。"
436
+ : "Please execute the pd-daily skill to configure and send your daily evolution report. The system will guide you through the configuration process."
437
+ }));
438
+ registerCommandWithAlias('pd-grooming', 'pdg', getCommandDescription('pd-grooming', language), () => ({
439
+ text: language === 'zh'
440
+ ? "请执行 pd-grooming 技能来执行大扫除。例如输入: '执行 pd-grooming 技能'"
441
+ : "Please execute the pd-grooming skill to clean up. For example: 'Execute pd-grooming skill'"
442
+ }));
443
+ registerCommandWithAlias('pd-help', 'pdh', getCommandDescription('pd-help', language), () => {
411
444
  if (language === 'zh') {
412
445
  return { text: `
413
446
  📖 **Principles Disciple 命令大全**
414
447
 
415
- ## 🚀 快速开始
416
- | 命令 | 用途 | 使用时机 |
417
- |------|------|----------|
418
- | \`/pd-init\` | 初始化工作区 | 新项目开始时 |
419
- | \`/pd-bootstrap\` | 环境工具扫描 | 缺少开发工具时 |
420
-
421
- ## 📊 状态查询
422
- | 命令 | 用途 | 使用时机 |
423
- |------|------|----------|
424
- | \`/pd-status\` | 查看进化状态 | 想了解当前 GFI 和 Pain 情况 |
425
- | \`/pd-focus\` | 焦点文件管理 | 查看/压缩/回滚历史版本 |
426
- | \`/pd-export\` | 导出数据 | 导出 analytics/corrections/orpo |
427
- | \`/pd-samples\` | 审核纠错样本 | 查看待审核样本并批准/拒绝 |
428
- | \`/pd-nocturnal-review\` | 审核 nocturnal 样本 | 审核 nocturnal 训练样本并导出 ORPO |
429
-
430
- ## ⚙️ 配置管理
431
- | 命令 | 用途 | 使用时机 |
432
- |------|------|----------|
433
- | \`/pd-context\` | 控制上下文注入 | 想减少/增加注入内容 |
434
- | \`/pd-okr\` | OKR 目标管理 | 设置战略目标 |
435
-
436
- ## 🧠 进化相关
437
- | 命令 | 用途 | 使用时机 |
438
- |------|------|----------|
439
- | \`/pd-thinking\` | 思维模型管理 | 更新 Thinking OS |
440
- | \`/pd-daily\` | 进化日报 | 每日回顾时 |
441
- | \`/pd-grooming\` | 工作区大扫除 | 定期清理 |
442
-
443
- ## 💡 常用命令示例
444
-
445
- **减少 token 消耗:**
446
- \`\`\`
447
- /pd-context minimal
448
- \`\`\`
449
-
450
- **恢复完整上下文:**
451
- \`\`\`
452
- /pd-context full
453
- \`\`\`
454
-
455
- **查看当前配置:**
456
- \`\`\`
457
- /pd-context status
458
- \`\`\`
459
-
460
- 🔍 输入任意命令后加 \`help\` 可查看详细帮助,如 \`/pd-context help\`
448
+ ## 快速开始
449
+ | 短命令 | 长命令 | 用途 |
450
+ |--------|--------|------|
451
+ | \`/pdi\` | \`/pd-init\` | 初始化工作区 |
452
+ | \`/pdb\` | \`/pd-bootstrap\` | 环境工具扫描 |
453
+ | \`/pdr\` | \`/pd-research\` | 研究工具方案 |
454
+
455
+ ## 状态查询
456
+ | 短命令 | 长命令 | 用途 |
457
+ |--------|--------|------|
458
+ | \`/pdk\` | \`/pd-okr\` | OKR 目标管理 |
459
+ | \`/pdt\` | \`/pd-thinking\` | 思维模型管理 |
460
+ | \`/pdrl\` | \`/pd-reflect\` | 手动触发反思 |
461
+ | \`/pdd\` | \`/pd-daily\` | 进化日报 |
462
+ | \`/pdg\` | \`/pd-grooming\` | 工作区清理 |
463
+
464
+ ## 其他命令
465
+ | 命令 | 用途 |
466
+ |------|------|
467
+ | \`/pd-status\` | 查看系统状态 |
468
+ | \`/pd-context\` | 控制上下文注入 |
469
+ | \`/pd-focus\` | 焦点文件管理 |
470
+ | \`/pd-export\` | 导出数据 |
471
+ | \`/pd-samples\` | 审核纠错样本 |
472
+ | \`/pd-nocturnal-review\` | 审核 nocturnal 样本 |
473
+ | \`/pd-rollback\` | 回滚情绪事件惩罚 |
474
+ | \`/pd-principle-rollback\` | 回滚原则 |
475
+ | \`/pd-help\` | 显示本帮助 |
461
476
  `.trim() };
462
477
  } else {
463
478
  return { text: `
464
479
  📖 **Principles Disciple Command Reference**
465
480
 
466
- ## 🚀 Quick Start
467
- | Command | Purpose | When to Use |
468
- |---------|---------|-------------|
469
- | \`/pd-init\` | Initialize workspace | Starting a new project |
470
- | \`/pd-bootstrap\` | Scan environment tools | Missing dev tools |
471
-
472
- ## 📊 Status Query
473
- | Command | Purpose | When to Use |
474
- |---------|---------|-------------|
475
- | \`/pd-status\` | View evolution status | Check GFI and Pain status |
476
- | \`/pd-focus\` | Focus file management | View/compress/rollback history |
477
- | \`/pd-export\` | Export data | Export analytics/corrections/orpo |
478
- | \`/pd-samples\` | Review correction samples | Review pending correction samples |
479
- | \`/pd-nocturnal-review\` | Review nocturnal samples | Review nocturnal training samples and export ORPO |
480
-
481
- ## ⚙️ Configuration
482
- | Command | Purpose | When to Use |
483
- |---------|---------|-------------|
484
- | \`/pd-context\` | Control context injection | Reduce/increase injected content |
485
- | \`/pd-okr\` | OKR goal management | Set strategic goals |
486
-
487
- ## 🧠 Evolution
488
- | Command | Purpose | When to Use |
489
- |---------|---------|-------------|
490
- | \`/pd-thinking\` | Mental model management | Update Thinking OS |
491
- | \`/pd-daily\` | Evolution report | Daily review |
492
- | \`/pd-grooming\` | Workspace cleanup | Periodic cleanup |
493
-
494
- ## 💡 Common Examples
495
-
496
- **Reduce token usage:**
497
- \`\`\`
498
- /pd-context minimal
499
- \`\`\`
500
-
501
- **Restore full context:**
502
- \`\`\`
503
- /pd-context full
504
- \`\`\`
505
-
506
- **View current config:**
507
- \`\`\`
508
- /pd-context status
509
- \`\`\`
510
-
511
- 🔍 Add \`help\` after any command for details, e.g., \`/pd-context help\`
481
+ ## Quick Start
482
+ | Short | Full | Purpose |
483
+ |-------|------|---------|
484
+ | \`/pdi\` | \`/pd-init\` | Initialize workspace |
485
+ | \`/pdb\` | \`/pd-bootstrap\` | Scan environment tools |
486
+ | \`/pdr\` | \`/pd-research\` | Research tool solutions |
487
+
488
+ ## Status
489
+ | Short | Full | Purpose |
490
+ |-------|------|---------|
491
+ | \`/pdk\` | \`/pd-okr\` | OKR goal management |
492
+ | \`/pdt\` | \`/pd-thinking\` | Mental model management |
493
+ | \`/pdrl\` | \`/pd-reflect\` | Manual reflection trigger |
494
+ | \`/pdd\` | \`/pd-daily\` | Evolution report |
495
+ | \`/pdg\` | \`/pd-grooming\` | Workspace cleanup |
496
+
497
+ ## Other Commands
498
+ | Command | Purpose |
499
+ |---------|---------|
500
+ | \`/pd-status\` | View system status |
501
+ | \`/pd-context\` | Control context injection |
502
+ | \`/pd-focus\` | Focus file management |
503
+ | \`/pd-export\` | Export data |
504
+ | \`/pd-samples\` | Review correction samples |
505
+ | \`/pd-nocturnal-review\` | Review nocturnal samples |
506
+ | \`/pd-rollback\` | Rollback empathy penalty |
507
+ | \`/pd-principle-rollback\` | Rollback principle |
508
+ | \`/pd-help\` | Show this help |
512
509
  `.trim() };
513
510
  }
514
- }
515
511
  });
516
512
 
517
513
  api.registerCommand({
@@ -520,7 +516,7 @@ const plugin = {
520
516
  acceptsArgs: true,
521
517
  handler: (ctx) => {
522
518
  try {
523
- const workspaceDir = api.resolvePath('.');
519
+ const workspaceDir = resolveCommandWorkspaceDir(api, ctx);
524
520
  // Ensure workspaceDir is in config for handlePainCommand
525
521
  if (ctx.config) ctx.config.workspaceDir = workspaceDir;
526
522
  return handlePainCommand(ctx);
@@ -537,7 +533,7 @@ const plugin = {
537
533
  acceptsArgs: true,
538
534
  handler: (ctx) => {
539
535
  try {
540
- const workspaceDir = api.resolvePath('.');
536
+ const workspaceDir = resolveCommandWorkspaceDir(api, ctx);
541
537
  if (ctx.config) ctx.config.workspaceDir = workspaceDir;
542
538
  return handleContextCommand(ctx);
543
539
  } catch (err) {
@@ -553,7 +549,7 @@ const plugin = {
553
549
  acceptsArgs: true,
554
550
  handler: (ctx) => {
555
551
  try {
556
- const workspaceDir = api.resolvePath('.');
552
+ const workspaceDir = resolveCommandWorkspaceDir(api, ctx);
557
553
  if (ctx.config) ctx.config.workspaceDir = workspaceDir;
558
554
  return handleFocusCommand(ctx, api);
559
555
  } catch (err) {
@@ -569,7 +565,7 @@ const plugin = {
569
565
  description: getCommandDescription('pd-evolution-status', language),
570
566
  handler: (ctx) => {
571
567
  try {
572
- const workspaceDir = api.resolvePath('.');
568
+ const workspaceDir = resolveCommandWorkspaceDir(api, ctx);
573
569
  if (ctx.config) ctx.config.workspaceDir = workspaceDir;
574
570
  return handleEvolutionStatusCommand(ctx);
575
571
  } catch (err) {
@@ -585,7 +581,7 @@ const plugin = {
585
581
  acceptsArgs: true,
586
582
  handler: (ctx) => {
587
583
  try {
588
- const workspaceDir = api.resolvePath('.');
584
+ const workspaceDir = resolveCommandWorkspaceDir(api, ctx);
589
585
  if (ctx.config) ctx.config.workspaceDir = workspaceDir;
590
586
  return handlePrincipleRollbackCommand(ctx);
591
587
  } catch (err) {
@@ -601,7 +597,7 @@ const plugin = {
601
597
  acceptsArgs: true,
602
598
  handler: (ctx) => {
603
599
  try {
604
- const workspaceDir = api.resolvePath('.');
600
+ const workspaceDir = resolveCommandWorkspaceDir(api, ctx);
605
601
  if (ctx.config) ctx.config.workspaceDir = workspaceDir;
606
602
  return handleRollbackCommand(ctx);
607
603
  } catch (err) {
@@ -618,7 +614,7 @@ const plugin = {
618
614
  acceptsArgs: true,
619
615
  handler: (ctx) => {
620
616
  try {
621
- const workspaceDir = api.resolvePath('.');
617
+ const workspaceDir = resolveCommandWorkspaceDir(api, ctx);
622
618
  if (ctx.config) ctx.config.workspaceDir = workspaceDir;
623
619
  return handleExportCommand(ctx);
624
620
  } catch (err) {
@@ -634,7 +630,7 @@ const plugin = {
634
630
  acceptsArgs: true,
635
631
  handler: (ctx) => {
636
632
  try {
637
- const workspaceDir = api.resolvePath('.');
633
+ const workspaceDir = resolveCommandWorkspaceDir(api, ctx);
638
634
  if (ctx.config) ctx.config.workspaceDir = workspaceDir;
639
635
  return handleSamplesCommand(ctx);
640
636
  } catch (err) {
@@ -650,7 +646,7 @@ const plugin = {
650
646
  acceptsArgs: true,
651
647
  handler: (ctx) => {
652
648
  try {
653
- const workspaceDir = api.resolvePath('.');
649
+ const workspaceDir = resolveCommandWorkspaceDir(api, ctx);
654
650
  if (ctx.config) ctx.config.workspaceDir = workspaceDir;
655
651
  return handleNocturnalReviewCommand(ctx);
656
652
  } catch (err) {
@@ -666,7 +662,7 @@ const plugin = {
666
662
  acceptsArgs: true,
667
663
  handler: (ctx) => {
668
664
  try {
669
- const workspaceDir = api.resolvePath('.');
665
+ const workspaceDir = resolveCommandWorkspaceDir(api, ctx);
670
666
  if (ctx.config) ctx.config.workspaceDir = workspaceDir;
671
667
  return handleNocturnalTrainCommand(ctx);
672
668
  } catch (err) {
@@ -682,7 +678,7 @@ const plugin = {
682
678
  acceptsArgs: true,
683
679
  handler: (ctx) => {
684
680
  try {
685
- const workspaceDir = api.resolvePath('.');
681
+ const workspaceDir = resolveCommandWorkspaceDir(api, ctx);
686
682
  if (ctx.config) ctx.config.workspaceDir = workspaceDir;
687
683
  return handleNocturnalRolloutCommand(ctx);
688
684
  } catch (err) {
@@ -698,7 +694,7 @@ const plugin = {
698
694
  acceptsArgs: true,
699
695
  handler: (ctx) => {
700
696
  try {
701
- const workspaceDir = api.resolvePath('.');
697
+ const workspaceDir = resolveCommandWorkspaceDir(api, ctx);
702
698
  if (ctx.config) ctx.config.workspaceDir = workspaceDir;
703
699
  return handleWorkflowDebugCommand(ctx);
704
700
  } catch (err) {
@@ -715,7 +711,7 @@ const plugin = {
715
711
  acceptsArgs: true,
716
712
  handler: (ctx) => {
717
713
  try {
718
- const workspaceDir = api.resolvePath('.');
714
+ const workspaceDir = resolveCommandWorkspaceDir(api, ctx);
719
715
  if (ctx.config) ctx.config.workspaceDir = workspaceDir;
720
716
  return handlePromoteImplCommand(ctx);
721
717
  } catch (err) {
@@ -731,7 +727,7 @@ const plugin = {
731
727
  acceptsArgs: true,
732
728
  handler: (ctx) => {
733
729
  try {
734
- const workspaceDir = api.resolvePath('.');
730
+ const workspaceDir = resolveCommandWorkspaceDir(api, ctx);
735
731
  if (ctx.config) ctx.config.workspaceDir = workspaceDir;
736
732
  return handleDisableImplCommand(ctx);
737
733
  } catch (err) {
@@ -747,7 +743,7 @@ const plugin = {
747
743
  acceptsArgs: true,
748
744
  handler: (ctx) => {
749
745
  try {
750
- const workspaceDir = api.resolvePath('.');
746
+ const workspaceDir = resolveCommandWorkspaceDir(api, ctx);
751
747
  if (ctx.config) ctx.config.workspaceDir = workspaceDir;
752
748
  return handleArchiveImplCommand(ctx);
753
749
  } catch (err) {
@@ -763,7 +759,7 @@ const plugin = {
763
759
  acceptsArgs: true,
764
760
  handler: (ctx) => {
765
761
  try {
766
- const workspaceDir = api.resolvePath('.');
762
+ const workspaceDir = resolveCommandWorkspaceDir(api, ctx);
767
763
  if (ctx.config) ctx.config.workspaceDir = workspaceDir;
768
764
  return handleRollbackImplCommand(ctx);
769
765
  } catch (err) {
@@ -17,7 +17,7 @@ export interface CentralHealthResponse {
17
17
  * Evolution, Principles, and Queue stats are workspace-specific.
18
18
  */
19
19
  export class CentralHealthService {
20
- /* eslint-disable @typescript-eslint/class-methods-use-this -- Reason: utility method that doesn't need instance state */
20
+
21
21
  getAllWorkspaceHealth(): CentralHealthResponse {
22
22
  const centralDb = getCentralDatabase();
23
23
  const workspaces: WorkspaceHealthEntry[] = [];
@@ -23,14 +23,14 @@ export class CentralOverviewService {
23
23
  this.centralDb = getCentralDatabase();
24
24
  }
25
25
 
26
- /* eslint-disable @typescript-eslint/class-methods-use-this -- Reason: intentionally no-op, centralDb is a process-wide singleton, see comment below */
26
+
27
27
  dispose(): void {
28
28
  // Do NOT dispose centralDb — it's a singleton shared across all requests.
29
29
  // Individual services that open per-request connections (e.g. HealthQueryService)
30
30
  // must dispose their own connections, but the central aggregated DB lives for
31
31
  // the lifetime of the process.
32
32
  }
33
- /* eslint-enable @typescript-eslint/class-methods-use-this */
33
+
34
34
 
35
35
  getOverview(days = 30): CentralOverviewResponse {
36
36
  const stats = this.centralDb.getOverviewStats();
@@ -60,7 +60,7 @@ export class CentralOverviewService {
60
60
  // gate_blocks: no equivalent in aggregated DB schema; hardcode to 0
61
61
 
62
62
  // D-06: sampleQueue.counters from aggregated_correction_samples GROUP BY review_status
63
- // eslint-disable-next-line no-useless-assignment -- Reason: initial value unused due to immediate reassignment in try/catch
63
+
64
64
  let sampleCounters: Record<string, number> = {};
65
65
  try {
66
66
  sampleCounters = this.centralDb.getSampleCountersByStatus();
@@ -154,7 +154,7 @@ export class EvolutionQueryService {
154
154
  * 释放资源
155
155
  * 注意:不关闭 trajectory,因为它是单例由 TrajectoryRegistry 管理
156
156
  */
157
- /* eslint-disable @typescript-eslint/class-methods-use-this -- Reason: Delegates to TrajectoryRegistry lifecycle management */
157
+
158
158
  dispose(): void {
159
159
  // EvolutionQueryService 不拥有 trajectory,所以不关闭它
160
160
  // trajectory 是由 TrajectoryRegistry 管理的单例