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 +125 -12
- package/memory-daemon/claudia_memory/__main__.py +6 -13
- package/memory-daemon/claudia_memory/config.py +5 -9
- package/memory-daemon/claudia_memory/services/vault_sync.py +491 -247
- package/memory-daemon/tests/test_vault_sync.py +26 -24
- package/memory-daemon/tests/test_vault_sync_v2.py +2 -2
- package/package.json +1 -1
- package/template-v2/CLAUDE.md +26 -14
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
|
-
|
|
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
|
-
|
|
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
|
-
"--
|
|
318
|
+
"--migrate-vault-para",
|
|
319
319
|
action="store_true",
|
|
320
|
-
help="Migrate vault to
|
|
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 --
|
|
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.
|
|
844
|
+
if args.migrate_vault_para:
|
|
845
845
|
setup_logging(debug=args.debug)
|
|
846
|
-
from .services.vault_sync import get_vault_path,
|
|
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
|
-
|
|
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
|
-
#
|
|
99
|
-
|
|
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 "
|
|
178
|
-
config.
|
|
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
|
-
"
|
|
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,
|