create-principles-disciple 1.75.0 → 1.77.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/core/dist/runtime-v2/__tests__/architecture-regression.test.js +3 -2
- package/core/dist/runtime-v2/__tests__/architecture-regression.test.js.map +1 -1
- package/core/dist/runtime-v2/__tests__/workspace-guidance-migration.test.d.ts +2 -0
- package/core/dist/runtime-v2/__tests__/workspace-guidance-migration.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/__tests__/workspace-guidance-migration.test.js +328 -0
- package/core/dist/runtime-v2/__tests__/workspace-guidance-migration.test.js.map +1 -0
- package/core/dist/runtime-v2/activation/index.d.ts +0 -2
- package/core/dist/runtime-v2/activation/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/index.js +0 -1
- package/core/dist/runtime-v2/activation/index.js.map +1 -1
- package/core/dist/runtime-v2/index.d.ts +6 -4
- package/core/dist/runtime-v2/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/index.js +4 -2
- package/core/dist/runtime-v2/index.js.map +1 -1
- package/core/dist/runtime-v2/types/event-types.d.ts +3 -24
- package/core/dist/runtime-v2/types/event-types.d.ts.map +1 -1
- package/core/dist/runtime-v2/types/event-types.js +0 -10
- package/core/dist/runtime-v2/types/event-types.js.map +1 -1
- package/core/dist/runtime-v2/workspace-guidance-migration.d.ts +12 -0
- package/core/dist/runtime-v2/workspace-guidance-migration.d.ts.map +1 -0
- package/core/dist/runtime-v2/workspace-guidance-migration.js +193 -0
- package/core/dist/runtime-v2/workspace-guidance-migration.js.map +1 -0
- package/dist/utils/env.d.ts.map +1 -1
- package/dist/utils/env.js +0 -1
- package/dist/utils/env.js.map +1 -1
- package/package.json +1 -1
- package/plugin/dist/core/event-log.d.ts +1 -3
- package/plugin/dist/core/event-log.js +0 -6
- package/plugin/dist/core/migration.js +0 -1
- package/plugin/dist/core/path-resolver.js +0 -1
- package/plugin/dist/core/paths.d.ts +0 -1
- package/plugin/dist/core/paths.js +0 -1
- package/plugin/dist/core/workspace-guidance-migrator.d.ts +12 -0
- package/plugin/dist/core/workspace-guidance-migrator.js +141 -0
- package/plugin/dist/hooks/gate-block-helper.js +17 -20
- package/plugin/dist/hooks/gate.js +12 -58
- package/plugin/dist/hooks/prompt.d.ts +6 -0
- package/plugin/dist/hooks/prompt.js +1 -56
- package/plugin/dist/index.js +8 -12
- package/plugin/dist/types/event-types.d.ts +1 -1
- package/plugin/dist/utils/io.d.ts +0 -1
- package/plugin/dist/utils/io.js +0 -23
- package/plugin/templates/langs/en/core/AGENTS.md +5 -5
- package/plugin/templates/langs/en/core/BOOTSTRAP.md +1 -1
- package/plugin/templates/langs/en/principles/THINKING_OS.md +4 -3
- package/plugin/templates/langs/en/skills/admin/SKILL.md +2 -2
- package/plugin/templates/langs/en/skills/evolve-task/SKILL.md +2 -2
- package/plugin/templates/langs/en/skills/pd-grooming/SKILL.md +1 -1
- package/plugin/templates/langs/en/skills/pd-mentor/SKILL.md +1 -2
- package/plugin/templates/langs/en/skills/reflection/SKILL.md +2 -2
- package/plugin/templates/langs/en/skills/report/SKILL.md +1 -1
- package/plugin/templates/langs/zh/core/AGENTS.md +5 -5
- package/plugin/templates/langs/zh/core/BOOTSTRAP.md +1 -1
- package/plugin/templates/langs/zh/principles/THINKING_OS.md +4 -3
- package/plugin/templates/langs/zh/skills/admin/SKILL.md +2 -2
- package/plugin/templates/langs/zh/skills/evolve-task/SKILL.md +2 -2
- package/plugin/templates/langs/zh/skills/pd-grooming/SKILL.md +1 -1
- package/plugin/templates/langs/zh/skills/pd-mentor/SKILL.md +1 -2
- package/plugin/templates/langs/zh/skills/reflection/SKILL.md +2 -2
- package/plugin/templates/langs/zh/skills/report/SKILL.md +1 -1
- package/plugin/templates/workspace/.principles/THINKING_OS.md +4 -3
- package/templates/langs/en/core/AGENTS.md +7 -7
- 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/evolve-task/SKILL.md +3 -3
- 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 +7 -7
- 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/evolve-task/SKILL.md +4 -4
- 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/templates/workspace/.principles/THINKING_OS.md +3 -2
- package/core/dist/runtime-v2/__tests__/sqlite-confirm-first-state-store.test.d.ts +0 -2
- package/core/dist/runtime-v2/__tests__/sqlite-confirm-first-state-store.test.d.ts.map +0 -1
- package/core/dist/runtime-v2/__tests__/sqlite-confirm-first-state-store.test.js +0 -148
- package/core/dist/runtime-v2/__tests__/sqlite-confirm-first-state-store.test.js.map +0 -1
- package/core/dist/runtime-v2/activation/sqlite-confirm-first-state-store.d.ts +0 -22
- package/core/dist/runtime-v2/activation/sqlite-confirm-first-state-store.d.ts.map +0 -1
- package/core/dist/runtime-v2/activation/sqlite-confirm-first-state-store.js +0 -136
- package/core/dist/runtime-v2/activation/sqlite-confirm-first-state-store.js.map +0 -1
- package/plugin/dist/core/confirm-first-gate.d.ts +0 -59
- package/plugin/dist/core/confirm-first-gate.js +0 -215
- package/plugin/templates/langs/en/skills/plan-script/SKILL.md +0 -32
- package/plugin/templates/langs/zh/skills/plan-script/SKILL.md +0 -32
- package/plugin/templates/workspace/PLAN.md +0 -2
- 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
|
@@ -15,7 +15,6 @@ export function migrateDirectoryStructure(api, workspaceDir) {
|
|
|
15
15
|
{ legacy: path.join(legacyDocsDir, 'PRINCIPLES.md'), newKey: 'PRINCIPLES' },
|
|
16
16
|
{ legacy: path.join(legacyDocsDir, 'THINKING_OS.md'), newKey: 'THINKING_OS' },
|
|
17
17
|
{ legacy: path.join(legacyDocsDir, 'DECISION_POLICY.json'), newKey: 'DECISION_POLICY' },
|
|
18
|
-
{ legacy: path.join(legacyDocsDir, 'PLAN.md'), newKey: 'PLAN' },
|
|
19
18
|
{ legacy: path.join(legacyDocsDir, 'evolution_queue.json'), newKey: 'EVOLUTION_QUEUE' },
|
|
20
19
|
{ legacy: path.join(legacyDocsDir, '.pain_flag'), newKey: 'PAIN_FLAG' },
|
|
21
20
|
{ legacy: path.join(legacyDocsDir, 'SYSTEM_CAPABILITIES.json'), newKey: 'SYSTEM_CAPABILITIES' },
|
|
@@ -240,7 +240,6 @@ export class PathResolver {
|
|
|
240
240
|
'THINKING_OS': workspacePath.join(workspace, '.principles', 'THINKING_OS.md'),
|
|
241
241
|
'DECISION_POLICY': workspacePath.join(workspace, '.principles', 'DECISION_POLICY.json'),
|
|
242
242
|
'MODELS_DIR': workspacePath.join(workspace, '.principles', 'models'),
|
|
243
|
-
'PLAN': workspacePath.join(workspace, 'PLAN.md'),
|
|
244
243
|
'AGENT_SCORECARD': workspacePath.join(state, 'AGENT_SCORECARD.json'),
|
|
245
244
|
'PAIN_FLAG': workspacePath.join(state, '.pain_flag'),
|
|
246
245
|
'EVOLUTION_QUEUE': workspacePath.join(state, 'evolution_queue.json'),
|
|
@@ -61,7 +61,6 @@ export const PD_FILES = {
|
|
|
61
61
|
NOCTURNAL_MEMORY_DIR: PD_DIRS.NOCTURNAL_MEMORY,
|
|
62
62
|
NOCTURNAL_EXPORTS_DIR: PD_DIRS.NOCTURNAL_EXPORTS,
|
|
63
63
|
IMPL_CODE_DIR: PD_DIRS.IMPL_CODE_DIR,
|
|
64
|
-
PLAN: 'PLAN.md',
|
|
65
64
|
MEMORY_MD: 'MEMORY.md',
|
|
66
65
|
HEARTBEAT: 'HEARTBEAT.md',
|
|
67
66
|
SYSTEM_LOG: posixJoin(PD_DIRS.LOGS, 'SYSTEM.log'),
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { OpenClawPluginApi } from '../openclaw-sdk.js';
|
|
2
|
+
interface MigrationError {
|
|
3
|
+
file: string;
|
|
4
|
+
error: string;
|
|
5
|
+
}
|
|
6
|
+
export interface MigrationResult {
|
|
7
|
+
migratedFiles: string[];
|
|
8
|
+
skippedFiles: string[];
|
|
9
|
+
errors: MigrationError[];
|
|
10
|
+
}
|
|
11
|
+
export declare function migrateStaleWorkspaceGuidance(api: OpenClawPluginApi, workspaceDir: string): MigrationResult;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { migrateWorkspaceGuidance, containsStalePlanMdGuidance } from '@principles/core/runtime-v2';
|
|
4
|
+
const WORKSPACE_GUIDANCE_FILES = [
|
|
5
|
+
'AGENTS.md',
|
|
6
|
+
'MEMORY.md',
|
|
7
|
+
];
|
|
8
|
+
const PRINCIPLES_SUBDIR_FILES = [
|
|
9
|
+
'THINKING_OS.md',
|
|
10
|
+
];
|
|
11
|
+
const SKILLS_DIR = path.join('.principles', 'skills');
|
|
12
|
+
const PRINCIPLES_DIR = '.principles';
|
|
13
|
+
const BACKUP_SUFFIX = '.pre-pri286.bak';
|
|
14
|
+
function readFileContent(filePath) {
|
|
15
|
+
try {
|
|
16
|
+
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
17
|
+
if (typeof raw !== 'string') {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
return raw;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function writeBackup(filePath, content) {
|
|
27
|
+
const backupPath = filePath + BACKUP_SUFFIX;
|
|
28
|
+
try {
|
|
29
|
+
fs.writeFileSync(backupPath, content, 'utf-8');
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function discoverSkillFiles(workspaceDir) {
|
|
37
|
+
const skillsDir = path.join(workspaceDir, SKILLS_DIR);
|
|
38
|
+
if (!fs.existsSync(skillsDir)) {
|
|
39
|
+
return { files: [] };
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
const entries = fs.readdirSync(skillsDir, { withFileTypes: true });
|
|
43
|
+
const skillFiles = [];
|
|
44
|
+
for (const entry of entries) {
|
|
45
|
+
if (entry.isDirectory()) {
|
|
46
|
+
const skillMd = path.join(skillsDir, entry.name, 'SKILL.md');
|
|
47
|
+
if (fs.existsSync(skillMd)) {
|
|
48
|
+
skillFiles.push(skillMd);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return { files: skillFiles };
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
56
|
+
return {
|
|
57
|
+
files: [],
|
|
58
|
+
error: {
|
|
59
|
+
file: SKILLS_DIR,
|
|
60
|
+
error: `Failed to enumerate skills directory: ${errMsg}`,
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function collectCandidateFiles(workspaceDir, result) {
|
|
66
|
+
const candidates = [];
|
|
67
|
+
for (const filename of WORKSPACE_GUIDANCE_FILES) {
|
|
68
|
+
candidates.push(path.join(workspaceDir, filename));
|
|
69
|
+
}
|
|
70
|
+
for (const filename of PRINCIPLES_SUBDIR_FILES) {
|
|
71
|
+
candidates.push(path.join(workspaceDir, PRINCIPLES_DIR, filename));
|
|
72
|
+
}
|
|
73
|
+
const skillDiscovery = discoverSkillFiles(workspaceDir);
|
|
74
|
+
if (skillDiscovery.error) {
|
|
75
|
+
result.errors.push(skillDiscovery.error);
|
|
76
|
+
}
|
|
77
|
+
candidates.push(...skillDiscovery.files);
|
|
78
|
+
return candidates;
|
|
79
|
+
}
|
|
80
|
+
export function migrateStaleWorkspaceGuidance(api, workspaceDir) {
|
|
81
|
+
const result = {
|
|
82
|
+
migratedFiles: [],
|
|
83
|
+
skippedFiles: [],
|
|
84
|
+
errors: [],
|
|
85
|
+
};
|
|
86
|
+
const candidates = collectCandidateFiles(workspaceDir, result);
|
|
87
|
+
for (const filePath of candidates) {
|
|
88
|
+
const relativePath = path.relative(workspaceDir, filePath);
|
|
89
|
+
if (!fs.existsSync(filePath)) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
const content = readFileContent(filePath);
|
|
93
|
+
if (content === null) {
|
|
94
|
+
result.errors.push({
|
|
95
|
+
file: relativePath,
|
|
96
|
+
error: 'Failed to read file content',
|
|
97
|
+
});
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (!containsStalePlanMdGuidance(content, relativePath)) {
|
|
101
|
+
result.skippedFiles.push(relativePath);
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
const migrationResult = migrateWorkspaceGuidance(content, relativePath);
|
|
105
|
+
if (!migrationResult.changed) {
|
|
106
|
+
result.skippedFiles.push(relativePath);
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
const migrated = migrationResult.migrated;
|
|
110
|
+
const backupOk = writeBackup(filePath, content);
|
|
111
|
+
if (!backupOk) {
|
|
112
|
+
result.errors.push({
|
|
113
|
+
file: relativePath,
|
|
114
|
+
error: 'Failed to create backup file before migration',
|
|
115
|
+
});
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
try {
|
|
119
|
+
fs.writeFileSync(filePath, migrated, 'utf-8');
|
|
120
|
+
result.migratedFiles.push(relativePath);
|
|
121
|
+
api.logger.info(`[PD:GuidanceMigration] Migrated ${relativePath} (backup at ${relativePath}${BACKUP_SUFFIX})`);
|
|
122
|
+
}
|
|
123
|
+
catch (writeErr) {
|
|
124
|
+
const errMsg = writeErr instanceof Error ? writeErr.message : String(writeErr);
|
|
125
|
+
result.errors.push({
|
|
126
|
+
file: relativePath,
|
|
127
|
+
error: `Failed to write migrated content: ${errMsg}`,
|
|
128
|
+
});
|
|
129
|
+
try {
|
|
130
|
+
fs.writeFileSync(filePath, content, 'utf-8');
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
api.logger.error(`[PD:GuidanceMigration] CRITICAL: Failed to restore original content for ${relativePath} after write failure`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (result.migratedFiles.length > 0) {
|
|
138
|
+
api.logger.info(`[PD:GuidanceMigration] Migration complete: ${result.migratedFiles.length} migrated, ${result.skippedFiles.length} skipped, ${result.errors.length} errors`);
|
|
139
|
+
}
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
@@ -115,34 +115,31 @@ export function recordGateBlockAndReturn(wctx, blockCtx, logger) {
|
|
|
115
115
|
logger.info?.(`[PD_GATE] Gate block recorded without Runtime V2 diagnosis: ${gate.detail}`);
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
|
-
// 6. Return consistent block result with operator guidance
|
|
118
|
+
// 6. Return consistent block result with contextual operator guidance
|
|
119
|
+
const blockMessage = buildContextualBlockMessage({ filePath, reason });
|
|
119
120
|
return {
|
|
120
121
|
block: true,
|
|
121
|
-
blockReason:
|
|
122
|
+
blockReason: blockMessage,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Build contextual block message based on block source.
|
|
127
|
+
* - rule-host: principle-based guidance
|
|
128
|
+
* - default/gate: generic security gate message
|
|
129
|
+
*/
|
|
130
|
+
function buildContextualBlockMessage({ filePath, reason, }) {
|
|
131
|
+
// rule-host or generic gate blocks
|
|
132
|
+
return `[Principles Disciple] Security Gate Blocked this action.
|
|
122
133
|
File: ${filePath}
|
|
123
134
|
Reason: ${reason}
|
|
124
135
|
|
|
125
136
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
126
137
|
📋 How to unblock this operation:
|
|
127
138
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
- Target Files: ${filePath}
|
|
133
|
-
- Steps: What you want to do (be specific)
|
|
134
|
-
- Metrics: How to verify success
|
|
135
|
-
- Active Mental Models: Select 2 relevant models from .principles/THINKING_OS.md
|
|
136
|
-
- Rollback: How to restore if it fails
|
|
137
|
-
|
|
138
|
-
3. After completing the plan, set STATUS: READY in PLAN.md
|
|
139
|
-
|
|
140
|
-
4. Retry the operation
|
|
141
|
-
|
|
142
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
143
|
-
This is a mandatory security gate. The operation was blocked because the modification exceeds the allowed threshold for your current evolution tier.
|
|
144
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`,
|
|
145
|
-
};
|
|
139
|
+
This action was blocked by a Rule Host principle.
|
|
140
|
+
If the blocked path is correct and safe, explain the reasoning to the owner
|
|
141
|
+
and ask for explicit confirmation to proceed.
|
|
142
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`;
|
|
146
143
|
}
|
|
147
144
|
/**
|
|
148
145
|
* Schedule retry for trajectory gate block persistence.
|
|
@@ -8,15 +8,12 @@
|
|
|
8
8
|
* 1. Early Return: Skip if not write/bash/agent tool or no workspace
|
|
9
9
|
* 2. Rule Host: Dynamic principle-based evaluation (sole gate)
|
|
10
10
|
*/
|
|
11
|
-
import
|
|
12
|
-
import * as path from 'path';
|
|
13
|
-
import { normalizePath, planStatus } from '../utils/io.js';
|
|
11
|
+
import { normalizePath } from '../utils/io.js';
|
|
14
12
|
import { WorkspaceContext } from '../core/workspace-context.js';
|
|
15
13
|
import { recordGateBlockAndReturn } from './gate-block-helper.js';
|
|
16
14
|
import { RuleHost } from '../core/rule-host.js';
|
|
17
15
|
import { validateCorrectionProposal, validateProposedPathBounds } from '@principles/core/runtime-v2';
|
|
18
16
|
import { AGENT_TOOLS, BASH_TOOLS_SET, WRITE_TOOLS } from '../constants/tools.js';
|
|
19
|
-
import { evaluateConfirmFirstGateSync } from '../core/confirm-first-gate.js';
|
|
20
17
|
import { getSession, hasRecentThinking } from '../core/session-tracker.js';
|
|
21
18
|
import { getEvolutionEngine } from '../core/evolution-engine.js';
|
|
22
19
|
import { EventLogService } from '../core/event-log.js';
|
|
@@ -31,35 +28,6 @@ export function handleBeforeToolCall(event, ctx) {
|
|
|
31
28
|
return;
|
|
32
29
|
}
|
|
33
30
|
const wctx = WorkspaceContext.fromHookContext(ctx);
|
|
34
|
-
// 1.5. Confirm-First Gate — runs BEFORE filePath resolution to catch apply_patch/no-path cases
|
|
35
|
-
try {
|
|
36
|
-
const cfResult = evaluateConfirmFirstGateSync(ctx.sessionId, event.toolName, event.params);
|
|
37
|
-
if (cfResult.action === 'block') {
|
|
38
|
-
const eventLog = EventLogService.get(wctx.stateDir, logger);
|
|
39
|
-
eventLog.recordConfirmFirstGateBlocked({
|
|
40
|
-
sessionId: ctx.sessionId ?? 'unknown',
|
|
41
|
-
workspaceDir: ctx.workspaceDir,
|
|
42
|
-
toolName: event.toolName,
|
|
43
|
-
reason: cfResult.reason ?? 'confirm_first_required',
|
|
44
|
-
principleId: cfResult.principleId ?? 'unknown',
|
|
45
|
-
nextAction: cfResult.nextAction ?? '',
|
|
46
|
-
});
|
|
47
|
-
// Use safe placeholder when filePath is unavailable (e.g., apply_patch with no path)
|
|
48
|
-
const safePath = (event.params?.file_path || event.params?.path || event.params?.file || event.params?.target)
|
|
49
|
-
?? `<tool:${event.toolName}>`;
|
|
50
|
-
return recordGateBlockAndReturn(wctx, {
|
|
51
|
-
filePath: typeof safePath === 'string' ? safePath : `<tool:${event.toolName}>`,
|
|
52
|
-
reason: cfResult.reason ?? 'confirm_first_required',
|
|
53
|
-
toolName: event.toolName,
|
|
54
|
-
sessionId: ctx.sessionId,
|
|
55
|
-
blockSource: 'confirm-first-gate',
|
|
56
|
-
}, logger);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
catch (cfErr) {
|
|
60
|
-
// ERR-002: fail loud — log but do not crash the gate
|
|
61
|
-
logger?.warn?.(`[PD:ConfirmFirst] Gate evaluation failed (non-blocking): ${String(cfErr)}`);
|
|
62
|
-
}
|
|
63
31
|
// 2. Resolve the target file path
|
|
64
32
|
let filePath = event.params?.file_path || event.params?.path || event.params?.file || event.params?.target;
|
|
65
33
|
// Heuristic for bash mutation detection
|
|
@@ -74,6 +42,11 @@ export function handleBeforeToolCall(event, ctx) {
|
|
|
74
42
|
filePath = command;
|
|
75
43
|
}
|
|
76
44
|
}
|
|
45
|
+
// Write tools without a file path must still go through RuleHost evaluation.
|
|
46
|
+
// Use a synthetic path so RuleHost can evaluate and potentially block.
|
|
47
|
+
if (!filePath && isWriteTool) {
|
|
48
|
+
filePath = `<tool:${event.toolName}>`;
|
|
49
|
+
}
|
|
77
50
|
if (typeof filePath !== 'string')
|
|
78
51
|
return;
|
|
79
52
|
const relPath = normalizePath(filePath, ctx.workspaceDir);
|
|
@@ -88,8 +61,12 @@ export function handleBeforeToolCall(event, ctx) {
|
|
|
88
61
|
},
|
|
89
62
|
workspace: {
|
|
90
63
|
isRiskPath: false, // Rule Host determines risk dynamically
|
|
91
|
-
|
|
92
|
-
|
|
64
|
+
// DEPRECATED (PRI-286): planStatus/hasPlanFile are legacy compatibility fields.
|
|
65
|
+
// Live PD no longer reads or manages PLAN.md state. These fields must not be
|
|
66
|
+
// used for new MVP behavior. Future "plan-first" enforcement must come from
|
|
67
|
+
// owner-approved RuleHost/code_tool_hook activation, not built-in state.
|
|
68
|
+
planStatus: 'NONE',
|
|
69
|
+
hasPlanFile: false,
|
|
93
70
|
},
|
|
94
71
|
session: {
|
|
95
72
|
sessionId: ctx.sessionId,
|
|
@@ -353,29 +330,6 @@ function _extractParamsSummary(params) {
|
|
|
353
330
|
summary.new_string = params.new_string;
|
|
354
331
|
return summary;
|
|
355
332
|
}
|
|
356
|
-
function _getPlanStatus(workspaceDir) {
|
|
357
|
-
try {
|
|
358
|
-
const status = planStatus(workspaceDir);
|
|
359
|
-
if (status === 'READY')
|
|
360
|
-
return 'READY';
|
|
361
|
-
if (status === 'DRAFT')
|
|
362
|
-
return 'DRAFT';
|
|
363
|
-
if (status === '')
|
|
364
|
-
return 'NONE';
|
|
365
|
-
return 'UNKNOWN';
|
|
366
|
-
}
|
|
367
|
-
catch {
|
|
368
|
-
return 'UNKNOWN';
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
function _hasPlanFile(workspaceDir) {
|
|
372
|
-
try {
|
|
373
|
-
return fs.existsSync(path.join(workspaceDir, 'PLAN.md'));
|
|
374
|
-
}
|
|
375
|
-
catch {
|
|
376
|
-
return false;
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
333
|
function _getCurrentGfi(sessionId) {
|
|
380
334
|
if (!sessionId)
|
|
381
335
|
return 0;
|
|
@@ -40,6 +40,12 @@ export declare function loadContextInjectionConfig(workspaceDir: string): Contex
|
|
|
40
40
|
* @internal Helper for model configuration resolution
|
|
41
41
|
*/
|
|
42
42
|
export declare function getDiagnosticianModel(api: PromptHookApi | null, logger?: PluginLogger): string;
|
|
43
|
+
/**
|
|
44
|
+
* Extract recent user messages for keyword optimization context.
|
|
45
|
+
*/
|
|
46
|
+
/**
|
|
47
|
+
* Build prompt for keyword optimization subagent.
|
|
48
|
+
*/
|
|
43
49
|
export declare function handleBeforePromptBuild(event: PluginHookBeforePromptBuildEvent, ctx: PluginHookAgentContext & {
|
|
44
50
|
api?: PromptHookApi;
|
|
45
51
|
}): Promise<PluginHookBeforePromptBuildResult | void>;
|
|
@@ -4,11 +4,10 @@ import { clearInjectedProbationIds, getSession, resetFriction, setInjectedProbat
|
|
|
4
4
|
import { WorkspaceContext } from '../core/workspace-context.js';
|
|
5
5
|
import { defaultContextConfig } from '../types.js';
|
|
6
6
|
import { classifyTask } from '../core/local-worker-routing.js';
|
|
7
|
-
import { detectApprovalMarker, setConfirmFirstApproval, setConfirmFirstDirective, hydrateFromStore, pruneStoreStaleRows, setConfirmFirstStore, resetConfirmFirst } from '../core/confirm-first-gate.js';
|
|
8
7
|
import { extractSummary, getHistoryVersions, parseWorkingMemorySection, workingMemoryToInjection, autoCompressFocus, safeReadCurrentFocus } from '../core/focus-history.js';
|
|
9
8
|
import { PathResolver } from '../core/path-resolver.js';
|
|
10
9
|
import { selectPrinciplesForInjection, DEFAULT_PRINCIPLE_BUDGET } from '../core/principle-injection.js';
|
|
11
|
-
import { getCachedMaskedPrincipleSet, WorkflowFunnelLoader, PiAiRuntimeAdapter, EmpathyObserver, AgentScheduler
|
|
10
|
+
import { getCachedMaskedPrincipleSet, WorkflowFunnelLoader, PiAiRuntimeAdapter, EmpathyObserver, AgentScheduler } from '@principles/core/runtime-v2';
|
|
12
11
|
import { truncateInjectionToBudget } from '@principles/core/prompt-builder';
|
|
13
12
|
import { PromptActivationReader, RUNTIME_V2_PRINCIPLE_BUDGET } from '../core/runtime-v2-prompt-activation-reader.js';
|
|
14
13
|
import { matchEmpathyKeywords, loadKeywordStore, saveKeywordStore, getKeywordStoreSummary, } from '../core/empathy-keyword-matcher.js';
|
|
@@ -51,7 +50,6 @@ function cachedReadFile(filePath) {
|
|
|
51
50
|
// Module-level empathy state — shared across calls to avoid per-turn I/O
|
|
52
51
|
let _empathyTurnCounter = 0;
|
|
53
52
|
let _empathyKeywordCache = null;
|
|
54
|
-
let _confirmFirstHydrationCounter = 0;
|
|
55
53
|
/**
|
|
56
54
|
* OpenClaw API Prompt Hook
|
|
57
55
|
* Constructs the system prompt injected into LLM context for Principles Disciple
|
|
@@ -186,19 +184,6 @@ export function getDiagnosticianModel(api, logger) {
|
|
|
186
184
|
/**
|
|
187
185
|
* Build prompt for keyword optimization subagent.
|
|
188
186
|
*/
|
|
189
|
-
function ensureConfirmFirstStore(workspaceDir) {
|
|
190
|
-
if (!_confirmFirstStoreInitialized) {
|
|
191
|
-
try {
|
|
192
|
-
const connection = new SqliteConnection({ workspaceDir, readonly: false });
|
|
193
|
-
setConfirmFirstStore(new SqliteConfirmFirstStateStore(connection));
|
|
194
|
-
_confirmFirstStoreInitialized = true;
|
|
195
|
-
}
|
|
196
|
-
catch (err) {
|
|
197
|
-
console.warn(`[PD:ConfirmFirst] Failed to initialize store: ${String(err)}`);
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
let _confirmFirstStoreInitialized = false;
|
|
202
187
|
export async function handleBeforePromptBuild(event, ctx) {
|
|
203
188
|
const { workspaceDir } = ctx;
|
|
204
189
|
const logger = ctx.api?.logger;
|
|
@@ -213,17 +198,6 @@ export async function handleBeforePromptBuild(event, ctx) {
|
|
|
213
198
|
if (sessionId) {
|
|
214
199
|
wctx.trajectory?.recordSession?.({ sessionId });
|
|
215
200
|
}
|
|
216
|
-
if (sessionId) {
|
|
217
|
-
ensureConfirmFirstStore(workspaceDir);
|
|
218
|
-
hydrateFromStore(sessionId);
|
|
219
|
-
_confirmFirstHydrationCounter++;
|
|
220
|
-
if (_confirmFirstHydrationCounter % 100 === 0) {
|
|
221
|
-
const pruned = pruneStoreStaleRows();
|
|
222
|
-
if (pruned > 0) {
|
|
223
|
-
logger?.info?.(`[PD:ConfirmFirst] Pruned ${pruned} stale rows from confirm_first_state`);
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
201
|
if (sessionId && trigger === 'user' && Array.isArray(event.messages) && event.messages.length > 0) {
|
|
228
202
|
const latestUserIndex = [...event.messages]
|
|
229
203
|
.map((message, index) => ({ message, index }))
|
|
@@ -231,25 +205,6 @@ export async function handleBeforePromptBuild(event, ctx) {
|
|
|
231
205
|
.find((entry) => entry.message?.role === 'user');
|
|
232
206
|
if (latestUserIndex) {
|
|
233
207
|
const userText = getTextContent(latestUserIndex.message);
|
|
234
|
-
// ── Confirm-first approval detection ──
|
|
235
|
-
// If user sends approval language, mark session as approved for confirm-first gate
|
|
236
|
-
if (sessionId && detectApprovalMarker(userText)) {
|
|
237
|
-
setConfirmFirstApproval(sessionId);
|
|
238
|
-
// P2: Emit approval telemetry for observability (ERR-002)
|
|
239
|
-
try {
|
|
240
|
-
wctx.eventLog.recordConfirmFirstGateApproved({
|
|
241
|
-
sessionId,
|
|
242
|
-
workspaceDir: wctx.workspaceDir,
|
|
243
|
-
toolName: '(approval)',
|
|
244
|
-
reason: 'user_approval_detected',
|
|
245
|
-
principleId: 'confirm-first',
|
|
246
|
-
nextAction: 'mutating tools now permitted',
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
catch (logErr) {
|
|
250
|
-
logger?.warn?.(`[PD:ConfirmFirst] Failed to emit approval event: ${String(logErr)}`);
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
208
|
// Use CorrectionCueLearner for detection — supports learned keywords, not just hardcoded list
|
|
254
209
|
let correctionCue = null;
|
|
255
210
|
try {
|
|
@@ -839,19 +794,9 @@ ${heartbeatChecklist}
|
|
|
839
794
|
catch (logErr) {
|
|
840
795
|
logger?.warn?.(`[PD:RuntimeV2] Failed to emit activation observability event: ${String(logErr)}`);
|
|
841
796
|
}
|
|
842
|
-
// ── Set confirm-first directive state for gate enforcement ──
|
|
843
|
-
if (sessionId) {
|
|
844
|
-
const cfPrinciple = dedupedV2.find((p) => p.principleId === 'princ-mvp-acceptance-confirm-first' ||
|
|
845
|
-
(p.text.toLowerCase().includes('confirm requirements') &&
|
|
846
|
-
p.text.toLowerCase().includes('owner approval')));
|
|
847
|
-
setConfirmFirstDirective(sessionId, !!cfPrinciple, cfPrinciple?.principleId);
|
|
848
|
-
}
|
|
849
797
|
}
|
|
850
798
|
catch (e) {
|
|
851
799
|
logger?.warn?.(`[PD:RuntimeV2] Failed to read Runtime V2 prompt activations: ${String(e)}`);
|
|
852
|
-
if (sessionId) {
|
|
853
|
-
resetConfirmFirst(sessionId);
|
|
854
|
-
}
|
|
855
800
|
}
|
|
856
801
|
// Build appendSystemContext with recency effect
|
|
857
802
|
// Content order (most important last): behavioral_constraints -> project_context -> working_memory -> reflection_log -> thinking_os -> principles
|
package/plugin/dist/index.js
CHANGED
|
@@ -32,15 +32,14 @@ import { PDTaskService } from './core/pd-task-service.js';
|
|
|
32
32
|
import { CentralSyncService } from './service/central-sync-service.js';
|
|
33
33
|
import { ensureWorkspaceTemplates } from './core/init.js';
|
|
34
34
|
import { migrateDirectoryStructure } from './core/migration.js';
|
|
35
|
+
import { migrateStaleWorkspaceGuidance } from './core/workspace-guidance-migrator.js';
|
|
35
36
|
import { SystemLogger } from './core/system-logger.js';
|
|
36
37
|
import { PathResolver } from './core/path-resolver.js';
|
|
37
38
|
import { resolveCommandWorkspaceDir, resolveToolHookWorkspaceDirSafe } from './utils/workspace-resolver.js';
|
|
38
39
|
import { computeRuntimeShadowTaskFingerprint, PD_LOCAL_PROFILES } from './utils/shadow-fingerprint.js';
|
|
39
40
|
import { validateWorkspaceDir } from './core/workspace-dir-validation.js';
|
|
40
41
|
import { resolveWorkspaceDirFromApi } from './core/path-resolver.js';
|
|
41
|
-
// Track
|
|
42
|
-
let workspaceInitialized = false;
|
|
43
|
-
// Track started evolution workers — one per workspace
|
|
42
|
+
// Track started workspaces — one-time init + evolution worker per workspace
|
|
44
43
|
const startedWorkspaces = new Set();
|
|
45
44
|
const HOOK_WORKSPACE_RESOLUTION_NEXT_ACTION = 'verify gateway plugin activation and hook workspace binding; ' +
|
|
46
45
|
'migrate live hook workspace resolution to PD-owned canonical configuration before relying on config-based recovery';
|
|
@@ -81,18 +80,15 @@ const plugin = {
|
|
|
81
80
|
return;
|
|
82
81
|
}
|
|
83
82
|
try {
|
|
84
|
-
if (!
|
|
83
|
+
if (!startedWorkspaces.has(workspaceDir)) {
|
|
84
|
+
startedWorkspaces.add(workspaceDir);
|
|
85
85
|
migrateDirectoryStructure(api, workspaceDir);
|
|
86
|
+
migrateStaleWorkspaceGuidance(api, workspaceDir);
|
|
86
87
|
ensureWorkspaceTemplates(api, workspaceDir, language);
|
|
87
88
|
SystemLogger.log(workspaceDir, 'SYSTEM_BOOT', `Principles Disciple online. Language: ${language}`);
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
// Each agent has its own heartbeat task. When before_prompt_build fires,
|
|
92
|
-
// it fires for the current agent's workspaceDir. Start one EvolutionWorker
|
|
93
|
-
// per workspace so each agent's pain signals are processed independently.
|
|
94
|
-
if (!startedWorkspaces.has(workspaceDir)) {
|
|
95
|
-
startedWorkspaces.add(workspaceDir);
|
|
89
|
+
// ── Start EvolutionWorker for THIS workspace ──
|
|
90
|
+
// One EvolutionWorker per workspace so each agent's pain signals
|
|
91
|
+
// are processed independently.
|
|
96
92
|
EvolutionWorkerService.api = api;
|
|
97
93
|
EvolutionWorkerService.start({
|
|
98
94
|
config: api.config,
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export type { EventType, EventCategory, EventLogEntry, ToolCallEventData, PainSignalEventData, RuleMatchEventData, RulePromotionEventData, HookExecutionEventData, GateBlockEventData, GateBypassEventData, PlanApprovalEventData, EvolutionTaskEventData, EmpathyRollbackEventData, HeartbeatDiagnosisEventData, DiagnosisTaskEventData, DiagnosticianReportEventData, PrincipleCandidateEventData, RuleEnforcedEventData, RuleHostEvaluatedEventData, RuleHostBlockedEventData, RuleHostRequireApprovalEventData, RuleHostAutoCorrectProposedEventData, RuleHostAutoCorrectAppliedEventData, RuntimeV2PromptActivationsInjectedEventData,
|
|
1
|
+
export type { EventType, EventCategory, EventLogEntry, ToolCallEventData, PainSignalEventData, RuleMatchEventData, RulePromotionEventData, HookExecutionEventData, GateBlockEventData, GateBypassEventData, PlanApprovalEventData, EvolutionTaskEventData, EmpathyRollbackEventData, HeartbeatDiagnosisEventData, DiagnosisTaskEventData, DiagnosticianReportEventData, PrincipleCandidateEventData, RuleEnforcedEventData, RuleHostEvaluatedEventData, RuleHostBlockedEventData, RuleHostRequireApprovalEventData, RuleHostAutoCorrectProposedEventData, RuleHostAutoCorrectAppliedEventData, RuntimeV2PromptActivationsInjectedEventData, ToolCallStats, ErrorStats, PainStats, EmpathyEventStats, GfiStats, EvolutionStats as EventEvolutionStats, HookStats, DailyStats, } from '@principles/core/runtime-v2';
|
|
2
2
|
export { createEmptyDailyStats, } from '@principles/core/runtime-v2';
|
|
@@ -4,7 +4,6 @@ export declare function normalizeRiskPath(p: string): string;
|
|
|
4
4
|
export declare function isRisky(relPath: string, riskPaths: string[]): boolean;
|
|
5
5
|
export declare function parseKvLines(text: string): Record<string, string>;
|
|
6
6
|
export declare function serializeKvLines(data: Record<string, any>): string;
|
|
7
|
-
export declare function planStatus(projectDir: string): string;
|
|
8
7
|
/**
|
|
9
8
|
* Normalize command arguments from PluginCommandContext.args.
|
|
10
9
|
* Handles string | string[] | undefined union by joining arrays with spaces.
|
package/plugin/dist/utils/io.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import * as path from 'path';
|
|
2
2
|
import * as fs from 'fs';
|
|
3
|
-
import { resolvePdPath } from '../core/paths.js';
|
|
4
3
|
/**
|
|
5
4
|
* Atomic file write — write to temp then rename to prevent partial writes on crash.
|
|
6
5
|
*
|
|
@@ -141,28 +140,6 @@ export function serializeKvLines(data) {
|
|
|
141
140
|
}
|
|
142
141
|
return lines.join('\n');
|
|
143
142
|
}
|
|
144
|
-
export function planStatus(projectDir) {
|
|
145
|
-
const planPath = resolvePdPath(projectDir, 'PLAN');
|
|
146
|
-
try {
|
|
147
|
-
if (!fs.existsSync(planPath))
|
|
148
|
-
return '';
|
|
149
|
-
const content = fs.readFileSync(planPath, 'utf8');
|
|
150
|
-
const lines = content.split('\n');
|
|
151
|
-
for (const line of lines) {
|
|
152
|
-
if (line.startsWith('STATUS:')) {
|
|
153
|
-
const parts = line.split(':');
|
|
154
|
-
if (parts.length > 1) {
|
|
155
|
-
return parts[1].trim().split(/\s+/)[0] || '';
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
/* eslint-disable @typescript-eslint/no-unused-vars -- Reason: Error is intentionally ignored for graceful degradation */
|
|
160
|
-
}
|
|
161
|
-
catch (_e) {
|
|
162
|
-
// Ignore read errors
|
|
163
|
-
}
|
|
164
|
-
return '';
|
|
165
|
-
}
|
|
166
143
|
/**
|
|
167
144
|
* Normalize command arguments from PluginCommandContext.args.
|
|
168
145
|
* Handles string | string[] | undefined union by joining arrays with spaces.
|
|
@@ -17,7 +17,6 @@ As Principles Disciple, you must distinguish between two physical spaces:
|
|
|
17
17
|
Make decisions based on relative paths in the **Project Battlefield**:
|
|
18
18
|
|
|
19
19
|
- **Strategic Focus**: `./memory/STRATEGY.md`
|
|
20
|
-
- **Physical Plan**: `./PLAN.md`
|
|
21
20
|
- **Pain Signal**: Runtime V2 `PainSignalBridge` (`pd pain record` for manual trigger; `.state/.pain_flag` is legacy compatibility only)
|
|
22
21
|
- **System Capabilities**: `./.state/SYSTEM_CAPABILITIES.json`
|
|
23
22
|
|
|
@@ -166,12 +165,13 @@ On platforms that support reactions (Discord, Slack), use emoji reactions natura
|
|
|
166
165
|
You default to architect mode.
|
|
167
166
|
|
|
168
167
|
- **L1 (Direct Execution)**: Single-file tweaks, doc maintenance → do it directly
|
|
169
|
-
- **L2 (Delegation Protocol)**: Major changes →
|
|
168
|
+
- **L2 (Delegation Protocol)**: Major changes → recommended to describe the plan and get owner confirmation before executing
|
|
170
169
|
|
|
171
|
-
###
|
|
170
|
+
### Planning Guidance
|
|
172
171
|
|
|
173
|
-
-
|
|
174
|
-
-
|
|
172
|
+
- For complex tasks, consider drafting a plan document and getting owner approval before making large changes
|
|
173
|
+
- This is a behavioral suggestion, not a built-in gate — PD does not enforce plan-before-action by default
|
|
174
|
+
- If an owner-approved RuleHost rule enforces planning behavior, that rule takes effect automatically
|
|
175
175
|
- **Prevent pollution**: Never write execution details back to strategic documents
|
|
176
176
|
|
|
177
177
|
---
|
|
@@ -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
|
|
|
@@ -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)
|