principles-disciple 1.181.0 → 1.183.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.
@@ -1,9 +1,11 @@
1
1
  import * as fs from 'fs';
2
2
  import * as path from 'path';
3
+ import * as yaml from 'js-yaml';
3
4
  import { resolvePluginCommandWorkspaceDir } from '../utils/workspace-resolver.js';
4
5
  import { atomicWriteFileSync, normalizeCommandArgs } from '../utils/io.js';
5
6
  import { defaultContextConfig } from '../types.js';
6
7
  import { loadContextInjectionConfig } from '../hooks/prompt.js';
8
+ import { getPdConfigPath } from '../core/pd-config-loader.js';
7
9
  /**
8
10
  * Get workspace directory from context
9
11
  */
@@ -12,26 +14,30 @@ function getWorkspaceDir(ctx) {
12
14
  return resolvePluginCommandWorkspaceDir(ctx, 'context');
13
15
  }
14
16
  /**
15
- * Save context injection config to PROFILE.json
17
+ * Save context injection config to .pd/config.yaml
16
18
  */
17
19
  function saveConfig(workspaceDir, config) {
18
- const profilePath = path.join(workspaceDir, '.principles', 'PROFILE.json');
20
+ const configPath = getPdConfigPath(workspaceDir);
19
21
  try {
20
22
  // Ensure directory exists
21
- const dir = path.dirname(profilePath);
23
+ const dir = path.dirname(configPath);
22
24
  if (!fs.existsSync(dir)) {
23
25
  fs.mkdirSync(dir, { recursive: true });
24
26
  }
25
- // Load existing profile or create new one
26
- let profile = {};
27
- if (fs.existsSync(profilePath)) {
28
- const raw = fs.readFileSync(profilePath, 'utf-8');
29
- profile = JSON.parse(raw);
27
+ // Load existing config or start fresh
28
+ let rawConfig = {};
29
+ if (fs.existsSync(configPath)) {
30
+ const raw = fs.readFileSync(configPath, 'utf-8');
31
+ const parsed = yaml.load(raw, { schema: yaml.JSON_SCHEMA });
32
+ if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {
33
+ rawConfig = parsed;
34
+ }
30
35
  }
31
36
  // Update contextInjection
32
- profile.contextInjection = config;
33
- // Write back
34
- atomicWriteFileSync(profilePath, JSON.stringify(profile, null, 2));
37
+ rawConfig.contextInjection = config;
38
+ // Write back as YAML
39
+ const yamlStr = yaml.dump(rawConfig, { indent: 2, lineWidth: 120, noRefs: true, forceQuotes: false });
40
+ atomicWriteFileSync(configPath, yamlStr);
35
41
  return true;
36
42
  }
37
43
  catch (e) {
package/dist/core/init.js CHANGED
@@ -2,7 +2,6 @@ import * as fs from 'fs';
2
2
  import * as path from 'path';
3
3
  import { fileURLToPath } from 'url';
4
4
  import { PD_DIRS } from './paths.js';
5
- import { defaultContextConfig } from '../types.js';
6
5
  import { loadStore, setPrincipleState } from './principle-training-state.js';
7
6
  import { addPrincipleToLedger } from './principle-tree-ledger.js';
8
7
  import { atomicWriteFileSync } from '../utils/io.js';
@@ -10,11 +9,11 @@ import { createDefaultKeywordStore, saveKeywordStore } from './empathy-keyword-m
10
9
  import { CORE_PRINCIPLES } from '@principles/core/runtime-v2';
11
10
  /**
12
11
  * Default PROFILE.json content
12
+ * Note: contextInjection is migrated to .pd/config.yaml — not initialized here.
13
13
  */
14
14
  const DEFAULT_PROFILE = {
15
15
  name: "Principles Disciple Agent",
16
16
  version: "1.0.0",
17
- contextInjection: defaultContextConfig
18
17
  };
19
18
  const CORE_GUIDANCE_VERSION = 'pd-core-guidance-v2';
20
19
  const CORE_GUIDANCE_FILES = new Set(['AGENTS.md', 'TOOLS.md']);
@@ -85,7 +84,7 @@ export function ensureWorkspaceTemplates(api, workspaceDir, language = 'en') {
85
84
  }
86
85
  copyRecursiveSync(painTemplatesDir, painDestDir, api);
87
86
  }
88
- // 4. Initialize PROFILE.json with default contextInjection config
87
+ // 4. Initialize PROFILE.json with project identity metadata
89
88
  const principlesDir = path.join(workspaceDir, PD_DIRS.IDENTITY);
90
89
  const profilePath = path.join(principlesDir, 'PROFILE.json');
91
90
  if (!fs.existsSync(profilePath)) {
@@ -94,7 +93,7 @@ export function ensureWorkspaceTemplates(api, workspaceDir, language = 'en') {
94
93
  fs.mkdirSync(principlesDir, { recursive: true });
95
94
  }
96
95
  atomicWriteFileSync(profilePath, JSON.stringify(DEFAULT_PROFILE, null, 2));
97
- api.logger.info(`[PD] Initialized PROFILE.json with default contextInjection config`);
96
+ api.logger.info(`[PD] Initialized PROFILE.json with identity metadata (contextInjection migrated to .pd/config.yaml)`);
98
97
  }
99
98
  }
100
99
  catch (err) {
@@ -11,8 +11,9 @@ export declare function resetPromptStateForTest(workspaceDir?: string): void;
11
11
  * Constructs the system prompt injected into LLM context for Principles Disciple
12
12
  */
13
13
  /**
14
- * Loads context injection config from .principles/PROFILE.json
15
- * Parses contextInjection configuration from PROFILE.json for context injection
14
+ * Loads context injection config from .pd/config.yaml via loadPdConfigForPlugin.
15
+ * The resolved config is computed by the core config layer (pd-config-effective.ts),
16
+ * which merges user partial input with DEFAULT_CONTEXT_INJECTION defaults.
16
17
  * @internal Used by evolution engine for context settings
17
18
  */
18
19
  export declare function loadContextInjectionConfig(workspaceDir: string): ContextInjectionConfig;
@@ -1,8 +1,6 @@
1
1
  import * as fs from 'fs';
2
- import * as path from 'path';
3
2
  import { clearInjectedProbationIds, getSession, resetFriction, setInjectedProbationIds, decayGfi, getGfiDecayElapsed } from '../core/session-tracker.js';
4
3
  import { WorkspaceContext } from '../core/workspace-context.js';
5
- import { defaultContextConfig } from '../types.js';
6
4
  // local-worker-routing module and its routing helpers removed entirely per PRI-448.
7
5
  // Routing guidance is no longer injected into prompts.
8
6
  import { extractSummary, getHistoryVersions, parseWorkingMemorySection, workingMemoryToInjection, autoCompressFocus, safeReadCurrentFocus } from '../core/focus-history.js';
@@ -11,7 +9,7 @@ import { selectPrinciplesForInjection, DEFAULT_PRINCIPLE_BUDGET } from '../core/
11
9
  import { getCachedMaskedPrincipleSet, RUNTIME_V2_PRINCIPLE_BUDGET, trimToBudget, renderPrinciplesToDirectives } from '@principles/core/runtime-v2';
12
10
  import { truncateInjectionToBudget } from '@principles/core/prompt-builder';
13
11
  import { PromptActivationReader } from '../core/runtime-v2-prompt-activation-reader.js';
14
- import { loadFeatureFlagFromConfig } from '../core/pd-config-loader.js';
12
+ import { loadPdConfigForPlugin, loadFeatureFlagFromConfig } from '../core/pd-config-loader.js';
15
13
  import { safeReadIntentDoc, resetIntentDocCacheForTest } from '../core/intent-doc-reader.js';
16
14
  import { resolveIntentLang } from '../core/intent-doc-reader-adapter.js';
17
15
  import { buildIntentFrictionBlock } from '@principles/core/runtime-v2';
@@ -108,81 +106,19 @@ function getSignalCollectorHost(wctx, logger) {
108
106
  }
109
107
  return host;
110
108
  }
111
- function parseContextInjectionConfig(value) {
112
- if (typeof value !== 'object' || value === null || Array.isArray(value))
113
- return null;
114
- const config = { ...defaultContextConfig };
115
- const thinkingOs = getOwnValue(value, 'thinkingOs');
116
- const projectFocus = getOwnValue(value, 'projectFocus');
117
- const evolutionContext = getOwnValue(value, 'evolutionContext');
118
- if (thinkingOs !== undefined) {
119
- if (typeof thinkingOs !== 'boolean')
120
- return null;
121
- config.thinkingOs = thinkingOs;
122
- }
123
- if (projectFocus !== undefined) {
124
- if (projectFocus !== 'full' && projectFocus !== 'summary' && projectFocus !== 'off')
125
- return null;
126
- config.projectFocus = projectFocus;
127
- }
128
- if (evolutionContext !== undefined) {
129
- if (typeof evolutionContext !== 'object' || evolutionContext === null || Array.isArray(evolutionContext))
130
- return null;
131
- config.evolutionContext = { ...defaultContextConfig.evolutionContext };
132
- const enabled = getOwnValue(evolutionContext, 'enabled');
133
- const maxMessages = getOwnValue(evolutionContext, 'maxMessages');
134
- const maxCharsPerMessage = getOwnValue(evolutionContext, 'maxCharsPerMessage');
135
- if (enabled !== undefined) {
136
- if (typeof enabled !== 'boolean')
137
- return null;
138
- config.evolutionContext.enabled = enabled;
139
- }
140
- if (maxMessages !== undefined) {
141
- if (typeof maxMessages !== 'number' || !Number.isFinite(maxMessages))
142
- return null;
143
- config.evolutionContext.maxMessages = maxMessages;
144
- }
145
- if (maxCharsPerMessage !== undefined) {
146
- if (typeof maxCharsPerMessage !== 'number' || !Number.isFinite(maxCharsPerMessage))
147
- return null;
148
- config.evolutionContext.maxCharsPerMessage = maxCharsPerMessage;
149
- }
150
- }
151
- return config;
152
- }
153
109
  /**
154
110
  * OpenClaw API Prompt Hook
155
111
  * Constructs the system prompt injected into LLM context for Principles Disciple
156
112
  */
157
113
  /**
158
- * Loads context injection config from .principles/PROFILE.json
159
- * Parses contextInjection configuration from PROFILE.json for context injection
114
+ * Loads context injection config from .pd/config.yaml via loadPdConfigForPlugin.
115
+ * The resolved config is computed by the core config layer (pd-config-effective.ts),
116
+ * which merges user partial input with DEFAULT_CONTEXT_INJECTION defaults.
160
117
  * @internal Used by evolution engine for context settings
161
118
  */
162
119
  export function loadContextInjectionConfig(workspaceDir) {
163
- const profilePath = path.join(workspaceDir, '.principles', 'PROFILE.json');
164
- try {
165
- const raw = cachedReadFile(profilePath, workspaceDir);
166
- if (raw) {
167
- const profile = JSON.parse(raw);
168
- if (profile && typeof profile === 'object' && !Array.isArray(profile)) {
169
- const contextInjection = getOwnValue(profile, 'contextInjection');
170
- if (contextInjection !== undefined) {
171
- const parsed = parseContextInjectionConfig(contextInjection);
172
- if (!parsed) {
173
- console.warn(`[PD:Prompt] Invalid contextInjection config in ${profilePath}; using defaults.`);
174
- return { ...defaultContextConfig };
175
- }
176
- return parsed;
177
- }
178
- }
179
- }
180
- }
181
- catch (e) {
182
- // Failed to load config — continue with defaults, but log for diagnostics
183
- console.warn(`[PD:Prompt] Failed to load contextInjection config: ${String(e)}`);
184
- }
185
- return { ...defaultContextConfig };
120
+ const result = loadPdConfigForPlugin(workspaceDir);
121
+ return { ...result.effective.resolvedContextInjection };
186
122
  }
187
123
  export async function handleBeforePromptBuild(event, ctx) {
188
124
  const { workspaceDir } = ctx;
package/dist/types.d.ts CHANGED
@@ -1,33 +1,13 @@
1
1
  export type { PluginCommandContext, PluginCommandResult } from './openclaw-sdk.js';
2
- /**
3
- * Context Injection Configuration
4
- * Controls what content gets injected into the LLM prompt.
5
- *
6
- * NOTE: Core Principles (PRINCIPLES.md) are ALWAYS injected and cannot be disabled.
7
- * This is by design - principles are the foundation of the agent's behavior.
8
- */
9
- export type ProjectFocusMode = 'full' | 'summary' | 'off';
10
- export interface EvolutionContextConfig {
11
- /** Enable conversation context in evolution task (default: true) */
12
- enabled: boolean;
13
- /** Max recent messages included in evolution task (default: 4) */
14
- maxMessages: number;
15
- /** Max chars per message snippet (default: 200) */
16
- maxCharsPerMessage: number;
17
- }
18
- export interface ContextInjectionConfig {
19
- /** Thinking OS (mental models) - can be toggled */
20
- thinkingOs: boolean;
21
- /** Project context (CURRENT_FOCUS.md) mode */
22
- projectFocus: ProjectFocusMode;
23
- /** Evolution task context injection settings */
24
- evolutionContext: EvolutionContextConfig;
25
- }
2
+ export type { ContextInjectionConfig, EvolutionContextConfig, ProjectFocusMode, } from '@principles/core';
26
3
  /**
27
4
  * Default context injection configuration
28
5
  * Based on MVP-first strategy (ADR-0014):
29
6
  * - principles: always on (not configurable)
30
7
  * - thinkingOs: false by default (MVP-Quiet, user can opt-in via /pd-context)
31
8
  * - projectFocus: 'off' (default closed, user can enable)
9
+ *
10
+ * Migrated to DEFAULT_CONTEXT_INJECTION in @principles/core.
11
+ * Re-exported for backward compatibility.
32
12
  */
33
- export declare const defaultContextConfig: ContextInjectionConfig;
13
+ export { DEFAULT_CONTEXT_INJECTION as defaultContextConfig } from '@principles/core';
package/dist/types.js CHANGED
@@ -4,13 +4,8 @@
4
4
  * - principles: always on (not configurable)
5
5
  * - thinkingOs: false by default (MVP-Quiet, user can opt-in via /pd-context)
6
6
  * - projectFocus: 'off' (default closed, user can enable)
7
+ *
8
+ * Migrated to DEFAULT_CONTEXT_INJECTION in @principles/core.
9
+ * Re-exported for backward compatibility.
7
10
  */
8
- export const defaultContextConfig = {
9
- thinkingOs: false,
10
- projectFocus: 'off',
11
- evolutionContext: {
12
- enabled: true,
13
- maxMessages: 4,
14
- maxCharsPerMessage: 200,
15
- },
16
- };
11
+ export { DEFAULT_CONTEXT_INJECTION as defaultContextConfig } from '@principles/core';
@@ -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.181.0",
5
+ "version": "1.183.0",
6
6
  "activation": {
7
7
  "onCapabilities": [
8
8
  "hook"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "principles-disciple",
3
- "version": "1.181.0",
3
+ "version": "1.183.0",
4
4
  "description": "Native OpenClaw plugin for Principles Disciple",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",