orchestrix-yuri 4.4.0 → 4.5.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.
@@ -59,6 +59,50 @@ function loadL1Context() {
59
59
  : '';
60
60
  }
61
61
 
62
+ /**
63
+ * Load L2 (project-level) context for the active project.
64
+ * Only loads lightweight files: identity.yaml and project focus.yaml.
65
+ * knowledge/*.md files are intentionally excluded (too large for system prompt —
66
+ * Claude can Read them on demand via tool use).
67
+ */
68
+ function loadL2Context() {
69
+ const projectRoot = resolveProjectRoot();
70
+ if (!projectRoot) return '';
71
+
72
+ const yuriDir = path.join(projectRoot, '.yuri');
73
+ if (!fs.existsSync(yuriDir)) return '';
74
+
75
+ const files = [
76
+ { label: 'Project Identity', path: path.join(yuriDir, 'identity.yaml') },
77
+ { label: 'Project Focus', path: path.join(yuriDir, 'focus.yaml') },
78
+ ];
79
+
80
+ const sections = [];
81
+ for (const f of files) {
82
+ if (!fs.existsSync(f.path)) continue;
83
+ const content = fs.readFileSync(f.path, 'utf8').trim();
84
+ if (!content || isEmptyTemplate(content)) continue;
85
+ sections.push(`### ${f.label}\n\`\`\`yaml\n${content}\n\`\`\``);
86
+ }
87
+
88
+ if (sections.length === 0) return '';
89
+
90
+ // Also list available knowledge files (so Claude knows they exist)
91
+ const knowledgeDir = path.join(yuriDir, 'knowledge');
92
+ let knowledgeNote = '';
93
+ if (fs.existsSync(knowledgeDir)) {
94
+ try {
95
+ const knowledgeFiles = fs.readdirSync(knowledgeDir).filter((f) => f.endsWith('.md'));
96
+ if (knowledgeFiles.length > 0) {
97
+ knowledgeNote = `\n\n*Project knowledge files available (use Read tool to access):*\n` +
98
+ knowledgeFiles.map((f) => `- \`${path.join(yuriDir, 'knowledge', f)}\``).join('\n');
99
+ }
100
+ } catch { /* ok */ }
101
+ }
102
+
103
+ return `## Active Project Context (L2)\n\n${sections.join('\n\n')}${knowledgeNote}`;
104
+ }
105
+
62
106
  function resolveProjectRoot() {
63
107
  const registryPath = path.join(YURI_GLOBAL, 'portfolio', 'registry.yaml');
64
108
  if (!fs.existsSync(registryPath)) return null;
@@ -170,6 +214,12 @@ function buildSystemPrompt() {
170
214
  const l1 = loadL1Context();
171
215
  if (l1) parts.push(l1);
172
216
 
217
+ // Layer 2.5: L2 project context (lightweight — identity + focus only)
218
+ // knowledge/*.md is NOT loaded here (too large for system prompt).
219
+ // Claude can Read those files when needed via tool use.
220
+ const l2 = loadL2Context();
221
+ if (l2) parts.push(l2);
222
+
173
223
  // Layer 3: Channel mode instructions
174
224
  parts.push(CHANNEL_MODE_INSTRUCTIONS);
175
225
 
@@ -373,20 +423,26 @@ async function callClaude(opts) {
373
423
  function composePrompt(userMessage) {
374
424
  const crypto = require('crypto');
375
425
  const l1 = loadL1Context();
376
- const l1Hash = crypto.createHash('md5').update(l1 || '').digest('hex');
426
+ const l2 = loadL2Context();
427
+ const combined = (l1 || '') + (l2 || '');
428
+ const contextHash = crypto.createHash('md5').update(combined).digest('hex');
377
429
 
378
- // First call or L1 unchanged: just the user message
379
- if (!_lastL1Hash || l1Hash === _lastL1Hash) {
380
- _lastL1Hash = l1Hash;
430
+ // First call or context unchanged: just the user message
431
+ if (!_lastL1Hash || contextHash === _lastL1Hash) {
432
+ _lastL1Hash = contextHash;
381
433
  return userMessage;
382
434
  }
383
435
 
384
- // L1 changed: prepend context refresh
385
- _lastL1Hash = l1Hash;
386
- if (!l1) return userMessage;
436
+ // Context changed: prepend refresh
437
+ _lastL1Hash = contextHash;
438
+ if (!combined) return userMessage;
439
+
440
+ const sections = [];
441
+ if (l1) sections.push(l1);
442
+ if (l2) sections.push(l2);
387
443
 
388
- log.engine('L1 context changed, injecting refresh into prompt');
389
- return `[CONTEXT UPDATE — Your global memory has been updated]\n${l1}\n[END CONTEXT UPDATE]\n\n${userMessage}`;
444
+ log.engine('Memory context changed, injecting refresh into prompt');
445
+ return `[CONTEXT UPDATE — Your memory has been updated]\n${sections.join('\n\n')}\n[END CONTEXT UPDATE]\n\n${userMessage}`;
390
446
  }
391
447
 
392
448
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orchestrix-yuri",
3
- "version": "4.4.0",
3
+ "version": "4.5.0",
4
4
  "description": "Yuri — Meta-Orchestrator for Orchestrix. Drive your entire project lifecycle with natural language.",
5
5
  "main": "lib/installer.js",
6
6
  "bin": {