principles-disciple 1.74.0 → 1.75.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/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/src/core/workspace-guidance-migrator.ts +179 -0
- package/src/index.ts +8 -12
- package/templates/langs/en/core/BOOTSTRAP.md +1 -1
- package/templates/langs/en/principles/THINKING_OS.md +1 -1
- package/templates/langs/en/skills/admin/SKILL.md +2 -2
- package/templates/langs/en/skills/pd-grooming/SKILL.md +1 -1
- package/templates/langs/en/skills/reflection/SKILL.md +2 -2
- package/templates/langs/en/skills/report/SKILL.md +1 -1
- package/templates/langs/zh/core/BOOTSTRAP.md +1 -1
- package/templates/langs/zh/principles/THINKING_OS.md +1 -1
- package/templates/langs/zh/skills/admin/SKILL.md +2 -2
- package/templates/langs/zh/skills/pd-grooming/SKILL.md +1 -1
- package/templates/langs/zh/skills/reflection/SKILL.md +2 -2
- package/templates/langs/zh/skills/report/SKILL.md +1 -1
- package/tests/core-anti-growth.test.ts +1 -0
- package/templates/workspace/PLAN.md +0 -2
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import type { OpenClawPluginApi } from '../openclaw-sdk.js';
|
|
4
|
+
import { migrateWorkspaceGuidance, containsStalePlanMdGuidance } from '@principles/core/runtime-v2';
|
|
5
|
+
|
|
6
|
+
const WORKSPACE_GUIDANCE_FILES = [
|
|
7
|
+
'AGENTS.md',
|
|
8
|
+
'MEMORY.md',
|
|
9
|
+
] as const;
|
|
10
|
+
|
|
11
|
+
const PRINCIPLES_SUBDIR_FILES = [
|
|
12
|
+
'THINKING_OS.md',
|
|
13
|
+
] as const;
|
|
14
|
+
|
|
15
|
+
const SKILLS_DIR = path.join('.principles', 'skills');
|
|
16
|
+
const PRINCIPLES_DIR = '.principles';
|
|
17
|
+
const BACKUP_SUFFIX = '.pre-pri286.bak';
|
|
18
|
+
|
|
19
|
+
interface MigrationError {
|
|
20
|
+
file: string;
|
|
21
|
+
error: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface MigrationResult {
|
|
25
|
+
migratedFiles: string[];
|
|
26
|
+
skippedFiles: string[];
|
|
27
|
+
errors: MigrationError[];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function readFileContent(filePath: string): string | null {
|
|
31
|
+
try {
|
|
32
|
+
const raw: unknown = fs.readFileSync(filePath, 'utf-8');
|
|
33
|
+
if (typeof raw !== 'string') {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
return raw;
|
|
37
|
+
} catch {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function writeBackup(filePath: string, content: string): boolean {
|
|
43
|
+
const backupPath = filePath + BACKUP_SUFFIX;
|
|
44
|
+
try {
|
|
45
|
+
fs.writeFileSync(backupPath, content, 'utf-8');
|
|
46
|
+
return true;
|
|
47
|
+
} catch {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
interface DiscoverResult {
|
|
53
|
+
files: string[];
|
|
54
|
+
error?: MigrationError;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function discoverSkillFiles(workspaceDir: string): DiscoverResult {
|
|
58
|
+
const skillsDir = path.join(workspaceDir, SKILLS_DIR);
|
|
59
|
+
if (!fs.existsSync(skillsDir)) {
|
|
60
|
+
return { files: [] };
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
const entries = fs.readdirSync(skillsDir, { withFileTypes: true });
|
|
64
|
+
const skillFiles: string[] = [];
|
|
65
|
+
for (const entry of entries) {
|
|
66
|
+
if (entry.isDirectory()) {
|
|
67
|
+
const skillMd = path.join(skillsDir, entry.name, 'SKILL.md');
|
|
68
|
+
if (fs.existsSync(skillMd)) {
|
|
69
|
+
skillFiles.push(skillMd);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return { files: skillFiles };
|
|
74
|
+
} catch (err: unknown) {
|
|
75
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
76
|
+
return {
|
|
77
|
+
files: [],
|
|
78
|
+
error: {
|
|
79
|
+
file: SKILLS_DIR,
|
|
80
|
+
error: `Failed to enumerate skills directory: ${errMsg}`,
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function collectCandidateFiles(workspaceDir: string, result: MigrationResult): string[] {
|
|
87
|
+
const candidates: string[] = [];
|
|
88
|
+
|
|
89
|
+
for (const filename of WORKSPACE_GUIDANCE_FILES) {
|
|
90
|
+
candidates.push(path.join(workspaceDir, filename));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
for (const filename of PRINCIPLES_SUBDIR_FILES) {
|
|
94
|
+
candidates.push(path.join(workspaceDir, PRINCIPLES_DIR, filename));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const skillDiscovery = discoverSkillFiles(workspaceDir);
|
|
98
|
+
if (skillDiscovery.error) {
|
|
99
|
+
result.errors.push(skillDiscovery.error);
|
|
100
|
+
}
|
|
101
|
+
candidates.push(...skillDiscovery.files);
|
|
102
|
+
|
|
103
|
+
return candidates;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function migrateStaleWorkspaceGuidance(
|
|
107
|
+
api: OpenClawPluginApi,
|
|
108
|
+
workspaceDir: string,
|
|
109
|
+
): MigrationResult {
|
|
110
|
+
const result: MigrationResult = {
|
|
111
|
+
migratedFiles: [],
|
|
112
|
+
skippedFiles: [],
|
|
113
|
+
errors: [],
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const candidates = collectCandidateFiles(workspaceDir, result);
|
|
117
|
+
|
|
118
|
+
for (const filePath of candidates) {
|
|
119
|
+
const relativePath = path.relative(workspaceDir, filePath);
|
|
120
|
+
|
|
121
|
+
if (!fs.existsSync(filePath)) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const content = readFileContent(filePath);
|
|
126
|
+
if (content === null) {
|
|
127
|
+
result.errors.push({
|
|
128
|
+
file: relativePath,
|
|
129
|
+
error: 'Failed to read file content',
|
|
130
|
+
});
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (!containsStalePlanMdGuidance(content, relativePath)) {
|
|
135
|
+
result.skippedFiles.push(relativePath);
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const migrationResult = migrateWorkspaceGuidance(content, relativePath);
|
|
140
|
+
if (!migrationResult.changed) {
|
|
141
|
+
result.skippedFiles.push(relativePath);
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const migrated = migrationResult.migrated;
|
|
146
|
+
|
|
147
|
+
const backupOk = writeBackup(filePath, content);
|
|
148
|
+
if (!backupOk) {
|
|
149
|
+
result.errors.push({
|
|
150
|
+
file: relativePath,
|
|
151
|
+
error: 'Failed to create backup file before migration',
|
|
152
|
+
});
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
try {
|
|
157
|
+
fs.writeFileSync(filePath, migrated, 'utf-8');
|
|
158
|
+
result.migratedFiles.push(relativePath);
|
|
159
|
+
api.logger.info(`[PD:GuidanceMigration] Migrated ${relativePath} (backup at ${relativePath}${BACKUP_SUFFIX})`);
|
|
160
|
+
} catch (writeErr: unknown) {
|
|
161
|
+
const errMsg = writeErr instanceof Error ? writeErr.message : String(writeErr);
|
|
162
|
+
result.errors.push({
|
|
163
|
+
file: relativePath,
|
|
164
|
+
error: `Failed to write migrated content: ${errMsg}`,
|
|
165
|
+
});
|
|
166
|
+
try {
|
|
167
|
+
fs.writeFileSync(filePath, content, 'utf-8');
|
|
168
|
+
} catch {
|
|
169
|
+
api.logger.error(`[PD:GuidanceMigration] CRITICAL: Failed to restore original content for ${relativePath} after write failure`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (result.migratedFiles.length > 0) {
|
|
175
|
+
api.logger.info(`[PD:GuidanceMigration] Migration complete: ${result.migratedFiles.length} migrated, ${result.skippedFiles.length} skipped, ${result.errors.length} errors`);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return result;
|
|
179
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -51,6 +51,7 @@ import { PDTaskService } from './core/pd-task-service.js';
|
|
|
51
51
|
import { CentralSyncService } from './service/central-sync-service.js';
|
|
52
52
|
import { ensureWorkspaceTemplates } from './core/init.js';
|
|
53
53
|
import { migrateDirectoryStructure } from './core/migration.js';
|
|
54
|
+
import { migrateStaleWorkspaceGuidance } from './core/workspace-guidance-migrator.js';
|
|
54
55
|
import { SystemLogger } from './core/system-logger.js';
|
|
55
56
|
import { PathResolver } from './core/path-resolver.js';
|
|
56
57
|
import { resolveCommandWorkspaceDir, resolveToolHookWorkspaceDirSafe } from './utils/workspace-resolver.js';
|
|
@@ -59,9 +60,7 @@ import type { WorkerProfile } from './core/model-deployment-registry.js';
|
|
|
59
60
|
import { validateWorkspaceDir } from './core/workspace-dir-validation.js';
|
|
60
61
|
import { resolveWorkspaceDirFromApi } from './core/path-resolver.js';
|
|
61
62
|
|
|
62
|
-
// Track
|
|
63
|
-
let workspaceInitialized = false;
|
|
64
|
-
// Track started evolution workers — one per workspace
|
|
63
|
+
// Track started workspaces — one-time init + evolution worker per workspace
|
|
65
64
|
const startedWorkspaces = new Set<string>();
|
|
66
65
|
|
|
67
66
|
const HOOK_WORKSPACE_RESOLUTION_NEXT_ACTION =
|
|
@@ -113,19 +112,16 @@ const plugin = {
|
|
|
113
112
|
return;
|
|
114
113
|
}
|
|
115
114
|
try {
|
|
116
|
-
if (!
|
|
115
|
+
if (!startedWorkspaces.has(workspaceDir)) {
|
|
116
|
+
startedWorkspaces.add(workspaceDir);
|
|
117
117
|
migrateDirectoryStructure(api, workspaceDir);
|
|
118
|
+
migrateStaleWorkspaceGuidance(api, workspaceDir);
|
|
118
119
|
ensureWorkspaceTemplates(api, workspaceDir, language);
|
|
119
120
|
SystemLogger.log(workspaceDir, 'SYSTEM_BOOT', `Principles Disciple online. Language: ${language}`);
|
|
120
|
-
workspaceInitialized = true;
|
|
121
|
-
}
|
|
122
121
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
// per workspace so each agent's pain signals are processed independently.
|
|
127
|
-
if (!startedWorkspaces.has(workspaceDir)) {
|
|
128
|
-
startedWorkspaces.add(workspaceDir);
|
|
122
|
+
// ── Start EvolutionWorker for THIS workspace ──
|
|
123
|
+
// One EvolutionWorker per workspace so each agent's pain signals
|
|
124
|
+
// are processed independently.
|
|
129
125
|
EvolutionWorkerService.api = api;
|
|
130
126
|
EvolutionWorkerService.start({
|
|
131
127
|
config: api.config,
|
|
@@ -183,7 +183,7 @@ openclaw cron add --name "pd-grooming-daily" \
|
|
|
183
183
|
openclaw cron add --name "health-check" \
|
|
184
184
|
--every 4h \
|
|
185
185
|
--session main \
|
|
186
|
-
--system-event 'Health check: Verify core tools (rg, node, python) are available. Check if
|
|
186
|
+
--system-event 'Health check: Verify core tools (rg, node, python) are available. Check if workspace state matches actual progress.'
|
|
187
187
|
```
|
|
188
188
|
|
|
189
189
|
### 3. Strategy Alignment (Daily at 9 AM)
|
|
@@ -19,7 +19,7 @@ LLMs are highly sensitive to XML tags; this structure is designed to boost instr
|
|
|
19
19
|
|
|
20
20
|
<directive id="T-02" name="PHYSICAL_MEMORY_PERSISTENCE">
|
|
21
21
|
<trigger>When reasoning across multiple files, facing complex debugging, or when the conversation context grows long (>5 turns).</trigger>
|
|
22
|
-
<must>TRUST FILES, NOT YOUR CONTEXT WINDOW. You MUST actively write your intermediate conclusions, breakpoints, and next steps to `memory/.scratchpad.md
|
|
22
|
+
<must>TRUST FILES, NOT YOUR CONTEXT WINDOW. You MUST actively write your intermediate conclusions, breakpoints, and next steps to `memory/.scratchpad.md`.</must>
|
|
23
23
|
<forbidden>Relying on your internal "brain memory" to hold complex state, which will inevitably be wiped by context compression.</forbidden>
|
|
24
24
|
</directive>
|
|
25
25
|
|
|
@@ -15,7 +15,7 @@ You are now the "Evolutionary System Administrator". Your responsibility is to m
|
|
|
15
15
|
### 1. `diagnose` (System Diagnosis)
|
|
16
16
|
**Action**: Check the integrity of the "bare-bones" architecture.
|
|
17
17
|
- **Core Components**: Check if `.claude/hooks/hook_runner.py` exists and is executable.
|
|
18
|
-
- **Documentation Integrity**: Check if `.principles/PROFILE.json
|
|
18
|
+
- **Documentation Integrity**: Check if `.principles/PROFILE.json` etc. exist.
|
|
19
19
|
- **Tool Awareness**: Check `.state/SYSTEM_CAPABILITIES.json`. If missing, prompt user: "⚠️ Toolchain upgrade not performed. Recommend running `/bootstrap-tools` to significantly enhance system capabilities."
|
|
20
20
|
- **Memory Mount**: Check if `CLAUDE.md` contains `System Integration` section.
|
|
21
21
|
- **Output**: Generate a health report listing missing or abnormal items.
|
|
@@ -23,7 +23,7 @@ You are now the "Evolutionary System Administrator". Your responsibility is to m
|
|
|
23
23
|
### 2. `repair` (System Repair)
|
|
24
24
|
**Action**:
|
|
25
25
|
- **Config Recovery**: If `PROFILE.json` is missing or corrupted, attempt recovery from `.claude/templates/PROFILE.json`.
|
|
26
|
-
- **Structure Completion**: Ensure
|
|
26
|
+
- **Structure Completion**: Ensure workspace structure is complete.
|
|
27
27
|
- **Forced Cleanup**: Delete `.pain_flag`, `.verdict.json`, `.user_verdict.json`, `.pending_reflection` and other temporary markers.
|
|
28
28
|
|
|
29
29
|
### 3. `reset` (Force Reset)
|
|
@@ -24,7 +24,7 @@ When performing cleanup operations, you MUST strictly adhere to the following wh
|
|
|
24
24
|
### 🌟 Core Assets
|
|
25
25
|
**These files must remain in the root directory. Do not touch:**
|
|
26
26
|
- `AGENTS.md`, `SOUL.md`, `HEARTBEAT.md`, `TOOLS.md`, `IDENTITY.md`, `USER.md`, `MEMORY.md`
|
|
27
|
-
- `README.md
|
|
27
|
+
- `README.md`
|
|
28
28
|
- `.principles/`, `.state/`
|
|
29
29
|
|
|
30
30
|
### 🎯 Targets for Grooming
|
|
@@ -12,7 +12,7 @@ disable-model-invocation: false
|
|
|
12
12
|
Please execute the following reflection steps:
|
|
13
13
|
|
|
14
14
|
## 1. Status Scan
|
|
15
|
-
- **Goal**: What was our original objective? (Check
|
|
15
|
+
- **Goal**: What was our original objective? (Check early conversation context)
|
|
16
16
|
- **Status**: How much is completed now? Where are we stuck?
|
|
17
17
|
- **Cost**: We've consumed significant tokens. Is the output matching the cost?
|
|
18
18
|
|
|
@@ -37,4 +37,4 @@ If pain detected, must execute:
|
|
|
37
37
|
|
|
38
38
|
## 5. Recovery Plan
|
|
39
39
|
- Since we're about to compact context, how should we continue with the "cleanest" state?
|
|
40
|
-
- Update `
|
|
40
|
+
- Update `memory/.scratchpad.md`, mark current progress, ensure seamless continuation after compaction.
|
|
@@ -10,4 +10,4 @@ User (the boss) requests an immediate work report.
|
|
|
10
10
|
|
|
11
11
|
## Execution Action
|
|
12
12
|
1. Immediately delegate ``pd_spawn_agent(reporter)``.
|
|
13
|
-
2. Task description: "The boss wants to know the current situation. Please analyze current conversation context
|
|
13
|
+
2. Task description: "The boss wants to know the current situation. Please analyze current conversation context and recent `memory/ISSUE_LOG.md` to write an elegant report for the boss. Remember to check their profile first!"
|
|
@@ -183,7 +183,7 @@ openclaw cron add --name "pd-grooming-daily" \
|
|
|
183
183
|
openclaw cron add --name "health-check" \
|
|
184
184
|
--every 4h \
|
|
185
185
|
--session main \
|
|
186
|
-
--system-event '环境健康检查:验证核心工具(rg, node, python
|
|
186
|
+
--system-event '环境健康检查:验证核心工具(rg, node, python)是否可用,检查工作区状态与实际进度是否一致。'
|
|
187
187
|
```
|
|
188
188
|
|
|
189
189
|
### 3. 战略对齐检查(每天上午 9 点)
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
<directive id="T-02" name="PHYSICAL_MEMORY_PERSISTENCE">
|
|
21
21
|
<trigger>在跨越多个文件进行推理、面临复杂的 Debug、或当对话上下文变得很长(>5 轮)时。</trigger>
|
|
22
|
-
<must>信任文件,而不是你的上下文窗口。你必须主动将中间结论、断点和后续步骤写入 `memory/.scratchpad.md
|
|
22
|
+
<must>信任文件,而不是你的上下文窗口。你必须主动将中间结论、断点和后续步骤写入 `memory/.scratchpad.md`。</must>
|
|
23
23
|
<forbidden>依赖你内部的“大脑记忆”来保持复杂状态,这些状态必然会被上下文压缩机制抹除。</forbidden>
|
|
24
24
|
</directive>
|
|
25
25
|
|
|
@@ -15,7 +15,7 @@ disable-model-invocation: true
|
|
|
15
15
|
### 1. `diagnose` (系统诊断)
|
|
16
16
|
**动作**: 检查“毛坯房”架构的完整性。
|
|
17
17
|
- **核心组件**: 检查 `.claude/hooks/hook_runner.py` 是否存在且可执行。
|
|
18
|
-
- **文档完整性**: 检查 `.principles/PROFILE.json
|
|
18
|
+
- **文档完整性**: 检查 `.principles/PROFILE.json` 等是否存在。
|
|
19
19
|
- **工具感知**: 检查 `.state/SYSTEM_CAPABILITIES.json`。若缺失,提示用户:"⚠️ 尚未进行工具链升级。建议运行 `/bootstrap-tools` 以大幅提升系统能力。"
|
|
20
20
|
- **记忆挂载**: 检查 `CLAUDE.md` 是否包含 `System Integration` 章节。
|
|
21
21
|
- **输出**: 生成一份健康报告,列出缺失或异常的项目。
|
|
@@ -23,7 +23,7 @@ disable-model-invocation: true
|
|
|
23
23
|
### 2. `repair` (系统修复)
|
|
24
24
|
**动作**:
|
|
25
25
|
- **配置恢复**: 如果 `PROFILE.json` 缺失或损坏,尝试从 `.claude/templates/PROFILE.json` 恢复。
|
|
26
|
-
- **结构补全**:
|
|
26
|
+
- **结构补全**: 确保工作区结构完整。
|
|
27
27
|
- **强制清理**: 删除 `.pain_flag`, `.verdict.json`, `.user_verdict.json`, `.pending_reflection` 等临时标记。
|
|
28
28
|
|
|
29
29
|
### 3. `reset` (强制重置)
|
|
@@ -24,7 +24,7 @@ description: 执行工作区"大扫除",将散落的临时文件归档或清
|
|
|
24
24
|
### 🌟 核心资产区 (Core Assets)
|
|
25
25
|
**这些文件必须留在根目录,不可触碰:**
|
|
26
26
|
- `AGENTS.md`, `SOUL.md`, `HEARTBEAT.md`, `TOOLS.md`, `IDENTITY.md`, `USER.md`, `MEMORY.md`
|
|
27
|
-
- `README.md
|
|
27
|
+
- `README.md`
|
|
28
28
|
- `.principles/`, `.state/`
|
|
29
29
|
|
|
30
30
|
### 🎯 可处理区 (Targets for Grooming)
|
|
@@ -12,7 +12,7 @@ disable-model-invocation: false
|
|
|
12
12
|
请执行以下反思步骤:
|
|
13
13
|
|
|
14
14
|
## 1. 现状扫描 (Status Scan)
|
|
15
|
-
- **Goal**: 我们最初的目标是什么?(
|
|
15
|
+
- **Goal**: 我们最初的目标是什么?(检查早期对话上下文)
|
|
16
16
|
- **Status**: 现在完成了多少?卡在哪里?
|
|
17
17
|
- **Cost**: 我们消耗了大量 Token,产出是否匹配?
|
|
18
18
|
|
|
@@ -37,4 +37,4 @@ disable-model-invocation: false
|
|
|
37
37
|
|
|
38
38
|
## 5. 恢复计划 (Recovery)
|
|
39
39
|
- 既然要压缩上下文,我们下一步该如何以“最干净”的状态继续?
|
|
40
|
-
- 更新 `
|
|
40
|
+
- 更新 `memory/.scratchpad.md`,标记当前进度,确保压缩后能无缝衔接。
|