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.
- package/README.md +13 -5
- package/openclaw.plugin.json +4 -4
- package/package.json +1 -1
- package/src/commands/archive-impl.ts +3 -3
- package/src/commands/capabilities.ts +1 -1
- package/src/commands/context.ts +3 -3
- package/src/commands/disable-impl.ts +1 -1
- package/src/commands/evolution-status.ts +2 -2
- package/src/commands/focus.ts +2 -2
- package/src/commands/nocturnal-train.ts +6 -6
- package/src/commands/pain.ts +4 -4
- package/src/commands/pd-reflect.ts +87 -0
- package/src/commands/rollback-impl.ts +4 -4
- package/src/commands/rollback.ts +2 -2
- package/src/commands/samples.ts +2 -2
- package/src/commands/workflow-debug.ts +1 -1
- package/src/config/errors.ts +1 -1
- package/src/core/adaptive-thresholds.ts +1 -1
- package/src/core/code-implementation-storage.ts +2 -2
- package/src/core/config.ts +1 -1
- package/src/core/diagnostician-task-store.ts +2 -2
- package/src/core/empathy-keyword-matcher.ts +3 -3
- package/src/core/event-log.ts +5 -5
- package/src/core/evolution-engine.ts +4 -4
- package/src/core/evolution-logger.ts +1 -1
- package/src/core/evolution-reducer.ts +3 -3
- package/src/core/evolution-types.ts +5 -5
- package/src/core/external-training-contract.ts +1 -1
- package/src/core/focus-history.ts +14 -14
- package/src/core/hygiene/tracker.ts +1 -1
- package/src/core/init.ts +2 -2
- package/src/core/model-deployment-registry.ts +2 -2
- package/src/core/model-training-registry.ts +2 -2
- package/src/core/nocturnal-arbiter.ts +1 -1
- package/src/core/nocturnal-artificer.ts +2 -2
- package/src/core/nocturnal-candidate-scoring.ts +2 -2
- package/src/core/nocturnal-compliance.ts +4 -3
- package/src/core/nocturnal-dataset.ts +3 -3
- package/src/core/nocturnal-export.ts +4 -4
- package/src/core/nocturnal-rule-implementation-validator.ts +1 -1
- package/src/core/nocturnal-snapshot-contract.ts +112 -0
- package/src/core/nocturnal-trajectory-extractor.ts +7 -5
- package/src/core/nocturnal-trinity.ts +480 -158
- package/src/core/pain-context-extractor.ts +3 -3
- package/src/core/pain.ts +124 -11
- package/src/core/path-resolver.ts +4 -4
- package/src/core/pd-task-reconciler.ts +10 -10
- package/src/core/pd-task-service.ts +1 -1
- package/src/core/pd-task-store.ts +1 -1
- package/src/core/principle-internalization/deprecated-readiness.ts +1 -1
- package/src/core/principle-training-state.ts +2 -2
- package/src/core/principle-tree-ledger.ts +7 -7
- package/src/core/promotion-gate.ts +9 -9
- package/src/core/replay-engine.ts +12 -12
- package/src/core/risk-calculator.ts +1 -1
- package/src/core/rule-host-types.ts +2 -2
- package/src/core/rule-host.ts +5 -5
- package/src/core/schema/db-types.ts +1 -1
- package/src/core/schema/schema-definitions.ts +1 -1
- package/src/core/session-tracker.ts +96 -4
- package/src/core/shadow-observation-registry.ts +3 -3
- package/src/core/system-logger.ts +2 -2
- package/src/core/thinking-os-parser.ts +1 -1
- package/src/core/training-program.ts +2 -2
- package/src/core/trajectory.ts +8 -8
- package/src/core/workspace-context.ts +2 -2
- package/src/core/workspace-dir-service.ts +85 -0
- package/src/core/workspace-dir-validation.ts +30 -107
- package/src/hooks/bash-risk.ts +3 -3
- package/src/hooks/edit-verification.ts +4 -4
- package/src/hooks/gate-block-helper.ts +4 -4
- package/src/hooks/gate.ts +10 -10
- package/src/hooks/gfi-gate.ts +7 -7
- package/src/hooks/lifecycle.ts +2 -2
- package/src/hooks/llm.ts +1 -1
- package/src/hooks/pain.ts +25 -5
- package/src/hooks/progressive-trust-gate.ts +7 -7
- package/src/hooks/prompt.ts +24 -5
- package/src/hooks/subagent.ts +2 -2
- package/src/hooks/thinking-checkpoint.ts +2 -2
- package/src/hooks/trajectory-collector.ts +1 -1
- package/src/http/principles-console-route.ts +14 -6
- package/src/i18n/commands.ts +4 -0
- package/src/index.ts +181 -185
- package/src/service/central-health-service.ts +1 -1
- package/src/service/central-overview-service.ts +3 -3
- package/src/service/evolution-query-service.ts +1 -1
- package/src/service/evolution-worker.ts +221 -109
- package/src/service/health-query-service.ts +27 -17
- package/src/service/monitoring-query-service.ts +3 -3
- package/src/service/nocturnal-runtime.ts +4 -4
- package/src/service/nocturnal-service.ts +40 -23
- package/src/service/nocturnal-target-selector.ts +11 -4
- package/src/service/runtime-summary-service.ts +1 -1
- package/src/service/subagent-workflow/deep-reflect-workflow-manager.ts +1 -1
- package/src/service/subagent-workflow/empathy-observer-workflow-manager.ts +3 -3
- package/src/service/subagent-workflow/nocturnal-workflow-manager.ts +16 -13
- package/src/service/subagent-workflow/runtime-direct-driver.ts +10 -6
- package/src/service/subagent-workflow/types.ts +4 -4
- package/src/service/subagent-workflow/workflow-manager-base.ts +5 -5
- package/src/service/subagent-workflow/workflow-store.ts +2 -2
- package/src/tools/critique-prompt.ts +2 -3
- package/src/tools/deep-reflect.ts +17 -16
- package/src/tools/model-index.ts +1 -1
- package/src/utils/file-lock.ts +1 -1
- package/src/utils/io.ts +7 -2
- package/src/utils/nlp.ts +1 -1
- package/src/utils/plugin-logger.ts +2 -2
- package/src/utils/retry.ts +3 -2
- package/src/utils/subagent-probe.ts +20 -33
- package/templates/langs/en/skills/pd-pain-signal/SKILL.md +8 -7
- package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/nocturnal-trinity-quality-enhancement.json +111 -0
- package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/task-specs.mjs +1 -1
- package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/run.mjs +1 -1
- package/templates/langs/zh/skills/pd-pain-signal/SKILL.md +8 -7
- package/templates/pain_settings.json +1 -1
- package/tests/build-artifacts.test.ts +4 -58
- package/tests/commands/pd-reflect.test.ts +49 -0
- package/tests/core/nocturnal-snapshot-contract.test.ts +70 -0
- package/tests/core/pain-auto-repair.test.ts +96 -0
- package/tests/core/pain-integration.test.ts +483 -0
- package/tests/core/pain.test.ts +5 -4
- package/tests/core/workspace-dir-service.test.ts +68 -0
- package/tests/core/workspace-dir-validation.test.ts +56 -192
- package/tests/hooks/pain.test.ts +20 -0
- package/tests/http/principles-console-route.test.ts +42 -20
- package/tests/integration/empathy-workflow-integration.test.ts +1 -2
- package/tests/integration/tool-hooks-workspace-dir.e2e.test.ts +9 -17
- package/tests/service/empathy-observer-workflow-manager.test.ts +1 -2
- package/tests/service/evolution-worker.nocturnal.test.ts +118 -109
- package/tests/service/nocturnal-runtime-hardening.test.ts +33 -0
- package/tests/utils/subagent-probe.test.ts +32 -0
package/README.md
CHANGED
|
@@ -17,12 +17,21 @@ This plugin integrates with OpenClaw to provide an evolutionary programming fram
|
|
|
17
17
|
|
|
18
18
|
### Slash Commands
|
|
19
19
|
|
|
20
|
+
All commands support **short aliases** for easier input:
|
|
21
|
+
|
|
22
|
+
| Short | Full Command | Description |
|
|
23
|
+
|-------|--------------|-------------|
|
|
24
|
+
| `/pdi` | `/pd-init` | Initialize workspace |
|
|
25
|
+
| `/pdb` | `/pd-bootstrap` | Scan environment tools |
|
|
26
|
+
| `/pdr` | `/pd-research` | Research tools and capabilities |
|
|
27
|
+
| `/pdt` | `/pd-thinking` | Manage thinking models |
|
|
28
|
+
| `/pdrl` | `/pd-reflect` | Manually trigger nocturnal reflection |
|
|
29
|
+
| `/pdd` | `/pd-daily` | Configure and send daily report |
|
|
30
|
+
| `/pdg` | `/pd-grooming` | Workspace cleanup |
|
|
31
|
+
| `/pdh` | `/pd-help` | Show command reference |
|
|
32
|
+
|
|
20
33
|
| Command | Description |
|
|
21
34
|
|---------|-------------|
|
|
22
|
-
| `/pd-init` | Initialize workspace |
|
|
23
|
-
| `/pd-bootstrap` | Scan environment tools |
|
|
24
|
-
| `/pd-research` | Research tools and capabilities |
|
|
25
|
-
| `/pd-thinking` | Manage thinking models |
|
|
26
35
|
| `/pd-status` | View evolution status |
|
|
27
36
|
| `/pd-context` | Control context injection |
|
|
28
37
|
| `/pd-focus` | Focus file management |
|
|
@@ -34,7 +43,6 @@ This plugin integrates with OpenClaw to provide an evolutionary programming fram
|
|
|
34
43
|
| `/nocturnal-train` | Nocturnal training operations |
|
|
35
44
|
| `/nocturnal-rollout` | Nocturnal rollout and promotion |
|
|
36
45
|
| `/pd-workflow-debug` | Debug workflow state |
|
|
37
|
-
| `/pd-help` | Show command reference |
|
|
38
46
|
|
|
39
47
|
### Tools
|
|
40
48
|
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "principles-disciple",
|
|
3
3
|
"name": "Principles Disciple",
|
|
4
4
|
"description": "Evolutionary programming agent framework with strategic guardrails and reflection loops.",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.18.0",
|
|
6
6
|
"skills": [
|
|
7
7
|
"./skills"
|
|
8
8
|
],
|
|
@@ -76,8 +76,8 @@
|
|
|
76
76
|
}
|
|
77
77
|
},
|
|
78
78
|
"buildFingerprint": {
|
|
79
|
-
"gitSha": "
|
|
80
|
-
"bundleMd5": "
|
|
81
|
-
"builtAt": "2026-04-
|
|
79
|
+
"gitSha": "bce835db37a0",
|
|
80
|
+
"bundleMd5": "9e44177badb37ac423669fd187bf2667",
|
|
81
|
+
"builtAt": "2026-04-10T14:01:23.050Z"
|
|
82
82
|
}
|
|
83
83
|
}
|
package/package.json
CHANGED
|
@@ -51,13 +51,13 @@ export function handleArchiveImplCommand(ctx: PluginCommandContext): PluginComma
|
|
|
51
51
|
|
|
52
52
|
// Subcommand: list
|
|
53
53
|
if (subcommand === 'list') {
|
|
54
|
-
|
|
54
|
+
|
|
55
55
|
return _handleListArchivable(stateDir, isZh);
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
// Archive by ID
|
|
59
59
|
const targetId = subcommand;
|
|
60
|
-
|
|
60
|
+
|
|
61
61
|
return _handleArchiveImpl(workspaceDir, stateDir, targetId, isZh);
|
|
62
62
|
}
|
|
63
63
|
|
|
@@ -94,7 +94,7 @@ function _handleListArchivable(
|
|
|
94
94
|
return { text: output };
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
|
|
97
|
+
|
|
98
98
|
function _handleArchiveImpl(
|
|
99
99
|
workspaceDir: string,
|
|
100
100
|
stateDir: string,
|
|
@@ -24,7 +24,7 @@ function scanEnvironment(wctx: WorkspaceContext): any {
|
|
|
24
24
|
available: true,
|
|
25
25
|
version: versionLine.trim(),
|
|
26
26
|
};
|
|
27
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- Reason: catch parameter intentionally unused - we only care that the command failed
|
|
28
28
|
} catch (_e) {
|
|
29
29
|
tools[tool.name] = { available: false };
|
|
30
30
|
}
|
package/src/commands/context.ts
CHANGED
|
@@ -98,7 +98,7 @@ function showStatus(workspaceDir: string, isZh: boolean): string {
|
|
|
98
98
|
/**
|
|
99
99
|
* Toggle a boolean setting
|
|
100
100
|
*/
|
|
101
|
-
|
|
101
|
+
|
|
102
102
|
function toggleSetting(
|
|
103
103
|
workspaceDir: string,
|
|
104
104
|
key: 'thinkingOs' | 'reflectionLog',
|
|
@@ -213,7 +213,7 @@ function applyPreset(
|
|
|
213
213
|
preset: 'minimal' | 'standard' | 'full',
|
|
214
214
|
isZh: boolean
|
|
215
215
|
): string {
|
|
216
|
-
|
|
216
|
+
|
|
217
217
|
let config: ContextInjectionConfig;
|
|
218
218
|
|
|
219
219
|
switch (preset) {
|
|
@@ -314,7 +314,7 @@ export function handleContextCommand(ctx: PluginCommandContext): PluginCommandRe
|
|
|
314
314
|
// Detect language from context
|
|
315
315
|
const isZh = (ctx.config?.language as string) === 'zh';
|
|
316
316
|
|
|
317
|
-
|
|
317
|
+
|
|
318
318
|
let result: string;
|
|
319
319
|
|
|
320
320
|
switch (subCommand) {
|
|
@@ -69,7 +69,7 @@ function _handleListActive(
|
|
|
69
69
|
return { text: output };
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
|
|
73
73
|
function _handleDisableImpl(
|
|
74
74
|
workspaceDir: string,
|
|
75
75
|
stateDir: string,
|
|
@@ -45,7 +45,7 @@ function formatRouteRecommendations(
|
|
|
45
45
|
.join(', ');
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
|
|
49
49
|
function buildEnglishOutput(
|
|
50
50
|
workspaceDir: string,
|
|
51
51
|
sessionId: string | null,
|
|
@@ -97,7 +97,7 @@ function buildEnglishOutput(
|
|
|
97
97
|
return lines.join('\n');
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
|
|
100
|
+
|
|
101
101
|
function buildChineseOutput(
|
|
102
102
|
workspaceDir: string,
|
|
103
103
|
sessionId: string | null,
|
package/src/commands/focus.ts
CHANGED
|
@@ -281,7 +281,7 @@ async function compressFocus(
|
|
|
281
281
|
cleanupHistory(focusPath);
|
|
282
282
|
|
|
283
283
|
// 5. 压缩内容
|
|
284
|
-
|
|
284
|
+
|
|
285
285
|
let compressedContent: string;
|
|
286
286
|
try {
|
|
287
287
|
compressedContent = compressFocusContent(oldContent, workspaceDir);
|
|
@@ -477,7 +477,7 @@ export async function handleFocusCommand(
|
|
|
477
477
|
// 检测语言(与 context.ts 保持一致)
|
|
478
478
|
const isZh = (ctx.config?.language as string) === 'zh';
|
|
479
479
|
|
|
480
|
-
|
|
480
|
+
|
|
481
481
|
let result: string;
|
|
482
482
|
|
|
483
483
|
switch (subCommand) {
|
|
@@ -270,12 +270,12 @@ Hardware tiers:
|
|
|
270
270
|
// This closes the gap in the create-experiment -> trainer -> import-result chain.
|
|
271
271
|
// NOTE: This blocks until training completes (could be minutes).
|
|
272
272
|
if (runNow) {
|
|
273
|
-
|
|
273
|
+
|
|
274
274
|
const {spec} = createResult;
|
|
275
275
|
const baseDir = TRAINER_SCRIPTS_DIR;
|
|
276
276
|
const scriptPath = path.join(baseDir, 'main.py');
|
|
277
277
|
const specPath = path.join(baseDir, `experiment-${spec.experimentId}.json`);
|
|
278
|
-
|
|
278
|
+
|
|
279
279
|
const {outputDir} = spec;
|
|
280
280
|
const resultFilePath = path.join(outputDir, `result-${spec.experimentId}.json`);
|
|
281
281
|
|
|
@@ -286,7 +286,7 @@ Hardware tiers:
|
|
|
286
286
|
}
|
|
287
287
|
fs.writeFileSync(specPath, JSON.stringify(spec, null, 2), 'utf-8');
|
|
288
288
|
|
|
289
|
-
|
|
289
|
+
|
|
290
290
|
let trainerResult!: import('../core/external-training-contract.js').TrainingExperimentResult;
|
|
291
291
|
|
|
292
292
|
try {
|
|
@@ -394,7 +394,7 @@ Hardware tiers:
|
|
|
394
394
|
|
|
395
395
|
// Process trainer result (register checkpoint)
|
|
396
396
|
// dry_run returns null (no checkpoint); other statuses throw on error
|
|
397
|
-
|
|
397
|
+
|
|
398
398
|
let processed: { checkpointId: string; checkpointRef: string } | null;
|
|
399
399
|
try {
|
|
400
400
|
processed = program.processResult({
|
|
@@ -536,7 +536,7 @@ Next steps:
|
|
|
536
536
|
}
|
|
537
537
|
}
|
|
538
538
|
|
|
539
|
-
// eslint-disable-next-line @typescript-eslint/
|
|
539
|
+
// 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
|
|
540
540
|
let result: any;
|
|
541
541
|
try {
|
|
542
542
|
result = JSON.parse(resultJson);
|
|
@@ -567,7 +567,7 @@ Next steps:
|
|
|
567
567
|
|
|
568
568
|
// Process the result
|
|
569
569
|
const program = new TrainingProgram(workspaceDir);
|
|
570
|
-
|
|
570
|
+
|
|
571
571
|
let processed: { checkpointId: string; checkpointRef: string } | null;
|
|
572
572
|
try {
|
|
573
573
|
processed = program.processResult({
|
package/src/commands/pain.ts
CHANGED
|
@@ -96,7 +96,7 @@ export function handlePainCommand(ctx: PluginCommandContext): PluginCommandResul
|
|
|
96
96
|
|
|
97
97
|
// Handle empathy subcommand
|
|
98
98
|
if (args.startsWith('empathy')) {
|
|
99
|
-
|
|
99
|
+
|
|
100
100
|
return handleEmpathySubcommand(wctx, args, sessionId, isZh);
|
|
101
101
|
}
|
|
102
102
|
|
|
@@ -126,7 +126,7 @@ export function handlePainCommand(ctx: PluginCommandContext): PluginCommandResul
|
|
|
126
126
|
const gfiBar = createProgressBar(gfi, 100, 15);
|
|
127
127
|
|
|
128
128
|
// Determine Mental Mode (aligned with prompt.ts logic)
|
|
129
|
-
|
|
129
|
+
|
|
130
130
|
let mentalMode = '';
|
|
131
131
|
if (isZh) {
|
|
132
132
|
if (gfi >= 70) mentalMode = '🚑 救赎模式 (HUMBLE_RECOVERY)';
|
|
@@ -139,7 +139,7 @@ export function handlePainCommand(ctx: PluginCommandContext): PluginCommandResul
|
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
// Determine health status based on GFI
|
|
142
|
-
|
|
142
|
+
|
|
143
143
|
let healthLabel = 'Healthy';
|
|
144
144
|
let suggestionText = '';
|
|
145
145
|
|
|
@@ -218,7 +218,7 @@ export function handlePainCommand(ctx: PluginCommandContext): PluginCommandResul
|
|
|
218
218
|
/**
|
|
219
219
|
* Handle /pd-status empathy subcommand
|
|
220
220
|
*/
|
|
221
|
-
|
|
221
|
+
|
|
222
222
|
function handleEmpathySubcommand(
|
|
223
223
|
wctx: WorkspaceContext,
|
|
224
224
|
args: string,
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PD Reflect Command (/pd-reflect)
|
|
3
|
+
*
|
|
4
|
+
* Manually trigger a sleep_reflection task, bypassing idle check.
|
|
5
|
+
* This command must operate on an explicitly resolved active workspace.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { PluginCommandDefinition, PluginCommandContext, PluginCommandResult, OpenClawPluginApi } from '../openclaw-sdk.js';
|
|
9
|
+
import { acquireQueueLock, EVOLUTION_QUEUE_LOCK_SUFFIX } from '../service/evolution-worker.js';
|
|
10
|
+
import * as fs from 'fs';
|
|
11
|
+
import * as path from 'path';
|
|
12
|
+
|
|
13
|
+
interface PdReflectContext extends PluginCommandContext {
|
|
14
|
+
api?: OpenClawPluginApi;
|
|
15
|
+
workspaceDir?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const handlePdReflect: PluginCommandDefinition = {
|
|
19
|
+
name: 'pd-reflect',
|
|
20
|
+
description: 'Manually trigger Nocturnal sleep reflection pipeline',
|
|
21
|
+
acceptsArgs: false,
|
|
22
|
+
requireAuth: false,
|
|
23
|
+
handler: async (ctx: PdReflectContext): Promise<PluginCommandResult> => {
|
|
24
|
+
try {
|
|
25
|
+
const workspaceDir = ctx.workspaceDir;
|
|
26
|
+
if (!workspaceDir) {
|
|
27
|
+
return { text: 'Cannot determine workspace directory. Ensure you are in an active workspace.', isError: true };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const stateDir = path.join(workspaceDir, '.state');
|
|
31
|
+
const queuePath = path.join(stateDir, 'evolution_queue.json');
|
|
32
|
+
|
|
33
|
+
// Acquire lock before modifying queue
|
|
34
|
+
const releaseLock = await acquireQueueLock(queuePath, ctx.api?.logger, EVOLUTION_QUEUE_LOCK_SUFFIX);
|
|
35
|
+
let taskId: string | undefined;
|
|
36
|
+
try {
|
|
37
|
+
let rawQueue: unknown[] = [];
|
|
38
|
+
try {
|
|
39
|
+
rawQueue = JSON.parse(fs.readFileSync(queuePath, 'utf8')) as unknown[];
|
|
40
|
+
} catch {
|
|
41
|
+
rawQueue = [];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const hasPending = rawQueue.some((item: unknown) => {
|
|
45
|
+
const task = item as Record<string, string> | undefined;
|
|
46
|
+
return task?.taskKind === 'sleep_reflection' && (task?.status === 'pending' || task?.status === 'in_progress');
|
|
47
|
+
});
|
|
48
|
+
if (hasPending) {
|
|
49
|
+
return { text: 'A sleep_reflection task is already pending. Wait for it to complete or fail.' };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const now = new Date();
|
|
53
|
+
taskId = `manual_${now.getTime().toString(36).slice(-8)}`;
|
|
54
|
+
const nowIso = now.toISOString();
|
|
55
|
+
|
|
56
|
+
rawQueue.push({
|
|
57
|
+
id: taskId,
|
|
58
|
+
taskKind: 'sleep_reflection',
|
|
59
|
+
priority: 'high',
|
|
60
|
+
score: 50,
|
|
61
|
+
source: 'manual',
|
|
62
|
+
reason: 'Manual reflection triggered via /pd-reflect',
|
|
63
|
+
trigger_text_preview: 'User commanded /pd-reflect',
|
|
64
|
+
timestamp: nowIso,
|
|
65
|
+
enqueued_at: nowIso,
|
|
66
|
+
status: 'pending',
|
|
67
|
+
traceId: taskId,
|
|
68
|
+
retryCount: 0,
|
|
69
|
+
maxRetries: 1,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
fs.writeFileSync(queuePath, JSON.stringify(rawQueue, null, 2), 'utf8');
|
|
73
|
+
} finally {
|
|
74
|
+
releaseLock();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
text: `Nocturnal reflection task enqueued: \`${taskId}\`\n\nIt will be processed in the next evolution worker cycle (~15s). Check .state/nocturnal/samples/ for results.`,
|
|
79
|
+
};
|
|
80
|
+
} catch (error) {
|
|
81
|
+
return {
|
|
82
|
+
text: `Failed to trigger reflection: ${String(error)}`,
|
|
83
|
+
isError: true,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
};
|
|
@@ -57,11 +57,11 @@ export function handleRollbackImplCommand(ctx: PluginCommandContext): PluginComm
|
|
|
57
57
|
|
|
58
58
|
// List active
|
|
59
59
|
if (subcommand === 'list' || subcommand === '') {
|
|
60
|
-
|
|
60
|
+
|
|
61
61
|
return _handleListActiveRollback(stateDir, isZh);
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
|
|
65
65
|
return _handleRollbackImpl(workspaceDir, stateDir, implId, reason, isZh, ctx.sessionId);
|
|
66
66
|
}
|
|
67
67
|
|
|
@@ -103,7 +103,7 @@ function _handleListActiveRollback(
|
|
|
103
103
|
return { text: output };
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
|
|
106
|
+
|
|
107
107
|
function _handleRollbackImpl(
|
|
108
108
|
workspaceDir: string,
|
|
109
109
|
stateDir: string,
|
|
@@ -138,7 +138,7 @@ function _handleRollbackImpl(
|
|
|
138
138
|
// Step 1: Current active -> disabled
|
|
139
139
|
transitionImplementationState(stateDir, implId, 'disabled');
|
|
140
140
|
|
|
141
|
-
|
|
141
|
+
|
|
142
142
|
let restoredMessage: string;
|
|
143
143
|
|
|
144
144
|
if (previousActiveId && allImpls.some((i) => i.id === previousActiveId)) {
|
package/src/commands/rollback.ts
CHANGED
|
@@ -44,9 +44,9 @@ Usage:
|
|
|
44
44
|
};
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
|
|
48
48
|
let eventId: string | null;
|
|
49
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
49
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- Reason: triggerMethod is reserved for future extension - tracking rollback trigger source
|
|
50
50
|
const _triggerMethod = 'user_command' as const;
|
|
51
51
|
|
|
52
52
|
if (args === 'last') {
|
package/src/commands/samples.ts
CHANGED
|
@@ -29,11 +29,11 @@ export function handleSamplesCommand(ctx: PluginCommandContext): PluginCommandRe
|
|
|
29
29
|
}
|
|
30
30
|
const normalizedDecision = decision === 'approve' ? 'approved' : 'rejected';
|
|
31
31
|
const note = noteParts.join(' ').trim();
|
|
32
|
-
|
|
32
|
+
|
|
33
33
|
let record;
|
|
34
34
|
try {
|
|
35
35
|
record = wctx.trajectory.reviewCorrectionSample(sampleId, normalizedDecision, note);
|
|
36
|
-
/* eslint-disable @typescript-eslint/no-unused-vars
|
|
36
|
+
/* eslint-disable @typescript-eslint/no-unused-vars -- Reason: error handling only - returning failure response */
|
|
37
37
|
} catch (error) {
|
|
38
38
|
return {
|
|
39
39
|
text: zh
|
|
@@ -20,7 +20,7 @@ function formatState(state: string): string {
|
|
|
20
20
|
return `${icon} ${state}`;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
|
|
24
24
|
function buildOutput(
|
|
25
25
|
workflowId: string,
|
|
26
26
|
summary: ReturnType<InstanceType<typeof WorkflowStore>['getWorkflow']>,
|
package/src/config/errors.ts
CHANGED
|
@@ -300,7 +300,7 @@ export function getEffectiveThresholds(stateDir: string): ThresholdValues {
|
|
|
300
300
|
* @param reason - Reason for the adjustment (required for tracking)
|
|
301
301
|
* @returns UpdateThresholdResult
|
|
302
302
|
*/
|
|
303
|
-
|
|
303
|
+
|
|
304
304
|
export function updateThresholdState(
|
|
305
305
|
stateDir: string,
|
|
306
306
|
thresholdName: ThresholdName,
|
|
@@ -134,7 +134,7 @@ export function writeManifest(
|
|
|
134
134
|
});
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
-
|
|
137
|
+
|
|
138
138
|
export function writeEntrySource(
|
|
139
139
|
stateDir: string,
|
|
140
140
|
implId: string,
|
|
@@ -189,7 +189,7 @@ export function loadEntrySource(stateDir: string, implId: string): string | null
|
|
|
189
189
|
*
|
|
190
190
|
* Idempotent: calling again with the same implId will NOT overwrite an existing entry.js.
|
|
191
191
|
*/
|
|
192
|
-
|
|
192
|
+
|
|
193
193
|
export function createImplementationAssetDir(
|
|
194
194
|
stateDir: string,
|
|
195
195
|
implId: string,
|
package/src/core/config.ts
CHANGED
|
@@ -290,7 +290,7 @@ export class PainConfig {
|
|
|
290
290
|
/**
|
|
291
291
|
* Basic validation for critical settings
|
|
292
292
|
*/
|
|
293
|
-
|
|
293
|
+
|
|
294
294
|
private validate(settings: PainSettings): void {
|
|
295
295
|
// Ensure intervals are positive
|
|
296
296
|
if (settings.intervals.worker_poll_ms < 1000) settings.intervals.worker_poll_ms = 15 * 60 * 1000;
|
|
@@ -82,7 +82,7 @@ export async function addDiagnosticianTask(
|
|
|
82
82
|
): Promise<void> {
|
|
83
83
|
const filePath = resolveTasksPath(stateDir);
|
|
84
84
|
await withLockAsync(filePath, async () => {
|
|
85
|
-
|
|
85
|
+
|
|
86
86
|
const store = readTaskStoreSync(filePath);
|
|
87
87
|
store.tasks[taskId] = {
|
|
88
88
|
prompt,
|
|
@@ -105,7 +105,7 @@ export async function completeDiagnosticianTask(
|
|
|
105
105
|
): Promise<void> {
|
|
106
106
|
const filePath = resolveTasksPath(stateDir);
|
|
107
107
|
await withLockAsync(filePath, async () => {
|
|
108
|
-
|
|
108
|
+
|
|
109
109
|
const store = readTaskStoreSync(filePath);
|
|
110
110
|
delete store.tasks[taskId];
|
|
111
111
|
const tmpPath = filePath + '.tmp';
|
|
@@ -80,7 +80,7 @@ export function loadKeywordStore(stateDir: string, language?: 'zh' | 'en'): Empa
|
|
|
80
80
|
try {
|
|
81
81
|
if (!fs.existsSync(filePath)) {
|
|
82
82
|
const store = createDefaultKeywordStore(language);
|
|
83
|
-
|
|
83
|
+
|
|
84
84
|
saveKeywordStore(stateDir, store);
|
|
85
85
|
return store;
|
|
86
86
|
}
|
|
@@ -92,7 +92,7 @@ export function loadKeywordStore(stateDir: string, language?: 'zh' | 'en'): Empa
|
|
|
92
92
|
if (!parsed.terms || !parsed.stats || !parsed.version) {
|
|
93
93
|
console.warn('[PD:Empathy] Invalid keyword store format, creating default');
|
|
94
94
|
const store = createDefaultKeywordStore(language);
|
|
95
|
-
|
|
95
|
+
|
|
96
96
|
saveKeywordStore(stateDir, store);
|
|
97
97
|
return store;
|
|
98
98
|
}
|
|
@@ -101,7 +101,7 @@ export function loadKeywordStore(stateDir: string, language?: 'zh' | 'en'): Empa
|
|
|
101
101
|
} catch (e) {
|
|
102
102
|
console.warn(`[PD:Empathy] Failed to load keyword store: ${e}`);
|
|
103
103
|
const store = createDefaultKeywordStore(language);
|
|
104
|
-
|
|
104
|
+
|
|
105
105
|
saveKeywordStore(stateDir, store);
|
|
106
106
|
return store;
|
|
107
107
|
}
|
package/src/core/event-log.ts
CHANGED
|
@@ -107,7 +107,7 @@ export class EventLog {
|
|
|
107
107
|
this.record('warn', 'failure', sessionId, { message, ...context });
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
|
|
110
|
+
|
|
111
111
|
private record(
|
|
112
112
|
type: EventType,
|
|
113
113
|
category: EventCategory,
|
|
@@ -134,7 +134,7 @@ export class EventLog {
|
|
|
134
134
|
}
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
-
|
|
137
|
+
|
|
138
138
|
private formatDate(date: Date): string {
|
|
139
139
|
return date.toISOString().split('T')[0];
|
|
140
140
|
}
|
|
@@ -160,7 +160,7 @@ export class EventLog {
|
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
if (entry.type === 'tool_call') {
|
|
163
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
163
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- Reason: data used for type narrowing only, actual fields accessed via stats
|
|
164
164
|
const _data = entry.data as unknown as ToolCallEventData;
|
|
165
165
|
stats.tools.total++;
|
|
166
166
|
if (entry.category === 'success') stats.tools.success++;
|
|
@@ -243,7 +243,7 @@ export class EventLog {
|
|
|
243
243
|
return this.eventBuffer.map((entry) => ({ ...entry, data: { ...entry.data } }));
|
|
244
244
|
}
|
|
245
245
|
|
|
246
|
-
|
|
246
|
+
|
|
247
247
|
private getEventDedupKey(entry: EventLogEntry): string {
|
|
248
248
|
const eventId = typeof (entry.data as { eventId?: unknown } | undefined)?.eventId === 'string'
|
|
249
249
|
? String((entry.data as { eventId?: string }).eventId)
|
|
@@ -459,7 +459,7 @@ export class EventLog {
|
|
|
459
459
|
* Rollback an empathy event by ID.
|
|
460
460
|
* Returns the rolled back score, or 0 if event not found.
|
|
461
461
|
*/
|
|
462
|
-
|
|
462
|
+
|
|
463
463
|
rollbackEmpathyEvent(eventId: string, sessionId: string | undefined, reason: string, triggeredBy: 'user_command' | 'natural_language' | 'system'): number {
|
|
464
464
|
const allEvents = this.getMergedEvents();
|
|
465
465
|
let foundEvent: { entry: EventLogEntry; data: PainSignalEventData } | null = null;
|
|
@@ -323,7 +323,7 @@ export class EvolutionEngine {
|
|
|
323
323
|
|
|
324
324
|
// ===== 事件管理 =====
|
|
325
325
|
|
|
326
|
-
|
|
326
|
+
|
|
327
327
|
private createEvent(
|
|
328
328
|
type: 'success' | 'failure',
|
|
329
329
|
taskHash: string,
|
|
@@ -385,7 +385,7 @@ export class EvolutionEngine {
|
|
|
385
385
|
return this.createNewScorecard();
|
|
386
386
|
}
|
|
387
387
|
|
|
388
|
-
|
|
388
|
+
|
|
389
389
|
private createNewScorecard(): EvolutionScorecard {
|
|
390
390
|
const now = new Date().toISOString();
|
|
391
391
|
return {
|
|
@@ -444,7 +444,7 @@ export class EvolutionEngine {
|
|
|
444
444
|
} catch (e) {
|
|
445
445
|
console.error(`[Evolution] Failed to save scorecard: ${String(e)}`);
|
|
446
446
|
this.scheduleRetrySave();
|
|
447
|
-
/* eslint-disable @typescript-eslint/no-unused-vars
|
|
447
|
+
/* eslint-disable @typescript-eslint/no-unused-vars -- Reason: intentionally ignored - cleanup failure should not mask original error */
|
|
448
448
|
try { fs.unlinkSync(tempPath); } catch (_e) {
|
|
449
449
|
// Cleanup failure intentionally ignored - should not mask original error
|
|
450
450
|
}
|
|
@@ -527,7 +527,7 @@ export class EvolutionEngine {
|
|
|
527
527
|
|
|
528
528
|
// ===== 工具方法 =====
|
|
529
529
|
|
|
530
|
-
|
|
530
|
+
|
|
531
531
|
private generateId(): string {
|
|
532
532
|
return `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
533
533
|
}
|
|
@@ -264,7 +264,7 @@ export class EvolutionLogger {
|
|
|
264
264
|
durationMs?: number;
|
|
265
265
|
principlesGenerated?: number;
|
|
266
266
|
}): void {
|
|
267
|
-
|
|
267
|
+
|
|
268
268
|
let summary: string;
|
|
269
269
|
if (params.resolution === 'marker_detected' || params.resolution === 'late_marker_principle_created') {
|
|
270
270
|
summary = `任务 ${params.taskId} 完成,已生成 ${params.principlesGenerated || 0} 条原则`;
|
|
@@ -22,7 +22,7 @@ import type {
|
|
|
22
22
|
import { isCompleteDetectorMetadata } from './evolution-types.js';
|
|
23
23
|
import { updateTrainingStore } from './principle-tree-ledger.js';
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
|
|
26
26
|
export interface EvolutionReducer {
|
|
27
27
|
|
|
28
28
|
emit(_event: EvolutionLoopEvent): void;
|
|
@@ -72,7 +72,7 @@ export interface EvolutionReducer {
|
|
|
72
72
|
lastPromotedAt: string | null;
|
|
73
73
|
};
|
|
74
74
|
}
|
|
75
|
-
|
|
75
|
+
|
|
76
76
|
|
|
77
77
|
const PROBATION_SUCCESS_THRESHOLD = 3;
|
|
78
78
|
const CIRCUIT_BREAKER_THRESHOLD = 3;
|
|
@@ -663,7 +663,7 @@ export class EvolutionReducerImpl implements EvolutionReducer {
|
|
|
663
663
|
});
|
|
664
664
|
}
|
|
665
665
|
|
|
666
|
-
|
|
666
|
+
|
|
667
667
|
private onPainDetected(data: PainDetectedData, _eventTs: string): void {
|
|
668
668
|
const trigger = String(data.reason ?? data.source ?? 'unknown trigger');
|
|
669
669
|
|