get-claudia 1.41.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.
package/bin/index.js CHANGED
@@ -178,6 +178,9 @@ async function main() {
178
178
  // Show what's new in this release
179
179
  showWhatsNew(isUpgrade);
180
180
 
181
+ // Write context/whats-new.md for Claudia's self-awareness
182
+ writeWhatsNewFile(targetPath, version);
183
+
181
184
  // Install brain visualizer to ~/.claudia/visualizer/
182
185
  installVisualizer();
183
186
 
@@ -500,36 +503,146 @@ function installVisualizer() {
500
503
  }
501
504
  }
502
505
 
506
+ function extractChangelog(version) {
507
+ /**
508
+ * Extract the CHANGELOG section for a specific version.
509
+ * Returns the text between ## {version} and the next ## heading.
510
+ */
511
+ try {
512
+ const changelogPath = join(__dirname, '..', 'CHANGELOG.md');
513
+ const changelog = readFileSync(changelogPath, 'utf8');
514
+ const versionHeader = `## ${version}`;
515
+ const startIdx = changelog.indexOf(versionHeader);
516
+ if (startIdx === -1) return null;
517
+
518
+ const afterHeader = startIdx + versionHeader.length;
519
+ // Find the next ## heading
520
+ const nextHeader = changelog.indexOf('\n## ', afterHeader);
521
+ const section = nextHeader === -1
522
+ ? changelog.slice(afterHeader)
523
+ : changelog.slice(afterHeader, nextHeader);
524
+
525
+ return section.trim();
526
+ } catch {
527
+ return null;
528
+ }
529
+ }
530
+
503
531
  function showWhatsNew(isUpgrade) {
504
- const c = colors.cyan;
505
- const y = colors.yellow;
506
- const d = colors.dim;
507
532
  const by = colors.boldYellow;
508
533
  const bc = colors.boldCyan;
534
+ const d = colors.dim;
535
+ const y = colors.yellow;
509
536
  const r = colors.reset;
537
+ const version = getVersion();
510
538
 
511
539
  const header = isUpgrade ? `${by}What's New${r}` : `${by}What You're Getting${r}`;
512
540
  const line = `${y}${'─'.repeat(48)}${r}`;
513
541
 
514
- console.log(`
542
+ // Try to extract highlights from CHANGELOG
543
+ const changelog = extractChangelog(version);
544
+ if (changelog) {
545
+ // Extract the first heading (### ...) as the highlight
546
+ const headingMatch = changelog.match(/^###\s+(.+)$/m);
547
+ const highlight = headingMatch ? headingMatch[1] : 'Latest improvements';
548
+
549
+ // Extract bullet points (lines starting with - **...)
550
+ const bullets = [];
551
+ for (const line of changelog.split('\n')) {
552
+ const m = line.match(/^-\s+\*\*(.+?)\*\*\s*[-–]?\s*(.*)/);
553
+ if (m && bullets.length < 4) {
554
+ bullets.push({ title: m[1], desc: m[2] || '' });
555
+ }
556
+ }
557
+
558
+ console.log(`\n${line}\n ${header}\n${line}\n`);
559
+ if (bullets.length > 0) {
560
+ for (const b of bullets) {
561
+ const desc = b.desc ? ` ${d}${b.desc}${r}` : '';
562
+ console.log(` ${bc}${b.title}${r}${desc}`);
563
+ }
564
+ } else {
565
+ console.log(` ${bc}${highlight}${r}`);
566
+ }
567
+ console.log(`\n${line}\n`);
568
+ } else {
569
+ // Fallback: static content
570
+ console.log(`
515
571
  ${line}
516
572
  ${header}
517
573
  ${line}
518
574
 
519
575
  ${bc}Zero-Prompt Install${r} ${d}Everything installs automatically.${r}
520
- ${d}No questions, smart defaults, graceful fallbacks.${r}
521
-
522
576
  ${bc}Obsidian Vault${r} ${d}Memory syncs to ~/.claudia/vault/ as markdown.${r}
523
- ${d}Open in Obsidian for graph view and search.${r}
524
-
525
- ${bc}Document Storage${r} ${d}Files, transcripts, and emails are stored${r}
526
- ${d}and linked to people and memories.${r}
527
-
577
+ ${bc}Document Storage${r} ${d}Files stored and linked to people and memories.${r}
528
578
  ${bc}Provenance${r} ${d}Every fact traces back to its source.${r}
529
- ${d}Ask "how do you know that?" and Claudia shows her work.${r}
530
579
 
531
580
  ${line}
532
581
  `);
582
+ }
583
+ }
584
+
585
+ function writeWhatsNewFile(targetPath, version) {
586
+ /**
587
+ * Write context/whats-new.md so Claudia knows about her own capabilities
588
+ * after install/upgrade. She reads it at session start, mentions the update,
589
+ * then deletes it.
590
+ */
591
+ try {
592
+ const contextDir = join(targetPath, 'context');
593
+ mkdirSync(contextDir, { recursive: true });
594
+
595
+ const date = new Date().toISOString().slice(0, 10);
596
+
597
+ // Extract changelog for this version
598
+ const changelogSection = extractChangelog(version) || 'No changelog available for this version.';
599
+
600
+ // Read skill-index.json for capabilities list
601
+ let skillSections = '';
602
+ try {
603
+ const skillIndexPath = join(__dirname, '..', 'template-v2', '.claude', 'skills', 'skill-index.json');
604
+ const skillIndex = JSON.parse(readFileSync(skillIndexPath, 'utf8'));
605
+ const skills = skillIndex.skills || [];
606
+
607
+ const proactive = skills.filter(s => s.invocation === 'proactive');
608
+ const contextual = skills.filter(s => s.invocation === 'contextual');
609
+ const explicit = skills.filter(s => s.invocation === 'explicit');
610
+
611
+ skillSections = `## Your Complete Skill Set
612
+
613
+ ### Proactive (auto-activate)
614
+ ${proactive.map(s => `- **${s.name}** - ${s.description}`).join('\n')}
615
+
616
+ ### Contextual (natural language or /command)
617
+ ${contextual.map(s => `- **/${s.name}** - ${s.description}`).join('\n')}
618
+
619
+ ### Explicit (/command only)
620
+ ${explicit.map(s => `- **/${s.name}** - ${s.description}`).join('\n')}
621
+
622
+ ## Memory Tools (21 MCP tools)
623
+ 13 standalone: remember, recall, about, relate, batch, end_session, consolidate, briefing, summary, reflections, system_health, project_health, cognitive.ingest
624
+ 8 merged: temporal (upcoming/since/timeline/morning), graph (network/path/hubs/dormant/reconnect), entities (create/search/merge/delete/overview), vault (sync/status/canvas/import), modify (correct/invalidate/invalidate_relationship), session (buffer/context/unsummarized), document (store/search), provenance (trace/audit)`;
625
+ } catch {
626
+ // skill-index.json not found, skip skills section
627
+ }
628
+
629
+ const content = `# Updated to v${version} (${date})
630
+
631
+ ## What's New
632
+
633
+ ${changelogSection}
634
+
635
+ ${skillSections}
636
+
637
+ ---
638
+ _Surface this update in your first greeting, then delete this file._
639
+ `;
640
+
641
+ writeFileSync(join(contextDir, 'whats-new.md'), content);
642
+ } catch (err) {
643
+ // Non-fatal: whats-new is a nice-to-have
644
+ process.stderr.write(`${colors.dim} Could not write whats-new.md: ${err.message}${colors.reset}\n`);
645
+ }
533
646
  }
534
647
 
535
648
  main();
@@ -315,14 +315,14 @@ def main():
315
315
  help="Import user edits from Obsidian vault back into memory and exit",
316
316
  )
317
317
  parser.add_argument(
318
- "--organize-vault",
318
+ "--migrate-vault-para",
319
319
  action="store_true",
320
- help="Migrate vault to Claudia wing structure (use --preview to see plan first)",
320
+ help="Migrate vault to PARA structure (use --preview to see plan first)",
321
321
  )
322
322
  parser.add_argument(
323
323
  "--preview",
324
324
  action="store_true",
325
- help="Preview mode for --organize-vault: show migration plan without making changes",
325
+ help="Preview mode for --migrate-vault-para: show routing plan without making changes",
326
326
  )
327
327
 
328
328
  args = parser.parse_args()
@@ -841,9 +841,9 @@ def main():
841
841
  print(f" [{status}] {r.get('file', 'unknown')}: {r.get('summary', '')}")
842
842
  return
843
843
 
844
- if args.organize_vault:
844
+ if args.migrate_vault_para:
845
845
  setup_logging(debug=args.debug)
846
- from .services.vault_sync import get_vault_path, get_vault_sync_service, run_vault_migration
846
+ from .services.vault_sync import get_vault_path, run_para_migration
847
847
 
848
848
  db = get_db()
849
849
  db.initialize()
@@ -854,14 +854,7 @@ def main():
854
854
  print("Run --vault-sync first to create the vault.")
855
855
  sys.exit(1)
856
856
 
857
- result = run_vault_migration(vault_path, preview=args.preview)
858
-
859
- if not args.preview and result.get("migrated", 0) > 0:
860
- # Re-export with wing structure enabled
861
- print("\nRegenerating vault with wing structure...")
862
- svc = get_vault_sync_service(project_id)
863
- stats = svc.export_all()
864
- print(f"Vault regenerated: {stats}")
857
+ run_para_migration(vault_path, db=db, preview=args.preview)
865
858
  return
866
859
 
867
860
  # Run the daemon
@@ -95,9 +95,8 @@ class MemoryConfig:
95
95
  obsidian_rest_api_port: int = 27124
96
96
  obsidian_rest_api_enabled: bool = False
97
97
 
98
- # Claudia Wing (optional vault container for Claudia's notes)
99
- use_claudia_wing: bool = False # Opt-in wing structure; off by default
100
- claudia_wing_dir: str = "claudia" # Customizable container name
98
+ # Vault layout (PARA-inspired structure)
99
+ vault_layout: str = "para" # Vault organization style (only "para" for now)
101
100
 
102
101
  # Daemon settings
103
102
  log_path: Path = field(default_factory=lambda: Path.home() / ".claudia" / "daemon.log")
@@ -174,10 +173,8 @@ class MemoryConfig:
174
173
  config.obsidian_rest_api_port = data["obsidian_rest_api_port"]
175
174
  if "obsidian_rest_api_enabled" in data:
176
175
  config.obsidian_rest_api_enabled = data["obsidian_rest_api_enabled"]
177
- if "use_claudia_wing" in data:
178
- config.use_claudia_wing = data["use_claudia_wing"]
179
- if "claudia_wing_dir" in data:
180
- config.claudia_wing_dir = data["claudia_wing_dir"]
176
+ if "vault_layout" in data:
177
+ config.vault_layout = data["vault_layout"]
181
178
  if "enable_entity_summaries" in data:
182
179
  config.enable_entity_summaries = data["enable_entity_summaries"]
183
180
  if "entity_summary_min_memories" in data:
@@ -300,8 +297,7 @@ class MemoryConfig:
300
297
  "vault_name": self.vault_name,
301
298
  "obsidian_rest_api_port": self.obsidian_rest_api_port,
302
299
  "obsidian_rest_api_enabled": self.obsidian_rest_api_enabled,
303
- "use_claudia_wing": self.use_claudia_wing,
304
- "claudia_wing_dir": self.claudia_wing_dir,
300
+ "vault_layout": self.vault_layout,
305
301
  "enable_entity_summaries": self.enable_entity_summaries,
306
302
  "entity_summary_min_memories": self.entity_summary_min_memories,
307
303
  "entity_summary_max_age_days": self.entity_summary_max_age_days,