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.
@@ -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.74.0",
5
+ "version": "1.75.0",
6
6
  "activation": {
7
7
  "onCapabilities": [
8
8
  "hook"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "principles-disciple",
3
- "version": "1.74.0",
3
+ "version": "1.75.0",
4
4
  "description": "Native OpenClaw plugin for Principles Disciple",
5
5
  "type": "module",
6
6
  "main": "./dist/bundle.js",
@@ -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 initialization to avoid repeated calls
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 (!workspaceInitialized) {
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
- // ── Start EvolutionWorker for THIS workspace ──
124
- // Each agent has its own heartbeat task. When before_prompt_build fires,
125
- // it fires for the current agent's workspaceDir. Start one EvolutionWorker
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 PLAN.md state matches actual progress.'
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` or `PLAN.md`.</must>
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`, `PLAN.md` etc. exist.
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 `PLAN.md` contains `## Target Files` heading.
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`, `PLAN.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 `PLAN.md` or early conversation)
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 `PLAN.md`, mark current progress, ensure seamless continuation after compaction.
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, `PLAN.md`, and recent `memory/ISSUE_LOG.md` to write an elegant report for the boss. Remember to check their profile first!"
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)是否可用,检查 PLAN.md 状态与实际进度是否一致。'
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` 或 `PLAN.md`。</must>
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`, `PLAN.md` 等是否存在。
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
- - **结构补全**: 确保 `PLAN.md` 包含 `## Target Files` 标题。
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`, `PLAN.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**: 我们最初的目标是什么?(Check `PLAN.md` or early conversation)
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
- - 更新 `PLAN.md`,标记当前进度,确保压缩后能无缝衔接。
40
+ - 更新 `memory/.scratchpad.md`,标记当前进度,确保压缩后能无缝衔接。
@@ -10,4 +10,4 @@ disable-model-invocation: true
10
10
 
11
11
  ## 执行动作
12
12
  1. 立即委派 ``pd_spawn_agent(reporter)``。
13
- 2. 任务描述:“老板想知道当前的情况。请分析当前的对话上下文、`PLAN.md` 和最近的 `memory/ISSUE_LOG.md`,为老板写一份优雅的汇报。请记住先看他的画像!”
13
+ 2. 任务描述:“老板想知道当前的情况。请分析当前的对话上下文和最近的 `memory/ISSUE_LOG.md`,为老板写一份优雅的汇报。请记住先看他的画像!”
@@ -122,6 +122,7 @@ describe('PRI-212 plugin core anti-growth guard', () => {
122
122
  'evolution-logger.ts',
123
123
  'evolution-engine.ts',
124
124
  'runtime-v2-prompt-activation-reader.ts',
125
+ 'workspace-guidance-migrator.ts',
125
126
  ] as const;
126
127
 
127
128
  // Category 6: Test files
@@ -1,2 +0,0 @@
1
- STATUS: DRAFT
2
- Steps...