principles-disciple 1.40.0 → 1.42.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.
Files changed (52) hide show
  1. package/.planning/codebase/ARCHITECTURE.md +157 -0
  2. package/.planning/codebase/CONCERNS.md +145 -0
  3. package/.planning/codebase/CONVENTIONS.md +148 -0
  4. package/.planning/codebase/INTEGRATIONS.md +81 -0
  5. package/.planning/codebase/STACK.md +87 -0
  6. package/.planning/codebase/STRUCTURE.md +193 -0
  7. package/.planning/codebase/TESTING.md +243 -0
  8. package/esbuild.config.js +32 -3
  9. package/openclaw.plugin.json +1 -1
  10. package/package.json +2 -1
  11. package/scripts/compile-principles.mjs +94 -0
  12. package/scripts/sync-plugin.mjs +96 -281
  13. package/src/commands/pain.ts +12 -5
  14. package/src/commands/promote-impl.ts +13 -7
  15. package/src/commands/rollback.ts +10 -3
  16. package/src/core/event-log.ts +8 -6
  17. package/src/core/evolution-types.ts +33 -1
  18. package/src/core/principle-compiler/code-validator.ts +120 -0
  19. package/src/core/principle-compiler/compiler.ts +242 -0
  20. package/src/core/principle-compiler/index.ts +10 -0
  21. package/src/core/principle-compiler/ledger-registrar.ts +107 -0
  22. package/src/core/principle-compiler/template-generator.ts +108 -0
  23. package/src/core/reflection/reflection-context.ts +228 -0
  24. package/src/hooks/message-sanitize.ts +18 -5
  25. package/src/hooks/prompt.ts +15 -4
  26. package/src/hooks/subagent.ts +2 -3
  27. package/src/http/principles-console-route.ts +21 -4
  28. package/src/service/evolution-worker.ts +89 -365
  29. package/src/service/queue-io.ts +375 -0
  30. package/src/service/queue-migration.ts +122 -0
  31. package/src/service/sleep-cycle.ts +157 -0
  32. package/src/service/subagent-workflow/runtime-direct-driver.ts +1 -1
  33. package/src/service/workflow-watchdog.ts +168 -0
  34. package/src/tools/deep-reflect.ts +22 -11
  35. package/src/types/event-payload.ts +80 -0
  36. package/src/types/queue.ts +70 -0
  37. package/src/utils/file-lock.ts +2 -2
  38. package/src/utils/io.ts +11 -3
  39. package/tests/core/code-validator.test.ts +197 -0
  40. package/tests/core/evolution-migration.test.ts +325 -1
  41. package/tests/core/ledger-registrar.test.ts +232 -0
  42. package/tests/core/principle-compiler.test.ts +348 -0
  43. package/tests/core/queue-purge.test.ts +337 -0
  44. package/tests/core/reflection-context.test.ts +356 -0
  45. package/tests/core/template-generator.test.ts +101 -0
  46. package/tests/fixtures/legacy-queue-v1.json +74 -0
  47. package/tests/integration/principle-compiler-e2e.test.ts +335 -0
  48. package/tests/queue/async-lock.test.ts +200 -0
  49. package/tests/service/evolution-worker.queue.test.ts +296 -0
  50. package/tests/service/queue-io.test.ts +229 -0
  51. package/tests/service/queue-migration.test.ts +147 -0
  52. package/tests/service/workflow-watchdog.test.ts +372 -0
