principles-disciple 1.73.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/INSTALL.md +1 -3
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/src/core/event-log.ts +0 -9
- package/src/core/migration.ts +0 -1
- package/src/core/path-resolver.ts +0 -1
- package/src/core/paths.ts +0 -1
- package/src/core/workspace-guidance-migrator.ts +179 -0
- package/src/hooks/gate-block-helper.ts +25 -20
- package/src/hooks/gate.ts +13 -61
- package/src/hooks/prompt.ts +1 -61
- package/src/index.ts +8 -12
- package/src/types/event-types.ts +0 -1
- package/src/utils/io.ts +0 -22
- package/templates/langs/en/core/AGENTS.md +5 -5
- package/templates/langs/en/core/BOOTSTRAP.md +1 -1
- package/templates/langs/en/principles/THINKING_OS.md +4 -3
- package/templates/langs/en/skills/admin/SKILL.md +2 -2
- package/templates/langs/en/skills/ai-sprint-orchestration/runtime/.gitignore +2 -2
- package/templates/langs/en/skills/evolve-task/SKILL.md +2 -2
- package/templates/langs/en/skills/pd-grooming/SKILL.md +1 -1
- package/templates/langs/en/skills/pd-mentor/SKILL.md +1 -2
- 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/AGENTS.md +5 -5
- package/templates/langs/zh/core/BOOTSTRAP.md +1 -1
- package/templates/langs/zh/principles/THINKING_OS.md +4 -3
- package/templates/langs/zh/skills/admin/SKILL.md +2 -2
- package/templates/langs/zh/skills/ai-sprint-orchestration/runtime/.gitignore +2 -2
- package/templates/langs/zh/skills/evolve-task/SKILL.md +2 -2
- package/templates/langs/zh/skills/pd-grooming/SKILL.md +1 -1
- package/templates/langs/zh/skills/pd-mentor/SKILL.md +1 -2
- package/templates/langs/zh/skills/reflection/SKILL.md +2 -2
- package/templates/langs/zh/skills/report/SKILL.md +1 -1
- package/tests/core/migration.test.ts +7 -7
- package/tests/core/path-resolver.test.ts +1 -1
- package/tests/core/paths-refactor.test.ts +0 -22
- package/tests/core/workspace-context.test.ts +2 -2
- package/tests/core-anti-growth.test.ts +1 -1
- package/tests/hooks/confirm-first-removal.test.ts +188 -0
- package/tests/hooks/gate-no-path-write-tool.test.ts +172 -0
- package/src/core/confirm-first-gate.ts +0 -255
- package/templates/langs/en/skills/plan-script/SKILL.md +0 -32
- package/templates/langs/zh/skills/plan-script/SKILL.md +0 -32
- package/templates/workspace/PLAN.md +0 -2
- package/tests/hooks/confirm-first-gate.test.ts +0 -333
|
@@ -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
|
|
|
@@ -39,8 +39,9 @@ LLMs are highly sensitive to XML tags; this structure is designed to boost instr
|
|
|
39
39
|
<!-- 执行与物理限制 (Execution & Physical Constraints) -->
|
|
40
40
|
<directive id="T-05" name="PHYSICAL_DEFENSE_AND_ORCHESTRATION">
|
|
41
41
|
<trigger>When asked to perform a major refactoring, multi-file change (>2 files), or an architectural shift.</trigger>
|
|
42
|
-
<
|
|
43
|
-
<
|
|
42
|
+
<should>For complex changes, describe your plan and get owner confirmation before executing.</should>
|
|
43
|
+
<must>Limit your blast radius. After any code change, you MUST run canary tests (e.g., `npm test`, linters) to verify integrity.</must>
|
|
44
|
+
<forbidden>Executing large-scale unstructured changes directly, or skipping post-modification validation.</forbidden>
|
|
44
45
|
</directive>
|
|
45
46
|
|
|
46
47
|
<directive id="T-06" name="OCCAMS_RAZOR_MVC">
|
|
@@ -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)
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
*
|
|
2
|
-
!.gitignore
|
|
1
|
+
*
|
|
2
|
+
!.gitignore
|
|
@@ -51,7 +51,7 @@ Output:
|
|
|
51
51
|
|
|
52
52
|
## Step 6: Delegate Planner (Movie Script Plan)
|
|
53
53
|
- Planner outputs Plan (steps/commands/metrics/rollback).
|
|
54
|
-
- Write plan to
|
|
54
|
+
- Write plan to a planning document for owner review.
|
|
55
55
|
- **Task Sync**:
|
|
56
56
|
- If `CLAUDE_CODE_TASK_LIST_ID` is set, you must convert the Plan's core steps to Native Tasks (via natural language command "Add task..." or related tools).
|
|
57
57
|
- If not set and in interactive mode, prompt user: "Recommend running `export CLAUDE_CODE_TASK_LIST_ID=task-$(date +%s)` to enable persistent task tracking."
|
|
@@ -59,7 +59,7 @@ Output:
|
|
|
59
59
|
- **Performance Evaluation**: After task completion, write to `.state/.verdict.json`. Format follows `@.principles/schemas/agent_verdict_schema.json`.
|
|
60
60
|
|
|
61
61
|
## Step 7: Delegate Implementer (Execution)
|
|
62
|
-
- Implementer
|
|
62
|
+
- Implementer executes according to the plan from Step 6. Any deviation must first be approved by updating the plan.
|
|
63
63
|
- **Performance Evaluation**: After task completion, write to `.state/.verdict.json` based on verification results. Format follows `@.principles/schemas/agent_verdict_schema.json`.
|
|
64
64
|
|
|
65
65
|
## Step 8: Delegate Reviewer (Review)
|
|
@@ -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
|
|
@@ -185,7 +185,7 @@ For complex scenarios, combine multiple skills:
|
|
|
185
185
|
|
|
186
186
|
| Scenario | Combined Flow |
|
|
187
187
|
|----------|---------------|
|
|
188
|
-
| Major refactor | `/pd-evolve` → `
|
|
188
|
+
| Major refactor | `/pd-evolve` → `deductive-audit` → execute |
|
|
189
189
|
| System optimization | `/pd-status` → `evolve-system` → `root-cause` |
|
|
190
190
|
| Project review | `/pd-daily` → `/pd-okr` → `reflection-log` |
|
|
191
191
|
|
|
@@ -196,7 +196,6 @@ These skills are usually called automatically by the system, but advanced users
|
|
|
196
196
|
- `triage` - Issue triage
|
|
197
197
|
- `root-cause` - Root cause analysis
|
|
198
198
|
- `deductive-audit` - Deductive audit
|
|
199
|
-
- `plan-script` - Plan orchestration
|
|
200
199
|
- `reflection` - Metacognitive reflection
|
|
201
200
|
- `reflection-log` - Reflection logging
|
|
202
201
|
|
|
@@ -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!"
|
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
基于**项目战场**中的相对路径进行决策:
|
|
18
18
|
|
|
19
19
|
- **项目最高战略**: `./memory/STRATEGY.md`
|
|
20
|
-
- **项目物理计划**: `./PLAN.md`
|
|
21
20
|
- **痛觉反射信号**: Runtime V2 `PainSignalBridge`(手动触发使用 `pd pain record`;`.state/.pain_flag` 仅为 legacy compatibility)
|
|
22
21
|
- **系统能力快照**: `./.state/SYSTEM_CAPABILITIES.json`
|
|
23
22
|
|
|
@@ -158,12 +157,13 @@
|
|
|
158
157
|
你默认处于架构师模式。
|
|
159
158
|
|
|
160
159
|
- **L1 (直接执行)**:单文件微调、文档维护 → 直接操作
|
|
161
|
-
- **L2 (委派协议)**:重大变更 →
|
|
160
|
+
- **L2 (委派协议)**:重大变更 → 建议先描述计划并获得 owner 确认后再执行
|
|
162
161
|
|
|
163
|
-
###
|
|
162
|
+
### 计划引导 (Planning Guidance)
|
|
164
163
|
|
|
165
|
-
-
|
|
166
|
-
-
|
|
164
|
+
- 对复杂任务,建议先起草计划文档并获得 owner 批准后再做大幅修改
|
|
165
|
+
- 这是行为建议,不是内置门禁 — PD 默认不强制"先计划后执行"
|
|
166
|
+
- 若 owner 批准的 RuleHost 规则强制了计划行为,该规则会自动生效
|
|
167
167
|
- **防止污染**:禁止将执行层细节写回战略文档
|
|
168
168
|
|
|
169
169
|
---
|
|
@@ -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
|
|
|
@@ -39,8 +39,9 @@
|
|
|
39
39
|
<!-- 执行与物理限制 (Execution & Physical Constraints) -->
|
|
40
40
|
<directive id="T-05" name="PHYSICAL_DEFENSE_AND_ORCHESTRATION">
|
|
41
41
|
<trigger>当被要求执行大型重构、多文件修改(>2 个文件)或架构变更时。</trigger>
|
|
42
|
-
<
|
|
43
|
-
<
|
|
42
|
+
<should>对复杂变更,先描述计划并获得 owner 确认后再执行。</should>
|
|
43
|
+
<must>限制爆炸半径。在修改任何代码后,必须运行金丝雀测试(例如 `npm test`、linters)以验证完整性。</must>
|
|
44
|
+
<forbidden>直接执行大规模非结构化变更,或跳过修改后的验证环节。</forbidden>
|
|
44
45
|
</directive>
|
|
45
46
|
|
|
46
47
|
<directive id="T-06" name="OCCAMS_RAZOR_MVC">
|
|
@@ -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` (强制重置)
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
*
|
|
2
|
-
!.gitignore
|
|
1
|
+
*
|
|
2
|
+
!.gitignore
|
|
@@ -51,7 +51,7 @@ disable-model-invocation: true
|
|
|
51
51
|
|
|
52
52
|
## Step 6: 委派 Planner(电影剧本计划)
|
|
53
53
|
- Planner 输出 Plan(步骤/命令/指标/回滚)。
|
|
54
|
-
-
|
|
54
|
+
- 将计划写入计划文档供 owner 审阅。
|
|
55
55
|
- **任务同步 (Task Sync)**:
|
|
56
56
|
- 如果 `CLAUDE_CODE_TASK_LIST_ID` 已设置,你必须将上述 Plan 的核心步骤直接转化为 Native Tasks(通过自然语言指令"Add task..."或相关工具)。
|
|
57
57
|
- 如果未设置且为交互模式,提示用户:"建议运行 `export CLAUDE_CODE_TASK_LIST_ID=task-$(date +%s)` 以启用持久化任务追踪。"
|
|
@@ -59,7 +59,7 @@ disable-model-invocation: true
|
|
|
59
59
|
- **绩效评估**: 任务完成后,写入 `.state/.verdict.json`。格式遵循 `@.principles/schemas/agent_verdict_schema.json`。
|
|
60
60
|
|
|
61
61
|
## Step 7: 委派 Implementer(执行)
|
|
62
|
-
- Implementer
|
|
62
|
+
- Implementer 按照 Step 6 的计划执行。任何偏离必须先更新计划并获得确认。
|
|
63
63
|
- **绩效评估**: 任务完成后,根据验证结果写入 `.state/.verdict.json`。格式遵循 `@.principles/schemas/agent_verdict_schema.json`。
|
|
64
64
|
|
|
65
65
|
## Step 8: 委派 Reviewer(审查)
|
|
@@ -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)
|
|
@@ -185,7 +185,7 @@ disable-model-invocation: true
|
|
|
185
185
|
|
|
186
186
|
| 场景 | 组合流程 |
|
|
187
187
|
|------|----------|
|
|
188
|
-
| 大型重构 | `/pd-evolve` → `
|
|
188
|
+
| 大型重构 | `/pd-evolve` → `deductive-audit` → 执行 |
|
|
189
189
|
| 系统优化 | `/pd-status` → `evolve-system` → `root-cause` |
|
|
190
190
|
| 项目复盘 | `/pd-daily` → `/pd-okr` → `reflection-log` |
|
|
191
191
|
|
|
@@ -196,7 +196,6 @@ disable-model-invocation: true
|
|
|
196
196
|
- `triage` - 问题分诊
|
|
197
197
|
- `root-cause` - 根因分析
|
|
198
198
|
- `deductive-audit` - 演绎审计
|
|
199
|
-
- `plan-script` - 计划编排
|
|
200
199
|
- `reflection` - 元认知反思
|
|
201
200
|
- `reflection-log` - 反思落盘
|
|
202
201
|
|
|
@@ -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`,标记当前进度,确保压缩后能无缝衔接。
|
|
@@ -18,25 +18,25 @@ describe('Directory Structure Migration', () => {
|
|
|
18
18
|
vi.clearAllMocks();
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
-
it('should move
|
|
22
|
-
const
|
|
23
|
-
const
|
|
21
|
+
it('should move THINKING_OS.md from docs/ to .principles/', () => {
|
|
22
|
+
const legacyThinkingOs = path.join(workspaceDir, 'docs', 'THINKING_OS.md');
|
|
23
|
+
const newThinkingOs = '/mock/workspace/.principles/THINKING_OS.md';
|
|
24
24
|
|
|
25
25
|
vi.mocked(fs.existsSync).mockImplementation((p) => {
|
|
26
26
|
const pathStr = p.toString();
|
|
27
27
|
if (pathStr === path.join(workspaceDir, 'docs')) return true;
|
|
28
|
-
if (pathStr ===
|
|
28
|
+
if (pathStr === legacyThinkingOs) return true;
|
|
29
29
|
// Destination directories don't exist yet
|
|
30
30
|
if (pathStr === path.join(workspaceDir, '.principles')) return false;
|
|
31
31
|
// Destination files don't exist yet
|
|
32
|
-
if (pathStr ===
|
|
32
|
+
if (pathStr === newThinkingOs) return false;
|
|
33
33
|
return false;
|
|
34
34
|
});
|
|
35
35
|
|
|
36
36
|
migrateDirectoryStructure(mockApi, workspaceDir);
|
|
37
37
|
|
|
38
|
-
// Verify it moved
|
|
39
|
-
expect(fs.renameSync).toHaveBeenCalledWith(
|
|
38
|
+
// Verify it moved THINKING_OS.md to .principles/
|
|
39
|
+
expect(fs.renameSync).toHaveBeenCalledWith(legacyThinkingOs, newThinkingOs);
|
|
40
40
|
|
|
41
41
|
expect(mockLogger.info).toHaveBeenCalledWith(expect.stringContaining('Successfully migrated'));
|
|
42
42
|
});
|
|
@@ -20,7 +20,7 @@ describe('PathResolver', () => {
|
|
|
20
20
|
const { PathResolver } = await import('../../src/core/path-resolver.js');
|
|
21
21
|
const resolver = new PathResolver({ workspaceDir: '/test/workspace' });
|
|
22
22
|
|
|
23
|
-
const requiredKeys = ['PROFILE', '
|
|
23
|
+
const requiredKeys = ['PROFILE', 'AGENT_SCORECARD', 'PAIN_FLAG', 'EVOLUTION_QUEUE', 'THINKING_OS', 'THINKING_OS_USAGE', 'THINKING_OS_CANDIDATES'];
|
|
24
24
|
|
|
25
25
|
for (const key of requiredKeys) {
|
|
26
26
|
expect(() => resolver.resolve(key)).not.toThrow();
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
-
import { planStatus } from '../../src/utils/io.js';
|
|
3
2
|
import { resolvePdPath } from '../../src/core/paths.js';
|
|
4
|
-
import * as fs from 'fs';
|
|
5
|
-
|
|
6
|
-
vi.mock('fs');
|
|
7
3
|
|
|
8
4
|
describe('Path Anchoring Integration', () => {
|
|
9
5
|
const workspaceDir = '/mock/workspace';
|
|
@@ -17,26 +13,8 @@ describe('Path Anchoring Integration', () => {
|
|
|
17
13
|
expect(resolvePdPath(workspaceDir, 'PROFILE')).toBe(expected);
|
|
18
14
|
});
|
|
19
15
|
|
|
20
|
-
it('should resolve PLAN.md at the project root', () => {
|
|
21
|
-
const expected = '/mock/workspace/PLAN.md';
|
|
22
|
-
expect(resolvePdPath(workspaceDir, 'PLAN')).toBe(expected);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
16
|
it('should resolve AGENT_SCORECARD.json inside .state/', () => {
|
|
26
17
|
const expected = '/mock/workspace/.state/AGENT_SCORECARD.json';
|
|
27
18
|
expect(resolvePdPath(workspaceDir, 'AGENT_SCORECARD')).toBe(expected);
|
|
28
19
|
});
|
|
29
|
-
|
|
30
|
-
it('planStatus should look for PLAN.md in the root', () => {
|
|
31
|
-
const rootPlanPath = '/mock/workspace/PLAN.md';
|
|
32
|
-
vi.mocked(fs.existsSync).mockImplementation((p) => p === rootPlanPath);
|
|
33
|
-
vi.mocked(fs.readFileSync).mockReturnValue('STATUS: READY');
|
|
34
|
-
|
|
35
|
-
const status = planStatus(workspaceDir);
|
|
36
|
-
|
|
37
|
-
expect(status).toBe('READY');
|
|
38
|
-
expect(fs.existsSync).toHaveBeenCalledWith(rootPlanPath);
|
|
39
|
-
// Verify it does NOT look in docs/
|
|
40
|
-
expect(fs.existsSync).not.toHaveBeenCalledWith(expect.stringContaining('docs/PLAN.md'));
|
|
41
|
-
});
|
|
42
20
|
});
|
|
@@ -65,8 +65,8 @@ describe('WorkspaceContext', () => {
|
|
|
65
65
|
|
|
66
66
|
// PROFILE is at .principles/PROFILE.json
|
|
67
67
|
expect(wctx.resolve('PROFILE')).toBe(path.join(workspaceDir, '.principles', 'PROFILE.json'));
|
|
68
|
-
//
|
|
69
|
-
expect(wctx.resolve('
|
|
68
|
+
// THINKING_OS is at .principles/THINKING_OS.md
|
|
69
|
+
expect(wctx.resolve('THINKING_OS')).toBe(path.join(workspaceDir, '.principles', 'THINKING_OS.md'));
|
|
70
70
|
});
|
|
71
71
|
|
|
72
72
|
it('should support explicit disposal from cache', () => {
|
|
@@ -94,7 +94,6 @@ describe('PRI-212 plugin core anti-growth guard', () => {
|
|
|
94
94
|
'external-training-contract.ts',
|
|
95
95
|
'merge-gate-audit.ts',
|
|
96
96
|
'shadow-observation-registry.ts',
|
|
97
|
-
'confirm-first-gate.ts',
|
|
98
97
|
'control-ui-db.ts',
|
|
99
98
|
'thinking-models.ts',
|
|
100
99
|
'pd-task-reconciler.ts',
|
|
@@ -123,6 +122,7 @@ describe('PRI-212 plugin core anti-growth guard', () => {
|
|
|
123
122
|
'evolution-logger.ts',
|
|
124
123
|
'evolution-engine.ts',
|
|
125
124
|
'runtime-v2-prompt-activation-reader.ts',
|
|
125
|
+
'workspace-guidance-migrator.ts',
|
|
126
126
|
] as const;
|
|
127
127
|
|
|
128
128
|
// Category 6: Test files
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PRI-286: Verify confirm-first gate has been fully removed from live paths.
|
|
3
|
+
*
|
|
4
|
+
* These tests prove that:
|
|
5
|
+
* 1. The confirm-first-gate module no longer exists as an importable live module
|
|
6
|
+
* 2. gate.ts does not call any confirm-first function
|
|
7
|
+
* 3. prompt.ts does not import any confirm-first function
|
|
8
|
+
* 4. gate-block-helper does not output confirm-first specific block messages
|
|
9
|
+
* 5. confirm_first_gate does not appear in DEFAULT_FEATURE_FLAGS
|
|
10
|
+
* 6. Default PD installation does not block mutating tools due to PLAN.md absence
|
|
11
|
+
* 7. PLAN.md is not a canonical PD path (paths.ts, path-resolver.ts, env.ts, migration.ts)
|
|
12
|
+
* 8. confirm-first event types and state store are fully deleted
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { describe, it, expect } from 'vitest';
|
|
16
|
+
import fs from 'fs';
|
|
17
|
+
import path from 'path';
|
|
18
|
+
|
|
19
|
+
// __dirname = packages/openclaw-plugin/tests/hooks → go up 4 to monorepo root
|
|
20
|
+
// (hooks → tests → openclaw-plugin → packages → monorepo-root)
|
|
21
|
+
const ROOT = path.resolve(__dirname, '..', '..', '..', '..');
|
|
22
|
+
|
|
23
|
+
describe('PRI-286: Confirm-first gate removal verification', () => {
|
|
24
|
+
it('confirm-first-gate.ts source file has been deleted', () => {
|
|
25
|
+
const gatePath = path.join(ROOT, 'packages/openclaw-plugin/src/core/confirm-first-gate.ts');
|
|
26
|
+
expect(fs.existsSync(gatePath)).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('gate.ts does not import from confirm-first-gate', async () => {
|
|
30
|
+
const gateSource = fs.readFileSync(
|
|
31
|
+
path.join(ROOT, 'packages/openclaw-plugin/src/hooks/gate.ts'),
|
|
32
|
+
'utf8',
|
|
33
|
+
);
|
|
34
|
+
expect(gateSource).not.toContain('confirm-first-gate');
|
|
35
|
+
expect(gateSource).not.toContain('evaluateConfirmFirstGateSync');
|
|
36
|
+
expect(gateSource).not.toContain('confirm-first');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('prompt.ts does not import from confirm-first-gate', async () => {
|
|
40
|
+
const promptSource = fs.readFileSync(
|
|
41
|
+
path.join(ROOT, 'packages/openclaw-plugin/src/hooks/prompt.ts'),
|
|
42
|
+
'utf8',
|
|
43
|
+
);
|
|
44
|
+
expect(promptSource).not.toContain('confirm-first-gate');
|
|
45
|
+
expect(promptSource).not.toContain('detectApprovalMarker');
|
|
46
|
+
expect(promptSource).not.toContain('setConfirmFirstDirective');
|
|
47
|
+
expect(promptSource).not.toContain('setConfirmFirstApproval');
|
|
48
|
+
expect(promptSource).not.toContain('hydrateFromStore');
|
|
49
|
+
expect(promptSource).not.toContain('pruneStoreStaleRows');
|
|
50
|
+
expect(promptSource).not.toContain('setConfirmFirstStore');
|
|
51
|
+
expect(promptSource).not.toContain('resetConfirmFirst');
|
|
52
|
+
expect(promptSource).not.toContain('setConfirmFirstGateEnabled');
|
|
53
|
+
expect(promptSource).not.toContain('SqliteConfirmFirstStateStore');
|
|
54
|
+
expect(promptSource).not.toContain('confirm_first_gate');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('gate-block-helper does not have confirm-first specific branch', () => {
|
|
58
|
+
const helperSource = fs.readFileSync(
|
|
59
|
+
path.join(ROOT, 'packages/openclaw-plugin/src/hooks/gate-block-helper.ts'),
|
|
60
|
+
'utf8',
|
|
61
|
+
);
|
|
62
|
+
expect(helperSource).not.toContain('confirm-first-gate');
|
|
63
|
+
expect(helperSource).not.toContain('Confirm-First Gate Blocked');
|
|
64
|
+
expect(helperSource).not.toContain('confirm-first behavioral directive');
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('confirm_first_gate is not in DEFAULT_FEATURE_FLAGS', async () => {
|
|
68
|
+
const { DEFAULT_FEATURE_FLAGS } = await import('@principles/core/runtime-v2');
|
|
69
|
+
const ids = DEFAULT_FEATURE_FLAGS.map((f: { id: string }) => f.id);
|
|
70
|
+
expect(ids).not.toContain('confirm_first_gate');
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('no PLAN.md physical interception language in AGENTS.md templates', () => {
|
|
74
|
+
const templateDirs = [
|
|
75
|
+
path.join(ROOT, 'packages/openclaw-plugin/templates'),
|
|
76
|
+
path.join(ROOT, 'packages/create-principles-disciple/templates'),
|
|
77
|
+
path.join(ROOT, 'packages/create-principles-disciple/plugin/templates'),
|
|
78
|
+
];
|
|
79
|
+
|
|
80
|
+
for (const dir of templateDirs) {
|
|
81
|
+
if (!fs.existsSync(dir)) continue;
|
|
82
|
+
const agentsFiles = findFiles(dir, 'AGENTS.md');
|
|
83
|
+
for (const file of agentsFiles) {
|
|
84
|
+
const content = fs.readFileSync(file, 'utf8');
|
|
85
|
+
// Must NOT contain physical interception language
|
|
86
|
+
expect(content, `${file} should not contain physical interception`).not.toContain('Physical interception');
|
|
87
|
+
expect(content, `${file} should not contain 物理拦截`).not.toContain('物理拦截');
|
|
88
|
+
expect(content, `${file} should not contain Single source of truth.*PLAN`).not.toMatch(/Single source of truth.*PLAN/i);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('no mandatory PLAN.md STATUS:READY in THINKING_OS templates', () => {
|
|
94
|
+
const templateDirs = [
|
|
95
|
+
path.join(ROOT, 'packages/openclaw-plugin/templates'),
|
|
96
|
+
path.join(ROOT, 'packages/create-principles-disciple/templates'),
|
|
97
|
+
path.join(ROOT, 'packages/create-principles-disciple/plugin/templates'),
|
|
98
|
+
];
|
|
99
|
+
|
|
100
|
+
for (const dir of templateDirs) {
|
|
101
|
+
if (!fs.existsSync(dir)) continue;
|
|
102
|
+
const thinkingFiles = findFiles(dir, 'THINKING_OS.md');
|
|
103
|
+
for (const file of thinkingFiles) {
|
|
104
|
+
const content = fs.readFileSync(file, 'utf8');
|
|
105
|
+
expect(content, `${file} should not require PLAN.md status: READY`).not.toContain('PLAN.md` (status: READY)');
|
|
106
|
+
expect(content, `${file} should not require PLAN.md(状态:READY)`).not.toContain('PLAN.md`(状态:READY)');
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// ── Round 2: Canonical PLAN.md path removal ──
|
|
112
|
+
|
|
113
|
+
it('paths.ts does not contain PLAN: entry', () => {
|
|
114
|
+
const source = fs.readFileSync(
|
|
115
|
+
path.join(ROOT, 'packages/openclaw-plugin/src/core/paths.ts'),
|
|
116
|
+
'utf8',
|
|
117
|
+
);
|
|
118
|
+
expect(source).not.toMatch(/PLAN:\s*'PLAN\.md'/);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('path-resolver.ts does not contain PLAN key', () => {
|
|
122
|
+
const source = fs.readFileSync(
|
|
123
|
+
path.join(ROOT, 'packages/openclaw-plugin/src/core/path-resolver.ts'),
|
|
124
|
+
'utf8',
|
|
125
|
+
);
|
|
126
|
+
expect(source).not.toContain("'PLAN':");
|
|
127
|
+
expect(source).not.toContain('"PLAN":');
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('env.ts CORE_FILES does not contain PLAN.md', () => {
|
|
131
|
+
const source = fs.readFileSync(
|
|
132
|
+
path.join(ROOT, 'packages/create-principles-disciple/src/utils/env.ts'),
|
|
133
|
+
'utf8',
|
|
134
|
+
);
|
|
135
|
+
// Match 'PLAN.md' inside the CORE_FILES array — should not exist
|
|
136
|
+
expect(source).not.toMatch(/CORE_FILES\s*=\s*\[[\s\S]*?'PLAN\.md'/);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('migration.ts does not migrate docs/PLAN.md', () => {
|
|
140
|
+
const source = fs.readFileSync(
|
|
141
|
+
path.join(ROOT, 'packages/openclaw-plugin/src/core/migration.ts'),
|
|
142
|
+
'utf8',
|
|
143
|
+
);
|
|
144
|
+
expect(source).not.toContain("'PLAN.md'");
|
|
145
|
+
expect(source).not.toContain("newKey: 'PLAN'");
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// ── Round 2: Event type and state store full deletion ──
|
|
149
|
+
|
|
150
|
+
it('event-types.ts does not contain runtime_v2_confirm_first_gate', () => {
|
|
151
|
+
const source = fs.readFileSync(
|
|
152
|
+
path.join(ROOT, 'packages/principles-core/src/runtime-v2/types/event-types.ts'),
|
|
153
|
+
'utf8',
|
|
154
|
+
);
|
|
155
|
+
expect(source).not.toContain('runtime_v2_confirm_first_gate');
|
|
156
|
+
expect(source).not.toContain('RuntimeV2ConfirmFirstGate');
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('confirm-first state store source has been deleted', () => {
|
|
160
|
+
const storePath = path.join(
|
|
161
|
+
ROOT, 'packages/principles-core/src/runtime-v2/activation/sqlite-confirm-first-state-store.ts',
|
|
162
|
+
);
|
|
163
|
+
expect(fs.existsSync(storePath)).toBe(false);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('confirm-first state store test has been deleted', () => {
|
|
167
|
+
const testPath = path.join(
|
|
168
|
+
ROOT, 'packages/principles-core/src/runtime-v2/__tests__/sqlite-confirm-first-state-store.test.ts',
|
|
169
|
+
);
|
|
170
|
+
expect(fs.existsSync(testPath)).toBe(false);
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
function findFiles(dir: string, filename: string): string[] {
|
|
175
|
+
const results: string[] = [];
|
|
176
|
+
function walk(d: string): void {
|
|
177
|
+
for (const entry of fs.readdirSync(d, { withFileTypes: true })) {
|
|
178
|
+
const full = path.join(d, entry.name);
|
|
179
|
+
if (entry.isDirectory()) {
|
|
180
|
+
walk(full);
|
|
181
|
+
} else if (entry.name === filename) {
|
|
182
|
+
results.push(full);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
walk(dir);
|
|
187
|
+
return results;
|
|
188
|
+
}
|