@@ -0,0 +1,193 @@
1
+ # Codebase Structure
2
+
3
+ **Analysis Date:** 2026-04-15
4
+
5
+ ## Directory Layout
6
+
7
+ ```
8
+ openclaw-plugin/
9
+ ├── src/ # Main source code
10
+ │ ├── commands/ # Slash command implementations
11
+ │ ├── config/ # Configuration defaults and errors
12
+ │ ├── constants/ # Shared constants
13
+ │ ├── core/ # Core business logic
14
+ │ │ ├── hygiene/ # Hygiene tracking
15
+ │ │ ├── principle-internalization/ # Principle lifecycle
16
+ │ │ └── schema/ # Database schema and migrations
17
+ │ ├── hooks/ # OpenClaw hook handlers
18
+ │ ├── http/ # HTTP route handlers
19
+ │ ├── i18n/ # Internationalization
20
+ │ ├── service/ # Background services
21
+ │ │ └── subagent-workflow/ # Workflow managers
22
+ │ ├── tools/ # Plugin tools
23
+ │ ├── types/ # TypeScript type definitions
24
+ │ └── utils/ # Utility functions
25
+ ├── ui/ # React UI
26
+ │ └── src/
27
+ │ ├── components/ # React components
28
+ │ ├── context/ # React contexts
29
+ │ ├── hooks/ # React hooks
30
+ │ └── pages/ # Page components
31
+ ├── tests/ # Test suite
32
+ │ ├── commands/ # Command tests
33
+ │ ├── core/ # Core module tests
34
+ │ ├── fixtures/ # Test fixtures
35
+ │ ├── hooks/ # Hook tests
36
+ │ ├── integration/ # Integration tests
37
+ │ ├── service/ # Service tests
38
+ │ └── utils/ # Utility tests
39
+ ├── templates/ # Workspace templates
40
+ │ ├── langs/ # Language-specific templates
41
+ │ └── workspace/ # Workspace structure templates
42
+ ├── dist/ # Build output
43
+ ├── scripts/ # Build scripts
44
+ ├── .state/ # Runtime state (gitignored)
45
+ └── .tmp/ # Temporary files (gitignored)
46
+ ```
47
+
48
+ ## Directory Purposes
49
+
50
+ **src/commands/:**
51
+ - Purpose: Slash command implementations
52
+ - Contains: 20+ command handlers (strategy, focus, pain, rollback, nocturnal-review, nocturnal-train, etc.)
53
+ - Key files: `strategy.ts`, `focus.ts`, `nocturnal-train.ts`, `nocturnal-rollout.ts`
54
+
55
+ **src/core/:**
56
+ - Purpose: Core business logic (evolution, trajectory, pain, training, rules)
57
+ - Contains: 70+ core modules including `evolution-engine.ts`, `trajectory.ts`, `nocturnal-trinity.ts`, `pain.ts`, `principle-tree-ledger.ts`
58
+ - Key files: `evolution-engine.ts`, `nocturnal-trinity.ts`, `rule-host.ts`
59
+
60
+ **src/hooks/:**
61
+ - Purpose: OpenClaw hook handlers for intercepting agent behavior
62
+ - Contains: `prompt.ts`, `gate.ts`, `pain.ts`, `llm.ts`, `lifecycle.ts`, `subagent.ts`, `trajectory-collector.ts`
63
+ - Key files: `gate.ts` (security), `prompt.ts` (context injection)
64
+
65
+ **src/service/:**
66
+ - Purpose: Background worker services
67
+ - Contains: `evolution-worker.ts` (main worker), `nocturnal-service.ts`, `trajectory-service.ts`, `central-database.ts`
68
+ - Key files: `evolution-worker.ts` (144KB, main async processor)
69
+
70
+ **src/service/subagent-workflow/:**
71
+ - Purpose: Workflow orchestration for complex subagent operations
72
+ - Contains: `nocturnal-workflow-manager.ts`, `deep-reflect-workflow-manager.ts`, `empathy-observer-workflow-manager.ts`
73
+ - Key files: `workflow-manager-base.ts`, `dynamic-timeout.ts`
74
+
75
+ **src/utils/:**
76
+ - Purpose: Shared utility functions
77
+ - Contains: `io.ts` (atomic writes), `plugin-logger.ts`, `retry.ts`, `hashing.ts`, `file-lock.ts`
78
+ - Key files: `io.ts` (critical for safe file operations)
79
+
80
+ **src/schema/:**
81
+ - Purpose: SQLite database schema and migrations
82
+ - Contains: `schema-definitions.ts`, `migration-runner.ts`, `migrations/*.ts`
83
+ - Migrations: 4 migrations (001-004)
84
+
85
+ **ui/src/:**
86
+ - Purpose: React-based plugin UI
87
+ - Contains: Pages (Overview, Evolution, Feedback, GateMonitor), components (Shell, ProtectedRoute)
88
+ - Key files: `App.tsx`, `pages/EvolutionPage.tsx`, `pages/FeedbackPage.tsx`
89
+
90
+ ## Key File Locations
91
+
92
+ **Entry Points:**
93
+ - `src/index.ts`: Plugin entry point, registers all hooks/commands/tools
94
+
95
+ **Configuration:**
96
+ - `src/core/config.ts`: PainSettings defaults
97
+ - `src/core/paths.ts`: Directory and file path constants (PD_DIRS, PD_FILES)
98
+ - `openclaw.plugin.json`: Plugin manifest
99
+
100
+ **Core Logic:**
101
+ - `src/core/evolution-engine.ts`: Evolution processing (18KB)
102
+ - `src/core/nocturnal-trinity.ts`: Nocturnal training orchestration (87KB - largest file)
103
+ - `src/core/trajectory.ts`: Trajectory tracking (64KB)
104
+ - `src/core/principle-tree-ledger.ts`: Principle lifecycle management (22KB)
105
+ - `src/core/rule-host.ts`: Sandboxed rule execution (7KB)
106
+
107
+ **Service Layer:**
108
+ - `src/service/evolution-worker.ts`: Background evolution worker (144KB - largest file)
109
+ - `src/service/nocturnal-service.ts`: Nocturnal training service (59KB)
110
+ - `src/service/nocturnal-runtime.ts`: Runtime for nocturnal operations (24KB)
111
+
112
+ **Testing:**
113
+ - `tests/`: Test suite with unit and integration layers
114
+ - `vitest.config.ts`: Test configuration with unit/integration project separation
115
+
116
+ ## Naming Conventions
117
+
118
+ **Files:**
119
+ - TypeScript: `kebab-case.ts` or `camelCase.ts` depending on module type
120
+ - Commands: `kebab-case.ts` (e.g., `nocturnal-review.ts`)
121
+ - Core modules: `camelCase.ts` (e.g., `evolutionEngine.ts`)
122
+ - React components: `PascalCase.tsx`
123
+
124
+ **Directories:**
125
+ - kebab-case: `subagent-workflow`, `principle-internalization`
126
+
127
+ **Types:**
128
+ - Interfaces: `PascalCase` (e.g., `PainSettings`, `EvolutionContext`)
129
+ - Type aliases: `PascalCase`
130
+ - Enums: `PascalCase`
131
+
132
+ ## Where to Add New Code
133
+
134
+ **New Command:**
135
+ - Primary code: `src/commands/<name>.ts`
136
+ - Handler registration: `src/index.ts` in `registerCommandWithAlias()` or `api.registerCommand()`
137
+ - Tests: `tests/commands/<name>.test.ts`
138
+
139
+ **New Hook Handler:**
140
+ - Implementation: `src/hooks/<name>.ts`
141
+ - Registration: `src/index.ts` in `api.on('<hook_name>', ...)` call
142
+ - Tests: `tests/hooks/<name>.test.ts`
143
+
144
+ **New Core Service:**
145
+ - Implementation: `src/core/<name>.ts` or `src/service/<name>.ts`
146
+ - Registration: `src/index.ts` in `api.registerService()`
147
+ - Tests: `tests/core/<name>.test.ts` or `tests/service/<name>.test.ts`
148
+
149
+ **New Workflow Manager:**
150
+ - Implementation: `src/service/subagent-workflow/<name>-workflow-manager.ts`
151
+ - Base class: `src/service/subagent-workflow/workflow-manager-base.ts`
152
+ - Tests: `tests/service/subagent-workflow/<name>.test.ts`
153
+
154
+ **New Database Migration:**
155
+ - Implementation: `src/core/schema/migrations/<number>-<description>.ts`
156
+ - Registration: `src/core/schema/migrations/index.ts`
157
+ - Tests: Integration test in `tests/core/control-ui-db.test.ts`
158
+
159
+ **New Utility:**
160
+ - Shared: `src/utils/<name>.ts`
161
+ - Tests: `tests/utils/<name>.test.ts`
162
+
163
+ ## Special Directories
164
+
165
+ **.state/:**
166
+ - Purpose: Runtime state (per workspace)
167
+ - Generated: Yes (created at runtime)
168
+ - Committed: No (gitignored)
169
+
170
+ **.tmp/:**
171
+ - Purpose: Temporary files during build/dev
172
+ - Generated: Yes
173
+ - Committed: No (gitignored)
174
+
175
+ **dist/:**
176
+ - Purpose: Build output
177
+ - Generated: Yes (by `npm run build`)
178
+ - Committed: Yes (in some branches)
179
+
180
+ **templates/:**
181
+ - Purpose: Workspace template files copied on init
182
+ - Generated: No
183
+ - Committed: Yes
184
+ - Contains: Language-specific templates (en, zh), workspace structure
185
+
186
+ **node_modules/:**
187
+ - Purpose: Dependencies
188
+ - Generated: Yes (by pnpm install)
189
+ - Committed: No
190
+
191
+ ---
192
+
193
+ *Structure analysis: 2026-04-15*
@@ -0,0 +1,243 @@
1
+ # Testing Patterns
2
+
3
+ **Analysis Date:** 2026-04-15
4
+
5
+ ## Test Framework
6
+
7
+ **Runner:** Vitest 4.1.0
8
+ - Config: `vitest.config.ts`
9
+ - Environment: `node`
10
+ - Pool: `threads` (required for `better-sqlite3` native handle cleanup)
11
+
12
+ **Assertion Library:** Vitest built-in (`expect`)
13
+
14
+ **Coverage:** `@vitest/coverage-v8`
15
+ - Thresholds: lines 70%, functions 70%, branches 60%, statements 70%
16
+ - Excludes: `tests/**`
17
+
18
+ **Run Commands:**
19
+ ```bash
20
+ npm test # Run unit tests (fast, parallel)
21
+ npm run test:unit # Alias for above
22
+ npm run test:integration # Run integration tests only
23
+ npm run test:coverage # Run with coverage report
24
+ npm run test:all # Run all tests (unit + integration)
25
+ ```
26
+
27
+ ## Test File Organization
28
+
29
+ **Location:**
30
+ - Tests co-located in `tests/` directory, mirroring `src/` structure
31
+ - `tests/core/`, `tests/commands/`, `tests/hooks/`, `tests/service/`, `tests/utils/`
32
+ - Integration tests in `tests/integration/`
33
+
34
+ **Naming:**
35
+ - `*.test.ts` suffix for all test files
36
+ - Example: `tests/core/detection-service.test.ts`
37
+
38
+ **Structure:**
39
+ ```
40
+ tests/
41
+ ├── commands/ # Command handlers
42
+ ├── core/ # Core services and logic
43
+ ├── fixtures/ # Shared fixtures
44
+ ├── hooks/ # Hook handlers
45
+ ├── integration/ # End-to-end tests
46
+ ├── scripts/ # Script tests
47
+ └── service/ # Service layer
48
+ ```
49
+
50
+ ## Test Structure
51
+
52
+ **Suite Organization:**
53
+ ```typescript
54
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
55
+
56
+ describe('DetectionService', () => {
57
+ beforeEach(() => {
58
+ vi.clearAllMocks();
59
+ // Reset state between tests
60
+ DetectionService.reset();
61
+ });
62
+
63
+ it('should create a new instance on first get', () => {
64
+ // Test implementation
65
+ });
66
+ });
67
+ ```
68
+
69
+ **Patterns:**
70
+ - `beforeEach` for setup, `afterEach` for teardown
71
+ - `vi.clearAllMocks()` between tests (not `vi.resetAllMocks()`)
72
+ - `vi.useFakeTimers()` / `vi.useRealTimers()` for time-sensitive tests
73
+
74
+ ## Mocking
75
+
76
+ **Framework:** Vitest's `vi.fn()` and `vi.mock()`
77
+
78
+ **Module Mocking:**
79
+ ```typescript
80
+ vi.mock('../../src/core/dictionary-service.js');
81
+ vi.mock('../../src/core/detection-funnel.js');
82
+
83
+ // Then configure mock implementations
84
+ vi.mocked(DictionaryService.get).mockReturnValue(mockDict as any);
85
+ ```
86
+
87
+ **Built-in Module Mocking:**
88
+ ```typescript
89
+ vi.mock('fs');
90
+ vi.mocked(fs.existsSync).mockReturnValue(true);
91
+ vi.mocked(fs.readFileSync).mockImplementation((p) => {
92
+ if (p.toString() === configPath) return JSON.stringify(mockConfig);
93
+ return '';
94
+ });
95
+ ```
96
+
97
+ **Mock Reset:**
98
+ - `vi.clearAllMocks()` clears call history but keeps implementations
99
+ - `vi.resetAllMocks()` clears both (use with caution)
100
+ - Reset singleton state: `DetectionService.reset()`, `WorkspaceContext.clearCache()`
101
+
102
+ **Partial Mocks:**
103
+ ```typescript
104
+ vi.mocked(fs.existsSync).mockImplementation((p) => p.toString() === configPath);
105
+ ```
106
+
107
+ ## Fixtures and Factories
108
+
109
+ **Temp Directory Pattern (integration tests):**
110
+ ```typescript
111
+ const tempDirs: string[] = [];
112
+
113
+ function makeWorkspace(): string {
114
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'pd-runtime-summary-'));
115
+ tempDirs.push(dir);
116
+ fs.mkdirSync(path.join(dir, '.state', 'sessions'), { recursive: true });
117
+ return dir;
118
+ }
119
+
120
+ afterEach(() => {
121
+ for (const dir of tempDirs.splice(0)) {
122
+ fs.rmSync(dir, { recursive: true, force: true });
123
+ }
124
+ });
125
+ ```
126
+
127
+ **JSON Fixture Writing:**
128
+ ```typescript
129
+ function writeJson(filePath: string, value: unknown): void {
130
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
131
+ fs.writeFileSync(filePath, JSON.stringify(value, null, 2), 'utf8');
132
+ }
133
+ ```
134
+
135
+ **Session File Helper:**
136
+ ```typescript
137
+ function writeSession(workspace: string, sessionId: string, payload: Record<string, unknown>): void {
138
+ writeJson(path.join(workspace, '.state', 'sessions', `${sessionId}.json`), {
139
+ sessionId,
140
+ ...payload,
141
+ });
142
+ }
143
+ ```
144
+
145
+ ## Integration Tests
146
+
147
+ **Requirements:**
148
+ - Real SQLite database via `better-sqlite3`
149
+ - Thread pool required (not `vm` pool) due to native handle cleanup issues
150
+ - Explicit file list in `vitest.config.ts` integration array
151
+
152
+ **Integration Test Files:**
153
+ ```typescript
154
+ const integrationTests = [
155
+ 'tests/core/control-ui-db.test.ts',
156
+ 'tests/core/evolution-logger.test.ts',
157
+ 'tests/core/nocturnal-e2e.test.ts',
158
+ // ...
159
+ ];
160
+ ```
161
+
162
+ ## Common Patterns
163
+
164
+ **Async Testing with Fake Timers:**
165
+ ```typescript
166
+ beforeEach(() => {
167
+ vi.useFakeTimers();
168
+ });
169
+
170
+ afterEach(() => {
171
+ vi.useRealTimers();
172
+ });
173
+
174
+ it('should retry on retryable error', async () => {
175
+ const fn = vi.fn()
176
+ .mockRejectedValueOnce(new Error('ETIMEDOUT'))
177
+ .mockResolvedValue('success');
178
+
179
+ const resultPromise = retryAsync(fn, { initialDelayMs: 100 });
180
+ await vi.advanceTimersByTimeAsync(100);
181
+ const result = await resultPromise;
182
+ expect(result).toBe('success');
183
+ });
184
+ ```
185
+
186
+ **Error Testing:**
187
+ ```typescript
188
+ it('should throw after max retries exceeded', async () => {
189
+ vi.useRealTimers();
190
+ const fn = vi.fn().mockRejectedValue(new Error('ETIMEDOUT'));
191
+
192
+ await expect(retryAsync(fn, { maxRetries: 1, initialDelayMs: 1, logger: { warn: vi.fn() } }))
193
+ .rejects.toThrow('ETIMEDOUT');
194
+ });
195
+ ```
196
+
197
+ **Singleton Reset Pattern:**
198
+ ```typescript
199
+ // Many services use singleton pattern requiring reset between tests
200
+ DetectionService.reset();
201
+ WorkspaceContext.clearCache();
202
+ clearSession('live-session');
203
+ ```
204
+
205
+ ## Test Naming and Documentation
206
+
207
+ **Descriptive Test Names:**
208
+ ```typescript
209
+ it('should block risk path writes at Seed tier (EP system)', () => { ... });
210
+ it('should return default values if file does not exist', () => { ... });
211
+ ```
212
+
213
+ **Test Comments for Context:**
214
+ ```typescript
215
+ // Task 4: Default Values Consistency Tests
216
+ describe('Gate Default Values Consistency', () => {
217
+ /**
218
+ * PURPOSE: Prove that gate.ts inline defaults match PROFILE_DEFAULTS.
219
+ * If gate.ts has inline defaults that differ from normalizeProfile(),
220
+ * this is a bug - the defaults should come from a single source of truth.
221
+ */
222
+ });
223
+ ```
224
+
225
+ ## Test Isolation
226
+
227
+ **Environment Variable Injection:**
228
+ ```typescript
229
+ // Set env before module load
230
+ process.env.PD_TEST_AGENTS_DIR = TEST_AGENTS_DIR;
231
+ ```
232
+
233
+ **Path Traversal Protection Tests:**
234
+ ```typescript
235
+ it('rejects path traversal session IDs', async () => {
236
+ const result = await extractRecentConversation('../../etc/passwd', 'main');
237
+ expect(result).toBe('');
238
+ });
239
+ ```
240
+
241
+ ---
242
+
243
+ *Testing analysis: 2026-04-15*
package/esbuild.config.js CHANGED
@@ -25,6 +25,7 @@ function copyRecursive(src, dest) {
25
25
 
26
26
  async function bundlePlugin() {
27
27
  try {
28
+ // 1. Build the main bundle for OpenClaw
28
29
  await build({
29
30
  entryPoints: ['src/index.ts'],
30
31
  outfile: 'dist/bundle.js',
@@ -44,7 +45,35 @@ async function bundlePlugin() {
44
45
  metafile: true,
45
46
  });
46
47
 
47
- console.log('Bundle created: dist/bundle.js');
48
+ console.log('Main bundle created: dist/bundle.js');
49
+
50
+ // 2. Build core tools for CLI usage (bootstrap-rules, etc)
51
+ // We keep these separate and un-minified for easier debugging and CLI importing
52
+ await build({
53
+ entryPoints: {
54
+ 'core/bootstrap-rules': 'src/core/bootstrap-rules.ts',
55
+ 'core/principle-tree-ledger': 'src/core/principle-tree-ledger.ts',
56
+ 'core/principle-training-state': 'src/core/principle-training-state.ts',
57
+ 'core/principle-compiler/index': 'src/core/principle-compiler/index.ts',
58
+ 'core/trajectory/index': 'src/core/trajectory.ts',
59
+ },
60
+ outdir: 'dist',
61
+ bundle: true,
62
+ platform: 'node',
63
+ target: 'node20',
64
+ format: 'esm',
65
+ outbase: 'src',
66
+ external: [
67
+ 'openclaw',
68
+ '@openclaw/sdk',
69
+ '@openclaw/plugin-kit',
70
+ 'better-sqlite3',
71
+ ],
72
+ sourcemap: false,
73
+ minify: false,
74
+ });
75
+
76
+ console.log('Core CLI tools built in dist/core/');
48
77
 
49
78
  const staticFiles = ['templates', 'openclaw.plugin.json'];
50
79
  const distDir = 'dist';
@@ -65,9 +94,9 @@ async function bundlePlugin() {
65
94
  console.log(`Copied: ${file} -> dist/${file}`);
66
95
  }
67
96
 
68
- console.log('\nPlugin bundle ready for distribution.');
97
+ console.log('\nPlugin build ready for distribution.');
69
98
  } catch (error) {
70
- console.error('Bundle failed:', error);
99
+ console.error('Build failed:', error);
71
100
  process.exit(1);
72
101
  }
73
102
  }
@@ -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.40.0",
5
+ "version": "1.42.0",
6
6
  "skills": [
7
7
  "./skills"
8
8
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "principles-disciple",
3
- "version": "1.40.0",
3
+ "version": "1.42.0",
4
4
  "description": "Native OpenClaw plugin for Principles Disciple",
5
5
  "type": "module",
6
6
  "main": "./dist/bundle.js",
@@ -37,6 +37,7 @@
37
37
  "test:all": "vitest run",
38
38
  "lint": "eslint src/",
39
39
  "bootstrap-rules": "node scripts/bootstrap-rules.mjs",
40
+ "compile-principles": "node scripts/compile-principles.mjs",
40
41
  "validate-live-path": "tsx scripts/validate-live-path.ts"
41
42
  },
42
43
  "devDependencies": {
@@ -0,0 +1,94 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Principle Compiler CLI
5
+ *
6
+ * Compiles eligible principles (those derived from pain events) into
7
+ * auto-generated rules via the PrincipleCompiler pipeline.
8
+ *
9
+ * Usage:
10
+ * npm run compile-principles
11
+ * WORKSPACE_DIR=/path/to/workspace npm run compile-principles
12
+ * node scripts/compile-principles.mjs /path/to/workspace
13
+ */
14
+
15
+ import { join, dirname } from 'path';
16
+ import { fileURLToPath } from 'url';
17
+
18
+ const __filename = fileURLToPath(import.meta.url);
19
+ const __dirname = dirname(__filename);
20
+
21
+ // Resolve workspace directory: CLI arg > env var > default
22
+ const WORKSPACE_DIR = process.argv[2]
23
+ || process.env.WORKSPACE_DIR
24
+ || join(process.env.HOME, '.openclaw', 'workspace-main');
25
+
26
+ const STATE_DIR = join(WORKSPACE_DIR, '.state');
27
+
28
+ async function run() {
29
+ console.log('Principle Compiler CLI');
30
+ console.log(` Workspace: ${WORKSPACE_DIR}`);
31
+ console.log(` State dir: ${STATE_DIR}`);
32
+
33
+ let compilerModule, trajectoryModule;
34
+
35
+ try {
36
+ compilerModule = await import('../dist/core/principle-compiler/index.js');
37
+ } catch {
38
+ console.error('PrincipleCompiler module not found in dist/. Build first: node esbuild.config.js');
39
+ process.exit(1);
40
+ }
41
+
42
+ try {
43
+ trajectoryModule = await import('../dist/core/trajectory/index.js');
44
+ } catch {
45
+ console.error('TrajectoryDatabase module not found in dist/. Build first: node esbuild.config.js');
46
+ process.exit(1);
47
+ }
48
+
49
+ const { PrincipleCompiler } = compilerModule;
50
+ const { TrajectoryDatabase } = trajectoryModule;
51
+
52
+ let trajectory;
53
+ try {
54
+ trajectory = new TrajectoryDatabase({ workspaceDir: WORKSPACE_DIR });
55
+ } catch (err) {
56
+ console.error(`Failed to open trajectory database: ${err.message}`);
57
+ process.exit(1);
58
+ }
59
+
60
+ try {
61
+ const compiler = new PrincipleCompiler(STATE_DIR, trajectory);
62
+
63
+ console.log('\nCompiling eligible principles...');
64
+ const results = compiler.compileAll();
65
+
66
+ const succeeded = results.filter(r => r.success);
67
+ const failed = results.filter(r => !r.success);
68
+
69
+ console.log(`\nResults: ${succeeded.length} succeeded, ${failed.length} failed`);
70
+
71
+ for (const r of succeeded) {
72
+ console.log(` + ${r.principleId} -> rule ${r.ruleId} (impl: ${r.implementationId})`);
73
+ }
74
+
75
+ for (const r of failed) {
76
+ console.log(` x ${r.principleId}: ${r.reason}`);
77
+ }
78
+
79
+ if (results.length === 0) {
80
+ console.log(' No eligible principles found for compilation.');
81
+ }
82
+
83
+ if (failed.length > 0) {
84
+ process.exitCode = 1;
85
+ }
86
+ } finally {
87
+ trajectory.dispose();
88
+ }
89
+ }
90
+
91
+ run().catch((err) => {
92
+ console.error(`Fatal: ${err.message}`);
93
+ process.exit(1);
94
+ });